From 6363a93e76871778c754296d582bdd5327d4dfbb Mon Sep 17 00:00:00 2001 From: ty Date: Mon, 6 Jul 2026 23:42:34 -0400 Subject: [PATCH 01/16] Add LiveExample control for live, self-contained docs examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - playground/browser.js: output (params, messages, clear) now flows through a configurable listener via window.ElectroDB.configure(); the original DOM rendering into #param-container remains the default so existing consumers are unaffected. Error reference links open in a new tab. - www: new LiveExample control (src/components/LiveExample) renders a docs example as tabs — Example / Entity / Table Definition — and executes the example in the browser against the mocked ElectroDB client to display its generated DynamoDB parameters live, plus an "Edit in Playground" deep link into electrodb.fun's multi-file (#files) format. - Examples live as real TypeScript modules under www/src/examples// (example.ts imports the entity from ./entity.ts, which imports the table name from ./table.ts), so each example is self-contained and type-checked against the repo's index.d.ts by `npm run check` — examples can no longer drift from the API, and per-example schema deviations stay local. - Sources are transpiled to CommonJS at build time (no TS compiler shipped to the client); the control hydrates lazily with client:visible. - Convert mutations/put and queries/get as exemplar pages, replacing the shared "Example Setup" partial and hard-coded Equivalent Parameters JSON. --- playground/browser.js | 101 +- www/package-lock.json | 48 +- www/package.json | 6 +- www/public/scripts/electrodb-playground.js | 17969 ++++++++++++++++ .../components/LiveExample/LiveExample.astro | 71 + .../components/LiveExample/LiveExample.css | 207 + .../LiveExample/LiveExampleControl.tsx | 123 + www/src/components/LiveExample/runtime.ts | 181 + www/src/examples/README.md | 32 + www/src/examples/get-store-location/entity.ts | 125 + .../examples/get-store-location/example.ts | 8 + www/src/examples/get-store-location/table.ts | 76 + www/src/examples/put-store-location/entity.ts | 125 + .../examples/put-store-location/example.ts | 14 + www/src/examples/put-store-location/table.ts | 76 + www/src/pages/en/mutations/put.mdx | 55 +- www/src/pages/en/queries/get.mdx | 29 +- www/tsconfig.json | 12 +- 18 files changed, 19144 insertions(+), 114 deletions(-) create mode 100644 www/public/scripts/electrodb-playground.js create mode 100644 www/src/components/LiveExample/LiveExample.astro create mode 100644 www/src/components/LiveExample/LiveExample.css create mode 100644 www/src/components/LiveExample/LiveExampleControl.tsx create mode 100644 www/src/components/LiveExample/runtime.ts create mode 100644 www/src/examples/README.md create mode 100644 www/src/examples/get-store-location/entity.ts create mode 100644 www/src/examples/get-store-location/example.ts create mode 100644 www/src/examples/get-store-location/table.ts create mode 100644 www/src/examples/put-store-location/entity.ts create mode 100644 www/src/examples/put-store-location/example.ts create mode 100644 www/src/examples/put-store-location/table.ts diff --git a/playground/browser.js b/playground/browser.js index a58d35ec..f6fb6282 100644 --- a/playground/browser.js +++ b/playground/browser.js @@ -3,7 +3,6 @@ const ElectroDB = require("../index"); window.Prism = window.Prism || {}; window.electroParams = window.electroParams || []; -const appDiv = document.getElementById("param-container"); window.notifyRedirect = function notifyRedirect(e) { if (top.location !== self.location) { @@ -90,26 +89,6 @@ function formatParamLabel(state, entity) { } } -function printToScreen({ params, state, entity, cache } = {}) { - const innerHtml = appDiv.innerHTML; - const label = formatParamLabel(state, entity); - if (cache) { - window.electroParams.push({ title: label, json: params }); - } - let code = `
${JSON.stringify(
-    params,
-    null,
-    4,
-  )}
`; - if (label) { - code = `
${label}${code}`; - } else { - code = `
${code}`; - } - appDiv.innerHTML = innerHtml + code; - window.Prism.highlightAll(); -} - function formatError(message) { const electroErrorPattern = "- For more detail on this error reference:"; const isElectroError = message.match(electroErrorPattern); @@ -117,20 +96,85 @@ function formatError(message) { return `

${message}

`; } const [description, link] = message.split(electroErrorPattern); - return `

${description}


For more detail on this error reference ${link}

`; + return `

${description}


For more detail on this error reference ${link}

`; +} + +// The default listener preserves the original playground behavior: append +// rendered output directly to the #param-container element when one exists. +const domListener = { + getContainer() { + return document.getElementById("param-container"); + }, + onParams({ label, params }) { + const appDiv = this.getContainer(); + if (!appDiv) { + return; + } + let code = `
${JSON.stringify(
+      params,
+      null,
+      4,
+    )}
`; + if (label) { + code = `
${label}${code}`; + } else { + code = `
${code}`; + } + appDiv.innerHTML = appDiv.innerHTML + code; + if (typeof window.Prism.highlightAll === "function") { + window.Prism.highlightAll(); + } + }, + onMessage({ type, html }) { + const appDiv = this.getContainer(); + if (!appDiv) { + return; + } + const label = type === "info" ? "" : "

Query Error

"; + const code = `
${label}
${html}
`; + appDiv.innerHTML = appDiv.innerHTML + code; + }, + onClear() { + const appDiv = this.getContainer(); + if (appDiv) { + appDiv.innerHTML = ""; + } + }, +}; + +let listener = domListener; + +// Allows consumers (the React playground, documentation embeds, etc.) to +// receive playground output as structured events instead of DOM mutations. +// Returns a function that restores the previous listener. +function configure(custom = {}) { + const previous = listener; + listener = { + onParams: custom.onParams || (() => {}), + onMessage: custom.onMessage || (() => {}), + onClear: custom.onClear || (() => {}), + }; + return function restore() { + listener = previous; + }; +} + +function printToScreen({ params, state, entity, cache } = {}) { + const label = formatParamLabel(state, entity); + if (cache) { + window.electroParams.push({ title: label, json: params }); + } + listener.onParams({ label, params, cache }); } function printMessage(type, message) { - const error = formatError(message); - const innerHtml = appDiv.innerHTML; - const label = type === "info" ? "" : "

Query Error

"; - const code = `
${label}
${error}
`; - appDiv.innerHTML = innerHtml + code; + const html = formatError(message); + listener.onMessage({ type, html, text: message }); } function clearScreen() { - appDiv.innerHTML = ""; window.electroParams = []; + listener.onClear(); } function promiseCallback(results) { @@ -267,6 +311,7 @@ const CustomAttributeType = ElectroDB.CustomAttributeType; window.ElectroDB = { Entity, Service, + configure, clearScreen, printMessage, printToScreen, diff --git a/www/package-lock.json b/www/package-lock.json index cb38ef8b..7e2e4255 100644 --- a/www/package-lock.json +++ b/www/package-lock.json @@ -19,13 +19,17 @@ "@types/react": "^17.0.45", "@types/react-dom": "^18.0.0", "astro": "^1.6.14", + "lz-string": "^1.5.0", "preact": "^10.7.3", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.1.0", "sharp": "^0.31.2" }, "devDependencies": { - "pagefind": "^1.5.2" + "@types/prismjs": "^1.26.3", + "pagefind": "^1.5.2", + "typescript": "~5.2.2" } }, "node_modules/@algolia/autocomplete-core": { @@ -1204,6 +1208,13 @@ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -3648,6 +3659,15 @@ "node": ">=10" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -6575,15 +6595,16 @@ } }, "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unherit": { @@ -8416,6 +8437,12 @@ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" }, + "@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -10058,6 +10085,11 @@ "yallist": "^4.0.0" } }, + "lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -12017,9 +12049,9 @@ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" }, "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" }, "unherit": { "version": "3.0.0", diff --git a/www/package.json b/www/package.json index b6219459..276ca472 100644 --- a/www/package.json +++ b/www/package.json @@ -21,6 +21,8 @@ "@docsearch/css": "^3.1.0", "@docsearch/react": "^3.1.0", "@types/node": "^18.0.0", + "lz-string": "^1.5.0", + "prismjs": "^1.29.0", "@types/react": "^17.0.45", "@types/react-dom": "^18.0.0", "astro": "^1.6.14", @@ -30,6 +32,8 @@ "sharp": "^0.31.2" }, "devDependencies": { - "pagefind": "^1.5.2" + "@types/prismjs": "^1.26.3", + "pagefind": "^1.5.2", + "typescript": "~5.2.2" } } diff --git a/www/public/scripts/electrodb-playground.js b/www/public/scripts/electrodb-playground.js new file mode 100644 index 00000000..17be0f4f --- /dev/null +++ b/www/public/scripts/electrodb-playground.js @@ -0,0 +1,17969 @@ +(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk( + uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) + )) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + +},{}],3:[function(require,module,exports){ +(function (Buffer){(function (){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + var arr = new Uint8Array(1) + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) + } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + var length = byteLength(string, encoding) | 0 + var buf = createBuffer(length) + + var actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf +} + +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf +} + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + var buf = createBuffer(len) + + if (buf.length === 0) { + return buf + } + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) + } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } +} + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + var len = string.length + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + var strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (var i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"base64-js":2,"buffer":3,"ieee754":4}],4:[function(require,module,exports){ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],5:[function(require,module,exports){ +'use strict'; + +var helpers = require('./helpers'); + +/** @type ValidatorResult */ +var ValidatorResult = helpers.ValidatorResult; +/** @type SchemaError */ +var SchemaError = helpers.SchemaError; + +var attribute = {}; + +attribute.ignoreProperties = { + // informative properties + 'id': true, + 'default': true, + 'description': true, + 'title': true, + // arguments to other properties + 'additionalItems': true, + 'then': true, + 'else': true, + // special-handled properties + '$schema': true, + '$ref': true, + 'extends': true, +}; + +/** + * @name validators + */ +var validators = attribute.validators = {}; + +/** + * Validates whether the instance if of a certain type + * @param instance + * @param schema + * @param options + * @param ctx + * @return {ValidatorResult|null} + */ +validators.type = function validateType (instance, schema, options, ctx) { + // Ignore undefined instances + if (instance === undefined) { + return null; + } + var result = new ValidatorResult(instance, schema, options, ctx); + var types = Array.isArray(schema.type) ? schema.type : [schema.type]; + if (!types.some(this.testType.bind(this, instance, schema, options, ctx))) { + var list = types.map(function (v) { + if(!v) return; + var id = v.$id || v.id; + return id ? ('<' + id + '>') : (v+''); + }); + result.addError({ + name: 'type', + argument: list, + message: "is not of a type(s) " + list, + }); + } + return result; +}; + +function testSchemaNoThrow(instance, options, ctx, callback, schema){ + var throwError = options.throwError; + var throwAll = options.throwAll; + options.throwError = false; + options.throwAll = false; + var res = this.validateSchema(instance, schema, options, ctx); + options.throwError = throwError; + options.throwAll = throwAll; + + if (!res.valid && callback instanceof Function) { + callback(res); + } + return res.valid; +} + +/** + * Validates whether the instance matches some of the given schemas + * @param instance + * @param schema + * @param options + * @param ctx + * @return {ValidatorResult|null} + */ +validators.anyOf = function validateAnyOf (instance, schema, options, ctx) { + // Ignore undefined instances + if (instance === undefined) { + return null; + } + var result = new ValidatorResult(instance, schema, options, ctx); + var inner = new ValidatorResult(instance, schema, options, ctx); + if (!Array.isArray(schema.anyOf)){ + throw new SchemaError("anyOf must be an array"); + } + if (!schema.anyOf.some( + testSchemaNoThrow.bind( + this, instance, options, ctx, function(res){inner.importErrors(res);} + ))) { + var list = schema.anyOf.map(function (v, i) { + var id = v.$id || v.id; + if(id) return '<' + id + '>'; + return(v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']'; + }); + if (options.nestedErrors) { + result.importErrors(inner); + } + result.addError({ + name: 'anyOf', + argument: list, + message: "is not any of " + list.join(','), + }); + } + return result; +}; + +/** + * Validates whether the instance matches every given schema + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null} + */ +validators.allOf = function validateAllOf (instance, schema, options, ctx) { + // Ignore undefined instances + if (instance === undefined) { + return null; + } + if (!Array.isArray(schema.allOf)){ + throw new SchemaError("allOf must be an array"); + } + var result = new ValidatorResult(instance, schema, options, ctx); + var self = this; + schema.allOf.forEach(function(v, i){ + var valid = self.validateSchema(instance, v, options, ctx); + if(!valid.valid){ + var id = v.$id || v.id; + var msg = id || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']'; + result.addError({ + name: 'allOf', + argument: { id: msg, length: valid.errors.length, valid: valid }, + message: 'does not match allOf schema ' + msg + ' with ' + valid.errors.length + ' error[s]:', + }); + result.importErrors(valid); + } + }); + return result; +}; + +/** + * Validates whether the instance matches exactly one of the given schemas + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null} + */ +validators.oneOf = function validateOneOf (instance, schema, options, ctx) { + // Ignore undefined instances + if (instance === undefined) { + return null; + } + if (!Array.isArray(schema.oneOf)){ + throw new SchemaError("oneOf must be an array"); + } + var result = new ValidatorResult(instance, schema, options, ctx); + var inner = new ValidatorResult(instance, schema, options, ctx); + var count = schema.oneOf.filter( + testSchemaNoThrow.bind( + this, instance, options, ctx, function(res) {inner.importErrors(res);} + ) ).length; + var list = schema.oneOf.map(function (v, i) { + var id = v.$id || v.id; + return id || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']'; + }); + if (count!==1) { + if (options.nestedErrors) { + result.importErrors(inner); + } + result.addError({ + name: 'oneOf', + argument: list, + message: "is not exactly one from " + list.join(','), + }); + } + return result; +}; + +/** + * Validates "then" or "else" depending on the result of validating "if" + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null} + */ +validators.if = function validateIf (instance, schema, options, ctx) { + // Ignore undefined instances + if (instance === undefined) return null; + if (!helpers.isSchema(schema.if)) throw new Error('Expected "if" keyword to be a schema'); + var ifValid = testSchemaNoThrow.call(this, instance, options, ctx, null, schema.if); + var result = new ValidatorResult(instance, schema, options, ctx); + var res; + if(ifValid){ + if (schema.then === undefined) return; + if (!helpers.isSchema(schema.then)) throw new Error('Expected "then" keyword to be a schema'); + res = this.validateSchema(instance, schema.then, options, ctx.makeChild(schema.then)); + result.importErrors(res); + }else{ + if (schema.else === undefined) return; + if (!helpers.isSchema(schema.else)) throw new Error('Expected "else" keyword to be a schema'); + res = this.validateSchema(instance, schema.else, options, ctx.makeChild(schema.else)); + result.importErrors(res); + } + return result; +}; + +function getEnumerableProperty(object, key){ + // Determine if `key` shows up in `for(var key in object)` + // First test Object.hasOwnProperty.call as an optimization: that guarantees it does + if(Object.hasOwnProperty.call(object, key)) return object[key]; + // Test `key in object` as an optimization; false means it won't + if(!(key in object)) return; + while( (object = Object.getPrototypeOf(object)) ){ + if(Object.propertyIsEnumerable.call(object, key)) return object[key]; + } +} + +/** + * Validates propertyNames + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.propertyNames = function validatePropertyNames (instance, schema, options, ctx) { + if(!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var subschema = schema.propertyNames!==undefined ? schema.propertyNames : {}; + if(!helpers.isSchema(subschema)) throw new SchemaError('Expected "propertyNames" to be a schema (object or boolean)'); + + for (var property in instance) { + if(getEnumerableProperty(instance, property) !== undefined){ + var res = this.validateSchema(property, subschema, options, ctx.makeChild(subschema)); + result.importErrors(res); + } + } + + return result; +}; + +/** + * Validates properties + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.properties = function validateProperties (instance, schema, options, ctx) { + if(!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var properties = schema.properties || {}; + for (var property in properties) { + var subschema = properties[property]; + if(subschema===undefined){ + continue; + }else if(subschema===null){ + throw new SchemaError('Unexpected null, expected schema in "properties"'); + } + if (typeof options.preValidateProperty == 'function') { + options.preValidateProperty(instance, property, subschema, options, ctx); + } + var prop = getEnumerableProperty(instance, property); + var res = this.validateSchema(prop, subschema, options, ctx.makeChild(subschema, property)); + if(res.instance !== result.instance[property]) result.instance[property] = res.instance; + result.importErrors(res); + } + return result; +}; + +/** + * Test a specific property within in instance against the additionalProperties schema attribute + * This ignores properties with definitions in the properties schema attribute, but no other attributes. + * If too many more types of property-existence tests pop up they may need their own class of tests (like `type` has) + * @private + * @return {boolean} + */ +function testAdditionalProperty (instance, schema, options, ctx, property, result) { + if(!this.types.object(instance)) return; + if (schema.properties && schema.properties[property] !== undefined) { + return; + } + if (schema.additionalProperties === false) { + result.addError({ + name: 'additionalProperties', + argument: property, + message: "is not allowed to have the additional property " + JSON.stringify(property), + }); + } else { + var additionalProperties = schema.additionalProperties || {}; + + if (typeof options.preValidateProperty == 'function') { + options.preValidateProperty(instance, property, additionalProperties, options, ctx); + } + + var res = this.validateSchema(instance[property], additionalProperties, options, ctx.makeChild(additionalProperties, property)); + if(res.instance !== result.instance[property]) result.instance[property] = res.instance; + result.importErrors(res); + } +} + +/** + * Validates patternProperties + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.patternProperties = function validatePatternProperties (instance, schema, options, ctx) { + if(!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var patternProperties = schema.patternProperties || {}; + + for (var property in instance) { + var test = true; + for (var pattern in patternProperties) { + var subschema = patternProperties[pattern]; + if(subschema===undefined){ + continue; + }else if(subschema===null){ + throw new SchemaError('Unexpected null, expected schema in "patternProperties"'); + } + try { + var regexp = new RegExp(pattern, 'u'); + } catch(_e) { + // In the event the stricter handling causes an error, fall back on the forgiving handling + // DEPRECATED + regexp = new RegExp(pattern); + } + if (!regexp.test(property)) { + continue; + } + test = false; + + if (typeof options.preValidateProperty == 'function') { + options.preValidateProperty(instance, property, subschema, options, ctx); + } + + var res = this.validateSchema(instance[property], subschema, options, ctx.makeChild(subschema, property)); + if(res.instance !== result.instance[property]) result.instance[property] = res.instance; + result.importErrors(res); + } + if (test) { + testAdditionalProperty.call(this, instance, schema, options, ctx, property, result); + } + } + + return result; +}; + +/** + * Validates additionalProperties + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.additionalProperties = function validateAdditionalProperties (instance, schema, options, ctx) { + if(!this.types.object(instance)) return; + // if patternProperties is defined then we'll test when that one is called instead + if (schema.patternProperties) { + return null; + } + var result = new ValidatorResult(instance, schema, options, ctx); + for (var property in instance) { + testAdditionalProperty.call(this, instance, schema, options, ctx, property, result); + } + return result; +}; + +/** + * Validates whether the instance value is at least of a certain length, when the instance value is a string. + * @param instance + * @param schema + * @return {String|null} + */ +validators.minProperties = function validateMinProperties (instance, schema, options, ctx) { + if (!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var keys = Object.keys(instance); + if (!(keys.length >= schema.minProperties)) { + result.addError({ + name: 'minProperties', + argument: schema.minProperties, + message: "does not meet minimum property length of " + schema.minProperties, + }); + } + return result; +}; + +/** + * Validates whether the instance value is at most of a certain length, when the instance value is a string. + * @param instance + * @param schema + * @return {String|null} + */ +validators.maxProperties = function validateMaxProperties (instance, schema, options, ctx) { + if (!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var keys = Object.keys(instance); + if (!(keys.length <= schema.maxProperties)) { + result.addError({ + name: 'maxProperties', + argument: schema.maxProperties, + message: "does not meet maximum property length of " + schema.maxProperties, + }); + } + return result; +}; + +/** + * Validates items when instance is an array + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.items = function validateItems (instance, schema, options, ctx) { + var self = this; + if (!this.types.array(instance)) return; + if (schema.items===undefined) return; + var result = new ValidatorResult(instance, schema, options, ctx); + instance.every(function (value, i) { + if(Array.isArray(schema.items)){ + var items = schema.items[i]===undefined ? schema.additionalItems : schema.items[i]; + }else{ + var items = schema.items; + } + if (items === undefined) { + return true; + } + if (items === false) { + result.addError({ + name: 'items', + message: "additionalItems not permitted", + }); + return false; + } + var res = self.validateSchema(value, items, options, ctx.makeChild(items, i)); + if(res.instance !== result.instance[i]) result.instance[i] = res.instance; + result.importErrors(res); + return true; + }); + return result; +}; + +/** + * Validates the "contains" keyword + * @param instance + * @param schema + * @param options + * @param ctx + * @return {String|null|ValidatorResult} + */ +validators.contains = function validateContains (instance, schema, options, ctx) { + var self = this; + if (!this.types.array(instance)) return; + if (schema.contains===undefined) return; + if (!helpers.isSchema(schema.contains)) throw new Error('Expected "contains" keyword to be a schema'); + var result = new ValidatorResult(instance, schema, options, ctx); + var count = instance.some(function (value, i) { + var res = self.validateSchema(value, schema.contains, options, ctx.makeChild(schema.contains, i)); + return res.errors.length===0; + }); + if(count===false){ + result.addError({ + name: 'contains', + argument: schema.contains, + message: "must contain an item matching given schema", + }); + } + return result; +}; + +/** + * Validates minimum and exclusiveMinimum when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.minimum = function validateMinimum (instance, schema, options, ctx) { + if (!this.types.number(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (schema.exclusiveMinimum && schema.exclusiveMinimum === true) { + if(!(instance > schema.minimum)){ + result.addError({ + name: 'minimum', + argument: schema.minimum, + message: "must be greater than " + schema.minimum, + }); + } + } else { + if(!(instance >= schema.minimum)){ + result.addError({ + name: 'minimum', + argument: schema.minimum, + message: "must be greater than or equal to " + schema.minimum, + }); + } + } + return result; +}; + +/** + * Validates maximum and exclusiveMaximum when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.maximum = function validateMaximum (instance, schema, options, ctx) { + if (!this.types.number(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (schema.exclusiveMaximum && schema.exclusiveMaximum === true) { + if(!(instance < schema.maximum)){ + result.addError({ + name: 'maximum', + argument: schema.maximum, + message: "must be less than " + schema.maximum, + }); + } + } else { + if(!(instance <= schema.maximum)){ + result.addError({ + name: 'maximum', + argument: schema.maximum, + message: "must be less than or equal to " + schema.maximum, + }); + } + } + return result; +}; + +/** + * Validates the number form of exclusiveMinimum when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.exclusiveMinimum = function validateExclusiveMinimum (instance, schema, options, ctx) { + // Support the boolean form of exclusiveMinimum, which is handled by the "minimum" keyword. + if(typeof schema.exclusiveMinimum === 'boolean') return; + if (!this.types.number(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var valid = instance > schema.exclusiveMinimum; + if (!valid) { + result.addError({ + name: 'exclusiveMinimum', + argument: schema.exclusiveMinimum, + message: "must be strictly greater than " + schema.exclusiveMinimum, + }); + } + return result; +}; + +/** + * Validates the number form of exclusiveMaximum when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.exclusiveMaximum = function validateExclusiveMaximum (instance, schema, options, ctx) { + // Support the boolean form of exclusiveMaximum, which is handled by the "maximum" keyword. + if(typeof schema.exclusiveMaximum === 'boolean') return; + if (!this.types.number(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var valid = instance < schema.exclusiveMaximum; + if (!valid) { + result.addError({ + name: 'exclusiveMaximum', + argument: schema.exclusiveMaximum, + message: "must be strictly less than " + schema.exclusiveMaximum, + }); + } + return result; +}; + +/** + * Perform validation for multipleOf and divisibleBy, which are essentially the same. + * @param instance + * @param schema + * @param validationType + * @param errorMessage + * @returns {String|null} + */ +var validateMultipleOfOrDivisbleBy = function validateMultipleOfOrDivisbleBy (instance, schema, options, ctx, validationType, errorMessage) { + if (!this.types.number(instance)) return; + + var validationArgument = schema[validationType]; + if (validationArgument == 0) { + throw new SchemaError(validationType + " cannot be zero"); + } + + var result = new ValidatorResult(instance, schema, options, ctx); + + var instanceDecimals = helpers.getDecimalPlaces(instance); + var divisorDecimals = helpers.getDecimalPlaces(validationArgument); + + var maxDecimals = Math.max(instanceDecimals , divisorDecimals); + var multiplier = Math.pow(10, maxDecimals); + + if (Math.round(instance * multiplier) % Math.round(validationArgument * multiplier) !== 0) { + result.addError({ + name: validationType, + argument: validationArgument, + message: errorMessage + JSON.stringify(validationArgument), + }); + } + + return result; +}; + +/** + * Validates divisibleBy when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.multipleOf = function validateMultipleOf (instance, schema, options, ctx) { + return validateMultipleOfOrDivisbleBy.call(this, instance, schema, options, ctx, "multipleOf", "is not a multiple of (divisible by) "); +}; + +/** + * Validates multipleOf when the type of the instance value is a number. + * @param instance + * @param schema + * @return {String|null} + */ +validators.divisibleBy = function validateDivisibleBy (instance, schema, options, ctx) { + return validateMultipleOfOrDivisbleBy.call(this, instance, schema, options, ctx, "divisibleBy", "is not divisible by (multiple of) "); +}; + +/** + * Validates whether the instance value is present. + * @param instance + * @param schema + * @return {String|null} + */ +validators.required = function validateRequired (instance, schema, options, ctx) { + var result = new ValidatorResult(instance, schema, options, ctx); + if (instance === undefined && schema.required === true) { + // A boolean form is implemented for reverse-compatibility with schemas written against older drafts + result.addError({ + name: 'required', + message: "is required", + }); + } else if (this.types.object(instance) && Array.isArray(schema.required)) { + schema.required.forEach(function(n){ + if(getEnumerableProperty(instance, n)===undefined){ + result.addError({ + name: 'required', + argument: n, + message: "requires property " + JSON.stringify(n), + }); + } + }); + } + return result; +}; + +/** + * Validates whether the instance value matches the regular expression, when the instance value is a string. + * @param instance + * @param schema + * @return {String|null} + */ +validators.pattern = function validatePattern (instance, schema, options, ctx) { + if (!this.types.string(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var pattern = schema.pattern; + try { + var regexp = new RegExp(pattern, 'u'); + } catch(_e) { + // In the event the stricter handling causes an error, fall back on the forgiving handling + // DEPRECATED + regexp = new RegExp(pattern); + } + if (!instance.match(regexp)) { + result.addError({ + name: 'pattern', + argument: schema.pattern, + message: "does not match pattern " + JSON.stringify(schema.pattern.toString()), + }); + } + return result; +}; + +/** + * Validates whether the instance value is of a certain defined format or a custom + * format. + * The following formats are supported for string types: + * - date-time + * - date + * - time + * - ip-address + * - ipv6 + * - uri + * - color + * - host-name + * - alpha + * - alpha-numeric + * - utc-millisec + * @param instance + * @param schema + * @param [options] + * @param [ctx] + * @return {String|null} + */ +validators.format = function validateFormat (instance, schema, options, ctx) { + if (instance===undefined) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (!result.disableFormat && !helpers.isFormat(instance, schema.format, this)) { + result.addError({ + name: 'format', + argument: schema.format, + message: "does not conform to the " + JSON.stringify(schema.format) + " format", + }); + } + return result; +}; + +/** + * Validates whether the instance value is at least of a certain length, when the instance value is a string. + * @param instance + * @param schema + * @return {String|null} + */ +validators.minLength = function validateMinLength (instance, schema, options, ctx) { + if (!this.types.string(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + var hsp = instance.match(/[\uDC00-\uDFFF]/g); + var length = instance.length - (hsp ? hsp.length : 0); + if (!(length >= schema.minLength)) { + result.addError({ + name: 'minLength', + argument: schema.minLength, + message: "does not meet minimum length of " + schema.minLength, + }); + } + return result; +}; + +/** + * Validates whether the instance value is at most of a certain length, when the instance value is a string. + * @param instance + * @param schema + * @return {String|null} + */ +validators.maxLength = function validateMaxLength (instance, schema, options, ctx) { + if (!this.types.string(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + // TODO if this was already computed in "minLength", use that value instead of re-computing + var hsp = instance.match(/[\uDC00-\uDFFF]/g); + var length = instance.length - (hsp ? hsp.length : 0); + if (!(length <= schema.maxLength)) { + result.addError({ + name: 'maxLength', + argument: schema.maxLength, + message: "does not meet maximum length of " + schema.maxLength, + }); + } + return result; +}; + +/** + * Validates whether instance contains at least a minimum number of items, when the instance is an Array. + * @param instance + * @param schema + * @return {String|null} + */ +validators.minItems = function validateMinItems (instance, schema, options, ctx) { + if (!this.types.array(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (!(instance.length >= schema.minItems)) { + result.addError({ + name: 'minItems', + argument: schema.minItems, + message: "does not meet minimum length of " + schema.minItems, + }); + } + return result; +}; + +/** + * Validates whether instance contains no more than a maximum number of items, when the instance is an Array. + * @param instance + * @param schema + * @return {String|null} + */ +validators.maxItems = function validateMaxItems (instance, schema, options, ctx) { + if (!this.types.array(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (!(instance.length <= schema.maxItems)) { + result.addError({ + name: 'maxItems', + argument: schema.maxItems, + message: "does not meet maximum length of " + schema.maxItems, + }); + } + return result; +}; + +/** + * Deep compares arrays for duplicates + * @param v + * @param i + * @param a + * @private + * @return {boolean} + */ +function testArrays (v, i, a) { + var j, len = a.length; + for (j = i + 1, len; j < len; j++) { + if (helpers.deepCompareStrict(v, a[j])) { + return false; + } + } + return true; +} + +/** + * Validates whether there are no duplicates, when the instance is an Array. + * @param instance + * @return {String|null} + */ +validators.uniqueItems = function validateUniqueItems (instance, schema, options, ctx) { + if (schema.uniqueItems!==true) return; + if (!this.types.array(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + if (!instance.every(testArrays)) { + result.addError({ + name: 'uniqueItems', + message: "contains duplicate item", + }); + } + return result; +}; + +/** + * Validate for the presence of dependency properties, if the instance is an object. + * @param instance + * @param schema + * @param options + * @param ctx + * @return {null|ValidatorResult} + */ +validators.dependencies = function validateDependencies (instance, schema, options, ctx) { + if (!this.types.object(instance)) return; + var result = new ValidatorResult(instance, schema, options, ctx); + for (var property in schema.dependencies) { + if (instance[property] === undefined) { + continue; + } + var dep = schema.dependencies[property]; + var childContext = ctx.makeChild(dep, property); + if (typeof dep == 'string') { + dep = [dep]; + } + if (Array.isArray(dep)) { + dep.forEach(function (prop) { + if (instance[prop] === undefined) { + result.addError({ + // FIXME there's two different "dependencies" errors here with slightly different outputs + // Can we make these the same? Or should we create different error types? + name: 'dependencies', + argument: childContext.propertyPath, + message: "property " + prop + " not found, required by " + childContext.propertyPath, + }); + } + }); + } else { + var res = this.validateSchema(instance, dep, options, childContext); + if(result.instance !== res.instance) result.instance = res.instance; + if (res && res.errors.length) { + result.addError({ + name: 'dependencies', + argument: childContext.propertyPath, + message: "does not meet dependency required by " + childContext.propertyPath, + }); + result.importErrors(res); + } + } + } + return result; +}; + +/** + * Validates whether the instance value is one of the enumerated values. + * + * @param instance + * @param schema + * @return {ValidatorResult|null} + */ +validators['enum'] = function validateEnum (instance, schema, options, ctx) { + if (instance === undefined) { + return null; + } + if (!Array.isArray(schema['enum'])) { + throw new SchemaError("enum expects an array", schema); + } + var result = new ValidatorResult(instance, schema, options, ctx); + if (!schema['enum'].some(helpers.deepCompareStrict.bind(null, instance))) { + result.addError({ + name: 'enum', + argument: schema['enum'], + message: "is not one of enum values: " + schema['enum'].map(String).join(','), + }); + } + return result; +}; + +/** + * Validates whether the instance exactly matches a given value + * + * @param instance + * @param schema + * @return {ValidatorResult|null} + */ +validators['const'] = function validateEnum (instance, schema, options, ctx) { + if (instance === undefined) { + return null; + } + var result = new ValidatorResult(instance, schema, options, ctx); + if (!helpers.deepCompareStrict(schema['const'], instance)) { + result.addError({ + name: 'const', + argument: schema['const'], + message: "does not exactly match expected constant: " + schema['const'], + }); + } + return result; +}; + +/** + * Validates whether the instance if of a prohibited type. + * @param instance + * @param schema + * @param options + * @param ctx + * @return {null|ValidatorResult} + */ +validators.not = validators.disallow = function validateNot (instance, schema, options, ctx) { + var self = this; + if(instance===undefined) return null; + var result = new ValidatorResult(instance, schema, options, ctx); + var notTypes = schema.not || schema.disallow; + if(!notTypes) return null; + if(!Array.isArray(notTypes)) notTypes=[notTypes]; + notTypes.forEach(function (type) { + if (self.testType(instance, schema, options, ctx, type)) { + var id = type && (type.$id || type.id); + var schemaId = id || type; + result.addError({ + name: 'not', + argument: schemaId, + message: "is of prohibited type " + schemaId, + }); + } + }); + return result; +}; + +module.exports = attribute; + +},{"./helpers":6}],6:[function(require,module,exports){ +'use strict'; + +var ValidationError = exports.ValidationError = function ValidationError (message, instance, schema, path, name, argument) { + if(Array.isArray(path)){ + this.path = path; + this.property = path.reduce(function(sum, item){ + return sum + makeSuffix(item); + }, 'instance'); + }else if(path !== undefined){ + this.property = path; + } + if (message) { + this.message = message; + } + if (schema) { + var id = schema.$id || schema.id; + this.schema = id || schema; + } + if (instance !== undefined) { + this.instance = instance; + } + this.name = name; + this.argument = argument; + this.stack = this.toString(); +}; + +ValidationError.prototype.toString = function toString() { + return this.property + ' ' + this.message; +}; + +var ValidatorResult = exports.ValidatorResult = function ValidatorResult(instance, schema, options, ctx) { + this.instance = instance; + this.schema = schema; + this.options = options; + this.path = ctx.path; + this.propertyPath = ctx.propertyPath; + this.errors = []; + this.throwError = options && options.throwError; + this.throwFirst = options && options.throwFirst; + this.throwAll = options && options.throwAll; + this.disableFormat = options && options.disableFormat === true; +}; + +ValidatorResult.prototype.addError = function addError(detail) { + var err; + if (typeof detail == 'string') { + err = new ValidationError(detail, this.instance, this.schema, this.path); + } else { + if (!detail) throw new Error('Missing error detail'); + if (!detail.message) throw new Error('Missing error message'); + if (!detail.name) throw new Error('Missing validator type'); + err = new ValidationError(detail.message, this.instance, this.schema, this.path, detail.name, detail.argument); + } + + this.errors.push(err); + if (this.throwFirst) { + throw new ValidatorResultError(this); + }else if(this.throwError){ + throw err; + } + return err; +}; + +ValidatorResult.prototype.importErrors = function importErrors(res) { + if (typeof res == 'string' || (res && res.validatorType)) { + this.addError(res); + } else if (res && res.errors) { + this.errors = this.errors.concat(res.errors); + } +}; + +function stringizer (v,i){ + return i+': '+v.toString()+'\n'; +} +ValidatorResult.prototype.toString = function toString(res) { + return this.errors.map(stringizer).join(''); +}; + +Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() { + return !this.errors.length; +} }); + +module.exports.ValidatorResultError = ValidatorResultError; +function ValidatorResultError(result) { + if(typeof Error.captureStackTrace === 'function'){ + Error.captureStackTrace(this, ValidatorResultError); + } + this.instance = result.instance; + this.schema = result.schema; + this.options = result.options; + this.errors = result.errors; +} +ValidatorResultError.prototype = new Error(); +ValidatorResultError.prototype.constructor = ValidatorResultError; +ValidatorResultError.prototype.name = "Validation Error"; + +/** + * Describes a problem with a Schema which prevents validation of an instance + * @name SchemaError + * @constructor + */ +var SchemaError = exports.SchemaError = function SchemaError (msg, schema) { + this.message = msg; + this.schema = schema; + Error.call(this, msg); + if(typeof Error.captureStackTrace === 'function'){ + Error.captureStackTrace(this, SchemaError); + } +}; +SchemaError.prototype = Object.create(Error.prototype, + { + constructor: {value: SchemaError, enumerable: false}, + name: {value: 'SchemaError', enumerable: false}, + }); + +var SchemaContext = exports.SchemaContext = function SchemaContext (schema, options, path, base, schemas) { + this.schema = schema; + this.options = options; + if(Array.isArray(path)){ + this.path = path; + this.propertyPath = path.reduce(function(sum, item){ + return sum + makeSuffix(item); + }, 'instance'); + }else{ + this.propertyPath = path; + } + this.base = base; + this.schemas = schemas; +}; + +SchemaContext.prototype.resolve = function resolve (target) { + return (() => resolveUrl(this.base,target))(); +}; + +SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){ + var path = (propertyName===undefined) ? this.path : this.path.concat([propertyName]); + var id = schema.$id || schema.id; + let base = (() => resolveUrl(this.base,id||''))(); + var ctx = new SchemaContext(schema, this.options, path, base, Object.create(this.schemas)); + if(id && !ctx.schemas[base]){ + ctx.schemas[base] = schema; + } + return ctx; +}; + +var FORMAT_REGEXPS = exports.FORMAT_REGEXPS = { + // 7.3.1. Dates, Times, and Duration + 'date-time': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])[tT ](2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])(\.\d+)?([zZ]|[+-]([0-5][0-9]):(60|[0-5][0-9]))$/, + 'date': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])$/, + 'time': /^(2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])$/, + 'duration': /P(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S)|\d+(D|M(\d+D)?|Y(\d+M(\d+D)?)?)(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S))?|\d+W)/i, + + // 7.3.2. Email Addresses + // TODO: fix the email production + 'email': /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/, + 'idn-email': /^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u, + + // 7.3.3. Hostnames + + // 7.3.4. IP Addresses + 'ip-address': /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, + // FIXME whitespace is invalid + 'ipv6': /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/, + + // 7.3.5. Resource Identifiers + // TODO: A more accurate regular expression for "uri" goes: + // [A-Za-z][+\-.0-9A-Za-z]*:((/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?)?#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])|/?%[0-9A-Fa-f]{2}|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*(#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?)? + 'uri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/, + 'uri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/, + 'iri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/, + 'iri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~-\u{10FFFF}]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~-\u{10FFFF}])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/u, + 'uuid': /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + + // 7.3.6. uri-template + 'uri-template': /(%[0-9a-f]{2}|[!#$&(-;=?@\[\]_a-z~]|\{[!#&+,./;=?@|]?(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?(,(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?)*\})*/iu, + + // 7.3.7. JSON Pointers + 'json-pointer': /^(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*$/iu, + 'relative-json-pointer': /^\d+(#|(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*)$/iu, + + // hostname regex from: http://stackoverflow.com/a/1420225/5628 + 'hostname': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/, + 'host-name': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/, + + 'utc-millisec': function (input) { + return (typeof input === 'string') && parseFloat(input) === parseInt(input, 10) && !isNaN(input); + }, + + // 7.3.8. regex + 'regex': function (input) { + var result = true; + try { + new RegExp(input); + } catch (e) { + result = false; + } + return result; + }, + + // Other definitions + // "style" was removed from JSON Schema in draft-4 and is deprecated + 'style': /[\r\n\t ]*[^\r\n\t ][^:]*:[\r\n\t ]*[^\r\n\t ;]*[\r\n\t ]*;?/, + // "color" was removed from JSON Schema in draft-4 and is deprecated + 'color': /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/, + 'phone': /^\+(?:[0-9] ?){6,14}[0-9]$/, + 'alpha': /^[a-zA-Z]+$/, + 'alphanumeric': /^[a-zA-Z0-9]+$/, +}; + +FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex; +FORMAT_REGEXPS.pattern = FORMAT_REGEXPS.regex; +FORMAT_REGEXPS.ipv4 = FORMAT_REGEXPS['ip-address']; + +exports.isFormat = function isFormat (input, format, validator) { + if (typeof input === 'string' && FORMAT_REGEXPS[format] !== undefined) { + if (FORMAT_REGEXPS[format] instanceof RegExp) { + return FORMAT_REGEXPS[format].test(input); + } + if (typeof FORMAT_REGEXPS[format] === 'function') { + return FORMAT_REGEXPS[format](input); + } + } else if (validator && validator.customFormats && + typeof validator.customFormats[format] === 'function') { + return validator.customFormats[format](input); + } + return true; +}; + +var makeSuffix = exports.makeSuffix = function makeSuffix (key) { + key = key.toString(); + // This function could be capable of outputting valid a ECMAScript string, but the + // resulting code for testing which form to use would be tens of thousands of characters long + // That means this will use the name form for some illegal forms + if (!key.match(/[.\s\[\]]/) && !key.match(/^[\d]/)) { + return '.' + key; + } + if (key.match(/^\d+$/)) { + return '[' + key + ']'; + } + return '[' + JSON.stringify(key) + ']'; +}; + +exports.deepCompareStrict = function deepCompareStrict (a, b) { + if (typeof a !== typeof b) { + return false; + } + if (Array.isArray(a)) { + if (!Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + return a.every(function (v, i) { + return deepCompareStrict(a[i], b[i]); + }); + } + if (typeof a === 'object') { + if (!a || !b) { + return a === b; + } + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) { + return false; + } + return aKeys.every(function (v) { + return deepCompareStrict(a[v], b[v]); + }); + } + return a === b; +}; + +function deepMerger (target, dst, e, i) { + if (typeof e === 'object') { + dst[i] = deepMerge(target[i], e); + } else { + if (target.indexOf(e) === -1) { + dst.push(e); + } + } +} + +function copyist (src, dst, key) { + dst[key] = src[key]; +} + +function copyistWithDeepMerge (target, src, dst, key) { + if (typeof src[key] !== 'object' || !src[key]) { + dst[key] = src[key]; + } + else { + if (!target[key]) { + dst[key] = src[key]; + } else { + dst[key] = deepMerge(target[key], src[key]); + } + } +} + +function deepMerge (target, src) { + var array = Array.isArray(src); + var dst = array && [] || {}; + + if (array) { + target = target || []; + dst = dst.concat(target); + src.forEach(deepMerger.bind(null, target, dst)); + } else { + if (target && typeof target === 'object') { + Object.keys(target).forEach(copyist.bind(null, target, dst)); + } + Object.keys(src).forEach(copyistWithDeepMerge.bind(null, target, src, dst)); + } + + return dst; +} + +module.exports.deepMerge = deepMerge; + +/** + * Validates instance against the provided schema + * Implements URI+JSON Pointer encoding, e.g. "%7e"="~0"=>"~", "~1"="%2f"=>"/" + * @param o + * @param s The path to walk o along + * @return any + */ +exports.objectGetPath = function objectGetPath(o, s) { + var parts = s.split('/').slice(1); + var k; + while (typeof (k=parts.shift()) == 'string') { + var n = decodeURIComponent(k.replace(/~0/,'~').replace(/~1/g,'/')); + if (!(n in o)) return; + o = o[n]; + } + return o; +}; + +function pathEncoder (v) { + return '/'+encodeURIComponent(v).replace(/~/g,'%7E'); +} +/** + * Accept an Array of property names and return a JSON Pointer URI fragment + * @param Array a + * @return {String} + */ +exports.encodePath = function encodePointer(a){ + // ~ must be encoded explicitly because hacks + // the slash is encoded by encodeURIComponent + return a.map(pathEncoder).join(''); +}; + + +/** + * Calculate the number of decimal places a number uses + * We need this to get correct results out of multipleOf and divisibleBy + * when either figure is has decimal places, due to IEEE-754 float issues. + * @param number + * @returns {number} + */ +exports.getDecimalPlaces = function getDecimalPlaces(number) { + + var decimalPlaces = 0; + if (isNaN(number)) return decimalPlaces; + + if (typeof number !== 'number') { + number = Number(number); + } + + var parts = number.toString().split('e'); + if (parts.length === 2) { + if (parts[1][0] !== '-') { + return decimalPlaces; + } else { + decimalPlaces = Number(parts[1].slice(1)); + } + } + + var decimalParts = parts[0].split('.'); + if (decimalParts.length === 2) { + decimalPlaces += decimalParts[1].length; + } + + return decimalPlaces; +}; + +exports.isSchema = function isSchema(val){ + return (typeof val === 'object' && val) || (typeof val === 'boolean'); +}; + +/** + * Resolve target URL from a base and relative URL. + * Similar to Node's URL Lib's legacy resolve function. + * Code from example in deprecation note in said library. + * @param string + * @param string + * @returns {string} + */ +var resolveUrl = exports.resolveUrl = function resolveUrl(from, to) { + const resolvedUrl = new URL(to, new URL(from, 'resolve://')); + if (resolvedUrl.protocol === 'resolve:') { + const { pathname, search, hash } = resolvedUrl; + return pathname + search + hash; + } + return resolvedUrl.toString(); +} + +},{}],7:[function(require,module,exports){ +'use strict'; + +var Validator = module.exports.Validator = require('./validator'); + +module.exports.ValidatorResult = require('./helpers').ValidatorResult; +module.exports.ValidatorResultError = require('./helpers').ValidatorResultError; +module.exports.ValidationError = require('./helpers').ValidationError; +module.exports.SchemaError = require('./helpers').SchemaError; +module.exports.SchemaScanResult = require('./scan').SchemaScanResult; +module.exports.scan = require('./scan').scan; + +module.exports.validate = function (instance, schema, options) { + var v = new Validator(); + return v.validate(instance, schema, options); +}; + +},{"./helpers":6,"./scan":8,"./validator":9}],8:[function(require,module,exports){ +"use strict"; + +var helpers = require('./helpers'); + +module.exports.SchemaScanResult = SchemaScanResult; +function SchemaScanResult(found, ref){ + this.id = found; + this.ref = ref; +} + +/** + * Adds a schema with a certain urn to the Validator instance. + * @param string uri + * @param object schema + * @return {Object} + */ +module.exports.scan = function scan(base, schema){ + function scanSchema(baseuri, schema){ + if(!schema || typeof schema!='object') return; + // Mark all referenced schemas so we can tell later which schemas are referred to, but never defined + if(schema.$ref){ + let resolvedUri = helpers.resolveUrl(baseuri,schema.$ref); + ref[resolvedUri] = ref[resolvedUri] ? ref[resolvedUri]+1 : 0; + return; + } + var id = schema.$id || schema.id; + let resolvedBase = helpers.resolveUrl(baseuri,id); + var ourBase = id ? resolvedBase : baseuri; + if (ourBase) { + // If there's no fragment, append an empty one + if(ourBase.indexOf('#')<0) ourBase += '#'; + if(found[ourBase]){ + if(!helpers.deepCompareStrict(found[ourBase], schema)){ + throw new Error('Schema <'+ourBase+'> already exists with different definition'); + } + return found[ourBase]; + } + found[ourBase] = schema; + // strip trailing fragment + if(ourBase[ourBase.length-1]=='#'){ + found[ourBase.substring(0, ourBase.length-1)] = schema; + } + } + scanArray(ourBase+'/items', (Array.isArray(schema.items)?schema.items:[schema.items])); + scanArray(ourBase+'/extends', (Array.isArray(schema.extends)?schema.extends:[schema.extends])); + scanSchema(ourBase+'/additionalItems', schema.additionalItems); + scanObject(ourBase+'/properties', schema.properties); + scanSchema(ourBase+'/additionalProperties', schema.additionalProperties); + scanObject(ourBase+'/definitions', schema.definitions); + scanObject(ourBase+'/patternProperties', schema.patternProperties); + scanObject(ourBase+'/dependencies', schema.dependencies); + scanArray(ourBase+'/disallow', schema.disallow); + scanArray(ourBase+'/allOf', schema.allOf); + scanArray(ourBase+'/anyOf', schema.anyOf); + scanArray(ourBase+'/oneOf', schema.oneOf); + scanSchema(ourBase+'/not', schema.not); + } + function scanArray(baseuri, schemas){ + if(!Array.isArray(schemas)) return; + for(var i=0; i", schema); + } + var subschema = helpers.objectGetPath(ctx.schemas[document], fragment.substr(1)); + if(subschema===undefined){ + throw new SchemaError("no such schema " + fragment + " located in <" + document + ">", schema); + } + return {subschema: subschema, switchSchema: switchSchema}; +}; + +/** + * Tests whether the instance if of a certain type. + * @private + * @param instance + * @param schema + * @param options + * @param ctx + * @param type + * @return {boolean} + */ +Validator.prototype.testType = function validateType (instance, schema, options, ctx, type) { + if(type===undefined){ + return; + }else if(type===null){ + throw new SchemaError('Unexpected null in "type" keyword'); + } + if (typeof this.types[type] == 'function') { + return this.types[type].call(this, instance); + } + if (type && typeof type == 'object') { + var res = this.validateSchema(instance, type, options, ctx); + return res === undefined || !(res && res.errors.length); + } + // Undefined or properties not on the list are acceptable, same as not being defined + return true; +}; + +var types = Validator.prototype.types = {}; +types.string = function testString (instance) { + return typeof instance == 'string'; +}; +types.number = function testNumber (instance) { + // isFinite returns false for NaN, Infinity, and -Infinity + return typeof instance == 'number' && isFinite(instance); +}; +types.integer = function testInteger (instance) { + return (typeof instance == 'number') && instance % 1 === 0; +}; +types.boolean = function testBoolean (instance) { + return typeof instance == 'boolean'; +}; +types.array = function testArray (instance) { + return Array.isArray(instance); +}; +types['null'] = function testNull (instance) { + return instance === null; +}; +types.date = function testDate (instance) { + return instance instanceof Date; +}; +types.any = function testAny (instance) { + return true; +}; +types.object = function testObject (instance) { + // TODO: fix this - see #15 + return instance && (typeof instance === 'object') && !(Array.isArray(instance)) && !(instance instanceof Date); +}; + +module.exports = Validator; + +},{"./attribute":5,"./helpers":6,"./scan":8}],10:[function(require,module,exports){ +/* istanbul ignore file */ +const ElectroDB = require("../index"); + +window.Prism = window.Prism || {}; +window.electroParams = window.electroParams || []; + +window.notifyRedirect = function notifyRedirect(e) { + if (top.location !== self.location) { + e.preventDefault(); + window.top.postMessage( + JSON.stringify({ type: "redirect", data: e.target.href }), + "*", + ); + } +}; + +function aOrAn(value = "") { + return ["a", "e", "i", "o", "u"].includes(value[0].toLowerCase()) + ? "an" + : "a"; +} + +function properCase(str = "") { + let newStr = ""; + for (let i = 0; i < str.length; i++) { + let value = i === 0 ? str[i].toUpperCase() : str[i]; + newStr += value; + } + return newStr; +} + +function formatProper(value) { + return formatStrict(properCase(value)); +} + +function formatStrict(value) { + return `${value}`; +} + +function formatProvidedKeys(pk = {}, sks = []) { + let keys = { ...pk }; + for (const sk of sks) { + keys = { ...keys, ...sk.facets }; + } + const provided = Object.keys(keys).map((key) => formatStrict(key)); + if (provided.length === 0) { + return ""; + } else if (provided.length === 1) { + return provided[0]; + } else if (provided.length === 2) { + return provided.join(" and "); + } else { + provided[provided.length - 1] = `and ${provided[provided.length - 1]}`; + return provided.join(", "); + } +} + +function formatParamLabel(state, entity) { + if (!state) { + return null; + } else if (typeof state === "string") { + return `

${state}

`; + } else { + const method = state.query.method; + const type = state.query.type; + const collection = state.query.collection; + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + const keys = formatProvidedKeys(state.query.keys.pk, state.query.keys.sk); + if (collection) { + return `

Queries the collection ${formatProper( + collection, + )}, on the service ${formatProper( + entity.model.service, + )}, by ${keys}

`; + } else if (method === "query") { + return `

Queries the access pattern ${formatProper( + accessPattern, + )}, on the entity ${formatProper(entity.model.name)}, by ${keys}

`; + } else if (state.self === "commit") { + // handled inside the "client" so each operation doesn't get its own printed line + } else { + return `

Performs ${aOrAn(method)} ${formatProper( + method, + )} operation, on the entity ${formatProper(entity.model.name)}

`; + } + } +} + +function formatError(message) { + const electroErrorPattern = "- For more detail on this error reference:"; + const isElectroError = message.match(electroErrorPattern); + if (!isElectroError) { + return `

${message}

`; + } + const [description, link] = message.split(electroErrorPattern); + return `

${description}


For more detail on this error reference ${link}

`; +} + +// The default listener preserves the original playground behavior: append +// rendered output directly to the #param-container element when one exists. +const domListener = { + getContainer() { + return document.getElementById("param-container"); + }, + onParams({ label, params }) { + const appDiv = this.getContainer(); + if (!appDiv) { + return; + } + let code = `
${JSON.stringify(
+      params,
+      null,
+      4,
+    )}
`; + if (label) { + code = `
${label}${code}`; + } else { + code = `
${code}`; + } + appDiv.innerHTML = appDiv.innerHTML + code; + if (typeof window.Prism.highlightAll === "function") { + window.Prism.highlightAll(); + } + }, + onMessage({ type, html }) { + const appDiv = this.getContainer(); + if (!appDiv) { + return; + } + const label = type === "info" ? "" : "

Query Error

"; + const code = `
${label}
${html}
`; + appDiv.innerHTML = appDiv.innerHTML + code; + }, + onClear() { + const appDiv = this.getContainer(); + if (appDiv) { + appDiv.innerHTML = ""; + } + }, +}; + +let listener = domListener; + +// Allows consumers (the React playground, documentation embeds, etc.) to +// receive playground output as structured events instead of DOM mutations. +// Returns a function that restores the previous listener. +function configure(custom = {}) { + const previous = listener; + listener = { + onParams: custom.onParams || (() => {}), + onMessage: custom.onMessage || (() => {}), + onClear: custom.onClear || (() => {}), + }; + return function restore() { + listener = previous; + }; +} + +function printToScreen({ params, state, entity, cache } = {}) { + const label = formatParamLabel(state, entity); + if (cache) { + window.electroParams.push({ title: label, json: params }); + } + listener.onParams({ label, params, cache }); +} + +function printMessage(type, message) { + const html = formatError(message); + listener.onMessage({ type, html, text: message }); +} + +function clearScreen() { + window.electroParams = []; + listener.onClear(); +} + +function promiseCallback(results) { + return { + promise: async () => results, + }; +} + +class Entity extends ElectroDB.Entity { + constructor(schema, options = {}) { + super(schema, { + ...options, + client: { + put: () => promiseCallback({}), + delete: () => promiseCallback({}), + update: () => promiseCallback({}), + get: () => promiseCallback({ Item: {} }), + query: () => promiseCallback({ Items: [] }), + scan: () => promiseCallback({ Items: [] }), + batchWrite: () => + promiseCallback({ + UnprocessedKeys: { [options.table]: { Keys: [] } }, + }), + batchGet: () => + promiseCallback({ + Responses: { [options.table]: [] }, + UnprocessedKeys: { [options.table]: { Keys: [] } }, + }), + transactWrite: (params) => { + return { + promise: async () => { + printToScreen({ + params, + entity: this, + cache: true, + state: "Performs a TransactWrite operation", + }); + return {}; + }, + on: () => {}, + }; + }, + transactGet: (params) => { + return { + promise: async () => { + printToScreen({ + params, + entity: this, + cache: true, + state: "Performs a TransactGet operation", + }); + return { Responses: [] }; + }, + on: () => {}, + }; + }, + createSet: (val) => val, + }, + }); + } + + _demoParams(method, state, config) { + try { + const params = super[method](state, config); + if (params && typeof params.catch === "function") { + params.catch((err) => { + console.log("param creation rejected: %o", err); + printMessage("error", err.message); + }); + } + if (state.self !== "commit") { + printToScreen({ params, state, entity: this, cache: true }); + } + return params; + } catch (err) { + console.log("create params error: %o", err); + printMessage("error", err.message); + } + } + + _queryParams(state, config) { + return this._demoParams("_queryParams", state, config); + } + + _batchWriteParams(state, config) { + return this._demoParams("_batchWriteParams", state, config); + } + + _batchGetParams(state, config) { + return this._demoParams("_batchGetParams", state, config); + } + + _params(state, config) { + return this._demoParams("_params", state, config); + } + + _makeChain(index, clauses, rootClause, options) { + const params = clauses.params.action; + const go = clauses.go.action; + const commit = clauses.commit.action; + clauses.params.action = (entity, state, options) => { + try { + return params(entity, state, options); + } catch (err) { + printMessage("error", err.message); + } + }; + clauses.go.action = async (entity, state, options) => { + try { + return await go(entity, state, options); + } catch (err) { + printMessage("error", err.message); + } + }; + clauses.commit.action = (entity, state, options) => { + try { + return commit(entity, state, options); + } catch (err) { + printMessage("error", err.message); + } + }; + return super._makeChain(index, clauses, rootClause, options); + } +} + +class Service extends ElectroDB.Service {} + +const createSchema = ElectroDB.createSchema; + +const createCustomAttribute = ElectroDB.createCustomAttribute; + +const CustomAttributeType = ElectroDB.CustomAttributeType; + +window.ElectroDB = { + Entity, + Service, + configure, + clearScreen, + printMessage, + printToScreen, + createSchema, + createCustomAttribute, + CustomAttributeType, +}; + +},{"../index":1}],11:[function(require,module,exports){ +const { + QueryTypes, + MethodTypes, + ItemOperations, + ExpressionTypes, + TransactionCommitSymbol, + TransactionOperations, + TerminalOperation, + KeyTypes, + IndexTypes, + UpsertOperations, + ComparisonTypes, +} = require("./types"); +const { + AttributeOperationProxy, + UpdateOperations, + FilterOperationNames, +} = require("./operations"); +const { UpdateExpression } = require("./update"); +const { FilterExpression } = require("./where"); +const v = require("./validations"); +const e = require("./errors"); +const u = require("./util"); + +function handleNonIsolatedCollection( + entity, + state, + collection = "", + facets /* istanbul ignore next */ = {}, +) { + if (state.getError() !== null) { + return state; + } + try { + const { pk, sk } = state.getCompositeAttributes(); + return state + .setMethod(MethodTypes.query) + .setCollection(collection) + .setPK(entity._expectFacets(facets, pk)) + .ifSK(() => { + const { composites, unused } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + state.setSK(composites); + state.beforeBuildParams(({ options, state }) => { + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + + if ( + options.compare === ComparisonTypes.attributes || + options.compare === ComparisonTypes.v2 + ) { + if ( + !entity.model.indexes[accessPattern].sk.isFieldRef && + sk.length > 1 + ) { + state.filterProperties(FilterOperationNames.eq, { + ...unused, + ...composites, + }); + } + } + }); + }) + .whenOptions(({ options, state }) => { + if (!options.ignoreOwnership && !state.getParams()) { + state.query.options.expressions.names = { + ...state.query.options.expressions.names, + ...state.query.options.identifiers.names, + }; + state.query.options.expressions.values = { + ...state.query.options.expressions.values, + ...state.query.options.identifiers.values, + }; + state.query.options.expressions.expression = + state.query.options.expressions.expression.length > 1 + ? `(${state.query.options.expressions.expression}) AND ${state.query.options.identifiers.expression}` + : `${state.query.options.identifiers.expression}`; + } + }); + } catch (err) { + state.setError(err); + return state; + } +} + +const methodChildren = { + upsert: [ + "upsertSet", + "upsertAppend", + "upsertAdd", + "go", + "params", + "upsertSubtract", + "commit", + "upsertIfNotExists", + "where", + ], + update: [ + "data", + "set", + "append", + "add", + "updateRemove", + "updateDelete", + "go", + "params", + "subtract", + "commit", + "composite", + "ifNotExists", + "where", + ], + put: ["where", "params", "go", "commit"], + del: ["where", "params", "go", "commit"], +}; + +function batchAction(action, type, entity, state, payload) { + if (state.getError() !== null) { + return state; + } + try { + state.setMethod(type); + for (let facets of payload) { + let batchState = action(entity, state.createSubState(), facets); + if (batchState.getError() !== null) { + throw batchState.getError(); + } + } + return state; + } catch (err) { + state.setError(err); + return state; + } +} + +let clauses = { + index: { + name: "index", + children: [ + "check", + "get", + "delete", + "update", + "query", + "upsert", + "put", + "scan", + "collection", + "clusteredCollection", + "compositeCollection", + "create", + "remove", + "patch", + "batchPut", + "batchDelete", + "batchGet", + ], + }, + compositeCollection: { + name: "compositeCollection", + action( + entity, + state, + collection = "", + facets /* istanbul ignore next */ = {}, + ) { + return handleNonIsolatedCollection( + entity, + state.setType(QueryTypes.composite_collection), + collection, + facets, + ); + }, + children: ["between", "gte", "gt", "lte", "lt", "begins", "params", "go"], + }, + clusteredCollection: { + name: "clusteredCollection", + action( + entity, + state, + collection = "", + facets /* istanbul ignore next */ = {}, + ) { + return handleNonIsolatedCollection( + entity, + state.setType(QueryTypes.clustered_collection), + collection, + facets, + ); + }, + children: ["between", "gte", "gt", "lte", "lt", "begins", "params", "go"], + }, + collection: { + name: "collection", + /* istanbul ignore next */ + action( + entity, + state, + collection = "", + facets /* istanbul ignore next */ = {}, + ) { + if (state.getError() !== null) { + return state; + } + try { + const { pk, sk } = state.getCompositeAttributes(); + return state + .setType(QueryTypes.collection) + .setMethod(MethodTypes.query) + .setCollection(collection) + .setPK(entity._expectFacets(facets, pk)) + .whenOptions(({ options, state }) => { + if (!options.ignoreOwnership && !state.getParams()) { + state.query.options.expressions.names = { + ...state.query.options.expressions.names, + ...state.query.options.identifiers.names, + }; + state.query.options.expressions.values = { + ...state.query.options.expressions.values, + ...state.query.options.identifiers.values, + }; + state.query.options.expressions.expression = + state.query.options.expressions.expression.length > 1 + ? `(${state.query.options.expressions.expression}) AND ${state.query.options.identifiers.expression}` + : `${state.query.options.identifiers.expression}`; + } + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["params", "go"], + }, + scan: { + name: "scan", + action(entity, state, config) { + if (state.getError() !== null) { + return state; + } + try { + return state + .setMethod(MethodTypes.scan) + .whenOptions(({ state, options }) => { + if (!options.ignoreOwnership && !state.getParams()) { + state.unsafeApplyFilter( + {}, + FilterOperationNames.eq, + entity.identifiers.entity, + entity.getName(), + ); + state.unsafeApplyFilter( + {}, + FilterOperationNames.eq, + entity.identifiers.version, + entity.getVersion(), + ); + } + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["params", "go"], + }, + get: { + name: "get", + /* istanbul ignore next */ + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + const { pk, sk } = state.getCompositeAttributes(); + const { composites } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + return state + .setMethod(MethodTypes.get) + .setType(QueryTypes.eq) + .setPK(entity._expectFacets(facets, pk)) + .ifSK(() => { + entity._expectFacets(facets, sk); + state.setSK(composites); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["params", "go", "commit"], + }, + check: { + name: "check", + action(...params) { + return clauses.get.action(...params).setMethod(MethodTypes.check); + }, + children: ["commit"], + }, + batchGet: { + name: "batchGet", + action: (entity, state, payload) => + batchAction( + clauses.get.action, + MethodTypes.batchGet, + entity, + state, + payload, + ), + children: ["params", "go"], + }, + batchDelete: { + name: "batchDelete", + action: (entity, state, payload) => + batchAction( + clauses.delete.action, + MethodTypes.batchWrite, + entity, + state, + payload, + ), + children: ["params", "go"], + }, + delete: { + name: "delete", + /* istanbul ignore next */ + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + const { pk, sk } = state.getCompositeAttributes(); + const pkComposite = entity._expectFacets(facets, pk); + state.addOption("_includeOnResponseItem", pkComposite); + return state + .setMethod(MethodTypes.delete) + .setType(QueryTypes.eq) + .setPK(pkComposite) + .ifSK(() => { + entity._expectFacets(facets, sk); + const skComposite = state.buildQueryComposites(facets, sk); + state.setSK(skComposite); + state.addOption("_includeOnResponseItem", { + ...skComposite, + ...pkComposite, + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["where", "params", "go", "commit"], + }, + remove: { + name: "remove", + /* istanbul ignore next */ + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + const attributes = state.getCompositeAttributes(); + const filter = state.query.filter[ExpressionTypes.ConditionExpression]; + const { pk, sk } = entity._getPrimaryIndexFieldNames(); + filter.unsafeSet({}, FilterOperationNames.exists, pk); + if (sk) { + filter.unsafeSet({}, FilterOperationNames.exists, sk); + } + const pkComposite = entity._expectFacets(facets, attributes.pk); + state.addOption("_includeOnResponseItem", pkComposite); + return state + .setMethod(MethodTypes.delete) + .setType(QueryTypes.eq) + .setPK(pkComposite) + .ifSK(() => { + entity._expectFacets(facets, attributes.sk); + const skComposite = state.buildQueryComposites( + facets, + attributes.sk, + ); + state.setSK(skComposite); + state.addOption("_includeOnResponseItem", { + ...skComposite, + ...pkComposite, + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.del, + }, + upsert: { + name: "upsert", + action(entity, state, payload = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state + .setMethod(MethodTypes.upsert) + .setType(QueryTypes.eq) + .applyUpsert(UpsertOperations.set, payload) + .beforeBuildParams(({ state }) => { + const { upsert, update, updateProxy } = state.query; + + state.query.update.set(entity.identifiers.entity, entity.getName()); + state.query.update.set( + entity.identifiers.version, + entity.getVersion(), + ); + + // only "set" data is used to make keys + const setData = {}; + const nonSetData = {}; + let allData = {}; + + for (const name in upsert.data) { + const { operation, value } = upsert.data[name]; + allData[name] = value; + if (operation === UpsertOperations.set) { + setData[name] = value; + } else { + nonSetData[name] = value; + } + } + + const upsertData = entity.model.schema.checkCreate({ ...allData }); + const attributes = state.getCompositeAttributes(); + const pkComposite = entity._expectFacets(upsertData, attributes.pk); + + state + .addOption("_includeOnResponseItem", pkComposite) + .setPK(pkComposite) + .ifSK(() => { + entity._expectFacets(upsertData, attributes.sk); + const skComposite = entity._buildQueryFacets( + upsertData, + attributes.sk, + ); + state.setSK(skComposite); + state.addOption("_includeOnResponseItem", { + ...skComposite, + ...pkComposite, + }); + }); + + const appliedData = entity.model.schema.applyAttributeSetters({ + ...upsertData, + }); + + const onlySetAppliedData = {}; + const nonSetAppliedData = {}; + for (const name in appliedData) { + const value = appliedData[name]; + const isSetOperation = setData[name] !== undefined; + const cameFromApplyingSetters = allData[name] === undefined; + const isNotUndefined = appliedData[name] !== undefined; + const applyAsSet = isSetOperation || cameFromApplyingSetters; + if (applyAsSet && isNotUndefined) { + onlySetAppliedData[name] = value; + } else { + nonSetAppliedData[name] = value; + } + } + + // we build this above, and set them to state, but use it here, not ideal but + // the way it worked out so that this could be wrapped in beforeBuildParams + const { pk } = state.query.keys; + const sk = state.query.keys.sk[0]; + + const { + updatedKeys, + setAttributes, + indexKey, + deletedKeys = [], + } = entity._getPutKeys(pk, sk && sk.facets, onlySetAppliedData); + + for (const deletedKey of deletedKeys) { + state.query.update.remove(deletedKey); + } + + // calculated here but needs to be used when building the params + upsert.indexKey = indexKey; + + // only "set" data is used to make keys + const setFields = entity.model.schema.translateToFields(setAttributes); + + // add the keys impacted except for the table index keys; they are upserted + // automatically by dynamo + for (const key in updatedKeys) { + const value = updatedKeys[key]; + if (indexKey[key] === undefined) { + setFields[key] = value; + } else { + delete setFields[key]; + } + } + + entity._maybeApplyUpsertUpdate({ + fields: Object.entries(setFields), + operation: UpsertOperations.set, + updateProxy, + update, + }); + + for (const name in nonSetData) { + const value = appliedData[name]; + if (value === undefined || upsert.data[name] === undefined) { + continue; + } + + const { operation } = upsert.data[name]; + const fields = entity.model.schema.translateToFields({ + [name]: value, + }); + entity._maybeApplyUpsertUpdate({ + fields: Object.entries(fields), + updateProxy, + operation, + update, + }); + } + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + put: { + name: "put", + /* istanbul ignore next */ + action(entity, state, payload = {}) { + if (state.getError() !== null) { + return state; + } + try { + let record = entity.model.schema.checkCreate({ ...payload }); + const attributes = state.getCompositeAttributes(); + return state + .setMethod(MethodTypes.put) + .setType(QueryTypes.eq) + .applyPut(record) + .setPK(entity._expectFacets(record, attributes.pk)) + .ifSK(() => { + entity._expectFacets(record, attributes.sk); + state.setSK(state.buildQueryComposites(record, attributes.sk)); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.put, + }, + batchPut: { + name: "batchPut", + action: (entity, state, payload) => + batchAction( + clauses.put.action, + MethodTypes.batchWrite, + entity, + state, + payload, + ), + children: ["params", "go"], + }, + create: { + name: "create", + action(entity, state, payload) { + if (state.getError() !== null) { + return state; + } + try { + let record = entity.model.schema.checkCreate({ ...payload }); + const attributes = state.getCompositeAttributes(); + const filter = state.query.filter[ExpressionTypes.ConditionExpression]; + const { pk, sk } = entity._getPrimaryIndexFieldNames(); + filter.unsafeSet({}, FilterOperationNames.notExists, pk); + if (sk) { + filter.unsafeSet({}, FilterOperationNames.notExists, sk); + } + return state + .setMethod(MethodTypes.put) + .setType(QueryTypes.eq) + .applyPut(record) + .setPK(entity._expectFacets(record, attributes.pk)) + .ifSK(() => { + entity._expectFacets(record, attributes.sk); + state.setSK(state.buildQueryComposites(record, attributes.sk)); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.put, + }, + patch: { + name: "patch", + action(entity, state, facets) { + if (state.getError() !== null) { + return state; + } + try { + const attributes = state.getCompositeAttributes(); + const filter = state.query.filter[ExpressionTypes.ConditionExpression]; + const { pk, sk } = entity._getPrimaryIndexFieldNames(); + filter.unsafeSet({}, FilterOperationNames.exists, pk); + if (sk) { + filter.unsafeSet({}, FilterOperationNames.exists, sk); + } + const pkComposite = entity._expectFacets(facets, attributes.pk); + state.addOption("_includeOnResponseItem", pkComposite); + return state + .setMethod(MethodTypes.update) + .setType(QueryTypes.eq) + .setPK(pkComposite) + .ifSK(() => { + entity._expectFacets(facets, attributes.sk); + const skComposite = state.buildQueryComposites( + facets, + attributes.sk, + ); + state.setSK(skComposite); + state.addOption("_includeOnResponseItem", { + ...skComposite, + ...pkComposite, + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + update: { + name: "update", + action(entity, state, facets) { + if (state.getError() !== null) { + return state; + } + try { + const attributes = state.getCompositeAttributes(); + const pkComposite = entity._expectFacets(facets, attributes.pk); + state.addOption("_includeOnResponseItem", pkComposite); + return state + .setMethod(MethodTypes.update) + .setType(QueryTypes.eq) + .setPK(pkComposite) + .ifSK(() => { + entity._expectFacets(facets, attributes.sk); + const skComposite = state.buildQueryComposites( + facets, + attributes.sk, + ); + state.setSK(skComposite); + state.addOption("_includeOnResponseItem", { + ...pkComposite, + ...skComposite, + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + data: { + name: "data", + action(entity, state, cb) { + if (state.getError() !== null) { + return state; + } + try { + state.query.updateProxy.invokeCallback(cb); + for (const path of Object.keys(state.query.update.refs)) { + const operation = state.query.update.impacted[path]; + const attribute = state.query.update.refs[path]; + // note: keyValue will be empty if the user used `name`/`value` operations + // because it becomes hard to know how they are used and which attribute + // should validate the change. This is an edge case however, this change + // still improves on the existing implementation. + const keyValue = state.query.update.paths[path] || {}; + if (!attribute) { + throw new e.ElectroAttributeValidationError( + path, + `Attribute "${path}" does not exist on model.`, + ); + } + + entity.model.schema.checkOperation( + attribute, + operation, + keyValue.value, + ); + } + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + set: { + name: "set", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.set, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + upsertSet: { + name: "set", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data, { allowReadOnly: true }); + state.query.upsert.addData(UpsertOperations.set, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + composite: { + name: "composite", + action(entity, state, composites = {}) { + if (state.getError() !== null) { + return state; + } + try { + for (const attrName in composites) { + // todo: validate attrName is facet + if (entity.model.facets.byAttr[attrName]) { + const wasSet = state.query.update.addComposite( + attrName, + composites[attrName], + ); + if (!wasSet) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateUpdateCompositesProvided, + `The composite attribute ${attrName} has been provided more than once with different values. Remove the duplication before running again`, + ); + } + state.applyCondition( + FilterOperationNames.eq, + attrName, + composites[attrName], + ); + } + } + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + append: { + name: "append", + action(entity, state, data = {}) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.append, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + ifNotExists: { + name: "ifNotExists", + action(entity, state, data = {}) { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.ifNotExists, data); + return state; + }, + children: methodChildren.update, + }, + upsertIfNotExists: { + name: "ifNotExists", + action(entity, state, data = {}) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data, { allowReadOnly: true }); + state.query.upsert.addData(UpsertOperations.ifNotExists, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + upsertAppend: { + name: "append", + action(entity, state, data = {}) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data, { allowReadOnly: true }); + state.query.upsert.addData(UpsertOperations.append, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + updateRemove: { + name: "remove", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + if (!Array.isArray(data)) { + throw new Error("Update method 'remove' expects type Array"); + } + entity.model.schema.checkRemove(data); + state.query.updateProxy.fromArray(ItemOperations.remove, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + updateDelete: { + name: "delete", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.delete, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + add: { + name: "add", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.add, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + upsertAdd: { + name: "add", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data, { allowReadOnly: true }); + state.query.upsert.addData(UpsertOperations.add, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + upsertSubtract: { + name: "subtract", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data, { allowReadOnly: true }); + state.query.upsert.addData(UpsertOperations.subtract, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.upsert, + }, + subtract: { + name: "subtract", + action(entity, state, data) { + if (state.getError() !== null) { + return state; + } + try { + entity.model.schema.checkUpdate(data); + state.query.updateProxy.fromObject(ItemOperations.subtract, data); + return state; + } catch (err) { + state.setError(err); + return state; + } + }, + children: methodChildren.update, + }, + query: { + name: "query", + action(entity, state, facets, options = {}) { + if (state.getError() !== null) { + return state; + } + try { + state.addOption("_isPagination", true); + const { pk, sk } = state.getCompositeAttributes(); + return state + .setMethod(MethodTypes.query) + .setType(QueryTypes.is) + .setPK(entity._expectFacets(facets, pk)) + .ifSK(() => { + const { composites, unused } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + state.setSK(state.buildQueryComposites(facets, sk)); + + state.whenOptions(({ options, state }) => { + if ( + options.compare === ComparisonTypes.attributes || + options.compare === ComparisonTypes.v2 + ) { + if (sk.length > 1) { + state.filterProperties(FilterOperationNames.eq, { + ...unused, + ...composites, + }); + } + } + + if ( + state.query.options.indexType === IndexTypes.clustered && + Object.keys(composites).length < sk.length && + !options.ignoreOwnership && + !state.getParams() + ) { + state + .unsafeApplyFilter( + {}, + FilterOperationNames.eq, + entity.identifiers.entity, + entity.getName(), + ) + .unsafeApplyFilter( + {}, + FilterOperationNames.eq, + entity.identifiers.version, + entity.getVersion(), + ); + } + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["between", "gte", "gt", "lte", "lt", "begins", "params", "go"], + }, + between: { + name: "between", + action(entity, state, startingFacets = {}, endingFacets = {}) { + if (state.getError() !== null) { + return state; + } + try { + const { pk, sk } = state.getCompositeAttributes(); + const endingSk = state.identifyCompositeAttributes( + endingFacets, + sk, + pk, + ); + const startingSk = state.identifyCompositeAttributes( + startingFacets, + sk, + pk, + ); + + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + + return state + .setType(QueryTypes.and) + .setSK(endingSk.composites) + .setType(QueryTypes.between) + .setSK(startingSk.composites) + .beforeBuildParams(({ options, state }) => { + if ( + options.compare === ComparisonTypes.attributes || + options.compare === ComparisonTypes.v2 + ) { + if (!entity.model.indexes[accessPattern].sk.isFieldRef) { + state.filterProperties( + FilterOperationNames.lte, + endingSk.composites, + { asPrefix: true }, + ); + } + if (options.compare === ComparisonTypes.attributes) { + if (!entity.model.indexes[accessPattern].sk.isFieldRef) { + state.filterProperties( + FilterOperationNames.gte, + startingSk.composites, + { asPrefix: true }, + ); + } + } + } + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + begins: { + name: "begins", + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state.setType(QueryTypes.begins).ifSK((state) => { + const attributes = state.getCompositeAttributes(); + state.setSK(state.buildQueryComposites(facets, attributes.sk)); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + gt: { + name: "gt", + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state.setType(QueryTypes.gt).ifSK((state) => { + const { pk, sk } = state.getCompositeAttributes(); + const { composites } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + state.setSK(composites); + state.beforeBuildParams(({ options, state }) => { + if ( + options.compare === ComparisonTypes.attributes || + options.compare === ComparisonTypes.v2 + ) { + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + + if (!entity.model.indexes[accessPattern].sk.isFieldRef) { + state.filterProperties(FilterOperationNames.gt, composites, { + asPrefix: true, + }); + } + } + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + gte: { + name: "gte", + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state.setType(QueryTypes.gte).ifSK((state) => { + const attributes = state.getCompositeAttributes(); + state.setSK(state.buildQueryComposites(facets, attributes.sk)); + state.beforeBuildParams(({ options, state }) => { + const { composites } = state.identifyCompositeAttributes( + facets, + attributes.sk, + attributes.pk, + ); + if (options.compare === ComparisonTypes.attributes) { + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + if ( + !entity.model.indexes[accessPattern].sk.isFieldRef && + attributes.sk.length > 1 + ) { + state.filterProperties(FilterOperationNames.gte, composites, { + asPrefix: true, + }); + } + } + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + lt: { + name: "lt", + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state.setType(QueryTypes.lt).ifSK((state) => { + const { pk, sk } = state.getCompositeAttributes(); + const { composites } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + state.setSK(composites); + state.beforeBuildParams(({ options, state }) => { + if (options.compare === ComparisonTypes.attributes) { + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + if (!entity.model.indexes[accessPattern].sk.isFieldRef) { + state.filterProperties(FilterOperationNames.lt, composites, { + asPrefix: true, + }); + } + } + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + lte: { + name: "lte", + action(entity, state, facets = {}) { + if (state.getError() !== null) { + return state; + } + try { + return state.setType(QueryTypes.lte).ifSK((state) => { + const { pk, sk } = state.getCompositeAttributes(); + const { composites } = state.identifyCompositeAttributes( + facets, + sk, + pk, + ); + state.setSK(composites); + + state.beforeBuildParams(({ options, state }) => { + if ( + options.compare === ComparisonTypes.attributes || + options.compare === ComparisonTypes.v2 + ) { + const accessPattern = + entity.model.translations.indexes.fromIndexToAccessPattern[ + state.query.index + ]; + if (!entity.model.indexes[accessPattern].sk.isFieldRef) { + state.filterProperties(FilterOperationNames.lte, composites, { + asPrefix: true, + }); + } + } + }); + }); + } catch (err) { + state.setError(err); + return state; + } + }, + children: ["go", "params"], + }, + commit: { + name: "commit", + action(entity, state, options) { + if (state.getError() !== null) { + throw state.error; + } + + const results = clauses.params.action(entity, state, { + ...options, + _returnOptions: true, + _isTransaction: true, + }); + + const method = TransactionOperations[state.query.method]; + if (!method) { + throw new Error("Invalid commit method"); + } + + return { + [method]: results.params, + [TransactionCommitSymbol]: () => { + return { + entity, + }; + }, + }; + }, + children: [], + }, + params: { + name: "params", + action(entity, state, options = {}) { + if (state.getError() !== null) { + throw state.error; + } + try { + if ( + !v.isStringHasLength(options.table) && + !v.isStringHasLength(entity.getTableName()) + ) { + throw new e.ElectroError( + e.ErrorCodes.MissingTable, + `Table name not defined. Table names must be either defined on the model, instance configuration, or as a query option.`, + ); + } + const method = state.getMethod(); + const normalizedOptions = entity._normalizeExecutionOptions({ + provided: [state.getOptions(), state.query.options, options], + context: { + operation: options._isTransaction + ? MethodTypes.transactWrite + : undefined, + state, + }, + }); + + state.applyWithOptions(normalizedOptions); + state.applyBeforeBuildParams(normalizedOptions); + + let results; + switch (method) { + case MethodTypes.query: { + results = entity._queryParams(state, normalizedOptions); + break; + } + case MethodTypes.batchWrite: { + results = entity._batchWriteParams(state, normalizedOptions); + break; + } + case MethodTypes.batchGet: { + results = entity._batchGetParams(state, normalizedOptions); + break; + } + default: { + results = entity._params(state, normalizedOptions); + break; + } + } + + if ( + method === MethodTypes.update && + results.ExpressionAttributeValues && + Object.keys(results.ExpressionAttributeValues).length === 0 + ) { + // An update that only does a `remove` operation would result in an empty object + // todo: change the getValues() method to return undefined in this case (would potentially require a more generous refactor) + delete results.ExpressionAttributeValues; + } + + if (options._returnOptions) { + results = { + params: results, + options: normalizedOptions, + }; + } + + state.setParams(results); + + return results; + } catch (err) { + throw err; + } + }, + children: [], + }, + go: { + name: "go", + action(entity, state, options = {}) { + if (state.getError() !== null) { + return Promise.reject(state.error); + } + try { + if (entity.client === undefined && options.client === undefined) { + throw new e.ElectroError( + e.ErrorCodes.NoClientDefined, + "No client defined on model or provided in query options", + ); + } + options.terminalOperation = TerminalOperation.go; + const paramResults = clauses.params.action(entity, state, { + ...options, + _returnOptions: true, + }); + return entity.go( + state.getMethod(), + paramResults.params, + paramResults.options, + ); + } catch (err) { + return Promise.reject(err); + } + }, + children: [], + }, +}; + +class ChainState { + constructor({ + index = "", + compositeAttributes = {}, + attributes = {}, + hasSortKey = false, + options = {}, + parentState = null, + } = {}) { + const update = new UpdateExpression({ prefix: "_u" }); + this.parentState = parentState; + this.error = null; + this.attributes = attributes; + this.query = { + collection: "", + index: index, + type: "", + method: "", + facets: { ...compositeAttributes }, + update, + updateProxy: new AttributeOperationProxy({ + builder: update, + attributes: attributes, + operations: UpdateOperations, + }), + put: { + data: {}, + }, + upsert: { + data: {}, + indexKey: null, + addData(operation = UpsertOperations.set, data = {}) { + for (const name of Object.keys(data)) { + const value = data[name]; + this.data[name] = { + operation, + value, + }; + } + }, + getData(operationFilter) { + const results = {}; + for (const name in this.data) { + const { operation, value } = this.data[name]; + if (!operationFilter || operationFilter === operation) { + results[name] = value; + } + } + + return results; + }, + }, + keys: { + provided: [], + pk: {}, + sk: [], + }, + filter: { + [ExpressionTypes.ConditionExpression]: new FilterExpression(), + [ExpressionTypes.FilterExpression]: new FilterExpression(), + }, + options, + }; + this.subStates = []; + this.hasSortKey = hasSortKey; + this.prev = null; + this.self = null; + this.params = null; + this.applyAfterOptions = []; + this.beforeBuildParamsOperations = []; + this.beforeBuildParamsHasRan = false; + } + + getParams() { + return this.params; + } + + setParams(params) { + if (params) { + this.params = params; + } + } + + init(entity, allClauses, currentClause) { + let current = {}; + for (let child of currentClause.children) { + const name = allClauses[child].name; + current[name] = (...args) => { + this.prev = this.self; + this.self = child; + let results = allClauses[child].action(entity, this, ...args); + if (allClauses[child].children.length) { + return this.init(entity, allClauses, allClauses[child]); + } else { + return results; + } + }; + } + return current; + } + + getMethod() { + return this.query.method; + } + + getOptions() { + return this.query.options; + } + + addOption(key, value) { + this.query.options[key] = value; + return this; + } + + _appendProvided(type, attributes) { + const newAttributes = Object.keys(attributes).map((attribute) => { + return { + type, + attribute, + }; + }); + return u.getUnique(this.query.keys.provided, newAttributes); + } + + setPK(attributes) { + this.query.keys.pk = attributes; + this.query.keys.provided = this._appendProvided(KeyTypes.pk, attributes); + + return this; + } + + ifSK(cb) { + if (this.hasSortKey) { + cb(this); + } + return this; + } + + getCompositeAttributes() { + return this.query.facets; + } + + buildQueryComposites(provided, definition) { + return definition + .map((name) => [name, provided[name]]) + .reduce((result, [name, value]) => { + if (value !== undefined) { + result[name] = value; + } + return result; + }, {}); + } + + identifyCompositeAttributes(provided, defined, skip) { + // todo: make sure attributes are valid + const composites = {}; + const unused = {}; + const definedSet = new Set(defined || []); + const skipSet = new Set(skip || []); + for (const key of Object.keys(provided)) { + const value = provided[key]; + if (definedSet.has(key)) { + composites[key] = value; + } else if (skipSet.has(key)) { + continue; + } else { + unused[key] = value; + } + } + + return { + composites, + unused, + }; + } + + applyFilter(operation, name, values, filterOptions) { + if ( + FilterOperationNames[operation] !== undefined && + name !== undefined && + values !== undefined + ) { + const attribute = this.attributes[name]; + if (attribute !== undefined) { + this.unsafeApplyFilter( + filterOptions, + operation, + attribute.field, + values, + ); + } + } + return this; + } + + applyCondition(operation, name, ...values) { + if ( + FilterOperationNames[operation] !== undefined && + name !== undefined && + values.length > 0 + ) { + const attribute = this.attributes[name]; + if (attribute !== undefined) { + const filter = this.query.filter[ExpressionTypes.ConditionExpression]; + filter.unsafeSet({}, operation, attribute.field, ...values); + } + } + return this; + } + + unsafeApplyFilter(filterOptions = {}, operation, name, values) { + if ( + (FilterOperationNames[operation] !== undefined) & (name !== undefined) && + values !== undefined + ) { + const filter = this.query.filter[ExpressionTypes.FilterExpression]; + filter.unsafeSet(filterOptions, operation, name, values); + } + return this; + } + + filterProperties(operation, obj = {}, filterOptions = {}) { + for (const property in obj) { + const value = obj[property]; + if (value !== undefined) { + this.applyFilter(operation, property, value, filterOptions); + } + } + return this; + } + + setSK(attributes, type = this.query.type) { + if (this.hasSortKey) { + this.query.keys.sk.push({ + type: type, + facets: attributes, + }); + this.query.keys.provided = this._appendProvided(KeyTypes.sk, attributes); + } + return this; + } + + setType(type) { + if (!QueryTypes[type]) { + throw new Error(`Invalid query type: "${type}"`); + } + this.query.type = QueryTypes[type]; + return this; + } + + setMethod(method) { + if (!MethodTypes[method]) { + throw new Error(`Invalid method type: "${method}"`); + } + this.query.method = MethodTypes[method]; + return this; + } + + setCollection(collection) { + this.query.collection = collection; + return this; + } + + createSubState() { + let subState = new ChainState({ + parentState: this, + index: this.query.index, + attributes: this.attributes, + hasSortKey: this.hasSortKey, + options: this.query.options, + compositeAttributes: this.query.facets, + }); + this.subStates.push(subState); + return subState; + } + + getError() { + return this.error; + } + + setError(err) { + this.error = err; + if (this.parentState) { + this.parentState.setError(err); + } + } + + applyUpsert(operation = UpsertOperations.set, data = {}) { + this.query.upsert.addData(operation, data); + return this; + } + + applyPut(data = {}) { + this.query.put.data = { ...this.query.put.data, ...data }; + return this; + } + + whenOptions(fn) { + if (v.isFunction(fn)) { + this.applyAfterOptions.push((options) => { + fn({ options, state: this }); + }); + } + + return this; + } + + // these are ran before "beforeBuildParams" + applyWithOptions(options = {}) { + this.applyAfterOptions.forEach((fn) => fn(options)); + } + + beforeBuildParams(fn) { + if (v.isFunction(fn)) { + this.beforeBuildParamsOperations.push((options) => { + fn({ options, state: this }); + }); + } + return this; + } + + applyBeforeBuildParams(options = {}) { + if (!this.beforeBuildParamsHasRan) { + this.beforeBuildParamsHasRan = true; + this.beforeBuildParamsOperations.forEach((fn) => fn(options)); + } + } +} + +module.exports = { + clauses, + ChainState, +}; + +},{"./errors":15,"./operations":19,"./types":24,"./update":25,"./util":27,"./validations":28,"./where":29}],12:[function(require,module,exports){ +const lib = {} +const util = {} +const { isFunction } = require("./validations"); +const { ElectroError, ErrorCodes } = require("./errors"); +const { EntityIdentifiers } = require("./types"); +const DocumentClientVersions = { + v2: "v2", + v3: "v3", + electro: "electro", +}; +const unmarshallItem = (value) => { + const unmarshall = util.unmarshall || ((val) => val); + try { + value.Item = unmarshall(value.Item); + } catch (err) { + console.error("Internal Error: Failed to unmarshal input", err); + } + + return value; +}; + +const v3Methods = ["send"]; +const v2Methods = [ + "get", + "put", + "update", + "delete", + "batchWrite", + "batchGet", + "scan", + "query", + "createSet", + "transactWrite", + "transactGet", +]; +const supportedClientVersions = { + [DocumentClientVersions.v2]: v2Methods, + [DocumentClientVersions.v3]: v3Methods, +}; + +class DocumentClientV2Wrapper { + static init(client) { + return new DocumentClientV2Wrapper(client, lib); + } + + constructor(client, lib) { + this.client = client; + this.lib = lib; + this.__v = "v2"; + } + + _wrapRequest(makeRequest, signal) { + return { + promise: () => { + return new Promise((resolve, reject) => { + if (signal && signal.aborted) { + return reject( + new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ), + ); + } + + const request = makeRequest(); + + const onAbort = () => { + request.abort(); + reject( + new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ), + ); + }; + + if (signal) { + signal.addEventListener("abort", onAbort, { once: true }); + } + + request + .promise() + .then((result) => { + if (signal) { + signal.removeEventListener("abort", onAbort); + } + resolve(result); + }) + .catch((err) => { + if (signal) { + signal.removeEventListener("abort", onAbort); + } + reject(err); + }); + }); + }, + }; + } + + get(params, options = {}) { + return this._wrapRequest(() => this.client.get(params), options.abortSignal); + } + + put(params, options = {}) { + return this._wrapRequest(() => this.client.put(params), options.abortSignal); + } + + update(params, options = {}) { + return this._wrapRequest(() => this.client.update(params), options.abortSignal); + } + + delete(params, options = {}) { + return this._wrapRequest(() => this.client.delete(params), options.abortSignal); + } + + batchWrite(params, options = {}) { + return this._wrapRequest(() => this.client.batchWrite(params), options.abortSignal); + } + + batchGet(params, options = {}) { + return this._wrapRequest(() => this.client.batchGet(params), options.abortSignal); + } + + scan(params, options = {}) { + return this._wrapRequest(() => this.client.scan(params), options.abortSignal); + } + + query(params, options = {}) { + return this._wrapRequest(() => this.client.query(params), options.abortSignal); + } + + _transact(makeTransactionRequest, signal) { + return { + promise: () => { + return new Promise((resolve, reject) => { + if (signal && signal.aborted) { + return reject( + new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ), + ); + } + + const transactionRequest = makeTransactionRequest(); + let cancellationReasons; + transactionRequest.on("extractError", (response) => { + try { + cancellationReasons = JSON.parse( + response.httpResponse.body.toString(), + ).CancellationReasons; + } catch (err) {} + }); + + const onAbort = () => { + transactionRequest.abort(); + reject( + new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ), + ); + }; + + if (signal) { + signal.addEventListener("abort", onAbort, { once: true }); + } + + transactionRequest + .promise() + .then((result) => { + if (signal) { + signal.removeEventListener("abort", onAbort); + } + resolve(result); + }) + .catch((err) => { + if (signal) { + signal.removeEventListener("abort", onAbort); + } + if (err) { + if (Array.isArray(cancellationReasons)) { + resolve({ + canceled: cancellationReasons.map((reason) => { + if (reason.Item) { + return unmarshallItem(reason); + } + return reason; + }), + }); + } else { + reject(err); + } + } + }); + }); + }, + }; + } + + transactWrite(params, options = {}) { + return this._transact(() => this.client.transactWrite(params), options.abortSignal); + } + + transactGet(params, options = {}) { + return this._transact(() => this.client.transactGet(params), options.abortSignal); + } + + createSet(value, ...rest) { + if (Array.isArray(value)) { + return this.client.createSet(value, ...rest); + } else { + return this.client.createSet([value], ...rest); + } + } +} + +class DocumentClientV3Wrapper { + static init(client) { + return new DocumentClientV3Wrapper(client, lib); + } + + constructor(client, lib) { + this.client = client; + this.lib = lib; + this.__v = "v3"; + } + + promiseWrap(fn, signal) { + return { + promise: async () => { + if (signal && signal.aborted) { + throw new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ); + } + try { + return await fn(); + } catch (err) { + if (signal && signal.aborted) { + throw new ElectroError( + ErrorCodes.OperationAborted, + "The operation was aborted", + ); + } + throw err; + } + }, + }; + } + + get(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.GetCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + put(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.PutCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + update(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.UpdateCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + delete(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.DeleteCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + batchWrite(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.BatchWriteCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + batchGet(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.BatchGetCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + scan(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.ScanCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + query(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.QueryCommand(params); + return this.client.send(command, { abortSignal: options.abortSignal }); + }, options.abortSignal); + } + + transactWrite(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.TransactWriteCommand(params); + return this.client + .send(command, { abortSignal: options.abortSignal }) + .then((result) => { + return result; + }) + .catch((err) => { + if (err.CancellationReasons) { + return { + canceled: err.CancellationReasons.map((reason) => { + if (reason.Item) { + return unmarshallItem(reason); + } + return reason; + }), + }; + } + throw err; + }); + }, options.abortSignal); + } + transactGet(params, options = {}) { + return this.promiseWrap(() => { + const command = new this.lib.TransactGetCommand(params); + return this.client + .send(command, { abortSignal: options.abortSignal }) + .then((result) => { + return result; + }) + .catch((err) => { + if (err.CancellationReasons) { + return { + canceled: err.CancellationReasons.map((reason) => { + if (reason.Item) { + return unmarshallItem(reason); + } + return reason; + }), + }; + } + throw err; + }); + }, options.abortSignal); + } + createSet(value) { + if (Array.isArray(value)) { + return new Set(value); + } else { + return new Set([value]); + } + } +} + +function identifyClientVersion(client = {}) { + if ( + client instanceof DocumentClientV3Wrapper || + client instanceof DocumentClientV2Wrapper + ) { + return DocumentClientVersions.electro; + } + for (const [version, methods] of Object.entries(supportedClientVersions)) { + const hasMethods = methods.every((method) => { + return method in client && isFunction(client[method]); + }); + if (hasMethods) { + return version; + } + } +} + +function normalizeClient(client) { + if (client === undefined) return client; + const version = identifyClientVersion(client); + switch (version) { + case DocumentClientVersions.v3: + return DocumentClientV3Wrapper.init(client); + case DocumentClientVersions.v2: + return DocumentClientV2Wrapper.init(client); + case DocumentClientVersions.electro: + return client; + default: + throw new ElectroError( + ErrorCodes.InvalidClientProvided, + "Invalid DynamoDB Document Client provided. ElectroDB supports the v2 and v3 DynamoDB Document Clients from the aws-sdk", + ); + } +} + +function normalizeConfig(config = {}) { + const identifiers = config.identifiers || {}; + return { + ...config, + client: normalizeClient(config.client), + identifiers: { + entity: identifiers.entity || EntityIdentifiers.entity, + version: identifiers.version || EntityIdentifiers.version + } + }; +} + +module.exports = { + util, + v2Methods, + v3Methods, + normalizeClient, + normalizeConfig, + identifyClientVersion, + DocumentClientVersions, + supportedClientVersions, + DocumentClientV3Wrapper, + DocumentClientV2Wrapper, +}; + +},{"./errors":15,"./types":24,"./validations":28}],13:[function(require,module,exports){ +function createConversions(entity) { + const conversions = { + fromComposite: { + toKeys: (composite, options = {}) => + entity._fromCompositeToKeys({ provided: composite }, options), + toCursor: (composite) => + entity._fromCompositeToCursor( + { provided: composite }, + { strict: "all" }, + ), + }, + fromKeys: { + toCursor: (keys) => entity._fromKeysToCursor({ provided: keys }, {}), + toComposite: (keys) => entity._fromKeysToComposite({ provided: keys }), + }, + fromCursor: { + toKeys: (cursor) => entity._fromCursorToKeys({ provided: cursor }), + toComposite: (cursor) => + entity._fromCursorToComposite({ provided: cursor }), + }, + byAccessPattern: {}, + }; + + for (let accessPattern in entity.model.indexes) { + let index = entity.model.indexes[accessPattern].index; + conversions.byAccessPattern[accessPattern] = { + fromKeys: { + toCursor: (keys) => + entity._fromKeysToCursorByIndex({ indexName: index, provided: keys }), + toComposite: (keys) => + entity._fromKeysToCompositeByIndex({ + indexName: index, + provided: keys, + }), + }, + fromCursor: { + toKeys: (cursor) => + entity._fromCursorToKeysByIndex({ + indexName: index, + provided: cursor, + }), + toComposite: (cursor) => + entity._fromCursorToCompositeByIndex({ + indexName: index, + provided: cursor, + }), + }, + fromComposite: { + toCursor: (composite) => + entity._fromCompositeToCursorByIndex( + { indexName: index, provided: composite }, + { strict: "all" }, + ), + toKeys: (composite, options = {}) => + entity._fromCompositeToKeysByIndex( + { indexName: index, provided: composite }, + options, + ), + }, + }; + } + + return conversions; +} + +module.exports = { + createConversions, +}; + +},{}],14:[function(require,module,exports){ +"use strict"; +const { Schema } = require("./schema"); +const { + AllPages, + KeyCasing, + DefaultKeyCasing, + TableIndex, + FormatToReturnValues, + ReturnValues, + EntityVersions, + ItemOperations, + UnprocessedTypes, + Pager, + ElectroInstance, + KeyTypes, + QueryTypes, + MethodTypes, + Comparisons, + ExpressionTypes, + ModelVersions, + ElectroInstanceTypes, + MaxBatchItems, + TerminalOperation, + ResultOrderOption, + ResultOrderParam, + IndexTypes, + KeyAttributesComparisons, + MethodTypeTranslation, + TransactionCommitSymbol, + CastKeyOptions, + ComparisonTypes, + DataOptions, + IndexProjectionOptions, +} = require("./types"); +const { FilterFactory } = require("./filters"); +const { FilterOperations, ExpressionState, formatExpressionName } = require("./operations"); +const { WhereFactory } = require("./where"); +const { clauses, ChainState } = require("./clauses"); +const { EventManager } = require("./events"); +const validations = require("./validations"); +const c = require("./client"); +const u = require("./util"); +const e = require("./errors"); +const v = require("./validations"); + +const ImpactedIndexTypeSource = { + composite: "composite", + provided: "provided", +}; + +class Entity { + constructor(model, config = {}) { + this.config = c.normalizeConfig(config); + this.identifiers = this.config.identifiers; + this.client = this.config.client; + this.eventManager = new EventManager({ + listeners: this.config.listeners, + }); + this.eventManager.add(this.config.logger); + this._validateModel(model); + this.version = EntityVersions.v1; + this.model = this._parseModel(model, this.config); + /** start beta/v1 condition **/ + this.config.table = config.table || model.table; + /** end beta/v1 condition **/ + this._filterBuilder = new FilterFactory( + this.model.schema.attributes, + FilterOperations, + ); + this._whereBuilder = new WhereFactory( + this.model.schema.attributes, + FilterOperations, + ); + this._clausesWithFilters = this._filterBuilder.injectFilterClauses( + clauses, + this.model.filters, + ); + this._clausesWithFilters = this._whereBuilder.injectWhereClauses( + this._clausesWithFilters, + ); + + this.query = {}; + for (let accessPattern in this.model.indexes) { + let index = this.model.indexes[accessPattern].index; + this.query[accessPattern] = (...values) => { + const options = { + indexType: + this.model.indexes[accessPattern].type || IndexTypes.isolated, + }; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + options, + ).query(...values); + }; + } + this._instance = ElectroInstance.entity; + this._instanceType = ElectroInstanceTypes.entity; + this.schema = model; + } + + get scan() { + const result = this._makeChain( + TableIndex, + this._clausesWithFilters, + clauses.index, + { _isPagination: true }, + ).scan(); + + for (const accessPattern in this.model.indexes) { + const index = this.model.indexes[accessPattern].index; + + result[accessPattern] = this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + { _isPagination: true }, + ).scan(); + } + + return result; + } + + setIdentifier(type = "", identifier = "") { + if (!this.identifiers[type]) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIdentifier, + `Invalid identifier type: "${type}". Valid identifiers include: ${u.commaSeparatedString( + Object.keys(this.identifiers), + )}`, + ); + } else { + this.identifiers[type] = identifier; + } + } + + getName() { + return this.model.entity; + } + + getVersion() { + return this.model.version; + } + + ownsItem(item) { + return ( + item && + this.getName() === item[this.identifiers.entity] && + this.getVersion() === item[this.identifiers.version] && + validations.isStringHasLength(item[this.identifiers.entity]) && + validations.isStringHasLength(item[this.identifiers.version]) + ); + } + + _itemIncludesKeys(item) { + let { pk, sk } = this.model.prefixes[TableIndex]; + return item[pk.field] !== undefined && ( + sk.field === undefined || item[sk.field] !== undefined + ); + } + + ownsKeys(key = {}) { + const accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[TableIndex]; + let { pk, sk } = this.model.prefixes[TableIndex]; + let hasSK = this.model.lookup.indexHasSortKeys[TableIndex]; + const typeofPkProvided = typeof key[pk.field]; + const pkPrefixMatch = + typeofPkProvided === "string" && + key[pk.field].startsWith(pk.prefix) && + (!pk.postfix || key[pk.field].endsWith(pk.postfix)); + const isNumericPk = typeofPkProvided === "number" && pk.cast === "number"; + let pkMatch = pkPrefixMatch || isNumericPk; + let skMatch = pkMatch && !hasSK; + if (pkMatch && hasSK) { + const typeofSkProvided = typeof key[sk.field]; + if (typeofSkProvided === "number") { + skMatch = sk.cast === "number"; + } else if (typeofSkProvided === "string") { + // if sk is a string, check prefix and postfix match + const hasNoPrefixOrStartsWithPrefix = !sk.prefix || key[sk.field].startsWith(sk.prefix); + const hasNoPostfixOrEndsWithPostfix = !sk.postfix || key[sk.field].endsWith(sk.postfix); + skMatch = + hasNoPrefixOrStartsWithPrefix && + hasNoPostfixOrEndsWithPostfix; + } + } + + return ( + pkMatch && skMatch && this._formatKeysToItem(TableIndex, key) !== null + ); + } + + ownsCursor(cursor) { + if (typeof cursor === "string") { + cursor = u.cursorFormatter.deserialize(cursor); + } + return this.ownsKeys(cursor); + } + + serializeCursor(key) { + return u.cursorFormatter.serialize(key); + } + + deserializeCursor(cursor) { + return u.cursorFormatter.deserialize(cursor); + } + + /** @depricated pagers no longer exist, use the new cursor api */ + ownsPager(pager, index = TableIndex) { + if (pager === null) { + return false; + } + let tableIndexFacets = this.model.facets.byIndex[index]; + // todo: is the fact it doesn't use the provided index a bug? + // feels like collections may have played a roll into why this is this way + let indexFacets = this.model.facets.byIndex[index]; + + // Unknown index + if (tableIndexFacets === undefined || indexFacets === undefined) { + return false; + } + + // Should match all primary index facets + let matchesTableIndex = tableIndexFacets.all.every((facet) => { + return pager[facet.name] !== undefined; + }); + + // If the pager doesnt match the table index, exit early + if (!matchesTableIndex) { + return false; + } + + return indexFacets.all.every((facet) => { + return pager[facet.name] !== undefined; + }); + } + + match(facets = {}) { + const options = { _isPagination: true }; + const match = this._findBestIndexKeyMatch(facets); + if (match.shouldScan) { + return this._makeChain( + TableIndex, + this._clausesWithFilters, + clauses.index, + options, + ) + .scan() + .filter((attr) => { + let eqFilters = []; + for (let facet of Object.keys(facets)) { + if (attr[facet] !== undefined && facets[facet] !== undefined) { + eqFilters.push(attr[facet].eq(facets[facet])); + } + } + return eqFilters.join(" AND "); + }); + } else { + return this._makeChain( + match.index, + this._clausesWithFilters, + clauses.index, + options, + ) + .query(facets) + .filter((attr) => { + let eqFilters = []; + for (let facet of Object.keys(facets)) { + if (attr[facet] !== undefined && facets[facet] !== undefined) { + eqFilters.push(attr[facet].eq(facets[facet])); + } + } + return eqFilters.join(" AND "); + }); + } + } + + find(facets = {}) { + const options = { _isPagination: true }; + const match = this._findBestIndexKeyMatch(facets); + if (match.shouldScan) { + return this._makeChain( + TableIndex, + this._clausesWithFilters, + clauses.index, + options, + ).scan(); + } else { + return this._makeChain( + match.index, + this._clausesWithFilters, + clauses.index, + options, + ).query(facets); + } + } + + collection(collection = "", clauses = {}, facets = {}, options = {}) { + const chainOptions = { + ...options, + _isPagination: true, + _isCollectionQuery: true, + }; + + let index = + this.model.translations.collections.fromCollectionToIndex[collection]; + if (index === undefined) { + throw new Error(`Invalid collection: ${collection}`); + } + const chain = this._makeChain(index, clauses, clauses.index, chainOptions); + if (options.indexType === IndexTypes.clustered) { + return chain.clusteredCollection(collection, facets); + } else if (options.indexType === IndexTypes.composite) { + return chain.compositeCollection(collection, facets); + } else { + return chain.collection(collection, facets); + } + } + + _validateModel(model) { + return validations.model(model); + } + + check(compositeAttributes = {}) { + return this._makeChain( + TableIndex, + this._clausesWithFilters, + clauses.index, + ).check(compositeAttributes); + } + + get(facets = {}) { + let index = TableIndex; + if (Array.isArray(facets)) { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).batchGet(facets); + } else { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).get(facets); + } + } + + delete(facets = {}) { + let index = TableIndex; + if (Array.isArray(facets)) { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).batchDelete(facets); + } else { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).delete(facets); + } + } + + put(attributes = {}) { + let index = TableIndex; + if (Array.isArray(attributes)) { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).batchPut(attributes); + } else { + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).put(attributes); + } + } + + upsert(attributes = {}) { + let index = TableIndex; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).upsert(attributes); + } + + create(attributes = {}) { + let index = TableIndex; + let options = {}; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + options, + ).create(attributes); + } + + update(facets = {}) { + let index = TableIndex; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + ).update(facets); + } + + patch(facets = {}) { + let index = TableIndex; + let options = {}; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + options, + ).patch(facets); + } + + remove(facets = {}) { + let index = TableIndex; + let options = {}; + return this._makeChain( + index, + this._clausesWithFilters, + clauses.index, + options, + ).remove(facets); + } + + async transactWrite(parameters, config) { + return this._exec( + MethodTypes.transactWrite, + parameters, + config, + ); + } + + async transactGet(parameters, config) { + return this._exec( + MethodTypes.transactGet, + parameters, + config, + ); + } + + async go(method, parameters = {}, config = {}) { + let stackTrace; + if (!config.originalErr) { + stackTrace = new e.ElectroError(e.ErrorCodes.AWSError); + } + try { + switch (method) { + case MethodTypes.batchWrite: + return await this.executeBulkWrite(parameters, config); + case MethodTypes.batchGet: + return await this.executeBulkGet(parameters, config); + case MethodTypes.query: + case MethodTypes.scan: + return await this.executeQuery(method, parameters, config); + default: + return await this.executeOperation(method, parameters, config); + } + } catch (err) { + if (config.originalErr || stackTrace === undefined) { + return Promise.reject(err); + } else { + if (err.__isAWSError) { + stackTrace.message = `Error thrown by DynamoDB client: "${err.message}" - For more detail on this error reference: https://electrodb.dev/en/reference/errors/#aws-error`; + stackTrace.cause = err; + e.applyParamsFn(stackTrace, err.__edb_params); + return Promise.reject(stackTrace); + } else if (err.isElectroError) { + e.applyParamsFn(err, err.__edb_params); + return Promise.reject(err); + } else { + stackTrace.message = new e.ElectroError( + e.ErrorCodes.UnknownError, + err.message, + err, + ).message; + e.applyParamsFn(stackTrace, err.__edb_params); + return Promise.reject(stackTrace); + } + } + } + } + + async _exec(method, params, config = {}) { + const notifyQuery = () => { + this.eventManager.trigger( + { + type: "query", + method, + params, + config, + }, + config.listeners, + ); + }; + const notifyResults = (results, success) => { + this.eventManager.trigger( + { + type: "results", + method, + config, + success, + results, + }, + config.listeners, + ); + }; + const dynamoDBMethod = MethodTypeTranslation[method]; + const client = config.client || this.client; + const clientOptions = { abortSignal: config.abortSignal }; + return client[dynamoDBMethod](params, clientOptions) + .promise() + .then((results) => { + notifyQuery(); + notifyResults(results, true); + return results; + }) + .catch((err) => { + notifyQuery(); + notifyResults(err, false); + Object.defineProperty(err, '__edb_params', { + enumerable: false, + value: params, + }); + // Only mark as AWS error if it's not already an ElectroError + if (!err.isElectroError) { + err.__isAWSError = true; + } + throw err; + }); + } + + async executeBulkWrite(parameters, config) { + if (!Array.isArray(parameters)) { + parameters = [parameters]; + } + let results = []; + let concurrent = this._normalizeConcurrencyValue(config.concurrent); + let concurrentOperations = u.batchItems(parameters, concurrent); + for (let operation of concurrentOperations) { + if (config.abortSignal && config.abortSignal.aborted) { + throw new e.ElectroError( + e.ErrorCodes.OperationAborted, + "The operation was aborted", + ); + } + await Promise.all( + operation.map(async (params) => { + let response = await this._exec( + MethodTypes.batchWrite, + params, + config, + ); + if (validations.isFunction(config.parse)) { + let parsed = config.parse(config, response); + if (parsed) { + results.push(parsed); + } + } else { + let { unprocessed } = this.formatBulkWriteResponse( + response, + config, + ); + for (let u of unprocessed) { + results.push(u); + } + } + }), + ); + } + + return { unprocessed: results }; + } + + _createNewBatchGetOrderMaintainer(config = {}) { + const pkName = this.model.translations.keys[TableIndex].pk; + const skName = this.model.translations.keys[TableIndex].sk; + const enabled = !!config.preserveBatchOrder; + const table = this.config.table; + const keyFormatter = (record = {}) => { + const pk = record[pkName]; + const sk = record[skName]; + return `${pk}${sk}`; + }; + + return new u.BatchGetOrderMaintainer({ + table, + enabled, + keyFormatter, + }); + } + + _safeMinimum(...values) { + let eligibleNumbers = []; + for (let value of values) { + if (typeof value === "number") { + eligibleNumbers.push(value); + } + } + + if (eligibleNumbers.length) { + return Math.min(...eligibleNumbers); + } + + return undefined; + } + + async executeBulkGet(parameters, config) { + if (!Array.isArray(parameters)) { + parameters = [parameters]; + } + + const orderMaintainer = this._createNewBatchGetOrderMaintainer(config); + orderMaintainer.defineOrder(parameters); + let concurrent = this._normalizeConcurrencyValue(config.concurrent); + let concurrentOperations = u.batchItems(parameters, concurrent); + let resultsAll = config.preserveBatchOrder + ? new Array(orderMaintainer.getSize()).fill(null) + : []; + let unprocessedAll = []; + for (let operation of concurrentOperations) { + if (config.abortSignal && config.abortSignal.aborted) { + throw new e.ElectroError( + e.ErrorCodes.OperationAborted, + "The operation was aborted", + ); + } + await Promise.all( + operation.map(async (params) => { + let response = await this._exec(MethodTypes.batchGet, params, config); + if (validations.isFunction(config.parse)) { + resultsAll.push(config.parse(config, response)); + } else { + this.applyBulkGetResponseFormatting({ + orderMaintainer, + resultsAll, + unprocessedAll, + response, + config, + }); + } + }), + ); + } + return { data: resultsAll, unprocessed: unprocessedAll }; + } + + async hydrate(index, keys = [], config) { + const items = []; + const validKeys = []; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const item = this._formatKeysToItem(TableIndex, key); + if (item !== null) { + items.push(item); + validKeys.push(key); + } + } + + const results = await this.get(items).go({ + ...config, + hydrate: false, + parse: undefined, + hydrator: undefined, + _isCollectionQuery: false, + preserveBatchOrder: true, + ignoreOwnership: config._providedIgnoreOwnership, + attributes: config._providedAttributes, + }); + + const unprocessed = []; + const data = []; + + for (let i = 0; i < results.data.length; i++) { + const key = validKeys[i]; + const item = results.data[i]; + if (!item) { + if (key) { + unprocessed.push(key); + } + } else { + data.push(item); + } + } + + return { + unprocessed, + data, + }; + } + + async executeQuery(method, parameters, config = {}) { + const indexName = parameters.IndexName; + let results = config._isCollectionQuery ? {} : []; + let ExclusiveStartKey = this._formatExclusiveStartKey({ + indexName, + config, + }); + if (ExclusiveStartKey === null) { + ExclusiveStartKey = undefined; + } + let pages = this._normalizePagesValue(config.pages); + let iterations = 0; + let count = 0; + let hydratedUnprocessed = []; + const shouldHydrate = + config.hydrate && + (method === MethodTypes.query || method === MethodTypes.scan); + do { + if (config.abortSignal && config.abortSignal.aborted) { + throw new e.ElectroError( + e.ErrorCodes.OperationAborted, + "The operation was aborted", + ); + } + let response = await this._exec( + method, + { ExclusiveStartKey, ...parameters }, + config, + ); + + ExclusiveStartKey = response.LastEvaluatedKey; + + response = this.formatResponse(response, parameters.IndexName, { + ...config, + data: + shouldHydrate && + (!config.data || config.data === DataOptions.attributes) + ? "includeKeys" + : config.data, + ignoreOwnership: shouldHydrate || config.ignoreOwnership, + }); + if (config.data === DataOptions.raw) { + return response; + } else if (config._isCollectionQuery) { + for (const entity in response.data) { + let items = response.data[entity]; + if (shouldHydrate && items.length) { + const hydrated = await config.hydrator( + entity, + parameters.IndexName, + items, + config, + ); + items = hydrated.data; + hydratedUnprocessed = hydratedUnprocessed.concat( + hydrated.unprocessed, + ); + } + results[entity] = results[entity] || []; + results[entity] = [...results[entity], ...items]; + } + } else if (Array.isArray(response.data)) { + let prevCount = count; + if (config.count) { + count += response.data.length; + } + let items = response.data; + const moreItemsThanRequired = !!config.count && count > config.count; + if (moreItemsThanRequired) { + items = items.slice(0, config.count - prevCount); + } + if (shouldHydrate) { + const hydrated = await this.hydrate( + parameters.IndexName, + items, + config, + ); + items = hydrated.data; + hydratedUnprocessed = hydratedUnprocessed.concat( + hydrated.unprocessed, + ); + } + results = [...results, ...items]; + if (moreItemsThanRequired || count === config.count) { + const lastItem = results[results.length - 1]; + ExclusiveStartKey = this._fromCompositeToKeysByIndex({ + indexName, + provided: lastItem, + }); + break; + } + } else { + return response; + } + iterations++; + } while ( + ExclusiveStartKey && + (pages === AllPages || + config.count !== undefined || + iterations < pages) && + (config.count === undefined || count < config.count) + ); + + const cursor = this._formatReturnPager(config, ExclusiveStartKey); + + if (shouldHydrate) { + return { + cursor, + data: results, + unprocessed: hydratedUnprocessed, + }; + } + return { data: results, cursor }; + } + + async executeOperation(method, parameters, config) { + const conditionCheckMode = config.returnOnConditionCheckFailure; + const hasConditionCheck = conditionCheckMode === "all_old" || conditionCheckMode === true; + + let response; + try { + response = await this._exec(method, parameters, config); + } catch (err) { + if (hasConditionCheck && this._isConditionalCheckFailedException(err)) { + if (conditionCheckMode === "all_old") { + const rawItem = err.Item; + if (rawItem) { + const item = c.util.unmarshall(rawItem); + const formatted = this.formatResponse({ Item: item }, TableIndex, config); + return { rejected: true, data: formatted.data }; + } + return { rejected: true, data: null }; + } + return { rejected: true }; + } + throw err; + } + + let result; + switch (parameters.ReturnValues) { + case FormatToReturnValues.none: + result = { data: null }; + break; + case FormatToReturnValues.all_new: + case FormatToReturnValues.all_old: + case FormatToReturnValues.updated_new: + case FormatToReturnValues.updated_old: + result = this.formatResponse(response, TableIndex, config); + break; + case FormatToReturnValues.default: + default: + result = this._formatDefaultResponse( + method, + parameters.IndexName, + parameters, + config, + response, + ); + break; + } + + if (hasConditionCheck) { + return { rejected: false, data: result.data }; + } + return result; + } + + _isConditionalCheckFailedException(err) { + return err.name === "ConditionalCheckFailedException" || err.code === "ConditionalCheckFailedException"; + } + + _formatDefaultResponse(method, index, parameters, config = {}, response) { + switch (method) { + case MethodTypes.put: + case MethodTypes.create: + return this.formatResponse(parameters, index, config); + case MethodTypes.update: + case MethodTypes.patch: + case MethodTypes.delete: + case MethodTypes.remove: + case MethodTypes.upsert: + return this.formatResponse(response, index, { + ...config, + _objectOnEmpty: true, + }); + default: + return this.formatResponse(response, index, config); + } + } + + cleanseRetrievedData(item = {}, options = {}) { + let data = {}; + let names = this.model.schema.translationForRetrieval; + for (let [attr, value] of Object.entries(item)) { + let name = names[attr]; + if (name) { + data[name] = value; + } else if (options.data === DataOptions.includeKeys) { + data[attr] = value; + } + } + return data; + } + + formatBulkWriteResponse(response = {}, config = {}) { + if (!response || !response.UnprocessedItems) { + return response; + } + const table = config.table || this.getTableName(); + const index = TableIndex; + let unprocessed = response.UnprocessedItems[table]; + if (Array.isArray(unprocessed) && unprocessed.length) { + unprocessed = unprocessed.map((request) => { + if (request.PutRequest) { + return this.formatResponse(request.PutRequest, index, config).data; + } else if (request.DeleteRequest) { + if (config.unprocessed === UnprocessedTypes.raw) { + return request.DeleteRequest.Key; + } else { + return this._formatKeysToItem(index, request.DeleteRequest.Key); + } + } else { + throw new Error("Unknown response format"); + } + }); + } else { + unprocessed = []; + } + + return { unprocessed }; + } + + applyBulkGetResponseFormatting({ + resultsAll, + unprocessedAll, + orderMaintainer, + response = {}, + config = {}, + }) { + const table = config.table || this.getTableName(); + const index = TableIndex; + + if (!response.UnprocessedKeys || !response.Responses) { + throw new Error("Unknown response format"); + } + + if ( + response.UnprocessedKeys[table] && + response.UnprocessedKeys[table].Keys && + Array.isArray(response.UnprocessedKeys[table].Keys) + ) { + for (let value of response.UnprocessedKeys[table].Keys) { + if (config && config.unprocessed === UnprocessedTypes.raw) { + unprocessedAll.push(value); + } else { + unprocessedAll.push(this._formatKeysToItem(index, value)); + } + } + } + + if (response.Responses[table] && Array.isArray(response.Responses[table])) { + const responses = response.Responses[table]; + for (let i = 0; i < responses.length; i++) { + const item = responses[i]; + const slot = orderMaintainer.getOrder(item); + const formatted = this.formatResponse({ Item: item }, index, config); + if (slot !== -1) { + resultsAll[slot] = formatted.data; + } else { + resultsAll.push(formatted.data); + } + } + } + } + + is(item, config) { + return ( + config.ignoreOwnership && + config.attributes && + config.attributes.length > 0 && + !this._itemIncludesKeys(item) + ) || ( + (config.ignoreOwnership || config.hydrate) && + this.ownsKeys(item) + ) || ( + this.ownsItem(item) + ); + } + + formatResponse(response, index, config = {}) { + let stackTrace; + if (!config.originalErr) { + stackTrace = new e.ElectroError(e.ErrorCodes.AWSError); + } + try { + let results = {}; + if (validations.isFunction(config.parse)) { + results = config.parse(config, response); + } else if (config.data === DataOptions.raw && !config._isPagination) { + if (response.TableName) { + results = {}; + } else { + results = response; + } + } else if ( + config.data === DataOptions.raw && + (config._isPagination || config.lastEvaluatedKeyRaw) + ) { + results = response; + } else { + if (response.Item) { + if (this.is(response.Item, config)) { + results = this.model.schema.formatItemForRetrieval( + response.Item, + config, + ); + } else if (!config._objectOnEmpty) { + results = null; + } + } else if (response.Items) { + results = []; + for (let item of response.Items) { + if (this.is(item, config)) { + let record = this.model.schema.formatItemForRetrieval( + item, + config, + ); + results.push(record); + } + } + } else if (response.Attributes) { + results = this.model.schema.formatItemForRetrieval( + response.Attributes, + config, + ); + if (Object.keys(results).length === 0 && !config._objectOnEmpty) { + results = null; + } + } else if (config._objectOnEmpty) { + return { + data: { + ...config._includeOnResponseItem, + }, + }; + } else { + results = null; + } + } + + if (config._isPagination || response.LastEvaluatedKey) { + const nextPage = this._formatReturnPager( + config, + response.LastEvaluatedKey, + ); + return { cursor: nextPage || null, data: results }; + } + + return { data: results }; + } catch (err) { + if ( + config.originalErr || + stackTrace === undefined || + err.isElectroError + ) { + throw err; + } else { + stackTrace.message = `Error thrown by DynamoDB client: "${err.message}" - For more detail on this error reference: https://electrodb.dev/en/reference/errors/#aws-error`; + stackTrace.cause = err; + throw stackTrace; + } + } + } + + parse(item, options = {}) { + if (item === undefined || item === null) { + return null; + } + const config = { + ignoreOwnership: true, + ...(options || {}), + }; + return this.formatResponse(item, TableIndex, config); + } + + _fromCompositeToKeys({ provided }, options = {}) { + if (!provided || Object.keys(provided).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCompositeProvided, + "Invalid conversion composite provided", + ); + } + + let keys = {}; + const secondaryIndexStrictMode = + options.strict === "all" || options.strict === "pk" ? "pk" : "none"; + for (const index of Object.values(this.model.indexes)) { + const indexName = index.index; + const indexKeys = this._fromCompositeToKeysByIndex( + { indexName, provided }, + { + strict: + indexName === TableIndex ? options.strict : secondaryIndexStrictMode, + }, + ); + if (indexKeys) { + keys = { + ...keys, + ...indexKeys, + }; + } + } + + if (Object.keys(keys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCompositeProvided, + "Invalid conversion composite provided", + ); + } + + return keys; + } + + _fromCompositeToCursor({ provided }, options = {}) { + const keys = this._fromCompositeToKeys({ provided }, options); + if (!keys || Object.keys(keys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCompositeProvided, + "Invalid conversion composite provided", + ); + } + return u.cursorFormatter.serialize(keys); + } + + _fromKeysToCursor({ provided }, options = {}) { + if (!provided || Object.keys(provided).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + "Invalid keys provided", + ); + } + return u.cursorFormatter.serialize(provided); + } + + _fromKeysToComposite({ provided }, options = {}) { + if (!provided || Object.keys(provided).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + "Provided keys could not be used to form composite attributes", + ); + } + + let keys = {}; + for (const { index } of Object.values(this.model.indexes)) { + const composite = this._fromKeysToCompositeByIndex( + { indexName: index, provided }, + options, + ); + if (composite) { + for (const attribute in composite) { + if (keys[attribute] === undefined) { + keys[attribute] = composite[attribute]; + } + } + } + } + + if (Object.keys(keys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + "Provided keys could not be used to form composite attributes", + ); + } + + return keys; + } + + _fromCursorToKeys({ provided }, options = {}) { + if (typeof provided !== "string") { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCursorProvided, + "Invalid conversion cursor provided", + ); + } + + return u.cursorFormatter.deserialize(provided); + } + + _fromCursorToComposite({ provided }, options = {}) { + if (typeof provided !== "string") { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCursorProvided, + "Invalid conversion cursor provided", + ); + } + + const keys = this._fromCursorToKeys({ provided }, options); + if (!keys) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCursorProvided, + "Invalid conversion cursor provided", + ); + } + + return this._fromKeysToComposite({ provided: keys }, options); + } + + _fromCompositeToCursorByIndex( + { indexName = TableIndex, provided }, + options = {}, + ) { + if (!provided || Object.keys(provided).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCompositeProvided, + "Invalid conversion composite provided", + ); + } + + const keys = this._formatSuppliedPager(indexName, provided, { + relaxedPk: false, + relaxedSk: false, + }); + + return this._fromKeysToCursorByIndex( + { indexName, provided: keys }, + options, + ); + } + + _fromCompositeToKeysByIndex( + { indexName = TableIndex, provided }, + options = {}, + ) { + return this._formatSuppliedPager(indexName, provided, { + relaxedPk: options.strict !== "pk" && options.strict !== "all", + relaxedSk: options.strict !== "all", + }); + } + + _fromCursorToKeysByIndex({ provided }, options = {}) { + if (typeof provided !== "string" || provided.length < 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCursorProvided, + "Invalid conversion cursor provided", + ); + } + + return u.cursorFormatter.deserialize(provided); + } + + _fromKeysToCursorByIndex({ indexName = TableIndex, provided }, options = {}) { + const isValidTableIndex = this._verifyKeys({ + indexName: TableIndex, + provided, + }); + const isValidIndex = this._verifyKeys({ indexName, provided }); + if (!isValidTableIndex) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + "Provided keys did not include valid properties for the primary index", + ); + } else if (!isValidIndex) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + `Provided keys did not include valid properties for the index "${indexName}"`, + ); + } + + const keys = this._trimKeysToIndex({ indexName, provided }); + + if (!keys || Object.keys(keys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + `Provided keys not defined`, + ); + } + + return u.cursorFormatter.serialize(provided); + } + + _fromKeysToCompositeByIndex( + { indexName = TableIndex, provided }, + options = {}, + ) { + let allKeys = {}; + + if (this._getIndexType(indexName) === IndexTypes.composite) { + const item = this.model.schema.translateFromFields(provided); + allKeys = { + ...this._findFacets(item, this.model.facets.byIndex[indexName].pk), + ...this._findFacets(item, this.model.facets.byIndex[indexName].sk), + } + } else { + const indexKeys = this._deconstructIndex({ + index: indexName, + keys: provided, + }); + if (!indexKeys) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + `Provided keys did not include valid properties for the index "${indexName}"`, + ); + } + allKeys = { + ...indexKeys, + }; + } + + let tableKeys; + if (indexName !== TableIndex) { + tableKeys = this._deconstructIndex({ index: TableIndex, keys: provided }); + } + + if (tableKeys === null) { + return allKeys; + } + + allKeys = { + ...allKeys, + ...tableKeys, + }; + + if (Object.keys(allKeys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + "Provided keys could not be used to form composite attributes", + ); + } + + return allKeys; + } + + _fromCursorToCompositeByIndex( + { indexName = TableIndex, provided }, + options = {}, + ) { + const keys = this._fromCursorToKeysByIndex( + { indexName, provided }, + options, + ); + if (!keys || Object.keys(keys).length === 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionCursorProvided, + "Invalid conversion cursor provided", + ); + } + return this._fromKeysToCompositeByIndex( + { indexName, provided: keys }, + options, + ); + } + + _getIndexType(indexName) { + return this.model.facets.byIndex[indexName].type; + } + + _trimKeysToIndex({ indexName = TableIndex, provided }) { + if (!provided) { + return null; + } + if (this.model.facets.byIndex[indexName].type === IndexTypes.composite) { + return provided; + } + + const pkName = this.model.translations.keys[indexName].pk; + const skName = this.model.translations.keys[indexName].sk; + const tablePKName = this.model.translations.keys[TableIndex].pk; + const tableSKName = this.model.translations.keys[TableIndex].sk; + + const keys = { + [pkName]: provided[pkName], + [skName]: provided[skName], + [tablePKName]: provided[tablePKName], + [tableSKName]: provided[tableSKName], + }; + + if (!keys || Object.keys(keys).length === 0) { + return null; + } + + return keys; + } + + _verifyKeys({ indexName, provided }) { + if (!provided) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConversionKeysProvided, + `Provided keys not defined`, + ); + } + + if (this._getIndexType(indexName) === IndexTypes.composite) { + const item = this.model.schema.translateFromFields(provided); + return this.model.facets.byIndex[indexName].pk.every((attr) => item[attr] !== undefined); + } else { + const pkName = this.model.translations.keys[indexName].pk; + const skName = this.model.translations.keys[indexName].sk; + return ( + provided[pkName] !== undefined && + (!skName || provided[skName] !== undefined) + ); + } + } + + _formatReturnPager(config, lastEvaluatedKey) { + let page = lastEvaluatedKey || null; + if (config.data === DataOptions.raw || config.pager === Pager.raw) { + return page; + } + return config.formatCursor.serialize(page) || null; + } + + _formatExclusiveStartKey({ config, indexName = TableIndex }) { + let exclusiveStartKey = config.cursor; + if (config.data === DataOptions.raw || config.pager === Pager.raw) { + return ( + this._trimKeysToIndex({ provided: exclusiveStartKey, indexName }) || + null + ); + } + let keys; + if (config.pager === Pager.item) { + keys = this._fromCompositeToKeysByIndex({ + indexName, + provided: exclusiveStartKey, + }); + } else { + keys = config.formatCursor.deserialize(exclusiveStartKey); + } + if (!keys) { + return null; + } + + return this._trimKeysToIndex({ provided: keys, indexName }) || null; + } + + setClient(client) { + if (client) { + this.client = c.normalizeClient(client); + } + } + + setTableName(tableName) { + this.config.table = tableName; + } + + getTableName() { + return this.config.table; + } + + _chain(state, clauses, clause) { + let current = {}; + for (let child of clause.children) { + current[child] = (...args) => { + state.prev = state.self; + state.self = child; + let results = clauses[child].action(this, state, ...args); + if (clauses[child].children.length) { + return this._chain(results, clauses, clauses[child]); + } else { + return results; + } + }; + } + return current; + } + /* istanbul ignore next */ + _makeChain(index = TableIndex, clauses, rootClause, options = {}) { + let state = new ChainState({ + index, + options, + attributes: options.attributes || this.model.schema.attributes, + hasSortKey: + options.hasSortKey || this.model.lookup.indexHasSortKeys[index], + compositeAttributes: + options.compositeAttributes || this.model.facets.byIndex[index], + }); + return state.init(this, clauses, rootClause); + } + + _regexpEscape(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + + _normalizeConcurrencyValue(value = 1) { + value = parseInt(value); + if (isNaN(value) || value < 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidConcurrencyOption, + "Query option 'concurrent' must be of type 'number' and greater than zero.", + ); + } + return value; + } + + _normalizePagesValue(value) { + if (value === AllPages) { + return value; + } + value = parseInt(value); + if (isNaN(value) || value < 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidPagesOption, + `Query option 'pages' must be of type 'number' and greater than zero or the string value '${AllPages}'`, + ); + } + return value; + } + + _normalizeLimitValue(value) { + if (value !== undefined) { + value = parseInt(value); + if (isNaN(value) || value < 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidLimitOption, + "Query option 'limit' must be of type 'number' and greater than zero.", + ); + } + } + return value; + } + + _createKeyDeconstructor(prefixes = {}, labels = [], attributes = {}) { + let { prefix, isCustom, postfix, cast } = prefixes; + let names = []; + let types = []; + let pattern = `^${this._regexpEscape(prefix || "")}`; + for (let { name, label } of labels) { + let attr = attributes[name]; + if (isCustom && !name && label) { + // this case is for when someone uses a direct attribute reference but with a postfix (zoinks ;P) + pattern += `${this._regexpEscape(label)}`; + } else if (isCustom) { + pattern += `${this._regexpEscape( + label === undefined ? "" : label, + )}(.+)`; + } else { + pattern += `#${this._regexpEscape( + label === undefined ? name : label, + )}_(.+)`; + } + names.push(name); + if (attr) { + types.push(attr.type); + } + } + if (typeof postfix === "string") { + pattern += this._regexpEscape(postfix); + } + pattern += "$"; + + let regex = new RegExp(pattern, "i"); + + return ({ key } = {}) => { + const typeofKey = typeof key; + if (!["string", "number"].includes(typeofKey)) { + return null; + } + key = `${key}`; + const isNumeric = + cast === CastKeyOptions.number && typeofKey === "number"; + let match = key.match(regex); + let results = {}; + if (match || isNumeric) { + for (let i = 0; i < names.length; i++) { + let keyName = names[i]; + let value = isNumeric ? key : match[i + 1]; + let type = types[i]; + switch (type) { + case "number": { + value = parseFloat(value); + break; + } + case "boolean": { + value = value === "true"; + break; + } + } + if (keyName && value !== undefined) { + results[keyName] = value; + } + } + } else { + results = null; + } + + return results; + }; + } + + _deconstructIndex({ index = TableIndex, keys = {} } = {}) { + const hasIndex = !!this.model.translations.keys[index]; + if (!hasIndex) { + return null; + } + let pkName = this.model.translations.keys[index].pk; + let skName = this.model.translations.keys[index].sk; + const indexHasSortKey = this.model.lookup.indexHasSortKeys[index]; + const deconstructors = this.model.keys.deconstructors[index]; + const pk = keys[pkName]; + if (pk === undefined) { + return null; + } + const pkComposites = deconstructors.pk({ key: pk }); + if (pkComposites === null) { + return null; + } + let skComposites = {}; + if (indexHasSortKey) { + const sk = keys[skName]; + if (sk === undefined) { + return null; + } + skComposites = deconstructors.sk({ key: sk }); + if (skComposites === null) { + return null; + } + } + return { + ...pkComposites, + ...skComposites, + }; + } + + _formatKeysToItem(index = TableIndex, keys) { + if ( + keys === null || + typeof keys !== "object" || + Object.keys(keys).length === 0 + ) { + return keys; + } + let tableIndex = TableIndex; + let indexParts = this._deconstructIndex({ index, keys }); + if (indexParts === null) { + return null; + } + // lastEvaluatedKeys from query calls include the index pk/sk as well as the table index's pk/sk + if (index !== tableIndex) { + const tableIndexParts = this._deconstructIndex({ + index: tableIndex, + keys, + }); + if (tableIndexParts === null) { + return null; + } + indexParts = { ...indexParts, ...tableIndexParts }; + } + let noPartsFound = + Object.keys(indexParts).length === 0 && + this.model.facets.byIndex[tableIndex].all.length > 0; + let partsAreIncomplete = this.model.facets.byIndex[tableIndex].all.find( + (facet) => indexParts[facet.name] === undefined, + ); + if (noPartsFound || partsAreIncomplete) { + // In this case no suitable record could be found be the deconstructed pager. + // This can be valid in cases where a scan is performed but returns no results. + return null; + } + + return indexParts; + } + + _constructPagerIndex(index = TableIndex, item, options = {}) { + let pkAttributes = options.relaxedPk + ? this._findFacets(item, this.model.facets.byIndex[index].pk) + : this._expectFacets(item, this.model.facets.byIndex[index].pk); + let skAttributes = options.relaxedSk + ? this._findFacets(item, this.model.facets.byIndex[index].sk) + : this._expectFacets(item, this.model.facets.byIndex[index].sk); + + if (this._getIndexType(index) === IndexTypes.composite) { + return this.model.schema.translateToFields({ + ...pkAttributes, + ...skAttributes, + }); + } + + let keys = this._makeIndexKeys({ + index, + pkAttributes, + skAttributes: [skAttributes], + }); + + return this._makeParameterKey(index, keys.pk, ...keys.sk); + } + + _formatSuppliedPager(index = TableIndex, item, options = {}) { + if (typeof item !== "object" || Object.keys(item).length === 0) { + return item; + } + + let tableIndex = TableIndex; + let pager = this._constructPagerIndex(index, item, options); + if (index !== tableIndex) { + pager = { + ...pager, + ...this._constructPagerIndex(tableIndex, item, options), + }; + } + + return pager; + } + + _normalizeExecutionOptions({ provided = [], context = {} } = {}) { + let config = { + includeKeys: false, + originalErr: false, + raw: false, + params: {}, + page: {}, + lastEvaluatedKeyRaw: false, + table: undefined, + concurrent: undefined, + parse: undefined, + pager: Pager.named, + unprocessed: UnprocessedTypes.item, + response: "default", + cursor: null, + data: "attributes", + consistent: undefined, + compare: ComparisonTypes.keys, + complete: false, + ignoreOwnership: !!this.config.ignoreOwnership, + _providedIgnoreOwnership: false, + _isPagination: false, + _isCollectionQuery: false, + pages: 1, + count: undefined, + listeners: [], + preserveBatchOrder: false, + attributes: [], + _providedAttributes: [], + terminalOperation: undefined, + formatCursor: u.cursorFormatter, + order: undefined, + hydrate: false, + hydrator: (_entity, _indexName, items) => items, + _objectOnEmpty: false, + _includeOnResponseItem: {}, + abortSignal: undefined, + }; + + // Auto-set ignoreOwnership: true for INCLUDE or KEYS_ONLY indexes + if (context.state && context.state.query && context.state.query.index) { + const indexName = context.state.query.index; + const accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[indexName]; + if (accessPattern) { + const indexDefinition = this.model.indexes[accessPattern]; + config.ignoreOwnership = + indexDefinition.projection === IndexProjectionOptions.keys_only || + (Array.isArray(indexDefinition.projection) && !this.model.indexes[accessPattern].identifiersAreProjected); + } + } + + return provided.filter(Boolean).reduce((config, option) => { + if (typeof option.order === "string") { + switch (option.order.toLowerCase()) { + case "asc": + config.params[ResultOrderParam] = ResultOrderOption.asc; + break; + case "desc": + config.params[ResultOrderParam] = ResultOrderOption.desc; + break; + default: + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for query option "order" provided. Valid options include 'asc' and 'desc, received: "${option.order}"`, + ); + } + } + + if (typeof option.compare === "string") { + const type = ComparisonTypes[option.compare.toLowerCase()]; + if (type) { + config.compare = type; + if (type === ComparisonTypes.v2 && option.complete === undefined) { + config.complete = true; + } + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for query option "compare" provided. Valid options include ${u.commaSeparatedString( + Object.keys(ComparisonTypes), + )}, received: "${option.compare}"`, + ); + } + } + + if (typeof option.response === "string" && option.response.length) { + const format = ReturnValues[option.response]; + if (format === undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for query option "format" provided: "${ + option.format + }". Allowed values include ${u.commaSeparatedString( + Object.keys(ReturnValues), + )}.`, + ); + } else if (format !== ReturnValues.default) { + config.response = format; + if (context.operation === MethodTypes.transactWrite) { + config.params.ReturnValuesOnConditionCheckFailure = + FormatToReturnValues[format]; + } else { + config.params.ReturnValues = FormatToReturnValues[format]; + } + } + } + + if (option.formatCursor) { + const isValid = ["serialize", "deserialize"].every( + (method) => + method in option.formatCursor && + validations.isFunction(option.formatCursor[method]), + ); + if (isValid) { + config.formatCursor = option.formatCursor; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for query option "formatCursor" provided. Formatter interface must have serialize and deserialize functions`, + ); + } + } + + if (option.terminalOperation in TerminalOperation) { + config.terminalOperation = TerminalOperation[option.terminalOperation]; + } + + if (Array.isArray(option.attributes)) { + config.attributes = config.attributes.concat(option.attributes); + config._providedAttributes = option.attributes; + } + + if (option.preserveBatchOrder === true) { + config.preserveBatchOrder = true; + } + + if (option.pages !== undefined) { + config.pages = option.pages; + } + + if (option._isCollectionQuery === true) { + config._isCollectionQuery = true; + } + + if (option.includeKeys === true) { + config.includeKeys = true; + } + + if (option.originalErr === true) { + config.originalErr = true; + } + + if (typeof option.returnOnConditionCheckFailure === "boolean") { + if (option.returnOnConditionCheckFailure === true) { + config.returnOnConditionCheckFailure = true; + } + } else if (typeof option.returnOnConditionCheckFailure === "string") { + const value = option.returnOnConditionCheckFailure.toLowerCase(); + if (value === "all_old") { + config.returnOnConditionCheckFailure = "all_old"; + config.params.ReturnValuesOnConditionCheckFailure = "ALL_OLD"; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for query option "returnOnConditionCheckFailure" provided: "${option.returnOnConditionCheckFailure}". Allowed values include true, false, or "all_old".`, + ); + } + } + + if (option.raw === true) { + config.raw = true; + } + + if (option._isPagination) { + config._isPagination = true; + } + + if (option.lastEvaluatedKeyRaw === true) { + config.lastEvaluatedKeyRaw = true; + config.pager = Pager.raw; + config.unprocessed = UnprocessedTypes.raw; + } + + if (option.cursor) { + config.cursor = option.cursor; + } + + if (option.data) { + if (!DataOptions[option.data]) { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Query option 'data' must be one of ${u.commaSeparatedString( + Object.keys(DataOptions), + )}.`, + ); + } + config.data = option.data; + switch (option.data) { + case DataOptions.raw: + config.raw = true; + break; + case DataOptions.includeKeys: + config.includeKeys = true; + break; + } + } + + if (option.count !== undefined) { + if (typeof option.count !== "number" || option.count < 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Query option 'count' must be of type 'number' and greater than zero.`, + ); + } + config.count = option.count; + } + + if (option.consistent === true) { + config.consistent = true; + config.params.ConsistentRead = true; + } + + if (option.limit !== undefined) { + config.limit = option.limit; + config.params.Limit = option.limit; + } + + if (validations.isStringHasLength(option.table)) { + config.params.TableName = option.table; + config.table = option.table; + } + + if (option.concurrent !== undefined) { + config.concurrent = option.concurrent; + } + + if (validations.isFunction(option.parse)) { + config.parse = option.parse; + } + + if (typeof option.pager === "string") { + if (typeof Pager[option.pager] === "string") { + config.pager = option.pager; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for option "pager" provided: "${ + option.pager + }". Allowed values include ${u.commaSeparatedString( + Object.keys(Pager), + )}.`, + ); + } + } + + if (typeof option.unprocessed === "string") { + if (typeof UnprocessedTypes[option.unprocessed] === "string") { + config.unprocessed = UnprocessedTypes[option.unprocessed]; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + `Invalid value for option "unprocessed" provided: "${ + option.unprocessed + }". Allowed values include ${u.commaSeparatedString( + Object.keys(UnprocessedTypes), + )}.`, + ); + } + } + + if (option.ignoreOwnership !== undefined) { + config.ignoreOwnership = option.ignoreOwnership; + config._providedIgnoreOwnership = option.ignoreOwnership; + } + + if (option.listeners) { + if (Array.isArray(option.listeners)) { + config.listeners = config.listeners.concat(option.listeners); + } + } + + if (option.logger) { + if (validations.isFunction(option.logger)) { + config.listeners.push(option.logger); + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidLoggerProvided, + `Loggers must be of type function`, + ); + } + } + + if (option.hydrate) { + config.hydrate = true; + config.ignoreOwnership = true; + // if we will hydrate later, we don't want to provide a ProjectionExpression since the attributes + // may contain non-projected attributes that the user expects to receive from the main table + // after hydration + config.attributes = []; + } + + if (validations.isFunction(option.hydrator)) { + config.hydrator = option.hydrator; + } + + if (option.client !== undefined) { + config.client = c.normalizeClient(option.client); + } + + if (option.abortSignal !== undefined) { + if (!validations.isAbortSignal(option.abortSignal)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidOptions, + "Invalid 'abortSignal' option provided. Expected an AbortSignal-like object with an 'aborted' boolean and 'addEventListener'/'removeEventListener' methods.", + ); + } + config.abortSignal = option.abortSignal; + } + + if (option._includeOnResponseItem) { + config._includeOnResponseItem = { + ...config._includeOnResponseItem, + ...option._includeOnResponseItem, + }; + } + + config.page = Object.assign({}, config.page, option.page); + config.params = Object.assign({}, config.params, option.params); + return config; + }, config); + } + + _applyParameterOptions({ params = {}, options = {} } = {}) { + let parameters = Object.assign({}, params); + + for (let customParameter of Object.keys(options.params || {})) { + if (options.params[customParameter] !== undefined) { + parameters[customParameter] = options.params[customParameter]; + } + } + + return parameters; + } + + addListeners(logger) { + this.eventManager.add(logger); + } + + _addLogger(logger) { + if (validations.isFunction(logger)) { + this.addListeners(logger); + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidLoggerProvided, + `Logger must be of type function`, + ); + } + } + + _getPrimaryIndexFieldNames() { + let hasSortKey = this.model.lookup.indexHasSortKeys[TableIndex]; + let accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[TableIndex]; + let pkField = this.model.indexes[accessPattern].pk.field; + let skField; + if (hasSortKey) { + skField = this.model.indexes[accessPattern].sk.field; + } + return { + pk: pkField, + sk: skField, + }; + } + + _applyParameterExpressionTypes(params, filter) { + const conditions = filter[ExpressionTypes.ConditionExpression]; + if (conditions.build().length > 0) { + if ( + typeof params[ExpressionTypes.ConditionExpression] === "string" && + params[ExpressionTypes.ConditionExpression].length > 0 + ) { + params[ExpressionTypes.ConditionExpression] = `${ + params[ExpressionTypes.ConditionExpression] + } AND ${conditions.build()}`; + } else { + params[ExpressionTypes.ConditionExpression] = conditions.build(); + } + if (Object.keys(conditions.getNames()).length > 0) { + params.ExpressionAttributeNames = params.ExpressionAttributeNames || {}; + params.ExpressionAttributeNames = Object.assign( + {}, + conditions.getNames(), + params.ExpressionAttributeNames, + ); + } + if (Object.keys(conditions.getValues()).length > 0) { + params.ExpressionAttributeValues = + params.ExpressionAttributeValues || {}; + params.ExpressionAttributeValues = Object.assign( + {}, + conditions.getValues(), + params.ExpressionAttributeValues, + ); + } + } + return params; + } + /* istanbul ignore next */ + _params(state, config = {}) { + const { + keys = {}, + method = "", + put = {}, + update = {}, + filter = {}, + upsert, + updateProxy, + } = state.query; + let consolidatedQueryFacets = this._consolidateQueryFacets(keys.sk); + let params = {}; + switch (method) { + case MethodTypes.check: + case MethodTypes.get: + case MethodTypes.delete: + case MethodTypes.remove: + params = this._makeSimpleIndexParams( + keys.pk, + ...consolidatedQueryFacets, + ); + break; + case MethodTypes.upsert: + params = this._makeUpsertParams( + { update, upsert, updateProxy }, + keys.pk, + ...keys.sk, + ); + break; + case MethodTypes.put: + case MethodTypes.create: + params = this._makePutParams(put, keys.pk, ...keys.sk); + break; + case MethodTypes.update: + case MethodTypes.patch: + params = this._makeUpdateParams( + update, + keys.pk, + ...consolidatedQueryFacets, + ); + break; + case MethodTypes.scan: + params = this._makeScanParam( + filter[ExpressionTypes.FilterExpression], + config, + state, + ); + break; + /* istanbul ignore next */ + default: + throw new Error(`Invalid method: ${method}`); + } + + let appliedParameters = this._applyParameterOptions({ + params, + options: config, + }); + + return this._applyParameterExpressions( + method, + appliedParameters, + config, + filter, + ); + } + + _applyParameterExpressions(method, parameters, config, filter) { + if (method !== MethodTypes.get) { + return this._applyParameterExpressionTypes(parameters, filter); + } else { + parameters = this._applyProjectionExpressions({ parameters, config }); + return this._applyParameterExpressionTypes(parameters, filter); + } + } + + _applyProjectionExpressions({ parameters = {}, config = {} } = {}) { + const attributes = config.attributes || []; + if (attributes.length === 0) { + return parameters; + } + + const requiresRawResponse = config.data === DataOptions.raw; + const enforcesOwnership = !config.ignoreOwnership; + const requiresUserInvolvedPagination = + TerminalOperation[config.terminalOperation] === TerminalOperation.page; + const isServerBound = + TerminalOperation[config.terminalOperation] === TerminalOperation.go || + TerminalOperation[config.terminalOperation] === TerminalOperation.page; + + // Convert all attribute names to their respective "field" names + let hasTableIndexPk = false; + let hasTableIndexSk = !this.model.translations.keys[TableIndex].sk; + const attributeFields = new Map(); + for (let [key, name] of Object.entries(parameters.ExpressionAttributeNames || {})) { + if (key.startsWith("#")) { + key = key.slice(1); + } + attributeFields.set(key, name); + if (name === this.model.translations.keys[TableIndex].pk) { + hasTableIndexPk = true; + } + if (name === this.model.translations.keys[TableIndex].sk) { + hasTableIndexSk = true; + } + } + + if (!hasTableIndexPk) { + const field = this.model.translations.keys[TableIndex].pk; + const name = formatExpressionName(field, attributeFields); + attributeFields.set(name, field); + } + + if (!hasTableIndexSk) { + const field = this.model.translations.keys[TableIndex].sk; + const name = formatExpressionName(field, attributeFields); + attributeFields.set(name, field); + } + + for (const attributeName of attributes) { + const fieldName = this.model.schema.getFieldName(attributeName) || attributeName; + if (fieldName) { + const formatted = formatExpressionName(fieldName, attributeFields); + attributeFields.set(formatted, fieldName); + } + } + + // add ExpressionAttributeNames if it doesn't exist already + parameters.ExpressionAttributeNames = + parameters.ExpressionAttributeNames || {}; + + if ( + // The response you're returning: + // 1. is not expected to be raw + !requiresRawResponse && + // 2. is making a request to the server + isServerBound && + // 3. will expect entity identifiers down stream + enforcesOwnership + ) { + // add entity identifiers to so items can be identified + attributeFields.set(this.identifiers.entity, this.identifiers.entity); + attributeFields.set(this.identifiers.version, this.identifiers.version); + + // if pagination is required you may enter into a scenario where + // the LastEvaluatedKey doesn't belong to entity and one must be formed. + // We must add the attributes necessary to make that key to not break + // pagination. This stinks. + if (requiresUserInvolvedPagination && config.pager !== Pager.raw) { + // LastEvaluatedKeys return the TableIndex keys and the keys for the SecondaryIndex + let tableIndexFacets = this.model.facets.byIndex[TableIndex]; + let indexFacets = this.model.facets.byIndex[parameters.IndexName] || { + all: [], + }; + + for (const attribute of [...tableIndexFacets.all, ...indexFacets.all]) { + const fieldName = this.model.schema.getFieldName(attribute.name); + const formatted = formatExpressionName(attribute.name, attributeFields); + attributeFields.set(formatted, fieldName); + } + } + } + + for (const [attributeField, attributeName] of attributeFields.entries()) { + // prefix the ExpressionAttributeNames because some prefixes are not allowed + parameters.ExpressionAttributeNames["#" + attributeField] = + attributeName; + } + + // if there is already a ProjectionExpression (e.g. config "params"), merge it + if (typeof parameters.ProjectionExpression === "string") { + parameters.ProjectionExpression = [ + parameters.ProjectionExpression, + ...Object.keys(parameters.ExpressionAttributeNames), + ].join(", "); + } else { + parameters.ProjectionExpression = Object.keys( + parameters.ExpressionAttributeNames, + ).join(", "); + } + + return parameters; + } + + _batchGetParams(state, config = {}) { + let table = config.table || this.getTableName(); + let userDefinedParams = this._applyProjectionExpressions({ + parameters: config.params || {}, + config, + }); + + // TableName is added when the config provided includes "table" + // this is evaluated upstream so we remove it to avoid forming + // bad syntax. Code should reconsider how this is applied to + // make this cleaner :( + delete userDefinedParams.TableName; + + let records = []; + for (let itemState of state.subStates) { + let method = itemState.query.method; + let params = this._params(itemState, config); + if (method === MethodTypes.get) { + let { Key } = params; + records.push(Key); + } + } + let batches = u.batchItems(records, MaxBatchItems.batchGet); + return batches.map((batch) => { + return { + RequestItems: { + [table]: { + ...userDefinedParams, + Keys: batch, + }, + }, + }; + }); + } + + _batchWriteParams(state, config = {}) { + let table = config.table || this.getTableName(); + let records = []; + for (let itemState of state.subStates) { + let method = itemState.query.method; + let params = this._params(itemState, config); + switch (method) { + case MethodTypes.put: + let { Item } = params; + records.push({ PutRequest: { Item } }); + break; + case MethodTypes.delete: + let { Key } = params; + records.push({ DeleteRequest: { Key } }); + break; + /* istanbul ignore next */ + default: + throw new Error("Invalid method type"); + } + } + let batches = u.batchItems(records, MaxBatchItems.batchWrite); + return batches.map((batch) => { + return { + RequestItems: { + [table]: batch, + }, + }; + }); + } + + _makeParameterKey(index, pk, sk) { + let hasSortKey = this.model.lookup.indexHasSortKeys[index]; + let accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[index]; + let pkField = this.model.indexes[accessPattern].pk.field; + let key = { + [pkField]: pk, + }; + if (hasSortKey && sk !== undefined) { + let skField = this.model.indexes[accessPattern].sk.field; + key[skField] = sk; + } + return key; + } + + applyIdentifierExpressionState(expressionState, alias) { + const name = this.getName(); + const version = this.getVersion(); + const nameRef = expressionState.setName({}, this.identifiers.entity, this.identifiers.entity); + const versionRef = expressionState.setName({}, this.identifiers.version, this.identifiers.version); + const nameVal = expressionState.setValue( + `${this.identifiers.entity}_${alias || name}`, + name, + ); + const versionVal = expressionState.setValue( + `${this.identifiers.version}_${alias || name}`, + version, + ); + return `(${nameRef.expression} = ${nameVal} AND ${versionRef.expression} = ${versionVal})`; + } + + /* istanbul ignore next */ + _makeScanParam(filter = {}, options = {}, state = {}) { + let index = state.query.index || TableIndex; + let hasSortKey = this.model.lookup.indexHasSortKeys[index]; + let accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[index]; + let pkField = this.model.indexes[accessPattern].pk.field; + let { pk, sk } = this._makeIndexKeys({ + index, + }); + + let keys = this._makeParameterKey(index, pk, ...sk); + // trim empty key values (this can occur when keys are defined by users) + for (let key in keys) { + if (keys[key] === undefined || keys[key] === "") { + delete keys[key]; + } + } + + let keyExpressions = this._expressionAttributeBuilder(keys); + + const expressionAttributeNames = this._mergeExpressionsAttributes( + filter.getNames(), + keyExpressions.ExpressionAttributeNames, + ); + + const expressionAttributeValues = this._mergeExpressionsAttributes( + filter.getValues(), + keyExpressions.ExpressionAttributeValues, + ); + + let params = { + TableName: this.getTableName(), + }; + + if (Object.keys(expressionAttributeNames).length) { + params["ExpressionAttributeNames"] = expressionAttributeNames; + } + + if (Object.keys(expressionAttributeValues).length) { + params["ExpressionAttributeValues"] = expressionAttributeValues; + } + + let filterExpressions = []; + + if (keys[pkField]) { + filterExpressions.push(`begins_with(#${pkField}, :${pkField})`); + } + + if (hasSortKey) { + let skField = this.model.indexes[accessPattern].sk.field; + if (keys[skField]) { + filterExpressions.push(`begins_with(#${skField}, :${skField})`); + } + } + + if (filter.build()) { + filterExpressions.push(filter.build()); + } + + if (filterExpressions.length) { + params.FilterExpression = filterExpressions.join(" AND "); + } + + if (index) { + params.IndexName = index; + } + + return this._applyProjectionExpressions({ + parameters: params, + config: options, + }); + } + + _makeSimpleIndexParams(partition, sort) { + let index = TableIndex; + let keys = this._makeIndexKeys({ + index, + pkAttributes: partition, + skAttributes: [sort], + }); + let Key = this._makeParameterKey(index, keys.pk, ...keys.sk); + let TableName = this.getTableName(); + return { Key, TableName }; + } + + _removeAttributes(item, keys) { + let copy = { ...item }; + for (let key of Object.keys(keys)) { + delete copy[key]; + } + return copy; + } + + _makeUpdateParams(update = {}, pk = {}, sk = {}) { + let primaryIndexAttributes = { ...pk, ...sk }; + let modifiedAttributeValues = {}; + let modifiedAttributeNames = {}; + for (const path of Object.keys(update.paths)) { + const { value, name } = update.paths[path]; + modifiedAttributeValues[path] = value; + modifiedAttributeNames[path] = name; + } + const removed = {}; + for (const name in update.impacted) { + if (update.impacted[name] === ItemOperations.remove) { + removed[name] = name; + } + } + modifiedAttributeValues = this._removeAttributes(modifiedAttributeValues, { + ...pk, + ...sk, + ...this.model.schema.getReadOnly(), + }); + const preparedUpdateValues = this.model.schema.applyAttributeSetters( + modifiedAttributeValues, + ); + // We need to remove the pk/sk facets from before applying the Attribute setters because these values didnt + // change, and we also don't want to trigger the setters of any attributes watching these facets because that + // should only happen when an attribute is changed. + const attributesAndComposites = { + ...preparedUpdateValues, + }; + const { + indexKey, + updatedKeys, + deletedKeys = [], + } = this._getUpdatedKeys( + pk, + sk, + attributesAndComposites, + removed, + update.composites, + ); + const accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[TableIndex]; + for (const path of Object.keys(preparedUpdateValues)) { + if ( + modifiedAttributeNames[path] !== undefined && + preparedUpdateValues[path] !== undefined + ) { + update.updateValue( + modifiedAttributeNames[path], + preparedUpdateValues[path], + ); + } else if (preparedUpdateValues[path] !== undefined) { + const attr = this.model.schema.getAttribute(path); + if (attr) { + // attributes might enter into this flow because they were triggered via a `watch` event and were + // not supplied directly by the user. In this case we should set the field name. + // TODO: This will only work with root attributes and should be refactored for nested attributes. + update.set(attr.field, preparedUpdateValues[path]); + } else { + // this could be fields added by electro that don't appear in the schema + update.set(path, preparedUpdateValues[path]); + } + } + } + + for (const indexKey of Object.keys(updatedKeys)) { + const isNotTablePK = + indexKey !== this.model.indexes[accessPattern].pk.field; + const isNotTableSK = + indexKey !== this.model.indexes[accessPattern].sk.field; + const wasNotAlreadyModified = + modifiedAttributeNames[indexKey] === undefined; + if (isNotTablePK && isNotTableSK && wasNotAlreadyModified) { + update.set(indexKey, updatedKeys[indexKey]); + } + } + + for (const indexKey of deletedKeys) { + const isNotTablePK = + indexKey !== this.model.indexes[accessPattern].pk.field; + const isNotTableSK = + indexKey !== this.model.indexes[accessPattern].sk.field; + const wasNotAlreadyModified = + modifiedAttributeNames[indexKey] === undefined; + if (isNotTablePK && isNotTableSK && wasNotAlreadyModified) { + update.remove(indexKey); + } + } + + // This loop adds the composite attributes to the Primary Index. This is important + // in the case an update results in an "upsert". We want to add the Primary Index + // composite attributes to the update so they will be included on the item when it + // is created. It is done after all of the above because it is not a true "update" + // so it should not be subject to the above "rules". + for (const primaryIndexAttribute of Object.keys(primaryIndexAttributes)) { + // isNotTablePK and isNotTableSK is important to check in case these properties + // are not also the name of the index (you cannot modify the PK or SK of an item + // after its creation) + const attribute = this.model.schema.attributes[primaryIndexAttribute]; + const isNotTablePK = !!( + attribute && + attribute.field !== this.model.indexes[accessPattern].pk.field + ); + const isNotTableSK = !!( + attribute && + attribute.field !== this.model.indexes[accessPattern].sk.field + ); + const wasNotAlreadyModified = + modifiedAttributeNames[primaryIndexAttribute] === undefined; + if (isNotTablePK && isNotTableSK && wasNotAlreadyModified) { + update.set( + attribute.field, + primaryIndexAttributes[primaryIndexAttribute], + ); + } + } + + update.set(this.identifiers.entity, this.getName()); + update.set(this.identifiers.version, this.getVersion()); + + return { + UpdateExpression: update.build(), + ExpressionAttributeNames: update.getNames(), + ExpressionAttributeValues: update.getValues(), + TableName: this.getTableName(), + Key: indexKey, + }; + } + + /* istanbul ignore next */ + _makePutParams({ data } = {}, pk, sk) { + let appliedData = this.model.schema.applyAttributeSetters(data); + let { updatedKeys, setAttributes } = this._getPutKeys( + pk, + sk && sk.facets, + appliedData, + ); + let translatedFields = this.model.schema.translateToFields(setAttributes); + return { + Item: { + ...translatedFields, + ...updatedKeys, + [this.identifiers.entity]: this.getName(), + [this.identifiers.version]: this.getVersion(), + }, + TableName: this.getTableName(), + }; + } + + _maybeApplyUpsertUpdate({ fields = [], operation, updateProxy, update }) { + for (let [field, value] of fields) { + const name = this.model.schema.translationForRetrieval[field]; + if (name) { + const attribute = this.model.schema.attributes[name]; + if ( + this.model.schema.readOnlyAttributes.has(name) && + (!attribute || !attribute.indexes || attribute.indexes.length === 0) + ) { + /* + // this should be considered but is likely overkill at best and unexpected at worst. + // It also is likely symbolic of a deeper issue. That said maybe it could be helpful + // in the future? It is unclear, if this were added, whether this should get the + // default value and then call the setter on the defaultValue. That would at least + // make parity between upsert and a create (without including the attribute) and then + // an "update" + + const defaultValue = attribute.default(); + const valueIsNumber = typeof value === 'number'; + const resolvedDefaultValue = typeof defaultValue === 'number' ? defaultValue : 0; + if (operation === UpsertOperations.subtract && valueIsNumber) { + value = resolvedDefaultValue - value; + } else if (operation === UpsertOperations.add && valueIsNumber) { + value = resolvedDefaultValue + value; + // } + */ + update.set(field, value, ItemOperations.ifNotExists); + } else { + updateProxy.performOperation({ + value, + operation, + path: name, + force: true, + }); + } + } else { + // I think this is for keys + update.set(field, value, operation); + } + } + } + + _makeUpsertParams({ update, upsert } = {}) { + return { + TableName: this.getTableName(), + UpdateExpression: update.build(), + ExpressionAttributeNames: update.getNames(), + ExpressionAttributeValues: update.getValues(), + Key: upsert.indexKey, + }; + } + + _updateExpressionBuilder(data) { + let accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[TableIndex]; + let skip = [ + // Removing readOnly from here because this should have been validated earlier in the process. Not checking + // readOnly here also allows `watch` properties to circumnavigate the readOnly check for attributes that + // should be calculated but not updatable by the user. + // ...this.model.schema.getReadOnly(), + + // ...this.model.facets.fields, + this.model.indexes[accessPattern].pk.field, + this.model.indexes[accessPattern].sk.field, + ]; + return this._expressionAttributeBuilder(data, ItemOperations.set, { skip }); + } + + _queryKeyExpressionAttributeBuilder(index, pk, ...sks) { + let translate = { ...this.model.translations.keys[index] }; + let restrict = ["pk"]; + let keys = { pk }; + sks = sks.filter((sk) => sk !== undefined); + + for (let i = 0; i < sks.length; i++) { + let id = `sk${i + 1}`; + keys[id] = sks[i]; + restrict.push(id); + translate[id] = translate["sk"]; + } + + let keyExpressions = this._expressionAttributeBuilder( + keys, + ItemOperations.set, + { + translate, + restrict, + }, + ); + + return { + ExpressionAttributeNames: Object.assign( + {}, + keyExpressions.ExpressionAttributeNames, + ), + ExpressionAttributeValues: Object.assign( + {}, + keyExpressions.ExpressionAttributeValues, + ), + }; + } + + /* istanbul ignore next */ + _expressionAttributeBuilder(item = {}, operation = "", options = {}) { + let { + require = [], + reject = [], + restrict = [], + skip = [], + translate = {}, + } = options; + /* + In order of execution: + require - if all elements in require are not present as attributes, it throws. + reject - if an attribute on item is present in "reject", it throws. + restrict - if an attribute on item is not present in "restrict", it throws. + skip - if an attribute matches an element in "skip", it is skipped. + translate - if an attribute in item matches a property in "translate", use the value in "translate". + */ + let expressions = { + UpdateExpression: [], + ExpressionAttributeNames: {}, + ExpressionAttributeValues: {}, + }; + + if (require.length) { + let props = Object.keys(item); + let missing = require.filter((prop) => !props.includes(prop)); + if (!missing) { + throw new e.ElectroError( + e.ErrorCodes.MissingAttribute, + `Item is missing attributes: ${u.commaSeparatedString(missing)}`, + ); + } + } + + for (let prop in item) { + if (reject.includes(prop)) { + throw new Error(`Invalid attribute ${prop}`); + } + if (restrict.length && !restrict.includes(prop)) { + throw new Error( + `${prop} is not a valid attribute: ${u.commaSeparatedString( + restrict, + )}`, + ); + } + if (prop === undefined || skip.includes(prop)) { + continue; + } + + let name = prop; + let value = item[prop]; + let nameProp = `#${prop}`; + let valProp = `:${prop}`; + + if (translate[prop]) { + name = translate[prop]; + } + + expressions.UpdateExpression.push(`${nameProp} = ${valProp}`); + expressions.ExpressionAttributeNames[nameProp] = name; + expressions.ExpressionAttributeValues[valProp] = value; + } + expressions.UpdateExpression = `${operation.toUpperCase()} ${expressions.UpdateExpression.join( + ", ", + )}`.trim(); + return expressions; + } + + _makeQueryKeys(state, options) { + let consolidatedQueryFacets = this._consolidateQueryFacets( + state.query.keys.sk, + ); + switch (state.query.type) { + case QueryTypes.is: + return this._makeIndexKeys({ + index: state.query.index, + pkAttributes: state.query.keys.pk, + skAttributes: consolidatedQueryFacets, + indexType: state.query.options.indexType, + queryType: state.query.type, + isCollection: state.query.options._isCollectionQuery, + }); + default: + return this._makeIndexKeysWithoutTail( + state, + consolidatedQueryFacets, + options, + ); + } + } + + + _compositeQueryParams(state = {}, options = {}) { + // todo: review "_consolidateQueryFacets" + const consolidated = this._consolidateQueryFacets( + state.query.keys.sk, + ) || []; + + const pkAttributes = state.query.keys.pk; + const skAttributes = consolidated[0] || {}; + + // provided has length, isArray? + const provided = state.query.keys.provided; + const all = state.query.facets.all || []; + const queryType = state.query.type; + const expressionState = new ExpressionState({ prefix: "k_" }); + + const expressions = []; + if (queryType === QueryTypes.between) { + for (const [name, value] of Object.entries(pkAttributes)) { + const field = this.model.schema.getFieldName(name); + const nameRef = expressionState.setName({}, name, field); + const valueRef = expressionState.setValue(name, value); + expressions.push(`${nameRef.expression} = ${valueRef}`); + } + let is = {} + let start = {} + let end = {}; + (state.query.keys.sk || []).forEach(({type, facets}) => { + if (type === QueryTypes.is || type === QueryTypes.composite_collection) { + is = facets; + } else if (type === QueryTypes.between) { + start = facets; + } else if (type === QueryTypes.and) { + end = facets; + } else { + // todo: improve error handling + throw new Error('Internal error: Invalid sort key type in composite between query'); + } + }); + + let lastFound; + const skNames = state.query.facets.sk || []; + for (const name of skNames) { + if (is[name] !== undefined) { + lastFound = name; + } else if (start[name] !== undefined && end[name] !== undefined) { + lastFound = name; + } else if (start[name] !== undefined || end[name] !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidQueryParameters, + `Invalid attribute combination provided to between query. Between queries on composite indexes must have the same attribute for start and end values until the last sort key attribute. The provided attribute ${name} is missing ${start[name] !== undefined ? 'an end' : 'a start'} value. This is a DynamoDB constraint.` + ); + } else { + break; + } + } + + for (let i = 0; i < skNames.length; i++) { + const name = skNames[i]; + if (lastFound === name) { + const startValue = start[name]; + const endValue = end[name]; + const field = this.model.schema.getFieldName(name); + const nameRef = expressionState.setName({}, name, field); + const startValueRef = expressionState.setValue(name, startValue); + const endValueRef = expressionState.setValue(name, endValue); + expressions.push(`${nameRef.expression} BETWEEN ${startValueRef} AND ${endValueRef}`); + } else if (is[name] !== undefined) { + const value = is[name]; + const field = this.model.schema.getFieldName(name); + const nameRef = expressionState.setName({}, name, field); + const valueRef = expressionState.setValue(name, value); + expressions.push(`${nameRef.expression} = ${valueRef}`); + } else if (start[name] !== undefined && end[name] !== undefined) { + if (start[name] !== end[name]) { + throw new e.ElectroError( + e.ErrorCodes.InvalidQueryParameters, + `Invalid attribute combination provided to between query. Between queries on composite indexes must have the same attribute for start and end values until the last sort key attribute. The provided attribute ${name} has different start and end values. This is a DynamoDB constraint.` + ); + } + const value = start[name]; + const field = this.model.schema.getFieldName(name); + const nameRef = expressionState.setName({}, name, field); + const valueRef = expressionState.setValue(name, value); + expressions.push(`${nameRef.expression} = ${valueRef}`); + } + } + } else { + const attrs = []; + for (const { type, name } of all) { + const value = type === "pk" ? pkAttributes[name] : skAttributes[name]; + if (value === undefined) { + break; + } + attrs.push({type, name, value}); + } + for (let i = 0; i < attrs.length; i++) { + const { type, name, value } = attrs[i]; + const field = this.model.schema.getFieldName(name); + const nameRef = expressionState.setName({}, name, field); + const valueRef = expressionState.setValue(name, value); + const shouldApplyEq = !(type === "sk" && i === attrs.length - 1) + if (shouldApplyEq) { + expressions.push(`${nameRef.expression} = ${valueRef}`); + continue; + } + switch (queryType) { + case QueryTypes.is: + case QueryTypes.eq: + case QueryTypes.collection: + case QueryTypes.composite_collection: + expressions.push(`${nameRef.expression} = ${valueRef}`); + break; + case QueryTypes.begins: + expressions.push(`begins_with(${nameRef.expression}, ${valueRef})`); + break; + case QueryTypes.gt: + expressions.push(`${nameRef.expression} > ${valueRef}`); + break; + case QueryTypes.gte: + expressions.push(`${nameRef.expression} >= ${valueRef}`); + break; + case QueryTypes.lt: + expressions.push(`${nameRef.expression} < ${valueRef}`); + break; + case QueryTypes.lte: + expressions.push(`${nameRef.expression} <= ${valueRef}`); + break; + case QueryTypes.between: { + const second = consolidated[consolidated.length - 1]; + const value2 = second[name]; + const valueRef2 = expressionState.setValue(name, value2); + expressions.push(`${nameRef.expression} BETWEEN ${valueRef} AND ${valueRef2}`); + break; + } + // todo: clean up here + case QueryTypes.clustered_collection: + default: + // todo: improve error handling + throw new Error('Not supported') + } + } + } + + const filter = state.query.filter[ExpressionTypes.FilterExpression]; + const customExpressions = { + names: (state.query.options.expressions && state.query.options.expressions.names) || {}, + values: (state.query.options.expressions && state.query.options.expressions.values) || {}, + expression: (state.query.options.expressions && state.query.options.expressions.expression) || "", + }; + + // identifiers are added via custom expressions on collection queries inside `clauses/handleNonIsolatedCollection` + // Don't duplicate filters if they are provided. + const identifierExpression = !options.ignoreOwnership && !customExpressions.expression ? this.applyIdentifierExpressionState(expressionState) : ''; + + const params = { + IndexName: state.query.index, + KeyConditionExpression: expressions.join(' AND '), + TableName: this.getTableName(), + ExpressionAttributeNames: this._mergeExpressionsAttributes( + filter.getNames(), + expressionState.getNames(), + customExpressions.names, + ), + ExpressionAttributeValues: this._mergeExpressionsAttributes( + filter.getValues(), + expressionState.getValues(), + customExpressions.values, + ), + } + + let filerExpressions = [customExpressions.expression || "", filter.build(), identifierExpression] + .map(s => s.trim()) + .filter(Boolean) + .join(" AND "); + + if (filerExpressions.length) { + params.FilterExpression = filerExpressions; + } + + return params; + } + + _makeQueryParams(state = {}, options = {}, indexKeys) { + switch (state.query.type) { + case QueryTypes.is: + return this._makeIsQueryParams( + state.query, + state.query.index, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys.pk, + ...indexKeys.sk, + ); + case QueryTypes.begins: + return this._makeBeginsWithQueryParams( + state.query.options, + state.query.index, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys.pk, + ...indexKeys.sk, + ); + case QueryTypes.collection: + return this._makeBeginsWithQueryParams( + state.query.options, + state.query.index, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys.pk, + this._getCollectionSk(state.query.collection), + ); + case QueryTypes.clustered_collection: + return this._makeBeginsWithQueryParams( + state.query.options, + state.query.index, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys.pk, + ...indexKeys.sk, + ); + case QueryTypes.between: + return this._makeBetweenQueryParams( + state.query.options, + state.query.index, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys.pk, + ...indexKeys.sk, + ); + case QueryTypes.gte: + case QueryTypes.gt: + case QueryTypes.lte: + case QueryTypes.lt: + return this._makeComparisonQueryParams( + state.query.index, + state.query.type, + state.query.filter[ExpressionTypes.FilterExpression], + indexKeys, + options, + state.query.options, + ); + default: + throw new Error(`Invalid query type: ${state.query.type}`); + } + } + + /* istanbul ignore next */ + _queryParams(state = {}, options = {}) { + const indexKeys = this._makeQueryKeys(state, options); + let parameters; + if (state.query.options.indexType !== IndexTypes.composite) { + parameters = this._makeQueryParams(state, options, indexKeys); + } else { + parameters = this._compositeQueryParams(state, options); + } + + const appliedParameters = this._applyParameterOptions({ + params: parameters, + options, + }); + + return this._applyProjectionExpressions({ + parameters: appliedParameters, + config: options, + }); + } + + _makeBetweenQueryParams(queryOptions, index, filter, pk, ...sk) { + let keyExpressions = this._queryKeyExpressionAttributeBuilder( + index, + pk, + ...sk, + ); + + delete keyExpressions.ExpressionAttributeNames["#sk2"]; + + const customExpressions = { + names: (queryOptions.expressions && queryOptions.expressions.names) || {}, + values: + (queryOptions.expressions && queryOptions.expressions.values) || {}, + expression: + (queryOptions.expressions && queryOptions.expressions.expression) || "", + }; + + let params = { + TableName: this.getTableName(), + ExpressionAttributeNames: this._mergeExpressionsAttributes( + filter.getNames(), + keyExpressions.ExpressionAttributeNames, + customExpressions.names, + ), + ExpressionAttributeValues: this._mergeExpressionsAttributes( + filter.getValues(), + keyExpressions.ExpressionAttributeValues, + customExpressions.values, + ), + KeyConditionExpression: `#pk = :pk and #sk1 BETWEEN :sk1 AND :sk2`, + }; + + if (index) { + params["IndexName"] = index; + } + + let expressions = [customExpressions.expression, filter.build()] + .filter(Boolean) + .join(" AND "); + + if (expressions.length) { + params.FilterExpression = expressions; + } + + return params; + } + + _makeInclusiveQueryParams(options, index, filter, pk, sk, type) { + let keyExpressions = this._queryKeyExpressionAttributeBuilder( + index, + pk, + sk, + ); + let KeyConditionExpression = "#pk = :pk"; + + if ( + this.model.lookup.indexHasSortKeys[index] && + (typeof keyExpressions.ExpressionAttributeValues[":sk1"] === "number" || + (typeof keyExpressions.ExpressionAttributeValues[":sk1"] === "string" && + keyExpressions.ExpressionAttributeValues[":sk1"].length > 0)) + ) { + if (type === QueryTypes.is) { + KeyConditionExpression = `${KeyConditionExpression} and #sk1 = :sk1`; + } else { + KeyConditionExpression = `${KeyConditionExpression} and begins_with(#sk1, :sk1)`; + } + } else { + delete keyExpressions.ExpressionAttributeNames["#sk1"]; + delete keyExpressions.ExpressionAttributeValues[":sk1"]; + } + + let customExpressions = { + names: (options.expressions && options.expressions.names) || {}, + values: (options.expressions && options.expressions.values) || {}, + expression: (options.expressions && options.expressions.expression) || "", + }; + + let params = { + KeyConditionExpression, + TableName: this.getTableName(), + ExpressionAttributeNames: this._mergeExpressionsAttributes( + filter.getNames(), + keyExpressions.ExpressionAttributeNames, + customExpressions.names, + ), + ExpressionAttributeValues: this._mergeExpressionsAttributes( + filter.getValues(), + keyExpressions.ExpressionAttributeValues, + customExpressions.values, + ), + }; + + if (index) { + params["IndexName"] = index; + } + + let expressions = [customExpressions.expression, filter.build()] + .filter(Boolean) + .join(" AND "); + + if (expressions.length) { + params.FilterExpression = expressions; + } + + return params; + } + + _makeIsQueryParams(query, index, filter, pk, sk) { + const { options, keys } = query; + + const providedSks = keys.provided + .filter((item) => item.type === KeyTypes.sk) + .map((item) => item.attribute); + + const skDefinition = + (this.model.facets.byIndex[index] && + this.model.facets.byIndex[index].sk && + Array.isArray(this.model.facets.byIndex[index].sk) && + this.model.facets.byIndex[index].sk) || + []; + + const skCompositeAttributes = new Set(skDefinition); + const skIsCompletelyFulfilled = + skCompositeAttributes.size === providedSks.length && + skDefinition.every((attr) => providedSks.includes(attr)); + + if (skIsCompletelyFulfilled) { + return this._makeInclusiveQueryParams( + options, + index, + filter, + pk, + sk, + QueryTypes.is, + ); + } else { + return this._makeBeginsWithQueryParams(options, index, filter, pk, sk); + } + } + + _makeBeginsWithQueryParams(options, index, filter, pk, sk) { + return this._makeInclusiveQueryParams( + options, + index, + filter, + pk, + sk, + QueryTypes.begins, + ); + } + + _mergeExpressionsAttributes(...expressionAttributes) { + let merged = {}; + for (let obj of expressionAttributes) { + if (obj) { + merged = { ...merged, ...obj }; + } + } + return merged; + } + + _getComparisonOperator(comparison, skType, comparisonType) { + if (skType === "number") { + return Comparisons[comparison]; + } else if (comparisonType === ComparisonTypes.v2) { + return KeyAttributesComparisons[comparison]; + } else { + return Comparisons[comparison]; + } + } + + /* istanbul ignore next */ + _makeComparisonQueryParams( + index = TableIndex, + comparison = "", + filter = {}, + indexKeys = {}, + options = {}, + queryOptions = {}, + ) { + const { pk } = indexKeys; + const sk = indexKeys.sk[0]; + + let operator = this._getComparisonOperator( + comparison, + typeof sk, + options.compare, + ); + if (!operator) { + throw new Error( + `Unexpected comparison operator "${comparison}", expected ${u.commaSeparatedString( + Object.keys(KeyAttributesComparisons), + )}`, + ); + } + + let customExpressions = { + names: (queryOptions.expressions && queryOptions.expressions.names) || {}, + values: + (queryOptions.expressions && queryOptions.expressions.values) || {}, + expression: + (queryOptions.expressions && queryOptions.expressions.expression) || "", + }; + + let keyExpressions = this._queryKeyExpressionAttributeBuilder( + index, + pk, + sk, + ); + + let params = { + TableName: this.getTableName(), + ExpressionAttributeNames: this._mergeExpressionsAttributes( + filter.getNames(), + keyExpressions.ExpressionAttributeNames, + customExpressions.names, + ), + ExpressionAttributeValues: this._mergeExpressionsAttributes( + filter.getValues(), + keyExpressions.ExpressionAttributeValues, + customExpressions.values, + ), + KeyConditionExpression: `#pk = :pk and #sk1 ${operator} :sk1`, + }; + + if (index) { + params["IndexName"] = index; + } + + let expressions = [customExpressions.expression, filter.build()] + .filter(Boolean) + .join(" AND "); + + if (expressions.length) { + params.FilterExpression = expressions; + } + + return params; + } + + _expectIndexFacets( + attributes, + facets, + { utilizeIncludedOnlyIndexes, skipConditionCheck } = {}, + ) { + let [isIncomplete, { incomplete, complete }] = this._getIndexImpact( + attributes, + facets, + { utilizeIncludedOnlyIndexes, skipConditionCheck }, + ); + + if (isIncomplete) { + let incompleteAccessPatterns = incomplete.map( + ({ index }) => + this.model.translations.indexes.fromIndexToAccessPattern[index], + ); + let missingFacets = incomplete.reduce( + (result, { missing }) => [...result, ...missing], + [], + ); + + throw new e.ElectroError( + e.ErrorCodes.IncompleteCompositeAttributes, + `Incomplete composite attributes: Without the composite attributes ${u.commaSeparatedString( + missingFacets, + )} the following access patterns cannot be updated: ${u.commaSeparatedString( + incompleteAccessPatterns.filter((val) => val !== undefined), + )}. If a composite attribute is readOnly and cannot be set, use the 'composite' chain method on update to supply the value for key formatting purposes.`, + ); + } + + return complete; + } + + _makeKeysFromAttributes(indexes, attributes, conditions) { + let indexKeys = {}; + for (let [index, keyTypes] of Object.entries(indexes)) { + if (this.model.lookup.compositeIndexes.has(index)) { + continue; + } + + const shouldMakeKeys = + (!this._indexConditionIsDefined(index) || conditions[index]); + if (!shouldMakeKeys && index !== TableIndex) { + continue; + } + + let keys = this._makeIndexKeys({ + index, + pkAttributes: attributes, + skAttributes: [attributes], + }); + if (keyTypes.pk || keyTypes.sk) { + indexKeys[index] = {}; + } + + if (keyTypes.pk && keys.pk) { + indexKeys[index].pk = keys.pk; + } + + if (keyTypes.sk && keys.sk) { + indexKeys[index].sk = keys.sk; + } else { + // at least return the same datatype (array) + indexKeys[index].sk = []; + } + } + return indexKeys; + } + + _makePutKeysFromAttributes(indexes, attributes) { + let indexKeys = {}; + for (let index of indexes) { + const shouldMakeKeys = + this.model.indexes[ + this.model.translations.indexes.fromIndexToAccessPattern[index] + ].condition(attributes); + if (!shouldMakeKeys) { + continue; + } + indexKeys[index] = this._makeIndexKeys({ + index, + pkAttributes: attributes, + skAttributes: [attributes], + }); + } + return indexKeys; + } + + _getPutKeys(pk, sk, set, validationAssistance) { + let setAttributes = set; + let updateIndex = TableIndex; + let keyTranslations = this.model.translations.keys; + let keyAttributes = { ...sk, ...pk }; + let completeFacets = this._expectIndexFacets( + { ...setAttributes, ...validationAssistance }, + { ...keyAttributes }, + { set }, + ); + + let deletedKeys = []; + for (const [indexName, condition] of Object.entries( + completeFacets.conditions, + )) { + if (!condition) { + deletedKeys.push(this.model.translations.keys[indexName][KeyTypes.pk]); + if (this.model.translations.keys[indexName][KeyTypes.sk]) { + deletedKeys.push( + this.model.translations.keys[indexName][KeyTypes.sk], + ); + } + } + } + + // complete facets, only includes impacted facets which likely does not include the updateIndex which then needs to be added here. + if (!completeFacets.indexes.includes(updateIndex)) { + completeFacets.indexes.push(updateIndex); + } + let composedKeys = this._makePutKeysFromAttributes(completeFacets.indexes, { + ...keyAttributes, + ...setAttributes, + }); + let updatedKeys = {}; + let indexKey = {}; + for (let [index, keys] of Object.entries(composedKeys)) { + let { pk, sk } = keyTranslations[index]; + if (index === updateIndex) { + indexKey[pk] = keys.pk; + if (sk) { + indexKey[sk] = keys.sk[0]; + } + } + if (keys.pk !== undefined && keys.pk !== "") { + updatedKeys[pk] = keys.pk; + } + if (sk && keys.sk[0] !== undefined && keys.sk[0] !== "") { + updatedKeys[sk] = keys.sk[0]; + } + } + + return { indexKey, updatedKeys, setAttributes, deletedKeys }; + } + + _getUpdatedKeys(pk, sk, set, removed, composite = {}) { + let updateIndex = TableIndex; + let keyTranslations = this.model.translations.keys; + let keyAttributes = { ...sk, ...pk }; + + let completeFacets = this._expectIndexFacets( + { ...set }, + { ...composite, ...keyAttributes }, + { utilizeIncludedOnlyIndexes: true }, + ); + + const removedKeyImpact = this._expectIndexFacets( + { ...removed }, + { ...keyAttributes }, + { skipConditionCheck: true }, + ); + + // complete facets, only includes impacted facets which likely does not include the updateIndex which then needs to be added here. + if (completeFacets.impactedIndexTypes[updateIndex] === undefined) { + completeFacets.impactedIndexTypes[updateIndex] = { + pk: "pk", + sk: "sk", + }; + } + + let composedKeys = this._makeKeysFromAttributes( + completeFacets.impactedIndexTypes, + { ...composite, ...set, ...keyAttributes }, + completeFacets.conditions, + ); + + let updatedKeys = {}; + let deletedKeys = []; + let indexKey = {}; + for (const [indexName, condition] of Object.entries( + completeFacets.conditions, + )) { + if (!condition) { + deletedKeys.push(this.model.translations.keys[indexName][KeyTypes.pk]); + if (this.model.translations.keys[indexName][KeyTypes.sk]) { + deletedKeys.push( + this.model.translations.keys[indexName][KeyTypes.sk], + ); + } + } + } + + for (const keys of Object.values(removedKeyImpact.impactedIndexTypes)) { + deletedKeys = deletedKeys.concat(Object.values(keys)); + } + + for (let [index, keys] of Object.entries(composedKeys)) { + let { pk, sk } = keyTranslations[index]; + if (index === updateIndex) { + indexKey[pk] = keys.pk; + if (sk) { + indexKey[sk] = keys.sk[0]; + } + } else { + // This block is for when Sort Keys used in sparse indexes never get made because they don't actually + // have any composite attributes. Without this the PK would be made for the GSI but the SK would always + // be blank, and therefore, not queryable. + let noImpactSk = Array.isArray(keys.sk) && keys.sk.length === 0; + let indexHasSk = this.model.lookup.indexHasSortKeys[index]; + let noAttributeSk = + indexHasSk && this.model.facets.byIndex[index].sk.length === 0; + let hasPrefix = + indexHasSk && this.model.prefixes[index].sk.prefix !== undefined; + let hasPostfix = + indexHasSk && this.model.prefixes[index].sk.prefix !== undefined; + if (noImpactSk && noAttributeSk) { + let key = hasPrefix ? this.model.prefixes[index].sk.prefix : ""; + if (hasPostfix) { + key = `${key}${this.model.prefixes[index].sk.postfix}`; + } + if (key) { + keys.sk.push(key); + } + } + } + + if (keys.pk) { + updatedKeys[pk] = keys.pk; + } + + if (sk && keys.sk[0]) { + updatedKeys[sk] = keys.sk[0]; + } + } + return { indexKey, updatedKeys, deletedKeys }; + } + + _indexConditionIsDefined(index) { + const definition = + this.model.indexes[ + this.model.translations.indexes.fromIndexToAccessPattern[index] + ]; + return definition && definition.conditionDefined; + } + + /* istanbul ignore next */ + _getIndexImpact( + attributes = {}, + included = {}, + { utilizeIncludedOnlyIndexes, skipConditionCheck } = {}, + ) { + // beware: this entire algorithm stinks and needs to be completely refactored. It does redundant loops and fights + // itself the whole way through. I am sorry. + let includedFacets = Object.keys(included); + let impactedIndexes = {}; + let conditions = {}; + let impactedIndexTypes = {}; + let impactedIndexTypeSources = {}; + let completedIndexes = []; + let facets = {}; + for (let [attribute, indexes] of Object.entries(this.model.facets.byAttr)) { + if (attributes[attribute] !== undefined) { + facets[attribute] = attributes[attribute]; + indexes.forEach((definition) => { + // composite indexes do not have keys + if (definition.type === IndexTypes.composite) { + return; + } + + const { index, type } = definition; + impactedIndexes[index] = impactedIndexes[index] || {}; + impactedIndexes[index][type] = impactedIndexes[index][type] || []; + impactedIndexes[index][type].push(attribute); + impactedIndexTypes[index] = impactedIndexTypes[index] || {}; + impactedIndexTypes[index][type] = + this.model.translations.keys[index][type]; + + impactedIndexTypeSources[index] = + impactedIndexTypeSources[index] || {}; + impactedIndexTypeSources[index][type] = + ImpactedIndexTypeSource.provided; + }); + } + } + + // this function is used to determine key impact for update `set`, update `delete`, and `put`. This block is currently only used by update `set` + if (utilizeIncludedOnlyIndexes) { + for (const [index, { pk, sk, type }] of Object.entries( + this.model.facets.byIndex, + )) { + if (type === IndexTypes.composite) { + continue; + } + // The main table index is handled somewhere else (messy I know), and we only want to do this processing if an + // index condition is defined for backwards compatibility. Backwards compatibility is not required for this + // change, but I have paranoid concerns of breaking changes around sparse indexes. + if (index === TableIndex || !this._indexConditionIsDefined(index)) { + continue; + } + + if ( + pk && + pk.length && + pk.every((attr) => included[attr] !== undefined) + ) { + pk.forEach((attr) => { + facets[attr] = included[attr]; + }); + impactedIndexes[index] = impactedIndexes[index] || {}; + impactedIndexes[index][KeyTypes.pk] = [...pk]; + impactedIndexTypes[index] = impactedIndexTypes[index] || {}; + impactedIndexTypes[index][KeyTypes.pk] = + this.model.translations.keys[index][KeyTypes.pk]; + + // flagging the impactedIndexTypeSource as `composite` means the entire key is only being impacted because + // all composites are in `included`. This will help us determine if we need to evaluate the `condition` + // callback for the index. If both the `sk` and `pk` were impacted because of `included` then we can skip + // the condition check because the index doesn't need to be recalculated; + impactedIndexTypeSources[index] = + impactedIndexTypeSources[index] || {}; + impactedIndexTypeSources[index][KeyTypes.pk] = + impactedIndexTypeSources[index][KeyTypes.pk] || + ImpactedIndexTypeSource.composite; + } + + if ( + sk && + sk.length && + sk.every((attr) => included[attr] !== undefined) + ) { + if (this.model.translations.keys[index][KeyTypes.sk]) { + sk.forEach((attr) => { + facets[attr] = included[attr]; + }); + impactedIndexes[index] = impactedIndexes[index] || {}; + impactedIndexes[index][KeyTypes.sk] = [...sk]; + impactedIndexTypes[index] = impactedIndexTypes[index] || {}; + impactedIndexTypes[index][KeyTypes.sk] = + this.model.translations.keys[index][KeyTypes.sk]; + + // flagging the impactedIndexTypeSource as `composite` means the entire key is only being impacted because + // all composites are in `included`. This will help us determine if we need to evaluate the `condition` + // callback for the index. If both the `sk` and `pk` were impacted because of `included` then we can skip + // the condition check because the index doesn't need to be recalculated; + impactedIndexTypeSources[index] = + impactedIndexTypeSources[index] || {}; + impactedIndexTypeSources[index][KeyTypes.sk] = + impactedIndexTypeSources[index][KeyTypes.sk] || + ImpactedIndexTypeSource.composite; + } + } + } + } + + let indexesWithMissingComposites = []; + for (const [index, definition] of Object.entries(this.model.facets.byIndex)) { + const { pk, sk, type } = definition; + if (type === IndexTypes.composite) { + continue; + } + let impacted = impactedIndexes[index]; + let impact = { + index, + definition, + missing: [], + }; + if (impacted) { + let missingPk = + impacted[KeyTypes.pk] && impacted[KeyTypes.pk].length !== pk.length; + let missingSk = + impacted[KeyTypes.sk] && impacted[KeyTypes.sk].length !== sk.length; + if (missingPk) { + impact.missing = [ + ...impact.missing, + ...pk.filter((attr) => { + return ( + !impacted[KeyTypes.pk].includes(attr) && + !includedFacets.includes(attr) + ); + }), + ]; + } + if (missingSk) { + impact.missing = [ + ...impact.missing, + ...sk.filter( + (attr) => + !impacted[KeyTypes.sk].includes(attr) && + !includedFacets.includes(attr), + ), + ]; + } + if (!missingPk && !missingSk) { + completedIndexes.push(index); + } + } + + indexesWithMissingComposites.push(impact); + } + + let incomplete = []; + for (const { index, missing, definition } of indexesWithMissingComposites) { + const indexConditionIsDefined = this._indexConditionIsDefined(index); + + // `skipConditionCheck` is being used by update `remove`. If Attributes are being removed then the condition check + // is meaningless and ElectroDB should uphold its obligation to keep keys and attributes in sync. + // `index === TableIndex` is a special case where we don't need to check the condition because the main table is immutable + // `!this._indexConditionIsDefined(index)` means the index doesn't have a condition defined, so we can skip the check + if ( + skipConditionCheck || + index === TableIndex || + !indexConditionIsDefined + ) { + incomplete.push({ index, missing }); + conditions[index] = true; + continue; + } + + const memberAttributeIsImpacted = + impactedIndexTypeSources[index] && + (impactedIndexTypeSources[index][KeyTypes.pk] === + ImpactedIndexTypeSource.provided || + impactedIndexTypeSources[index][KeyTypes.sk] === + ImpactedIndexTypeSource.provided); + const allMemberAttributesAreIncluded = definition.all.every( + ({ name }) => included[name] !== undefined, + ); + + if (memberAttributeIsImpacted || allMemberAttributesAreIncluded) { + // the `missing` array will contain indexes that are partially provided, but that leaves cases where the pk or + // sk of an index is complete but not both. Both cases are invalid if `indexConditionIsDefined=true` + const missingAttributes = definition.all + .filter( + ({ name }) => + (attributes[name] === undefined && + included[name] === undefined) || + missing.includes(name), + ) + .map(({ name }) => name); + + if (missingAttributes.length) { + throw new e.ElectroError( + e.ErrorCodes.IncompleteIndexCompositesAttributesProvided, + `Incomplete composite attributes provided for index ${index}. Write operations that include composite attributes, for indexes with a condition callback defined, must always provide values for every index composite. This is to ensure consistency between index values and attribute values. Missing composite attributes identified: ${u.commaSeparatedString( + missingAttributes, + )}`, + ); + } + + const accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[index]; + let shouldMakeKeys = !!this.model.indexes[accessPattern].condition({ + ...attributes, + ...included, + }); + + // this helps identify which conditions were checked (key is present) and what the result was (true/false) + conditions[index] = shouldMakeKeys; + if (!shouldMakeKeys) { + continue; + } + } else { + incomplete.push({ index, missing }); + } + } + + incomplete = incomplete.filter(({ missing }) => missing.length); + + let isIncomplete = !!incomplete.length; + let complete = { + facets, + indexes: completedIndexes, + impactedIndexTypes, + conditions, + }; + return [isIncomplete, { incomplete, complete }]; + } + + _consolidateQueryFacets(queryFacets) { + let sk1 = {}; + let sk2 = {}; + for (let { type, facets } of queryFacets) { + if (type === QueryTypes.between) { + sk1 = { ...sk1, ...facets }; + } else if (type === QueryTypes.and) { + sk2 = { ...sk2, ...facets }; + } else { + sk1 = { ...sk1, ...facets }; + sk2 = { ...sk2, ...facets }; + } + } + return [sk1, sk2]; + } + + _buildQueryFacets(facets, skFacets) { + let queryFacets = this._findProperties(facets, skFacets).reduce( + (result, [name, value]) => { + if (value !== undefined) { + result[name] = value; + } + return result; + }, + {}, + ); + return { ...queryFacets }; + } + + /* istanbul ignore next */ + _expectFacets(obj = {}, properties = [], type = "key composite attributes") { + let [incompletePk, missing, matching] = this._expectProperties( + obj, + properties, + ); + if (incompletePk) { + throw new e.ElectroError( + e.ErrorCodes.IncompleteCompositeAttributes, + `Incomplete or invalid ${type} supplied. Missing properties: ${u.commaSeparatedString( + missing, + )}`, + ); + } else { + return matching; + } + } + + _findFacets(obj, properties) { + return Object.fromEntries(this._findProperties(obj, properties)); + } + + _findProperties(obj, properties = []) { + return properties.map((name) => [name, obj[name]]); + } + + _expectProperties(obj, properties) { + let missing = []; + let matching = {}; + this._findProperties(obj, properties).forEach(([name, value]) => { + if (value === undefined) { + missing.push(name); + } else { + matching[name] = value; + } + }); + return [!!missing.length, missing, matching]; + } + + _makeKeyFixings({ + service, + entity, + version = "1", + tableIndex, + modelVersion, + isClustered, + schema, + prefixes = {}, + }) { + /* + Collections will prefix the sort key so they can be queried with + a "begins_with" operator when crossing entities. It is also possible + that the user defined a custom key on either the PK or SK. In the case + of a customKey AND a collection, the collection is ignored to favor + the custom key. + */ + let keys = { + pk: { + prefix: "", + field: tableIndex.pk.field, + casing: tableIndex.pk.casing, + isCustom: tableIndex.customFacets.pk, + cast: tableIndex.pk.cast, + }, + sk: { + prefix: "", + casing: tableIndex.sk.casing, + isCustom: tableIndex.customFacets.sk, + field: tableIndex.sk ? tableIndex.sk.field : undefined, + cast: tableIndex.sk ? tableIndex.sk.cast : undefined, + }, + }; + + let previouslyDefinedPk = null; + let previouslyDefinedSk = null; + for (const [indexName, definition] of Object.entries(prefixes)) { + if (definition.pk.field === tableIndex.pk.field) { + previouslyDefinedPk = { indexName, definition: definition.pk }; + } else if (definition.sk && definition.sk.field === tableIndex.pk.field) { + previouslyDefinedPk = { indexName, definition: definition.sk }; + } + + if (tableIndex.sk) { + if (definition.pk.field === tableIndex.sk.field) { + previouslyDefinedSk = { indexName, definition: definition.pk }; + } else if (definition.sk && definition.sk.field === tableIndex.sk.field) { + previouslyDefinedSk = { indexName, definition: definition.sk }; + } + } + + if (previouslyDefinedPk && (previouslyDefinedSk || !tableIndex.sk)) { + break; + } + } + + let pk = `$${service}`; + let sk = ""; + let entityKeys = ""; + let postfix = ""; + // If the index is in a collections, prepend the sk; + let collectionPrefix = this._makeCollectionPrefix(tableIndex.collection); + if (validations.isStringHasLength(collectionPrefix)) { + sk = `${collectionPrefix}`; + entityKeys += `#${entity}`; + } else { + entityKeys += `$${entity}`; + } + + /** start beta/v1 condition **/ + if (modelVersion === ModelVersions.beta) { + pk = `${pk}_${version}`; + } else { + entityKeys = `${entityKeys}_${version}`; + } + /** end beta/v1 condition **/ + + if (isClustered) { + postfix = entityKeys; + } else { + sk = `${sk}${entityKeys}`; + } + + // If no sk, append the sk properties to the pk + if (Object.keys(tableIndex.sk).length === 0) { + pk += sk; + if (isClustered) { + pk += postfix; + } + } + + // If keys are not custom, set the prefixes + if (!keys.pk.isCustom) { + if (tableIndex.scope) { + pk = `${pk}_${tableIndex.scope}`; + } + keys.pk.prefix = u.formatKeyCasing(pk, tableIndex.pk.casing); + } + + if (!keys.sk.isCustom) { + keys.sk.prefix = u.formatKeyCasing(sk, tableIndex.sk.casing); + keys.sk.postfix = u.formatKeyCasing(postfix, tableIndex.sk.casing); + } + + const castKeys = tableIndex.hasSk + ? [tableIndex.pk, tableIndex.sk] + : [tableIndex.pk]; + + for (const castKey of castKeys) { + if (castKey.cast === CastKeyOptions.string) { + keys[castKey.type].cast = CastKeyOptions.string; + } else if ( + // custom keys with only one facet and no labels are numeric by default + castKey.cast === undefined && + castKey.isCustom && + castKey.facets.length === 1 && + castKey.facetLabels.every(({ label }) => !label) && + schema.attributes[castKey.facets[0]] && + schema.attributes[castKey.facets[0]].type === "number" + ) { + keys[castKey.type].cast = CastKeyOptions.number; + } else if ( + castKey.cast === CastKeyOptions.number && + castKey.facets.length === 1 && + schema.attributes[castKey.facets[0]] && + ["number", "string", "boolean"].includes( + schema.attributes[castKey.facets[0]].type, + ) + ) { + keys[castKey.type].cast = CastKeyOptions.number; + } else if ( + castKey.cast === CastKeyOptions.number && + castKey.facets.length > 1 + ) { + throw new e.ElectroError( + e.ErrorCodes.InvalidModel, + `Invalid "cast" option provided for ${ + castKey.type + } definition on index "${u.formatIndexNameForDisplay( + tableIndex.index, + )}". Keys can only be cast to 'number' if they are a composite of one numeric attribute.`, + ); + } else { + keys[castKey.type].cast = CastKeyOptions.string; + } + } + + if (previouslyDefinedPk) { + const casingMatch = u.toKeyCasingOption(keys.pk.casing) === u.toKeyCasingOption(previouslyDefinedPk.definition.casing); + if (!casingMatch) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCasing, + `Partition Key (pk) on Access Pattern '${u.formatIndexNameForDisplay( + tableIndex.index, + )}' is defined with the casing ${keys.pk.casing}, but the Access Pattern '${u.formatIndexNameForDisplay( + previouslyDefinedPk.definition.accessPattern, + )}' defines the same index field with the ${previouslyDefinedPk.definition.casing === DefaultKeyCasing ? '(default)' : ''} casing ${previouslyDefinedPk.definition.casing}. Key fields must have the same casing definitions across all indexes they are involved with.`, + ); + } + + keys.pk = previouslyDefinedPk.definition; + } + + if (previouslyDefinedSk) { + const casingMatch = u.toKeyCasingOption(keys.sk.casing) === u.toKeyCasingOption(previouslyDefinedSk.definition.casing); + if (!casingMatch) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCasing, + `Sort Key (sk) on Access Pattern '${u.formatIndexNameForDisplay( + tableIndex.index, + )}' is defined with the casing ${keys.sk.casing}, but the Access Pattern '${u.formatIndexNameForDisplay( + previouslyDefinedSk.definition.accessPattern, + )}' defines the same index field with the ${previouslyDefinedSk.definition.casing === DefaultKeyCasing ? '(default)' : ''} casing ${previouslyDefinedSk.definition.casing}. Key fields must have the same casing definitions across all indexes they are involved with.`, + ); + } + keys.sk = previouslyDefinedSk.definition; + } + + return keys; + } + + _formatKeyCasing(accessPattern, key) { + const casing = + this.model.indexes[accessPattern] !== undefined + ? this.model.indexes[accessPattern].sk.casing + : undefined; + + return u.formatKeyCasing(key, casing); + } + + _validateIndex(index) { + if (!this.model.facets.byIndex[index]) { + throw new Error(`Invalid index: ${index}`); + } + } + + _getCollectionSk(collection = "") { + const subCollections = this.model.subCollections[collection]; + const index = + this.model.translations.collections.fromCollectionToIndex[collection]; + const accessPattern = + this.model.translations.indexes.fromIndexToAccessPattern[index]; + const prefixes = this.model.prefixes[index]; + const prefix = this._makeCollectionPrefix(subCollections); + if (prefixes.sk && prefixes.sk.isCustom) { + return ""; + } + return this._formatKeyCasing(accessPattern, prefix); + } + + _makeCollectionPrefix(collection = []) { + let prefix = ""; + if (validations.isArrayHasLength(collection)) { + for (let i = 0; i < collection.length; i++) { + let subCollection = collection[i]; + if (i === 0) { + prefix += `$${subCollection}`; + } else { + prefix += `#${subCollection}`; + } + } + } else if (validations.isStringHasLength(collection)) { + prefix = `$${collection}`; + } + return prefix; + } + + _makeKeyTransforms(queryType, options = {}) { + const transforms = []; + const shiftUp = (val) => u.shiftSortOrder(val, 1); + const noop = (val) => val; + if (options.compare !== ComparisonTypes.v2) { + transforms.push(noop); + } else if (queryType === QueryTypes.between) { + transforms.push(noop, shiftUp); + } else if (queryType === QueryTypes.lte || queryType === QueryTypes.gt) { + transforms.push(shiftUp); + } else { + transforms.push(noop); + } + + return transforms; + } + + /* istanbul ignore next */ + _makeIndexKeysWithoutTail(state = {}, skFacets = [], options) { + const index = state.query.index || TableIndex; + this._validateIndex(index); + const pkFacets = state.query.keys.pk || {}; + const excludePostfix = + state.query.options.indexType === IndexTypes.clustered && + state.query.options._isCollectionQuery; + const transforms = this._makeKeyTransforms(state.query.type, options); + if (!skFacets.length) { + skFacets.push({}); + } + let facets = this.model.facets.byIndex[index]; + let prefixes = this.model.prefixes[index]; + if (!prefixes) { + throw new Error(`Invalid index: ${index}`); + } + // let partitionKey = this._makeKey(prefixes.pk, facets.pk, pkFacets, this.model.facets.labels[index].pk, { excludeLabelTail: true }); + let partitionKey = this._makeKey( + prefixes.pk, + facets.pk, + pkFacets, + this.model.facets.labels[index].pk, + ); + let pk = partitionKey.key; + let sk = []; + let fulfilled = false; + if (this.model.lookup.indexHasSortKeys[index]) { + for (let i = 0; i < skFacets.length; i++) { + const skFacet = skFacets[i]; + const transform = transforms[i]; + let hasLabels = + this.model.facets.labels[index] && + Array.isArray(this.model.facets.labels[index].sk); + let labels = hasLabels ? this.model.facets.labels[index].sk : []; + let sortKey = this._makeKey(prefixes.sk, facets.sk, skFacet, labels, { + excludeLabelTail: true, + excludePostfix, + transform, + }); + if (sortKey.key !== undefined) { + sk.push(sortKey.key); + } + if (sortKey.fulfilled) { + fulfilled = true; + } + } + } + return { + pk, + sk, + fulfilled, + }; + } + + /* istanbul ignore next */ + _makeIndexKeys({ + index = TableIndex, + pkAttributes = {}, + skAttributes = [], + queryType, + indexType, + isCollection = false, + }) { + this._validateIndex(index); + const excludePostfix = indexType === IndexTypes.clustered && isCollection; + const transforms = this._makeKeyTransforms(queryType); + if (!skAttributes.length) { + skAttributes.push({}); + } + + let facets = this.model.facets.byIndex[index]; + + let prefixes = this.model.prefixes[index]; + if (!prefixes) { + throw new Error(`Invalid index: ${index}`); + } + + let pk = this._makeKey( + prefixes.pk, + facets.pk, + pkAttributes, + this.model.facets.labels[index].pk, + ); + + let sk = []; + let fulfilled = false; + if (this.model.lookup.indexHasSortKeys[index]) { + for (let i = 0; i < skAttributes.length; i++) { + const skFacet = skAttributes[i]; + const transform = transforms[i]; + let hasLabels = + this.model.facets.labels[index] && + Array.isArray(this.model.facets.labels[index].sk); + let labels = hasLabels ? this.model.facets.labels[index].sk : []; + let sortKey = this._makeKey(prefixes.sk, facets.sk, skFacet, labels, { + excludePostfix, + transform, + }); + if (sortKey.key !== undefined) { + sk.push(sortKey.key); + } + if (sortKey.fulfilled) { + fulfilled = true; + } + } + } + + return { + pk: pk.key, + sk, + fulfilled, + }; + } + + _formatNumericCastKey(attributeName, key) { + const fulfilled = key !== undefined; + if (!fulfilled) { + return { + fulfilled, + key, + }; + } + if (typeof key === "number") { + return { + fulfilled, + key, + }; + } + if (typeof key === "string") { + const parsed = parseInt(key); + if (!isNaN(parsed)) { + return { + fulfilled, + key: parsed, + }; + } + } + + if (typeof key === "boolean") { + return { + fulfilled, + key: key === true ? 1 : 0, + }; + } + + throw new e.ElectroAttributeValidationError( + attributeName, + `Invalid key value provided, could not cast composite attribute ${attributeName} to number for index`, + ); + } + + /* istanbul ignore next */ + _makeKey( + { prefix, isCustom, casing, postfix, cast } = {}, + facets = [], + supplied = {}, + labels = [], + { excludeLabelTail, excludePostfix, transform = (val) => val } = {}, + ) { + if (cast === CastKeyOptions.number) { + return this._formatNumericCastKey(facets[0], supplied[facets[0]]); + } + + let key = prefix; + let foundCount = 0; + for (let i = 0; i < labels.length; i++) { + const { name, label } = labels[i]; + const attribute = this.model.schema.getAttribute(name); + + let value = supplied[name]; + if (value === undefined && excludeLabelTail) { + break; + } + + if (attribute && validations.isFunction(attribute.format)) { + value = attribute.format(`${value}`); + } + + if (isCustom) { + key = `${key}${label}`; + } else { + key = `${key}#${label}_`; + } + + // Undefined facet value means we cant build any more of the key + if (supplied[name] === undefined) { + break; + } + + foundCount++; + + key = `${key}${value}`; + } + + // when sort keys are fulfilled we need to add the entity postfix + // this is used for cluster indexes + const fulfilled = foundCount === labels.length; + const shouldApplyPostfix = typeof postfix === "string" && !excludePostfix; + if (fulfilled && shouldApplyPostfix) { + key += postfix; + } + + const transformedKey = transform(u.formatKeyCasing(key, casing)); + + return { + fulfilled, + key: transformedKey, + }; + } + + _findBestIndexKeyMatch(attributes = {}) { + // an array of arrays, representing the order of pk and sk composites specified for each index, and then an + // array with each access pattern occupying the same array index. + let facets = this.model.facets.bySlot; + // a flat array containing the match results of each access pattern, in the same array index they occur within + // bySlot above + let matches = []; + for (let f = 0; f < facets.length; f++) { + const slots = facets[f] || []; + for (let s = 0; s < slots.length; s++) { + const accessPatternSlot = slots[s]; + matches[s] = matches[s] || { + index: accessPatternSlot.index, + allKeys: false, + hasSk: false, + count: 0, + done: false, + keys: [], + }; + // already determined to be out of contention on prior iteration + const indexOutOfContention = matches[s].done; + // composite shorter than other indexes + const lacksAttributeAtSlot = !accessPatternSlot; + // attribute at this slot is not in the object provided + const attributeNotProvided = + accessPatternSlot && attributes[accessPatternSlot.name] === undefined; + // if the next attribute is a sort key then all partition keys were provided + const nextAttributeIsSortKey = + accessPatternSlot && + accessPatternSlot.next && + facets[f + 1][s].type === "sk"; + // if no keys are left then all attribute requirements were met (remember indexes don't require a sort key) + const hasAllKeys = accessPatternSlot && !accessPatternSlot.next; + + // no sense iterating on items we know to be "done" + if ( + indexOutOfContention || + lacksAttributeAtSlot || + attributeNotProvided + ) { + matches[s].done = true; + continue; + } + + // if the next attribute is a sort key (and you reached this line) then you have fulfilled all the + // partition key requirements for this index + if (nextAttributeIsSortKey) { + matches[s].hasSk = true; + // if you reached this step and there are no more attributes, then you fulfilled the index + } else if (hasAllKeys) { + matches[s].allKeys = true; + } + + // number of successfully fulfilled attributes plays into the ranking heuristic + matches[s].count++; + + // note the names/types of fulfilled attributes + matches[s].keys.push({ + name: accessPatternSlot.name, + type: accessPatternSlot.type, + }); + } + } + // the highest count of matched attributes among all access patterns + let max = 0; + matches = matches + // remove incomplete indexes + .filter((match) => match.hasSk || match.allKeys) + // calculate max attribute match + .map((match) => { + max = Math.max(max, match.count); + return match; + }); + + // matched contains the ranked attributes. The closer an element is to zero the "higher" the rank. + const matched = []; + for (let m = 0; m < matches.length; m++) { + const match = matches[m]; + // a finished primary index is most ideal (could be a get) + const primaryIndexIsFinished = match.index === "" && match.allKeys; + // if there is a tie for matched index attributes, primary index should win + const primaryIndexIsMostMatched = + match.index === "" && match.count === max; + // composite attributes are complete + const indexRequirementsFulfilled = match.allKeys; + // having the most matches is important + const hasTheMostAttributeMatches = match.count === max; + if (primaryIndexIsFinished) { + matched[0] = match; + } else if (primaryIndexIsMostMatched) { + matched[1] = match; + } else if (indexRequirementsFulfilled) { + matched[2] = match; + } else if (hasTheMostAttributeMatches) { + matched[3] = match; + } + } + // find the first non-undefined element (best ranked) -- if possible + const match = matched.find((value) => !!value); + let keys = []; + let index = ""; + let shouldScan = true; + if (match) { + keys = match.keys; + index = match.index; + shouldScan = false; + } + return { keys, index, shouldScan }; + } + + /* istanbul ignore next */ + _parseComposedKey(key = TableIndex) { + let attributes = {}; + let names = key.match(/:[A-Z1-9]+/gi); + if (!names) { + throw new e.ElectroError( + e.ErrorCodes.InvalidKeyCompositeAttributeTemplate, + `Invalid key composite attribute template. No composite attributes provided, expected at least one composite attribute with the format ":attributeName". Received: ${key}`, + ); + } + let labels = key.split(/:[A-Z1-9]+/gi); + for (let i = 0; i < names.length; i++) { + let name = names[i].replace(":", ""); + let label = labels[i]; + if (name !== "") { + attributes[name] = attributes[name] || []; + attributes[name].push(label); + } + } + return attributes; + } + + _parseTemplateKey(template = "") { + let attributes = []; + let current = { + label: "", + name: "", + }; + let type = "label"; + for (let i = 0; i < template.length; i++) { + let char = template[i]; + let last = template[i - 1]; + let next = template[i + 1]; + if (char === "{" && last === "$" && type === "label") { + type = "name"; + } else if (char === "}" && type === "name") { + if (current.name.match(/^\s*$/)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidKeyCompositeAttributeTemplate, + `Invalid key composite attribute template. Empty expression "\${${current.name}}" provided. Expected attribute name.`, + ); + } + attributes.push({ name: current.name, label: current.label }); + current.name = ""; + current.label = ""; + type = "label"; + } else if (char === "$" && next === "{" && type === "label") { + continue; + } else { + current[type] += char; + } + } + if (current.name.length > 0 || current.label.length > 0) { + attributes.push({ name: current.name, label: current.label }); + } + + return attributes; + } + + _parseFacets(facets) { + let isCustom = !Array.isArray(facets) && typeof facets === "string"; + if (isCustom && facets.length > 0) { + let labels = this._parseComposedKey(facets); + return { + isCustom, + labels: [], + attributes: Object.keys(attributes), + }; + } else if (isCustom && facets.length === 0) { + // treat like empty array sk + return { + isCustom: false, + labels: [], + attributes: [], + }; + } else { + return { + isCustom, + labels: [], + attributes: Object.keys(facets), + }; + } + } + + _parseTemplateAttributes(composite = []) { + let isCustom = !Array.isArray(composite) && typeof composite === "string"; + if (isCustom && composite.length > 0) { + let labels = this._parseTemplateKey(composite); + return { + isCustom, + labels, + attributes: labels.map(({ name }) => name).filter((name) => !!name), + }; + } else if (isCustom && composite.length === 0) { + // treat like empty array sk + return { + isCustom: false, + labels: [], + attributes: [], + }; + } else { + return { + isCustom, + labels: composite.map((name) => ({ name })), + attributes: composite, + }; + } + } + + _compositeTemplateAreCompatible(parsedAttributes, composite) { + if ( + !Array.isArray(composite) || + !parsedAttributes || + !parsedAttributes.isCustom + ) { + // not beholden to compatibility constraints + return true; + } + + return validations.stringArrayMatch(composite, parsedAttributes.attributes); + } + + _optimizeIndexKey(keyDefinition) { + const hasTemplate = typeof keyDefinition.template === "string"; + const hasSingleItemComposite = + Array.isArray(keyDefinition.facets) && + keyDefinition.facets.length === 1 && + keyDefinition.facets[0] === keyDefinition.field; + if (!hasTemplate && hasSingleItemComposite) { + keyDefinition.facets = "${" + keyDefinition.field + "}"; + } + return keyDefinition; + } + + _optimizeMatchingKeyAttributes(model = {}) { + const attributeFields = []; + for (const name of Object.keys(model.attributes)) { + const { field } = model.attributes[name]; + attributeFields.push(field || name); + } + for (const accessPattern of Object.keys(model.indexes)) { + let { pk, sk } = model.indexes[accessPattern]; + if (attributeFields.includes(pk.field)) { + model.indexes[accessPattern].pk = this._optimizeIndexKey(pk); + } + if (sk && attributeFields.includes(sk.field)) { + model.indexes[accessPattern].sk = this._optimizeIndexKey(sk); + } + } + return model; + } + + _normalizeIndexes(indexes, config) { + let normalized = {}; + let indexFieldTranslation = {}; + let indexHasSortKeys = {}; + let indexHasSubCollections = {}; + let clusteredIndexes = new Set(); + let compositeIndexes = new Set(); + let indexAccessPatternTransaction = { + fromAccessPatternToIndex: {}, + fromIndexToAccessPattern: {}, + }; + let collectionIndexTranslation = { + fromCollectionToIndex: {}, + fromIndexToCollection: {}, + }; + let subCollections = {}; + let collections = {}; + let facets = { + byIndex: {}, + byField: {}, + byFacet: {}, + byAttr: {}, + byType: {}, + bySlot: [], + fields: [], + attributes: [], + labels: {}, + projections: [], + }; + let seenIndexes = {}; + let seenIndexFields = {}; + let accessPatterns = Object.keys(indexes); + + for (let i in accessPatterns) { + let accessPattern = accessPatterns[i]; + let index = indexes[accessPattern]; + let indexName = index.index || TableIndex; + let indexType = + typeof index.type === "string" ? index.type : IndexTypes.isolated; + let indexScope = index.scope || ""; + if (index.index === undefined && v.isFunction(index.condition)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCondition, + `The index option 'condition' is only allowed on secondary indexes`, + ); + } + + let conditionDefined = v.isFunction(index.condition); + let indexCondition = index.condition || (() => true); + + if (indexType === IndexTypes.clustered) { + // todo: make contents consistent with "compositeIndexes" below + // this is not consistent with "compositeIndexes" (which uses the index name), this should be fixed in the future. + clusteredIndexes.add(accessPattern); + } else if (indexType === IndexTypes.composite) { + if (indexName === TableIndex) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexDefinition, + `The Access Pattern "${accessPattern}" cannot be defined as a composite index. AWS DynamoDB does not allow for composite indexes on the main table index.`, + ); + } + if (conditionDefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCondition, + `The Access Pattern "${accessPattern}" is defined as a "${indexType}" index, but a condition callback is defined. Composite indexes do not support the use of a condition callback.`, + ); + } + if (index.scope !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCondition, + `The Access Pattern "${accessPattern}" is defined as a "${indexType}" index, but a "scope" value was defined. Composite indexes do not support the use of scope.`, + ); + } + if (index.pk.field !== undefined || (index.sk && index.sk.field !== undefined)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexDefinition, + `The Access Pattern "${accessPattern}" is defined as a "${indexType}" index, but the Partition Key or Sort Key is defined with a field property. Composite indexes do not support the use of a field property, their attributes defined in the composite array define the indexes member attributes.`, + ); + } + // this is not consistent with "clusteredIndexes" (which uses the access pattern name), but it is more correct given the naming. + compositeIndexes.add(indexName); + } + + if (indexType !== IndexTypes.composite) { + if (index.pk.field === undefined || (index.sk && index.sk.field === undefined)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexDefinition, + `The Access Pattern "${accessPattern}" is defined as a "${indexType}" index, but the Partition Key or Sort Key is defined without a field property. Unless using composite attributes, indexes must be defined with a field property that maps to the field name on the DynamoDB table KeySchema.`, + ); + } + } + + if (seenIndexes[indexName] !== undefined) { + if (indexName === TableIndex) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateIndexes, + `Duplicate index defined in model found in Access Pattern '${accessPattern}': '${u.formatIndexNameForDisplay( + indexName, + )}'. This could be because you forgot to specify the index name of a secondary index defined in your model.`, + ); + } else { + throw new e.ElectroError( + e.ErrorCodes.DuplicateIndexes, + `Duplicate index defined in model found in Access Pattern '${accessPattern}': '${indexName}'`, + ); + } + } + seenIndexes[indexName] = indexName; + let hasSk = !!index.sk; + let inCollection = !!index.collection; + if (!hasSk && inCollection) { + throw new e.ElectroError( + e.ErrorCodes.CollectionNoSK, + `Invalid Access pattern definition for '${accessPattern}': '${u.formatIndexNameForDisplay( + indexName, + )}', contains a collection definition without a defined SK. Collections can only be defined on indexes with a defined SK.`, + ); + } + + if (indexType !== IndexTypes.composite) { + if (hasSk && index.sk.field === undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCompositeAttributes, + `The ${accessPattern} Access pattern is defined as a "${indexType}" index, but a Sort Key is defined without a Range Key field mapping.`, + ); + } + if (index.pk.field === undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCompositeAttributes, + `The ${accessPattern} Access pattern is defined as a "${indexType}" index, but a Partition Key is defined without a HasKey field mapping.`, + ); + } + } + + let collection = index.collection || ""; + let customFacets = { + pk: false, + sk: false, + }; + + const pkCasing = + KeyCasing[index.pk.casing] === undefined + ? KeyCasing.default + : index.pk.casing; + let skCasing = KeyCasing.default; + if (hasSk && KeyCasing[index.sk.casing] !== undefined) { + skCasing = index.sk.casing; + } + indexHasSortKeys[indexName] = hasSk; + let parsedPKAttributes = this._parseTemplateAttributes(index.pk.facets); + customFacets.pk = parsedPKAttributes.isCustom; + // labels can be set via the attribute definition or as part of the facetTemplate. + facets.labels[indexName] = facets.labels[indexName] || {}; + facets.labels[indexName]["pk"] = + facets.labels[indexName]["pk"] || parsedPKAttributes; + facets.labels[indexName]["sk"] = + facets.labels[indexName]["sk"] || this._parseTemplateAttributes(); + let pk = { + inCollection, + accessPattern, + index: indexName, + casing: pkCasing, + type: KeyTypes.pk, + cast: index.pk.cast, + field: index.pk.field || "", + facets: parsedPKAttributes.attributes, + isCustom: parsedPKAttributes.isCustom, + facetLabels: parsedPKAttributes.labels, + template: index.pk.template, + }; + let sk = {}; + let parsedSKAttributes = {}; + if (hasSk) { + parsedSKAttributes = this._parseTemplateAttributes(index.sk.facets); + customFacets.sk = parsedSKAttributes.isCustom; + facets.labels[indexName]["sk"] = parsedSKAttributes; + sk = { + inCollection, + accessPattern, + index: indexName, + casing: skCasing, + type: KeyTypes.sk, + cast: index.sk.cast, + field: index.sk.field || "", + facets: parsedSKAttributes.attributes, + isCustom: parsedSKAttributes.isCustom, + facetLabels: parsedSKAttributes.labels, + template: index.sk.template, + }; + facets.fields.push(sk.field); + } + + if (Array.isArray(sk.facets)) { + let duplicates = pk.facets.filter((facet) => sk.facets.includes(facet)); + if (duplicates.length !== 0) { + if (sk.facets.length > 1) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateIndexCompositeAttributes, + `The Access Pattern '${accessPattern}' contains duplicate references the composite attribute(s): ${u.commaSeparatedString( + duplicates, + )}. Composite attributes can only be used more than once in an index if your sort key is limited to a single attribute. This is to prevent unexpected runtime errors related to the inability to generate keys.`, + ); + } + } + } + + let definition = { + pk, + sk, + hasSk, + collection, + customFacets, + type: indexType, + index: indexName, + scope: indexScope, + condition: indexCondition, + conditionDefined: conditionDefined, + projection: index.projection, + identifiersAreProjected: false, + }; + + let projections = []; + + if (index.projection !== undefined) { + if (typeof index.projection === "string" && ( + index.projection.toLowerCase() === IndexProjectionOptions.keys_only || + index.projection.toLowerCase() === IndexProjectionOptions.all + )) { + definition.projection = index.projection.toLowerCase(); + } else if (Array.isArray(index.projection) && index.projection.length > 0 && index.projection.every((attr) => typeof attr === "string")) { + definition.projection = index.projection; + let nameIdentifierPresent = false; + let versionIdentiferPresent = false; + for (const name of definition.projection) { + projections.push({ name, accessPattern }); + if (name === config.identifiers.entity) { + nameIdentifierPresent = true; + } else if (name === config.identifiers.version) { + versionIdentiferPresent = true; + } + } + definition.identifiersAreProjected = nameIdentifierPresent && versionIdentiferPresent; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidProjectionDefinition, + `The Access Pattern '${accessPattern}' contains an invalid "projection" value: ${u.toDisplayString(index.projection)}. Valid projection values include ${u.commaSeparatedString(Object.values(IndexProjectionOptions))}, or an array of attribute names with a length greater than one.` + ) + } + } + + indexHasSubCollections[indexName] = + inCollection && Array.isArray(collection); + + if (inCollection) { + let collectionArray = this._toSubCollectionArray(collection); + + for (let collectionName of collectionArray) { + if (collections[collectionName] !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateCollections, + `Duplicate collection, "${collectionName}" is defined across multiple indexes "${collections[collectionName]}" and "${accessPattern}". Collections must be unique names across indexes for an Entity.`, + ); + } else { + collections[collectionName] = accessPattern; + } + collectionIndexTranslation.fromCollectionToIndex[collectionName] = + indexName; + collectionIndexTranslation.fromIndexToCollection[indexName] = + collectionIndexTranslation.fromIndexToCollection[indexName] || []; + collectionIndexTranslation.fromIndexToCollection[indexName].push( + collection, + ); + } + subCollections = { + ...subCollections, + ...this._normalizeSubCollections(collectionArray), + }; + } + + let attributes = [ + ...pk.facets.map((name) => ({ + name, + index: indexName, + type: KeyTypes.pk, + })), + ...(sk.facets || []).map((name) => ({ + name, + index: indexName, + type: KeyTypes.sk, + })), + ]; + + normalized[accessPattern] = definition; + + indexAccessPatternTransaction.fromAccessPatternToIndex[accessPattern] = + indexName; + indexAccessPatternTransaction.fromIndexToAccessPattern[indexName] = + accessPattern; + + indexFieldTranslation[indexName] = { + pk: pk.field, + sk: sk.field || "", + }; + + facets.attributes = [...facets.attributes, ...attributes]; + facets.projections = [...facets.projections, ...projections]; + + if (definition.type !== IndexTypes.composite) { + facets.fields.push(pk.field); + } + + facets.byIndex[indexName] = { + customFacets, + pk: pk.facets, + sk: sk.facets, + all: attributes, + type: index.type, + collection: index.collection, + hasSortKeys: !!indexHasSortKeys[indexName], + hasSubCollections: !!indexHasSubCollections[indexName], + casing: { + pk: pkCasing, + sk: skCasing, + }, + }; + + if (definition.type !== IndexTypes.composite) { + facets.byField = facets.byField || {}; + facets.byField[pk.field] = facets.byField[pk.field] || {}; + facets.byField[pk.field][indexName] = pk; + if (sk.field) { + facets.byField[sk.field] = facets.byField[sk.field] || {}; + facets.byField[sk.field][indexName] = sk; + } + + if (seenIndexFields[pk.field] !== undefined) { + const definition = Object.values(facets.byField[pk.field]).find( + (definition) => definition.index !== indexName, + ); + + const definitionsMatch = validations.stringArrayMatch( + pk.facets, + definition.facets, + ); + if (!definitionsMatch) { + throw new e.ElectroError( + e.ErrorCodes.InconsistentIndexDefinition, + `Partition Key (pk) on Access Pattern '${u.formatIndexNameForDisplay( + accessPattern, + )}' is defined with the composite attribute(s) ${u.commaSeparatedString( + pk.facets, + )}, but the Access Pattern '${u.formatIndexNameForDisplay( + definition.accessPattern, + )}' defines this field with the composite attributes ${u.commaSeparatedString( + definition.facets, + )}'. Key fields must have the same composite attribute definitions across all indexes they are involved with`, + ); + } + + const keyTemplatesMatch = pk.template === definition.template + + if (!keyTemplatesMatch) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate, + `Partition Key (pk) on Access Pattern '${u.formatIndexNameForDisplay( + accessPattern, + )}' is defined with the template ${pk.template || '(undefined)'}, but the Access Pattern '${u.formatIndexNameForDisplay( + definition.accessPattern, + )}' defines this field with the key labels ${definition.template || '(undefined)'}'. Key fields must have the same template definitions across all indexes they are involved with`, + ); + } + + seenIndexFields[pk.field].push({ accessPattern, type: "pk" }); + } else { + seenIndexFields[pk.field] = []; + seenIndexFields[pk.field].push({ accessPattern, type: "pk" }); + } + + if (sk.field) { + if (sk.field === pk.field) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateIndexFields, + `The Access Pattern '${u.formatIndexNameForDisplay( + accessPattern, + )}' references the field '${ + sk.field + }' as the field name for both the PK and SK. Fields used for indexes need to be unique to avoid conflicts.`, + ); + } else if (seenIndexFields[sk.field] !== undefined) { + const definition = Object.values(facets.byField[sk.field]).find( + (definition) => definition.index !== indexName, + ); + + const definitionsMatch = validations.stringArrayMatch( + sk.facets, + definition.facets, + ) + + if (!definitionsMatch) { + throw new e.ElectroError( + e.ErrorCodes.DuplicateIndexFields, + `Sort Key (sk) on Access Pattern '${u.formatIndexNameForDisplay( + accessPattern, + )}' is defined with the composite attribute(s) ${u.commaSeparatedString( + sk.facets, + )}, but the Access Pattern '${u.formatIndexNameForDisplay( + definition.accessPattern, + )}' defines this field with the composite attributes ${u.commaSeparatedString( + definition.facets, + )}'. Key fields must have the same composite attribute definitions across all indexes they are involved with`, + ); + } + + const keyTemplatesMatch = sk.template === definition.template + + if (!keyTemplatesMatch) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate, + `Sort Key (sk) on Access Pattern '${u.formatIndexNameForDisplay( + accessPattern, + )}' is defined with the template ${sk.template || '(undefined)'}, but the Access Pattern '${u.formatIndexNameForDisplay( + definition.accessPattern, + )}' defines this field with the key labels ${definition.template || '(undefined)'}'. Key fields must have the same template definitions across all indexes they are involved with`, + ); + } + + seenIndexFields[sk.field].push({ accessPattern, type: "sk" }); + } else { + seenIndexFields[sk.field] = []; + seenIndexFields[sk.field].push({ accessPattern, type: "sk" }); + } + } + } + + attributes.forEach(({ index, type, name }, j) => { + let next = + attributes[j + 1] !== undefined ? attributes[j + 1].name : ""; + let facet = { index, name, type, next }; + facets.byAttr[name] = facets.byAttr[name] || []; + facets.byAttr[name].push(facet); + facets.byType[type] = facets.byType[type] || []; + facets.byType[type].push(facet); + facets.byFacet[name] = facets.byFacet[name] || []; + facets.byFacet[name][j] = facets.byFacet[name][j] || []; + facets.byFacet[name][j].push(facet); + facets.bySlot[j] = facets.bySlot[j] || []; + facets.bySlot[j][i] = facet; + }); + + let pkTemplateIsCompatible = this._compositeTemplateAreCompatible( + parsedPKAttributes, + index.pk.composite, + ); + if (!pkTemplateIsCompatible) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate, + `Incompatible PK 'template' and 'composite' properties for defined on index "${u.formatIndexNameForDisplay( + indexName, + )}". PK "template" string is defined as having composite attributes ${u.commaSeparatedString( + parsedPKAttributes.attributes, + )} while PK "composite" array is defined with composite attributes ${u.commaSeparatedString( + index.pk.composite, + )}`, + ); + } + + if ( + index.sk !== undefined && + Array.isArray(index.sk.composite) && + typeof index.sk.template === "string" + ) { + let skTemplateIsCompatible = this._compositeTemplateAreCompatible( + parsedSKAttributes, + index.sk.composite, + ); + if (!skTemplateIsCompatible) { + throw new e.ElectroError( + e.ErrorCodes.IncompatibleKeyCompositeAttributeTemplate, + `Incompatible SK 'template' and 'composite' properties for defined on index "${u.formatIndexNameForDisplay( + indexName, + )}". SK "template" string is defined as having composite attributes ${u.commaSeparatedString( + parsedSKAttributes.attributes, + )} while SK "composite" array is defined with composite attributes ${u.commaSeparatedString( + index.sk.composite, + )}`, + ); + } + } + } + + if (facets.byIndex[TableIndex] === undefined) { + throw new e.ElectroError( + e.ErrorCodes.MissingPrimaryIndex, + "Schema is missing an index definition for the table's main index. Please update the schema to include an index without a specified name to define the table's natural index", + ); + } + + return { + facets, + subCollections, + indexHasSortKeys, + clusteredIndexes, + compositeIndexes, + indexHasSubCollections, + indexes: normalized, + indexField: indexFieldTranslation, + indexAccessPattern: indexAccessPatternTransaction, + indexCollection: collectionIndexTranslation, + collections: Object.keys(collections), + }; + } + + _normalizeFilters(filters = {}) { + let normalized = {}; + let invalidFilterNames = ["go", "params", "filter", "where", "set"]; + + for (let [name, fn] of Object.entries(filters)) { + if (invalidFilterNames.includes(name)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidFilter, + `Invalid filter name: ${name}. Filter cannot be named ${u.commaSeparatedString( + invalidFilterNames, + )}`, + ); + } else { + normalized[name] = fn; + } + } + + return normalized; + } + + _normalizeKeyFixings({ + service, + entity, + version, + indexes, + modelVersion, + clusteredIndexes, + schema, + }) { + let prefixes = {}; + for (let accessPattern of Object.keys(indexes)) { + let tableIndex = indexes[accessPattern]; + prefixes[tableIndex.index] = this._makeKeyFixings({ + service, + entity, + version, + tableIndex, + modelVersion, + isClustered: clusteredIndexes.has(accessPattern), + schema, + prefixes, + }); + } + return prefixes; + } + + _normalizeSubCollections(collections = []) { + let lookup = {}; + for (let i = collections.length - 1; i >= 0; i--) { + let subCollection = collections[i]; + lookup[subCollection] = lookup[subCollection] || []; + for (let j = 0; j <= i; j++) { + lookup[subCollection].push(collections[j]); + } + } + return lookup; + } + + _toSubCollectionArray(collection) { + let collectionArray = []; + if ( + Array.isArray(collection) && + collection.every((col) => validations.isStringHasLength(col)) + ) { + collectionArray = collection; + } else if (validations.isStringHasLength(collection)) { + collectionArray.push(collection); + } else { + throw new Error("Invalid collection definition"); + } + return collectionArray; + } + + _applyCompositeToFacetConversion(model) { + for (let accessPattern of Object.keys(model.indexes)) { + let index = model.indexes[accessPattern]; + let invalidPK = + index.pk.facets === undefined && + index.pk.composite === undefined && + index.pk.template === undefined; + let invalidSK = + index.sk && + index.sk.facets === undefined && + index.sk.composite === undefined && + index.sk.template === undefined; + if (invalidPK) { + throw new Error("Missing Index Composite Attributes!"); + } else if (invalidSK) { + throw new Error("Missing Index Composite Attributes!"); + } + + if (Array.isArray(index.pk.composite)) { + index.pk = { + ...index.pk, + facets: index.pk.composite, + }; + } + + if (typeof index.pk.template === "string") { + index.pk = { + ...index.pk, + facets: index.pk.template, + }; + } + + // SK may not exist on index + if (index.sk && Array.isArray(index.sk.composite)) { + index.sk = { + ...index.sk, + facets: index.sk.composite, + }; + } + + if (index.sk && typeof index.sk.template === "string") { + index.sk = { + ...index.sk, + facets: index.sk.template, + }; + } + + model.indexes[accessPattern] = index; + } + return model; + } + + _mergeKeyDefinitions(fromIndex, fromModel) { + let definitions = {}; + for (let indexName of Object.keys(fromIndex)) { + let pk = fromIndex[indexName].pk; + let sk = fromIndex[indexName].sk || { labels: [] }; + definitions[indexName] = { + pk: [], + sk: [], + }; + for (let { name, label } of pk.labels) { + if (pk.isCustom) { + definitions[indexName].pk.push({ name, label }); + } else { + definitions[indexName].pk.push({ + name, + label: fromModel[name] || name, + }); + } + } + for (let { name, label } of sk.labels) { + if (sk.isCustom) { + definitions[indexName].sk.push({ name, label }); + } else { + definitions[indexName].sk.push({ + name, + label: u.getFirstDefined(fromModel[name], name), + }); + } + } + } + + return definitions; + } + + _parseModel(model, config = {}) { + /** start beta/v1 condition **/ + let modelVersion = u.getModelVersion(model); + let service, entity, version, table, name; + switch (modelVersion) { + case ModelVersions.beta: + service = model.service; + entity = model.entity; + version = model.version; + table = config.table || model.table; + name = entity; + break; + case ModelVersions.v1: + service = model.model && model.model.service; + entity = model.model && model.model.entity; + version = model.model && model.model.version; + table = config.table || model.table; + name = entity; + break; + default: + throw new Error("Invalid model"); + } + + model = this._applyCompositeToFacetConversion(model); + + // _optimizeMatchingKeyAttributes abides by the design compromises made by _applyCompositeToFacetConversion :\ + model = this._optimizeMatchingKeyAttributes(model); + /** end beta/v1 condition **/ + + let { + facets, + indexes, + indexField, + collections, + subCollections, + indexCollection, + clusteredIndexes, + compositeIndexes, + indexHasSortKeys, + indexAccessPattern, + indexHasSubCollections, + } = this._normalizeIndexes(model.indexes, config); + let schema = new Schema(model.attributes, facets, { + isRoot: true, + getClient: () => this.client, + identifiers: { + [config.identifiers.entity]: config.identifiers.entity, + [config.identifiers.version]: config.identifiers.version, + }, + }); + + let filters = this._normalizeFilters(model.filters); + // todo: consider a rename + let prefixes = this._normalizeKeyFixings({ + service, + entity, + version, + indexes, + modelVersion, + clusteredIndexes, + schema, + }); + + // apply model defined labels + let schemaDefinedLabels = schema.getLabels(); + const deconstructors = {}; + facets.labels = this._mergeKeyDefinitions( + facets.labels, + schemaDefinedLabels, + ); + for (let indexName of Object.keys(facets.labels)) { + const accessPattern = + indexAccessPattern.fromIndexToAccessPattern[indexName]; + indexes[accessPattern].pk.labels = facets.labels[indexName].pk; + indexes[accessPattern].sk.labels = facets.labels[indexName].sk; + + const keyTypes = prefixes[indexName] || {}; + deconstructors[indexName] = {}; + for (const keyType in keyTypes) { + const prefixes = keyTypes[keyType]; + const labels = facets.labels[indexName][keyType] || []; + const attributes = schema.attributes; + deconstructors[indexName][keyType] = this._createKeyDeconstructor( + prefixes, + labels, + attributes, + ); + for (let attributeName in schema.attributes) { + const { field } = schema.attributes[attributeName]; + if (indexes[accessPattern][keyType].field === field) { + indexes[accessPattern][keyType].isFieldRef = true; + } + } + } + } + + return { + name, + table, + schema, + facets, + entity, + service, + indexes, + version, + filters, + prefixes, + collections, + modelVersion, + subCollections, + lookup: { + compositeIndexes, + clusteredIndexes, + indexHasSortKeys, + indexHasSubCollections, + }, + translations: { + keys: indexField, + indexes: indexAccessPattern, + collections: indexCollection, + }, + keys: { + deconstructors, + }, + original: model, + }; + } +} + +function getEntityIdentifiers(entities) { + let identifiers = []; + for (let alias of Object.keys(entities)) { + let entity = entities[alias]; + let name = entity.model.entity; + let version = entity.model.version; + identifiers.push({ + name, + alias, + version, + entity, + nameField: entity.identifiers.entity, + versionField: entity.identifiers.version, + }); + } + return identifiers; +} + +function matchToEntityAlias({ + paramItem, + identifiers, + record, + entities = {}, + allowMatchOnKeys = false, + config = {}, +} = {}) { + let entity; + if (paramItem && v.isFunction(paramItem[TransactionCommitSymbol])) { + const committed = paramItem[TransactionCommitSymbol](); + entity = committed.entity; + } + + let entityAlias; + for (let { name, version, nameField, versionField, alias } of identifiers) { + if ( + entity && + entity.model.entity === name && + entity.model.version === version + ) { + entityAlias = alias; + break; + } else if ( + record[nameField] !== undefined && + record[versionField] !== undefined && + record[nameField] === name && + record[versionField] === version + ) { + entityAlias = alias; + break; + // } else if (allowMatchOnKeys && entities[alias] && entities[alias].ownsKeys({keys: record})) { + // if (entityAlias) { + // if (alias !== entityAlias) { + // throw new Error('Key ownership found to be not distinct'); + // } + // } else { + // entityAlias = alias; + // } + // } + } else if (entities[alias] && entities[alias].is(record, config)) { + entityAlias = alias; + break; + } + } + + return entityAlias; +} + +module.exports = { + Entity, + clauses, + getEntityIdentifiers, + matchToEntityAlias, +}; + +},{"./clauses":11,"./client":12,"./errors":15,"./events":16,"./filters":18,"./operations":19,"./schema":20,"./types":24,"./util":27,"./validations":28,"./where":29}],15:[function(require,module,exports){ +// # Errors: +// 1000 - Configuration Errors +// 2000 - Invalid Queries +// 3000 - User Defined Errors +// 4000 - DynamoDB Errors +// 5000 - Unexpected Errors + +function getHelpLink(section) { + section = section || "unknown-error-5001"; + return `https://electrodb.dev/en/reference/errors/#${section}`; +} + +const ErrorCode = Symbol("error-code"); + +const ErrorCodes = { + NoClientDefined: { + code: 1001, + section: "no-client-defined-on-model", + name: "NoClientDefined", + sym: ErrorCode, + }, + InvalidIdentifier: { + code: 1002, + section: "invalid-identifier", + name: "InvalidIdentifier", + sym: ErrorCode, + }, + InvalidKeyCompositeAttributeTemplate: { + code: 1003, + section: "invalid-key-composite-attribute-template", + name: "InvalidKeyCompositeAttributeTemplate", + sym: ErrorCode, + }, + DuplicateIndexes: { + code: 1004, + section: "duplicate-indexes", + name: "DuplicateIndexes", + sym: ErrorCode, + }, + CollectionNoSK: { + code: 1005, + section: "collection-without-an-sk", + name: "CollectionNoSK", + sym: ErrorCode, + }, + DuplicateCollections: { + code: 1006, + section: "duplicate-collections", + name: "DuplicateCollections", + sym: ErrorCode, + }, + MissingPrimaryIndex: { + code: 1007, + section: "missing-primary-index", + name: "MissingPrimaryIndex", + sym: ErrorCode, + }, + InvalidAttributeDefinition: { + code: 1008, + section: "invalid-attribute-definition", + name: "InvalidAttributeDefinition", + sym: ErrorCode, + }, + InvalidModel: { + code: 1009, + section: "invalid-model", + name: "InvalidModel", + sym: ErrorCode, + }, + InvalidOptions: { + code: 1010, + section: "invalid-options", + name: "InvalidOptions", + sym: ErrorCode, + }, + InvalidFilter: { + code: 1011, + section: "filters", + name: "InvalidFilter", + sym: ErrorCode, + }, + InvalidWhere: { + code: 1012, + section: "where", + name: "InvalidWhere", + sym: ErrorCode, + }, + InvalidJoin: { + code: 1013, + section: "join", + name: "InvalidJoin", + sym: ErrorCode, + }, + DuplicateIndexFields: { + code: 1014, + section: "duplicate-index-fields", + name: "DuplicateIndexField", + sym: ErrorCode, + }, + DuplicateIndexCompositeAttributes: { + code: 1015, + section: "duplicate-index-composite-attributes", + name: "DuplicateIndexCompositeAttributes", + sym: ErrorCode, + }, + InvalidAttributeWatchDefinition: { + code: 1016, + section: "invalid-attribute-watch-definition", + name: "InvalidAttributeWatchDefinition", + sym: ErrorCode, + }, + IncompatibleKeyCompositeAttributeTemplate: { + code: 1017, + section: "incompatible-key-composite-attribute-template", + name: "IncompatibleKeyCompositeAttributeTemplate", + sym: ErrorCode, + }, + InvalidIndexWithAttributeName: { + code: 1018, + section: "invalid-index-with-attribute-name", + name: "InvalidIndexWithAttributeName", + sym: ErrorCode, + }, + InvalidCollectionOnIndexWithAttributeFieldNames: { + code: 1019, + section: "invalid-collection-on-index-with-attribute-field-names", + name: "InvalidIndexCompositeWithAttributeName", + sym: ErrorCode, + }, + IncompatibleKeyCasing: { + code: 1020, + section: "incompatible-key-casing", + name: "IncompatibleKeyCasing", + sym: ErrorCode, + }, + InvalidListenerProvided: { + code: 1021, + section: "invalid-listener-provided", + name: "InvalidListenerProvided", + sym: ErrorCode, + }, + InvalidLoggerProvided: { + code: 1022, + section: "invalid-logger-provided", + name: "InvalidLoggerProvided", + sym: ErrorCode, + }, + InvalidClientProvided: { + code: 1023, + section: "invalid-client-provided", + name: "InvalidClientProvided", + sym: ErrorCode, + }, + InconsistentIndexDefinition: { + code: 1024, + section: "inconsistent-index-definition", + name: "Inconsistent Index Definition", + sym: ErrorCode, + }, + InvalidProjectionDefinition: { + code: 1025, + section: "invalid-projection-definition", + name: "InvalidProjectionDefinition", + sym: ErrorCode, + }, + InvalidIndexDefinition: { + code: 1026, + section: "invalid-index-definition", + name: "InvalidIndexDefinition", + sym: ErrorCode, + }, + MissingAttribute: { + code: 2001, + section: "missing-attribute", + name: "MissingAttribute", + sym: ErrorCode, + }, + IncompleteCompositeAttributes: { + code: 2002, + section: "missing-composite-attributes", + name: "IncompleteCompositeAttributes", + sym: ErrorCode, + }, + MissingTable: { + code: 2003, + section: "missing-table", + name: "MissingTable", + sym: ErrorCode, + }, + InvalidConcurrencyOption: { + code: 2004, + section: "invalid-concurrency-option", + name: "InvalidConcurrencyOption", + sym: ErrorCode, + }, + InvalidPagesOption: { + code: 2005, + section: "invalid-pages-option", + name: "InvalidPagesOption", + sym: ErrorCode, + }, + InvalidLimitOption: { + code: 2006, + section: "invalid-limit-option", + name: "InvalidLimitOption", + sym: ErrorCode, + }, + InvalidConversionKeysProvided: { + code: 2007, + section: "invalid-conversion-values-provided", + name: "InvalidConversionKeysProvided", + sym: ErrorCode, + }, + InvalidConversionCursorProvided: { + code: 2008, + section: "invalid-conversion-values-provided", + name: "InvalidConversionCursorProvided", + sym: ErrorCode, + }, + InvalidConversionCompositeProvided: { + code: 2009, + section: "invalid-conversion-values-provided", + name: "InvalidConversionCompositeProvided", + sym: ErrorCode, + }, + DuplicateUpdateCompositesProvided: { + code: 2010, + section: "duplicate-update-composites-provided", + name: "DuplicateUpdateCompositesProvided", + sym: ErrorCode, + }, + InvalidIndexCondition: { + code: 2011, + section: "invalid-index-option", + name: "InvalidIndexOption", + sym: ErrorCode, + }, + IncompleteIndexCompositesAttributesProvided: { + code: 2012, + section: "invalid-index-composite-attributes-provided", + name: "IncompleteIndexCompositesAttributesProvided", + sym: ErrorCode, + }, + InvalidQueryParameters: { + code: 2013, + section: "invalid-query-parameters", + name: "InvalidQueryParameters", + sym: ErrorCode, + }, + InvalidAttribute: { + code: 3001, + section: "invalid-attribute", + name: "InvalidAttribute", + sym: ErrorCode, + }, + AWSError: { + code: 4001, + section: "aws-error", + name: "AWSError", + sym: ErrorCode, + }, + OperationAborted: { + code: 4002, + section: "operation-aborted", + name: "OperationAborted", + sym: ErrorCode, + }, + UnknownError: { + code: 5001, + section: "unknown-error", + name: "UnknownError", + sym: ErrorCode, + }, + GeneralError: { + code: 5002, + section: "", + name: "GeneralError", + sym: ErrorCode, + }, + LastEvaluatedKey: { + code: 5003, + section: "invalid-last-evaluated-key", + name: "LastEvaluatedKey", + sym: ErrorCode, + }, + NoOwnerForPager: { + code: 5004, + section: "no-owner-for-pager", + name: "NoOwnerForPager", + sym: ErrorCode, + }, + NoOwnerForCursor: { + code: 5004, + section: "no-owner-for-pager", + name: "NoOwnerForCursor", + sym: ErrorCode, + }, + PagerNotUnique: { + code: 5005, + section: "pager-not-unique", + name: "NoOwnerForPager", + sym: ErrorCode, + }, +}; + +function makeMessage(message, section) { + return `${message} - For more detail on this error reference: ${getHelpLink( + section, + )}`; +} + +class ElectroError extends Error { + constructor(code, message, cause, params = null) { + super(message, { cause }); + let detail = ErrorCodes.UnknownError; + if (code && code.sym === ErrorCode) { + detail = code; + } + this.cause = cause; + this._message = message; + // this.message = `${message} - For more detail on this error reference: ${getHelpLink(detail.section)}`; + this.message = makeMessage(message, detail.section); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, ElectroError); + } + + this.name = "ElectroError"; + this.ref = code; + this.code = detail.code; + this.date = Date.now(); + this.isElectroError = true; + applyParamsFn(this, params); + } +} + +function applyParamsFn(error, params = null) { + Object.defineProperty(error, 'params', { + enumerable: false, + writable: true, + configurable: true, + value: () => { + return params; + } + }); +} + +class ElectroValidationError extends ElectroError { + constructor(errors = []) { + const fields = []; + const messages = []; + for (let i = 0; i < errors.length; i++) { + const error = errors[i]; + const message = error ? error._message || error.message : undefined; + messages.push(message); + if (error instanceof ElectroUserValidationError) { + fields.push({ + field: error.field, + index: error.index, + reason: message, + cause: error.cause, + type: "validation", + }); + } else if (error instanceof ElectroAttributeValidationError) { + fields.push({ + field: error.field, + index: error.index, + reason: message, + cause: error.cause || error, // error | undefined + type: "validation", + }); + } else if (message) { + fields.push({ + field: "", + index: error.index, + reason: message, + cause: error !== undefined ? error.cause || error : undefined, + type: "fatal", + }); + } + } + + const message = + messages + .filter((message) => typeof message === "string" && message.length) + .join(", ") || `Invalid value(s) provided`; + + super(ErrorCodes.InvalidAttribute, message); + this.fields = fields; + this.name = "ElectroValidationError"; + } +} + +class ElectroUserValidationError extends ElectroError { + constructor(field, cause) { + let message; + let hasCause = false; + if (typeof cause === "string") { + message = cause; + } else if ( + cause !== undefined && + typeof cause._message === "string" && + cause._message.length + ) { + message = cause._message; + hasCause = true; + } else if ( + cause !== undefined && + typeof cause.message === "string" && + cause.message.length + ) { + message = cause.message; + hasCause = true; + } else { + message = "Invalid value provided"; + } + super(ErrorCodes.InvalidAttribute, message); + this.field = field; + this.name = "ElectroUserValidationError"; + if (hasCause) { + this.cause = cause; + } + } +} + +class ElectroAttributeValidationError extends ElectroError { + constructor(field, reason) { + super(ErrorCodes.InvalidAttribute, reason); + this.field = field; + } +} + +module.exports = { + ErrorCodes, + ElectroError, + applyParamsFn, + ElectroValidationError, + ElectroUserValidationError, + ElectroAttributeValidationError, +}; + +},{}],16:[function(require,module,exports){ +const e = require("./errors"); +const v = require("./validations"); + +class EventManager { + static createSafeListener(listener) { + if (listener === undefined) { + return undefined; + } + if (!v.isFunction(listener)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidListenerProvided, + `Provided listener is not of type 'function'`, + ); + } else { + return (...params) => { + try { + listener(...params); + } catch (err) { + console.error(`Error invoking user supplied listener`, err); + } + }; + } + } + + static normalizeListeners(listeners = []) { + if (!Array.isArray(listeners)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidListenerProvided, + `Listeners must be provided as an array of functions`, + ); + } + return listeners + .map((listener) => EventManager.createSafeListener(listener)) + .filter((listener) => { + switch (typeof listener) { + case "function": + return true; + case "undefined": + return false; + default: + throw new e.ElectroError( + e.ErrorCodes.InvalidListenerProvided, + `Provided listener is not of type 'function`, + ); + } + }); + } + + constructor({ listeners = [] } = {}) { + this.listeners = EventManager.normalizeListeners(listeners); + } + + add(listeners = []) { + if (!Array.isArray(listeners)) { + listeners = [listeners]; + } + + this.listeners = this.listeners.concat( + EventManager.normalizeListeners(listeners), + ); + } + + trigger(event, adHocListeners = []) { + const allListeners = [ + ...this.listeners, + ...EventManager.normalizeListeners(adHocListeners), + ]; + + for (const listener of allListeners) { + listener(event); + } + } +} + +module.exports = { + EventManager, +}; + +},{"./errors":15,"./validations":28}],17:[function(require,module,exports){ +const FilterOperations = { + escape: { + template: function escape(options, attr) { + return `${attr}`; + }, + rawValue: true, + }, + size: { + template: function size(options, attr, name) { + return `size(${name})`; + }, + strict: false, + }, + type: { + template: function attributeType(options, attr, name, value) { + return `attribute_type(${name}, ${value})`; + }, + strict: false, + }, + ne: { + template: function ne(options, attr, name, value) { + return `${name} <> ${value}`; + }, + strict: false, + }, + eq: { + template: function eq(options, attr, name, value) { + return `${name} = ${value}`; + }, + strict: false, + }, + gt: { + template: function gt(options, attr, name, value) { + return `${name} > ${value}`; + }, + strict: false, + }, + lt: { + template: function lt(options, attr, name, value) { + return `${name} < ${value}`; + }, + strict: false, + }, + gte: { + template: function gte(options, attr, name, value) { + return `${name} >= ${value}`; + }, + strict: false, + }, + lte: { + template: function lte(options, attr, name, value) { + return `${name} <= ${value}`; + }, + strict: false, + }, + between: { + template: function between(options, attr, name, value1, value2) { + return `(${name} between ${value1} and ${value2})`; + }, + strict: false, + }, + begins: { + template: function begins(options, attr, name, value) { + return `begins_with(${name}, ${value})`; + }, + strict: false, + }, + exists: { + template: function exists(options, attr, name) { + return `attribute_exists(${name})`; + }, + strict: false, + }, + notExists: { + template: function notExists(options, attr, name) { + return `attribute_not_exists(${name})`; + }, + strict: false, + }, + contains: { + template: function contains(options, attr, name, value) { + return `contains(${name}, ${value})`; + }, + strict: false, + }, + notContains: { + template: function notContains(options, attr, name, value) { + return `not contains(${name}, ${value})`; + }, + strict: false, + }, + value: { + template: function (options, attr, name, value) { + return value; + }, + strict: false, + canNest: true, + }, + name: { + template: function (options, attr, name) { + return name; + }, + strict: false, + canNest: true, + }, + eqOrNotExists: { + template: function eq(options, attr, name, value) { + return `(${name} = ${value} OR attribute_not_exists(${name}))`; + }, + strict: false, + }, + field: { + template: function (options, _, fieldName) { + return fieldName !== undefined ? `${fieldName}` : ""; + }, + strict: false, + canNest: true, + rawField: true, + }, +}; + +module.exports = { + FilterOperations, +}; + +},{}],18:[function(require,module,exports){ +const e = require("./errors"); +const { MethodTypes, ExpressionTypes } = require("./types"); + +class FilterFactory { + constructor(attributes = {}, filterTypes = {}) { + this.attributes = { ...attributes }; + this.filters = { + ...filterTypes, + }; + } + + getExpressionType(methodType) { + switch (methodType) { + case MethodTypes.put: + case MethodTypes.create: + case MethodTypes.update: + case MethodTypes.patch: + case MethodTypes.delete: + case MethodTypes.get: + case MethodTypes.upsert: + return ExpressionTypes.ConditionExpression; + default: + return ExpressionTypes.FilterExpression; + } + } + + _buildFilterAttributes(setName, setValue) { + let attributes = {}; + for (let [name, attribute] of Object.entries(this.attributes)) { + let filterAttribute = {}; + for (let [type, { template }] of Object.entries(this.filters)) { + Object.defineProperty(filterAttribute, type, { + get: () => { + return (...values) => { + let { prop } = setName({}, name, attribute.field); + let attrValues = []; + for (let value of values) { + if (template.length > 1) { + attrValues.push(setValue(name, value, name)); + } + } + let expression = template({}, attribute, prop, ...attrValues); + return expression.trim(); + }; + }, + }); + } + attributes[name] = filterAttribute; + } + return attributes; + } + + buildClause(filterFn) { + return (entity, state, ...params) => { + const type = this.getExpressionType(state.query.method); + const builder = state.query.filter[type]; + let setName = (paths, name, value) => builder.setName(paths, name, value); + let setValue = (name, value, path) => builder.setValue(name, value, path); + let attributes = this._buildFilterAttributes(setName, setValue); + const expression = filterFn(attributes, ...params); + if (typeof expression !== "string") { + throw new e.ElectroError( + e.ErrorCodes.InvalidFilter, + "Invalid filter response. Expected result to be of type string", + ); + } + builder.add(expression); + return state; + }; + } + + injectFilterClauses(clauses = {}, filters = {}) { + let injected = { ...clauses }; + let filterParents = Object.entries(injected) + .filter((clause) => { + let [name, { children }] = clause; + return children.find((child) => ["go", "commit"].includes(child)); + }) + .map(([name]) => name); + let modelFilters = Object.keys(filters); + let filterChildren = []; + for (let [name, filter] of Object.entries(filters)) { + filterChildren.push(name); + injected[name] = { + name: name, + action: this.buildClause(filter), + children: ["params", "go", "commit", "filter", ...modelFilters], + }; + } + filterChildren.push("filter"); + injected["filter"] = { + name: "filter", + action: (entity, state, fn) => { + return this.buildClause(fn)(entity, state); + }, + children: ["params", "go", "commit", "filter", ...modelFilters], + }; + for (let parent of filterParents) { + injected[parent] = { ...injected[parent] }; + injected[parent].children = [ + ...filterChildren, + ...injected[parent].children, + ]; + } + return injected; + } +} + +module.exports = { FilterFactory }; + +},{"./errors":15,"./types":24}],19:[function(require,module,exports){ +const { + AttributeTypes, + ItemOperations, + AttributeProxySymbol, + BuilderTypes, +} = require("./types"); +const { UpdateOperations } = require("./updateOperations"); +const { FilterOperations } = require("./filterOperations"); +const e = require("./errors"); +const u = require("./util"); + + +/** + * formatExpressionName: formats a field name for expression attribute names parameters. + * @param {string} name + * @param {Map} seen + */ +function formatExpressionName(name, seen) { + const nameWasNotANumber = isNaN(name); + const originalName = `${name}`; + let formattedName = originalName.replaceAll(/[^\w]/g, ""); + + if (formattedName.length === 0) { + formattedName = "p"; + } else if (nameWasNotANumber !== isNaN(formattedName)) { + // name became number due to replace + formattedName = `p${formattedName}`; + } + + const originalFormattedName = formattedName; + let nameSuffix = 1; + while ( + seen.has(formattedName) && + seen.get(formattedName) !== originalName + ) { + formattedName = `${originalFormattedName}_${++nameSuffix}`; + } + + seen.set(formattedName, originalName); + return formattedName; +} + +class ExpressionState { + constructor({ prefix } = {}) { + this.names = {}; + this.values = {}; + this.paths = {}; + this.counts = {}; + this.impacted = {}; + this.expression = ""; + this.prefix = prefix || ""; + this.refs = {}; + this.formattedNameToOriginalNameMap = new Map(); + } + + incrementName(name) { + if (this.counts[name] === undefined) { + this.counts[name] = 0; + } + return `${this.prefix}${this.counts[name]++}`; + } + + formatName(name = "") { + return formatExpressionName(name, this.formattedNameToOriginalNameMap); + } + + // todo: make the structure: name, value, paths + setName(paths, name, value) { + name = this.formatName(name); + let json = ""; + let expression = ""; + const prop = `#${name}`; + if (Object.keys(paths).length === 0) { + json = `${name}`; + expression = `${prop}`; + this.names[prop] = value; + } else if (isNaN(name)) { + json = `${paths.json}.${name}`; + expression = `${paths.expression}.${prop}`; + this.names[prop] = value; + } else { + json = `${paths.json}[${name}]`; + expression = `${paths.expression}[${name}]`; + } + return { json, expression, prop }; + } + + getNames() { + return this.names; + } + + setValue(name, value) { + const formated = this.formatName(name); + let valueCount = this.incrementName(formated); + let expression = `:${formated}${valueCount}`; + this.values[expression] = value; + return expression; + } + + updateValue(name, value) { + this.values[name] = value; + } + + getValues() { + return this.values; + } + + setPath(path, value) { + this.paths[path] = value; + } + + setExpression(expression) { + this.expression = expression; + } + + getExpression() { + return this.expression; + } + + setImpacted(operation, path, ref) { + this.impacted[path] = operation; + this.refs[path] = ref; + } +} + +class AttributeOperationProxy { + constructor({ builder, attributes = {}, operations = {} }) { + this.ref = { + attributes, + operations, + }; + this.attributes = AttributeOperationProxy.buildAttributes( + builder, + attributes, + ); + this.operations = AttributeOperationProxy.buildOperations( + builder, + operations, + ); + } + + invokeCallback(op, ...params) { + return op(this.attributes, this.operations, ...params); + } + + performOperation({ operation, path, value, force = false }) { + if (value === undefined) { + return; + } + const parts = u.parseJSONPath(path); + let attribute = this.attributes; + for (let part of parts) { + attribute = attribute[part]; + } + if (attribute) { + this.operations[operation](attribute, value); + const { target } = attribute(); + if (target.readOnly && !force) { + throw new Error( + `Attribute "${target.path}" is Read-Only and cannot be updated`, + ); + } + } + } + + fromObject(operation, record) { + for (let path of Object.keys(record)) { + this.performOperation({ + operation, + path, + value: record[path], + }); + } + } + + fromArray(operation, paths) { + for (let path of paths) { + const parts = u.parseJSONPath(path); + let attribute = this.attributes; + for (let part of parts) { + attribute = attribute[part]; + } + if (attribute) { + this.operations[operation](attribute); + const { target } = attribute(); + if (target.readOnly) { + throw new Error( + `Attribute "${target.path}" is Read-Only and cannot be updated`, + ); + } else if (operation === ItemOperations.remove && target.required) { + throw new Error( + `Attribute "${target.path}" is Required and cannot be removed`, + ); + } + } + } + } + + static buildOperations(builder, operations) { + let ops = {}; + let seen = new Map(); + for (let operation of Object.keys(operations)) { + let { template, canNest, rawValue, rawField } = operations[operation]; + Object.defineProperty(ops, operation, { + get: () => { + return (property, ...values) => { + if (property === undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidWhere, + `Invalid/Unknown property passed in where clause passed to operation: '${operation}'`, + ); + } + if (property[AttributeProxySymbol]) { + const { commit, target } = property(); + const fixedValues = values + .map((value) => target.applyFixings(value)) + .filter((value) => value !== undefined); + const isFilterBuilder = builder.type === BuilderTypes.filter; + const takesValueArgument = template.length > 3; + const isAcceptableValue = fixedValues.every((value) => { + const seenAttributes = seen.get(value); + if (seenAttributes) { + return seenAttributes.every((v) => target.acceptable(v)); + } + return target.acceptable(value); + }); + + const shouldCommit = + // if it is a filterBuilder than we don't care what they pass because the user needs more freedom here + isFilterBuilder || + // if the operation does not take a value argument then not committing here could cause problems. + // this should be revisited to make more robust, we could hypothetically store the commit in the + // "seen" map for when the value is used, but that's a lot of new complexity + !takesValueArgument || + // if the operation takes a value, we should determine if that value is acceptable. For + // example, in the cases of a "set" we check to see if it is empty, or if the value is + // undefined, we should not commit. The "fixedValues" length check is because the + // "fixedValues" array has been filtered for undefined, so no length there indicates an + // undefined value was passed. + (takesValueArgument && + isAcceptableValue && + fixedValues.length > 0); + + if (!shouldCommit) { + return ""; + } + + const paths = commit(); + const attributeValues = []; + let hasNestedValue = false; + for (let fixedValue of fixedValues) { + if (seen.has(fixedValue)) { + attributeValues.push(fixedValue); + hasNestedValue = true; + } else { + let attributeValueName = builder.setValue( + target.name, + fixedValue, + ); + builder.setPath(paths.json, { + value: fixedValue, + name: attributeValueName, + }); + attributeValues.push(attributeValueName); + } + } + + const options = { + nestedValue: hasNestedValue, + createValue: (name, value) => + builder.setValue(`${target.name}_${name}`, value), + }; + + const formatted = template( + options, + target, + paths.expression, + ...attributeValues, + ); + builder.setImpacted(operation, paths.json, target); + if (canNest) { + seen.set(paths.expression, attributeValues); + seen.set(formatted, attributeValues); + } + + if ( + builder.type === BuilderTypes.update && + formatted && + typeof formatted.operation === "string" && + typeof formatted.expression === "string" + ) { + builder.add(formatted.operation, formatted.expression); + return formatted.expression; + } + + return formatted; + } else if (rawValue) { + // const {json, expression} = builder.setName({}, property, property); + let attributeValueName = builder.setValue(property, property); + builder.setPath(property, { + value: property, + name: attributeValueName, + }); + const formatted = template({}, attributeValueName); + seen.set(attributeValueName, [property]); + seen.set(formatted, [property]); + return formatted; + } else if (rawField) { + const { prop, expression } = builder.setName( + {}, + property, + property, + ); + const formatted = template({}, null, prop); + seen.set(expression, [property]); + seen.set(formatted, [property]); + return formatted; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidWhere, + `Invalid Attribute in where clause passed to operation '${operation}'. Use injected attributes only.`, + ); + } + }; + }, + }); + } + return ops; + } + + static pathProxy(build) { + return new Proxy(() => build(), { + get: (_, prop, o) => { + if (prop === AttributeProxySymbol) { + return true; + } else { + return AttributeOperationProxy.pathProxy(() => { + const { commit, root, target, builder } = build(); + const attribute = target.getChild(prop); + const nestedAny = + attribute.type === AttributeTypes.any && + // if the name doesn't match that's because we are nested under 'any' + attribute.name !== prop; + let field; + if (attribute === undefined) { + throw new Error( + `Invalid attribute "${prop}" at path "${target.path}.${prop}"`, + ); + } else if (nestedAny) { + field = prop; + } else { + field = attribute.field; + } + + return { + root, + builder, + nestedAny, + target: attribute, + commit: () => { + const paths = commit(); + return builder.setName(paths, prop, field); + }, + }; + }); + } + }, + }); + } + + static buildAttributes(builder, attributes) { + let attr = {}; + for (let [name, attribute] of Object.entries(attributes)) { + Object.defineProperty(attr, name, { + get: () => { + return AttributeOperationProxy.pathProxy(() => { + return { + root: attribute, + target: attribute, + builder, + commit: () => + builder.setName({}, attribute.name, attribute.field), + }; + }); + }, + }); + } + return attr; + } +} + +const FilterOperationNames = Object.keys(FilterOperations).reduce( + (ops, name) => { + ops[name] = name; + return ops; + }, + {}, +); + +const UpdateOperationNames = Object.keys(UpdateOperations).reduce( + (ops, name) => { + ops[name] = name; + return ops; + }, + {}, +); + +module.exports = { + UpdateOperations, + UpdateOperationNames, + FilterOperations, + FilterOperationNames, + ExpressionState, + AttributeOperationProxy, + formatExpressionName, +}; + +},{"./errors":15,"./filterOperations":17,"./types":24,"./updateOperations":26,"./util":27}],20:[function(require,module,exports){ +const { + CastTypes, + ValueTypes, + KeyCasing, + AttributeTypes, + AttributeMutationMethods, + AttributeWildCard, + PathTypes, + TableIndex, + ItemOperations, + DataOptions, +} = require("./types"); +const AttributeTypeNames = Object.keys(AttributeTypes); +const ValidFacetTypes = [ + AttributeTypes.string, + AttributeTypes.number, + AttributeTypes.boolean, + AttributeTypes.enum, +]; +const e = require("./errors"); +const u = require("./util"); +const v = require("./validations"); +const { DynamoDBSet } = require("./set"); + +function getValueType(value) { + if (value === undefined) { + return ValueTypes.undefined; + } else if (value === null) { + return ValueTypes.null; + } else if (typeof value === "string") { + return ValueTypes.string; + } else if (typeof value === "number") { + return ValueTypes.number; + } else if (typeof value === "boolean") { + return ValueTypes.boolean; + } else if (Array.isArray(value)) { + return ValueTypes.array; + } else if (value.wrapperName === "Set") { + return ValueTypes.aws_set; + } else if (value.constructor.name === "Set") { + return ValueTypes.set; + } else if (value.constructor.name === "Map") { + return ValueTypes.map; + } else if (value.constructor.name === "Object") { + return ValueTypes.object; + } else { + return ValueTypes.unknown; + } +} + +class AttributeTraverser { + constructor(parentTraverser) { + if (parentTraverser instanceof AttributeTraverser) { + this.parent = parentTraverser; + this.paths = this.parent.paths; + } else { + this.parent = null; + this.paths = new Map(); + } + this.children = new Map(); + } + + setChild(name, attribute) { + this.children.set(name, attribute); + } + + asChild(name, attribute) { + if (this.parent) { + this.parent.setChild(name, attribute); + } + } + + setPath(path, attribute) { + if (this.parent) { + this.parent.setPath(path, attribute); + } + this.paths.set(path, attribute); + } + + getPath(path) { + path = u.genericizeJSONPath(path); + if (this.parent) { + return this.parent.getPath(path); + } + return this.paths.get(path); + } + + getChild(name) { + return this.children.get(name); + } + + getAllChildren() { + return this.children.entries(); + } + + getAll() { + if (this.parent) { + return this.parent.getAll(); + } + return this.paths.entries(); + } +} + +class Attribute { + constructor(definition = {}) { + this.name = definition.name; + this.field = definition.field || definition.name; + this.label = definition.label; + this.readOnly = !!definition.readOnly; + this.hidden = !!definition.hidden; + this.required = !!definition.required; + this.cast = this._makeCast(definition.name, definition.cast); + this.default = this._makeDefault(definition.default); + this.validate = this._makeValidate(definition.validate); + this.isKeyField = !!definition.isKeyField; + this.unformat = this._makeDestructureKey(definition); + this.format = this._makeStructureKey(definition); + this.padding = definition.padding; + this.applyFixings = this._makeApplyFixings(definition); + this.applyPadding = this._makePadding(definition); + this.indexes = [...(definition.indexes || [])]; + let { isWatched, isWatcher, watchedBy, watching, watchAll } = + Attribute._destructureWatcher(definition); + this._isWatched = isWatched; + this._isWatcher = isWatcher; + this.watchedBy = watchedBy; + this.watching = watching; + this.watchAll = watchAll; + let { type, enumArray } = this._makeType(this.name, definition); + this.type = type; + this.enumArray = enumArray; + this.parentType = definition.parentType; + this.parentPath = definition.parentPath; + const pathType = this.getPathType(this.type, this.parentType); + const path = Attribute.buildPath(this.name, pathType, this.parentPath); + const fieldPath = Attribute.buildPath( + this.field, + pathType, + this.parentType, + ); + this.path = path; + this.fieldPath = fieldPath; + this.traverser = new AttributeTraverser(definition.traverser); + this.traverser.setPath(this.path, this); + this.traverser.setPath(this.fieldPath, this); + this.traverser.asChild(this.name, this); + this.parent = { parentType: this.type, parentPath: this.path }; + this.get = this._makeGet(definition.get); + this.set = this._makeSet(definition.set); + this.getClient = definition.getClient; + } + + static buildChildAttributes(type, definition, parent) { + let items; + let properties; + if (type === AttributeTypes.list) { + items = Attribute.buildChildListItems(definition, parent); + } else if (type === AttributeTypes.set) { + items = Attribute.buildChildSetItems(definition, parent); + } else if (type === AttributeTypes.map) { + properties = Attribute.buildChildMapProperties(definition, parent); + } + + return { items, properties }; + } + + static buildChildListItems(definition, parent) { + const { items, getClient } = definition; + const prop = { ...items, ...parent }; + // The use of "*" is to ensure the child's name is "*" when added to the traverser and searching for the children of a list + return Schema.normalizeAttributes( + { "*": prop }, + {}, + { getClient, traverser: parent.traverser, parent }, + ).attributes["*"]; + } + + static buildChildSetItems(definition, parent) { + const { items, getClient } = definition; + + const allowedTypes = [ + AttributeTypes.string, + AttributeTypes.boolean, + AttributeTypes.number, + AttributeTypes.enum, + ]; + if (!Array.isArray(items) && !allowedTypes.includes(items)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid "items" definition for Set attribute: "${ + definition.path + }". Acceptable item types include ${u.commaSeparatedString( + allowedTypes, + )}`, + ); + } + const prop = { type: items, ...parent }; + return Schema.normalizeAttributes( + { prop }, + {}, + { getClient, traverser: parent.traverser, parent }, + ).attributes.prop; + } + + static buildChildMapProperties(definition, parent) { + const { properties, getClient } = definition; + if (!properties || typeof properties !== "object") { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid "properties" definition for Map attribute: "${definition.path}". The "properties" definition must describe the attributes that the Map will accept`, + ); + } + const attributes = {}; + for (let name of Object.keys(properties)) { + attributes[name] = { ...properties[name], ...parent }; + } + return Schema.normalizeAttributes( + attributes, + {}, + { getClient, traverser: parent.traverser, parent }, + ); + } + + static buildPath(name, type, parentPath) { + if (!parentPath) return name; + switch (type) { + case AttributeTypes.string: + case AttributeTypes.number: + case AttributeTypes.boolean: + case AttributeTypes.map: + case AttributeTypes.set: + case AttributeTypes.list: + case AttributeTypes.enum: + return `${parentPath}.${name}`; + case PathTypes.item: + return `${parentPath}[*]`; + case AttributeTypes.any: + default: + return `${parentPath}.*`; + } + } + + static _destructureWatcher(definition) { + let watchAll = !!definition.watchAll; + let watchingArr = watchAll ? [] : [...(definition.watching || [])]; + let watchedByArr = [...(definition.watchedBy || [])]; + let isWatched = watchedByArr.length > 0; + let isWatcher = watchingArr.length > 0; + let watchedBy = {}; + let watching = {}; + + for (let watched of watchedByArr) { + watchedBy[watched] = watched; + } + + for (let attribute of watchingArr) { + watching[attribute] = attribute; + } + + return { + watchAll, + watching, + watchedBy, + isWatched, + isWatcher, + }; + } + + _makeGet(get) { + this._checkGetSet(get, "get"); + const getter = get + ? (value, getSiblings) => get(value, getSiblings()) + : (attr) => attr; + return (value, getSiblings) => { + if (this.hidden) { + return; + } + value = this.unformat(value); + return getter(value, getSiblings); + }; + } + + _makeSet(set) { + this._checkGetSet(set, "set"); + return set + ? (value, getSiblings) => set(value, getSiblings()) + : (attr) => attr; + } + + _makeApplyFixings({ + prefix = "", + postfix = "", + casing = KeyCasing.none, + } = {}) { + return (value) => { + if (value === undefined) { + return; + } + + if ([AttributeTypes.string, AttributeTypes.enum].includes(this.type)) { + value = `${prefix}${value}${postfix}`; + } + + return u.formatAttributeCasing(value, casing); + }; + } + + _makeStructureKey() { + return (key) => { + return this.applyPadding(key); + }; + } + + _isPaddingEligible(padding = {}) { + return !!padding && padding.length && v.isStringHasLength(padding.char); + } + + _makePadding({ padding = {} }) { + return (value) => { + if (typeof value !== "string") { + return value; + } else if (this._isPaddingEligible(padding)) { + return u.addPadding({ padding, value }); + } else { + return value; + } + }; + } + + _makeRemoveFixings({ + prefix = "", + postfix = "", + casing = KeyCasing.none, + } = {}) { + return (key) => { + let value = ""; + if ( + ![AttributeTypes.string, AttributeTypes.enum].includes(this.type) || + typeof key !== "string" + ) { + value = key; + } else if (prefix.length > 0 && key.length > prefix.length) { + for (let i = prefix.length; i < key.length - postfix.length; i++) { + value += key[i]; + } + } else { + value = key; + } + + return value; + }; + } + + _makeDestructureKey({ + prefix = "", + postfix = "", + casing = KeyCasing.none, + padding = {}, + } = {}) { + return (key) => { + let value = ""; + if ( + ![AttributeTypes.string, AttributeTypes.enum].includes(this.type) || + typeof key !== "string" + ) { + return key; + } else if (key.length > prefix.length) { + value = u.removeFixings({ prefix, postfix, value: key }); + } else { + value = key; + } + + // todo: if an attribute is also used as a pk or sk directly in one index, but a composite in another, then padding is going to be broken + // if (padding && padding.length) { + // value = u.removePadding({padding, value}); + // } + + return value; + }; + } + + acceptable(val) { + return val !== undefined; + } + + getPathType(type, parentType) { + if ( + parentType === AttributeTypes.list || + parentType === AttributeTypes.set + ) { + return PathTypes.item; + } + return type; + } + + getAttribute(path) { + return this.traverser.getPath(path); + } + + getChild(path) { + if (this.type === AttributeTypes.any) { + return this; + } else if ( + !isNaN(path) && + (this.type === AttributeTypes.list || this.type === AttributeTypes.set) + ) { + // if they're asking for a number, and this is a list, children will be under "*" + return this.traverser.getChild("*"); + } else { + return this.traverser.getChild(path); + } + } + + _checkGetSet(val, type) { + if (typeof val !== "function" && val !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid "${type}" property for attribute ${this.path}. Please ensure value is a function or undefined.`, + ); + } + } + + _makeCast(name, cast) { + if (cast !== undefined && !CastTypes.includes(cast)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid "cast" property for attribute: "${name}". Acceptable types include ${CastTypes.join( + ", ", + )}`, + ); + } else if (cast === AttributeTypes.string) { + return (val) => { + if (val === undefined) { + // todo: #electroerror + throw new Error( + `Attribute ${name} is undefined and cannot be cast to type ${cast}`, + ); + } else if (typeof val === "string") { + return val; + } else { + return JSON.stringify(val); + } + }; + } else if (cast === AttributeTypes.number) { + return (val) => { + if (val === undefined) { + // todo: #electroerror + throw new Error( + `Attribute ${name} is undefined and cannot be cast to type ${cast}`, + ); + } else if (typeof val === "number") { + return val; + } else { + let results = Number(val); + if (isNaN(results)) { + // todo: #electroerror + throw new Error( + `Attribute ${name} cannot be cast to type ${cast}. Doing so results in NaN`, + ); + } else { + return results; + } + } + }; + } else { + return (val) => val; + } + } + + _makeValidate(definition) { + if (typeof definition === "function") { + return (val) => { + try { + let isValid = !!definition(val); + return [ + isValid, + isValid + ? [] + : [ + new e.ElectroUserValidationError( + this.path, + "Invalid value provided", + ), + ], + ]; + } catch (err) { + return [false, [new e.ElectroUserValidationError(this.path, err)]]; + } + }; + } else if (definition instanceof RegExp) { + return (val) => { + if (val === undefined) { + return [true, []]; + } + let isValid = definition.test(val); + let reason = []; + if (!isValid) { + reason.push( + new e.ElectroUserValidationError( + this.path, + `Invalid value for attribute "${this.path}": Failed model defined regex`, + ), + ); + } + return [isValid, reason]; + }; + } else { + return () => [true, []]; + } + } + + _makeDefault(definition) { + if (typeof definition === "function") { + return () => definition(); + } else { + return () => definition; + } + } + + _makeType(name, definition) { + let type = ""; + let enumArray = []; + if (Array.isArray(definition.type)) { + type = AttributeTypes.enum; + enumArray = [...definition.type]; + // } else if (definition.type === AttributeTypes.set && Array.isArray(definition.items)) { + // type = AttributeTypes.enumSet; + // enumArray = [...definition.items]; + } else { + type = definition.type || "string"; + } + if (!AttributeTypeNames.includes(type)) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid "type" property for attribute: "${name}". Acceptable types include ${AttributeTypeNames.join( + ", ", + )}`, + ); + } + return { type, enumArray }; + } + + isWatcher() { + return this._isWatcher; + } + + isWatched() { + return this._isWatched; + } + + isWatching(attribute) { + return this.watching[attribute] !== undefined; + } + + isWatchedBy(attribute) { + return this.watchedBy[attribute] !== undefined; + } + + _isType(value) { + if (value === undefined) { + let reason = []; + if (this.required) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Value is required.`, + ), + ); + } + return [!this.required, reason]; + } + let isTyped = false; + let reason = []; + switch (this.type) { + case AttributeTypes.enum: + // case AttributeTypes.enumSet: + // isTyped = this.enumArray.every(enumValue => { + // const val = Array.isArray(value) ? value : [value]; + // return val.includes(enumValue); + // }) + isTyped = this.enumArray.includes(value); + if (!isTyped) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${ + this.path + }". Value not found in set of acceptable values: ${u.commaSeparatedString( + this.enumArray, + )}`, + ), + ); + } + break; + case AttributeTypes.any: + case AttributeTypes.static: + case AttributeTypes.custom: + isTyped = true; + break; + case AttributeTypes.string: + case AttributeTypes.number: + case AttributeTypes.boolean: + default: + isTyped = typeof value === this.type; + if (!isTyped) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${ + this.path + }". Received value of type "${typeof value}", expected value of type "${ + this.type + }"`, + ), + ); + } + break; + } + return [isTyped, reason]; + } + + isValid(value) { + try { + let [isTyped, typeErrorReason] = this._isType(value); + let [isValid, validationError] = isTyped + ? this.validate(value) + : [false, []]; + let errors = [...typeErrorReason, ...validationError].filter( + (value) => value !== undefined, + ); + return [isTyped && isValid, errors]; + } catch (err) { + return [false, [err]]; + } + } + + val(value) { + value = this.cast(value); + if (value === undefined) { + value = this.default(); + } + return value; + } + + getValidate(value) { + value = this.val(value); + let [isValid, validationErrors] = this.isValid(value); + if (!isValid) { + throw new e.ElectroValidationError(validationErrors); + } + return value; + } +} + +class MapAttribute extends Attribute { + constructor(definition) { + super(definition); + const properties = Attribute.buildChildMapProperties(definition, { + parentType: this.type, + parentPath: this.path, + traverser: this.traverser, + }); + this.properties = properties; + this.isRoot = !!definition.isRoot; + this.get = this._makeGet(definition.get, properties); + this.set = this._makeSet(definition.set, properties); + } + + _makeGet(get, properties) { + this._checkGetSet(get, "get"); + const getter = get + ? (value, getSiblings) => get(value, getSiblings()) + : (val) => { + const isEmpty = !val || Object.keys(val).length === 0; + const isNotRequired = !this.required; + const doesNotHaveDefault = this.default === undefined; + const isRoot = this.isRoot; + if (isEmpty && isRoot && isNotRequired && doesNotHaveDefault) { + return undefined; + } + return val; + }; + return (values, getSiblings) => { + const data = {}; + + if (this.hidden) { + return; + } + + if (values === undefined) { + if (!get) { + return undefined; + } + return getter(data, getSiblings); + } + + for (const name of Object.keys(properties.attributes)) { + const attribute = properties.attributes[name]; + if (values[attribute.field] !== undefined) { + let results = attribute.get(values[attribute.field], () => ({ + ...values, + })); + if (results !== undefined) { + data[name] = results; + } + } + } + + return getter(data, getSiblings); + }; + } + + _makeSet(set, properties) { + this._checkGetSet(set, "set"); + const setter = set + ? (val, getSiblings) => set(val, getSiblings()) + : (val) => { + const isEmpty = !val || Object.keys(val).length === 0; + const isNotRequired = !this.required; + const doesNotHaveDefault = this.default === undefined; + const defaultIsValue = this.default === val; + const isRoot = this.isRoot; + if (defaultIsValue) { + return val; + } else if (isEmpty && isRoot && isNotRequired && doesNotHaveDefault) { + return undefined; + } else { + return val; + } + }; + + return (values, getSiblings) => { + const data = {}; + if (values === undefined) { + if (!set) { + return undefined; + } + return setter(values, getSiblings); + } + for (const name of Object.keys(properties.attributes)) { + const attribute = properties.attributes[name]; + if (values[name] !== undefined) { + const results = attribute.set(values[name], () => ({ ...values })); + if (results !== undefined) { + data[attribute.field] = results; + } + } + } + return setter(data, getSiblings); + }; + } + + _isType(value) { + if (value === undefined) { + let reason = []; + if (this.required) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Value is required.`, + ), + ); + } + return [!this.required, reason]; + } + const valueType = getValueType(value); + if (valueType !== ValueTypes.object) { + return [ + false, + [ + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path "${this.path}. Received value of type "${valueType}", expected value of type "object"`, + ), + ], + ]; + } + let reason = []; + const [childrenAreValid, childErrors] = this._validateChildren(value); + if (!childrenAreValid) { + reason = childErrors; + } + return [childrenAreValid, reason]; + } + + _validateChildren(value) { + const valueType = getValueType(value); + const attributes = this.properties.attributes; + let errors = []; + if (valueType === ValueTypes.object) { + for (const child of Object.keys(attributes)) { + const [isValid, errorValues] = attributes[child].isValid( + value === undefined ? value : value[child], + ); + if (!isValid) { + errors = [...errors, ...errorValues]; + } + } + } else if (valueType !== ValueTypes.object) { + errors.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Expected value to be an object to fulfill attribute type "${this.type}"`, + ), + ); + } else if (this.properties.hasRequiredAttributes) { + errors.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${ + this.path + }". Map attribute requires at least the properties ${u.commaSeparatedString( + Object.keys(attributes), + )}`, + ), + ); + } + return [errors.length === 0, errors]; + } + + val(value) { + const incomingIsEmpty = value === undefined; + let fromDefault = false; + let data; + if (value === undefined) { + data = this.default(); + if (data !== undefined) { + fromDefault = true; + } + } else { + data = value; + } + + const valueType = getValueType(data); + + if (data === undefined) { + return data; + } else if (valueType !== "object") { + throw new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Expected value to be an object to fulfill attribute type "${this.type}"`, + ); + } + + const response = {}; + + for (const name of Object.keys(this.properties.attributes)) { + const attribute = this.properties.attributes[name]; + const results = attribute.val(data[attribute.name]); + if (results !== undefined) { + response[name] = results; + } + } + + if ( + Object.keys(response).length === 0 && + !fromDefault && + this.isRoot && + !this.required && + incomingIsEmpty + ) { + return undefined; + } + + return response; + } +} + +class ListAttribute extends Attribute { + constructor(definition) { + super(definition); + const items = Attribute.buildChildListItems(definition, { + parentType: this.type, + parentPath: this.path, + traverser: this.traverser, + }); + this.items = items; + this.get = this._makeGet(definition.get, items); + this.set = this._makeSet(definition.set, items); + } + + _makeGet(get, items) { + this._checkGetSet(get, "get"); + + const getter = get + ? (value, getSiblings) => get(value, getSiblings()) + : (attr) => attr; + + return (values, getSiblings) => { + const data = []; + + if (this.hidden) { + return; + } + + if (values === undefined) { + return getter(data, getSiblings); + } + + for (let value of values) { + const results = items.get(value, () => [...values]); + if (results !== undefined) { + data.push(results); + } + } + + return getter(data, getSiblings); + }; + } + + _makeSet(set, items) { + this._checkGetSet(set, "set"); + const setter = set + ? (value, getSiblings) => set(value, getSiblings()) + : (attr) => attr; + return (values, getSiblings) => { + const data = []; + + if (values === undefined) { + return setter(values, getSiblings); + } + + for (const value of values) { + const results = items.set(value, () => [...values]); + if (results !== undefined) { + data.push(results); + } + } + + return setter(data, getSiblings); + }; + } + + _validateArrayValue(value) { + const reason = []; + const valueType = getValueType(value); + if (value !== undefined && valueType !== ValueTypes.array) { + return [ + false, + [ + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path "${this.path}. Received value of type "${valueType}", expected value of type "array"`, + ), + ], + ]; + } else { + return [true, []]; + } + } + + _isType(value) { + if (value === undefined) { + let reason = []; + if (this.required) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Value is required.`, + ), + ); + } + return [!this.required, reason]; + } + + const [isValidArray, errors] = this._validateArrayValue(value); + if (!isValidArray) { + return [isValidArray, errors]; + } + let reason = []; + const [childrenAreValid, childErrors] = this._validateChildren(value); + if (!childrenAreValid) { + reason = childErrors; + } + return [childrenAreValid, reason]; + } + + _validateChildren(value) { + const valueType = getValueType(value); + const errors = []; + if (valueType === ValueTypes.array) { + for (const i in value) { + const [isValid, errorValues] = this.items.isValid(value[i]); + if (!isValid) { + for (const err of errorValues) { + if ( + err instanceof e.ElectroAttributeValidationError || + err instanceof e.ElectroUserValidationError + ) { + err.index = parseInt(i); + } + errors.push(err); + } + } + } + } else { + errors.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Expected value to be an Array to fulfill attribute type "${this.type}"`, + ), + ); + } + return [errors.length === 0, errors]; + } + + val(value) { + const getValue = (v) => { + v = this.cast(v); + if (v === undefined) { + v = this.default(); + } + return v; + }; + + const data = value === undefined ? getValue(value) : value; + + if (data === undefined) { + return data; + } else if (!Array.isArray(data)) { + throw new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path "${ + this.path + }. Received value of type "${getValueType( + value, + )}", expected value of type "array"`, + ); + } + + const response = []; + for (const d of data) { + const results = this.items.val(d); + if (results !== undefined) { + response.push(results); + } + } + + return response; + } +} + +class SetAttribute extends Attribute { + constructor(definition) { + super(definition); + const items = Attribute.buildChildSetItems(definition, { + parentType: this.type, + parentPath: this.path, + traverser: this.traverser, + }); + this.items = items; + this.get = this._makeGet(definition.get, items); + this.set = this._makeSet(definition.set, items); + this.validate = this._makeSetValidate(definition); + } + + _makeSetValidate(definition) { + const validate = this._makeValidate(definition.validate); + return (value) => { + switch (getValueType(value)) { + case ValueTypes.array: + return validate([...value]); + case ValueTypes.aws_set: + return validate([...value.values]); + case ValueTypes.set: + return validate(Array.from(value)); + default: + return validate(value); + } + }; + } + + fromDDBSet(value) { + switch (getValueType(value)) { + case ValueTypes.aws_set: + return [...value.values]; + case ValueTypes.set: + return Array.from(value); + default: + return value; + } + } + + _createDDBSet(value) { + const client = this.getClient(); + if (client && typeof client.createSet === "function") { + value = Array.isArray(value) ? Array.from(new Set(value)) : value; + return client.createSet(value, { validate: true }); + } else { + return new DynamoDBSet(value, this.items.type); + } + } + + acceptable(val) { + return Array.isArray(val) ? val.length > 0 : this.items.acceptable(val); + } + + toDDBSet(value) { + const valueType = getValueType(value); + let array; + switch (valueType) { + case ValueTypes.set: + array = Array.from(value); + return this._createDDBSet(array); + case ValueTypes.aws_set: + return value; + case ValueTypes.array: + return this._createDDBSet(value); + case ValueTypes.string: + case ValueTypes.number: { + this.items.getValidate(value); + return this._createDDBSet(value); + } + default: + throw new e.ElectroAttributeValidationError( + this.path, + `Invalid attribute value supplied to "set" attribute "${this.path}". Received value of type "${valueType}". Set values must be supplied as either Arrays, native JavaScript Set objects, DocumentClient Set objects, strings, or numbers.`, + ); + } + } + + _makeGet(get, items) { + this._checkGetSet(get, "get"); + const getter = get + ? (value, getSiblings) => get(value, getSiblings()) + : (attr) => attr; + return (values, getSiblings) => { + if (this.hidden) { + return; + } + if (values !== undefined) { + const data = this.fromDDBSet(values); + return getter(data, getSiblings); + } + const data = this.fromDDBSet(values); + const results = getter(data, getSiblings); + if (results !== undefined) { + // if not undefined, try to convert, else no need to return + return this.fromDDBSet(results); + } + }; + } + + _makeSet(set, items) { + this._checkGetSet(set, "set"); + const setter = set + ? (value, getSiblings) => set(value, getSiblings()) + : (attr) => attr; + return (values, getSiblings) => { + const results = setter(this.fromDDBSet(values), getSiblings); + if (results !== undefined) { + return this.toDDBSet(results); + } + }; + } + + _isType(value) { + if (value === undefined) { + const reason = []; + if (this.required) { + reason.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at entity path: "${this.path}". Value is required.`, + ), + ); + } + return [!this.required, reason]; + } + + let reason = []; + const [childrenAreValid, childErrors] = this._validateChildren(value); + if (!childrenAreValid) { + reason = childErrors; + } + return [childrenAreValid, reason]; + } + + _validateChildren(value) { + const valueType = getValueType(value); + let errors = []; + let arr = []; + if (valueType === ValueTypes.array) { + arr = value; + } else if (valueType === ValueTypes.set) { + arr = Array.from(value); + } else if (valueType === ValueTypes.aws_set) { + arr = value.values; + } else { + errors.push( + new e.ElectroAttributeValidationError( + this.path, + `Invalid value type at attribute path: "${this.path}". Expected value to be an Expected value to be an Array, native JavaScript Set objects, or DocumentClient Set objects to fulfill attribute type "${this.type}"`, + ), + ); + } + for (const item of arr) { + const [isValid, errorValues] = this.items.isValid(item); + if (!isValid) { + errors = [...errors, ...errorValues]; + } + } + return [errors.length === 0, errors]; + } + + val(value) { + if (value === undefined) { + value = this.default(); + } + + if (value !== undefined) { + return this.toDDBSet(value); + } + } +} + +class Schema { + constructor( + properties = {}, + facets = {}, + { traverser = new AttributeTraverser(), getClient, parent, isRoot, identifiers } = {}, + ) { + this._validateProperties(properties, parent); + let schema = Schema.normalizeAttributes(properties, facets, { + traverser, + getClient, + parent, + isRoot, + identifiers, + }); + this.getClient = getClient; + this.attributes = schema.attributes; + this.enums = schema.enums; + this.translationForTable = schema.translationForTable; + this.translationForRetrieval = schema.translationForRetrieval; + this.hiddenAttributes = schema.hiddenAttributes; + this.readOnlyAttributes = schema.readOnlyAttributes; + this.requiredAttributes = schema.requiredAttributes; + this.translationForWatching = this._formatWatchTranslations( + this.attributes, + ); + this.traverser = traverser; + this.isRoot = !!isRoot; + } + + static normalizeAttributes( + attributes = {}, + facets = {}, + { traverser, getClient, parent, isRoot, identifiers = {} } = {}, + ) { + const attributeHasParent = !!parent; + let invalidProperties = []; + let normalized = {}; + let usedAttrs = {}; + let enums = {}; + let translationForTable = {}; + let translationForRetrieval = {}; + let watchedAttributes = {}; + let requiredAttributes = new Set(); + let hiddenAttributes = new Set(); + let readOnlyAttributes = new Set(); + let definitions = {}; + for (let name in attributes) { + let attribute = attributes[name]; + if ( + typeof attribute === AttributeTypes.string || + Array.isArray(attribute) + ) { + attribute = { + type: attribute, + }; + } + const field = attribute.field || name; + let isKeyField = false; + let prefix = ""; + let postfix = ""; + let casing = KeyCasing.none; + if (facets.byField && facets.byField[field] !== undefined) { + for (const indexName of Object.keys(facets.byField[field])) { + let definition = facets.byField[field][indexName]; + if (definition.facets.length > 1) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexWithAttributeName, + `Invalid definition for "${ + definition.type + }" field on index "${u.formatIndexNameForDisplay( + indexName, + )}". The ${definition.type} field "${ + definition.field + }" shares a field name with an attribute defined on the Entity, and therefore is not allowed to contain composite references to other attributes. Please either change the field name of the attribute, or redefine the index to use only the single attribute "${ + definition.field + }".`, + ); + } + if (definition.isCustom) { + const keyFieldLabels = + facets.labels[indexName][definition.type].labels; + // I am not sure how more than two would happen but it would mean either + // 1. Code prior has an unknown edge-case. + // 2. Method is being incorrectly used. + if (keyFieldLabels.length > 2) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexWithAttributeName, + `Unexpected definition for "${ + definition.type + }" field on index "${u.formatIndexNameForDisplay( + indexName, + )}". The ${definition.type} field "${ + definition.field + }" shares a field name with an attribute defined on the Entity, and therefore is not possible to have more than two labels as part of it's template. Please either change the field name of the attribute, or reformat the key template to reduce all pre-fixing or post-fixing text around the attribute reference to two.`, + ); + } + isKeyField = true; + casing = definition.casing; + // Walk through the labels, given the above exception handling, I'd expect the first element to + // be the prefix and the second element to be the postfix. + for (const value of keyFieldLabels) { + if (value.name === field) { + prefix = value.label || ""; + } else { + postfix = value.label || ""; + } + } + if ( + attribute.type !== AttributeTypes.string && + !Array.isArray(attribute.type) + ) { + if (prefix.length > 0 || postfix.length > 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexWithAttributeName, + `definition for "${ + definition.type + }" field on index "${u.formatIndexNameForDisplay( + indexName, + )}". Index templates may only have prefix or postfix values on "string" or "enum" type attributes. The ${ + definition.type + } field "${field}" is type "${ + attribute.type + }", and therefore cannot be used with prefixes or postfixes. Please either remove the prefixed or postfixed values from the template or change the field name of the attribute.`, + ); + } + } + } else { + // Upstream middleware should have taken care of this. An error here would mean: + // 1. Code prior has an unknown edge-case. + // 2. Method is being incorrectly used. + throw new e.ElectroError( + e.ErrorCodes.InvalidIndexCompositeWithAttributeName, + `Unexpected definition for "${ + definition.type + }" field on index "${u.formatIndexNameForDisplay( + indexName, + )}". The ${definition.type} field "${ + definition.field + }" shares a field name with an attribute defined on the Entity, and therefore must be defined with a template. Please either change the field name of the attribute, or add a key template to the "${ + definition.type + }" field on index "${u.formatIndexNameForDisplay( + indexName, + )}" with the value: "\${${definition.field}}"`, + ); + } + + if (definition.inCollection) { + throw new e.ElectroError( + e.ErrorCodes.InvalidCollectionOnIndexWithAttributeFieldNames, + `Invalid use of a collection on index "${u.formatIndexNameForDisplay( + indexName, + )}". The ${definition.type} field "${ + definition.field + }" shares a field name with an attribute defined on the Entity, and therefore the index is not allowed to participate in a Collection. Please either change the field name of the attribute, or remove all collection(s) from the index.`, + ); + } + + if (definition.field === field) { + if (attribute.padding !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid padding definition for the attribute "${name}". Padding is not currently supported for attributes that are also defined as table indexes.`, + ); + } + } + } + } + + let isKey = + !!facets.byIndex && + facets.byIndex[TableIndex].all.find((facet) => facet.name === name); + let definition = { + name, + field, + getClient, + casing, + prefix, + postfix, + traverser, + isKeyField: isKeyField || isKey, + isRoot: !!isRoot, + label: attribute.label, + required: !!attribute.required, + default: attribute.default, + validate: attribute.validate, + readOnly: !!attribute.readOnly || isKey, + hidden: !!attribute.hidden, + indexes: (facets.byAttr && facets.byAttr[name]) || [], + type: attribute.type, + get: attribute.get, + set: attribute.set, + watching: Array.isArray(attribute.watch) ? attribute.watch : [], + items: attribute.items, + properties: attribute.properties, + parentPath: attribute.parentPath, + parentType: attribute.parentType, + padding: attribute.padding, + }; + + if (definition.type === AttributeTypes.custom) { + definition.type = AttributeTypes.any; + } + + if (attribute.watch !== undefined) { + if (attribute.watch === AttributeWildCard) { + definition.watchAll = true; + definition.watching = []; + } else if (Array.isArray(attribute.watch)) { + definition.watching = attribute.watch; + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeWatchDefinition, + `Attribute Validation Error. The attribute '${name}' is defined to "watch" an invalid value of: '${attribute.watch}'. The watch property must either be a an array of attribute names, or the single string value of "${AttributeWildCard}".`, + ); + } + } else { + definition.watching = []; + } + + if (definition.readOnly) { + readOnlyAttributes.add(name); + } + + if (definition.hidden) { + hiddenAttributes.add(name); + } + + if (definition.required) { + requiredAttributes.add(name); + } + + if ( + facets.byAttr && + facets.byAttr[definition.name] !== undefined && + !ValidFacetTypes.includes(definition.type) && + !Array.isArray(definition.type) + ) { + let assignedIndexes = facets.byAttr[name].map((assigned) => + assigned.index === "" ? "Table Index" : assigned.index, + ); + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + `Invalid composite attribute definition: Composite attributes must be one of the following: ${ValidFacetTypes.join( + ", ", + )}. The attribute "${name}" is defined as being type "${ + attribute.type + }" but is a composite attribute of the following indexes: ${assignedIndexes.join( + ", ", + )}`, + ); + } + + if (usedAttrs[definition.field] || usedAttrs[name]) { + invalidProperties.push({ + name, + property: "field", + value: definition.field, + expected: `Unique field property, already used by attribute ${ + usedAttrs[definition.field] + }`, + }); + } else { + usedAttrs[definition.field] = definition.name; + } + + translationForTable[definition.name] = definition.field; + translationForRetrieval[definition.field] = definition.name; + + for (let watched of definition.watching) { + watchedAttributes[watched] = watchedAttributes[watched] || []; + watchedAttributes[watched].push(name); + } + + definitions[name] = definition; + } + + for (let name of Object.keys(definitions)) { + const definition = definitions[name]; + + definition.watchedBy = Array.isArray(watchedAttributes[name]) + ? watchedAttributes[name] + : []; + + switch (definition.type) { + case AttributeTypes.map: + normalized[name] = new MapAttribute(definition); + break; + case AttributeTypes.list: + normalized[name] = new ListAttribute(definition); + break; + case AttributeTypes.set: + normalized[name] = new SetAttribute(definition); + break; + default: + normalized[name] = new Attribute(definition); + } + } + + let watchedWatchers = []; + let watchingUnknownAttributes = []; + for (let watched of Object.keys(watchedAttributes)) { + if (normalized[watched] === undefined) { + for (let attribute of watchedAttributes[watched]) { + watchingUnknownAttributes.push({ attribute, watched }); + } + } else if (normalized[watched].isWatcher()) { + for (let attribute of watchedAttributes[watched]) { + watchedWatchers.push({ attribute, watched }); + } + } + } + + if (watchingUnknownAttributes.length > 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeWatchDefinition, + `Attribute Validation Error. The following attributes are defined to "watch" invalid/unknown attributes: ${watchingUnknownAttributes + .map(({ watched, attribute }) => `"${attribute}"->"${watched}"`) + .join(", ")}.`, + ); + } + + if (watchedWatchers.length > 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeWatchDefinition, + `Attribute Validation Error. Attributes may only "watch" other attributes also watch attributes. The following attributes are defined with ineligible attributes to watch: ${watchedWatchers + .map(({ attribute, watched }) => `"${attribute}"->"${watched}"`) + .join(", ")}.`, + ); + } + + let missingProjectionAttributes = Array.isArray(facets.projections) + ? facets.projections.filter(({ name }) => !normalized[name] && !identifiers[name]) + : []; + + if (missingProjectionAttributes.length > 0) { + const byAccessPattern = facets.projections.reduce((groups, { name, accessPattern }) => { + groups[accessPattern] = groups[accessPattern] || []; + groups[accessPattern].push(name); + return groups; + }, {}); + + const invalidDefinitionsByAccessPattern = Object.entries(byAccessPattern).map(([accessPattern, attributes]) => { + return `${accessPattern}: ${u.commaSeparatedString(attributes)}` + }); + + throw new e.ElectroError( + e.ErrorCodes.InvalidProjectionDefinition, + `Unknown index projection attributes provided. The following access patterns were defined with unknown attributes: ${u.commaSeparatedString(invalidDefinitionsByAccessPattern, '', '')}`, + ); + } + + let missingFacetAttributes = Array.isArray(facets.attributes) + ? facets.attributes + .filter(({ name }) => !normalized[name]) + .map((facet) => `"${facet.type}: ${facet.name}"`) + : []; + + if (missingFacetAttributes.length > 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidKeyCompositeAttributeTemplate, + `Invalid key composite attribute template. The following composite attribute attributes were described in the key composite attribute template but were not included model's attributes: ${missingFacetAttributes.join( + ", ", + )}`, + ); + } + if (invalidProperties.length > 0) { + let message = invalidProperties.map( + (prop) => + `Schema Validation Error. Attribute "${prop.name}" property "${prop.property}". Received: "${prop.value}", Expected: "${prop.expected}"`, + ); + throw new e.ElectroError( + e.ErrorCodes.InvalidAttributeDefinition, + message, + ); + } else { + return { + enums, + hiddenAttributes, + readOnlyAttributes, + requiredAttributes, + translationForTable, + translationForRetrieval, + attributes: normalized, + }; + } + } + + _validateProperties() {} + + _formatWatchTranslations(attributes) { + let watchersToAttributes = {}; + let attributesToWatchers = {}; + let watchAllAttributes = {}; + let hasWatchers = false; + for (let name of Object.keys(attributes)) { + if (attributes[name].isWatcher()) { + hasWatchers = true; + watchersToAttributes[name] = attributes[name].watching; + } else if (attributes[name].watchAll) { + hasWatchers = true; + watchAllAttributes[name] = name; + } else { + attributesToWatchers[name] = attributesToWatchers[name] || {}; + attributesToWatchers[name] = attributes[name].watchedBy; + } + } + return { + hasWatchers, + watchAllAttributes, + watchersToAttributes, + attributesToWatchers, + }; + } + + getAttribute(path) { + return this.traverser.getPath(path); + } + + getLabels() { + let labels = {}; + for (let name of Object.keys(this.attributes)) { + let label = this.attributes[name].label; + if (label !== undefined) { + labels[name] = label; + } + } + return labels; + } + + getLabels() { + let labels = {}; + for (let name of Object.keys(this.attributes)) { + let label = this.attributes[name].label; + if (label !== undefined) { + labels[name] = label; + } + } + return labels; + } + + _applyAttributeMutation(method, include, avoid, payload) { + let data = { ...payload }; + const getSiblings = () => ({ ...payload }); + for (let path of Object.keys(include)) { + // this.attributes[attribute] !== undefined | Attribute exists as actual attribute. If `includeKeys` is turned on for example this will include values that do not have a presence in the model and therefore will not have a `.get()` method + // avoid[attribute] === undefined | Attribute shouldn't be in the avoided + const attribute = this.getAttribute(path); + if (attribute !== undefined && avoid[path] === undefined) { + data[path] = attribute[method](payload[path], getSiblings); + } + } + return data; + } + + _fulfillAttributeMutationMethod(method, payload) { + let watchersToTrigger = {}; + // include: payload | We want to hit the getters/setters for any attributes coming in to be changed + // avoid: watchersToAttributes | We want to avoid anything that is a watcher, even if it was included + let avoid = { + ...this.translationForWatching.watchersToAttributes, + ...this.translationForWatching.watchAllAttributes, + }; + let data = this._applyAttributeMutation(method, payload, avoid, payload); + // `data` here will include all the original payload values, but with the mutations applied to on non-watchers + if (!this.translationForWatching.hasWatchers) { + // exit early, why not + return data; + } + for (let attribute of Object.keys(data)) { + let watchers = + this.translationForWatching.attributesToWatchers[attribute]; + // Any of the attributes on data have a watcher? + if (watchers !== undefined) { + watchersToTrigger = { ...watchersToTrigger, ...watchers }; + } + } + + // include: ...data, ...watchersToTrigger | We want to hit attributes that were watching an attribute included in data, and include an properties that were skipped because they were a watcher + // avoid: attributesToWatchers | We want to avoid hit anything that was not a watcher because they were already hit once above + let include = { + ...data, + ...watchersToTrigger, + ...this.translationForWatching.watchAllAttributes, + }; + return this._applyAttributeMutation( + method, + include, + this.translationForWatching.attributesToWatchers, + data, + ); + } + + applyAttributeGetters(payload = {}) { + return this._fulfillAttributeMutationMethod( + AttributeMutationMethods.get, + payload, + ); + } + + applyAttributeSetters(payload = {}) { + return this._fulfillAttributeMutationMethod( + AttributeMutationMethods.set, + payload, + ); + } + + translateFromFields(item = {}, options = {}) { + let data = {}; + let names = this.translationForRetrieval; + for (let [attr, value] of Object.entries(item)) { + let name = names[attr]; + if (name) { + data[name] = value; + } else if (options.data === DataOptions.includeKeys) { + data[attr] = value; + } + } + return data; + } + + translateToFields(payload = {}) { + let record = {}; + for (let [name, value] of Object.entries(payload)) { + let field = this.getFieldName(name); + if (value !== undefined) { + record[field] = value; + } + } + return record; + } + + getFieldName(name) { + if (typeof name === "string") { + return this.translationForTable[name]; + } + } + + checkCreate(payload = {}) { + let record = {}; + for (let attribute of Object.values(this.attributes)) { + let value = payload[attribute.name]; + record[attribute.name] = attribute.getValidate(value); + } + return record; + } + + checkRemove(paths = []) { + for (const path of paths) { + const attribute = this.traverser.getPath(path); + if (!attribute) { + throw new e.ElectroAttributeValidationError( + path, + `Attribute "${path}" does not exist on model.`, + ); + } else if (attribute.readOnly) { + throw new e.ElectroAttributeValidationError( + attribute.path, + `Attribute "${attribute.path}" is Read-Only and cannot be removed`, + ); + } else if (attribute.required) { + throw new e.ElectroAttributeValidationError( + attribute.path, + `Attribute "${attribute.path}" is Required and cannot be removed`, + ); + } + } + return paths; + } + + checkOperation(attribute, operation, value) { + if (attribute.required && operation === ItemOperations.remove) { + throw new e.ElectroAttributeValidationError( + attribute.path, + `Attribute "${attribute.path}" is Required and cannot be removed`, + ); + } else if (attribute.readOnly) { + throw new e.ElectroAttributeValidationError( + attribute.path, + `Attribute "${attribute.path}" is Read-Only and cannot be updated`, + ); + } + + return value === undefined ? undefined : attribute.getValidate(value); + } + + checkUpdate(payload = {}, { allowReadOnly } = {}) { + let record = {}; + for (let [path, value] of Object.entries(payload)) { + let attribute = this.traverser.paths.get(path); + if (attribute === undefined) { + continue; + } + if (attribute.readOnly && !allowReadOnly) { + throw new e.ElectroAttributeValidationError( + attribute.path, + `Attribute "${attribute.path}" is Read-Only and cannot be updated`, + ); + } else { + record[path] = attribute.getValidate(value); + } + } + return record; + } + + getReadOnly() { + return Array.from(this.readOnlyAttributes); + } + + getRequired() { + return Array.from(this.requiredAttributes); + } + + formatItemForRetrieval(item, config) { + let returnAttributes = new Set(config.attributes || []); + let hasUserSpecifiedReturnAttributes = returnAttributes.size > 0; + let remapped = this.translateFromFields(item, config); + let data = this._fulfillAttributeMutationMethod("get", remapped); + if (this.hiddenAttributes.size > 0 || hasUserSpecifiedReturnAttributes) { + for (let attribute of Object.keys(data)) { + if (this.hiddenAttributes.has(attribute)) { + delete data[attribute]; + } + if ( + hasUserSpecifiedReturnAttributes && + !returnAttributes.has(attribute) + ) { + delete data[attribute]; + } + } + } + return data; + } +} + +function createCustomAttribute(definition = {}) { + return { + ...definition, + type: "custom", + }; +} + +function CustomAttributeType(base) { + const supported = ["string", "number", "boolean", "any"]; + if (!supported.includes(base)) { + throw new Error( + `OpaquePrimitiveType only supports base types: ${u.commaSeparatedString( + supported, + )}`, + ); + } + return base; +} + +function createSchema(schema) { + v.model(schema); + return schema; +} + +module.exports = { + Schema, + Attribute, + CastTypes, + SetAttribute, + createSchema, + CustomAttributeType, + createCustomAttribute, +}; + +},{"./errors":15,"./set":22,"./types":24,"./util":27,"./validations":28}],21:[function(require,module,exports){ +const { + Entity, + getEntityIdentifiers, + matchToEntityAlias, +} = require("./entity"); +const { clauses } = require("./clauses"); +const { + TableIndex, + TransactionMethods, + KeyCasing, + ServiceVersions, + ElectroInstance, + ElectroInstanceTypes, + ModelVersions, + IndexTypes, + DataOptions, IndexProjectionOptions, +} = require("./types"); +const { FilterFactory } = require("./filters"); +const { FilterOperations, ExpressionState } = require("./operations"); +const { WhereFactory } = require("./where"); +const v = require("./validations"); +const c = require("./client"); +const e = require("./errors"); +const u = require("./util"); +const txn = require("./transaction"); +const { + getInstanceType, + getModelVersion, + applyBetaModelOverrides, +} = require("./util"); + +const ConstructorTypes = { + beta: "beta", + v1: "v1", + v1Map: "v1Map", + unknown: "unknown", +}; + +function inferConstructorType(service) { + if (v.isNameEntityRecordType(service) || v.isNameModelRecordType(service)) { + return ConstructorTypes.v1Map; + } else if (v.isBetaServiceConfig(service)) { + return ConstructorTypes.beta; + } else if (v.isStringHasLength(service)) { + return ConstructorTypes.v1; + } else { + return ConstructorTypes.unknown; + } +} + +function inferJoinValues(alias, instance, config) { + let hasAlias = true; + let args = { alias, instance, config, hasAlias }; + if (typeof alias !== "string") { + args.config = instance; + args.instance = alias; + args.hasAlias = false; + } + return args; +} + +class Service { + _betaConstructor(service, config) { + this.service = {}; + this._modelOverrides = {}; + + // Unique to Beta + this._modelVersion = ModelVersions.beta; + this._modelOverrides = { + table: service.table, + service: service.service, + version: service.version, + }; + this.service.name = service.name || service.service; + this.service.table = service.table; + this.service.version = service.version; + // Unique to Beta + + this.config = config; + this.client = config.client; + if (v.isFunction(config.logger)) { + this.logger = config.logger; + } + this.entities = {}; + this.find = {}; + this.collectionSchema = {}; + this.compositeAttributes = {}; + this.collections = {}; + this.identifiers = {}; + this.transaction = { + get: (fn) => { + return txn.createTransaction({ + fn, + getEntities: () => this.entities, + method: TransactionMethods.transactGet, + }); + }, + write: (fn) => { + return txn.createTransaction({ + fn, + getEntities: () => this.entities, + method: TransactionMethods.transactWrite, + }); + }, + }; + this._instance = ElectroInstance.service; + this._instanceType = ElectroInstanceTypes.service; + } + + _v1Constructor(service, config) { + this.service = {}; + this._modelOverrides = {}; + + // Unique to V1 + this._modelVersion = ModelVersions.v1; + this.service.name = service; + this.service.table = config.table; + this._modelOverrides.table = config.table; + // Unique to V1 + + this.config = config; + this.client = config.client; + if (v.isFunction(config.logger)) { + this.logger = config.logger; + } + this.entities = {}; + this.find = {}; + this.collectionSchema = {}; + this.compositeAttributes = {}; + this.collections = {}; + this.identifiers = {}; + this.transaction = { + get: (fn) => { + return txn.createTransaction({ + fn, + getEntities: () => this.entities, + method: TransactionMethods.transactGet, + }); + }, + write: (fn) => { + return txn.createTransaction({ + fn, + getEntities: () => this.entities, + method: TransactionMethods.transactWrite, + }); + }, + }; + this._instance = ElectroInstance.service; + this._instanceType = ElectroInstanceTypes.service; + } + + _v1MapConstructor(service, config) { + let entityNames = Object.keys(service); + let serviceName = this._inferServiceNameFromEntityMap(service); + this._v1Constructor(serviceName, config); + for (let name of entityNames) { + let entity = service[name]; + this.join(name, entity, config); + } + } + + constructor(service = "", config = {}) { + config = c.normalizeConfig(config); + this.version = ServiceVersions.v1; + let type = inferConstructorType(service); + switch (type) { + case ConstructorTypes.v1Map: + this._v1MapConstructor(service, config); + break; + case ConstructorTypes.beta: + this._betaConstructor(service, config); + break; + case ConstructorTypes.v1: + this._v1Constructor(service, config); + break; + default: + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Invalid service name: ${JSON.stringify( + service, + )}. Service name must have length greater than zero`, + ); + } + } + + _inferServiceNameFromEntityMap(service) { + let names = Object.keys(service); + let entity = names + .map((name) => service[name]) + .map((instance) => this._inferJoinEntity(instance)) + .find((entity) => entity && entity.model && entity.model.service); + + if (!entity || !entity.model || !entity.model.service) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Invalid service name: Entities/Models provided do not contain property for Service Name`, + ); + } + + return entity.model.service; + } + + _inferJoinEntity(instance, options) { + let entity = {}; + let type = getInstanceType(instance); + let modelVersion = getModelVersion(instance); + switch (type) { + case ElectroInstanceTypes.model: + entity = new Entity(instance, options); + break; + case ElectroInstanceTypes.entity: + entity = instance; + break; + default: + /** start beta/v1 condition **/ + if (modelVersion !== this._modelVersion) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + "Invalid instance: Valid instances to join include Models and Entity instances.", + ); + } else if (modelVersion === ModelVersions.beta) { + instance = applyBetaModelOverrides(instance, this._modelOverrides); + } else { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Invalid instance: Valid instances to join include Models and Entity instances.`, + ); + } + entity = new Entity(instance, options); + /** end beta/v1 condition **/ + break; + } + return entity; + } + + /** + * Join + * @param {string} alias + * @param instance + * @param config + * @returns {Service} + */ + join(...args) { + let { alias, instance, config, hasAlias } = inferJoinValues(...args); + let options = { ...config, ...this.config }; + + let entity = this._inferJoinEntity(instance, options); + + let name = hasAlias ? alias : entity.getName(); + + if ( + this.service.name.toLowerCase() !== entity.model.service.toLowerCase() + ) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Service name defined on joined instance, ${entity.model.service}, does not match the name of this Service: ${this.service.name}. Verify or update the service name on the Entity/Model to match the name defined on this service.`, + ); + } + + if (this.getTableName()) { + entity.setTableName(this.getTableName()); + } + + if (options.client) { + entity.setClient(options.client); + } + + if (options.logger) { + entity._addLogger(options.logger); + } + + if (options.listeners) { + entity.addListeners(options.listeners); + } + + if (this._modelVersion === ModelVersions.beta && this.service.version) { + entity.model.version = this.service.version; + } + + this.entities[name] = entity; + for (let collection of this.entities[name].model.collections) { + this._addCollectionEntity( + collection, + name, + this.entities[name], + ); + this.collections[collection] = (...facets) => { + return this._makeCollectionChain( + { + name: collection, + initialClauses: clauses, + }, + ...facets, + ); + }; + } + for (const collection in this.collectionSchema) { + const collectionSchema = this.collectionSchema[collection]; + this.compositeAttributes[collection] = + this._collectionSchemaToCompositeAttributes(collectionSchema); + } + this.find = { ...this.entities, ...this.collections }; + return this; + } + + _collectionSchemaToCompositeAttributes(schema) { + const keys = schema.keys; + return { + hasSortKeys: keys.hasSk, + customFacets: { + pk: keys.pk.isCustom, + sk: keys.sk.isCustom, + }, + pk: keys.pk.facets, + sk: keys.sk.facets, + all: [ + ...keys.pk.facets.map((name) => { + return { + name, + index: keys.index, + type: "pk", + }; + }), + ...keys.sk.facets.map((name) => { + return { + name, + index: keys.index, + type: "sk", + }; + }), + ], + collection: keys.collection, + hasSubCollections: schema.hasSubCollections, + casing: { + pk: keys.pk.casing, + sk: keys.sk.casing, + }, + }; + } + + setClient(client) { + if (client !== undefined) { + for (let entity of Object.values(this.entities)) { + entity.setClient(client); + } + } + } + + cleanseRetrievedData(index = TableIndex, entities, data = {}, config = {}) { + if (config.data === DataOptions.raw) { + return data; + } + const identifiers = getEntityIdentifiers(entities); + + data.Items = data.Items || []; + + const results = {}; + for (let { alias } of identifiers) { + results[alias] = []; + } + + for (let i = 0; i < data.Items.length; i++) { + const record = data.Items[i]; + + if (!record) { + continue; + } + + const entityAlias = matchToEntityAlias({ + identifiers, + record, + entities: this.entities, + allowMatchOnKeys: config.ignoreOwnership, + config, + }); + + if (!entityAlias) { + continue; + } + + // pager=false because we don't want the entity trying to parse the lastEvaluatedKey + let formatted; + if (config.hydrate) { + formatted = { + data: record, // entities[entityAlias]._formatKeysToItem(index, record), + }; + } else { + formatted = entities[entityAlias].formatResponse( + { Item: record }, + index, + { + ...config, + pager: false, + parse: undefined, + }, + ); + } + + results[entityAlias].push(formatted.data); + } + return results; + } + + findKeyOwner(lastEvaluatedKey) { + return Object.values(this.entities)[0]; + // return Object.values(this.entities) + // .find((entity) => entity.ownsLastEvaluatedKey(lastEvaluatedKey)); + } + + expectKeyOwner(lastEvaluatedKey) { + const owner = this.findKeyOwner(lastEvaluatedKey); + if (owner === undefined) { + throw new e.ElectroError( + e.ErrorCodes.NoOwnerForCursor, + `Supplied cursor does not resolve to Entity within the Service ${this.service.name}`, + ); + } + return owner; + } + + findCursorOwner(cursor) { + return Object.values(this.entities)[0]; + // return Object.values(this.entities) + // .find(entity => entity.ownsCursor(cursor)); + } + + expectCursorOwner(cursor) { + const owner = this.findCursorOwner(cursor); + if (owner === undefined) { + throw new e.ElectroError( + e.ErrorCodes.NoOwnerForCursor, + `Supplied cursor does not resolve to Entity within the Service ${this.service.name}`, + ); + } + return owner; + } + + getTableName() { + return this.service.table; + } + + setTableName(table) { + this.service.table = table; + for (let entity of Object.values(this.entities)) { + entity.setTableName(table); + } + } + + _makeCollectionChain({ name = "", initialClauses = {} }, facets = {}) { + const { entities, attributes, identifiers, indexType, index } = + this.collectionSchema[name]; + const compositeAttributes = this.compositeAttributes[name]; + const allEntities = Object.values(entities); + const entity = allEntities[0]; + + let filterBuilder = new FilterFactory(attributes, FilterOperations); + let whereBuilder = new WhereFactory(attributes, FilterOperations); + let clauses = { ...initialClauses }; + + clauses = filterBuilder.injectFilterClauses(clauses); + clauses = whereBuilder.injectWhereClauses(clauses); + + const expression = identifiers.expression || ""; + + let options = { + // expressions, // DynamoDB doesn't return what I expect it would when provided with these entity filters + parse: (options, data) => { + if (options.data === DataOptions.raw) { + return data; + } + return this.cleanseRetrievedData(index, entities, data, options); + }, + formatCursor: { + serialize: (key) => { + return this.expectKeyOwner(key).serializeCursor(key); + }, + deserialize: (cursor) => { + return this.expectCursorOwner(cursor).deserializeCursor(cursor); + }, + }, + identifiers: { + names: identifiers.names || {}, + values: identifiers.values || {}, + expression: allEntities.length > 1 ? `(${expression})` : expression, + }, + expressions: { + names: {}, + values: {}, + expression: "", + }, + attributes, + entities, + indexType, + compositeAttributes, + hydrator: async (entity, index, items, config) => { + if (entity && entities[entity]) { + return entities[entity].hydrate(index, items, { + ...config, + parse: undefined, + hydrator: undefined, + _isCollectionQuery: false, + ignoreOwnership: config._providedIgnoreOwnership, + attributes: config._providedAttributes, + }); + } + + let entityItemRefs = {}; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + for (let entityName in entities) { + entityItemRefs[entityName] = entityItemRefs[entityName] || []; + const entity = entities[entityName]; + if (entity.is(item, config)) { + entityItemRefs[entityName].push({ + item, + itemSlot: i, + }); + } + } + } + + let unprocessed = []; + let data = new Array(items.length).fill(null); + for (const entityName in entityItemRefs) { + const itemRefs = entityItemRefs[entityName]; + const items = itemRefs.map((ref) => ref.item); + const results = await entities[entity].hydrate(index, items, { + ...config, + parse: undefined, + hydrate: false, + hydrator: undefined, + _isCollectionQuery: false, + ignoreOwnership: config._providedIgnoreOwnership, + attributes: config._providedAttributes, + }); + unprocessed = unprocessed.concat(results.unprocessed); + if (results.data.length !== itemRefs.length) { + throw new Error("Temporary: something wrong"); + } + for (let r = 0; r < itemRefs.length; r++) { + const itemRef = itemRefs[r]; + const hydrated = results.data[r]; + data[itemRef.itemSlot] = hydrated; + } + } + + return { + data, + unprocessed, + }; + }, + }; + + return entity.collection(name, clauses, facets, options); + } + + _validateIndexCasingMatch(definition = {}, providedIndex = {}) { + const definitionSk = definition.sk || {}; + const providedSk = providedIndex.sk || {}; + const pkCasingMatch = v.isMatchingCasing( + definition.pk.casing, + providedIndex.pk.casing, + ); + const skCasingMatch = v.isMatchingCasing( + definitionSk.casing, + providedSk.casing, + ); + return { + pk: pkCasingMatch, + sk: skCasingMatch, + }; + } + + _validateIndexProjectionsMatch(definition = {}, providedIndex = {}) { + const definitionProjection = definition.projection; + const providedProjection = providedIndex.projection; + return v.isMatchingProjection(providedIndex.projection, definition.projection) + } + + _validateCollectionDefinition(definition = {}, providedIndex = {}) { + let isCustomMatchPK = definition.pk.isCustom === providedIndex.pk.isCustom; + let isCustomMatchSK = + !!(definition.sk && definition.sk.isCustom) === + !!(providedIndex.sk && providedIndex.sk.isCustom); + let indexMatch = definition.index === providedIndex.index; + let pkFieldMatch = definition.pk.field === providedIndex.pk.field; + let pkFacetLengthMatch = + definition.pk.facets.length === providedIndex.pk.facets.length; + let scopeMatch = definition.scope === providedIndex.scope; + let mismatchedFacetLabels = []; + let collectionDifferences = []; + let definitionIndexName = u.formatIndexNameForDisplay(definition.index); + let providedIndexName = u.formatIndexNameForDisplay(providedIndex.index); + let matchingKeyCasing = this._validateIndexCasingMatch( + definition, + providedIndex, + ); + + const matchingProjection = v.isMatchingProjection( + providedIndex.projection, + definition.projection + ) + + for ( + let i = 0; + i < Math.max(definition.pk.labels.length, providedIndex.pk.labels.length); + i++ + ) { + let definitionFacet = + definition.pk.labels[i] && definition.pk.labels[i].name; + let definitionLabel = + definition.pk.labels[i] && definition.pk.labels[i].label; + let providedFacet = + providedIndex.pk.labels[i] && providedIndex.pk.labels[i].name; + let providedLabel = + providedIndex.pk.labels[i] && providedIndex.pk.labels[i].label; + let noLabels = + definitionLabel === definitionFacet && providedLabel === providedFacet; + if (definitionLabel !== providedLabel) { + mismatchedFacetLabels.push({ + definitionFacet, + definitionLabel, + providedFacet, + providedLabel, + kind: "Partition", + type: noLabels ? "facet" : "label", + }); + break; + } else if (definitionFacet !== providedFacet) { + mismatchedFacetLabels.push({ + definitionFacet, + definitionLabel, + providedFacet, + providedLabel, + kind: "Partition", + type: "facet", + }); + break; + } + } + + if (!scopeMatch) { + collectionDifferences.push( + `The index scope value provided "${ + providedIndex.scope || "undefined" + }" does not match established index scope value "${ + definition.scope || "undefined" + }" on index "${providedIndexName}". Index scope options must match across all entities participating in a collection`, + ); + } + + if (!isCustomMatchPK) { + collectionDifferences.push( + `The usage of key templates the partition key on index ${definitionIndexName} must be consistent across all Entities, some entities provided use template while others do not`, + ); + } + + if (!isCustomMatchSK) { + collectionDifferences.push( + `The usage of key templates the sort key on index ${definitionIndexName} must be consistent across all Entities, some entities provided use template while others do not`, + ); + } + + if ( + definition.type === IndexTypes.clustered || + definition.type === IndexTypes.composite + ) { + for ( + let i = 0; + i < + Math.min(definition.sk.labels.length, providedIndex.sk.labels.length); + i++ + ) { + let definitionFacet = + definition.sk.labels[i] && definition.sk.labels[i].name; + let definitionLabel = + definition.sk.labels[i] && definition.sk.labels[i].label; + let providedFacet = + providedIndex.sk.labels[i] && providedIndex.sk.labels[i].name; + let providedLabel = + providedIndex.sk.labels[i] && providedIndex.sk.labels[i].label; + let noLabels = + definitionLabel === definitionFacet && + providedLabel === providedFacet; + if (definitionFacet === providedFacet) { + if (definitionLabel !== providedLabel) { + mismatchedFacetLabels.push({ + definitionFacet, + definitionLabel, + providedFacet, + providedLabel, + kind: "Sort", + type: noLabels ? "facet" : "label", + }); + } + } else { + break; + } + } + } + + if (!matchingKeyCasing.pk) { + collectionDifferences.push( + `The pk property "casing" provided "${ + providedIndex.pk.casing || KeyCasing.default + }" does not match established casing "${ + definition.pk.casing || KeyCasing.default + }" on index "${providedIndexName}". Index casing options must match across all entities participating in a collection`, + ); + } + + if (!matchingProjection) { + collectionDifferences.push( + `The provided projection definition ${u.commaSeparatedString(providedIndex.projection !== undefined && providedIndex.projection !== null ? providedIndex.projection : '')} does not match the established projection definition ${u.commaSeparatedString(definition.projection)} on index ${providedIndexName}. Index projection definitions must match across all entities participating in a collection` + ); + } + + if (!matchingKeyCasing.sk) { + const definedSk = definition.sk || {}; + const providedSk = providedIndex.sk || {}; + collectionDifferences.push( + `The sk property "casing" provided "${ + definedSk.casing || KeyCasing.default + }" does not match established casing "${ + providedSk.casing || KeyCasing.default + }" on index "${providedIndexName}". Index casing options must match across all entities participating in a collection`, + ); + } + + if (!indexMatch) { + collectionDifferences.push( + `Collection defined on provided index "${providedIndexName}" does not match collection established index "${definitionIndexName}". Collections must be defined on the same index across all entities within a service.`, + ); + } else if (!pkFieldMatch) { + collectionDifferences.push( + `Partition Key composite attributes provided "${providedIndex.pk.field}" for index "${providedIndexName}" do not match established field "${definition.pk.field}" on established index "${definitionIndexName}"`, + ); + } + + if (!pkFacetLengthMatch) { + collectionDifferences.push( + `Partition Key composite attributes provided [${providedIndex.pk.facets + .map((val) => `"${val}"`) + .join( + ", ", + )}] for index "${providedIndexName}" do not match established composite attributes [${definition.pk.facets + .map((val) => `"${val}"`) + .join(", ")}] on established index "${definitionIndexName}"`, + ); + // Else if used here because if they don't even have the same facet length then the data collected for the mismatched facets would include undefined values + // which would make the error messages even more confusing. + } else if (mismatchedFacetLabels.length > 0) { + for (let mismatch of mismatchedFacetLabels) { + if (mismatch.type === "facet") { + collectionDifferences.push( + `${mismatch.kind} Key composite attributes provided for index "${providedIndexName}" do not match established composite attribute "${mismatch.definitionFacet}" on established index "${definitionIndexName}": "${mismatch.definitionLabel}" != "${mismatch.providedLabel}"; Composite attribute definitions must match between all members of a collection to ensure key structures will resolve to identical Partition Keys. Please ensure these composite attribute definitions are identical for all entities associated with this service.`, + ); + } else { + collectionDifferences.push( + `${ + mismatch.kind + } Key composite attributes provided for index "${providedIndexName}" contain conflicting composite attribute labels for established composite attribute "${ + mismatch.definitionFacet || "" + }" on established index "${definitionIndexName}". Established composite attribute "${ + mismatch.definitionFacet || "" + }" on established index "${definitionIndexName}" was defined with label "${ + mismatch.definitionLabel + }" while provided composite attribute "${ + mismatch.providedFacet || "" + }" on provided index "${providedIndexName}" is defined with label "${ + mismatch.providedLabel + }". Composite attribute labels definitions must match between all members of a collection to ensure key structures will resolve to identical Partition Keys. Please ensure these labels definitions are identical for all entities associated with this service.`, + ); + } + } + } + return [!!collectionDifferences.length, collectionDifferences]; + } + + _compareEntityAttributes( + entityName, + definition = {}, + providedAttributes = {}, + keys, + ) { + let results = { + additions: {}, + invalid: [], + }; + for (let [name, detail] of Object.entries(providedAttributes)) { + let defined = definition[name]; + if (defined === undefined) { + results.additions[name] = detail; + } else if (defined.field !== detail.field) { + results.invalid.push( + `The attribute "${name}" with Table Field "${detail.field}" does not match established Table Field "${defined.field}"`, + ); + } + if (defined && detail && (defined.padding || detail.padding)) { + const definedPadding = defined.padding || {}; + const detailPadding = detail.padding || {}; + if ( + keys.pk.facets.includes(name) && + (definedPadding.length !== detailPadding.length || + definedPadding.char !== detailPadding.char) + ) { + results.invalid.push( + `The attribute "${name}" contains inconsistent padding definitions that impact how keys are formed`, + ); + } + } + } + return [!!results.invalid.length, results]; + } + + _processEntityAttributes( + entityName, + definition = {}, + providedAttributes = {}, + keys, + ) { + let [attributesAreIncompatible, attributeResults] = + this._compareEntityAttributes( + entityName, + definition, + providedAttributes, + keys, + ); + if (attributesAreIncompatible) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Inconsistent attribute(s) on the entity "${entityName}". The following attribute(s) are defined with incompatible or conflicting definitions across participating entities: ${attributeResults.invalid.join( + ", ", + )}. These attribute definitions must match among all members of the collection.`, + ); + } else { + return { + ...definition, + ...attributeResults.additions, + }; + } + } + + _processEntityKeys(name, definition = {}, providedIndex = {}) { + if (!Object.keys(definition).length) { + definition = providedIndex; + } + const [invalidDefinition, invalidIndexMessages] = + this._validateCollectionDefinition(definition, providedIndex); + if (invalidDefinition) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Validation Error while joining entity, "${name}". ${invalidIndexMessages.join( + "; ", + )}`, + ); + } + const sharedSortKeyAttributes = []; + const sharedSortKeyCompositeAttributeLabels = []; + const sharedSortKeyLabels = []; + if ( + providedIndex.hasSk && + definition.hasSk && + Array.isArray(definition.sk.labels) + ) { + for (let i = 0; i < definition.sk.labels.length; i++) { + const providedLabels = providedIndex.sk.labels[i]; + const definedLabels = definition.sk.labels[i]; + + const namesMatch = + providedLabels && providedLabels.name === definedLabels.name; + const labelsMatch = + providedLabels && providedLabels.label === definedLabels.label; + if (!namesMatch || !labelsMatch) { + break; + } + sharedSortKeyLabels.push({ ...definedLabels }); + sharedSortKeyCompositeAttributeLabels.push({ + ...definition.sk.facetLabels[i], + }); + sharedSortKeyAttributes.push(definition.sk.facets[i]); + } + } + return { + ...definition, + sk: { + ...definition.sk, + facets: sharedSortKeyAttributes, + facetLabels: sharedSortKeyCompositeAttributeLabels, + labels: sharedSortKeyLabels, + }, + }; + } + + _getEntityIndexFromCollectionName(collection, entity) { + for (let index of Object.values(entity.model.indexes)) { + let names = []; + if (v.isArrayHasLength(index.collection)) { + names = index.collection; + } else { + names.push(index.collection); + } + + for (let name of names) { + if (v.isStringHasLength(name) && name === collection) { + return index; + } + } + } + return Object.values(entity.model.indexes).find((index) => { + if (v.isStringHasLength(index.collection)) { + return index.collection === collection; + } else if (v.isArrayHasLength(index.collection)) { + return index.collection.indexOf(collection) > 0; + } + }); + } + + _processSubCollections( + providedType, + existing, + provided, + entityName, + collectionName, + ) { + let existingSubCollections; + let providedSubCollections; + if (v.isArrayHasLength(existing)) { + existingSubCollections = existing; + } else { + existingSubCollections = [existing]; + } + if (v.isArrayHasLength(provided)) { + providedSubCollections = provided; + } else { + providedSubCollections = [provided]; + } + + if ( + providedSubCollections.length > 1 && + (providedType === IndexTypes.clustered || + providedType === IndexTypes.composite) + ) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `"${providedType}" indexes do not support sub-collections. The sub-collection "${collectionName}", on Entity "${entityName}" must be defined as either an individual collection name or the index must be redefined as an "${IndexTypes.isolated}" index`, + ); + } + const existingRequiredIndex = + existingSubCollections.indexOf(collectionName); + const providedRequiredIndex = + providedSubCollections.indexOf(collectionName); + if (providedRequiredIndex < 0) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `The collection definition for Collection "${collectionName}" does not exist on Entity "${entityName}".`, + ); + } + if ( + existingRequiredIndex >= 0 && + existingRequiredIndex !== providedRequiredIndex + ) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `The collection definition for Collection "${collectionName}", on Entity "${entityName}", does not match the established sub-collection order for this service. The collection name provided in slot ${ + providedRequiredIndex + 1 + }, ${ + providedSubCollections[existingRequiredIndex] === undefined + ? "(not found)" + : `"${providedSubCollections[existingRequiredIndex]}"` + }, on Entity "${entityName}", does not match the established collection name in slot ${ + existingRequiredIndex + 1 + }, "${collectionName}". When using sub-collections, all Entities within a Service must must implement the same order for all preceding sub-collections.`, + ); + } + let length = Math.max(existingRequiredIndex, providedRequiredIndex); + + for (let i = 0; i <= length; i++) { + let existingCollection = existingSubCollections[i]; + let providedCollection = providedSubCollections[i]; + if (v.isStringHasLength(existingCollection)) { + if ( + existingCollection === providedCollection && + providedCollection === collectionName + ) { + return i; + } + if (existingCollection !== providedCollection) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `The collection definition for Collection "${collectionName}", on Entity "${entityName}", does not match the established sub-collection order for this service. The collection name provided in slot ${ + i + 1 + }, "${providedCollection}", on Entity "${entityName}", does not match the established collection name in slot ${ + i + 1 + }, "${existingCollection}". When using sub-collections, all Entities within a Service must must implement the same order for all preceding sub-collections.`, + ); + } + } else if (v.isStringHasLength(providedCollection)) { + if (providedCollection === collectionName) { + return i; + } + } + } + } + + _addCollectionEntity( + collection = "", + name = "", + entity = {}, + ) { + let providedIndex = this._getEntityIndexFromCollectionName( + collection, + entity, + ); + + this.collectionSchema[collection] = this.collectionSchema[collection] || { + entities: {}, + keys: {}, + attributes: {}, + identifiers: new ExpressionState({ prefix: "_c" }), + index: undefined, + table: "", + collection: [], + indexType: undefined, + hasSubCollections: undefined, + }; + const providedType = providedIndex.type || IndexTypes.isolated; + if (this.collectionSchema[collection].indexType === undefined) { + this.collectionSchema[collection].indexType = providedType; + } else if (this.collectionSchema[collection].indexType !== providedType) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Index type mismatch on collection ${collection}. The entity ${name} defines the index as type ${providedType} while the established type for that index is ${this.collectionSchema[collection].indexType}. Note that when omitted, indexes default to the type "${IndexTypes.isolated}"`, + ); + } + if (this.collectionSchema[collection].entities[name] !== undefined) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Entity with name '${name}' has already been joined to this service.`, + ); + } + + if (this.collectionSchema[collection].table !== "") { + if (this.collectionSchema[collection].table !== entity.getTableName()) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Entity with name '${name}' is defined to use a different Table than what is defined on other Service Entities and/or the Service itself. Entity '${name}' is defined with table name '${entity.getTableName()}' but the Service has been defined to use table name '${ + this.collectionSchema[collection].table + }'. All Entities in a Service must reference the same DynamoDB table. To ensure all Entities will use the same DynamoDB table, it is possible to apply the property 'table' to the Service constructor's configuration parameter.`, + ); + } + } else { + this.collectionSchema[collection].table = entity.getTableName(); + } + + this.collectionSchema[collection].keys = this._processEntityKeys( + name, + this.collectionSchema[collection].keys, + providedIndex, + ); + this.collectionSchema[collection].attributes = + this._processEntityAttributes( + name, + this.collectionSchema[collection].attributes, + entity.model.schema.attributes, + this.collectionSchema[collection].keys, + ); + this.collectionSchema[collection].entities[name] = entity; + + this.collectionSchema[collection].identifiers = + this._processEntityIdentifiers( + this.collectionSchema[collection].identifiers, + name, + entity, + ); + this.collectionSchema[collection].index = + this._processEntityCollectionIndex( + this.collectionSchema[collection].index, + providedIndex.index, + name, + collection, + ); + let collectionIndex = this._processSubCollections( + providedType, + this.collectionSchema[collection].collection, + providedIndex.collection, + name, + collection, + ); + this.collectionSchema[collection].collection[collectionIndex] = collection; + this.collectionSchema[collection].hasSubCollections = + this.collectionSchema[collection].hasSubCollections || + Array.isArray(providedIndex.collection); + return this.collectionSchema[collection]; + } + + _processEntityCollectionIndex(existing, provided, name, collection) { + if (typeof provided !== "string") { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Entity with name '${name}' does not have collection ${collection} defined on it's model`, + ); + } else if (existing === undefined) { + return provided; + } else if (provided !== existing) { + throw new e.ElectroError( + e.ErrorCodes.InvalidJoin, + `Entity with name '${name}' defines collection ${collection} on index `, + ); + } else { + return existing; + } + } + + _processEntityIdentifiers(state, alias, entity) { + const expression = entity.applyIdentifierExpressionState(state, alias); + if (expression) { + const combined = [state.getExpression().trim(), expression.trim()] + .filter(Boolean) + .join(" OR "); + state.setExpression(combined); + } + + return state; + } +} + +module.exports = { + Service, +}; + +},{"./clauses":11,"./client":12,"./entity":14,"./errors":15,"./filters":18,"./operations":19,"./transaction":23,"./types":24,"./util":27,"./validations":28,"./where":29}],22:[function(require,module,exports){ +const memberTypeToSetType = { + String: "String", + Number: "Number", + NumberValue: "Number", + Binary: "Binary", + string: "String", + number: "Number", + enum: "String", +}; + +class DynamoDBSet { + constructor(list, type) { + this.wrapperName = "Set"; + this.type = memberTypeToSetType[type]; + if (this.type === undefined) { + throw new Error(`Invalid Set type: ${type}`); + } + this.values = Array.from(new Set([].concat(list))); + } + + initialize(list, validate) {} + + detectType() { + return memberTypeToSetType[typeof this.values[0]]; + } + + validate() {} + + toJSON() { + return this.values; + } +} + +module.exports = { DynamoDBSet }; + +},{}],23:[function(require,module,exports){ +const { TableIndex, TransactionMethods, DataOptions } = require("./types"); +const { getEntityIdentifiers, matchToEntityAlias } = require("./entity"); + +function cleanseCanceledData( + index = TableIndex, + entities, + data = {}, + config = {}, +) { + if (config.data === DataOptions.raw) { + return data; + } + const identifiers = getEntityIdentifiers(entities); + const canceled = data.canceled || []; + const paramItems = config._paramItems || []; + const results = []; + for (let i = 0; i < canceled.length; i++) { + const { Item, Code, Message } = canceled[i] || {}; + const paramItem = paramItems[i]; + const code = Code || "None"; + const rejected = code !== "None"; + const result = { + rejected, + code, + message: Message, + }; + + if (Item) { + const entityAlias = matchToEntityAlias({ + record: Item, + paramItem, + identifiers, + }); + if (entityAlias) { + result.item = entities[entityAlias].formatResponse({ Item }, index, { + ...config, + pager: false, + parse: undefined, + }).data; + } else { + result.item = null; + } + } else { + result.item = null; + } + + results.push(result); + } + + return results; +} + +function cleanseTransactionData( + index = TableIndex, + entities, + data = {}, + config = {}, +) { + if (config.data === DataOptions.raw) { + return data; + } + const identifiers = getEntityIdentifiers(entities); + data.Items = data.Items || []; + const paramItems = config._paramItems || []; + const results = []; + for (let i = 0; i < data.Items.length; i++) { + const record = data.Items[i]; + if (!record) { + results.push(null); + continue; + } + + const paramItem = paramItems[i]; + const entityAlias = matchToEntityAlias({ paramItem, identifiers, record }); + if (!entityAlias) { + results.push(null); + continue; + } + + // pager=false because we don't want the entity trying to parse the lastEvaluatedKey + let formatted = entities[entityAlias].formatResponse( + { Item: record }, + index, + { + ...config, + pager: false, + parse: undefined, + }, + ); + + results.push(formatted.data); + } + + return results.map((item) => ({ + rejected: false, + item, + })); +} + +function createTransaction(options) { + const { fn, method, getEntities } = options; + const operations = { + params: (options = {}) => { + const paramItems = fn(getEntities()); + const params = { + TransactItems: paramItems, + }; + + if (typeof options.token === "string" && options.token.length) { + params["ClientRequestToken"] = options.token; + } + if (options._returnParamItems) { + return { params, paramItems }; + } + return params; + }, + go: async (options) => { + const driver = Object.values(getEntities())[0]; + + if (!driver) { + throw new Error( + "At least one entity must exist to perform a transaction", + ); + } + + const { params, paramItems } = operations.params({ + ...options, + _returnParamItems: true, + }); + + let canceled = false; + if (paramItems.length === 0) { + return { + canceled, + data: [], + }; + } + let listeners = + options && options.listeners ? [...options.listeners] : []; + if (options && options.logger) { + listeners = [...listeners, options.logger]; + } + const response = await driver.go(method, params, { + ...options, + listeners, + parse: (options, data) => { + if (options.data === DataOptions.raw) { + return data; + } else if (data.canceled) { + canceled = true; + return cleanseCanceledData(TableIndex, getEntities(), data, { + ...options, + _isTransaction: true, + _paramItems: paramItems, + }); + } else if (data.Responses) { + return cleanseTransactionData( + TableIndex, + getEntities(), + { + Items: data.Responses.map((response) => response.Item), + }, + { + ...options, + _isTransaction: true, + _paramItems: paramItems, + }, + ); + } else { + return Array.from( + { length: paramItems ? paramItems.length : 0 }, + () => ({ + item: null, + code: "None", + rejected: false, + message: undefined, + }), + ); + } + }, + }); + + return { + ...response, + canceled, + }; + }, + }; + + return operations; +} + +function createWriteTransaction(entities, fn) { + return createTransaction({ + fn, + method: TransactionMethods.transactWrite, + getEntities: () => entities, + }); +} + +function createGetTransaction(entities, fn) { + return createTransaction({ + fn, + method: TransactionMethods.transactGet, + getEntities: () => entities, + }); +} + +module.exports = { + createTransaction, + createWriteTransaction, + createGetTransaction, + cleanseTransactionData, + cleanseCanceledData, +}; + +},{"./entity":14,"./types":24}],24:[function(require,module,exports){ +const KeyTypes = { + pk: "pk", + sk: "sk", +}; + +const DataOptions = { + raw: "raw", + includeKeys: "includeKeys", + attributes: "attributes", +}; + +const BatchWriteTypes = { + batch: "batch", + concurrent: "concurrent", +}; + +const ComparisonTypes = { + keys: "keys", + attributes: "attributes", + v2: "v2", +}; + +const QueryTypes = { + and: "and", + gte: "gte", + gt: "gt", + lte: "lte", + lt: "lt", + eq: "eq", + begins: "begins", + between: "between", + collection: "collection", + clustered_collection: "clustered_collection", + composite_collection: "composite_collection", + is: "is", +}; + +const MethodTypes = { + check: "check", + put: "put", + get: "get", + query: "query", + scan: "scan", + update: "update", + delete: "delete", + remove: "remove", + patch: "patch", + create: "create", + batchGet: "batchGet", + batchWrite: "batchWrite", + upsert: "upsert", + transactWrite: "transactWrite", + transactGet: "transactGet", +}; + +const TransactionMethods = { + transactWrite: MethodTypes.transactWrite, + transactGet: MethodTypes.transactGet, +}; + +const TransactionOperations = { + [MethodTypes.get]: "Get", + [MethodTypes.check]: "ConditionCheck", + [MethodTypes.put]: "Put", + [MethodTypes.create]: "Put", + [MethodTypes.upsert]: "Update", + [MethodTypes.update]: "Update", + [MethodTypes.patch]: "Update", + [MethodTypes.remove]: "Delete", + [MethodTypes.delete]: "Delete", +}; + +const MethodTypeTranslation = { + put: "put", + get: "get", + query: "query", + scan: "scan", + update: "update", + delete: "delete", + remove: "delete", + patch: "update", + create: "put", + batchGet: "batchGet", + batchWrite: "batchWrite", + upsert: "update", + transactWrite: "transactWrite", + transactGet: "transactGet", +}; + +const IndexTypes = { + isolated: "isolated", + clustered: "clustered", + composite: "composite", +}; + +const Comparisons = { + lte: "<=", + lt: "<", + gte: ">=", + gt: ">", +}; + +const KeyAttributesComparisons = { + lt: "<", + gte: ">=", + + /** + * gt becomes gte and last character of incoming value is shifted up one character code + * example: + * sk > '2020-09-05' + * expected + * - 2020-09-06@05:05_hero + * - 2020-10-05@05:05_hero + * - 2022-02-05@05:05_villian + * - 2022-06-05@05:05_clown + * - 2022-09-06@05:05_clown + * actual (bad - includes all 2020-09-05 records) + * - 2020-09-05@05:05_hero + * - 2020-09-06@05:05_hero + * - 2020-10-05@05:05_hero + * - 2022-02-05@05:05_villian + * - 2022-06-05@05:05_clown + */ + gt: ">=", + + /** + * lte becomes lt and last character of incoming value is shifted up one character code + * example: + * sk >= '2020-09-05' + * expected + * - 2012-02-05@05:05_clown + * - 2015-10-05@05:05_hero + * - 2017-02-05@05:05_clown + * - 2017-02-05@05:05_villian + * - 2020-02-05@05:05_clown + * - 2020-02-25@05:05_clown + * - 2020-09-05@05:05_hero + * actual (bad - missing all 2020-09-05 records) + * - 2012-02-05@05:05_clown + * - 2015-10-05@05:05_hero + * - 2017-02-05@05:05_clown + * - 2017-02-05@05:05_villian + * - 2020-02-05@05:05_clown + * - 2020-02-25@05:05_clown + */ + lte: "<", +}; + +const CastTypes = ["string", "number"]; + +const AttributeTypes = { + string: "string", + number: "number", + boolean: "boolean", + enum: "enum", + map: "map", + set: "set", + // enumSet: "enumSet", + list: "list", + any: "any", + custom: "custom", + static: "static", +}; + +const PathTypes = { + ...AttributeTypes, + item: "item", +}; + +const ExpressionTypes = { + ConditionExpression: "ConditionExpression", + FilterExpression: "FilterExpression", +}; + +const ElectroInstance = { + entity: Symbol("entity"), + service: Symbol("service"), + electro: Symbol("electro"), +}; + +const ElectroInstanceTypes = { + electro: "electro", + service: "service", + entity: "entity", + model: "model", +}; + +const ModelVersions = { + beta: "beta", + v1: "v1", + v2: "v2", +}; + +const EntityVersions = { + v1: "v1", +}; + +const ServiceVersions = { + v1: "v1", +}; + +const MaxBatchItems = { + [MethodTypes.batchGet]: 100, + [MethodTypes.batchWrite]: 25, +}; + +const AttributeMutationMethods = { + get: "get", + set: "set", +}; + +const Pager = { + raw: "raw", + named: "named", + item: "item", + cursor: "cursor", +}; + +const UnprocessedTypes = { + raw: "raw", + item: "item", +}; + +const AttributeWildCard = "*"; + +const ItemOperations = { + set: "set", + delete: "delete", + remove: "remove", + add: "add", + subtract: "subtract", + append: "append", + ifNotExists: "ifNotExists", + none: "", +}; + +const UpsertOperations = { + set: "set", + add: "add", + subtract: "subtract", + append: "append", + ifNotExists: "ifNotExists", +}; + +const AttributeProxySymbol = Symbol("attribute_proxy"); +const TransactionCommitSymbol = Symbol("transaction_commit"); + +const BuilderTypes = { + update: "update", + filter: "filter", +}; + +const ValueTypes = { + string: "string", + boolean: "boolean", + number: "number", + array: "array", + set: "set", + aws_set: "aws_set", + object: "object", + map: "map", + null: "null", + undefined: "undefined", + unknown: "unknown", +}; + +const TraverserIndexes = { + readonly: "readonly", + required: "required", + getters: "getters", + setters: "setters", +}; + +const ReturnValues = { + default: "default", + none: "none", + all_old: "all_old", + updated_old: "updated_old", + all_new: "all_new", + updated_new: "updated_new", +}; + +const FormatToReturnValues = { + none: "NONE", + default: "NONE", + all_old: "ALL_OLD", + updated_old: "UPDATED_OLD", + all_new: "ALL_NEW", + updated_new: "UPDATED_NEW", +}; + +const TableIndex = ""; + +const KeyCasing = { + none: "none", + upper: "upper", + lower: "lower", + default: "default", +}; + +const DefaultKeyCasing = KeyCasing.lower; + +const EventSubscriptionTypes = ["query", "results"]; + +const TerminalOperation = { + go: "go", + page: "page", +}; + +const AllPages = "all"; + +const ResultOrderOption = { + asc: true, + desc: false, +}; + +const ResultOrderParam = "ScanIndexForward"; + +const DynamoDBAttributeTypes = Object.entries({ + string: "S", + stringSet: "SS", + number: "N", + numberSet: "NS", + binary: "B", + binarySet: "BS", + boolean: "BOOL", + null: "NULL", + list: "L", + map: "M", +}).reduce((obj, [name, type]) => { + obj[name] = type; + obj[type] = type; + return obj; +}, {}); + +const CastKeyOptions = { + string: "string", + number: "number", +}; + +const IndexProjectionOptions = { + all: 'all', + keys_only: 'keys_only', +}; + +const EntityIdentifiers = { + entity: "__edb_e__", + version: "__edb_v__", +} + +const EntityIdentifierFields = ["__edb_e__", "__edb_v__"]; + +module.exports = { + Pager, + KeyTypes, + CastTypes, + KeyCasing, + PathTypes, + IndexTypes, + QueryTypes, + ValueTypes, + TableIndex, + MethodTypes, + DataOptions, + Comparisons, + BuilderTypes, + ReturnValues, + MaxBatchItems, + ModelVersions, + ItemOperations, + AttributeTypes, + EntityVersions, + CastKeyOptions, + ComparisonTypes, + ServiceVersions, + ExpressionTypes, + ElectroInstance, + TraverserIndexes, + UnprocessedTypes, + AttributeWildCard, + TerminalOperation, + FormatToReturnValues, + AttributeProxySymbol, + ElectroInstanceTypes, + MethodTypeTranslation, + EventSubscriptionTypes, + DynamoDBAttributeTypes, + KeyAttributesComparisons, + AttributeMutationMethods, + AllPages, + ResultOrderOption, + ResultOrderParam, + TransactionCommitSymbol, + TransactionOperations, + TransactionMethods, + UpsertOperations, + BatchWriteTypes, + DefaultKeyCasing, + IndexProjectionOptions, + EntityIdentifiers, + EntityIdentifierFields, +}; + +},{}],25:[function(require,module,exports){ +const { UpdateOperations } = require("./updateOperations"); +const { AttributeOperationProxy, ExpressionState } = require("./operations"); +const { ItemOperations, BuilderTypes } = require("./types"); + +class UpdateExpression extends ExpressionState { + constructor(props = {}) { + super({ ...props }); + this.operations = { + set: new Set(), + remove: new Set(), + add: new Set(), + subtract: new Set(), + delete: new Set(), + }; + this.composites = {}; + this.seen = new Map(); + this.type = BuilderTypes.update; + } + addComposite(attrName, value) { + if (value !== undefined) { + if ( + this.composites[attrName] === undefined || + this.composites[attrName] === value + ) { + this.composites[attrName] = value; + return true; + } + } + return false; + } + + add(type, expression) { + this.operations[type].add(expression); + } + + unadd(type, expression) { + this.operations[type].delete(expression); + } + + set(name, value, operation = ItemOperations.set, attribute) { + let operationToApply = operation; + if (operation === ItemOperations.ifNotExists) { + operationToApply = ItemOperations.set; + } + const seen = this.seen.get(name); + let n; + let v; + if (seen) { + n = seen.name; + v = seen.value; + this.unadd(operationToApply, seen.expression); + } else { + n = this.setName({}, name, name); + v = this.setValue(name, value); + } + let expression = `${n.prop} = ${v}`; + if (operation === ItemOperations.ifNotExists) { + expression = `${n.prop} = if_not_exists(${n.prop}, ${v})`; + } + this.seen.set(name, { + name: n, + value: v, + expression, + }); + this.add(operationToApply, expression); + } + + remove(name) { + const n = this.setName({}, name, name); + this.add(ItemOperations.remove, `${n.prop}`); + } + + build() { + let expressions = []; + for (const type of Object.keys(this.operations)) { + const operations = this.operations[type]; + if (operations.size > 0) { + expressions.push( + `${type.toUpperCase()} ${Array.from(operations).join(", ")}`, + ); + } + } + return expressions.join(" "); + } +} + +class UpdateEntity { + constructor(attributes = {}, operations = {}) { + this.attributes = { ...attributes }; + this.operations = { ...operations }; + } + + buildCallbackHandler(entity, state) { + const proxy = new AttributeOperationProxy({ + builder: state.query.update, + attributes: this.attributes, + operations: this.operations, + }); + + return (cb, ...params) => { + if (typeof cb !== "function") { + throw new Error('Update Callback must be of type "function"'); + } + proxy.invokeCallback(cb, ...params); + }; + } +} + +module.exports = { + UpdateEntity, + UpdateExpression, +}; + +},{"./operations":19,"./types":24,"./updateOperations":26}],26:[function(require,module,exports){ +const { AttributeTypes, ItemOperations } = require("./types"); + +const deleteOperations = { + canNest: false, + template: function del(options, attr, path, value) { + let operation = ""; + let expression = ""; + switch (attr.type) { + case AttributeTypes.any: + case AttributeTypes.set: + operation = ItemOperations.delete; + expression = `${path} ${value}`; + break; + default: + throw new Error( + `Invalid Update Attribute Operation: "DELETE" Operation can only be performed on attributes with type "set" or "any".`, + ); + } + return { operation, expression }; + }, +}; + +const UpdateOperations = { + ifNotExists: { + template: function if_not_exists(options, attr, path, value) { + const operation = ItemOperations.set; + const expression = `${path} = if_not_exists(${path}, ${value})`; + return { operation, expression }; + }, + }, + name: { + canNest: true, + template: function name(options, attr, path) { + return path; + }, + }, + value: { + canNest: true, + template: function value(options, attr, path, value) { + return value; + }, + }, + append: { + canNest: false, + template: function append(options, attr, path, value) { + let operation = ""; + let expression = ""; + switch (attr.type) { + case AttributeTypes.any: + case AttributeTypes.list: + const defaultValue = options.createValue("default_value", []); + expression = `${path} = list_append(if_not_exists(${path}, ${defaultValue}), ${value})`; + operation = ItemOperations.set; + break; + default: + throw new Error( + `Invalid Update Attribute Operation: "APPEND" Operation can only be performed on attributes with type "list" or "any".`, + ); + } + return { operation, expression }; + }, + }, + add: { + canNest: false, + template: function add(options, attr, path, value, defaultValue) { + let operation = ""; + let expression = ""; + let type = attr.type; + if (type === AttributeTypes.any) { + type = + typeof value === "number" + ? AttributeTypes.number + : AttributeTypes.any; + } + switch (type) { + case AttributeTypes.any: + case AttributeTypes.set: { + operation = ItemOperations.add; + expression = `${path} ${value}`; + break; + } + case AttributeTypes.number: { + if (options.nestedValue) { + operation = ItemOperations.set; + expression = `${path} = ${path} + ${value}`; + } else if (defaultValue !== undefined) { + // const defaultValueName = options.createValue(`default_value`, defaultValue) + operation = ItemOperations.set; + expression = `${path} = (if_not_exists(${path}, ${defaultValue}) + ${value})`; + } else { + operation = ItemOperations.add; + expression = `${path} ${value}`; + } + break; + } + default: + throw new Error( + `Invalid Update Attribute Operation: "ADD" Operation can only be performed on attributes with type "number", "set", or "any".`, + ); + } + return { operation, expression }; + }, + }, + subtract: { + canNest: false, + template: function subtract(options, attr, path, value, defaultValue = 0) { + let operation = ""; + let expression = ""; + switch (attr.type) { + case AttributeTypes.any: + case AttributeTypes.number: { + let resolvedDefaultValue; + if ( + typeof defaultValue === "string" && + defaultValue.startsWith(":") + ) { + resolvedDefaultValue = defaultValue; + } else if (defaultValue !== undefined) { + resolvedDefaultValue = options.createValue( + "default_value", + defaultValue, + ); + } else { + resolvedDefaultValue = options.createValue("default_value", 0); + } + // const defaultValuePath = options.createValue('default_value', resolvedDefaultValue); + operation = ItemOperations.set; + expression = `${path} = (if_not_exists(${path}, ${resolvedDefaultValue}) - ${value})`; + break; + } + default: + throw new Error( + `Invalid Update Attribute Operation: "SUBTRACT" Operation can only be performed on attributes with type "number" or "any".`, + ); + } + + return { operation, expression }; + }, + }, + set: { + canNest: false, + template: function set(options, attr, path, value) { + let operation = ""; + let expression = ""; + switch (attr.type) { + case AttributeTypes.set: + case AttributeTypes.list: + case AttributeTypes.map: + case AttributeTypes.enum: + case AttributeTypes.string: + case AttributeTypes.number: + case AttributeTypes.boolean: + case AttributeTypes.any: + operation = ItemOperations.set; + expression = `${path} = ${value}`; + break; + default: + throw new Error( + `Invalid Update Attribute Operation: "SET" Operation can only be performed on attributes with type "list", "map", "string", "number", "boolean", or "any".`, + ); + } + return { operation, expression }; + }, + }, + remove: { + canNest: false, + template: function remove(options, attr, ...paths) { + let operation = ""; + let expression = ""; + switch (attr.type) { + case AttributeTypes.set: + case AttributeTypes.any: + case AttributeTypes.list: + case AttributeTypes.map: + case AttributeTypes.string: + case AttributeTypes.number: + case AttributeTypes.boolean: + case AttributeTypes.enum: + operation = ItemOperations.remove; + expression = paths.join(", "); + break; + default: { + throw new Error( + `Invalid Update Attribute Operation: "REMOVE" Operation can only be performed on attributes with type "map", "list", "string", "number", "boolean", or "any".`, + ); + } + } + return { operation, expression }; + }, + }, + del: deleteOperations, + delete: deleteOperations, +}; + +module.exports = { + UpdateOperations, +}; + +},{"./types":24}],27:[function(require,module,exports){ +(function (Buffer){(function (){ +const t = require("./types"); +const v = require("./validations"); + +function parseJSONPath(path = "") { + if (typeof path !== "string") { + throw new Error("Path must be a string"); + } + path = path.replace(/\[/g, "."); + path = path.replace(/\]/g, ""); + return path.split(".").filter((part) => part !== ""); +} + +function genericizeJSONPath(path = "") { + return path.replace(/\[\d+\]/g, "[*]"); +} + +function getInstanceType(instance = {}) { + let [isModel, errors] = v.testModel(instance); + if (!instance || Object.keys(instance).length === 0) { + return ""; + } else if (isModel) { + return t.ElectroInstanceTypes.model; + } else if (instance._instance === t.ElectroInstance.entity) { + return t.ElectroInstanceTypes.entity; + } else if (instance._instance === t.ElectroInstance.service) { + return t.ElectroInstanceTypes.service; + } else if (instance._instance === t.ElectroInstance.electro) { + return t.ElectroInstanceTypes.electro; + } else { + return ""; + } +} + +function getModelVersion(model = {}) { + let nameOnRoot = model && v.isStringHasLength(model.entity); + let nameInModelNamespace = + model && model.model && v.isStringHasLength(model.model.entity); + if (nameInModelNamespace) { + return t.ModelVersions.v1; + } else if (nameOnRoot) { + return t.ModelVersions.beta; + } else { + return ""; + } +} + +function applyBetaModelOverrides( + model = {}, + { service = "", version = "", table = "" } = {}, +) { + let type = getModelVersion(model); + if (type !== t.ModelVersions.beta) { + throw new Error("Invalid model"); + } + let copy = Object.assign({}, model); + if (v.isStringHasLength(service)) { + copy.service = service; + } + if (v.isStringHasLength(version)) { + copy.version = version; + } + if (v.isStringHasLength(table)) { + copy.table = table; + } + return copy; +} + +function batchItems(arr = [], size) { + if (isNaN(size)) { + throw new Error("Batch size must be of type number"); + } + let batched = []; + for (let i = 0; i < arr.length; i++) { + let partition = Math.floor(i / size); + batched[partition] = batched[partition] || []; + batched[partition].push(arr[i]); + } + return batched; +} + +function commaSeparatedString(array = [], prefix = '"', postfix = '"') { + if (typeof array === 'string') { + array = [array]; + } + return array.map((value) => `${prefix}${value}${postfix}`).join(", "); +} + +function toDisplayString(value) { + if (value === undefined) { + return ""; + } + return JSON.stringify(value); +} + +function formatStringCasing(str, casing, defaultCase) { + if (typeof str !== "string") { + return str; + } + let strCase = defaultCase; + if (v.isStringHasLength(casing) && typeof t.KeyCasing[casing] === "string") { + strCase = + t.KeyCasing.default === casing ? defaultCase : t.KeyCasing[casing]; + } + switch (strCase) { + case t.KeyCasing.upper: + return str.toUpperCase(); + case t.KeyCasing.none: + return str; + case t.KeyCasing.lower: + return str.toLowerCase(); + case t.KeyCasing.default: + default: + return str; + } +} + +function toKeyCasingOption(casing) { + switch(casing) { + case t.KeyCasing.upper: + return t.KeyCasing.upper; + case t.KeyCasing.none: + return t.KeyCasing.none; + case t.KeyCasing.lower: + return t.KeyCasing.lower; + case t.KeyCasing.default: + case undefined: + return t.DefaultKeyCasing; + default: + throw new Error(`Unknown casing option: ${casing}`); + } +} + +function formatKeyCasing(str, casing) { + return formatStringCasing(str, casing, t.DefaultKeyCasing); +} + +function formatAttributeCasing(str, casing) { + return formatStringCasing(str, casing, t.KeyCasing.none); +} + +function formatIndexNameForDisplay(index) { + if (index) { + return index; + } else { + return "(Primary Index)"; + } +} + +class BatchGetOrderMaintainer { + constructor({ table, enabled, keyFormatter }) { + this.table = table; + this.enabled = enabled; + this.keyFormatter = keyFormatter; + this.batchIndexMap = new Map(); + this.currentSlot = 0; + } + + getSize() { + return this.batchIndexMap.size; + } + + getOrder(item) { + const key = this.keyFormatter(item); + const value = this.batchIndexMap.get(key); + if (value === undefined) { + return -1; + } + return value; + } + + defineOrder(parameters = []) { + if (this.enabled) { + for (let i = 0; i < parameters.length; i++) { + const batchParams = parameters[i]; + const recordKeys = + (batchParams && + batchParams.RequestItems && + batchParams.RequestItems[this.table] && + batchParams.RequestItems[this.table].Keys) || + []; + for (const recordKey of recordKeys) { + const indexMapKey = this.keyFormatter(recordKey); + this.batchIndexMap.set(indexMapKey, this.currentSlot++); + } + } + } + } +} + +function getUnique(arr1, arr2) { + return Array.from(new Set([...arr1, ...arr2])); +} + +const cursorFormatter = { + serialize: (key) => { + if (!key) { + return null; + } else if (typeof val !== "string") { + key = JSON.stringify(key); + } + return Buffer.from(key).toString("base64url"); + }, + deserialize: (cursor) => { + if (!cursor) { + return undefined; + } else if (typeof cursor !== "string") { + throw new Error( + `Invalid cursor provided, expected type 'string' recieved: ${JSON.stringify( + cursor, + )}`, + ); + } + try { + return JSON.parse(Buffer.from(cursor, "base64url").toString("utf8")); + } catch (err) { + throw new Error("Unable to parse cursor"); + } + }, +}; + +function removeFixings({ prefix = "", postfix = "", value = "" } = {}) { + if (prefix === "" && postfix === "") return value; + + const valueLower = value.toLowerCase(); + + const start = valueLower.startsWith(prefix.toLowerCase()) ? prefix.length : 0; + const end = + value.length - + (valueLower.endsWith(postfix.toLowerCase()) ? postfix.length : 0); + + return value.slice(start, end); +} + +function addPadding({ padding = {}, value = "" } = {}) { + return value.padStart(padding.length, padding.char); +} + +function removePadding({ padding = {}, value = "" } = {}) { + if (!padding.length || value.length >= padding.length) { + return value; + } + + let formatted = ""; + let useRemaining = false; + for (let i = 0; i < value.length; i++) { + const char = value[i]; + if (useRemaining || i >= padding.length) { + formatted += char; + } else if (char !== padding.char) { + formatted += char; + useRemaining = true; + } + } + + return formatted; +} + +function shiftSortOrder(str = "", codePoint) { + let newString = ""; + for (let i = 0; i < str.length; i++) { + const isLast = i === str.length - 1; + let char = str[i]; + if (isLast) { + char = String.fromCodePoint(char.codePointAt(0) + codePoint); + } + newString += char; + } + return newString; +} + +function getFirstDefined(...params) { + return params.find((val) => val !== undefined); +} + +function regexpEscape(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +module.exports = { + getUnique, + batchItems, + addPadding, + regexpEscape, + removePadding, + removeFixings, + parseJSONPath, + shiftSortOrder, + toDisplayString, + getFirstDefined, + getInstanceType, + getModelVersion, + formatKeyCasing, + cursorFormatter, + toKeyCasingOption, + genericizeJSONPath, + commaSeparatedString, + formatAttributeCasing, + applyBetaModelOverrides, + formatIndexNameForDisplay, + BatchGetOrderMaintainer, +}; + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./types":24,"./validations":28,"buffer":3}],28:[function(require,module,exports){ +const e = require("./errors"); +const { KeyCasing, IndexProjectionOptions, IndexTypes } = require("./types"); + +const Validator = require("jsonschema").Validator; +Validator.prototype.customFormats.isFunction = function (input) { + return typeof input === "function"; +}; +Validator.prototype.customFormats.isFunctionOrString = function (input) { + return typeof input === "function" || typeof input === "string"; +}; +Validator.prototype.customFormats.isFunctionOrRegexp = function (input) { + return typeof input === "function" || input instanceof RegExp; +}; + +let v = new Validator(); + +const Attribute = { + id: "/Attribute", + type: ["object", "string", "array"], + required: ["type"], + properties: { + type: { + // todo: only specific values + type: ["string", "array"], + // enum: ["string", "number", "boolean", "enum"], + }, + field: { + type: "string", + }, + hidden: { + type: "boolean", + }, + watch: { + type: ["array", "string"], + items: { + type: "string", + }, + }, + label: { + type: "string", + }, + readOnly: { + type: "boolean", + }, + required: { + type: "boolean", + }, + cast: { + type: "string", + enum: ["string", "number"], + }, + default: { + type: "any", + }, + validate: { + type: "any", + format: "isFunctionOrRegexp", + }, + get: { + type: "any", + format: "isFunction", + }, + set: { + type: "any", + format: "isFunction", + }, + padding: { + type: "object", + required: ["length", "char"], + properties: { + length: { + type: "number", + }, + char: { + type: "string", + }, + }, + }, + }, +}; + +const Index = { + id: "/Index", + type: "object", + properties: { + pk: { + type: "object", + required: true, + properties: { + field: { + type: "string", + required: false, + }, + facets: { + type: ["array", "string"], + items: { + type: "string", + }, + required: false, + }, + composite: { + type: ["array"], + items: { + type: "string", + }, + required: false, + }, + template: { + type: "string", + required: false, + }, + casing: { + type: "string", + enum: ["upper", "lower", "none", "default"], + required: false, + }, + cast: { + type: "string", + enum: ["string", "number"], + required: false, + }, + scope: { + type: "string", + required: false, + }, + }, + }, + sk: { + type: "object", + properties: { + field: { + type: "string", + required: false, + }, + facets: { + type: ["array", "string"], + required: false, + items: { + type: "string", + }, + }, + composite: { + type: ["array"], + required: false, + items: { + type: "string", + }, + }, + template: { + type: "string", + required: false, + }, + casing: { + type: "string", + enum: ["upper", "lower", "none", "default"], + required: false, + }, + cast: { + type: "string", + enum: ["string", "number"], + required: false, + }, + }, + }, + index: { + type: "string", + }, + collection: { + type: ["array", "string"], + }, + type: { + type: "string", + enum: Object.values(IndexTypes), + required: false, + }, + condition: { + type: "any", + required: false, + format: "isFunction", + }, + projection: { + type: ["array", "string"], + items: { + type: "string", + } + }, + }, +}; + +const Modelv1 = { + type: "object", + properties: { + model: { + type: "object", + required: true, + properties: { + entity: { + type: "string", + required: true, + }, + version: { + type: "string", + required: true, + }, + service: { + type: "string", + required: true, + }, + }, + }, + table: { + type: "string", + }, + attributes: { + type: "object", + patternProperties: { + ["."]: { $ref: "/Attribute" }, + }, + }, + indexes: { + type: "object", + minProperties: 1, + patternProperties: { + ["."]: { $ref: "/Index" }, + }, + }, + filters: { $ref: "/Filters" }, + }, + required: ["model", "attributes", "indexes"], +}; + +const ModelBeta = { + type: "object", + properties: { + service: { + type: "string", + required: true, + }, + entity: { + type: "string", + required: true, + }, + table: { + type: "string", + }, + version: { + type: "string", + }, + attributes: { + type: "object", + patternProperties: { + ["."]: { $ref: "/Attribute" }, + }, + }, + indexes: { + type: "object", + minProperties: 1, + patternProperties: { + ["."]: { $ref: "/Index" }, + }, + }, + filters: { $ref: "/Filters" }, + }, + required: ["attributes", "indexes"], +}; + +const Filters = { + id: "/Filters", + type: "object", + patternProperties: { + ["."]: { + type: "any", + format: "isFunction", + message: "Requires function", + }, + }, +}; + +v.addSchema(Attribute, "/Attribute"); +v.addSchema(Index, "/Index"); +v.addSchema(Filters, "/Filters"); +v.addSchema(ModelBeta, "/ModelBeta"); +v.addSchema(Modelv1, "/Modelv1"); + +function validateModel(model = {}) { + /** start beta/v1 condition **/ + let betaErrors = v.validate(model, ModelBeta).errors; + if (betaErrors.length) { + /** end/v1 condition **/ + let errors = v.validate(model, Modelv1).errors; + if (errors.length) { + throw new e.ElectroError( + e.ErrorCodes.InvalidModel, + errors + .map((err) => { + let message = `${err.property}`; + switch (err.argument) { + case "isFunction": + return `${message} must be a function`; + case "isFunctionOrString": + return `${message} must be either a function or string`; + case "isFunctionOrRegexp": + return `${message} must be either a function or Regexp`; + default: + return `${message} ${err.message}`; + } + }) + .join(", "), + ); + } + } +} + +function testModel(model) { + let isModel = false; + let error = ""; + try { + validateModel(model); + isModel = true; + } catch (err) { + error = err.message; + } + return [isModel, error]; +} + +function isStringHasLength(str) { + return typeof str === "string" && str.length > 0; +} + +function isObjectHasLength(obj) { + return typeof obj === "object" && Object.keys(obj).length > 0; +} + +function isArrayHasLength(arr) { + return Array.isArray(arr) && arr.length > 0; +} + +function isNameEntityRecordType(entityRecord) { + return ( + isObjectHasLength(entityRecord) && + Object.values(entityRecord).find((value) => { + return value._instance !== undefined; + }) + ); +} + +function isNameModelRecordType(modelRecord) { + return ( + isObjectHasLength(modelRecord) && + Object.values(modelRecord).find((value) => { + return ( + value.model && + isStringHasLength(value.model.entity) && + isStringHasLength(value.model.version) && + isStringHasLength(value.model.service) + ); + }) + ); +} + +function isBetaServiceConfig(serviceConfig) { + return ( + isObjectHasLength(serviceConfig) && + (isStringHasLength(serviceConfig.service) || + isStringHasLength(serviceConfig.name)) && + isStringHasLength(serviceConfig.version) + ); +} + +function isFunction(value) { + return typeof value === "function"; +} + +function isAbortSignal(value) { + return ( + value !== null && + typeof value === "object" && + typeof value.aborted === "boolean" && + typeof value.addEventListener === "function" && + typeof value.removeEventListener === "function" + ); +} + +function stringArrayMatch(arr1, arr2) { + let areArrays = Array.isArray(arr1) && Array.isArray(arr2); + let match = areArrays && arr1.length === arr2.length; + for (let i = 0; i < arr1.length; i++) { + if (!match) { + break; + } + match = isStringHasLength(arr1[i]) && arr1[i] === arr2[i]; + } + return match; +} + +function isMatchingCasing(casing1, casing2) { + const equivalentCasings = [KeyCasing.default, KeyCasing.lower]; + if (isStringHasLength(casing1) && isStringHasLength(casing2)) { + let isRealCase = KeyCasing[casing1.toLowerCase()] !== undefined; + let casingsMatch = casing1 === casing2; + let casingsAreEquivalent = [casing1, casing2].every((casing) => { + return casing === KeyCasing.lower || casing === KeyCasing.default; + }); + return isRealCase && (casingsMatch || casingsAreEquivalent); + } else if (isStringHasLength(casing1)) { + return equivalentCasings.includes(casing1.toLowerCase()); + } else if (isStringHasLength(casing2)) { + return equivalentCasings.includes(casing2.toLowerCase()); + } else { + return casing1 === undefined && casing2 === undefined; + } +} + +function isValueOrUndefined(received, expected) { + return expected === received || received === undefined; +} + +function isMatchingProjection(received, expected) { + if (isStringHasLength(received) && isStringHasLength(expected)) { + return received === expected; + } else if (Array.isArray(received) && Array.isArray(expected)) { + return true; + } else { + return isValueOrUndefined(received, IndexProjectionOptions.all) && isValueOrUndefined(expected, IndexProjectionOptions.all) + } +} + +module.exports = { + testModel, + isFunction, + isAbortSignal, + stringArrayMatch, + isMatchingProjection, + isMatchingCasing, + isArrayHasLength, + isStringHasLength, + isObjectHasLength, + isBetaServiceConfig, + isNameModelRecordType, + isNameEntityRecordType, + model: validateModel, +}; + +},{"./errors":15,"./types":24,"jsonschema":7}],29:[function(require,module,exports){ +const { MethodTypes, ExpressionTypes, BuilderTypes } = require("./types"); +const { + AttributeOperationProxy, + ExpressionState, + FilterOperations, +} = require("./operations"); +const e = require("./errors"); + +class FilterExpression extends ExpressionState { + constructor(props) { + super(props); + this.expression = ""; + this.type = BuilderTypes.filter; + } + + _trim(expression) { + if (typeof expression === "string" && expression.length > 0) { + return expression.replace(/\n|\r/g, "").trim(); + } + return ""; + } + + _isEmpty(expression) { + if (typeof expression !== "string") { + throw new Error("Invalid expression value type. Expected type string."); + } + return !expression.replace(/\n|\r|\w/g, "").trim(); + } + + add(newExpression, filterOptions = {}) { + const asPrefix = !!filterOptions.asPrefix; + let expression = ""; + let existingExpression = this.expression; + if ( + typeof existingExpression === "string" && + existingExpression.length > 0 + ) { + newExpression = this._trim(newExpression); + let isEmpty = this._isEmpty(newExpression); + if (isEmpty) { + return existingExpression; + } + + if ( + !asPrefix && + !existingExpression.startsWith("(") && + !existingExpression.endsWith(")") + ) { + existingExpression = `(${existingExpression})`; + } + if (asPrefix) { + expression = `(${newExpression}) AND ${existingExpression}`; + } else { + expression = `${existingExpression} AND ${newExpression}`; + } + } else { + expression = this._trim(newExpression); + } + this.expression = expression; + } + + // applies operations without verifying them against known attributes. Used internally for key conditions. + unsafeSet(filterOptions, operation, name, ...values) { + const { template } = FilterOperations[operation] || {}; + if (template === undefined) { + throw new Error( + `Invalid operation: "${operation}". Please report this issue via a bug ticket.`, + ); + } + const names = this.setName({}, name, name); + const valueExpressions = values.map((value) => this.setValue(name, value)); + const condition = template( + {}, + names.expression, + names.prop, + ...valueExpressions, + ); + this.add(condition, filterOptions); + } + + build() { + return this.expression; + } +} + +class WhereFactory { + constructor(attributes = {}, operations = {}) { + this.attributes = { ...attributes }; + this.operations = { ...operations }; + } + + getExpressionType(methodType) { + switch (methodType) { + case MethodTypes.put: + case MethodTypes.create: + case MethodTypes.update: + case MethodTypes.patch: + case MethodTypes.delete: + case MethodTypes.remove: + case MethodTypes.upsert: + case MethodTypes.get: + case MethodTypes.check: + return ExpressionTypes.ConditionExpression; + default: + return ExpressionTypes.FilterExpression; + } + } + + buildClause(cb) { + if (typeof cb !== "function") { + throw new e.ElectroError( + e.ErrorCodes.InvalidWhere, + 'Where callback must be of type "function"', + ); + } + return (entity, state, ...params) => { + const type = this.getExpressionType(state.query.method); + const builder = state.query.filter[type]; + const proxy = new AttributeOperationProxy({ + builder, + attributes: this.attributes, + operations: this.operations, + }); + const expression = proxy.invokeCallback(cb, ...params); + if (typeof expression !== "string") { + throw new e.ElectroError( + e.ErrorCodes.InvalidWhere, + "Invalid response from where clause callback. Expected return result to be of type string", + ); + } + builder.add(expression); + return state; + }; + } + + injectWhereClauses(clauses = {}, filters = {}) { + let injected = { ...clauses }; + let filterParents = Object.entries(injected) + .filter((clause) => { + let [name, { children }] = clause; + return children.find((child) => ["go", "commit"].includes(child)); + }) + .map(([name]) => name); + let modelFilters = Object.keys(filters); + let filterChildren = []; + for (let [name, filter] of Object.entries(filters)) { + filterChildren.push(name); + injected[name] = { + name, + action: this.buildClause(filter), + children: ["params", "go", "commit", "where", ...modelFilters], + }; + } + filterChildren.push("where"); + injected["where"] = { + name: "where", + action: (entity, state, fn) => { + return this.buildClause(fn)(entity, state); + }, + children: ["params", "go", "commit", "where", ...modelFilters], + }; + for (let parent of filterParents) { + injected[parent] = { ...injected[parent] }; + injected[parent].children = [ + ...filterChildren, + ...injected[parent].children, + ]; + } + return injected; + } +} + +module.exports = { + WhereFactory, + FilterExpression, +}; + +},{"./errors":15,"./operations":19,"./types":24}]},{},[10]); diff --git a/www/src/components/LiveExample/LiveExample.astro b/www/src/components/LiveExample/LiveExample.astro new file mode 100644 index 00000000..9efc7fd2 --- /dev/null +++ b/www/src/components/LiveExample/LiveExample.astro @@ -0,0 +1,71 @@ +--- +import ts from "typescript"; +import lzString from "lz-string"; +import { LiveExampleControl } from "./LiveExampleControl"; +import type { ExampleFile } from "./runtime"; +import "./LiveExample.css"; + +export interface Props { + /** Directory name under src/examples containing the example files */ + name: string; +} + +const { name } = Astro.props as Props; + +const LABELS: Record = { + "example.ts": "Example", + "entity.ts": "Entity", + "table.ts": "Table Definition", +}; + +// example.ts must come first: it is the program entry point (the other +// files execute when imported), and it is the tab shown by default. +const ORDER = ["example.ts", "entity.ts", "table.ts"]; + +const sources = import.meta.glob("/src/examples/*/*.ts", { + as: "raw", + eager: true, +}) as Record; + +const files: ExampleFile[] = Object.entries(sources) + .filter(([path]) => path.includes(`/examples/${name}/`)) + .map(([path, source]) => { + const fileName = path.split("/").pop() as string; + const trimmed = source.trim(); + return { + name: fileName, + label: LABELS[fileName] ?? fileName, + source: trimmed, + compiled: ts.transpileModule(trimmed, { + fileName, + compilerOptions: { + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES2017, + esModuleInterop: true, + }, + }).outputText, + }; + }) + .sort((a, b) => { + const left = ORDER.indexOf(a.name); + const right = ORDER.indexOf(b.name); + return (left === -1 ? ORDER.length : left) - (right === -1 ? ORDER.length : right); + }); + +if (files.length === 0) { + throw new Error( + `LiveExample: no files found for example "${name}" (expected TypeScript files under src/examples/${name}/)`, + ); +} + +// Deep-link into the playground's multi-file format so readers can edit and +// run this exact example at electrodb.fun. +const playgroundUrl = `https://electrodb.fun/#files/${lzString.compressToEncodedURIComponent( + JSON.stringify({ + v: 1, + files: files.map((file) => ({ name: file.name, content: file.source })), + }), +)}`; +--- + + diff --git a/www/src/components/LiveExample/LiveExample.css b/www/src/components/LiveExample/LiveExample.css new file mode 100644 index 00000000..5f8f40c2 --- /dev/null +++ b/www/src/components/LiveExample/LiveExample.css @@ -0,0 +1,207 @@ +.live-example { + margin: 1.5rem 0; + border: 1px solid var(--theme-border); + border-radius: 8px; + overflow: hidden; + box-shadow: var(--theme-shadow-sm); +} + +.live-example__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + flex-wrap: wrap; + padding: 0 0.5rem; + background-color: var(--theme-bg-offset); + border-bottom: 1px solid var(--theme-border); +} + +.live-example__tabs { + display: flex; + align-items: stretch; +} + +.live-example__tab { + appearance: none; + border: none; + background: none; + cursor: pointer; + padding: 0.55rem 0.85rem; + font-size: 0.8rem; + font-weight: 500; + color: var(--theme-text-light); + border-bottom: 2px solid transparent; + font-family: var(--font-mono, monospace); +} + +.live-example__tab:hover { + color: var(--theme-text); +} + +.live-example__tab--active { + color: var(--theme-text-accent); + border-bottom-color: var(--theme-accent); +} + +.live-example__playground-link { + font-size: 0.75rem; + padding: 0.25rem 0.5rem; + color: var(--theme-text-accent); + text-decoration: none; + white-space: nowrap; +} + +.live-example__playground-link:hover { + text-decoration: underline; +} + +.live-example__code { + margin: 0; + padding: 1rem; + background-color: var(--theme-code-bg); + color: var(--theme-code-text); + overflow-x: auto; + font-size: 0.8125rem; + line-height: 1.5; + font-family: var(--font-mono, ui-monospace, "SFMono-Regular", Menlo, monospace); +} + +.live-example__code code { + background: none; + padding: 0; + font-size: inherit; + color: inherit; + font-family: inherit; +} + +.live-example__source { + border-bottom: 1px solid rgba(255, 255, 255, 0.08); +} + +.live-example__output { + background-color: var(--theme-code-bg); + padding: 0.75rem 1rem 1rem; +} + +.live-example__output-heading { + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #8b949e; + margin-bottom: 0.5rem; +} + +.live-example__loading { + color: #8b949e; + font-size: 0.8125rem; + font-style: italic; +} + +.live-example__output-item + .live-example__output-item { + margin-top: 1rem; +} + +.live-example__output-label { + font-size: 0.8125rem; + color: #e6edf3; + margin-bottom: 0.5rem; +} + +.live-example__output-label b { + color: #79c0ff; +} + +.live-example__output .live-example__code { + padding: 0.75rem; + border-radius: 6px; + background-color: #161b22; +} + +.live-example__message { + font-size: 0.8125rem; + padding: 0.75rem; + border-radius: 6px; +} + +.live-example__message h3 { + margin: 0; + font-size: 0.8125rem; + font-weight: 500; +} + +.live-example__message--error { + background-color: rgba(248, 81, 73, 0.15); + color: #ffa198; +} + +.live-example__message--error a { + color: #79c0ff; +} + +.live-example__message--info { + background-color: #161b22; + color: #e6edf3; +} + +/* Prism token colors (the docs' fenced code blocks use build-time Shiki; + these apply only to LiveExample content highlighted with Prism) */ + +.live-example .token.comment, +.live-example .token.block-comment, +.live-example .token.prolog, +.live-example .token.doctype, +.live-example .token.cdata { + color: #8b949e; +} + +.live-example .token.punctuation { + color: #c9d1d9; +} + +.live-example .token.property, +.live-example .token.class-name, +.live-example .token.constant, +.live-example .token.symbol { + color: #79c0ff; +} + +.live-example .token.boolean, +.live-example .token.number, +.live-example .token.function { + color: #ffc107; +} + +.live-example .token.selector, +.live-example .token.important, +.live-example .token.atrule, +.live-example .token.keyword, +.live-example .token.builtin { + color: #ff7b72; +} + +.live-example .token.string, +.live-example .token.char, +.live-example .token.attr-value, +.live-example .token.regex { + color: #a5d6ff; +} + +.live-example .token.variable { + color: #ffa657; +} + +.live-example .token.operator, +.live-example .token.entity, +.live-example .token.url { + color: #67cdcc; +} + +.live-example .token.bold { + font-weight: bold; +} + +.live-example .token.italic { + font-style: italic; +} diff --git a/www/src/components/LiveExample/LiveExampleControl.tsx b/www/src/components/LiveExample/LiveExampleControl.tsx new file mode 100644 index 00000000..6bab311a --- /dev/null +++ b/www/src/components/LiveExample/LiveExampleControl.tsx @@ -0,0 +1,123 @@ +import { useEffect, useMemo, useState } from "react"; +import Prism from "prismjs"; +import "prismjs/components/prism-typescript"; +import "prismjs/components/prism-json"; +import { runExample } from "./runtime"; +import type { ExampleFile, OutputItem } from "./runtime"; + +export interface LiveExampleControlProps { + files: ExampleFile[]; + playgroundUrl: string; +} + +function highlight(code: string, language: "typescript" | "json"): string { + return Prism.highlight(code, Prism.languages[language], language); +} + +function OutputBlock({ item }: { item: OutputItem }) { + if (item.kind === "message") { + return ( +
+ ); + } + return ( +
+ {item.label ? ( +
+ ) : null} +
+        
+      
+
+ ); +} + +export function LiveExampleControl({ + files, + playgroundUrl, +}: LiveExampleControlProps) { + const [activeName, setActiveName] = useState(files[0]?.name); + const [output, setOutput] = useState(null); + + useEffect(() => { + let cancelled = false; + runExample(files) + .then((items) => { + if (!cancelled) { + setOutput(items); + } + }) + .catch((err) => { + if (!cancelled) { + setOutput([ + { + kind: "message", + type: "error", + html: `

${err instanceof Error ? err.message : String(err)}

`, + }, + ]); + } + }); + return () => { + cancelled = true; + }; + }, [files]); + + const activeFile = files.find((file) => file.name === activeName) ?? files[0]; + const highlighted = useMemo( + () => highlight(activeFile.source, "typescript"), + [activeFile], + ); + + return ( +
+
+
+ {files.map((file) => ( + + ))} +
+ + Edit in Playground ↗ + +
+
+        
+      
+
+
+ Generated DynamoDB Parameters +
+ {output === null ? ( +
Generating parameters…
+ ) : ( + output.map((item, index) => ) + )} +
+
+ ); +} diff --git a/www/src/components/LiveExample/runtime.ts b/www/src/components/LiveExample/runtime.ts new file mode 100644 index 00000000..c5561a03 --- /dev/null +++ b/www/src/components/LiveExample/runtime.ts @@ -0,0 +1,181 @@ +export interface ExampleFile { + /** File name within the example directory, e.g. "entity.ts" */ + name: string; + /** Tab label, e.g. "Entity" */ + label: string; + /** Original TypeScript source (displayed in the tab) */ + source: string; + /** CommonJS output produced at build time (executed in the browser) */ + compiled: string; +} + +export type OutputItem = + | { kind: "params"; label: string | null; json: string } + | { kind: "message"; type: "info" | "error"; html: string }; + +interface PlaygroundListener { + onParams(event: { label: string | null; params: unknown }): void; + onMessage(event: { type: "info" | "error"; html: string; text: string }): void; + onClear(): void; +} + +interface ElectroDBPlayground { + Entity: unknown; + Service: unknown; + createSchema: unknown; + createCustomAttribute: unknown; + CustomAttributeType: unknown; + configure(listener: Partial): () => void; + clearScreen(): void; + printMessage(type: string, message: string): void; +} + +declare global { + interface Window { + ElectroDB?: ElectroDBPlayground; + } +} + +const BUNDLE_SRC = "/scripts/electrodb-playground.js"; + +let bundlePromise: Promise | null = null; + +function loadBundle(): Promise { + if (typeof window.ElectroDB !== "undefined") { + return Promise.resolve(); + } + if (!bundlePromise) { + bundlePromise = new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = BUNDLE_SRC; + script.async = true; + script.onload = () => resolve(); + script.onerror = () => + reject(new Error("Failed to load the ElectroDB playground bundle")); + document.head.appendChild(script); + }); + } + return bundlePromise; +} + +function stripLabelWrapper(label: string | null): string | null { + if (!label) { + return null; + } + return label.replace(/^

/, "").replace(/<\/h2>$/, ""); +} + +function resolveRequest(request: string, moduleNames: Set): string { + if (request === "electrodb") { + return request; + } + if (!request.startsWith("./")) { + throw new Error(`Cannot find module '${request}'`); + } + const base = request.slice(2); + const candidates = [base, `${base}.ts`, `${base}.tsx`]; + const resolved = candidates.find((candidate) => moduleNames.has(candidate)); + if (resolved === undefined) { + throw new Error(`Cannot find module '${request}'`); + } + return resolved; +} + +function executeFiles(files: ExampleFile[]): Promise { + const playground = window.ElectroDB; + if (!playground) { + throw new Error("The ElectroDB playground bundle failed to load."); + } + const electrodbModule = { + Entity: playground.Entity, + Service: playground.Service, + createSchema: playground.createSchema, + createCustomAttribute: playground.createCustomAttribute, + CustomAttributeType: playground.CustomAttributeType, + }; + const byName = new Map(files.map((file) => [file.name, file])); + const moduleNames = new Set(byName.keys()); + const cache = new Map }>(); + + function requireModule(name: string): unknown { + if (name === "electrodb") { + return electrodbModule; + } + const cached = cache.get(name); + if (cached) { + return cached.exports; + } + const file = byName.get(name); + if (!file) { + throw new Error(`Cannot find module '${name}'`); + } + const record = { exports: {} as Record }; + cache.set(name, record); + const localRequire = (request: string) => + requireModule(resolveRequest(request, moduleNames)); + const factory = new Function("require", "module", "exports", file.compiled); + factory(localRequire, record, record.exports); + return record.exports; + } + + const entry = files[0]; + const record = { exports: {} as Record }; + cache.set(entry.name, record); + const localRequire = (request: string) => + requireModule(resolveRequest(request, moduleNames)); + // The entry module is wrapped in an async function so examples can use + // top-level await, mirroring how they appear in the documentation. + const factory = new Function( + "require", + "module", + "exports", + `return (async () => {\n${entry.compiled}\n})();`, + ); + return Promise.resolve(factory(localRequire, record, record.exports)); +} + +async function collectOutput(files: ExampleFile[]): Promise { + await loadBundle(); + const playground = window.ElectroDB; + if (!playground) { + throw new Error("The ElectroDB playground bundle failed to load."); + } + let items: OutputItem[] = []; + const restore = playground.configure({ + onParams: ({ label, params }) => { + items.push({ + kind: "params", + label: stripLabelWrapper(label), + json: JSON.stringify(params, null, 2), + }); + }, + onMessage: ({ type, html }) => { + items.push({ kind: "message", type, html }); + }, + onClear: () => { + items = []; + }, + }); + try { + playground.clearScreen(); + await executeFiles(files); + // Allow un-awaited `.go()` calls (e.g. transactions) to flush output. + await new Promise((resolve) => setTimeout(resolve, 10)); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + playground.printMessage("error", message); + } finally { + restore(); + } + return items; +} + +// Multiple LiveExample islands can exist on one documentation page; the +// playground listener is global state, so runs are serialized. +let queue: Promise = Promise.resolve(); + +export function runExample(files: ExampleFile[]): Promise { + const run = queue.then(() => collectOutput(files)); + queue = run.catch(() => undefined); + return run; +} diff --git a/www/src/examples/README.md b/www/src/examples/README.md new file mode 100644 index 00000000..2ad2dfbf --- /dev/null +++ b/www/src/examples/README.md @@ -0,0 +1,32 @@ +# Live documentation examples + +Each directory here is a self-contained, type-safe example rendered in the +docs by the `LiveExample` component (`src/components/LiveExample`): + +``` +src/examples// + example.ts # the code shown by default; imports the entity from ./entity + entity.ts # the Entity instantiation; imports the table name from ./table + table.ts # the DynamoDB table definition + exported table name +``` + +Usage inside an `.mdx` page: + +```mdx +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + + +``` + +The control renders each file as a tab and executes `example.ts` in the +browser against a mocked ElectroDB client +(`public/scripts/electrodb-playground.js`, built from `playground/` at the +repo root via `npm run build`) to display the generated DynamoDB parameters. +It also links to the playground (electrodb.fun) preloaded with the example's +files. + +Because these are real TypeScript modules compiled by the site's `check` +step, examples cannot silently drift out of sync with the ElectroDB API: if +an example stops compiling, the docs build fails. An example that needs a +schema tweak can modify its own `entity.ts`/`table.ts` copies without +affecting other pages. diff --git a/www/src/examples/get-store-location/entity.ts b/www/src/examples/get-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/get-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/get-store-location/example.ts b/www/src/examples/get-store-location/example.ts new file mode 100644 index 00000000..056b5e68 --- /dev/null +++ b/www/src/examples/get-store-location/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +const results = await StoreLocations.get({ + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + cityId: "Atlanta1", +}).go(); diff --git a/www/src/examples/get-store-location/table.ts b/www/src/examples/get-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/get-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/put-store-location/entity.ts b/www/src/examples/put-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/put-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/put-store-location/example.ts b/www/src/examples/put-store-location/example.ts new file mode 100644 index 00000000..e44ebb10 --- /dev/null +++ b/www/src/examples/put-store-location/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.put({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}) + .where((attr, op) => op.eq(attr.rent, "4500.00")) + .go(); diff --git a/www/src/examples/put-store-location/table.ts b/www/src/examples/put-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/put-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/pages/en/mutations/put.mdx b/www/src/pages/en/mutations/put.mdx index 7edb2caa..504a612d 100644 --- a/www/src/pages/en/mutations/put.mdx +++ b/www/src/pages/en/mutations/put.mdx @@ -12,28 +12,13 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; Provide all _required_ Attributes as defined in the model to create a new record. **ElectroDB** will enforce any defined validations, defaults, casting, and field aliasing. A Put operation will trigger the `default`, and `set` attribute callbacks when writing to DynamoDB. By default, after performing a `put()` or `create()` operation, ElectroDB will format and return the record through the same process as a Get/Query. This process will invoke the `get` callback on all included attributes. If this behaviour is not desired, use the [Execution Option](#execution-options) `response:"none"` to return a null value. -> This example includes an optional conditional expression. +> This example includes an optional conditional expression. The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -```typescript -await StoreLocations.put({ - cityId: "Atlanta1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "BuildingA1", - unitId: "B47", - category: "food/coffee", - leaseEndDate: "2020-03-22", - rent: "4500.00", -}) - .where((attr, op) => op.eq(attr.rent, "4500.00")) - .go(); -``` + ## Response Format @@ -45,40 +30,6 @@ await StoreLocations.put({ } ``` -## Equivalent Parameters - -```json -{ - "Item": { - "cityId": "Atlanta1", - "mallId": "EastPointe", - "storeId": "LatteLarrys", - "buildingId": "BuildingA1", - "unitId": "B47", - "category": "food/coffee", - "leaseEndDate": "2020-03-22", - "rent": "4500.00", - "discount": "0.00", - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_buildinga1#storeid_lattelarrys", - "gsi1pk": "$mallstoredirectory#mallid_eastpointe", - "gsi1sk": "$mallstore_1#buildingid_buildinga1#unitid_b47", - "gsi2pk": "$mallstoredirectory#storeid_lattelarrys", - "gsi2sk": "$mallstore_1#leaseenddate_2020-03-22", - "__edb_e__": "MallStore", - "__edb_v__": "1" - }, - "TableName": "StoreDirectory", - "ConditionExpression": "#rent = :rent_w1", - "ExpressionAttributeNames": { - "#rent": "rent" - }, - "ExpressionAttributeValues": { - ":rent_w1": "4500.00" - } -} -``` - ## Execution Options import PartialExample from "../../../partials/mutation-query-options.mdx"; diff --git a/www/src/pages/en/queries/get.mdx b/www/src/pages/en/queries/get.mdx index c070dcc9..a948acb0 100644 --- a/www/src/pages/en/queries/get.mdx +++ b/www/src/pages/en/queries/get.mdx @@ -12,20 +12,13 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Provide all Table Index composite attributes in an object to the `get` method. In the event no record is found, a value of `null` will be returned. -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. - - -```typescript -const results = await StoreLocations.get({ - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - cityId: "Atlanta1", -}).go(); -``` + ## Response Format @@ -38,18 +31,6 @@ const results = await StoreLocations.get({ } ``` -## Equivalent Parameters - -```json -{ - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - }, - "TableName": "YOUR_TABLE_NAME" -} -``` - ## Execution Options Execution options can be added the `.params()` and `.go()` to change query behavior or add customer parameters to a query. @@ -86,4 +67,4 @@ By default, **ElectroDB** enables you to work with records as the names and prop | listeners | `[]` | An array of callbacks that are invoked when [internal ElectroDB events](/en/reference/events-logging) occur. | | logger | _none_ | A convenience option for a single event listener that semantically can be used for logging. | | consistent | _none_ | When set to `true`, DynamoDB will return the most up-to-date data reflecting updates from all prior write operations using DynamoDB's [`ConsistentRead`](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html#HowItWorks.ReadConsistency.Strongly) parameter. Strongly consistent reads are only supported on tables and local secondary indexes. | -| abortSignal | _none_ | An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that can be used to cancel the operation. This is useful for implementing request timeouts or cancelling long-running operations. When the signal is aborted, ElectroDB will throw an [`OperationAborted`](/en/reference/errors#operation-aborted) error. | \ No newline at end of file +| abortSignal | _none_ | An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that can be used to cancel the operation. This is useful for implementing request timeouts or cancelling long-running operations. When the signal is aborted, ElectroDB will throw an [`OperationAborted`](/en/reference/errors#operation-aborted) error. | diff --git a/www/tsconfig.json b/www/tsconfig.json index b6e94d23..26524aea 100644 --- a/www/tsconfig.json +++ b/www/tsconfig.json @@ -2,6 +2,16 @@ "extends": "astro/tsconfigs/strict", "compilerOptions": { "jsx": "preserve", - "skipLibCheck": true + "skipLibCheck": true, + "noEmit": true, + // astro v1's base tsconfig sets importsNotUsedAsValues, deprecated in TS 5 + "ignoreDeprecations": "5.0", + "baseUrl": ".", + "paths": { + // Resolves imports in src/examples/** against the actual ElectroDB + // typings at the repo root so documentation examples are type-checked + // against the current API. + "electrodb": ["../index.d.ts"] + } } } From 0d7d6c61d78441312c39a55dd232e67bd21a7273 Mon Sep 17 00:00:00 2001 From: ty Date: Tue, 7 Jul 2026 09:49:33 -0400 Subject: [PATCH 02/16] Upgrade docs site to Astro 5 so it builds on current Node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Astro 1.6 failed to render MDX pages on Node 20+ (undici body assertion in renderPage), forcing builds onto Node 18/22. The site now builds and checks cleanly on Node 24. - astro ^5, @astrojs/mdx ^4, @astrojs/react ^4, add @astrojs/check for `astro check`, typescript ^5.7 - Drop the unused @astrojs/image integration (and sharp) and the preact renderer: the four remaining preact components (ThemeToggleButton, TableOfContents, SidebarToggle, PackageInstall) are converted to React so the site uses a single JSX renderer and needs no include/exclude filters - Fix strictness fallout: type-only Frontmatter import (verbatimModuleSyntax), explicit PropsWithChildren where React 18 types dropped implicit children - import.meta.glob `as: "raw"` → `query/import` form for Vite 6 - tsconfig: drop the TS5 ignoreDeprecations shim; exclude dist/ and public/ --- www/.gitignore | 3 + www/astro.config.mjs | 11 +- www/package-lock.json | 18178 ++++++---------- www/package.json | 23 +- www/src/components/Display/Row.tsx | 5 +- www/src/components/HeadSEO.astro | 3 +- www/src/components/Header/SidebarToggle.tsx | 12 +- .../components/LiveExample/LiveExample.astro | 3 +- .../components/PageContent/PackageInstall.tsx | 32 +- www/src/components/PageContent/QuickLook.tsx | 5 +- .../RightSidebar/TableOfContents.tsx | 7 +- .../RightSidebar/ThemeToggleButton.tsx | 4 +- www/tsconfig.json | 5 +- 13 files changed, 7137 insertions(+), 11154 deletions(-) diff --git a/www/.gitignore b/www/.gitignore index b30e9811..ba6eeb30 100644 --- a/www/.gitignore +++ b/www/.gitignore @@ -19,3 +19,6 @@ pnpm-debug.log* # macOS-specific files .DS_Store + +# astro generated types +.astro/ diff --git a/www/astro.config.mjs b/www/astro.config.mjs index 66d6bcf8..5800a89e 100644 --- a/www/astro.config.mjs +++ b/www/astro.config.mjs @@ -1,18 +1,9 @@ import { defineConfig } from "astro/config"; -import preact from "@astrojs/preact"; import react from "@astrojs/react"; import mdx from "@astrojs/mdx"; -import image from "@astrojs/image"; - // https://astro.build/config export default defineConfig({ - integrations: [ - // Enable Preact to support Preact JSX components. - preact(), // Enable React for the Algolia search component. - react(), - mdx(), - image(), - ], + integrations: [react(), mdx()], site: "https://electrodb.dev", }); diff --git a/www/package-lock.json b/www/package-lock.json index 7e2e4255..ec5ccf2f 100644 --- a/www/package-lock.json +++ b/www/package-lock.json @@ -1,7 +1,7 @@ { "name": "@example/docs", "version": "0.0.1", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,421 +9,633 @@ "version": "0.0.1", "dependencies": { "@algolia/client-search": "^4.13.1", - "@astrojs/image": "^0.12.1", - "@astrojs/mdx": "^0.12.1", - "@astrojs/preact": "^1.1.0", - "@astrojs/react": "^1.2.2", + "@astrojs/mdx": "^4.3.0", + "@astrojs/react": "^4.3.0", "@docsearch/css": "^3.1.0", "@docsearch/react": "^3.1.0", - "@types/node": "^18.0.0", - "@types/react": "^17.0.45", - "@types/react-dom": "^18.0.0", - "astro": "^1.6.14", + "@types/node": "^20.14.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "astro": "^5.0.0", "lz-string": "^1.5.0", - "preact": "^10.7.3", "prismjs": "^1.29.0", - "react": "^18.2.0", - "react-dom": "^18.1.0", - "sharp": "^0.31.2" + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "devDependencies": { + "@astrojs/check": "^0.9.4", "@types/prismjs": "^1.26.3", "pagefind": "^1.5.2", - "typescript": "~5.2.2" + "typescript": "^5.7.2" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.21.1.tgz", + "integrity": "sha512-Wia5/mNTfiU0PIUN25UMfAGGdASkkwuCS9nBAdmhqrNPY/ff7U/6MgBVdwFDPsa3sA1msutPtO50gvOzx6MOXA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/abtesting/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.1.tgz", - "integrity": "sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", + "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", + "@algolia/autocomplete-shared": "1.17.9" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", + "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", + "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.7.1" + "@algolia/autocomplete-shared": "1.17.9" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.1.tgz", - "integrity": "sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", + "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", + "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.7.1" + "@algolia/autocomplete-shared": "1.17.9" }, "peerDependencies": { - "@algolia/client-search": "^4.9.1", - "algoliasearch": "^4.9.1" + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.1.tgz", - "integrity": "sha512-eTmGVqY3GeyBTT8IWiB2K5EuURAqhnumfktAEoHxfDY2o7vg2rSnO16ZtIG0fMgt3py28Vwgq42/bVEuaQV7pg==" - }, - "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz", - "integrity": "sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==", - "dependencies": { - "@algolia/cache-common": "4.14.2" + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", + "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" } }, "node_modules/@algolia/cache-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.2.tgz", - "integrity": "sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==" + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.27.0.tgz", + "integrity": "sha512-Sr8zjNXj82p6lO4W9CdzfF0m0/9h/H6VAdSHOTtimm/cTzXIYXRI2IZq7+Nt2ljJ7Ukx+7dIFcxQjE57eQSPsw==", + "license": "MIT" }, - "node_modules/@algolia/cache-in-memory": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz", - "integrity": "sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==", + "node_modules/@algolia/client-abtesting": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.55.1.tgz", + "integrity": "sha512-miW8RzAtBgNiEJ9fGEhsOPgWUpekAe64YcVufqXrlykj0Jjmo5nj0a5f/HAzRVX5ZuU1GAVd7BkzFDx7q50P3A==", + "license": "MIT", "dependencies": { - "@algolia/cache-common": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-account": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.2.tgz", - "integrity": "sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==", - "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/transporter": "4.14.2" + "node_modules/@algolia/client-abtesting/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.2.tgz", - "integrity": "sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==", + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.55.1.tgz", + "integrity": "sha512-eR3J3kB9JX6DdCvDRi3I4KPfwO6fR9HWYRXhVke2TXIoOQafMKCRAneg33JRmIrb+DnnJ/eWApJLF1O1CLPERg==", + "license": "MIT", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.2.tgz", - "integrity": "sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.27.0.tgz", + "integrity": "sha512-ZrT6l/YPQgyIUuBCxcYPeXol2VBLUMuNb1rKXrm6z1f/iTiwqtnEEb16/6CC11+Re0ZGXrdcMVrgDRrzveQ1aQ==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.27.0", + "@algolia/transporter": "4.27.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.55.1.tgz", + "integrity": "sha512-OVtj9uA//+pjvKQI5INnzbyLrf3ClNv3XRbWswwJ2kHIStQNHtBfHo+LofNB/WhM9xjuXlW5ANn2aMj65UGx7w==", + "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.2.tgz", - "integrity": "sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==", + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.55.1.tgz", + "integrity": "sha512-oKlVFlp+qbIEe4p7E54zSiP2gEV/vDu972Ykv8VDMFwEvreS7m0YKA3a8hGGHwc7yiBUGGiR3LlwzMLfnJmy6Q==", + "license": "MIT", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.55.1.tgz", + "integrity": "sha512-BOVrld6vdtsFmotVDMTVQfYXwrVplJ+DUvy60JFi+tkWV698q2J9NNPKEO3dr5qxtSLKQP4vHF8n+3U5PDWhOQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz", - "integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.27.0.tgz", + "integrity": "sha512-qmX/f67ay0eZ4V5Io8fWWOcUVo/gqre2yei1PnmEhQU2Gul6ushg25QnNrfu4BODiRrw1rwYveZaLCiHvcUxrQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.27.0", + "@algolia/requester-common": "4.27.0", + "@algolia/transporter": "4.27.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.55.1.tgz", + "integrity": "sha512-BXZw+C+gsWL7pZvbnhJUnCXASiDLGcQxVV7h55Pyh2DmSzwdZIVccE5xc9RVD2trtrhIqk5smuODTxtaZqd0IA==", + "license": "MIT", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/logger-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.2.tgz", - "integrity": "sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==" + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.27.0.tgz", + "integrity": "sha512-pIrmQRXtDV+zTMVXKtKCosC2rWhn0F0TdUeb9etA6RiAz6jY6bY6f0+JX7YekDK09SnmZMLIyUa7Jci+Ied9bw==", + "license": "MIT" }, - "node_modules/@algolia/logger-console": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.2.tgz", - "integrity": "sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==", + "node_modules/@algolia/monitoring": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.55.1.tgz", + "integrity": "sha512-9g/ceZrZTqA62FA3588Xj0onRPjDNfu0pVQqefK0rrHp9H6Wblph/YmzGjZ2g8uqbTh0ZGIvAGCzErU8f7MHpA==", + "license": "MIT", "dependencies": { - "@algolia/logger-common": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/requester-browser-xhr": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz", - "integrity": "sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==", + "node_modules/@algolia/monitoring/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.55.1.tgz", + "integrity": "sha512-cZTIrGyAP+W4A6jDVwvWM/JOaoJKQkD/2a5eLUEeNdKAD45jN7BCpsMDONyhZlosLa4UwL8uiINQzj4iFy9nqg==", + "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.14.2" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/requester-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.2.tgz", - "integrity": "sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==" + "node_modules/@algolia/recommend/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } }, - "node_modules/@algolia/requester-node-http": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz", - "integrity": "sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==", + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.55.1.tgz", + "integrity": "sha512-N6I3leW0UO8Y9Zv90yo2UHgYGuxZO0mjbvzNxDIJDjO0qECEF7Z9XMvSNeUWXQh/iNDA9lr8MfEy3rmZGIcclw==", + "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.14.2" + "@algolia/client-common": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/transporter": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.2.tgz", - "integrity": "sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==", + "node_modules/@algolia/requester-browser-xhr/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.27.0.tgz", + "integrity": "sha512-VC3prAQVgWTubMStb3mJz6i61Hqbtagi2LeIbgNtoFJFff3XZDcAaO1D5r0GYl2+DrB2VzUHnQXbkiuI+HHYyg==", + "license": "MIT" + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.55.1.tgz", + "integrity": "sha512-ukU5zeeFs44rQkzv+TRdYard+d+3lmPGs8lPZhHtWE8rfz+LlBSF6s9kP3VQ7LeOYL8Dz0u6tZfnyTrqrumbHQ==", + "license": "MIT", "dependencies": { - "@algolia/cache-common": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/requester-common": "4.14.2" + "@algolia/client-common": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@altano/tiny-async-pool": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@altano/tiny-async-pool/-/tiny-async-pool-1.0.2.tgz", - "integrity": "sha512-qQzaI0TBUPdpjZ3qo5b2ziQY9MSNpbziH2ZrE5lvtUZL+kn9GwVuVJwoOubaoNkeDB+rqEefnpu1k+oMpOCYiw==" + "node_modules/@algolia/requester-fetch/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "node_modules/@algolia/requester-node-http": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.55.1.tgz", + "integrity": "sha512-lCwXyijwPm3vbYHpBXPRomMcD6mgiptmps27gnMCf4HK+u/AOeFPBnIFh4V3l4A5SnP9VRiKBZqwGBpUH0vaTg==", + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@algolia/client-common": "5.55.1" }, "engines": { - "node": ">=6.0.0" + "node": ">= 14.0.0" } }, - "node_modules/@astrojs/compiler": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-0.30.1.tgz", - "integrity": "sha512-sH3hvGA9JR5eE2bHG3sr5QjaJl5ER9EmmZzSwBHkMPoBj0XU7XzQjSGoyCbIML6sSaelJEPnfsr9NsypvKOecg==" - }, - "node_modules/@astrojs/image": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@astrojs/image/-/image-0.12.1.tgz", - "integrity": "sha512-7pBUPCw7/FPwfEntx+mGjhdwpaWXNHwRVcTK71rpf+c2yb8iIesRS9r26U7lGozTzXUROh1y1ftA82ziuqYF6Q==", - "dependencies": { - "@altano/tiny-async-pool": "^1.0.2", - "http-cache-semantics": "^4.1.0", - "image-size": "^1.0.2", + "node_modules/@algolia/requester-node-http/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.27.0.tgz", + "integrity": "sha512-PvSbELU4VjN3xSX79ki+zIdOGhTxyJXWvRDzkUjfTx2iNfPWDdTjzKbP1o+268coJztxrkuBwJz90Urek7o1Kw==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.27.0", + "@algolia/logger-common": "4.27.0", + "@algolia/requester-common": "4.27.0" + } + }, + "node_modules/@astrojs/check": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@astrojs/check/-/check-0.9.9.tgz", + "integrity": "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/language-server": "^2.16.7", + "chokidar": "^4.0.3", "kleur": "^4.1.5", - "magic-string": "^0.25.9", - "mime": "^3.0.0", - "slash": "^4.0.0", - "web-streams-polyfill": "^3.2.1" + "yargs": "^17.7.2" }, - "peerDependencies": { - "sharp": ">=0.31.0" + "bin": { + "astro-check": "bin/astro-check.js" }, - "peerDependenciesMeta": { - "sharp": { - "optional": true - } + "peerDependencies": { + "typescript": "^5.0.0 || ^6.0.0" } }, + "node_modules/@astrojs/compiler": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.1.tgz", + "integrity": "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==", + "license": "MIT" + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.6.tgz", + "integrity": "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q==", + "license": "MIT" + }, "node_modules/@astrojs/language-server": { - "version": "0.28.3", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-0.28.3.tgz", - "integrity": "sha512-fPovAX/X46eE2w03jNRMpQ7W9m2mAvNt4Ay65lD9wl1Z5vIQYxlg7Enp9qP225muTr4jSVB5QiLumFJmZMAaVA==", - "dependencies": { - "@vscode/emmet-helper": "^2.8.4", - "events": "^3.3.0", - "prettier": "^2.7.1", - "prettier-plugin-astro": "^0.7.0", - "source-map": "^0.7.3", - "vscode-css-languageservice": "^6.0.1", - "vscode-html-languageservice": "^5.0.0", - "vscode-languageserver": "^8.0.1", - "vscode-languageserver-protocol": "^3.17.1", - "vscode-languageserver-textdocument": "^1.0.4", - "vscode-languageserver-types": "^3.17.1", - "vscode-uri": "^3.0.3" + "version": "2.16.11", + "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.11.tgz", + "integrity": "sha512-sJ/EfnFp0+gurTrkvONtd9qRqmMZLT9bHelfI1SA35CaQVTrRrA74qteOcNT/al1b9Atg3IiH1Jk/qfckyC+fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.13.1", + "@astrojs/yaml2ts": "^0.2.4", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@volar/kit": "~2.4.28", + "@volar/language-core": "~2.4.28", + "@volar/language-server": "~2.4.28", + "@volar/language-service": "~2.4.28", + "muggle-string": "^0.4.1", + "tinyglobby": "^0.2.16", + "volar-service-css": "0.0.71", + "volar-service-emmet": "0.0.71", + "volar-service-html": "0.0.71", + "volar-service-prettier": "0.0.71", + "volar-service-typescript": "0.0.71", + "volar-service-typescript-twoslash-queries": "0.0.71", + "volar-service-yaml": "0.0.71", + "vscode-html-languageservice": "^5.6.2", + "vscode-uri": "^3.1.0" }, "bin": { "astro-ls": "bin/nodeServer.js" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "prettier-plugin-astro": ">=0.11.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + } } }, "node_modules/@astrojs/markdown-remark": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-1.1.3.tgz", - "integrity": "sha512-6MDuQXbrp2fZBYBIqD+0jvSqYAukiMTte6oLNHiEYsLf3KIMlVAZj6dDgUJakgL7cQ4fmzWb0HUqzVpxAsasLw==", - "dependencies": { - "@astrojs/micromark-extension-mdx-jsx": "^1.0.3", - "@astrojs/prism": "^1.0.0", - "acorn": "^8.7.1", - "acorn-jsx": "^5.3.2", - "github-slugger": "^1.4.0", - "hast-util-to-html": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "mdast-util-from-markdown": "^1.2.0", - "mdast-util-mdx-expression": "^1.2.1", - "mdast-util-mdx-jsx": "^1.2.0", - "micromark-extension-mdx-expression": "^1.0.3", - "micromark-extension-mdx-md": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "rehype-raw": "^6.1.1", - "rehype-stringify": "^9.0.3", - "remark-gfm": "^3.0.1", - "remark-parse": "^10.0.1", - "remark-rehype": "^10.1.0", - "remark-smartypants": "^2.0.0", - "shiki": "^0.11.1", - "unified": "^10.1.2", - "unist-util-map": "^3.1.1", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2" - } - }, - "node_modules/@astrojs/mdx": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-0.12.1.tgz", - "integrity": "sha512-d41ariAR7VMHb+4ALiXPbYXMPSqjpGqTAZBSp40sRam084r/4Vwr6F1mwRKWFDwbwgN6iLN+fczSQDvqoOD2JQ==", - "dependencies": { - "@astrojs/prism": "^1.0.2", - "@mdx-js/mdx": "^2.1.2", - "@mdx-js/rollup": "^2.1.1", - "acorn": "^8.8.0", - "es-module-lexer": "^0.10.5", - "estree-util-visit": "^1.2.0", - "github-slugger": "^1.4.0", - "gray-matter": "^4.0.3", - "kleur": "^4.1.4", - "rehype-raw": "^6.1.1", - "remark-frontmatter": "^4.0.1", - "remark-gfm": "^3.0.1", - "remark-smartypants": "^2.0.0", - "shiki": "^0.11.1", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2" - }, - "engines": { - "node": "^14.18.0 || >=16.12.0" - } - }, - "node_modules/@astrojs/micromark-extension-mdx-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@astrojs/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", - "integrity": "sha512-O15+i2DGG0qb1R/1SYbFXgOKDGbYdV8iJMtuboVb1S9YFQfMOJxaCMco0bhXQI7PmZcQ4pZWIjT5oZ64dXUtRA==", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.11.tgz", + "integrity": "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==", + "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" + "@astrojs/internal-helpers": "0.7.6", + "@astrojs/prism": "3.3.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "shiki": "^3.21.0", + "smol-toml": "^1.6.0", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" } }, - "node_modules/@astrojs/preact": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@astrojs/preact/-/preact-1.1.0.tgz", - "integrity": "sha512-beUw4Y6dNJ7394Kqoz3kVNfhALLExjllXGB4+GtORmprZLs8hBqnGk4mOlNr/9iuZZumN5YCQmafkC5vkyCtZw==", + "node_modules/@astrojs/mdx": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.14.tgz", + "integrity": "sha512-FBrqJQORVm+rkRa2TS5CjU9PBA6hkhrwLVBSS9A77gN2+iehvjq1w6yya/d0YKC7osiVorKkr3Qd9wNbl0ZkGA==", + "license": "MIT", "dependencies": { - "@babel/core": ">=7.0.0-0 <8.0.0", - "@babel/plugin-transform-react-jsx": "^7.17.12", - "babel-plugin-module-resolver": "^4.1.0", - "preact-render-to-string": "^5.2.0" + "@astrojs/markdown-remark": "6.3.11", + "@mdx-js/mdx": "^3.1.1", + "acorn": "^8.15.0", + "es-module-lexer": "^1.7.0", + "estree-util-visit": "^2.0.0", + "hast-util-to-html": "^9.0.5", + "piccolore": "^0.1.3", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "remark-smartypants": "^3.0.2", + "source-map": "^0.7.6", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.3" }, "engines": { - "node": "^14.18.0 || >=16.12.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" }, "peerDependencies": { - "preact": "^10.6.5" + "astro": "^5.0.0" } }, "node_modules/@astrojs/prism": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-1.0.2.tgz", - "integrity": "sha512-o3cUVoAuALDqdN5puNlsN2eO4Yi1kDh68YO8V7o6U4Ts+J/mMayzlJ7JsgYAmob0xrf/XnADVgu8khfMv/w3uA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", + "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", + "license": "MIT", "dependencies": { - "prismjs": "^1.28.0" + "prismjs": "^1.30.0" }, "engines": { - "node": "^14.18.0 || >=16.12.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, "node_modules/@astrojs/react": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-1.2.2.tgz", - "integrity": "sha512-ab9fYvzkC74J7N+M3DWQuZgwu7sYjW0aLO3sEAdCX/jZZz+0BhrqS8m9QjtGJyQK/niF4tgJjpPfadopxKc56g==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-4.4.2.tgz", + "integrity": "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==", + "license": "MIT", "dependencies": { - "@babel/core": ">=7.0.0-0 <8.0.0", - "@babel/plugin-transform-react-jsx": "^7.17.12" + "@vitejs/plugin-react": "^4.7.0", + "ultrahtml": "^1.6.0", + "vite": "^6.4.1" }, "engines": { - "node": "^14.18.0 || >=16.12.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" }, "peerDependencies": { - "@types/react": "^17.0.50 || ^18.0.21", - "@types/react-dom": "^17.0.17 || ^18.0.6", - "react": "^17.0.2 || ^18.0.0", - "react-dom": "^17.0.2 || ^18.0.0" + "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", + "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "node_modules/@astrojs/telemetry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-1.0.1.tgz", - "integrity": "sha512-SJVfZHp00f8VZsT1fsx1+6acJGUNt/84xZytV5znPzzNE8RXjlE0rv03llgTsEeUHYZc6uJah91jNojS7RldFg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", + "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", + "license": "MIT", "dependencies": { - "ci-info": "^3.3.1", - "debug": "^4.3.4", + "ci-info": "^4.2.0", + "debug": "^4.4.0", "dlv": "^1.1.3", - "dset": "^3.1.2", + "dset": "^3.1.4", "is-docker": "^3.0.0", - "is-wsl": "^2.2.0", - "node-fetch": "^3.2.5", + "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" }, "engines": { - "node": "^14.18.0 || >=16.12.0" + "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, - "node_modules/@astrojs/webapi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@astrojs/webapi/-/webapi-1.1.1.tgz", - "integrity": "sha512-yeUvP27PoiBK/WCxyQzC4HLYZo4Hg6dzRd/dTsL50WGlAQVCwWcqzVJrIZKvzNDNaW/fIXutZTmdj6nec0PIGg==", + "node_modules/@astrojs/yaml2ts": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/yaml2ts/-/yaml2ts-0.2.4.tgz", + "integrity": "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A==", + "dev": true, + "license": "MIT", "dependencies": { - "global-agent": "^3.0.0", - "node-fetch": "^3.2.5" + "yaml": "^2.8.3" } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -434,203 +646,133 @@ } }, "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "dependencies": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "dependencies": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dependencies": { - "@babel/types": "^7.18.6" - }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dependencies": { - "@babel/types": "^7.18.6" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dependencies": { - "@babel/types": "^7.18.6" - }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/types": "^7.29.7" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==", "bin": { "parser": "bin/babel-parser.js" }, @@ -638,12 +780,13 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -652,16 +795,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", - "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.19.0" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -671,70 +811,84 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@docsearch/css": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.2.1.tgz", - "integrity": "sha512-gaP6TxxwQC+K8D6TRx5WULUWKrcbzECOPA2KCVMuI+6C7dNiGUk5yXXzVhc5sld79XKYLnO9DRTI4mjXDYkh+g==" + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.9.0.tgz", + "integrity": "sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==", + "license": "MIT" }, "node_modules/@docsearch/react": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.2.1.tgz", - "integrity": "sha512-EzTQ/y82s14IQC5XVestiK/kFFMe2aagoYFuTAIfIb/e+4FU7kSMKonRtLwsCiLQHmjvNQq+HO+33giJ5YVtaQ==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.9.0.tgz", + "integrity": "sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==", + "license": "MIT", "dependencies": { - "@algolia/autocomplete-core": "1.7.1", - "@algolia/autocomplete-preset-algolia": "1.7.1", - "@docsearch/css": "3.2.1", - "algoliasearch": "^4.0.0" + "@algolia/autocomplete-core": "1.17.9", + "@algolia/autocomplete-preset-algolia": "1.17.9", + "@docsearch/css": "3.9.0", + "algoliasearch": "^5.14.2" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0" + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" }, "peerDependenciesMeta": { "@types/react": { @@ -745,5347 +899,2313 @@ }, "react-dom": { "optional": true + }, + "search-insights": { + "optional": true } } }, "node_modules/@emmetio/abbreviation": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.2.3.tgz", - "integrity": "sha512-87pltuCPt99aL+y9xS6GPZ+Wmmyhll2WXH73gG/xpGcQ84DRnptBsI2r0BeIQ0EB/SQTOe2ANPqFqj3Rj5FOGA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", + "integrity": "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==", + "dev": true, + "license": "MIT", "dependencies": { - "@emmetio/scanner": "^1.0.0" + "@emmetio/scanner": "^1.0.4" } }, "node_modules/@emmetio/css-abbreviation": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.4.tgz", - "integrity": "sha512-qk9L60Y+uRtM5CPbB0y+QNl/1XKE09mSO+AhhSauIfr2YOx/ta3NJw2d8RtCFxgzHeRqFRr8jgyzThbu+MZ4Uw==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.8.tgz", + "integrity": "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/css-parser": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@emmetio/css-parser/-/css-parser-0.4.1.tgz", + "integrity": "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emmetio/stream-reader": "^2.2.0", + "@emmetio/stream-reader-utils": "^0.1.0" + } + }, + "node_modules/@emmetio/html-matcher": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emmetio/html-matcher/-/html-matcher-1.3.0.tgz", + "integrity": "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==", + "dev": true, + "license": "ISC", "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "node_modules/@emmetio/scanner": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.0.tgz", - "integrity": "sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.4.tgz", + "integrity": "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz", + "integrity": "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emmetio/stream-reader-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", + "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", - "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ - "loong64" + "arm64" ], + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@ljharb/has-package-exports-patterns": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@ljharb/has-package-exports-patterns/-/has-package-exports-patterns-0.0.2.tgz", - "integrity": "sha512-4/RWEeXDO6bocPONheFe6gX/oQdP/bEpv0oL4HqjPP5DCenBSt0mHgahppY49N0CpsaqffdwPq+TlX9CYOq2Dw==" - }, - "node_modules/@mdx-js/mdx": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.1.5.tgz", - "integrity": "sha512-zEG0lt+Bl/r5U6e0TOS7qDbsXICtemfAPquxWFsMbdzrvlWaqMGemLl+sjVpqlyaaiCiGVQBSGdCk0t1qXjkQg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/mdx": "^2.0.0", - "estree-util-build-jsx": "^2.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "estree-util-to-js": "^1.1.0", - "estree-walker": "^3.0.0", - "hast-util-to-estree": "^2.0.0", - "markdown-extensions": "^1.0.0", - "periscopic": "^3.0.0", - "remark-mdx": "^2.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^10.0.0", - "unified": "^10.0.0", - "unist-util-position-from-estree": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@mdx-js/rollup": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-2.1.5.tgz", - "integrity": "sha512-l90rSiwnEf6PnjH8uRXjZ1W0rR8p1fp1YIiDuA3uF7SOfxMQ98uymaIwI6BsX+8BC2dcWij7Racwp++JkvdOLQ==", - "dependencies": { - "@mdx-js/mdx": "^2.0.0", - "@rollup/pluginutils": "^4.0.0", - "source-map": "^0.7.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "rollup": ">=2" + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/@pagefind/darwin-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", - "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ - "arm64" + "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" - ] + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/darwin-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", - "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ - "x64" + "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" - ] + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/freebsd-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", - "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ - "x64" + "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "freebsd" - ] + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/linux-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", - "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ - "arm64" + "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/linux-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", - "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/windows-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", - "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] + "netbsd" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@pagefind/windows-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", - "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "dependencies": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" - }, + "netbsd" + ], "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" - }, - "node_modules/@proload/core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz", - "integrity": "sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==", - "dependencies": { - "deepmerge": "^4.2.2", - "escalade": "^3.1.1" + "node": ">=18" } }, - "node_modules/@proload/plugin-tsm": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@proload/plugin-tsm/-/plugin-tsm-0.2.1.tgz", - "integrity": "sha512-Ex1sL2BxU+g8MHdAdq9SZKz+pU34o8Zcl9PHWo2WaG9hrnlZme607PU6gnpoAYsDBpHX327+eu60wWUk+d/b+A==", - "dependencies": { - "tsm": "^2.1.4" - }, - "peerDependencies": { - "@proload/core": "^0.3.2" + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "dependencies": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">= 8.0.0" + "node": ">=18" } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - }, - "node_modules/@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "dependencies": { - "@types/estree": "*" + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dependencies": { - "@babel/types": "^7.0.0" + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", - "dependencies": { - "@babel/types": "^7.3.0" + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "dependencies": { - "@types/ms": "*" + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" } }, - "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" - }, - "node_modules/@types/estree-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.0.tgz", - "integrity": "sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==", - "dependencies": { - "@types/estree": "*" + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", - "dependencies": { - "@types/unist": "*" + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, - "node_modules/@types/html-escaper": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/html-escaper/-/html-escaper-3.0.0.tgz", - "integrity": "sha512-OcJcvP3Yk8mjYwf/IdXZtTE1tb/u0WF0qa29ER07ZHCYUBZXSN29Z1mBS+/96+kNMGTFUAbSz9X+pHmHpZrTCw==" - }, - "node_modules/@types/json5": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz", - "integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==" - }, - "node_modules/@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", - "dependencies": { - "@types/unist": "*" + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" - }, - "node_modules/@types/mdx": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.3.tgz", - "integrity": "sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==" - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, - "node_modules/@types/nlcst": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.0.tgz", - "integrity": "sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==", - "dependencies": { - "@types/unist": "*" + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" - }, - "node_modules/@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" - }, - "node_modules/@types/prismjs": { - "version": "1.26.6", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", - "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", - "dependencies": { - "@types/react": "*" + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==" - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "node_modules/@vscode/emmet-helper": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.8.4.tgz", - "integrity": "sha512-lUki5QLS47bz/U8IlG9VQ+1lfxMtxMZENmU5nu4Z71eOD5j9FK0SmYGL5NiVJg9WBWeAU0VxRADMY2Qpq7BfVg==", - "dependencies": { - "emmet": "^2.3.0", - "jsonc-parser": "^2.3.0", - "vscode-languageserver-textdocument": "^1.0.1", - "vscode-languageserver-types": "^3.15.1", - "vscode-nls": "^5.0.0", - "vscode-uri": "^2.1.2" + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@vscode/emmet-helper/node_modules/vscode-uri": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz", - "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==" - }, - "node_modules/@vscode/l10n": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.10.tgz", - "integrity": "sha512-E1OCmDcDWa0Ya7vtSjp/XfHFGqYJfh+YPC1RkATU71fTac+j1JjCcB3qwSzmlKAighx2WxhLlfhS0RwAN++PFQ==" + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/algoliasearch": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz", - "integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.14.2", - "@algolia/cache-common": "4.14.2", - "@algolia/cache-in-memory": "4.14.2", - "@algolia/client-account": "4.14.2", - "@algolia/client-analytics": "4.14.2", - "@algolia/client-common": "4.14.2", - "@algolia/client-personalization": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/logger-console": "4.14.2", - "@algolia/requester-browser-xhr": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/requester-node-http": "4.14.2", - "@algolia/transporter": "4.14.2" + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dependencies": { - "string-width": "^4.1.0" + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/ansi-align/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" } }, - "node_modules/ansi-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" } }, - "node_modules/ansi-align/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" } }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, - "node_modules/array-iterate": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-1.1.4.tgz", - "integrity": "sha512-sNRaPGh9nnmdC8Zf+pT3UqP8rnWj5Hf9wiFGsX3wUQ2yVSIhO2ShFwCoceIPpB41QF6i2OEmrHmCo36xronCVA==", + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, - "node_modules/ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, "dependencies": { - "tslib": "^2.0.1" + "@emnapi/runtime": "^1.7.0" }, "engines": { - "node": ">=4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/astring": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.3.tgz", - "integrity": "sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A==", - "bin": { - "astring": "bin/astring" + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/astro": { - "version": "1.6.14", - "resolved": "https://registry.npmjs.org/astro/-/astro-1.6.14.tgz", - "integrity": "sha512-8ljrWPKEU5Hrrbupan48ba4gLWPY14Aqiv4u0U92wSl3wtsqPJUWWlHGGkXcgS/9dx8aiLkUm4RzCPFVnP7V2w==", - "dependencies": { - "@astrojs/compiler": "^0.30.0", - "@astrojs/language-server": "^0.28.3", - "@astrojs/markdown-remark": "^1.1.3", - "@astrojs/telemetry": "^1.0.1", - "@astrojs/webapi": "^1.1.1", - "@babel/core": "^7.18.2", - "@babel/generator": "^7.18.2", - "@babel/parser": "^7.18.4", - "@babel/plugin-transform-react-jsx": "^7.17.12", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.4", - "@proload/core": "^0.3.3", - "@proload/plugin-tsm": "^0.2.1", - "@types/babel__core": "^7.1.19", - "@types/html-escaper": "^3.0.0", - "@types/yargs-parser": "^21.0.0", - "boxen": "^6.2.1", - "ci-info": "^3.3.1", - "common-ancestor-path": "^1.0.1", - "cookie": "^0.5.0", - "debug": "^4.3.4", - "deepmerge-ts": "^4.2.2", - "diff": "^5.1.0", - "es-module-lexer": "^0.10.5", - "execa": "^6.1.0", - "fast-glob": "^3.2.11", - "github-slugger": "^1.4.0", - "gray-matter": "^4.0.3", - "html-entities": "^2.3.3", - "html-escaper": "^3.0.3", - "import-meta-resolve": "^2.1.0", - "kleur": "^4.1.4", - "magic-string": "^0.25.9", - "mime": "^3.0.0", - "ora": "^6.1.0", - "path-browserify": "^1.0.1", - "path-to-regexp": "^6.2.1", - "postcss": "^8.4.14", - "postcss-load-config": "^3.1.4", - "preferred-pm": "^3.0.3", - "prompts": "^2.4.2", - "recast": "^0.20.5", - "rehype": "^12.0.1", - "resolve": "^1.22.0", - "rollup": "^2.79.1", - "semver": "^7.3.7", - "shiki": "^0.11.1", - "sirv": "^2.0.2", - "slash": "^4.0.0", - "string-width": "^5.1.2", - "strip-ansi": "^7.0.1", - "supports-esm": "^1.0.0", - "tsconfig-resolver": "^3.0.1", - "typescript": "*", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2", - "vite": "~3.2.5", - "vitefu": "^0.2.1", - "yargs-parser": "^21.0.1", - "zod": "^3.17.3" - }, - "bin": { - "astro": "astro.js" - }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^14.18.0 || >=16.12.0", - "npm": ">=6.14.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/astro/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", "dependencies": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", - "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" - }, - "engines": { - "node": ">= 8.0.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bl": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", - "integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" - }, - "node_modules/boxen": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", - "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^6.2.0", - "chalk": "^4.1.2", - "cli-boxes": "^3.0.0", - "string-width": "^5.0.1", - "type-fest": "^2.5.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/boxen/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/boxen/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" }, - "node_modules/boxen/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/@pagefind/darwin-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/boxen/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } + "node_modules/@pagefind/darwin-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/boxen/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/@pagefind/freebsd-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "node_modules/@pagefind/linux-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } + "node_modules/@pagefind/linux-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } + "node_modules/@pagefind/windows-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "cpu": [ + "arm64" ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } + "node_modules/@pagefind/windows-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "cpu": [ + "x64" ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=10" + "node": ">=14.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001400", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001400.tgz", - "integrity": "sha512-Mv659Hn65Z4LgZdJ7ge5JTVbE3rqbJaaXgW5LEI9/tOaXclfIZ8DW7D7FCWWWmWiiPS7AC48S8kf3DApSxQdgA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" ] }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/comma-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", - "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deepmerge-ts": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-4.2.2.tgz", - "integrity": "sha512-Ka3Kb21tiWjvQvS9U+1Dx+aqFAHsdTnMdYptLTmC2VAmDFMugWMY1e15aTODstipmCun8iNuqeSfcx6rsUUk0Q==", - "engines": { - "node": ">=12.4.0" - } - }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "node_modules/dset": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", - "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==", - "engines": { - "node": ">=4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.251", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.251.tgz", - "integrity": "sha512-k4o4cFrWPv4SoJGGAydd07GmlRVzmeDIJ6MaEChTUjk4Dmomn189tCicSzil2oyvbPoGgg2suwPDNWq4gWRhoQ==" - }, - "node_modules/emmet": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.3.6.tgz", - "integrity": "sha512-pLS4PBPDdxuUAmw7Me7+TcHbykTsBKN/S9XJbUOMFQrNv9MoshzyMFK/R57JBm94/6HSL4vHnDeEmxlC82NQ4A==", - "dependencies": { - "@emmetio/abbreviation": "^2.2.3", - "@emmetio/css-abbreviation": "^2.1.4" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-module-lexer": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.10.5.tgz", - "integrity": "sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==" - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" - }, - "node_modules/esbuild": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", - "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/linux-loong64": "0.14.54", - "esbuild-android-64": "0.14.54", - "esbuild-android-arm64": "0.14.54", - "esbuild-darwin-64": "0.14.54", - "esbuild-darwin-arm64": "0.14.54", - "esbuild-freebsd-64": "0.14.54", - "esbuild-freebsd-arm64": "0.14.54", - "esbuild-linux-32": "0.14.54", - "esbuild-linux-64": "0.14.54", - "esbuild-linux-arm": "0.14.54", - "esbuild-linux-arm64": "0.14.54", - "esbuild-linux-mips64le": "0.14.54", - "esbuild-linux-ppc64le": "0.14.54", - "esbuild-linux-riscv64": "0.14.54", - "esbuild-linux-s390x": "0.14.54", - "esbuild-netbsd-64": "0.14.54", - "esbuild-openbsd-64": "0.14.54", - "esbuild-sunos-64": "0.14.54", - "esbuild-windows-32": "0.14.54", - "esbuild-windows-64": "0.14.54", - "esbuild-windows-arm64": "0.14.54" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", - "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", - "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", - "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", - "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", - "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", - "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", - "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", - "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", - "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", - "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", - "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", - "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", - "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", - "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", - "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", - "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", - "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", - "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", - "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", - "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estree-util-attach-comments": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-2.1.0.tgz", - "integrity": "sha512-rJz6I4L0GaXYtHpoMScgDIwM0/Vwbu5shbMeER596rB2D1EWF6+Gj0e0UKzJPZrpoOc87+Q2kgVFHfjAymIqmw==", - "dependencies": { - "@types/estree": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-build-jsx": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-2.2.0.tgz", - "integrity": "sha512-apsfRxF9uLrqosApvHVtYZjISPvTJ+lBiIydpC+9wE6cF6ssbhnjyQLqaIjgzGxvC2Hbmec1M7g91PoBayYoQQ==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "estree-walker": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-is-identifier-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.1.tgz", - "integrity": "sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-to-js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-1.1.0.tgz", - "integrity": "sha512-490lbfCcpLk+ofK6HCgqDfYs4KAfq6QVvDw3+Bm1YoKRgiOjKiKYGAVQE1uwh7zVxBgWhqp4FDtp5SqunpUk1A==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "astring": "^1.8.0", - "source-map": "^0.7.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-util-visit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-1.2.0.tgz", - "integrity": "sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/estree-walker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.1.tgz", - "integrity": "sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", - "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^3.0.1", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fault": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", - "dependencies": { - "format": "^0.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", - "dependencies": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-babel-config/node_modules/json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-yarn-workspace-root2": { - "version": "1.2.16", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", - "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", - "dependencies": { - "micromatch": "^4.0.2", - "pkg-dir": "^4.2.0" - } - }, - "node_modules/format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "node_modules/github-slugger": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==" - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-package-exports": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/has-package-exports/-/has-package-exports-1.3.0.tgz", - "integrity": "sha512-e9OeXPQnmPhYoJ63lXC4wWe34TxEGZDZ3OQX9XRqp2VwsfLl3bQBy7VehLnd34g3ef8CmYlBLGqEMKXuz8YazQ==", - "dependencies": { - "@ljharb/has-package-exports-patterns": "^0.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hast-to-hyperscript": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-10.0.1.tgz", - "integrity": "sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==", - "dependencies": { - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^5.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.0.tgz", - "integrity": "sha512-m8yhANIAccpU4K6+121KpPP55sSl9/samzQSQGpb0mTExcNh2WlvjtMwSWFhg6uqD4Rr6Nfa8N6TMypQM51rzQ==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "@types/unist": "^2.0.0", - "hastscript": "^7.0.0", - "property-information": "^6.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-is-element": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", - "integrity": "sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-parse-selector": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.0.tgz", - "integrity": "sha512-AyjlI2pTAZEOeu7GeBPZhROx0RHBnydkQIXlhnFzDi0qfXTmGUWoCYZtomHbrdrheV4VFUlPcfJ6LMF5T6sQzg==", - "dependencies": { - "@types/hast": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-raw": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.2.tgz", - "integrity": "sha512-0x3BhhdlBcqRIKyc095lBSDvmQNMY3Eulj2PLsT5XCyKYrxssI5yr3P4Kv/PBo1s/DMkZy2voGkMXECnFCZRLQ==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "hast-util-from-parse5": "^7.0.0", - "hast-util-to-parse5": "^7.0.0", - "html-void-elements": "^2.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-estree": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.1.0.tgz", - "integrity": "sha512-Vwch1etMRmm89xGgz+voWXvVHba2iiMdGMKmaMfYt35rbVtFDq8JNwwAIvi8zHMkO6Gvqo9oTMwJTmzVRfXh4g==", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "estree-util-attach-comments": "^2.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "mdast-util-mdx-expression": "^1.0.0", - "mdast-util-mdxjs-esm": "^1.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.3.0", - "unist-util-position": "^4.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-html": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz", - "integrity": "sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==", - "dependencies": { - "@types/hast": "^2.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-is-element": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "html-void-elements": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.2", - "unist-util-is": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-parse5": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.0.0.tgz", - "integrity": "sha512-YHiS6aTaZ3N0Q3nxaY/Tj98D6kM8QX5Q8xqgg8G45zR7PvWnPGPP0vcKCgb/moIydEJ/QWczVrX0JODCVeoV7A==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "hast-to-hyperscript": "^10.0.0", - "property-information": "^6.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", - "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hastscript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.0.2.tgz", - "integrity": "sha512-uA8ooUY4ipaBvKcMuPehTAB/YfFLSSzCwFSwT6ltJbocFUKH/GDHLN+tflq7lSRf9H86uOuxOFkh1KgIy3Gg2g==", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, - "node_modules/html-escaper": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", - "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" - }, - "node_modules/html-void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", - "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "node_modules/human-signals": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", - "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/import-meta-resolve": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.0.tgz", - "integrity": "sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-reference": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.0.tgz", - "integrity": "sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", - "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==" - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "engines": { - "node": ">=10" - } - }, - "node_modules/load-yaml-file": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", - "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", - "dependencies": { - "graceful-fs": "^4.1.5", - "js-yaml": "^3.13.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/load-yaml-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/longest-streak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", - "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "license": "MIT", - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/markdown-extensions": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz", - "integrity": "sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/markdown-table": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", - "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/matcher/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-definitions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", - "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.1.tgz", - "integrity": "sha512-SobxkQXFAdd4b5WmEakmkVoh18icjQRxGy5OWTCzgsLRm1Fu/KCtwD1HIQSsmq5ZRjVH0Ehwg6/Fn3xIUk+nKw==", - "dependencies": { - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdast-util-from-markdown": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", - "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-frontmatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-1.0.0.tgz", - "integrity": "sha512-7itKvp0arEVNpCktOET/eLFAYaZ+0cNjVtFtIPxgQ5tV+3i+D4SDDTjTzPWl44LT59PC+xdx+glNTawBdF98Mw==", - "dependencies": { - "micromark-extension-frontmatter": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz", - "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==", - "dependencies": { - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-gfm-autolink-literal": "^1.0.0", - "mdast-util-gfm-footnote": "^1.0.0", - "mdast-util-gfm-strikethrough": "^1.0.0", - "mdast-util-gfm-table": "^1.0.0", - "mdast-util-gfm-task-list-item": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz", - "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==", - "dependencies": { - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-find-and-replace": "^2.0.0", - "micromark-util-character": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz", - "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==", - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0", - "micromark-util-normalize-identifier": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.1.tgz", - "integrity": "sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg==", - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", - "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", - "dependencies": { - "@types/mdast": "^3.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.3.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz", - "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==", - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz", - "integrity": "sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==", - "dependencies": { - "mdast-util-mdx-expression": "^1.0.0", - "mdast-util-mdx-jsx": "^2.0.0", - "mdast-util-mdxjs-esm": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.0.tgz", - "integrity": "sha512-9kTO13HaL/ChfzVCIEfDRdp1m5hsvsm6+R8yr67mH+KS2ikzZ0ISGLPTbTswOFpLLlgVHO9id3cul4ajutCvCA==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-1.2.0.tgz", - "integrity": "sha512-5+ot/kfxYd3ChgEMwsMUO71oAfYjyRI3pADEK4I7xTmWLGQ8Y7ghm1CG36zUoUvDPxMlIYwQV/9DYHAUWdG4dA==", - "dependencies": { - "@types/estree-jsx": "^0.0.1", - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^4.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/estree-jsx": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-0.0.1.tgz", - "integrity": "sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/mdast-util-mdx/node_modules/mdast-util-mdx-jsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.0.tgz", - "integrity": "sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-to-markdown": "^1.3.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^4.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.0.tgz", - "integrity": "sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "12.2.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.2.tgz", - "integrity": "sha512-lVkUttV9wqmdXFtEBXKcepvU/zfwbhjbkM5rxrquLW55dS1DfOrnAXCk5mg1be1sfY/WfMmayGy1NsbK1GLCYQ==", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", - "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "trim-lines": "^3.0.0", - "unist-builder": "^3.0.0", - "unist-util-generated": "^2.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", - "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "longest-streak": "^3.0.0", - "mdast-util-to-string": "^3.0.0", - "micromark-util-decode-string": "^1.0.0", - "unist-util-visit": "^4.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", - "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", - "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-extension-frontmatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-1.0.0.tgz", - "integrity": "sha512-EXjmRnupoX6yYuUJSQhrQ9ggK0iQtQlpi6xeJzVD5xscyAI+giqco5fdymayZhJMbIFecjnE2yz85S9NzIgQpg==", - "dependencies": { - "fault": "^2.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz", - "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^1.0.0", - "micromark-extension-gfm-footnote": "^1.0.0", - "micromark-extension-gfm-strikethrough": "^1.0.0", - "micromark-extension-gfm-table": "^1.0.0", - "micromark-extension-gfm-tagfilter": "^1.0.0", - "micromark-extension-gfm-task-list-item": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz", - "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==", - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz", - "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==", - "dependencies": { - "micromark-core-commonmark": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz", - "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==", - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz", - "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==", - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz", - "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==", - "dependencies": { - "micromark-util-types": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz", - "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==", - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdx-expression": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz", - "integrity": "sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-extension-mdx-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", - "integrity": "sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==", - "dependencies": { - "@types/acorn": "^4.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdx-md": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz", - "integrity": "sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==", - "dependencies": { - "micromark-util-types": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz", - "integrity": "sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==", - "dependencies": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^1.0.0", - "micromark-extension-mdx-jsx": "^1.0.0", - "micromark-extension-mdx-md": "^1.0.0", - "micromark-extension-mdxjs-esm": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-mdxjs-esm": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.3.tgz", - "integrity": "sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==", - "dependencies": { - "micromark-core-commonmark": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.1.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", - "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", - "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-factory-mdx-expression": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz", - "integrity": "sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", - "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", - "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", - "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", - "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", - "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", - "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", - "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", - "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", - "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", - "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-events-to-acorn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.0.tgz", - "integrity": "sha512-WWp3bf7xT9MppNuw3yPjpnOxa8cj5ACivEzXJKu0WwnjBYfzaBvIAT9KfeyI0Qkll+bfQtfftSwdgTH6QhTOKw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/acorn": "^4.0.0", - "@types/estree": "^1.0.0", - "estree-util-visit": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-location": "^4.0.0", - "vfile-message": "^3.0.0" - } - }, - "node_modules/micromark-util-html-tag-name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", - "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", - "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", - "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/micromark-util-subtokenize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", - "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", - "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" ] }, - "node_modules/micromark-util-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", - "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" ] }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" - }, - "node_modules/nlcst-to-string": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-2.0.4.tgz", - "integrity": "sha512-3x3jwTd6UPG7vi5k4GEzvxJ5rDA7hVUIRNHPblKuMVP9Z3xmlsd9cgLcpAMkc5uPOBna82EeshROFhsPkbnTZg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/node-abi": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz", - "integrity": "sha512-qWO5l3SCqbwQavymOmtTVuCWZE23++S+rxyoHjXqUmPyzRcaoI4lA2gO55/drddGnedAyjA7sk76SfQ5lfUMnw==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", - "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" - }, - "node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", - "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", - "dependencies": { - "bl": "^5.0.0", - "chalk": "^5.0.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.6.1", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.1.0", - "log-symbols": "^5.1.0", - "strip-ansi": "^7.0.1", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/pagefind": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", - "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", - "dev": true, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "bin": { - "pagefind": "lib/runner/bin.cjs" - }, - "optionalDependencies": { - "@pagefind/darwin-arm64": "1.5.2", - "@pagefind/darwin-x64": "1.5.2", - "@pagefind/freebsd-x64": "1.5.2", - "@pagefind/linux-arm64": "1.5.2", - "@pagefind/linux-x64": "1.5.2", - "@pagefind/windows-arm64": "1.5.2", - "@pagefind/windows-x64": "1.5.2" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/parse-entities": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.0.tgz", - "integrity": "sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ==", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/parse-latin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.0.tgz", - "integrity": "sha512-Ht+4/+AUySMS5HKGAiQpBmkFsHSoGrj6Y83flLCa5OIBdtsVkO3UD4OtboJ0O0vZiOznH02x8qlwg9KLUVXuNg==", - "dependencies": { - "nlcst-to-string": "^2.0.0", - "unist-util-modify-children": "^2.0.0", - "unist-util-visit-children": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/periscopic": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.0.4.tgz", - "integrity": "sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==", - "dependencies": { - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", + "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", + "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" } }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "license": "MIT", "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "@shikijs/types": "3.23.0" } }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/preact": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", - "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" + "@shikijs/types": "3.23.0" } }, - "node_modules/preact-render-to-string": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", - "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "license": "MIT", "dependencies": { - "pretty-format": "^3.8.0" - }, - "peerDependencies": { - "preact": ">=10" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/preferred-pm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", - "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", - "dependencies": { - "find-up": "^5.0.0", - "find-yarn-workspace-root2": "1.2.16", - "path-exists": "^4.0.0", - "which-pm": "2.0.0" - }, - "engines": { - "node": ">=10" - } + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" }, - "node_modules/preferred-pm/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/preferred-pm/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/types": "^7.0.0" } }, - "node_modules/preferred-pm/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/preferred-pm/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/preferred-pm/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "@babel/types": "^7.28.2" } }, - "node_modules/prettier-plugin-astro": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.7.0.tgz", - "integrity": "sha512-ehCUx7MqHWvkHwUmxxAWLsL35pFaCTM5YXQ8xjG/1W6dY2yBhvEks+2aCfjeI5zmMrZNCXkiMQtpznSlLSLrxw==", + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", "dependencies": { - "@astrojs/compiler": "^0.29.3", - "prettier": "^2.7.1", - "sass-formatter": "^0.7.5", - "synckit": "^0.8.4" - }, - "engines": { - "node": "^14.15.0 || >=16.0.0", - "npm": ">=6.14.0" + "@types/ms": "*" } }, - "node_modules/prettier-plugin-astro/node_modules/@astrojs/compiler": { - "version": "0.29.19", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-0.29.19.tgz", - "integrity": "sha512-lvPpoOA6Fc1NpJrPT65ZOhhFieYkiBds9wzOhWX55lXMUpNPu5CUxqzgDAkNSTIoXHZxkxHfi+6EpFNnRZBBYQ==" - }, - "node_modules/pretty-format": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", - "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" - } + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prompts/node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, - "node_modules/property-information": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", - "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "@types/estree": "*" } }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "@types/unist": "*" } }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", "dependencies": { - "inherits": "~2.0.3" + "@types/unist": "*" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/@types/mdx": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", + "license": "MIT" }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/unist": "*" } }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" + "undici-types": "~6.21.0" } }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, - "node_modules/recast": { - "version": "0.20.5", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", - "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "license": "MIT", "dependencies": { - "ast-types": "0.14.2", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 4" + "@types/prop-types": "*", + "csstype": "^3.2.2" } }, - "node_modules/recast/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" } }, - "node_modules/rehype": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/rehype/-/rehype-12.0.1.tgz", - "integrity": "sha512-ey6kAqwLM3X6QnMDILJthGvG1m1ULROS9NT4uG9IDCuv08SFyLlreSuvOa//DgEvbXx62DS6elGVqusWhRUbgw==", - "dependencies": { - "@types/hast": "^2.0.0", - "rehype-parse": "^8.0.0", - "rehype-stringify": "^9.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" }, - "node_modules/rehype-parse": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.4.tgz", - "integrity": "sha512-MJJKONunHjoTh4kc3dsM1v3C9kGrrxvA3U8PxZlP2SjH8RNUSrb+lF7Y0KVaUDnGH2QZ5vAn7ulkiajM9ifuqg==", - "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^7.0.0", - "parse5": "^6.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/@ungap/structured-clone": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.2.tgz", + "integrity": "sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==", + "license": "ISC" }, - "node_modules/rehype-raw": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", - "integrity": "sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==", + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-raw": "^7.2.0", - "unified": "^10.0.0" + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/rehype-stringify": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-9.0.3.tgz", - "integrity": "sha512-kWiZ1bgyWlgOxpqD5HnxShKAdXtb2IUljn3hQAhySeak6IOQPPt6DeGnsIh4ixm7yKJWzm8TXFuC/lPfcWHJqw==", + "node_modules/@volar/kit": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/kit/-/kit-2.4.28.tgz", + "integrity": "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "hast-util-to-html": "^8.0.0", - "unified": "^10.0.0" + "@volar/language-service": "2.4.28", + "@volar/typescript": "2.4.28", + "typesafe-path": "^0.2.2", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "peerDependencies": { + "typescript": "*" } }, - "node_modules/remark-frontmatter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-4.0.1.tgz", - "integrity": "sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==", + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-frontmatter": "^1.0.0", - "micromark-extension-frontmatter": "^1.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@volar/source-map": "2.4.28" } }, - "node_modules/remark-gfm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", - "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "node_modules/@volar/language-server": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-server/-/language-server-2.4.28.tgz", + "integrity": "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^2.0.0", - "micromark-extension-gfm": "^2.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@volar/language-core": "2.4.28", + "@volar/language-service": "2.4.28", + "@volar/typescript": "2.4.28", + "path-browserify": "^1.0.1", + "request-light": "^0.7.0", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" } }, - "node_modules/remark-mdx": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", - "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", + "node_modules/@volar/language-service": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-service/-/language-service-2.4.28.tgz", + "integrity": "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==", + "dev": true, + "license": "MIT", "dependencies": { - "mdast-util-mdx": "^2.0.0", - "micromark-extension-mdxjs": "^1.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@volar/language-core": "2.4.28", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" } }, - "node_modules/remark-parse": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", - "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/remark-rehype": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", - "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "node_modules/@vscode/emmet-helper": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.11.0.tgz", + "integrity": "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-to-hast": "^12.1.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "emmet": "^2.4.3", + "jsonc-parser": "^2.3.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.15.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/remark-smartypants": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.0.0.tgz", - "integrity": "sha512-Rc0VDmr/yhnMQIz8n2ACYXlfw/P/XZev884QU1I5u+5DgJls32o97Vc1RbK3pfumLsJomS2yy8eT4Fxj/2MDVA==", - "dependencies": { - "retext": "^8.1.0", - "retext-smartypants": "^5.1.0", - "unist-util-visit": "^4.1.0" + "node_modules/@vscode/l10n": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", + "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=0.4.0" } }, - "node_modules/reselect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", - "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" + "node_modules/ajv-i18n": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ajv-i18n/-/ajv-i18n-4.2.0.tgz", + "integrity": "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.0-beta.0" } }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/algoliasearch": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.55.1.tgz", + "integrity": "sha512-FyaFnnsbVPtevQwqSj/SdxE3jAsSsY0BEH8IVLf9rXxEBdAhAmT6VKCVSMWoaPIHVN1Eufh/1w8q6k8URpIkWw==", + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" - }, + "@algolia/abtesting": "1.21.1", + "@algolia/client-abtesting": "5.55.1", + "@algolia/client-analytics": "5.55.1", + "@algolia/client-common": "5.55.1", + "@algolia/client-insights": "5.55.1", + "@algolia/client-personalization": "5.55.1", + "@algolia/client-query-suggestions": "5.55.1", + "@algolia/client-search": "5.55.1", + "@algolia/ingestion": "1.55.1", + "@algolia/monitoring": "1.55.1", + "@algolia/recommend": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-common": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.55.1.tgz", + "integrity": "sha512-P5ak7EurwYqgAiDyb95mgA3WRR/Zu8CPMv36lWTISvL2AmlPyqQPy2nX/KEJRTcwaeTWwrk6wJV4/M93GfjOWw==", + "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14.0.0" } }, - "node_modules/retext": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz", - "integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==", + "node_modules/algoliasearch/node_modules/@algolia/client-search": { + "version": "5.55.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.55.1.tgz", + "integrity": "sha512-GAqHl9zERhC3bbBfubwUu07G3UXO06gORvOcsiTBZB3et0s3auNUbHlYdYNp4VKa3sUZqH5AcD3OKzU/KDGXjQ==", + "license": "MIT", "dependencies": { - "@types/nlcst": "^1.0.0", - "retext-latin": "^3.0.0", - "retext-stringify": "^3.0.0", - "unified": "^10.0.0" + "@algolia/client-common": "5.55.1", + "@algolia/requester-browser-xhr": "5.55.1", + "@algolia/requester-fetch": "5.55.1", + "@algolia/requester-node-http": "5.55.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/retext-latin": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-3.1.0.tgz", - "integrity": "sha512-5MrD1tuebzO8ppsja5eEu+ZbBeUNCjoEarn70tkXOS7Bdsdf6tNahsv2bY0Z8VooFF6cw7/6S+d3yI/TMlMVVQ==", + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", "dependencies": { - "@types/nlcst": "^1.0.0", - "parse-latin": "^5.0.0", - "unherit": "^3.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "string-width": "^4.1.0" } }, - "node_modules/retext-smartypants": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-5.2.0.tgz", - "integrity": "sha512-Do8oM+SsjrbzT2UNIKgheP0hgUQTDDQYyZaIY3kfq0pdFzoPk+ZClYJ+OERNXveog4xf1pZL4PfRxNoVL7a/jw==", - "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/retext-smartypants/node_modules/nlcst-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.0.tgz", - "integrity": "sha512-Y8HQWKw/zrHTCnu2zcFBN1dV6vN0NUG7s5fkEj380G8tF3R+vA2KG+tDl2QoHVQCTHGHVXwoni2RQkDSFQb1PA==", + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { - "@types/nlcst": "^1.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/retext-stringify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-3.1.0.tgz", - "integrity": "sha512-767TLOaoXFXyOnjx/EggXlb37ZD2u4P1n0GJqVdpipqACsQP+20W+BNpMYrlJkq7hxffnFk+jc6mAK9qrbuB8w==", + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0" + "ansi-regex": "^5.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/retext-stringify/node_modules/nlcst-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.0.tgz", - "integrity": "sha512-Y8HQWKw/zrHTCnu2zcFBN1dV6vN0NUG7s5fkEj380G8tF3R+vA2KG+tDl2QoHVQCTHGHVXwoni2RQkDSFQb1PA==", - "dependencies": { - "@types/nlcst": "^1.0.0" + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=8.0" + "node": ">= 8" } }, - "node_modules/roarr/node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "bin": { - "rollup": "dist/bin/rollup" - }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=8.6" }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/s.color": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", - "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==" - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dependencies": { - "mri": "^1.1.0" - }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/sass-formatter": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.5.tgz", - "integrity": "sha512-NKFP8ddjhUYi6A/iD1cEtzkEs91U61kzqe3lY9SVNuvX7LGc88xnEN0mmsWL7Ol//YTi2GL/ol7b9XZ2+hgXuA==", - "dependencies": { - "suf-log": "^2.5.3" + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" } }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "node_modules/astro": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.18.2.tgz", + "integrity": "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ==", + "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" + "@astrojs/compiler": "^2.13.0", + "@astrojs/internal-helpers": "0.7.6", + "@astrojs/markdown-remark": "6.3.11", + "@astrojs/telemetry": "3.3.0", + "@capsizecss/unpack": "^4.0.0", + "@oslojs/encoding": "^1.1.0", + "@rollup/pluginutils": "^5.3.0", + "acorn": "^8.15.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "boxen": "8.0.1", + "ci-info": "^4.3.1", + "clsx": "^2.1.1", + "common-ancestor-path": "^1.0.1", + "cookie": "^1.1.1", + "cssesc": "^3.0.0", + "debug": "^4.4.3", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.6.2", + "diff": "^8.0.3", + "dlv": "^1.1.3", + "dset": "^3.1.4", + "es-module-lexer": "^1.7.0", + "esbuild": "^0.27.3", + "estree-walker": "^3.0.3", + "flattie": "^1.1.1", + "fontace": "~0.4.0", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "import-meta-resolve": "^4.2.0", + "js-yaml": "^4.1.1", + "magic-string": "^0.30.21", + "magicast": "^0.5.1", + "mrmime": "^2.0.1", + "neotraverse": "^0.6.18", + "p-limit": "^6.2.0", + "p-queue": "^8.1.1", + "package-manager-detector": "^1.6.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.3", + "prompts": "^2.4.2", + "rehype": "^13.0.2", + "semver": "^7.7.3", + "shiki": "^3.21.0", + "smol-toml": "^1.6.0", + "svgo": "^4.0.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tsconfck": "^3.1.6", + "ultrahtml": "^1.6.0", + "unifont": "~0.7.3", + "unist-util-visit": "^5.0.0", + "unstorage": "^1.17.4", + "vfile": "^6.0.3", + "vite": "^6.4.1", + "vitefu": "^1.1.1", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^21.1.1", + "yocto-spinner": "^0.2.3", + "zod": "^3.25.76", + "zod-to-json-schema": "^3.25.1", + "zod-to-ts": "^1.2.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "bin": { - "semver": "bin/semver.js" + "astro": "astro.js" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.34.0" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "node_modules/astro/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", "dependencies": { - "type-fest": "^0.13.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "node_modules/astro/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "20 || >=22" } }, - "node_modules/sharp": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.2.tgz", - "integrity": "sha512-DUdNVEXgS5A97cTagSLIIp8dUZ/lZtk78iNVZgHdHbx1qnQR7JAHY0BnXnwwH39Iw+VKhO08CTYhIg0p98vQ5Q==", - "hasInstallScript": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", - "prebuild-install": "^7.1.1", - "semver": "^7.3.8", - "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", - "tunnel-agent": "^0.6.0" - }, + "node_modules/astro/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">= 20.19.0" }, "funding": { - "url": "https://opencollective.com/libvips" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/sharp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "node_modules/astro/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -6093,6485 +3213,5363 @@ "node": ">=10" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/astro/node_modules/unstorage": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/shiki": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", - "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "^6.0.0" + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/shiki/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.42", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz", + "integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/boxen": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", + "cli-boxes": "^3.0.0", + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "node_modules/browserslist": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.5.tgz", + "integrity": "sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "github", + "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sirv": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", - "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" + "baseline-browser-mapping": "^2.10.42", + "caniuse-lite": "^1.0.30001800", + "electron-to-chromium": "^1.5.387", + "node-releases": "^2.0.50", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">= 10" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "node_modules/space-separated-tokens": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", - "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/caniuse-lite": { + "version": "1.0.30001803", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001803.tgz", + "integrity": "sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" }, { - "type": "consulting", - "url": "https://feross.org/support" + "type": "github", + "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stringify-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", - "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "readdirp": "^4.0.1" }, "engines": { - "node": ">=12" + "node": ">= 14.16.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { + "node_modules/cli-boxes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", - "dependencies": { - "inline-style-parser": "0.1.1" - } - }, - "node_modules/suf-log": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", - "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", - "dependencies": { - "s.color": "0.0.15" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", "dependencies": { - "has-flag": "^3.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/supports-esm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-esm/-/supports-esm-1.0.0.tgz", - "integrity": "sha512-96Am8CDqUaC0I2+C/swJ0yEvM8ZnGn4unoers/LSdE4umhX7mELzqyLzx3HnZAluq5PXIsGMKqa7NkqaeHMPcg==", - "dependencies": { - "has-package-exports": "^1.1.0" + "node": ">=12" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", - "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.4.0" + "color-convert": "^2.0.1" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">=8" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/tar-stream/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "node": ">=8" } }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/totalist": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", - "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { + "node_modules/collapse-white-space": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/tsconfig-resolver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tsconfig-resolver/-/tsconfig-resolver-3.0.1.tgz", - "integrity": "sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/json5": "^0.0.30", - "@types/resolve": "^1.17.0", - "json5": "^2.1.3", - "resolve": "^1.17.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.13.1" + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/sponsors/ifiokjr" - } - }, - "node_modules/tsconfig-resolver/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=7.0.0" } }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/tsm": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.2.2.tgz", - "integrity": "sha512-bXkt675NbbqfwRHSSn8kSNEEHvoIUFDM9G6tUENkjEKpAEbrEzieO3PxUiRJylMw8fEGpcf5lSjadzzz12pc2A==", - "dependencies": { - "esbuild": "^0.14.0" - }, - "bin": { - "tsm": "bin.js" - }, - "engines": { - "node": ">=12" + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", "engines": { - "node": "*" + "node": ">=16" } }, - "node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "node_modules/common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "license": "ISC" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", "engines": { - "node": ">=12.20" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/unherit": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.0.tgz", - "integrity": "sha512-UmvIQZGEc9qdLIQ8mv8/61n6PiMgfbOoASPKHpCvII5srShCQSa6jSjBjlZOR4bxt2XnT6uo6csmPKRi+zQ0Jg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", + "license": "MIT" }, - "node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "uncrypto": "^0.1.3" } }, - "node_modules/unist-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", - "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", "dependencies": { - "@types/unist": "^2.0.0" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-generated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", - "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/unist-util-is": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", - "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/unist-util-map": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/unist-util-map/-/unist-util-map-3.1.2.tgz", - "integrity": "sha512-WLA2R6x/UaopedG2poaWLShf5LCi+BNa6mMkACdjft23PHou4v85PvZItjbO2XgXvukMP365PlL/DrbuMgr3eg==", - "dependencies": { - "@types/unist": "^2.0.0" + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/unist-util-modify-children": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-2.0.0.tgz", - "integrity": "sha512-HGrj7JQo9DwZt8XFsX8UD4gGqOsIlCih9opG6Y+N11XqkBGKzHo8cvDi+MfQQgiZ7zXRUiQREYHhjOBHERTMdg==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", "dependencies": { - "array-iterate": "^1.0.0" + "css-tree": "~2.2.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, - "node_modules/unist-util-position": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", - "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, - "node_modules/unist-util-position-from-estree": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz", - "integrity": "sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw==", + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" + "ms": "^2.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/unist-util-remove-position": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz", - "integrity": "sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==", + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" + "character-entities": "^2.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/unist-util-stringify-position": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", - "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/deterministic-object-hash": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", + "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0" + "base-64": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=18" } }, - "node_modules/unist-util-visit": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", - "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "node_modules/devalue": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", + "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" + "dequal": "^2.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/unist-util-visit-children": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-1.1.4.tgz", - "integrity": "sha512-sA/nXwYRCQVRwZU2/tQWUqJ9JSFM1X3x7JIOsIgSzrFHcfVt6NkzDtKzyxg2cZWkCwGF9CO8x4QNZRJRMK8FeQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" } }, - "node_modules/unist-util-visit-parents": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", - "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "type": "github", + "url": "https://github.com/sponsors/fb55" } ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "domelementtype": "^2.3.0" }, - "bin": { - "browserslist-lint": "cli.js" + "engines": { + "node": ">= 4" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", "dependencies": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - }, - "bin": { - "uvu": "bin.js" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/vfile": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", - "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "node_modules/electron-to-chromium": { + "version": "1.5.388", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.388.tgz", + "integrity": "sha512-Pl/aJaqOOxYxda3vcx1IKSJimwYXHDkEnGn0F+kG2EE68dDtx2uCinaS+Vih8Z91B9t8CSAbiF/HKyWcnXjhzw==", + "license": "ISC" + }, + "node_modules/emmet": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.4.11.tgz", + "integrity": "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "./packages/scanner", + "./packages/abbreviation", + "./packages/css-abbreviation", + "./" + ], "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "@emmetio/abbreviation": "^2.3.3", + "@emmetio/css-abbreviation": "^2.1.8" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/vfile-location": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.0.1.tgz", - "integrity": "sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "vfile": "^5.0.0" + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-message": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", - "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/vite": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", - "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/vite/node_modules/esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" } }, - "node_modules/vite/node_modules/esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vite/node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" } }, - "node_modules/vite/node_modules/esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", + "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/vite/node_modules/esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/vite/node_modules/esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.2" + } + }, + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", + "license": "MIT", + "dependencies": { + "tiny-inflate": "^1.0.3" + }, "engines": { - "node": ">=12" + "node": ">=20" } }, - "node_modules/vite/node_modules/esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "cpu": [ - "riscv64" - ], + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vite/node_modules/esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/vite/node_modules/esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=12" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/vite/node_modules/esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" + }, + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vitefu": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.3.tgz", - "integrity": "sha512-75l7TTuU8isAhz1QFtNKjDkqjxvndfMC1AfIMjJ0ZQ59ZD0Ow9QOIsJJX16Wv9PS8f+zMzp6fHy5cCbKG/yVUQ==", - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-css-languageservice": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.2.1.tgz", - "integrity": "sha512-FMaMjB2LQdkHjTCP2CWh2S94xuGsxSc8xr0H9nAACVd/iUDyZLoKFjwoB+mA3v0rpCH2U5vVCVwxyULy61CgqA==", + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", "dependencies": { - "@vscode/l10n": "^0.0.10", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-uri": "^3.0.6" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-html-languageservice": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.0.3.tgz", - "integrity": "sha512-6rfrtcHhXDMXmC5pR2WXrx02HiNCzQDynOBMn+53zLxr2hvZrDzoc0QgC0FaFGfcglf7GeOsfhkWvJBFC/a70g==", + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", "dependencies": { - "@vscode/l10n": "^0.0.10", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-uri": "^3.0.6" + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-jsonrpc": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", - "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", - "engines": { - "node": ">=14.0.0" + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-languageserver": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz", - "integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==", + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", "dependencies": { - "vscode-languageserver-protocol": "3.17.2" + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", - "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==", + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { - "vscode-jsonrpc": "8.0.2", - "vscode-languageserver-types": "3.17.2" + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" }, - "node_modules/vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==" + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==" + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" }, - "node_modules/vscode-textmate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", - "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==" + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/vscode-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", - "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dependencies": { - "defaults": "^1.0.3" + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" } }, - "node_modules/web-namespaces": { + "node_modules/is-alphabetical": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/which-pm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", - "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", - "dependencies": { - "load-yaml-file": "^0.2.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8.15" + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/which-pm/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", "dependencies": { - "string-width": "^5.0.1" + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" }, "engines": { - "node": ">=12" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", - "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yallist": { + "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, "engines": { - "node": ">=12" + "node": ">=6" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "engines": { - "node": ">=10" + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6" } }, - "node_modules/zod": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", - "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "node_modules/jsonc-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", + "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==", + "dev": true, + "license": "MIT" + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/zwitch": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", - "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==", + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } - } - }, - "dependencies": { - "@algolia/autocomplete-core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.1.tgz", - "integrity": "sha512-eiZw+fxMzNQn01S8dA/hcCpoWCOCwcIIEUtHHdzN5TGB3IpzLbuhqFeTfh2OUhhgkE8Uo17+wH+QJ/wYyQmmzg==", - "requires": { - "@algolia/autocomplete-shared": "1.7.1" - } - }, - "@algolia/autocomplete-preset-algolia": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.1.tgz", - "integrity": "sha512-pJwmIxeJCymU1M6cGujnaIYcY3QPOVYZOXhFkWVM7IxKzy272BwCvMFMyc5NpG/QmiObBxjo7myd060OeTNJXg==", - "requires": { - "@algolia/autocomplete-shared": "1.7.1" - } - }, - "@algolia/autocomplete-shared": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.1.tgz", - "integrity": "sha512-eTmGVqY3GeyBTT8IWiB2K5EuURAqhnumfktAEoHxfDY2o7vg2rSnO16ZtIG0fMgt3py28Vwgq42/bVEuaQV7pg==" - }, - "@algolia/cache-browser-local-storage": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz", - "integrity": "sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==", - "requires": { - "@algolia/cache-common": "4.14.2" - } - }, - "@algolia/cache-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.2.tgz", - "integrity": "sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==" - }, - "@algolia/cache-in-memory": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz", - "integrity": "sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==", - "requires": { - "@algolia/cache-common": "4.14.2" - } - }, - "@algolia/client-account": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.2.tgz", - "integrity": "sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==", - "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "@algolia/client-analytics": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.2.tgz", - "integrity": "sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==", - "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "@algolia/client-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.2.tgz", - "integrity": "sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==", - "requires": { - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "@algolia/client-personalization": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.2.tgz", - "integrity": "sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==", - "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "@algolia/client-search": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz", - "integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==", - "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "@algolia/logger-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.2.tgz", - "integrity": "sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==" - }, - "@algolia/logger-console": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.2.tgz", - "integrity": "sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==", - "requires": { - "@algolia/logger-common": "4.14.2" - } - }, - "@algolia/requester-browser-xhr": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz", - "integrity": "sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==", - "requires": { - "@algolia/requester-common": "4.14.2" - } - }, - "@algolia/requester-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.2.tgz", - "integrity": "sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==" - }, - "@algolia/requester-node-http": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz", - "integrity": "sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==", - "requires": { - "@algolia/requester-common": "4.14.2" - } - }, - "@algolia/transporter": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.2.tgz", - "integrity": "sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==", - "requires": { - "@algolia/cache-common": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/requester-common": "4.14.2" - } - }, - "@altano/tiny-async-pool": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@altano/tiny-async-pool/-/tiny-async-pool-1.0.2.tgz", - "integrity": "sha512-qQzaI0TBUPdpjZ3qo5b2ziQY9MSNpbziH2ZrE5lvtUZL+kn9GwVuVJwoOubaoNkeDB+rqEefnpu1k+oMpOCYiw==" - }, - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@astrojs/compiler": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-0.30.1.tgz", - "integrity": "sha512-sH3hvGA9JR5eE2bHG3sr5QjaJl5ER9EmmZzSwBHkMPoBj0XU7XzQjSGoyCbIML6sSaelJEPnfsr9NsypvKOecg==" - }, - "@astrojs/image": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@astrojs/image/-/image-0.12.1.tgz", - "integrity": "sha512-7pBUPCw7/FPwfEntx+mGjhdwpaWXNHwRVcTK71rpf+c2yb8iIesRS9r26U7lGozTzXUROh1y1ftA82ziuqYF6Q==", - "requires": { - "@altano/tiny-async-pool": "^1.0.2", - "http-cache-semantics": "^4.1.0", - "image-size": "^1.0.2", - "kleur": "^4.1.5", - "magic-string": "^0.25.9", - "mime": "^3.0.0", - "slash": "^4.0.0", - "web-streams-polyfill": "^3.2.1" - } - }, - "@astrojs/language-server": { - "version": "0.28.3", - "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-0.28.3.tgz", - "integrity": "sha512-fPovAX/X46eE2w03jNRMpQ7W9m2mAvNt4Ay65lD9wl1Z5vIQYxlg7Enp9qP225muTr4jSVB5QiLumFJmZMAaVA==", - "requires": { - "@vscode/emmet-helper": "^2.8.4", - "events": "^3.3.0", - "prettier": "^2.7.1", - "prettier-plugin-astro": "^0.7.0", - "source-map": "^0.7.3", - "vscode-css-languageservice": "^6.0.1", - "vscode-html-languageservice": "^5.0.0", - "vscode-languageserver": "^8.0.1", - "vscode-languageserver-protocol": "^3.17.1", - "vscode-languageserver-textdocument": "^1.0.4", - "vscode-languageserver-types": "^3.17.1", - "vscode-uri": "^3.0.3" - } - }, - "@astrojs/markdown-remark": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-1.1.3.tgz", - "integrity": "sha512-6MDuQXbrp2fZBYBIqD+0jvSqYAukiMTte6oLNHiEYsLf3KIMlVAZj6dDgUJakgL7cQ4fmzWb0HUqzVpxAsasLw==", - "requires": { - "@astrojs/micromark-extension-mdx-jsx": "^1.0.3", - "@astrojs/prism": "^1.0.0", - "acorn": "^8.7.1", - "acorn-jsx": "^5.3.2", - "github-slugger": "^1.4.0", - "hast-util-to-html": "^8.0.3", - "import-meta-resolve": "^2.1.0", - "mdast-util-from-markdown": "^1.2.0", - "mdast-util-mdx-expression": "^1.2.1", - "mdast-util-mdx-jsx": "^1.2.0", - "micromark-extension-mdx-expression": "^1.0.3", - "micromark-extension-mdx-md": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "rehype-raw": "^6.1.1", - "rehype-stringify": "^9.0.3", - "remark-gfm": "^3.0.1", - "remark-parse": "^10.0.1", - "remark-rehype": "^10.1.0", - "remark-smartypants": "^2.0.0", - "shiki": "^0.11.1", - "unified": "^10.1.2", - "unist-util-map": "^3.1.1", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2" - } - }, - "@astrojs/mdx": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-0.12.1.tgz", - "integrity": "sha512-d41ariAR7VMHb+4ALiXPbYXMPSqjpGqTAZBSp40sRam084r/4Vwr6F1mwRKWFDwbwgN6iLN+fczSQDvqoOD2JQ==", - "requires": { - "@astrojs/prism": "^1.0.2", - "@mdx-js/mdx": "^2.1.2", - "@mdx-js/rollup": "^2.1.1", - "acorn": "^8.8.0", - "es-module-lexer": "^0.10.5", - "estree-util-visit": "^1.2.0", - "github-slugger": "^1.4.0", - "gray-matter": "^4.0.3", - "kleur": "^4.1.4", - "rehype-raw": "^6.1.1", - "remark-frontmatter": "^4.0.1", - "remark-gfm": "^3.0.1", - "remark-smartypants": "^2.0.0", - "shiki": "^0.11.1", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2" - } - }, - "@astrojs/micromark-extension-mdx-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@astrojs/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", - "integrity": "sha512-O15+i2DGG0qb1R/1SYbFXgOKDGbYdV8iJMtuboVb1S9YFQfMOJxaCMco0bhXQI7PmZcQ4pZWIjT5oZ64dXUtRA==", - "requires": { - "@types/acorn": "^4.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "@astrojs/preact": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@astrojs/preact/-/preact-1.1.0.tgz", - "integrity": "sha512-beUw4Y6dNJ7394Kqoz3kVNfhALLExjllXGB4+GtORmprZLs8hBqnGk4mOlNr/9iuZZumN5YCQmafkC5vkyCtZw==", - "requires": { - "@babel/core": ">=7.0.0-0 <8.0.0", - "@babel/plugin-transform-react-jsx": "^7.17.12", - "babel-plugin-module-resolver": "^4.1.0", - "preact-render-to-string": "^5.2.0" - } - }, - "@astrojs/prism": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-1.0.2.tgz", - "integrity": "sha512-o3cUVoAuALDqdN5puNlsN2eO4Yi1kDh68YO8V7o6U4Ts+J/mMayzlJ7JsgYAmob0xrf/XnADVgu8khfMv/w3uA==", - "requires": { - "prismjs": "^1.28.0" - } - }, - "@astrojs/react": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-1.2.2.tgz", - "integrity": "sha512-ab9fYvzkC74J7N+M3DWQuZgwu7sYjW0aLO3sEAdCX/jZZz+0BhrqS8m9QjtGJyQK/niF4tgJjpPfadopxKc56g==", - "requires": { - "@babel/core": ">=7.0.0-0 <8.0.0", - "@babel/plugin-transform-react-jsx": "^7.17.12" - } - }, - "@astrojs/telemetry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-1.0.1.tgz", - "integrity": "sha512-SJVfZHp00f8VZsT1fsx1+6acJGUNt/84xZytV5znPzzNE8RXjlE0rv03llgTsEeUHYZc6uJah91jNojS7RldFg==", - "requires": { - "ci-info": "^3.3.1", - "debug": "^4.3.4", - "dlv": "^1.1.3", - "dset": "^3.1.2", - "is-docker": "^3.0.0", - "is-wsl": "^2.2.0", - "node-fetch": "^3.2.5", - "which-pm-runs": "^1.1.0" - } - }, - "@astrojs/webapi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@astrojs/webapi/-/webapi-1.1.1.tgz", - "integrity": "sha512-yeUvP27PoiBK/WCxyQzC4HLYZo4Hg6dzRd/dTsL50WGlAQVCwWcqzVJrIZKvzNDNaW/fIXutZTmdj6nec0PIGg==", - "requires": { - "global-agent": "^3.0.0", - "node-fetch": "^3.2.5" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.1.tgz", - "integrity": "sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==" - }, - "@babel/core": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.1.tgz", - "integrity": "sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==", - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-compilation-targets": "^7.19.1", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "requires": { - "@babel/types": "^7.19.0", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz", - "integrity": "sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==", - "requires": { - "@babel/compat-data": "^7.19.1", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" - }, - "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.1.tgz", - "integrity": "sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==" - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", - "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.19.0" - } - }, - "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" - } - }, - "@babel/traverse": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.1.tgz", - "integrity": "sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.1", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - } - }, - "@docsearch/css": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.2.1.tgz", - "integrity": "sha512-gaP6TxxwQC+K8D6TRx5WULUWKrcbzECOPA2KCVMuI+6C7dNiGUk5yXXzVhc5sld79XKYLnO9DRTI4mjXDYkh+g==" - }, - "@docsearch/react": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.2.1.tgz", - "integrity": "sha512-EzTQ/y82s14IQC5XVestiK/kFFMe2aagoYFuTAIfIb/e+4FU7kSMKonRtLwsCiLQHmjvNQq+HO+33giJ5YVtaQ==", - "requires": { - "@algolia/autocomplete-core": "1.7.1", - "@algolia/autocomplete-preset-algolia": "1.7.1", - "@docsearch/css": "3.2.1", - "algoliasearch": "^4.0.0" - } - }, - "@emmetio/abbreviation": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.2.3.tgz", - "integrity": "sha512-87pltuCPt99aL+y9xS6GPZ+Wmmyhll2WXH73gG/xpGcQ84DRnptBsI2r0BeIQ0EB/SQTOe2ANPqFqj3Rj5FOGA==", - "requires": { - "@emmetio/scanner": "^1.0.0" + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" } }, - "@emmetio/css-abbreviation": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-2.1.4.tgz", - "integrity": "sha512-qk9L60Y+uRtM5CPbB0y+QNl/1XKE09mSO+AhhSauIfr2YOx/ta3NJw2d8RtCFxgzHeRqFRr8jgyzThbu+MZ4Uw==", - "requires": { - "@emmetio/scanner": "^1.0.0" + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "@emmetio/scanner": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emmetio/scanner/-/scanner-1.0.0.tgz", - "integrity": "sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==" - }, - "@esbuild/android-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", - "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", - "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", - "optional": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" } }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@ljharb/has-package-exports-patterns": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@ljharb/has-package-exports-patterns/-/has-package-exports-patterns-0.0.2.tgz", - "integrity": "sha512-4/RWEeXDO6bocPONheFe6gX/oQdP/bEpv0oL4HqjPP5DCenBSt0mHgahppY49N0CpsaqffdwPq+TlX9CYOq2Dw==" - }, - "@mdx-js/mdx": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-2.1.5.tgz", - "integrity": "sha512-zEG0lt+Bl/r5U6e0TOS7qDbsXICtemfAPquxWFsMbdzrvlWaqMGemLl+sjVpqlyaaiCiGVQBSGdCk0t1qXjkQg==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/mdx": "^2.0.0", - "estree-util-build-jsx": "^2.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "estree-util-to-js": "^1.1.0", - "estree-walker": "^3.0.0", - "hast-util-to-estree": "^2.0.0", - "markdown-extensions": "^1.0.0", - "periscopic": "^3.0.0", - "remark-mdx": "^2.0.0", - "remark-parse": "^10.0.0", - "remark-rehype": "^10.0.0", - "unified": "^10.0.0", - "unist-util-position-from-estree": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0" - } - }, - "@mdx-js/rollup": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-2.1.5.tgz", - "integrity": "sha512-l90rSiwnEf6PnjH8uRXjZ1W0rR8p1fp1YIiDuA3uF7SOfxMQ98uymaIwI6BsX+8BC2dcWij7Racwp++JkvdOLQ==", - "requires": { - "@mdx-js/mdx": "^2.0.0", - "@rollup/pluginutils": "^4.0.0", - "source-map": "^0.7.0", - "vfile": "^5.0.0" + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@pagefind/darwin-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", - "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", - "dev": true, - "optional": true - }, - "@pagefind/darwin-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", - "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", - "dev": true, - "optional": true - }, - "@pagefind/freebsd-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", - "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", - "dev": true, - "optional": true - }, - "@pagefind/linux-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", - "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", - "dev": true, - "optional": true - }, - "@pagefind/linux-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", - "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", - "dev": true, - "optional": true - }, - "@pagefind/windows-arm64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", - "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", - "dev": true, - "optional": true - }, - "@pagefind/windows-x64": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", - "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", - "dev": true, - "optional": true - }, - "@pkgr/utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", - "requires": { - "cross-spawn": "^7.0.3", - "is-glob": "^4.0.3", - "open": "^8.4.0", - "picocolors": "^1.0.0", - "tiny-glob": "^0.2.9", - "tslib": "^2.4.0" + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" - }, - "@proload/core": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz", - "integrity": "sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==", - "requires": { - "deepmerge": "^4.2.2", - "escalade": "^3.1.1" + "node_modules/mdast-util-definitions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", + "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@proload/plugin-tsm": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@proload/plugin-tsm/-/plugin-tsm-0.2.1.tgz", - "integrity": "sha512-Ex1sL2BxU+g8MHdAdq9SZKz+pU34o8Zcl9PHWo2WaG9hrnlZme607PU6gnpoAYsDBpHX327+eu60wWUk+d/b+A==", - "requires": { - "tsm": "^2.1.4" + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@rollup/pluginutils": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", - "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", - "requires": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", "dependencies": { - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" - } - } - }, - "@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "requires": { - "@types/estree": "*" - } - }, - "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "requires": { - "@babel/types": "^7.0.0" + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", - "requires": { - "@babel/types": "^7.3.0" + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", - "requires": { - "@types/ms": "*" + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" - }, - "@types/estree-jsx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.0.tgz", - "integrity": "sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==", - "requires": { - "@types/estree": "*" + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", - "requires": { - "@types/unist": "*" + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/html-escaper": { + "node_modules/mdast-util-mdx": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/html-escaper/-/html-escaper-3.0.0.tgz", - "integrity": "sha512-OcJcvP3Yk8mjYwf/IdXZtTE1tb/u0WF0qa29ER07ZHCYUBZXSN29Z1mBS+/96+kNMGTFUAbSz9X+pHmHpZrTCw==" - }, - "@types/json5": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz", - "integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA==" - }, - "@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", - "requires": { - "@types/unist": "*" + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" - }, - "@types/mdx": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.3.tgz", - "integrity": "sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==" - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" - }, - "@types/nlcst": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.0.tgz", - "integrity": "sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==", - "requires": { - "@types/unist": "*" + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@types/node": { - "version": "18.7.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" - }, - "@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" - }, - "@types/prismjs": { - "version": "1.26.6", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", - "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/react": { - "version": "17.0.50", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", - "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", - "requires": { - "@types/react": "*" - } - }, - "@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==" - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" - }, - "@vscode/emmet-helper": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/@vscode/emmet-helper/-/emmet-helper-2.8.4.tgz", - "integrity": "sha512-lUki5QLS47bz/U8IlG9VQ+1lfxMtxMZENmU5nu4Z71eOD5j9FK0SmYGL5NiVJg9WBWeAU0VxRADMY2Qpq7BfVg==", - "requires": { - "emmet": "^2.3.0", - "jsonc-parser": "^2.3.0", - "vscode-languageserver-textdocument": "^1.0.1", - "vscode-languageserver-types": "^3.15.1", - "vscode-nls": "^5.0.0", - "vscode-uri": "^2.1.2" - }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", "dependencies": { - "vscode-uri": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-2.1.2.tgz", - "integrity": "sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==" - } + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "@vscode/l10n": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.10.tgz", - "integrity": "sha512-E1OCmDcDWa0Ya7vtSjp/XfHFGqYJfh+YPC1RkATU71fTac+j1JjCcB3qwSzmlKAighx2WxhLlfhS0RwAN++PFQ==" - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": {} - }, - "algoliasearch": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz", - "integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==", - "requires": { - "@algolia/cache-browser-local-storage": "4.14.2", - "@algolia/cache-common": "4.14.2", - "@algolia/cache-in-memory": "4.14.2", - "@algolia/client-account": "4.14.2", - "@algolia/client-analytics": "4.14.2", - "@algolia/client-common": "4.14.2", - "@algolia/client-personalization": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/logger-console": "4.14.2", - "@algolia/requester-browser-xhr": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/requester-node-http": "4.14.2", - "@algolia/transporter": "4.14.2" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "requires": { - "string-width": "^4.1.0" - }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - } + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "array-iterate": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-1.1.4.tgz", - "integrity": "sha512-sNRaPGh9nnmdC8Zf+pT3UqP8rnWj5Hf9wiFGsX3wUQ2yVSIhO2ShFwCoceIPpB41QF6i2OEmrHmCo36xronCVA==" - }, - "ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", - "requires": { - "tslib": "^2.0.1" - } - }, - "astring": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.3.tgz", - "integrity": "sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A==" - }, - "astro": { - "version": "1.6.14", - "resolved": "https://registry.npmjs.org/astro/-/astro-1.6.14.tgz", - "integrity": "sha512-8ljrWPKEU5Hrrbupan48ba4gLWPY14Aqiv4u0U92wSl3wtsqPJUWWlHGGkXcgS/9dx8aiLkUm4RzCPFVnP7V2w==", - "requires": { - "@astrojs/compiler": "^0.30.0", - "@astrojs/language-server": "^0.28.3", - "@astrojs/markdown-remark": "^1.1.3", - "@astrojs/telemetry": "^1.0.1", - "@astrojs/webapi": "^1.1.1", - "@babel/core": "^7.18.2", - "@babel/generator": "^7.18.2", - "@babel/parser": "^7.18.4", - "@babel/plugin-transform-react-jsx": "^7.17.12", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.4", - "@proload/core": "^0.3.3", - "@proload/plugin-tsm": "^0.2.1", - "@types/babel__core": "^7.1.19", - "@types/html-escaper": "^3.0.0", - "@types/yargs-parser": "^21.0.0", - "boxen": "^6.2.1", - "ci-info": "^3.3.1", - "common-ancestor-path": "^1.0.1", - "cookie": "^0.5.0", - "debug": "^4.3.4", - "deepmerge-ts": "^4.2.2", - "diff": "^5.1.0", - "es-module-lexer": "^0.10.5", - "execa": "^6.1.0", - "fast-glob": "^3.2.11", - "github-slugger": "^1.4.0", - "gray-matter": "^4.0.3", - "html-entities": "^2.3.3", - "html-escaper": "^3.0.3", - "import-meta-resolve": "^2.1.0", - "kleur": "^4.1.4", - "magic-string": "^0.25.9", - "mime": "^3.0.0", - "ora": "^6.1.0", - "path-browserify": "^1.0.1", - "path-to-regexp": "^6.2.1", - "postcss": "^8.4.14", - "postcss-load-config": "^3.1.4", - "preferred-pm": "^3.0.3", - "prompts": "^2.4.2", - "recast": "^0.20.5", - "rehype": "^12.0.1", - "resolve": "^1.22.0", - "rollup": "^2.79.1", - "semver": "^7.3.7", - "shiki": "^0.11.1", - "sirv": "^2.0.2", - "slash": "^4.0.0", - "string-width": "^5.1.2", - "strip-ansi": "^7.0.1", - "supports-esm": "^1.0.0", - "tsconfig-resolver": "^3.0.1", - "typescript": "*", - "unist-util-visit": "^4.1.0", - "vfile": "^5.3.2", - "vite": "~3.2.5", - "vitefu": "^0.2.1", - "yargs-parser": "^21.0.1", - "zod": "^3.17.3" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "requires": { - "lru-cache": "^6.0.0" - } - } + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", - "requires": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", - "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" }, - "bl": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz", - "integrity": "sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==", - "requires": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" - }, - "boxen": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", - "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^6.2.0", - "chalk": "^4.1.2", - "cli-boxes": "^3.0.0", - "string-width": "^5.0.1", - "type-fest": "^2.5.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" - }, - "caniuse-lite": { - "version": "1.0.30001400", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001400.tgz", - "integrity": "sha512-Mv659Hn65Z4LgZdJ7ge5JTVbE3rqbJaaXgW5LEI9/tOaXclfIZ8DW7D7FCWWWmWiiPS7AC48S8kf3DApSxQdgA==" - }, - "ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" - }, - "character-entities-html4": { + "node_modules/micromark-extension-gfm-task-list-item": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==" - }, - "character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" - }, - "character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "ci-info": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==" - }, - "cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==" - }, - "cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "requires": { - "restore-cursor": "^4.0.0" + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" - }, - "color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "requires": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "dependencies": { - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "comma-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", - "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==" - }, - "common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", - "requires": { - "character-entities": "^2.0.0" + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "deepmerge-ts": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-4.2.2.tgz", - "integrity": "sha512-Ka3Kb21tiWjvQvS9U+1Dx+aqFAHsdTnMdYptLTmC2VAmDFMugWMY1e15aTODstipmCun8iNuqeSfcx6rsUUk0Q==" - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "requires": { - "clone": "^1.0.2" + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" } }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - }, - "detect-libc": { + "node_modules/micromark-factory-title": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, - "dset": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", - "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==" - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, - "electron-to-chromium": { - "version": "1.4.251", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.251.tgz", - "integrity": "sha512-k4o4cFrWPv4SoJGGAydd07GmlRVzmeDIJ6MaEChTUjk4Dmomn189tCicSzil2oyvbPoGgg2suwPDNWq4gWRhoQ==" - }, - "emmet": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/emmet/-/emmet-2.3.6.tgz", - "integrity": "sha512-pLS4PBPDdxuUAmw7Me7+TcHbykTsBKN/S9XJbUOMFQrNv9MoshzyMFK/R57JBm94/6HSL4vHnDeEmxlC82NQ4A==", - "requires": { - "@emmetio/abbreviation": "^2.2.3", - "@emmetio/css-abbreviation": "^2.1.4" - } - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "es-module-lexer": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.10.5.tgz", - "integrity": "sha512-+7IwY/kiGAacQfY+YBhKMvEmyAJnw5grTUgjG85Pe7vcUI/6b7pZjZG8nQ7+48YhzEAEqrEgD2dCz/JIK+AYvw==" - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" - }, - "esbuild": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", - "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", - "requires": { - "@esbuild/linux-loong64": "0.14.54", - "esbuild-android-64": "0.14.54", - "esbuild-android-arm64": "0.14.54", - "esbuild-darwin-64": "0.14.54", - "esbuild-darwin-arm64": "0.14.54", - "esbuild-freebsd-64": "0.14.54", - "esbuild-freebsd-arm64": "0.14.54", - "esbuild-linux-32": "0.14.54", - "esbuild-linux-64": "0.14.54", - "esbuild-linux-arm": "0.14.54", - "esbuild-linux-arm64": "0.14.54", - "esbuild-linux-mips64le": "0.14.54", - "esbuild-linux-ppc64le": "0.14.54", - "esbuild-linux-riscv64": "0.14.54", - "esbuild-linux-s390x": "0.14.54", - "esbuild-netbsd-64": "0.14.54", - "esbuild-openbsd-64": "0.14.54", - "esbuild-sunos-64": "0.14.54", - "esbuild-windows-32": "0.14.54", - "esbuild-windows-64": "0.14.54", - "esbuild-windows-arm64": "0.14.54" - } - }, - "esbuild-android-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", - "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", - "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", - "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", - "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", - "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", - "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", - "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", - "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", - "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", - "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", - "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", - "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", - "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", - "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", - "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", - "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", - "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", - "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", - "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.54", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", - "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", - "optional": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "estree-util-attach-comments": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-2.1.0.tgz", - "integrity": "sha512-rJz6I4L0GaXYtHpoMScgDIwM0/Vwbu5shbMeER596rB2D1EWF6+Gj0e0UKzJPZrpoOc87+Q2kgVFHfjAymIqmw==", - "requires": { - "@types/estree": "^1.0.0" + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "estree-util-build-jsx": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-2.2.0.tgz", - "integrity": "sha512-apsfRxF9uLrqosApvHVtYZjISPvTJ+lBiIydpC+9wE6cF6ssbhnjyQLqaIjgzGxvC2Hbmec1M7g91PoBayYoQQ==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "estree-walker": "^3.0.0" + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "estree-util-is-identifier-name": { + "node_modules/micromark-util-classify-character": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.1.tgz", - "integrity": "sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==" + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "estree-util-to-js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-1.1.0.tgz", - "integrity": "sha512-490lbfCcpLk+ofK6HCgqDfYs4KAfq6QVvDw3+Bm1YoKRgiOjKiKYGAVQE1uwh7zVxBgWhqp4FDtp5SqunpUk1A==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "astring": "^1.8.0", - "source-map": "^0.7.0" + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "estree-util-visit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-1.2.0.tgz", - "integrity": "sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/unist": "^2.0.0" + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "estree-walker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.1.tgz", - "integrity": "sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g==" + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "execa": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", - "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^3.0.1", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - } - }, - "expand-template": { + "node_modules/micromark-util-events-to-acorn": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } }, - "extend-shallow": { + "node_modules/micromark-util-resolve-all": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "requires": { - "is-extendable": "^0.1.0" + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" } }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "requires": { - "reusify": "^1.0.4" + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "fault": { + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mrmime": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", - "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", - "requires": { - "format": "^0.2.0" + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" } }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" }, - "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", - "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==" + "node_modules/nanoid": { + "version": "3.3.15", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", + "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "find-yarn-workspace-root2": { - "version": "1.2.16", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", - "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", - "requires": { - "micromatch": "^4.0.2", - "pkg-dir": "^4.2.0" + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", + "engines": { + "node": ">= 10" } }, - "format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==" - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "node_modules/node-mock-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.4.tgz", + "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", + "license": "MIT" }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "node_modules/node-releases": { + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", + "license": "MIT", + "engines": { + "node": ">=18" } }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "github-slugger": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-agent": { + "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "requires": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - } + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "requires": { - "define-properties": "^1.1.3" + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==" - }, - "globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "requires": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" }, - "has-package-exports": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/has-package-exports/-/has-package-exports-1.3.0.tgz", - "integrity": "sha512-e9OeXPQnmPhYoJ63lXC4wWe34TxEGZDZ3OQX9XRqp2VwsfLl3bQBy7VehLnd34g3ef8CmYlBLGqEMKXuz8YazQ==", - "requires": { - "@ljharb/has-package-exports-patterns": "^0.0.2" + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" } }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" + "node_modules/p-limit": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "hast-to-hyperscript": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-10.0.1.tgz", - "integrity": "sha512-dhIVGoKCQVewFi+vz3Vt567E4ejMppS1haBRL6TEmeLeJVB1i/FJIIg/e6s1Bwn0g5qtYojHEKvyGA+OZuyifw==", - "requires": { - "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^5.0.0", - "web-namespaces": "^2.0.0" + "node_modules/p-queue": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", + "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "hast-util-from-parse5": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.0.tgz", - "integrity": "sha512-m8yhANIAccpU4K6+121KpPP55sSl9/samzQSQGpb0mTExcNh2WlvjtMwSWFhg6uqD4Rr6Nfa8N6TMypQM51rzQ==", - "requires": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "@types/unist": "^2.0.0", - "hastscript": "^7.0.0", - "property-information": "^6.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0", - "web-namespaces": "^2.0.0" + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "hast-util-is-element": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz", - "integrity": "sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA==", - "requires": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0" - } + "node_modules/package-manager-detector": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.7.0.tgz", + "integrity": "sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==", + "license": "MIT" }, - "hast-util-parse-selector": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.0.tgz", - "integrity": "sha512-AyjlI2pTAZEOeu7GeBPZhROx0RHBnydkQIXlhnFzDi0qfXTmGUWoCYZtomHbrdrheV4VFUlPcfJ6LMF5T6sQzg==", - "requires": { - "@types/hast": "^2.0.0" - } - }, - "hast-util-raw": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.2.tgz", - "integrity": "sha512-0x3BhhdlBcqRIKyc095lBSDvmQNMY3Eulj2PLsT5XCyKYrxssI5yr3P4Kv/PBo1s/DMkZy2voGkMXECnFCZRLQ==", - "requires": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "hast-util-from-parse5": "^7.0.0", - "hast-util-to-parse5": "^7.0.0", - "html-void-elements": "^2.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" + "node_modules/pagefind": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", + "dev": true, + "license": "MIT", + "bin": { + "pagefind": "lib/runner/bin.cjs" + }, + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.5.2", + "@pagefind/darwin-x64": "1.5.2", + "@pagefind/freebsd-x64": "1.5.2", + "@pagefind/linux-arm64": "1.5.2", + "@pagefind/linux-x64": "1.5.2", + "@pagefind/windows-arm64": "1.5.2", + "@pagefind/windows-x64": "1.5.2" } }, - "hast-util-to-estree": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.1.0.tgz", - "integrity": "sha512-Vwch1etMRmm89xGgz+voWXvVHba2iiMdGMKmaMfYt35rbVtFDq8JNwwAIvi8zHMkO6Gvqo9oTMwJTmzVRfXh4g==", - "requires": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { "@types/unist": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "estree-util-attach-comments": "^2.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "mdast-util-mdx-expression": "^1.0.0", - "mdast-util-mdxjs-esm": "^1.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.3.0", - "unist-util-position": "^4.0.0", - "zwitch": "^2.0.0" + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "hast-util-to-html": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz", - "integrity": "sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A==", - "requires": { - "@types/hast": "^2.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-is-element": "^2.0.0", - "hast-util-whitespace": "^2.0.0", - "html-void-elements": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.2", - "unist-util-is": "^5.0.0" - } + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" }, - "hast-util-to-parse5": { + "node_modules/parse-latin": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.0.0.tgz", - "integrity": "sha512-YHiS6aTaZ3N0Q3nxaY/Tj98D6kM8QX5Q8xqgg8G45zR7PvWnPGPP0vcKCgb/moIydEJ/QWczVrX0JODCVeoV7A==", - "requires": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "hast-to-hyperscript": "^10.0.0", - "property-information": "^6.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - } - }, - "hast-util-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", - "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==" - }, - "hastscript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.0.2.tgz", - "integrity": "sha512-uA8ooUY4ipaBvKcMuPehTAB/YfFLSSzCwFSwT6ltJbocFUKH/GDHLN+tflq7lSRf9H86uOuxOFkh1KgIy3Gg2g==", - "requires": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" - } - }, - "html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, - "html-escaper": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", - "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" - }, - "html-void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", - "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==" - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "human-signals": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", - "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "requires": { - "queue": "6.0.2" + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "import-meta-resolve": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.0.tgz", - "integrity": "sha512-CpPOtiCHxP9HdtDM5F45tNiAe66Cqlv3f5uHoJjt+KlaLrUh9/Wz9vepADZ78SlqEo62aDWZtj9ydMGXV+CPnw==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==" - }, - "is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "requires": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - } + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "requires": { - "has": "^1.0.3" + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==" - }, - "is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" + "node_modules/postcss": { + "version": "8.5.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", + "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==" - }, - "is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==" + "node_modules/prettier": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", + "integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } }, - "is-reference": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.0.tgz", - "integrity": "sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q==", - "requires": { - "@types/estree": "*" + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==" + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - } + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "jsonc-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.1.tgz", - "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==" + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" - }, - "lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==" - }, - "load-yaml-file": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", - "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", - "requires": { - "graceful-fs": "^4.1.5", - "js-yaml": "^3.13.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - } + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" } }, - "log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", - "requires": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" - }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", "dependencies": { - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==" - } + "regex-utilities": "^2.3.0" } }, - "longest-streak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz", - "integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==" + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" + "node_modules/rehype": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "rehype-parse": "^9.0.0", + "rehype-stringify": "^10.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" - }, - "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "requires": { - "sourcemap-codec": "^1.4.8" + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "markdown-extensions": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz", - "integrity": "sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==" - }, - "markdown-table": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.2.tgz", - "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==" + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "requires": { - "escape-string-regexp": "^4.0.0" + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - } + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-definitions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", - "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-find-and-replace": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.1.tgz", - "integrity": "sha512-SobxkQXFAdd4b5WmEakmkVoh18icjQRxGy5OWTCzgsLRm1Fu/KCtwD1HIQSsmq5ZRjVH0Ehwg6/Fn3xIUk+nKw==", - "requires": { - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.0.0" + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" - } + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-from-markdown": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", - "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - } - }, - "mdast-util-frontmatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-1.0.0.tgz", - "integrity": "sha512-7itKvp0arEVNpCktOET/eLFAYaZ+0cNjVtFtIPxgQ5tV+3i+D4SDDTjTzPWl44LT59PC+xdx+glNTawBdF98Mw==", - "requires": { - "micromark-extension-frontmatter": "^1.0.0" + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "mdast-util-gfm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.1.tgz", - "integrity": "sha512-42yHBbfWIFisaAfV1eixlabbsa6q7vHeSPY+cg+BBjX51M8xhgMacqH9g6TftB/9+YkcI0ooV4ncfrJslzm/RQ==", - "requires": { - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-gfm-autolink-literal": "^1.0.0", - "mdast-util-gfm-footnote": "^1.0.0", - "mdast-util-gfm-strikethrough": "^1.0.0", - "mdast-util-gfm-table": "^1.0.0", - "mdast-util-gfm-task-list-item": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-gfm-autolink-literal": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.2.tgz", - "integrity": "sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==", - "requires": { - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-find-and-replace": "^2.0.0", - "micromark-util-character": "^1.0.0" + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-gfm-footnote": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.1.tgz", - "integrity": "sha512-p+PrYlkw9DeCRkTVw1duWqPRHX6Ywh2BNKJQcZbCwAuP/59B0Lk9kakuAd7KbQprVO4GzdW8eS5++A9PUSqIyw==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0", - "micromark-util-normalize-identifier": "^1.0.0" + "node_modules/request-light": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.7.0.tgz", + "integrity": "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "mdast-util-gfm-strikethrough": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.1.tgz", - "integrity": "sha512-zKJbEPe+JP6EUv0mZ0tQUyLQOC+FADt0bARldONot/nefuISkaZFlmVK4tU6JgfyZGrky02m/I6PmehgAgZgqg==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" - } - }, - "mdast-util-gfm-table": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.6.tgz", - "integrity": "sha512-uHR+fqFq3IvB3Rd4+kzXW8dmpxUhvgCQZep6KdjsLK4O6meK5dYZEayLtIxNus1XO3gfjfcIFe8a7L0HZRGgag==", - "requires": { - "@types/mdast": "^3.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.3.0" + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "mdast-util-gfm-task-list-item": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.1.tgz", - "integrity": "sha512-KZ4KLmPdABXOsfnM6JHUIjxEvcx2ulk656Z/4Balw071/5qgnhz+H1uGtf2zIGnrnvDC8xR4Fj9uKbjAFGNIeA==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.3.0" + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-mdx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz", - "integrity": "sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==", - "requires": { - "mdast-util-mdx-expression": "^1.0.0", - "mdast-util-mdx-jsx": "^2.0.0", - "mdast-util-mdxjs-esm": "^1.0.0" - }, - "dependencies": { - "mdast-util-mdx-jsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.0.tgz", - "integrity": "sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "ccount": "^2.0.0", - "mdast-util-to-markdown": "^1.3.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^4.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - } - } + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-mdx-expression": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.0.tgz", - "integrity": "sha512-9kTO13HaL/ChfzVCIEfDRdp1m5hsvsm6+R8yr67mH+KS2ikzZ0ISGLPTbTswOFpLLlgVHO9id3cul4ajutCvCA==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-mdx-jsx": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-1.2.0.tgz", - "integrity": "sha512-5+ot/kfxYd3ChgEMwsMUO71oAfYjyRI3pADEK4I7xTmWLGQ8Y7ghm1CG36zUoUvDPxMlIYwQV/9DYHAUWdG4dA==", - "requires": { - "@types/estree-jsx": "^0.0.1", - "@types/mdast": "^3.0.0", - "mdast-util-to-markdown": "^1.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^4.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "dependencies": { - "@types/estree-jsx": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-0.0.1.tgz", - "integrity": "sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A==", - "requires": { - "@types/estree": "*" - } - } + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "mdast-util-mdxjs-esm": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.0.tgz", - "integrity": "sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "mdast-util-to-markdown": "^1.0.0" - } - }, - "mdast-util-to-hast": { - "version": "12.2.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.2.tgz", - "integrity": "sha512-lVkUttV9wqmdXFtEBXKcepvU/zfwbhjbkM5rxrquLW55dS1DfOrnAXCk5mg1be1sfY/WfMmayGy1NsbK1GLCYQ==", - "requires": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "@types/mdurl": "^1.0.0", - "mdast-util-definitions": "^5.0.0", - "mdurl": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "trim-lines": "^3.0.0", - "unist-builder": "^3.0.0", - "unist-util-generated": "^2.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0" + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" } }, - "mdast-util-to-markdown": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz", - "integrity": "sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA==", - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "longest-streak": "^3.0.0", - "mdast-util-to-string": "^3.0.0", - "micromark-util-decode-string": "^1.0.0", - "unist-util-visit": "^4.0.0", - "zwitch": "^2.0.0" + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" } }, - "mdast-util-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", - "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==" + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "micromark": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", - "integrity": "sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg==", - "requires": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "micromark-core-commonmark": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", - "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", - "requires": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "micromark-extension-frontmatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-1.0.0.tgz", - "integrity": "sha512-EXjmRnupoX6yYuUJSQhrQ9ggK0iQtQlpi6xeJzVD5xscyAI+giqco5fdymayZhJMbIFecjnE2yz85S9NzIgQpg==", - "requires": { - "fault": "^2.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0" + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "micromark-extension-gfm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.1.tgz", - "integrity": "sha512-p2sGjajLa0iYiGQdT0oelahRYtMWvLjy8J9LOCxzIQsllMCGLbsLW+Nc+N4vi02jcRJvedVJ68cjelKIO6bpDA==", - "requires": { - "micromark-extension-gfm-autolink-literal": "^1.0.0", - "micromark-extension-gfm-footnote": "^1.0.0", - "micromark-extension-gfm-strikethrough": "^1.0.0", - "micromark-extension-gfm-table": "^1.0.0", - "micromark-extension-gfm-tagfilter": "^1.0.0", - "micromark-extension-gfm-task-list-item": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-extension-gfm-autolink-literal": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.3.tgz", - "integrity": "sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" } }, - "micromark-extension-gfm-footnote": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.0.4.tgz", - "integrity": "sha512-E/fmPmDqLiMUP8mLJ8NbJWJ4bTw6tS+FEQS8CcuDtZpILuOb2kjLqPEeAePF1djXROHXChM/wPJw0iS4kHCcIg==", - "requires": { - "micromark-core-commonmark": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-strikethrough": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.4.tgz", - "integrity": "sha512-/vjHU/lalmjZCT5xt7CcHVJGq8sYRm80z24qAKXzaHzem/xsDYb2yLL+NNVbYvmpLx3O7SYPuGL5pzusL9CLIQ==", - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-gfm-table": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.5.tgz", - "integrity": "sha512-xAZ8J1X9W9K3JTJTUL7G6wSKhp2ZYHrFk5qJgY/4B33scJzE2kpfRL6oiw/veJTbt7jiM/1rngLlOKPWr1G+vg==", - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" + "node_modules/sharp/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "micromark-extension-gfm-tagfilter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.1.tgz", - "integrity": "sha512-Ty6psLAcAjboRa/UKUbbUcwjVAv5plxmpUTy2XC/3nJFL37eHej8jrHrRzkqcpipJliuBH30DTs7+3wqNcQUVA==", - "requires": { - "micromark-util-types": "^1.0.0" + "node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "micromark-extension-gfm-task-list-item": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.3.tgz", - "integrity": "sha512-PpysK2S1Q/5VXi72IIapbi/jliaiOFzv7THH4amwXeYXLq3l1uo8/2Be0Ac1rEwK20MQEsGH2ltAZLNY2KI/0Q==", - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" }, - "micromark-extension-mdx-expression": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz", - "integrity": "sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA==", - "requires": { - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-extension-mdx-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz", - "integrity": "sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==", - "requires": { - "@types/acorn": "^4.0.0", - "estree-util-is-identifier-name": "^2.0.0", - "micromark-factory-mdx-expression": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-extension-mdx-md": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz", - "integrity": "sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==", - "requires": { - "micromark-util-types": "^1.0.0" + "node_modules/smol-toml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", + "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" } }, - "micromark-extension-mdxjs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz", - "integrity": "sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==", - "requires": { - "acorn": "^8.0.0", - "acorn-jsx": "^5.0.0", - "micromark-extension-mdx-expression": "^1.0.0", - "micromark-extension-mdx-jsx": "^1.0.0", - "micromark-extension-mdx-md": "^1.0.0", - "micromark-extension-mdxjs-esm": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" } }, - "micromark-extension-mdxjs-esm": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.3.tgz", - "integrity": "sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==", - "requires": { - "micromark-core-commonmark": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.1.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-factory-destination": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", - "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-factory-label": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", - "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-factory-mdx-expression": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz", - "integrity": "sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA==", - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-events-to-acorn": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-position-from-estree": "^1.0.0", - "uvu": "^0.5.0", - "vfile-message": "^3.0.0" - } - }, - "micromark-factory-space": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", - "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "micromark-factory-title": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", - "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-factory-whitespace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", - "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", - "requires": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "micromark-util-character": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", - "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", - "requires": { - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "micromark-util-chunked": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", - "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", - "requires": { - "micromark-util-symbol": "^1.0.0" + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "micromark-util-classify-character": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", - "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "micromark-util-combine-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", - "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "micromark-util-decode-numeric-character-reference": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", - "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", - "requires": { - "micromark-util-symbol": "^1.0.0" + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" } }, - "micromark-util-decode-string": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", - "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", - "requires": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" } }, - "micromark-util-encode": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", - "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==" - }, - "micromark-util-events-to-acorn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.0.tgz", - "integrity": "sha512-WWp3bf7xT9MppNuw3yPjpnOxa8cj5ACivEzXJKu0WwnjBYfzaBvIAT9KfeyI0Qkll+bfQtfftSwdgTH6QhTOKw==", - "requires": { - "@types/acorn": "^4.0.0", - "@types/estree": "^1.0.0", - "estree-util-visit": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0", - "vfile-location": "^4.0.0", - "vfile-message": "^3.0.0" + "node_modules/svgo": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, - "micromark-util-html-tag-name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", - "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==" + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" }, - "micromark-util-normalize-identifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", - "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", - "requires": { - "micromark-util-symbol": "^1.0.0" + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "license": "MIT", + "engines": { + "node": ">=18" } }, - "micromark-util-resolve-all": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", - "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", - "requires": { - "micromark-util-types": "^1.0.0" + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "micromark-util-sanitize-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz", - "integrity": "sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg==", - "requires": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "micromark-util-subtokenize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", - "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", - "requires": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "micromark-util-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", - "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==" + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "micromark-util-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", - "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==" + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "deprecated": "unmaintained", + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, - "mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==" + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + "node_modules/typesafe-path": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/typesafe-path/-/typesafe-path-0.2.2.tgz", + "integrity": "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==", + "dev": true, + "license": "MIT" }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + "node_modules/typescript-auto-import-cache": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.6.tgz", + "integrity": "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.8" + } }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + "node_modules/typescript-auto-import-cache/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" }, - "mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==" + "node_modules/ultrahtml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", + "license": "MIT" }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "nlcst-to-string": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-2.0.4.tgz", - "integrity": "sha512-3x3jwTd6UPG7vi5k4GEzvxJ5rDA7hVUIRNHPblKuMVP9Z3xmlsd9cgLcpAMkc5uPOBna82EeshROFhsPkbnTZg==" - }, - "node-abi": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz", - "integrity": "sha512-qWO5l3SCqbwQavymOmtTVuCWZE23++S+rxyoHjXqUmPyzRcaoI4lA2gO55/drddGnedAyjA7sk76SfQ5lfUMnw==", - "requires": { - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } - } + "node_modules/unifont": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ofetch": "^1.5.1", + "ohash": "^2.0.11" } }, - "node-addon-api": { + "node_modules/unist-util-find-after": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", - "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" - }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "requires": { - "path-key": "^4.0.0" + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", "dependencies": { - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==" - } + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "requires": { - "mimic-fn": "^4.0.0" - } - }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "dependencies": { - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - } + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "ora": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", - "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", - "requires": { - "bl": "^5.0.0", - "chalk": "^5.0.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.6.1", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.1.0", - "log-symbols": "^5.1.0", - "strip-ansi": "^7.0.1", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==" - } + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "p-locate": { + "node_modules/unist-util-visit-children": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pagefind": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", - "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", - "dev": true, - "requires": { - "@pagefind/darwin-arm64": "1.5.2", - "@pagefind/darwin-x64": "1.5.2", - "@pagefind/freebsd-x64": "1.5.2", - "@pagefind/linux-arm64": "1.5.2", - "@pagefind/linux-x64": "1.5.2", - "@pagefind/windows-arm64": "1.5.2", - "@pagefind/windows-x64": "1.5.2" + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "parse-entities": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.0.tgz", - "integrity": "sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ==", - "requires": { - "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "parse-latin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.0.tgz", - "integrity": "sha512-Ht+4/+AUySMS5HKGAiQpBmkFsHSoGrj6Y83flLCa5OIBdtsVkO3UD4OtboJ0O0vZiOznH02x8qlwg9KLUVXuNg==", - "requires": { - "nlcst-to-string": "^2.0.0", - "unist-util-modify-children": "^2.0.0", - "unist-util-visit-children": "^1.0.0" + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" - }, - "periscopic": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.0.4.tgz", - "integrity": "sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg==", - "requires": { - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } + "terser": { + "optional": true }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } + "tsx": { + "optional": true }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "yaml": { + "optional": true } } }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "requires": { - "find-up": "^3.0.0" + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, - "postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - }, - "preact": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", - "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==" - }, - "preact-render-to-string": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", - "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", - "requires": { - "pretty-format": "^3.8.0" - } - }, - "prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "preferred-pm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", - "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", - "requires": { - "find-up": "^5.0.0", - "find-yarn-workspace-root2": "1.2.16", - "path-exists": "^4.0.0", - "which-pm": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - } + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==" + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "prettier-plugin-astro": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.7.0.tgz", - "integrity": "sha512-ehCUx7MqHWvkHwUmxxAWLsL35pFaCTM5YXQ8xjG/1W6dY2yBhvEks+2aCfjeI5zmMrZNCXkiMQtpznSlLSLrxw==", - "requires": { - "@astrojs/compiler": "^0.29.3", - "prettier": "^2.7.1", - "sass-formatter": "^0.7.5", - "synckit": "^0.8.4" - }, - "dependencies": { - "@astrojs/compiler": { - "version": "0.29.19", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-0.29.19.tgz", - "integrity": "sha512-lvPpoOA6Fc1NpJrPT65ZOhhFieYkiBds9wzOhWX55lXMUpNPu5CUxqzgDAkNSTIoXHZxkxHfi+6EpFNnRZBBYQ==" - } + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "pretty-format": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", - "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } }, - "prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "dependencies": { - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - } + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "property-information": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", - "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==" + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "requires": { - "inherits": "~2.0.3" + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "recast": { - "version": "0.20.5", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", - "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", - "requires": { - "ast-types": "0.14.2", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tslib": "^2.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "rehype": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/rehype/-/rehype-12.0.1.tgz", - "integrity": "sha512-ey6kAqwLM3X6QnMDILJthGvG1m1ULROS9NT4uG9IDCuv08SFyLlreSuvOa//DgEvbXx62DS6elGVqusWhRUbgw==", - "requires": { - "@types/hast": "^2.0.0", - "rehype-parse": "^8.0.0", - "rehype-stringify": "^9.0.0", - "unified": "^10.0.0" + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "rehype-parse": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.4.tgz", - "integrity": "sha512-MJJKONunHjoTh4kc3dsM1v3C9kGrrxvA3U8PxZlP2SjH8RNUSrb+lF7Y0KVaUDnGH2QZ5vAn7ulkiajM9ifuqg==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^7.0.0", - "parse5": "^6.0.0", - "unified": "^10.0.0" - } - }, - "rehype-raw": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", - "integrity": "sha512-d6AKtisSRtDRX4aSPsJGTfnzrX2ZkHQLE5kiUuGOeEoLpbEulFF4hj0mLPbsa+7vmguDKOVVEQdHKDSwoaIDsQ==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-raw": "^7.2.0", - "unified": "^10.0.0" - } - }, - "rehype-stringify": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-9.0.3.tgz", - "integrity": "sha512-kWiZ1bgyWlgOxpqD5HnxShKAdXtb2IUljn3hQAhySeak6IOQPPt6DeGnsIh4ixm7yKJWzm8TXFuC/lPfcWHJqw==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-to-html": "^8.0.0", - "unified": "^10.0.0" - } - }, - "remark-frontmatter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-4.0.1.tgz", - "integrity": "sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-frontmatter": "^1.0.0", - "micromark-extension-frontmatter": "^1.0.0", - "unified": "^10.0.0" + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "remark-gfm": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", - "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-gfm": "^2.0.0", - "micromark-extension-gfm": "^2.0.0", - "unified": "^10.0.0" + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "remark-mdx": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-2.1.5.tgz", - "integrity": "sha512-A8vw5s+BgOa968Irt8BO7DfWJTE0Fe7Ge3hX8zzDB1DnwMZTNdK6qF2IcFao+/7nzk1vSysKcFp+3ku4vhMpaQ==", - "requires": { - "mdast-util-mdx": "^2.0.0", - "micromark-extension-mdxjs": "^1.0.0" + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "remark-parse": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", - "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", - "requires": { - "@types/mdast": "^3.0.0", - "mdast-util-from-markdown": "^1.0.0", - "unified": "^10.0.0" - } - }, - "remark-rehype": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", - "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", - "requires": { - "@types/hast": "^2.0.0", - "@types/mdast": "^3.0.0", - "mdast-util-to-hast": "^12.1.0", - "unified": "^10.0.0" - } - }, - "remark-smartypants": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.0.0.tgz", - "integrity": "sha512-Rc0VDmr/yhnMQIz8n2ACYXlfw/P/XZev884QU1I5u+5DgJls32o97Vc1RbK3pfumLsJomS2yy8eT4Fxj/2MDVA==", - "requires": { - "retext": "^8.1.0", - "retext-smartypants": "^5.1.0", - "unist-util-visit": "^4.1.0" - } - }, - "reselect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", - "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - } + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "retext": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz", - "integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==", - "requires": { - "@types/nlcst": "^1.0.0", - "retext-latin": "^3.0.0", - "retext-stringify": "^3.0.0", - "unified": "^10.0.0" + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "retext-latin": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-3.1.0.tgz", - "integrity": "sha512-5MrD1tuebzO8ppsja5eEu+ZbBeUNCjoEarn70tkXOS7Bdsdf6tNahsv2bY0Z8VooFF6cw7/6S+d3yI/TMlMVVQ==", - "requires": { - "@types/nlcst": "^1.0.0", - "parse-latin": "^5.0.0", - "unherit": "^3.0.0", - "unified": "^10.0.0" + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "retext-smartypants": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-5.2.0.tgz", - "integrity": "sha512-Do8oM+SsjrbzT2UNIKgheP0hgUQTDDQYyZaIY3kfq0pdFzoPk+ZClYJ+OERNXveog4xf1pZL4PfRxNoVL7a/jw==", - "requires": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "dependencies": { - "nlcst-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.0.tgz", - "integrity": "sha512-Y8HQWKw/zrHTCnu2zcFBN1dV6vN0NUG7s5fkEj380G8tF3R+vA2KG+tDl2QoHVQCTHGHVXwoni2RQkDSFQb1PA==", - "requires": { - "@types/nlcst": "^1.0.0" - } - } + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, - "retext-stringify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-3.1.0.tgz", - "integrity": "sha512-767TLOaoXFXyOnjx/EggXlb37ZD2u4P1n0GJqVdpipqACsQP+20W+BNpMYrlJkq7hxffnFk+jc6mAK9qrbuB8w==", - "requires": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0" - }, - "dependencies": { - "nlcst-to-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.0.tgz", - "integrity": "sha512-Y8HQWKw/zrHTCnu2zcFBN1dV6vN0NUG7s5fkEj380G8tF3R+vA2KG+tDl2QoHVQCTHGHVXwoni2RQkDSFQb1PA==", - "requires": { - "@types/nlcst": "^1.0.0" - } - } + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" } }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "requires": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - } + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", - "requires": { - "fsevents": "~2.3.2" + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "s.color": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", - "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==" - }, - "sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "requires": { - "mri": "^1.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "sass-formatter": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.5.tgz", - "integrity": "sha512-NKFP8ddjhUYi6A/iD1cEtzkEs91U61kzqe3lY9SVNuvX7LGc88xnEN0mmsWL7Ol//YTi2GL/ol7b9XZ2+hgXuA==", - "requires": { - "suf-log": "^2.5.3" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "requires": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" - }, - "serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "requires": { - "type-fest": "^0.13.1" + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, - "dependencies": { - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==" + "peerDependenciesMeta": { + "vite": { + "optional": true } } }, - "sharp": { - "version": "0.31.2", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.2.tgz", - "integrity": "sha512-DUdNVEXgS5A97cTagSLIIp8dUZ/lZtk78iNVZgHdHbx1qnQR7JAHY0BnXnwwH39Iw+VKhO08CTYhIg0p98vQ5Q==", - "requires": { - "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", - "prebuild-install": "^7.1.1", - "semver": "^7.3.8", - "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", - "tunnel-agent": "^0.6.0" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "requires": { - "lru-cache": "^6.0.0" - } + "node_modules/volar-service-css": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-css/-/volar-service-css-0.0.71.tgz", + "integrity": "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-css-languageservice": "^6.3.0", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true } } }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "shiki": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", - "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", - "requires": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "^6.0.0" - }, + "node_modules/volar-service-emmet": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-emmet/-/volar-service-emmet-0.0.71.tgz", + "integrity": "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA==", + "dev": true, + "license": "MIT", "dependencies": { - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "@emmetio/css-parser": "^0.4.1", + "@emmetio/html-matcher": "^1.3.0", + "@vscode/emmet-helper": "^2.9.3", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true } } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "requires": { - "is-arrayish": "^0.3.1" - } - }, - "sirv": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", - "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", - "requires": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" - }, - "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "space-separated-tokens": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", - "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, + "node_modules/volar-service-html": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-html/-/volar-service-html-0.0.71.tgz", + "integrity": "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw==", + "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "vscode-html-languageservice": "^5.3.0", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true } } }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "stringify-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", - "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", - "requires": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" - }, - "strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" - }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" - }, - "style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", - "requires": { - "inline-style-parser": "0.1.1" - } - }, - "suf-log": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", - "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", - "requires": { - "s.color": "0.0.15" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" + "node_modules/volar-service-prettier": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-prettier/-/volar-service-prettier-0.0.71.tgz", + "integrity": "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0", + "prettier": "^2.2 || ^3.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + }, + "prettier": { + "optional": true + } } }, - "supports-esm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-esm/-/supports-esm-1.0.0.tgz", - "integrity": "sha512-96Am8CDqUaC0I2+C/swJ0yEvM8ZnGn4unoers/LSdE4umhX7mELzqyLzx3HnZAluq5PXIsGMKqa7NkqaeHMPcg==", - "requires": { - "has-package-exports": "^1.1.0" + "node_modules/volar-service-typescript": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript/-/volar-service-typescript-0.0.71.tgz", + "integrity": "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-browserify": "^1.0.1", + "semver": "^7.6.2", + "typescript-auto-import-cache": "^0.3.5", + "vscode-languageserver-textdocument": "^1.0.11", + "vscode-nls": "^5.2.0", + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } } }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "synckit": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", - "integrity": "sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==", - "requires": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.4.0" + "node_modules/volar-service-typescript-twoslash-queries": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-typescript-twoslash-queries/-/volar-service-typescript-twoslash-queries-0.0.71.tgz", + "integrity": "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-uri": "^3.0.8" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true + } } }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "node_modules/volar-service-typescript/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } + "node_modules/volar-service-yaml": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.71.tgz", + "integrity": "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-uri": "^3.0.8", + "yaml-language-server": "~1.23.0" + }, + "peerDependencies": { + "@volar/language-service": "~2.4.0" + }, + "peerDependenciesMeta": { + "@volar/language-service": { + "optional": true } } }, - "tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "requires": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" + "node_modules/vscode-css-languageservice": { + "version": "6.3.10", + "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.3.10.tgz", + "integrity": "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-languageserver-types": "3.17.5", + "vscode-uri": "^3.1.0" } }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "node_modules/vscode-css-languageservice/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" + "node_modules/vscode-html-languageservice": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz", + "integrity": "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-languageserver-types": "^3.17.5", + "vscode-uri": "^3.1.0" } }, - "totalist": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", - "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==" - }, - "trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" + "node_modules/vscode-json-languageservice": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.1.8.tgz", + "integrity": "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.16.0", + "vscode-nls": "^5.0.0", + "vscode-uri": "^3.0.2" + }, + "engines": { + "npm": ">=7.0.0" + } }, - "trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + "node_modules/vscode-json-languageservice/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" }, - "tsconfig-resolver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tsconfig-resolver/-/tsconfig-resolver-3.0.1.tgz", - "integrity": "sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==", - "requires": { - "@types/json5": "^0.0.30", - "@types/resolve": "^1.17.0", - "json5": "^2.1.3", - "resolve": "^1.17.0", - "strip-bom": "^4.0.0", - "type-fest": "^0.13.1" - }, - "dependencies": { - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==" - } + "node_modules/vscode-jsonrpc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.1.tgz", + "integrity": "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "tsm": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.2.2.tgz", - "integrity": "sha512-bXkt675NbbqfwRHSSn8kSNEEHvoIUFDM9G6tUENkjEKpAEbrEzieO3PxUiRJylMw8fEGpcf5lSjadzzz12pc2A==", - "requires": { - "esbuild": "^0.14.0" + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" + "node_modules/vscode-languageserver-protocol": { + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", + "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "9.0.1", + "vscode-languageserver-types": "3.18.0" } }, - "type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" }, - "typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" + "node_modules/vscode-languageserver-types": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", + "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "dev": true, + "license": "MIT" }, - "unherit": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.0.tgz", - "integrity": "sha512-UmvIQZGEc9qdLIQ8mv8/61n6PiMgfbOoASPKHpCvII5srShCQSa6jSjBjlZOR4bxt2XnT6uo6csmPKRi+zQ0Jg==" - }, - "unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "requires": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" + "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "unist-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", - "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", - "requires": { - "@types/unist": "^2.0.0" + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, - "unist-util-generated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", - "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==" + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" }, - "unist-util-is": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", - "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==" + "node_modules/vscode-nls": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", + "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", + "dev": true, + "license": "MIT" }, - "unist-util-map": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/unist-util-map/-/unist-util-map-3.1.2.tgz", - "integrity": "sha512-WLA2R6x/UaopedG2poaWLShf5LCi+BNa6mMkACdjft23PHou4v85PvZItjbO2XgXvukMP365PlL/DrbuMgr3eg==", - "requires": { - "@types/unist": "^2.0.0" - } + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" }, - "unist-util-modify-children": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-2.0.0.tgz", - "integrity": "sha512-HGrj7JQo9DwZt8XFsX8UD4gGqOsIlCih9opG6Y+N11XqkBGKzHo8cvDi+MfQQgiZ7zXRUiQREYHhjOBHERTMdg==", - "requires": { - "array-iterate": "^1.0.0" + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "unist-util-position": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", - "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", - "requires": { - "@types/unist": "^2.0.0" + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "engines": { + "node": ">=4" } }, - "unist-util-position-from-estree": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz", - "integrity": "sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw==", - "requires": { - "@types/unist": "^2.0.0" + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "unist-util-remove-position": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz", - "integrity": "sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-visit": "^4.0.0" + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "unist-util-stringify-position": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", - "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", - "requires": { - "@types/unist": "^2.0.0" - } + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" }, - "unist-util-visit": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", - "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" } }, - "unist-util-visit-children": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-1.1.4.tgz", - "integrity": "sha512-sA/nXwYRCQVRwZU2/tQWUqJ9JSFM1X3x7JIOsIgSzrFHcfVt6NkzDtKzyxg2cZWkCwGF9CO8x4QNZRJRMK8FeQ==" + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, - "unist-util-visit-parents": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", - "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, - "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "uvu": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", - "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", - "requires": { - "dequal": "^2.0.0", - "diff": "^5.0.0", - "kleur": "^4.0.3", - "sade": "^1.7.3" - } - }, - "vfile": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", - "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" + "node_modules/yaml-language-server": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/yaml-language-server/-/yaml-language-server-1.23.0.tgz", + "integrity": "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vscode/l10n": "^0.0.18", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-i18n": "^4.2.0", + "prettier": "^3.8.1", + "request-light": "^0.5.7", + "vscode-json-languageservice": "4.1.8", + "vscode-languageserver": "^9.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-languageserver-types": "^3.16.0", + "vscode-uri": "^3.0.2", + "yaml": "2.8.3" + }, + "bin": { + "yaml-language-server": "bin/yaml-language-server" } }, - "vfile-location": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.0.1.tgz", - "integrity": "sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==", - "requires": { - "@types/unist": "^2.0.0", - "vfile": "^5.0.0" - } + "node_modules/yaml-language-server/node_modules/request-light": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz", + "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==", + "dev": true, + "license": "MIT" }, - "vfile-message": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", - "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "node_modules/yaml-language-server/node_modules/yaml": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, - "vite": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", - "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", - "requires": { - "esbuild": "^0.15.9", - "fsevents": "~2.3.2", - "postcss": "^8.4.18", - "resolve": "^1.22.1", - "rollup": "^2.79.1" - }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", "dependencies": { - "@esbuild/linux-loong64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", - "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", - "optional": true - }, - "esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "requires": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "esbuild-android-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", - "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", - "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", - "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", - "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", - "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", - "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", - "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", - "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", - "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", - "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", - "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", - "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", - "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", - "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", - "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", - "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", - "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", - "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", - "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", - "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", - "optional": true - } + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "vitefu": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.3.tgz", - "integrity": "sha512-75l7TTuU8isAhz1QFtNKjDkqjxvndfMC1AfIMjJ0ZQ59ZD0Ow9QOIsJJX16Wv9PS8f+zMzp6fHy5cCbKG/yVUQ==", - "requires": {} - }, - "vscode-css-languageservice": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-6.2.1.tgz", - "integrity": "sha512-FMaMjB2LQdkHjTCP2CWh2S94xuGsxSc8xr0H9nAACVd/iUDyZLoKFjwoB+mA3v0rpCH2U5vVCVwxyULy61CgqA==", - "requires": { - "@vscode/l10n": "^0.0.10", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-uri": "^3.0.6" - } - }, - "vscode-html-languageservice": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.0.3.tgz", - "integrity": "sha512-6rfrtcHhXDMXmC5pR2WXrx02HiNCzQDynOBMn+53zLxr2hvZrDzoc0QgC0FaFGfcglf7GeOsfhkWvJBFC/a70g==", - "requires": { - "@vscode/l10n": "^0.0.10", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-languageserver-types": "^3.17.2", - "vscode-uri": "^3.0.6" - } - }, - "vscode-jsonrpc": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", - "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==" - }, - "vscode-languageserver": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz", - "integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==", - "requires": { - "vscode-languageserver-protocol": "3.17.2" - } - }, - "vscode-languageserver-protocol": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", - "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==", - "requires": { - "vscode-jsonrpc": "8.0.2", - "vscode-languageserver-types": "3.17.2" - } - }, - "vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" - }, - "vscode-languageserver-types": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" - }, - "vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==" - }, - "vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==" - }, - "vscode-textmate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", - "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==" - }, - "vscode-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", - "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==" - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "requires": { - "defaults": "^1.0.3" + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" } }, - "web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "which-pm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", - "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", - "requires": { - "load-yaml-file": "^0.2.0", - "path-exists": "^4.0.0" - }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - } + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==" - }, - "widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "requires": { - "string-width": "^5.0.1" + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", - "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==" - } + "node_modules/yocto-spinner": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", + "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", + "license": "MIT", + "dependencies": { + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18.19" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } }, - "zod": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", - "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==" + "node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", + "peerDependencies": { + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" + } }, - "zwitch": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.2.tgz", - "integrity": "sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==" + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/www/package.json b/www/package.json index 276ca472..6d9a2004 100644 --- a/www/package.json +++ b/www/package.json @@ -14,26 +14,23 @@ }, "dependencies": { "@algolia/client-search": "^4.13.1", - "@astrojs/image": "^0.12.1", - "@astrojs/mdx": "^0.12.1", - "@astrojs/preact": "^1.1.0", - "@astrojs/react": "^1.2.2", + "@astrojs/mdx": "^4.3.0", + "@astrojs/react": "^4.3.0", "@docsearch/css": "^3.1.0", "@docsearch/react": "^3.1.0", - "@types/node": "^18.0.0", + "@types/node": "^20.14.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "astro": "^5.0.0", "lz-string": "^1.5.0", "prismjs": "^1.29.0", - "@types/react": "^17.0.45", - "@types/react-dom": "^18.0.0", - "astro": "^1.6.14", - "preact": "^10.7.3", - "react": "^18.2.0", - "react-dom": "^18.1.0", - "sharp": "^0.31.2" + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "devDependencies": { + "@astrojs/check": "^0.9.4", "@types/prismjs": "^1.26.3", "pagefind": "^1.5.2", - "typescript": "~5.2.2" + "typescript": "^5.7.2" } } diff --git a/www/src/components/Display/Row.tsx b/www/src/components/Display/Row.tsx index 98642316..fb94c9be 100644 --- a/www/src/components/Display/Row.tsx +++ b/www/src/components/Display/Row.tsx @@ -1,7 +1,6 @@ -import react from "react"; -import type { FunctionComponent } from "react"; +import type { PropsWithChildren } from "react"; import "./Row.css"; -export const CenteredRow: FunctionComponent = ({ children }) => { +export const CenteredRow = ({ children }: PropsWithChildren) => { return
{children}
; }; diff --git a/www/src/components/HeadSEO.astro b/www/src/components/HeadSEO.astro index 1fb133c8..4628ed50 100644 --- a/www/src/components/HeadSEO.astro +++ b/www/src/components/HeadSEO.astro @@ -1,5 +1,6 @@ --- -import { SITE, OPEN_GRAPH, Frontmatter } from '../config'; +import { SITE, OPEN_GRAPH } from '../config'; +import type { Frontmatter } from '../config'; export interface Props { frontmatter: Frontmatter; diff --git a/www/src/components/Header/SidebarToggle.tsx b/www/src/components/Header/SidebarToggle.tsx index 6d30b141..c3374b01 100644 --- a/www/src/components/Header/SidebarToggle.tsx +++ b/www/src/components/Header/SidebarToggle.tsx @@ -1,8 +1,6 @@ -/** @jsxImportSource preact */ -import type { FunctionalComponent } from "preact"; -import { useState, useEffect } from "preact/hooks"; +import { useState, useEffect } from "react"; -const MenuToggle: FunctionalComponent = () => { +const MenuToggle = () => { const [sidebarShown, setSidebarShown] = useState(false); useEffect(() => { @@ -48,9 +46,9 @@ const MenuToggle: FunctionalComponent = () => { stroke="currentColor" > diff --git a/www/src/components/LiveExample/LiveExample.astro b/www/src/components/LiveExample/LiveExample.astro index 9efc7fd2..0e563093 100644 --- a/www/src/components/LiveExample/LiveExample.astro +++ b/www/src/components/LiveExample/LiveExample.astro @@ -23,7 +23,8 @@ const LABELS: Record = { const ORDER = ["example.ts", "entity.ts", "table.ts"]; const sources = import.meta.glob("/src/examples/*/*.ts", { - as: "raw", + query: "?raw", + import: "default", eager: true, }) as Record; diff --git a/www/src/components/PageContent/PackageInstall.tsx b/www/src/components/PageContent/PackageInstall.tsx index b13c19cf..e6602a90 100644 --- a/www/src/components/PageContent/PackageInstall.tsx +++ b/www/src/components/PageContent/PackageInstall.tsx @@ -1,6 +1,4 @@ -/** @jsxImportSource preact */ -import type { FunctionalComponent } from "preact"; -import { useEffect, useMemo, useState } from "preact/hooks"; +import { useEffect, useMemo, useState } from "react"; import "./PackageInstall.css"; type Manager = "npm" | "yarn" | "pnpm" | "bun"; @@ -41,10 +39,10 @@ type Props = { dev?: boolean; }; -const PackageInstall: FunctionalComponent = ({ +const PackageInstall = ({ packages, dev = false, -}) => { +}: Props) => { const [manager, setManager] = useState("npm"); const [copied, setCopied] = useState(false); @@ -116,15 +114,15 @@ const PackageInstall: FunctionalComponent = ({ }; return ( -
-
+
+
{MANAGERS.map((m) => (
-
-        {command}
+      
+        {command}
       
); diff --git a/www/src/components/PageContent/QuickLook.tsx b/www/src/components/PageContent/QuickLook.tsx index 39895f74..96ef7d0f 100644 --- a/www/src/components/PageContent/QuickLook.tsx +++ b/www/src/components/PageContent/QuickLook.tsx @@ -1,8 +1,7 @@ -import type { FunctionComponent } from "react"; -import react from "react"; +import type { PropsWithChildren } from "react"; import "./QuickLook.css"; -const QuickLook: FunctionComponent = ({ children }) => { +const QuickLook = ({ children }: PropsWithChildren) => { return
{children}
; }; diff --git a/www/src/components/RightSidebar/TableOfContents.tsx b/www/src/components/RightSidebar/TableOfContents.tsx index 91f9ee3c..def9d1d4 100644 --- a/www/src/components/RightSidebar/TableOfContents.tsx +++ b/www/src/components/RightSidebar/TableOfContents.tsx @@ -1,11 +1,12 @@ -import type { FunctionalComponent } from "preact"; -import { useState, useEffect, useRef } from "preact/hooks"; +import { useState, useEffect, useRef } from "react"; import type { MarkdownHeading } from "astro"; const ACTIVATION_OFFSET = 100; -const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[] }> = ({ +const TableOfContents = ({ headings = [], +}: { + headings: MarkdownHeading[]; }) => { const [activeId, setActiveId] = useState("overview"); const pinnedRef = useRef(false); diff --git a/www/src/components/RightSidebar/ThemeToggleButton.tsx b/www/src/components/RightSidebar/ThemeToggleButton.tsx index f22e888e..db1728dc 100644 --- a/www/src/components/RightSidebar/ThemeToggleButton.tsx +++ b/www/src/components/RightSidebar/ThemeToggleButton.tsx @@ -1,5 +1,3 @@ -/** @jsxImportSource preact */ -import type { FunctionalComponent } from "preact"; import "./ThemeToggleButton.css"; const SunIcon = ( @@ -44,7 +42,7 @@ const MoonIcon = ( ); -const ThemeToggle: FunctionalComponent = () => { +const ThemeToggle = () => { const handleClick = () => { const root = document.documentElement; let isDark: boolean; diff --git a/www/tsconfig.json b/www/tsconfig.json index 26524aea..40753393 100644 --- a/www/tsconfig.json +++ b/www/tsconfig.json @@ -4,8 +4,6 @@ "jsx": "preserve", "skipLibCheck": true, "noEmit": true, - // astro v1's base tsconfig sets importsNotUsedAsValues, deprecated in TS 5 - "ignoreDeprecations": "5.0", "baseUrl": ".", "paths": { // Resolves imports in src/examples/** against the actual ElectroDB @@ -13,5 +11,6 @@ // against the current API. "electrodb": ["../index.d.ts"] } - } + }, + "exclude": ["dist", "public"] } From 84e60b1868f3fafa2bdcb5f01db9b48034b638f2 Mon Sep 17 00:00:00 2001 From: ty Date: Tue, 7 Jul 2026 10:26:46 -0400 Subject: [PATCH 03/16] Capture query call sites in playground output events The mocked client now records the call stack (with a temporarily raised stack limit, since collection and create paths sit deeper than V8's default 10 frames) when parameters are created, and passes it to configured listeners via onParams. The playground UI uses it to link each generated params block to the query that produced it; the DOM fallback ignores it. --- playground/browser.js | 34 ++++++++++++++++++++-- www/public/scripts/electrodb-playground.js | 34 ++++++++++++++++++++-- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/playground/browser.js b/playground/browser.js index f6fb6282..46adb6fb 100644 --- a/playground/browser.js +++ b/playground/browser.js @@ -159,12 +159,14 @@ function configure(custom = {}) { }; } -function printToScreen({ params, state, entity, cache } = {}) { +function printToScreen({ params, state, entity, cache, stack } = {}) { const label = formatParamLabel(state, entity); if (cache) { window.electroParams.push({ title: label, json: params }); } - listener.onParams({ label, params, cache }); + // `stack` is the call stack captured where the operation was invoked; + // listeners can use it to associate output with the source that created it. + listener.onParams({ label, params, cache, stack }); } function printMessage(type, message) { @@ -183,6 +185,25 @@ function promiseCallback(results) { }; } +// Some operations (collections, create) sit many frames deep in electrodb +// internals; the default stack limit (10 in V8) can truncate the stack +// before it reaches the calling user code. +function captureStack() { + const limit = Error.stackTraceLimit; + try { + Error.stackTraceLimit = 64; + } catch (err) { + // not configurable in this engine + } + const stack = new Error().stack; + try { + Error.stackTraceLimit = limit; + } catch (err) { + // ignore + } + return stack; +} + class Entity extends ElectroDB.Entity { constructor(schema, options = {}) { super(schema, { @@ -204,6 +225,7 @@ class Entity extends ElectroDB.Entity { UnprocessedKeys: { [options.table]: { Keys: [] } }, }), transactWrite: (params) => { + const stack = captureStack(); return { promise: async () => { printToScreen({ @@ -211,6 +233,7 @@ class Entity extends ElectroDB.Entity { entity: this, cache: true, state: "Performs a TransactWrite operation", + stack, }); return {}; }, @@ -218,6 +241,7 @@ class Entity extends ElectroDB.Entity { }; }, transactGet: (params) => { + const stack = captureStack(); return { promise: async () => { printToScreen({ @@ -225,6 +249,7 @@ class Entity extends ElectroDB.Entity { entity: this, cache: true, state: "Performs a TransactGet operation", + stack, }); return { Responses: [] }; }, @@ -237,6 +262,9 @@ class Entity extends ElectroDB.Entity { } _demoParams(method, state, config) { + // Param creation happens synchronously inside the user's `.go()`/ + // `.params()` call, so the stack still contains their call site. + const stack = captureStack(); try { const params = super[method](state, config); if (params && typeof params.catch === "function") { @@ -246,7 +274,7 @@ class Entity extends ElectroDB.Entity { }); } if (state.self !== "commit") { - printToScreen({ params, state, entity: this, cache: true }); + printToScreen({ params, state, entity: this, cache: true, stack }); } return params; } catch (err) { diff --git a/www/public/scripts/electrodb-playground.js b/www/public/scripts/electrodb-playground.js index 17be0f4f..0a3e88d0 100644 --- a/www/public/scripts/electrodb-playground.js +++ b/www/public/scripts/electrodb-playground.js @@ -4043,12 +4043,14 @@ function configure(custom = {}) { }; } -function printToScreen({ params, state, entity, cache } = {}) { +function printToScreen({ params, state, entity, cache, stack } = {}) { const label = formatParamLabel(state, entity); if (cache) { window.electroParams.push({ title: label, json: params }); } - listener.onParams({ label, params, cache }); + // `stack` is the call stack captured where the operation was invoked; + // listeners can use it to associate output with the source that created it. + listener.onParams({ label, params, cache, stack }); } function printMessage(type, message) { @@ -4067,6 +4069,25 @@ function promiseCallback(results) { }; } +// Some operations (collections, create) sit many frames deep in electrodb +// internals; the default stack limit (10 in V8) can truncate the stack +// before it reaches the calling user code. +function captureStack() { + const limit = Error.stackTraceLimit; + try { + Error.stackTraceLimit = 64; + } catch (err) { + // not configurable in this engine + } + const stack = new Error().stack; + try { + Error.stackTraceLimit = limit; + } catch (err) { + // ignore + } + return stack; +} + class Entity extends ElectroDB.Entity { constructor(schema, options = {}) { super(schema, { @@ -4088,6 +4109,7 @@ class Entity extends ElectroDB.Entity { UnprocessedKeys: { [options.table]: { Keys: [] } }, }), transactWrite: (params) => { + const stack = captureStack(); return { promise: async () => { printToScreen({ @@ -4095,6 +4117,7 @@ class Entity extends ElectroDB.Entity { entity: this, cache: true, state: "Performs a TransactWrite operation", + stack, }); return {}; }, @@ -4102,6 +4125,7 @@ class Entity extends ElectroDB.Entity { }; }, transactGet: (params) => { + const stack = captureStack(); return { promise: async () => { printToScreen({ @@ -4109,6 +4133,7 @@ class Entity extends ElectroDB.Entity { entity: this, cache: true, state: "Performs a TransactGet operation", + stack, }); return { Responses: [] }; }, @@ -4121,6 +4146,9 @@ class Entity extends ElectroDB.Entity { } _demoParams(method, state, config) { + // Param creation happens synchronously inside the user's `.go()`/ + // `.params()` call, so the stack still contains their call site. + const stack = captureStack(); try { const params = super[method](state, config); if (params && typeof params.catch === "function") { @@ -4130,7 +4158,7 @@ class Entity extends ElectroDB.Entity { }); } if (state.self !== "commit") { - printToScreen({ params, state, entity: this, cache: true }); + printToScreen({ params, state, entity: this, cache: true, stack }); } return params; } catch (err) { From 7f8ae503f2b231b8539a11b3ed7441d36a15e0ec Mon Sep 17 00:00:00 2001 From: ty Date: Tue, 7 Jul 2026 14:22:10 -0400 Subject: [PATCH 04/16] Convert docs code examples to LiveExample controls (27 pages) Bulk conversion of runnable ElectroDB snippets across mutations, queries, modeling, core-concepts, recipes, and examples pages to the interactive LiveExample control: each snippet now lives as a self-contained, type-checked example directory (example.ts + entity/table, plus entities/service for Service-based walkthroughs) rendered with tabs and live-generated DynamoDB parameters. Adjacent hard-coded "Equivalent Parameters" JSON blocks and stale "Try it out!" badge links were removed with their snippets; intentionally failing "Bad:" examples now display their real thrown error. Response Format and Execution Options sections remain static. Also: LiveExample tab labels/ordering extended for entities.ts/service.ts; task-manager validate callbacks return booleans so entity schema inference stays literal. Not yet converted (pending follow-up): mutations/patch, examples/ human-resources, library-system, version-control; modeling/collections and examples/task-manager are partially converted (valid, some snippets still static). Unreferenced example dirs (patch-*, human-resources-*, two collections-*) are staged groundwork for those pages. --- .../components/LiveExample/LiveExample.astro | 4 +- .../batch-delete-store-locations/entity.ts | 125 +++++ .../batch-delete-store-locations/example.ts | 16 + .../batch-delete-store-locations/table.ts | 76 +++ .../batch-get-store-locations/entity.ts | 125 +++++ .../batch-get-store-locations/example.ts | 16 + .../batch-get-store-locations/table.ts | 76 +++ .../batch-put-store-locations/entity.ts | 125 +++++ .../batch-put-store-locations/example.ts | 24 + .../batch-put-store-locations/table.ts | 76 +++ .../entities.ts | 103 ++++ .../example.ts | 8 + .../service.ts | 4 + .../collection-assignments-filtered/table.ts | 52 ++ .../collection-assignments/entities.ts | 103 ++++ .../collection-assignments/example.ts | 5 + .../collection-assignments/service.ts | 4 + .../examples/collection-assignments/table.ts | 52 ++ .../entities.ts | 103 ++++ .../example.ts | 3 + .../service.ts | 7 + .../table.ts | 52 ++ .../entities.ts | 151 ++++++ .../example.ts | 5 + .../service.ts | 8 + .../collections-complex-assignments/table.ts | 52 ++ .../entities.ts | 151 ++++++ .../example.ts | 6 + .../service.ts | 8 + .../table.ts | 52 ++ .../entities.ts | 103 ++++ .../example.ts | 3 + .../service.ts | 7 + .../table.ts | 52 ++ .../collections-index-naming-staff/entity.ts | 51 ++ .../collections-index-naming-staff/example.ts | 3 + .../collections-index-naming-staff/table.ts | 52 ++ .../entities.ts | 103 ++++ .../example.ts | 5 + .../service.ts | 7 + .../table.ts | 52 ++ .../collections-simple-overview/entities.ts | 151 ++++++ .../collections-simple-overview/example.ts | 6 + .../collections-simple-overview/service.ts | 8 + .../collections-simple-overview/table.ts | 52 ++ .../entities.ts | 103 ++++ .../example.ts | 5 + .../service.ts | 7 + .../table.ts | 52 ++ .../entities.ts | 103 ++++ .../example.ts | 3 + .../service.ts | 7 + .../collections-taskapp-assignments/table.ts | 52 ++ .../conditions-condition-expression/entity.ts | 109 ++++ .../example.ts | 31 ++ .../conditions-condition-expression/table.ts | 52 ++ .../conditions-conditional-update/entity.ts | 125 +++++ .../conditions-conditional-update/example.ts | 15 + .../conditions-conditional-update/table.ts | 76 +++ .../entity.ts | 125 +++++ .../example.ts | 18 + .../conditions-detect-rejection-only/table.ts | 76 +++ .../entity.ts | 70 +++ .../example.ts | 18 + .../table.ts | 52 ++ .../examples/conditions-safe-create/entity.ts | 125 +++++ .../conditions-safe-create/example.ts | 18 + .../examples/conditions-safe-create/table.ts | 76 +++ .../conditions-where-chained/entity.ts | 109 ++++ .../conditions-where-chained/example.ts | 16 + .../conditions-where-chained/table.ts | 52 ++ .../conditions-where-destructured/entity.ts | 109 ++++ .../conditions-where-destructured/example.ts | 7 + .../conditions-where-destructured/table.ts | 52 ++ .../entity.ts | 109 ++++ .../example.ts | 21 + .../table.ts | 52 ++ .../entity.ts | 109 ++++ .../example.ts | 10 + .../conditions-where-escape-function/table.ts | 52 ++ .../conditions-where-field-function/entity.ts | 109 ++++ .../example.ts | 10 + .../conditions-where-field-function/table.ts | 52 ++ .../conditions-where-list-attribute/entity.ts | 109 ++++ .../example.ts | 7 + .../conditions-where-list-attribute/table.ts | 52 ++ .../conditions-where-map-attribute/entity.ts | 109 ++++ .../conditions-where-map-attribute/example.ts | 7 + .../conditions-where-map-attribute/table.ts | 52 ++ .../entity.ts | 109 ++++ .../example.ts | 11 + .../table.ts | 52 ++ .../conditions-where-name-function/entity.ts | 109 ++++ .../conditions-where-name-function/example.ts | 10 + .../conditions-where-name-function/table.ts | 52 ++ .../conditions-where-single-filter/entity.ts | 109 ++++ .../conditions-where-single-filter/example.ts | 7 + .../conditions-where-single-filter/table.ts | 52 ++ .../conditions-where-value-function/entity.ts | 109 ++++ .../example.ts | 10 + .../conditions-where-value-function/table.ts | 52 ++ .../examples/create-store-location/entity.ts | 125 +++++ .../examples/create-store-location/example.ts | 14 + .../examples/create-store-location/table.ts | 76 +++ .../examples/delete-store-location/entity.ts | 125 +++++ .../examples/delete-store-location/example.ts | 8 + .../examples/delete-store-location/table.ts | 76 +++ .../examples/executing-queries-go/entity.ts | 125 +++++ .../examples/executing-queries-go/example.ts | 9 + .../examples/executing-queries-go/table.ts | 76 +++ .../executing-queries-params/entity.ts | 125 +++++ .../executing-queries-params/example.ts | 9 + .../executing-queries-params/table.ts | 76 +++ .../existing-table-ignore-ownership/entity.ts | 51 ++ .../example.ts | 9 + .../existing-table-ignore-ownership/table.ts | 26 + .../filters-escape-function/entity.ts | 125 +++++ .../filters-escape-function/example.ts | 10 + .../examples/filters-escape-function/table.ts | 100 ++++ .../examples/filters-field-function/entity.ts | 125 +++++ .../filters-field-function/example.ts | 10 + .../examples/filters-field-function/table.ts | 100 ++++ .../filters-filter-expression/entity.ts | 125 +++++ .../filters-filter-expression/example.ts | 10 + .../filters-filter-expression/table.ts | 100 ++++ .../filters-multiple-where-clauses/entity.ts | 61 +++ .../filters-multiple-where-clauses/example.ts | 16 + .../filters-multiple-where-clauses/table.ts | 52 ++ .../examples/filters-name-function/entity.ts | 125 +++++ .../examples/filters-name-function/example.ts | 10 + .../examples/filters-name-function/table.ts | 100 ++++ .../examples/filters-value-function/entity.ts | 125 +++++ .../filters-value-function/example.ts | 10 + .../examples/filters-value-function/table.ts | 100 ++++ .../examples/filters-where-chained/entity.ts | 125 +++++ .../examples/filters-where-chained/example.ts | 13 + .../examples/filters-where-chained/table.ts | 100 ++++ .../filters-where-destructured/entity.ts | 125 +++++ .../filters-where-destructured/example.ts | 6 + .../filters-where-destructured/table.ts | 100 ++++ .../examples/filters-where-dynamic/entity.ts | 125 +++++ .../examples/filters-where-dynamic/example.ts | 19 + .../examples/filters-where-dynamic/table.ts | 100 ++++ .../filters-where-list-attribute/entity.ts | 125 +++++ .../filters-where-list-attribute/example.ts | 6 + .../filters-where-list-attribute/table.ts | 100 ++++ .../filters-where-map-attribute/entity.ts | 125 +++++ .../filters-where-map-attribute/example.ts | 6 + .../filters-where-map-attribute/table.ts | 100 ++++ .../examples/filters-where-multiple/entity.ts | 125 +++++ .../filters-where-multiple/example.ts | 10 + .../examples/filters-where-multiple/table.ts | 100 ++++ .../examples/filters-where-single/entity.ts | 125 +++++ .../examples/filters-where-single/example.ts | 6 + .../examples/filters-where-single/table.ts | 100 ++++ .../examples/find-store-location/entity.ts | 125 +++++ .../examples/find-store-location/example.ts | 6 + www/src/examples/find-store-location/table.ts | 76 +++ .../human-resources-assignments/entities.ts | 229 +++++++++ .../human-resources-assignments/example.ts | 3 + .../human-resources-assignments/service.ts | 8 + .../human-resources-assignments/table.ts | 148 ++++++ .../human-resources-birthdays/entities.ts | 229 +++++++++ .../human-resources-birthdays/service.ts | 8 + .../human-resources-birthdays/table.ts | 148 ++++++ .../entities.ts | 229 +++++++++ .../human-resources-direct-reports/service.ts | 8 + .../human-resources-direct-reports/table.ts | 148 ++++++ .../entities.ts | 229 +++++++++ .../human-resources-employee-roles/service.ts | 8 + .../human-resources-employee-roles/table.ts | 148 ++++++ .../entities.ts | 229 +++++++++ .../human-resources-employee-tasks/example.ts | 8 + .../human-resources-employee-tasks/service.ts | 8 + .../human-resources-employee-tasks/table.ts | 148 ++++++ .../entities.ts | 229 +++++++++ .../service.ts | 8 + .../human-resources-office-locations/table.ts | 148 ++++++ .../human-resources-project-tasks/entities.ts | 229 +++++++++ .../human-resources-project-tasks/example.ts | 10 + .../human-resources-project-tasks/service.ts | 8 + .../human-resources-project-tasks/table.ts | 148 ++++++ .../human-resources-workplaces/entities.ts | 229 +++++++++ .../human-resources-workplaces/example.ts | 3 + .../human-resources-workplaces/service.ts | 8 + .../human-resources-workplaces/table.ts | 148 ++++++ .../entity.ts | 67 +++ .../example.ts | 6 + .../table.ts | 53 ++ .../entity.ts | 67 +++ .../example.ts | 8 + .../table.ts | 53 ++ .../entity.ts | 67 +++ .../example.ts | 7 + .../table.ts | 53 ++ .../entity.ts | 67 +++ .../example.ts | 11 + .../table.ts | 53 ++ .../entity.ts | 67 +++ .../example.ts | 9 + .../include-projection-gsi-hydration/table.ts | 53 ++ .../entity.ts | 37 ++ .../example.ts | 8 + .../table.ts | 26 + .../entity.ts | 74 +++ .../example.ts | 5 + .../table.ts | 34 ++ .../indexes-multi-attribute-begins/entity.ts | 74 +++ .../indexes-multi-attribute-begins/example.ts | 6 + .../indexes-multi-attribute-begins/table.ts | 34 ++ .../indexes-multi-attribute-between/entity.ts | 74 +++ .../example.ts | 9 + .../indexes-multi-attribute-between/table.ts | 34 ++ .../entities.ts | 131 +++++ .../example.ts | 8 + .../service.ts | 4 + .../table.ts | 32 ++ .../entities.ts | 131 +++++ .../example.ts | 7 + .../service.ts | 4 + .../table.ts | 32 ++ .../indexes-multi-attribute-gt/entity.ts | 74 +++ .../indexes-multi-attribute-gt/example.ts | 6 + .../indexes-multi-attribute-gt/table.ts | 34 ++ .../indexes-scope-with-scope/entities.ts | 60 +++ .../indexes-scope-with-scope/example.ts | 5 + .../indexes-scope-with-scope/table.ts | 26 + .../indexes-scope-without-scope/entities.ts | 58 +++ .../indexes-scope-without-scope/example.ts | 5 + .../indexes-scope-without-scope/table.ts | 26 + .../introduction-patch-task/entity.ts | 122 +++++ .../introduction-patch-task/example.ts | 15 + .../examples/introduction-patch-task/table.ts | 76 +++ .../item-counters-read-select/entities.ts | 69 +++ .../item-counters-read-select/example.ts | 133 +++++ .../item-counters-read-select/service.ts | 4 + .../item-counters-read-select/table.ts | 26 + .../entities.ts | 146 ++++++ .../example.ts | 53 ++ .../service.ts | 14 + .../item-counters-write-transaction/table.ts | 26 + .../keys-only-gsi-hydrate-query/entity.ts | 63 +++ .../keys-only-gsi-hydrate-query/example.ts | 6 + .../keys-only-gsi-hydrate-query/table.ts | 52 ++ .../keys-only-gsi-include-keys/entity.ts | 63 +++ .../keys-only-gsi-include-keys/example.ts | 6 + .../keys-only-gsi-include-keys/table.ts | 52 ++ .../keys-only-gsi-raw-response/entity.ts | 63 +++ .../keys-only-gsi-raw-response/example.ts | 7 + .../keys-only-gsi-raw-response/table.ts | 52 ++ .../examples/match-store-location/entity.ts | 125 +++++ .../examples/match-store-location/example.ts | 8 + .../examples/match-store-location/table.ts | 76 +++ www/src/examples/pagination-count/entity.ts | 125 +++++ www/src/examples/pagination-count/example.ts | 19 + www/src/examples/pagination-count/table.ts | 76 +++ .../examples/pagination-entities/entity.ts | 125 +++++ .../examples/pagination-entities/example.ts | 9 + www/src/examples/pagination-entities/table.ts | 76 +++ www/src/examples/pagination-example/entity.ts | 50 ++ .../examples/pagination-example/example.ts | 25 + www/src/examples/pagination-example/table.ts | 52 ++ .../patch-complex-nested-set/entity.ts | 55 ++ .../patch-complex-nested-set/example.ts | 21 + .../patch-complex-nested-set/table.ts | 26 + .../patch-organization-composite/entity.ts | 60 +++ .../patch-organization-composite/example.ts | 9 + .../patch-organization-composite/table.ts | 52 ++ .../patch-store-location-add/entity.ts | 125 +++++ .../patch-store-location-add/example.ts | 14 + .../patch-store-location-add/table.ts | 76 +++ .../patch-store-location-append/entity.ts | 125 +++++ .../patch-store-location-append/example.ts | 18 + .../patch-store-location-append/table.ts | 76 +++ .../patch-store-location-data/entity.ts | 135 +++++ .../patch-store-location-data/example.ts | 28 + .../patch-store-location-data/table.ts | 76 +++ .../patch-store-location-delete/entity.ts | 129 +++++ .../patch-store-location-delete/example.ts | 11 + .../patch-store-location-delete/table.ts | 76 +++ .../patch-store-location-remove/entity.ts | 125 +++++ .../patch-store-location-remove/example.ts | 11 + .../patch-store-location-remove/table.ts | 76 +++ .../patch-store-location-set/entity.ts | 125 +++++ .../patch-store-location-set/example.ts | 11 + .../patch-store-location-set/table.ts | 76 +++ .../patch-store-location-subtract/entity.ts | 125 +++++ .../patch-store-location-subtract/example.ts | 11 + .../patch-store-location-subtract/table.ts | 76 +++ www/src/examples/patch-tasks/entity.ts | 122 +++++ www/src/examples/patch-tasks/example.ts | 20 + www/src/examples/patch-tasks/table.ts | 76 +++ .../patch-update-composite-edgecase/entity.ts | 53 ++ .../example.ts | 6 + .../patch-update-composite-edgecase/table.ts | 52 ++ .../query-bad-missing-pk-attribute/entity.ts | 125 +++++ .../query-bad-missing-pk-attribute/example.ts | 8 + .../query-bad-missing-pk-attribute/table.ts | 76 +++ www/src/examples/query-bad-no-pk/entity.ts | 125 +++++ www/src/examples/query-bad-no-pk/example.ts | 4 + www/src/examples/query-bad-no-pk/table.ts | 76 +++ .../examples/query-bad-out-of-order/entity.ts | 125 +++++ .../query-bad-out-of-order/example.ts | 9 + .../examples/query-bad-out-of-order/table.ts | 76 +++ .../query-good-includes-all-sk/entity.ts | 125 +++++ .../query-good-includes-all-sk/example.ts | 10 + .../query-good-includes-all-sk/table.ts | 76 +++ .../query-good-includes-pk-first-sk/entity.ts | 125 +++++ .../example.ts | 9 + .../query-good-includes-pk-first-sk/table.ts | 76 +++ .../examples/query-good-includes-pk/entity.ts | 125 +++++ .../query-good-includes-pk/example.ts | 8 + .../examples/query-good-includes-pk/table.ts | 76 +++ .../entity.ts | 125 +++++ .../example.ts | 6 + .../table.ts | 76 +++ .../entity.ts | 125 +++++ .../example.ts | 6 + .../query-leases-by-store-id-between/table.ts | 76 +++ .../query-leases-by-store-id-date/entity.ts | 125 +++++ .../query-leases-by-store-id-date/example.ts | 8 + .../query-leases-by-store-id-date/table.ts | 76 +++ .../query-leases-by-store-id-gt/entity.ts | 125 +++++ .../query-leases-by-store-id-gt/example.ts | 6 + .../query-leases-by-store-id-gt/table.ts | 76 +++ .../entity.ts | 125 +++++ .../example.ts | 14 + .../table.ts | 76 +++ .../query-leases-by-store-id-gte/entity.ts | 125 +++++ .../query-leases-by-store-id-gte/example.ts | 6 + .../query-leases-by-store-id-gte/table.ts | 76 +++ .../query-leases-by-store-id-lt/entity.ts | 125 +++++ .../query-leases-by-store-id-lt/example.ts | 6 + .../query-leases-by-store-id-lt/table.ts | 76 +++ .../query-leases-by-store-id-lte/entity.ts | 125 +++++ .../query-leases-by-store-id-lte/example.ts | 6 + .../query-leases-by-store-id-lte/table.ts | 76 +++ .../query-leases-by-store-id/entity.ts | 125 +++++ .../query-leases-by-store-id/example.ts | 3 + .../query-leases-by-store-id/table.ts | 76 +++ .../examples/query-units-example-1/entity.ts | 125 +++++ .../examples/query-units-example-1/example.ts | 7 + .../examples/query-units-example-1/table.ts | 76 +++ .../examples/query-units-example-2/entity.ts | 125 +++++ .../examples/query-units-example-2/example.ts | 8 + .../examples/query-units-example-2/table.ts | 76 +++ .../quick-start-books-by-author/entity.ts | 65 +++ .../quick-start-books-by-author/example.ts | 5 + .../quick-start-books-by-author/table.ts | 52 ++ .../entity.ts | 65 +++ .../example.ts | 6 + .../table.ts | 52 ++ .../quick-start-create-book/entity.ts | 65 +++ .../quick-start-create-book/example.ts | 12 + .../examples/quick-start-create-book/table.ts | 52 ++ .../examples/quick-start-get-book/entity.ts | 65 +++ .../examples/quick-start-get-book/example.ts | 6 + .../examples/quick-start-get-book/table.ts | 52 ++ .../quick-start-update-book/entity.ts | 65 +++ .../quick-start-update-book/example.ts | 11 + .../examples/quick-start-update-book/table.ts | 52 ++ .../examples/remove-store-location/entity.ts | 125 +++++ .../examples/remove-store-location/example.ts | 8 + .../examples/remove-store-location/table.ts | 76 +++ .../examples/scan-store-location/entity.ts | 125 +++++ .../examples/scan-store-location/example.ts | 14 + www/src/examples/scan-store-location/table.ts | 76 +++ www/src/examples/scan-units-index/entity.ts | 125 +++++ www/src/examples/scan-units-index/example.ts | 3 + www/src/examples/scan-units-index/table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 12 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 8 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 8 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 10 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 9 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 10 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 11 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 9 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 6 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 5 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 9 + .../table.ts | 76 +++ .../entity.ts | 96 ++++ .../example.ts | 9 + .../table.ts | 76 +++ .../task-manager-assignments/entities.ts | 287 +++++++++++ .../task-manager-assignments/example.ts | 5 + .../task-manager-assignments/service.ts | 8 + .../task-manager-assignments/table.ts | 148 ++++++ .../task-manager-create-task/entities.ts | 287 +++++++++++ .../task-manager-create-task/example.ts | 17 + .../task-manager-create-task/service.ts | 8 + .../task-manager-create-task/table.ts | 148 ++++++ .../entities.ts | 287 +++++++++++ .../task-manager-junior-developers/example.ts | 9 + .../task-manager-junior-developers/service.ts | 8 + .../task-manager-junior-developers/table.ts | 148 ++++++ .../task-manager-open-tasks/entities.ts | 287 +++++++++++ .../task-manager-open-tasks/example.ts | 9 + .../task-manager-open-tasks/service.ts | 8 + .../examples/task-manager-open-tasks/table.ts | 148 ++++++ .../task-manager-recent-hires/entities.ts | 287 +++++++++++ .../task-manager-recent-hires/example.ts | 16 + .../task-manager-recent-hires/service.ts | 8 + .../task-manager-recent-hires/table.ts | 148 ++++++ .../task-manager-workplace/entities.ts | 287 +++++++++++ .../task-manager-workplace/example.ts | 5 + .../task-manager-workplace/service.ts | 8 + .../examples/task-manager-workplace/table.ts | 148 ++++++ .../entities.ts | 83 +++ .../example.ts | 8 + .../service.ts | 4 + .../transact-get-employee-and-office/table.ts | 26 + .../entities.ts | 100 ++++ .../example.ts | 36 ++ .../service.ts | 4 + .../transact-write-idempotent-writes/table.ts | 52 ++ .../entities.ts | 100 ++++ .../example.ts | 28 + .../service.ts | 4 + .../transact-write-unique-constraint/table.ts | 52 ++ .../entity.ts | 54 ++ .../example.ts | 6 + .../table.ts | 52 ++ .../update-list-element-remove/entity.ts | 63 +++ .../update-list-element-remove/example.ts | 17 + .../update-list-element-remove/table.ts | 76 +++ .../examples/update-map-property/entity.ts | 63 +++ .../examples/update-map-property/example.ts | 17 + www/src/examples/update-map-property/table.ts | 76 +++ .../examples/update-nested-set-add/entity.ts | 63 +++ .../examples/update-nested-set-add/example.ts | 22 + .../examples/update-nested-set-add/table.ts | 76 +++ .../update-organization-composite/entity.ts | 60 +++ .../update-organization-composite/example.ts | 11 + .../update-organization-composite/table.ts | 52 ++ .../update-store-location-add/entity.ts | 125 +++++ .../update-store-location-add/example.ts | 14 + .../update-store-location-add/table.ts | 76 +++ .../update-store-location-append/entity.ts | 125 +++++ .../update-store-location-append/example.ts | 18 + .../update-store-location-append/table.ts | 76 +++ .../update-store-location-data/entity.ts | 135 +++++ .../update-store-location-data/example.ts | 28 + .../update-store-location-data/table.ts | 76 +++ .../update-store-location-delete/entity.ts | 129 +++++ .../update-store-location-delete/example.ts | 11 + .../update-store-location-delete/table.ts | 76 +++ .../update-store-location-remove/entity.ts | 125 +++++ .../update-store-location-remove/example.ts | 11 + .../update-store-location-remove/table.ts | 76 +++ .../update-store-location-set/entity.ts | 125 +++++ .../update-store-location-set/example.ts | 11 + .../update-store-location-set/table.ts | 76 +++ .../update-store-location-subtract/entity.ts | 125 +++++ .../update-store-location-subtract/example.ts | 11 + .../update-store-location-subtract/table.ts | 76 +++ .../update-tasks-set-add-append/entity.ts | 122 +++++ .../update-tasks-set-add-append/example.ts | 20 + .../update-tasks-set-add-append/table.ts | 76 +++ .../entity.ts | 128 +++++ .../example.ts | 24 + .../table.ts | 76 +++ .../examples/upsert-store-location/entity.ts | 125 +++++ .../examples/upsert-store-location/example.ts | 12 + .../examples/upsert-store-location/table.ts | 76 +++ .../en/core-concepts/executing-queries.mdx | 39 +- .../pages/en/core-concepts/introduction.mdx | 57 +-- .../pages/en/core-concepts/quick-start.mdx | 46 +- .../en/examples/shopping-mall-directory.mdx | 178 +------ www/src/pages/en/examples/task-manager.mdx | 53 +- www/src/pages/en/modeling/collections.mdx | 155 +----- www/src/pages/en/modeling/indexes.mdx | 168 +----- www/src/pages/en/mutations/batch-delete.mdx | 50 +- www/src/pages/en/mutations/batch-put.mdx | 88 +--- www/src/pages/en/mutations/conditions.mdx | 293 +---------- www/src/pages/en/mutations/create.mdx | 55 +- www/src/pages/en/mutations/delete.mdx | 27 +- www/src/pages/en/mutations/remove.mdx | 28 +- www/src/pages/en/mutations/transact-write.mdx | 215 +------- www/src/pages/en/mutations/update.mdx | 482 +----------------- www/src/pages/en/mutations/upsert.mdx | 155 +----- www/src/pages/en/queries/batch-get.mdx | 46 +- www/src/pages/en/queries/collection.mdx | 158 +----- www/src/pages/en/queries/filters.mdx | 201 +------- www/src/pages/en/queries/find.mdx | 35 +- www/src/pages/en/queries/match.mdx | 42 +- www/src/pages/en/queries/pagination.mdx | 89 +--- www/src/pages/en/queries/query.mdx | 136 +---- www/src/pages/en/queries/scan.mdx | 52 +- www/src/pages/en/queries/transact-get.mdx | 17 +- .../en/recipes/include-projection-gsi.mdx | 197 +------ www/src/pages/en/recipes/item-counters.mdx | 234 +-------- www/src/pages/en/recipes/keys-only-gsi.mdx | 163 +----- .../use-electrodb-with-existing-table.mdx | 10 +- 516 files changed, 31542 insertions(+), 3227 deletions(-) create mode 100644 www/src/examples/batch-delete-store-locations/entity.ts create mode 100644 www/src/examples/batch-delete-store-locations/example.ts create mode 100644 www/src/examples/batch-delete-store-locations/table.ts create mode 100644 www/src/examples/batch-get-store-locations/entity.ts create mode 100644 www/src/examples/batch-get-store-locations/example.ts create mode 100644 www/src/examples/batch-get-store-locations/table.ts create mode 100644 www/src/examples/batch-put-store-locations/entity.ts create mode 100644 www/src/examples/batch-put-store-locations/example.ts create mode 100644 www/src/examples/batch-put-store-locations/table.ts create mode 100644 www/src/examples/collection-assignments-filtered/entities.ts create mode 100644 www/src/examples/collection-assignments-filtered/example.ts create mode 100644 www/src/examples/collection-assignments-filtered/service.ts create mode 100644 www/src/examples/collection-assignments-filtered/table.ts create mode 100644 www/src/examples/collection-assignments/entities.ts create mode 100644 www/src/examples/collection-assignments/example.ts create mode 100644 www/src/examples/collection-assignments/service.ts create mode 100644 www/src/examples/collection-assignments/table.ts create mode 100644 www/src/examples/collections-collection-query-assignments/entities.ts create mode 100644 www/src/examples/collections-collection-query-assignments/example.ts create mode 100644 www/src/examples/collections-collection-query-assignments/service.ts create mode 100644 www/src/examples/collections-collection-query-assignments/table.ts create mode 100644 www/src/examples/collections-complex-assignments/entities.ts create mode 100644 www/src/examples/collections-complex-assignments/example.ts create mode 100644 www/src/examples/collections-complex-assignments/service.ts create mode 100644 www/src/examples/collections-complex-assignments/table.ts create mode 100644 www/src/examples/collections-complex-contributions/entities.ts create mode 100644 www/src/examples/collections-complex-contributions/example.ts create mode 100644 www/src/examples/collections-complex-contributions/service.ts create mode 100644 www/src/examples/collections-complex-contributions/table.ts create mode 100644 www/src/examples/collections-entity-query-assigned/entities.ts create mode 100644 www/src/examples/collections-entity-query-assigned/example.ts create mode 100644 www/src/examples/collections-entity-query-assigned/service.ts create mode 100644 www/src/examples/collections-entity-query-assigned/table.ts create mode 100644 www/src/examples/collections-index-naming-staff/entity.ts create mode 100644 www/src/examples/collections-index-naming-staff/example.ts create mode 100644 www/src/examples/collections-index-naming-staff/table.ts create mode 100644 www/src/examples/collections-response-structure-assignments/entities.ts create mode 100644 www/src/examples/collections-response-structure-assignments/example.ts create mode 100644 www/src/examples/collections-response-structure-assignments/service.ts create mode 100644 www/src/examples/collections-response-structure-assignments/table.ts create mode 100644 www/src/examples/collections-simple-overview/entities.ts create mode 100644 www/src/examples/collections-simple-overview/example.ts create mode 100644 www/src/examples/collections-simple-overview/service.ts create mode 100644 www/src/examples/collections-simple-overview/table.ts create mode 100644 www/src/examples/collections-subcollection-assignments/entities.ts create mode 100644 www/src/examples/collections-subcollection-assignments/example.ts create mode 100644 www/src/examples/collections-subcollection-assignments/service.ts create mode 100644 www/src/examples/collections-subcollection-assignments/table.ts create mode 100644 www/src/examples/collections-taskapp-assignments/entities.ts create mode 100644 www/src/examples/collections-taskapp-assignments/example.ts create mode 100644 www/src/examples/collections-taskapp-assignments/service.ts create mode 100644 www/src/examples/collections-taskapp-assignments/table.ts create mode 100644 www/src/examples/conditions-condition-expression/entity.ts create mode 100644 www/src/examples/conditions-condition-expression/example.ts create mode 100644 www/src/examples/conditions-condition-expression/table.ts create mode 100644 www/src/examples/conditions-conditional-update/entity.ts create mode 100644 www/src/examples/conditions-conditional-update/example.ts create mode 100644 www/src/examples/conditions-conditional-update/table.ts create mode 100644 www/src/examples/conditions-detect-rejection-only/entity.ts create mode 100644 www/src/examples/conditions-detect-rejection-only/example.ts create mode 100644 www/src/examples/conditions-detect-rejection-only/table.ts create mode 100644 www/src/examples/conditions-multiple-where-clauses/entity.ts create mode 100644 www/src/examples/conditions-multiple-where-clauses/example.ts create mode 100644 www/src/examples/conditions-multiple-where-clauses/table.ts create mode 100644 www/src/examples/conditions-safe-create/entity.ts create mode 100644 www/src/examples/conditions-safe-create/example.ts create mode 100644 www/src/examples/conditions-safe-create/table.ts create mode 100644 www/src/examples/conditions-where-chained/entity.ts create mode 100644 www/src/examples/conditions-where-chained/example.ts create mode 100644 www/src/examples/conditions-where-chained/table.ts create mode 100644 www/src/examples/conditions-where-destructured/entity.ts create mode 100644 www/src/examples/conditions-where-destructured/example.ts create mode 100644 www/src/examples/conditions-where-destructured/table.ts create mode 100644 www/src/examples/conditions-where-dynamic-filtering/entity.ts create mode 100644 www/src/examples/conditions-where-dynamic-filtering/example.ts create mode 100644 www/src/examples/conditions-where-dynamic-filtering/table.ts create mode 100644 www/src/examples/conditions-where-escape-function/entity.ts create mode 100644 www/src/examples/conditions-where-escape-function/example.ts create mode 100644 www/src/examples/conditions-where-escape-function/table.ts create mode 100644 www/src/examples/conditions-where-field-function/entity.ts create mode 100644 www/src/examples/conditions-where-field-function/example.ts create mode 100644 www/src/examples/conditions-where-field-function/table.ts create mode 100644 www/src/examples/conditions-where-list-attribute/entity.ts create mode 100644 www/src/examples/conditions-where-list-attribute/example.ts create mode 100644 www/src/examples/conditions-where-list-attribute/table.ts create mode 100644 www/src/examples/conditions-where-map-attribute/entity.ts create mode 100644 www/src/examples/conditions-where-map-attribute/example.ts create mode 100644 www/src/examples/conditions-where-map-attribute/table.ts create mode 100644 www/src/examples/conditions-where-multiple-conditions/entity.ts create mode 100644 www/src/examples/conditions-where-multiple-conditions/example.ts create mode 100644 www/src/examples/conditions-where-multiple-conditions/table.ts create mode 100644 www/src/examples/conditions-where-name-function/entity.ts create mode 100644 www/src/examples/conditions-where-name-function/example.ts create mode 100644 www/src/examples/conditions-where-name-function/table.ts create mode 100644 www/src/examples/conditions-where-single-filter/entity.ts create mode 100644 www/src/examples/conditions-where-single-filter/example.ts create mode 100644 www/src/examples/conditions-where-single-filter/table.ts create mode 100644 www/src/examples/conditions-where-value-function/entity.ts create mode 100644 www/src/examples/conditions-where-value-function/example.ts create mode 100644 www/src/examples/conditions-where-value-function/table.ts create mode 100644 www/src/examples/create-store-location/entity.ts create mode 100644 www/src/examples/create-store-location/example.ts create mode 100644 www/src/examples/create-store-location/table.ts create mode 100644 www/src/examples/delete-store-location/entity.ts create mode 100644 www/src/examples/delete-store-location/example.ts create mode 100644 www/src/examples/delete-store-location/table.ts create mode 100644 www/src/examples/executing-queries-go/entity.ts create mode 100644 www/src/examples/executing-queries-go/example.ts create mode 100644 www/src/examples/executing-queries-go/table.ts create mode 100644 www/src/examples/executing-queries-params/entity.ts create mode 100644 www/src/examples/executing-queries-params/example.ts create mode 100644 www/src/examples/executing-queries-params/table.ts create mode 100644 www/src/examples/existing-table-ignore-ownership/entity.ts create mode 100644 www/src/examples/existing-table-ignore-ownership/example.ts create mode 100644 www/src/examples/existing-table-ignore-ownership/table.ts create mode 100644 www/src/examples/filters-escape-function/entity.ts create mode 100644 www/src/examples/filters-escape-function/example.ts create mode 100644 www/src/examples/filters-escape-function/table.ts create mode 100644 www/src/examples/filters-field-function/entity.ts create mode 100644 www/src/examples/filters-field-function/example.ts create mode 100644 www/src/examples/filters-field-function/table.ts create mode 100644 www/src/examples/filters-filter-expression/entity.ts create mode 100644 www/src/examples/filters-filter-expression/example.ts create mode 100644 www/src/examples/filters-filter-expression/table.ts create mode 100644 www/src/examples/filters-multiple-where-clauses/entity.ts create mode 100644 www/src/examples/filters-multiple-where-clauses/example.ts create mode 100644 www/src/examples/filters-multiple-where-clauses/table.ts create mode 100644 www/src/examples/filters-name-function/entity.ts create mode 100644 www/src/examples/filters-name-function/example.ts create mode 100644 www/src/examples/filters-name-function/table.ts create mode 100644 www/src/examples/filters-value-function/entity.ts create mode 100644 www/src/examples/filters-value-function/example.ts create mode 100644 www/src/examples/filters-value-function/table.ts create mode 100644 www/src/examples/filters-where-chained/entity.ts create mode 100644 www/src/examples/filters-where-chained/example.ts create mode 100644 www/src/examples/filters-where-chained/table.ts create mode 100644 www/src/examples/filters-where-destructured/entity.ts create mode 100644 www/src/examples/filters-where-destructured/example.ts create mode 100644 www/src/examples/filters-where-destructured/table.ts create mode 100644 www/src/examples/filters-where-dynamic/entity.ts create mode 100644 www/src/examples/filters-where-dynamic/example.ts create mode 100644 www/src/examples/filters-where-dynamic/table.ts create mode 100644 www/src/examples/filters-where-list-attribute/entity.ts create mode 100644 www/src/examples/filters-where-list-attribute/example.ts create mode 100644 www/src/examples/filters-where-list-attribute/table.ts create mode 100644 www/src/examples/filters-where-map-attribute/entity.ts create mode 100644 www/src/examples/filters-where-map-attribute/example.ts create mode 100644 www/src/examples/filters-where-map-attribute/table.ts create mode 100644 www/src/examples/filters-where-multiple/entity.ts create mode 100644 www/src/examples/filters-where-multiple/example.ts create mode 100644 www/src/examples/filters-where-multiple/table.ts create mode 100644 www/src/examples/filters-where-single/entity.ts create mode 100644 www/src/examples/filters-where-single/example.ts create mode 100644 www/src/examples/filters-where-single/table.ts create mode 100644 www/src/examples/find-store-location/entity.ts create mode 100644 www/src/examples/find-store-location/example.ts create mode 100644 www/src/examples/find-store-location/table.ts create mode 100644 www/src/examples/human-resources-assignments/entities.ts create mode 100644 www/src/examples/human-resources-assignments/example.ts create mode 100644 www/src/examples/human-resources-assignments/service.ts create mode 100644 www/src/examples/human-resources-assignments/table.ts create mode 100644 www/src/examples/human-resources-birthdays/entities.ts create mode 100644 www/src/examples/human-resources-birthdays/service.ts create mode 100644 www/src/examples/human-resources-birthdays/table.ts create mode 100644 www/src/examples/human-resources-direct-reports/entities.ts create mode 100644 www/src/examples/human-resources-direct-reports/service.ts create mode 100644 www/src/examples/human-resources-direct-reports/table.ts create mode 100644 www/src/examples/human-resources-employee-roles/entities.ts create mode 100644 www/src/examples/human-resources-employee-roles/service.ts create mode 100644 www/src/examples/human-resources-employee-roles/table.ts create mode 100644 www/src/examples/human-resources-employee-tasks/entities.ts create mode 100644 www/src/examples/human-resources-employee-tasks/example.ts create mode 100644 www/src/examples/human-resources-employee-tasks/service.ts create mode 100644 www/src/examples/human-resources-employee-tasks/table.ts create mode 100644 www/src/examples/human-resources-office-locations/entities.ts create mode 100644 www/src/examples/human-resources-office-locations/service.ts create mode 100644 www/src/examples/human-resources-office-locations/table.ts create mode 100644 www/src/examples/human-resources-project-tasks/entities.ts create mode 100644 www/src/examples/human-resources-project-tasks/example.ts create mode 100644 www/src/examples/human-resources-project-tasks/service.ts create mode 100644 www/src/examples/human-resources-project-tasks/table.ts create mode 100644 www/src/examples/human-resources-workplaces/entities.ts create mode 100644 www/src/examples/human-resources-workplaces/example.ts create mode 100644 www/src/examples/human-resources-workplaces/service.ts create mode 100644 www/src/examples/human-resources-workplaces/table.ts create mode 100644 www/src/examples/include-projection-gsi-basic-query/entity.ts create mode 100644 www/src/examples/include-projection-gsi-basic-query/example.ts create mode 100644 www/src/examples/include-projection-gsi-basic-query/table.ts create mode 100644 www/src/examples/include-projection-gsi-filter-non-projected/entity.ts create mode 100644 www/src/examples/include-projection-gsi-filter-non-projected/example.ts create mode 100644 www/src/examples/include-projection-gsi-filter-non-projected/table.ts create mode 100644 www/src/examples/include-projection-gsi-filter-projected/entity.ts create mode 100644 www/src/examples/include-projection-gsi-filter-projected/example.ts create mode 100644 www/src/examples/include-projection-gsi-filter-projected/table.ts create mode 100644 www/src/examples/include-projection-gsi-hydration-attributes/entity.ts create mode 100644 www/src/examples/include-projection-gsi-hydration-attributes/example.ts create mode 100644 www/src/examples/include-projection-gsi-hydration-attributes/table.ts create mode 100644 www/src/examples/include-projection-gsi-hydration/entity.ts create mode 100644 www/src/examples/include-projection-gsi-hydration/example.ts create mode 100644 www/src/examples/include-projection-gsi-hydration/table.ts create mode 100644 www/src/examples/indexes-attributes-as-indexes-get/entity.ts create mode 100644 www/src/examples/indexes-attributes-as-indexes-get/example.ts create mode 100644 www/src/examples/indexes-attributes-as-indexes-get/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-basic-query/entity.ts create mode 100644 www/src/examples/indexes-multi-attribute-basic-query/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-basic-query/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-begins/entity.ts create mode 100644 www/src/examples/indexes-multi-attribute-begins/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-begins/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-between/entity.ts create mode 100644 www/src/examples/indexes-multi-attribute-between/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-between/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-begins/entities.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-begins/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-begins/service.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-begins/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-query/entities.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-query/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-query/service.ts create mode 100644 www/src/examples/indexes-multi-attribute-collection-query/table.ts create mode 100644 www/src/examples/indexes-multi-attribute-gt/entity.ts create mode 100644 www/src/examples/indexes-multi-attribute-gt/example.ts create mode 100644 www/src/examples/indexes-multi-attribute-gt/table.ts create mode 100644 www/src/examples/indexes-scope-with-scope/entities.ts create mode 100644 www/src/examples/indexes-scope-with-scope/example.ts create mode 100644 www/src/examples/indexes-scope-with-scope/table.ts create mode 100644 www/src/examples/indexes-scope-without-scope/entities.ts create mode 100644 www/src/examples/indexes-scope-without-scope/example.ts create mode 100644 www/src/examples/indexes-scope-without-scope/table.ts create mode 100644 www/src/examples/introduction-patch-task/entity.ts create mode 100644 www/src/examples/introduction-patch-task/example.ts create mode 100644 www/src/examples/introduction-patch-task/table.ts create mode 100644 www/src/examples/item-counters-read-select/entities.ts create mode 100644 www/src/examples/item-counters-read-select/example.ts create mode 100644 www/src/examples/item-counters-read-select/service.ts create mode 100644 www/src/examples/item-counters-read-select/table.ts create mode 100644 www/src/examples/item-counters-write-transaction/entities.ts create mode 100644 www/src/examples/item-counters-write-transaction/example.ts create mode 100644 www/src/examples/item-counters-write-transaction/service.ts create mode 100644 www/src/examples/item-counters-write-transaction/table.ts create mode 100644 www/src/examples/keys-only-gsi-hydrate-query/entity.ts create mode 100644 www/src/examples/keys-only-gsi-hydrate-query/example.ts create mode 100644 www/src/examples/keys-only-gsi-hydrate-query/table.ts create mode 100644 www/src/examples/keys-only-gsi-include-keys/entity.ts create mode 100644 www/src/examples/keys-only-gsi-include-keys/example.ts create mode 100644 www/src/examples/keys-only-gsi-include-keys/table.ts create mode 100644 www/src/examples/keys-only-gsi-raw-response/entity.ts create mode 100644 www/src/examples/keys-only-gsi-raw-response/example.ts create mode 100644 www/src/examples/keys-only-gsi-raw-response/table.ts create mode 100644 www/src/examples/match-store-location/entity.ts create mode 100644 www/src/examples/match-store-location/example.ts create mode 100644 www/src/examples/match-store-location/table.ts create mode 100644 www/src/examples/pagination-count/entity.ts create mode 100644 www/src/examples/pagination-count/example.ts create mode 100644 www/src/examples/pagination-count/table.ts create mode 100644 www/src/examples/pagination-entities/entity.ts create mode 100644 www/src/examples/pagination-entities/example.ts create mode 100644 www/src/examples/pagination-entities/table.ts create mode 100644 www/src/examples/pagination-example/entity.ts create mode 100644 www/src/examples/pagination-example/example.ts create mode 100644 www/src/examples/pagination-example/table.ts create mode 100644 www/src/examples/patch-complex-nested-set/entity.ts create mode 100644 www/src/examples/patch-complex-nested-set/example.ts create mode 100644 www/src/examples/patch-complex-nested-set/table.ts create mode 100644 www/src/examples/patch-organization-composite/entity.ts create mode 100644 www/src/examples/patch-organization-composite/example.ts create mode 100644 www/src/examples/patch-organization-composite/table.ts create mode 100644 www/src/examples/patch-store-location-add/entity.ts create mode 100644 www/src/examples/patch-store-location-add/example.ts create mode 100644 www/src/examples/patch-store-location-add/table.ts create mode 100644 www/src/examples/patch-store-location-append/entity.ts create mode 100644 www/src/examples/patch-store-location-append/example.ts create mode 100644 www/src/examples/patch-store-location-append/table.ts create mode 100644 www/src/examples/patch-store-location-data/entity.ts create mode 100644 www/src/examples/patch-store-location-data/example.ts create mode 100644 www/src/examples/patch-store-location-data/table.ts create mode 100644 www/src/examples/patch-store-location-delete/entity.ts create mode 100644 www/src/examples/patch-store-location-delete/example.ts create mode 100644 www/src/examples/patch-store-location-delete/table.ts create mode 100644 www/src/examples/patch-store-location-remove/entity.ts create mode 100644 www/src/examples/patch-store-location-remove/example.ts create mode 100644 www/src/examples/patch-store-location-remove/table.ts create mode 100644 www/src/examples/patch-store-location-set/entity.ts create mode 100644 www/src/examples/patch-store-location-set/example.ts create mode 100644 www/src/examples/patch-store-location-set/table.ts create mode 100644 www/src/examples/patch-store-location-subtract/entity.ts create mode 100644 www/src/examples/patch-store-location-subtract/example.ts create mode 100644 www/src/examples/patch-store-location-subtract/table.ts create mode 100644 www/src/examples/patch-tasks/entity.ts create mode 100644 www/src/examples/patch-tasks/example.ts create mode 100644 www/src/examples/patch-tasks/table.ts create mode 100644 www/src/examples/patch-update-composite-edgecase/entity.ts create mode 100644 www/src/examples/patch-update-composite-edgecase/example.ts create mode 100644 www/src/examples/patch-update-composite-edgecase/table.ts create mode 100644 www/src/examples/query-bad-missing-pk-attribute/entity.ts create mode 100644 www/src/examples/query-bad-missing-pk-attribute/example.ts create mode 100644 www/src/examples/query-bad-missing-pk-attribute/table.ts create mode 100644 www/src/examples/query-bad-no-pk/entity.ts create mode 100644 www/src/examples/query-bad-no-pk/example.ts create mode 100644 www/src/examples/query-bad-no-pk/table.ts create mode 100644 www/src/examples/query-bad-out-of-order/entity.ts create mode 100644 www/src/examples/query-bad-out-of-order/example.ts create mode 100644 www/src/examples/query-bad-out-of-order/table.ts create mode 100644 www/src/examples/query-good-includes-all-sk/entity.ts create mode 100644 www/src/examples/query-good-includes-all-sk/example.ts create mode 100644 www/src/examples/query-good-includes-all-sk/table.ts create mode 100644 www/src/examples/query-good-includes-pk-first-sk/entity.ts create mode 100644 www/src/examples/query-good-includes-pk-first-sk/example.ts create mode 100644 www/src/examples/query-good-includes-pk-first-sk/table.ts create mode 100644 www/src/examples/query-good-includes-pk/entity.ts create mode 100644 www/src/examples/query-good-includes-pk/example.ts create mode 100644 www/src/examples/query-good-includes-pk/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-begins-year/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-begins-year/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-begins-year/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-between/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-between/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-between/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-date/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-date/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-date/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-gt/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-gt/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-gt/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte-where/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte-where/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte-where/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-gte/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-lt/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-lt/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-lt/table.ts create mode 100644 www/src/examples/query-leases-by-store-id-lte/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id-lte/example.ts create mode 100644 www/src/examples/query-leases-by-store-id-lte/table.ts create mode 100644 www/src/examples/query-leases-by-store-id/entity.ts create mode 100644 www/src/examples/query-leases-by-store-id/example.ts create mode 100644 www/src/examples/query-leases-by-store-id/table.ts create mode 100644 www/src/examples/query-units-example-1/entity.ts create mode 100644 www/src/examples/query-units-example-1/example.ts create mode 100644 www/src/examples/query-units-example-1/table.ts create mode 100644 www/src/examples/query-units-example-2/entity.ts create mode 100644 www/src/examples/query-units-example-2/example.ts create mode 100644 www/src/examples/query-units-example-2/table.ts create mode 100644 www/src/examples/quick-start-books-by-author/entity.ts create mode 100644 www/src/examples/quick-start-books-by-author/example.ts create mode 100644 www/src/examples/quick-start-books-by-author/table.ts create mode 100644 www/src/examples/quick-start-books-by-store-location/entity.ts create mode 100644 www/src/examples/quick-start-books-by-store-location/example.ts create mode 100644 www/src/examples/quick-start-books-by-store-location/table.ts create mode 100644 www/src/examples/quick-start-create-book/entity.ts create mode 100644 www/src/examples/quick-start-create-book/example.ts create mode 100644 www/src/examples/quick-start-create-book/table.ts create mode 100644 www/src/examples/quick-start-get-book/entity.ts create mode 100644 www/src/examples/quick-start-get-book/example.ts create mode 100644 www/src/examples/quick-start-get-book/table.ts create mode 100644 www/src/examples/quick-start-update-book/entity.ts create mode 100644 www/src/examples/quick-start-update-book/example.ts create mode 100644 www/src/examples/quick-start-update-book/table.ts create mode 100644 www/src/examples/remove-store-location/entity.ts create mode 100644 www/src/examples/remove-store-location/example.ts create mode 100644 www/src/examples/remove-store-location/table.ts create mode 100644 www/src/examples/scan-store-location/entity.ts create mode 100644 www/src/examples/scan-store-location/example.ts create mode 100644 www/src/examples/scan-store-location/table.ts create mode 100644 www/src/examples/scan-units-index/entity.ts create mode 100644 www/src/examples/scan-units-index/example.ts create mode 100644 www/src/examples/scan-units-index/table.ts create mode 100644 www/src/examples/shopping-mall-directory-create-store/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-create-store/example.ts create mode 100644 www/src/examples/shopping-mall-directory-create-store/table.ts create mode 100644 www/src/examples/shopping-mall-directory-delete-store/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-delete-store/example.ts create mode 100644 www/src/examples/shopping-mall-directory-delete-store/table.ts create mode 100644 www/src/examples/shopping-mall-directory-get-store/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-get-store/example.ts create mode 100644 www/src/examples/shopping-mall-directory-get-store/table.ts create mode 100644 www/src/examples/shopping-mall-directory-patch-lease-date/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-patch-lease-date/example.ts create mode 100644 www/src/examples/shopping-mall-directory-patch-lease-date/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-by-category/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-by-category/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-by-category/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-between/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-between/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-between/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-filter/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-filter/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-filter/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-lt/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-lt/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-leases-lt/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-building/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-building/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-building/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-mall/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-mall/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-mall/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-unit/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-unit/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-by-unit/table.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-full/entity.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-full/example.ts create mode 100644 www/src/examples/shopping-mall-directory-query-units-full/table.ts create mode 100644 www/src/examples/task-manager-assignments/entities.ts create mode 100644 www/src/examples/task-manager-assignments/example.ts create mode 100644 www/src/examples/task-manager-assignments/service.ts create mode 100644 www/src/examples/task-manager-assignments/table.ts create mode 100644 www/src/examples/task-manager-create-task/entities.ts create mode 100644 www/src/examples/task-manager-create-task/example.ts create mode 100644 www/src/examples/task-manager-create-task/service.ts create mode 100644 www/src/examples/task-manager-create-task/table.ts create mode 100644 www/src/examples/task-manager-junior-developers/entities.ts create mode 100644 www/src/examples/task-manager-junior-developers/example.ts create mode 100644 www/src/examples/task-manager-junior-developers/service.ts create mode 100644 www/src/examples/task-manager-junior-developers/table.ts create mode 100644 www/src/examples/task-manager-open-tasks/entities.ts create mode 100644 www/src/examples/task-manager-open-tasks/example.ts create mode 100644 www/src/examples/task-manager-open-tasks/service.ts create mode 100644 www/src/examples/task-manager-open-tasks/table.ts create mode 100644 www/src/examples/task-manager-recent-hires/entities.ts create mode 100644 www/src/examples/task-manager-recent-hires/example.ts create mode 100644 www/src/examples/task-manager-recent-hires/service.ts create mode 100644 www/src/examples/task-manager-recent-hires/table.ts create mode 100644 www/src/examples/task-manager-workplace/entities.ts create mode 100644 www/src/examples/task-manager-workplace/example.ts create mode 100644 www/src/examples/task-manager-workplace/service.ts create mode 100644 www/src/examples/task-manager-workplace/table.ts create mode 100644 www/src/examples/transact-get-employee-and-office/entities.ts create mode 100644 www/src/examples/transact-get-employee-and-office/example.ts create mode 100644 www/src/examples/transact-get-employee-and-office/service.ts create mode 100644 www/src/examples/transact-get-employee-and-office/table.ts create mode 100644 www/src/examples/transact-write-idempotent-writes/entities.ts create mode 100644 www/src/examples/transact-write-idempotent-writes/example.ts create mode 100644 www/src/examples/transact-write-idempotent-writes/service.ts create mode 100644 www/src/examples/transact-write-idempotent-writes/table.ts create mode 100644 www/src/examples/transact-write-unique-constraint/entities.ts create mode 100644 www/src/examples/transact-write-unique-constraint/example.ts create mode 100644 www/src/examples/transact-write-unique-constraint/service.ts create mode 100644 www/src/examples/transact-write-unique-constraint/table.ts create mode 100644 www/src/examples/update-composite-attributes-edgecase/entity.ts create mode 100644 www/src/examples/update-composite-attributes-edgecase/example.ts create mode 100644 www/src/examples/update-composite-attributes-edgecase/table.ts create mode 100644 www/src/examples/update-list-element-remove/entity.ts create mode 100644 www/src/examples/update-list-element-remove/example.ts create mode 100644 www/src/examples/update-list-element-remove/table.ts create mode 100644 www/src/examples/update-map-property/entity.ts create mode 100644 www/src/examples/update-map-property/example.ts create mode 100644 www/src/examples/update-map-property/table.ts create mode 100644 www/src/examples/update-nested-set-add/entity.ts create mode 100644 www/src/examples/update-nested-set-add/example.ts create mode 100644 www/src/examples/update-nested-set-add/table.ts create mode 100644 www/src/examples/update-organization-composite/entity.ts create mode 100644 www/src/examples/update-organization-composite/example.ts create mode 100644 www/src/examples/update-organization-composite/table.ts create mode 100644 www/src/examples/update-store-location-add/entity.ts create mode 100644 www/src/examples/update-store-location-add/example.ts create mode 100644 www/src/examples/update-store-location-add/table.ts create mode 100644 www/src/examples/update-store-location-append/entity.ts create mode 100644 www/src/examples/update-store-location-append/example.ts create mode 100644 www/src/examples/update-store-location-append/table.ts create mode 100644 www/src/examples/update-store-location-data/entity.ts create mode 100644 www/src/examples/update-store-location-data/example.ts create mode 100644 www/src/examples/update-store-location-data/table.ts create mode 100644 www/src/examples/update-store-location-delete/entity.ts create mode 100644 www/src/examples/update-store-location-delete/example.ts create mode 100644 www/src/examples/update-store-location-delete/table.ts create mode 100644 www/src/examples/update-store-location-remove/entity.ts create mode 100644 www/src/examples/update-store-location-remove/example.ts create mode 100644 www/src/examples/update-store-location-remove/table.ts create mode 100644 www/src/examples/update-store-location-set/entity.ts create mode 100644 www/src/examples/update-store-location-set/example.ts create mode 100644 www/src/examples/update-store-location-set/table.ts create mode 100644 www/src/examples/update-store-location-subtract/entity.ts create mode 100644 www/src/examples/update-store-location-subtract/example.ts create mode 100644 www/src/examples/update-store-location-subtract/table.ts create mode 100644 www/src/examples/update-tasks-set-add-append/entity.ts create mode 100644 www/src/examples/update-tasks-set-add-append/example.ts create mode 100644 www/src/examples/update-tasks-set-add-append/table.ts create mode 100644 www/src/examples/upsert-store-location-add-subtract-append/entity.ts create mode 100644 www/src/examples/upsert-store-location-add-subtract-append/example.ts create mode 100644 www/src/examples/upsert-store-location-add-subtract-append/table.ts create mode 100644 www/src/examples/upsert-store-location/entity.ts create mode 100644 www/src/examples/upsert-store-location/example.ts create mode 100644 www/src/examples/upsert-store-location/table.ts diff --git a/www/src/components/LiveExample/LiveExample.astro b/www/src/components/LiveExample/LiveExample.astro index 0e563093..74de9f72 100644 --- a/www/src/components/LiveExample/LiveExample.astro +++ b/www/src/components/LiveExample/LiveExample.astro @@ -15,12 +15,14 @@ const { name } = Astro.props as Props; const LABELS: Record = { "example.ts": "Example", "entity.ts": "Entity", + "entities.ts": "Entities", + "service.ts": "Service", "table.ts": "Table Definition", }; // example.ts must come first: it is the program entry point (the other // files execute when imported), and it is the tab shown by default. -const ORDER = ["example.ts", "entity.ts", "table.ts"]; +const ORDER = ["example.ts", "service.ts", "entity.ts", "entities.ts", "table.ts"]; const sources = import.meta.glob("/src/examples/*/*.ts", { query: "?raw", diff --git a/www/src/examples/batch-delete-store-locations/entity.ts b/www/src/examples/batch-delete-store-locations/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/batch-delete-store-locations/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/batch-delete-store-locations/example.ts b/www/src/examples/batch-delete-store-locations/example.ts new file mode 100644 index 00000000..bb912252 --- /dev/null +++ b/www/src/examples/batch-delete-store-locations/example.ts @@ -0,0 +1,16 @@ +import { StoreLocations } from "./entity"; + +let unprocessed = await StoreLocations.delete([ + { + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + cityId: "LosAngeles1", + }, + { + storeId: "MochaJoes", + mallId: "EastPointe", + buildingId: "F35", + cityId: "LosAngeles1", + }, +]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` diff --git a/www/src/examples/batch-delete-store-locations/table.ts b/www/src/examples/batch-delete-store-locations/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/batch-delete-store-locations/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/batch-get-store-locations/entity.ts b/www/src/examples/batch-get-store-locations/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/batch-get-store-locations/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/batch-get-store-locations/example.ts b/www/src/examples/batch-get-store-locations/example.ts new file mode 100644 index 00000000..f96b1a76 --- /dev/null +++ b/www/src/examples/batch-get-store-locations/example.ts @@ -0,0 +1,16 @@ +import { StoreLocations } from "./entity"; + +const { data, unprocessed } = await StoreLocations.get([ + { + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + cityId: "Atlanta1", + }, + { + storeId: "MochaJoes", + mallId: "WestEnd", + buildingId: "A21", + cityId: "Madison2", + }, +]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` diff --git a/www/src/examples/batch-get-store-locations/table.ts b/www/src/examples/batch-get-store-locations/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/batch-get-store-locations/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/batch-put-store-locations/entity.ts b/www/src/examples/batch-put-store-locations/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/batch-put-store-locations/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/batch-put-store-locations/example.ts b/www/src/examples/batch-put-store-locations/example.ts new file mode 100644 index 00000000..18f2da2e --- /dev/null +++ b/www/src/examples/batch-put-store-locations/example.ts @@ -0,0 +1,24 @@ +import { StoreLocations } from "./entity"; + +const unprocessed = await StoreLocations.put([ + { + cityId: "LosAngeles1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + unitId: "a1", + category: "food/coffee", + leaseEndDate: "2022-03-22", + rent: "4500.00", + }, + { + cityId: "LosAngeles1", + storeId: "MochaJoes", + mallId: "EastPointe", + buildingId: "F35", + unitId: "a2", + category: "food/coffee", + leaseEndDate: "2021-01-22", + rent: "1500.00", + }, +]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` diff --git a/www/src/examples/batch-put-store-locations/table.ts b/www/src/examples/batch-put-store-locations/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/batch-put-store-locations/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collection-assignments-filtered/entities.ts b/www/src/examples/collection-assignments-filtered/entities.ts new file mode 100644 index 00000000..b77e6dc3 --- /dev/null +++ b/www/src/examples/collection-assignments-filtered/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employees = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"], + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collection-assignments-filtered/example.ts b/www/src/examples/collection-assignments-filtered/example.ts new file mode 100644 index 00000000..16ad94aa --- /dev/null +++ b/www/src/examples/collection-assignments-filtered/example.ts @@ -0,0 +1,8 @@ +import { TaskApp } from "./service"; + +const results = await TaskApp.collections + .assignments({ employeeId: "CBaskin" }) + .where(({ projectId }, { notExists, contains }) => ` + ${notExists(projectId)} OR ${contains(projectId, "murder")} + `) + .go(); diff --git a/www/src/examples/collection-assignments-filtered/service.ts b/www/src/examples/collection-assignments-filtered/service.ts new file mode 100644 index 00000000..cc7e77c7 --- /dev/null +++ b/www/src/examples/collection-assignments-filtered/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { employees, tasks } from "./entities"; + +export const TaskApp = new Service({ employees, tasks }); diff --git a/www/src/examples/collection-assignments-filtered/table.ts b/www/src/examples/collection-assignments-filtered/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collection-assignments-filtered/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collection-assignments/entities.ts b/www/src/examples/collection-assignments/entities.ts new file mode 100644 index 00000000..b77e6dc3 --- /dev/null +++ b/www/src/examples/collection-assignments/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employees = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"], + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collection-assignments/example.ts b/www/src/examples/collection-assignments/example.ts new file mode 100644 index 00000000..1993d18d --- /dev/null +++ b/www/src/examples/collection-assignments/example.ts @@ -0,0 +1,5 @@ +import { TaskApp } from "./service"; + +const results = await TaskApp.collections + .assignments({ employeeId: "JExotic" }) + .go(); diff --git a/www/src/examples/collection-assignments/service.ts b/www/src/examples/collection-assignments/service.ts new file mode 100644 index 00000000..cc7e77c7 --- /dev/null +++ b/www/src/examples/collection-assignments/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { employees, tasks } from "./entities"; + +export const TaskApp = new Service({ employees, tasks }); diff --git a/www/src/examples/collection-assignments/table.ts b/www/src/examples/collection-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collection-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-collection-query-assignments/entities.ts b/www/src/examples/collections-collection-query-assignments/entities.ts new file mode 100644 index 00000000..cc66e177 --- /dev/null +++ b/www/src/examples/collections-collection-query-assignments/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-collection-query-assignments/example.ts b/www/src/examples/collections-collection-query-assignments/example.ts new file mode 100644 index 00000000..690bd7ad --- /dev/null +++ b/www/src/examples/collections-collection-query-assignments/example.ts @@ -0,0 +1,3 @@ +import { TaskApp } from "./service"; + +await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); diff --git a/www/src/examples/collections-collection-query-assignments/service.ts b/www/src/examples/collections-collection-query-assignments/service.ts new file mode 100644 index 00000000..7c45bc5e --- /dev/null +++ b/www/src/examples/collections-collection-query-assignments/service.ts @@ -0,0 +1,7 @@ +import { Service } from "electrodb"; +import { Employee, Task } from "./entities"; + +export const TaskApp = new Service({ + employee: Employee, + task: Task, +}); diff --git a/www/src/examples/collections-collection-query-assignments/table.ts b/www/src/examples/collections-collection-query-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-collection-query-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-complex-assignments/entities.ts b/www/src/examples/collections-complex-assignments/entities.ts new file mode 100644 index 00000000..3e386a0f --- /dev/null +++ b/www/src/examples/collections-complex-assignments/entities.ts @@ -0,0 +1,151 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employees = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "contributions", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const projectMembers = new Entity( + { + model: { + entity: "projectMembers", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + members: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + projects: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-complex-assignments/example.ts b/www/src/examples/collections-complex-assignments/example.ts new file mode 100644 index 00000000..1993d18d --- /dev/null +++ b/www/src/examples/collections-complex-assignments/example.ts @@ -0,0 +1,5 @@ +import { TaskApp } from "./service"; + +const results = await TaskApp.collections + .assignments({ employeeId: "JExotic" }) + .go(); diff --git a/www/src/examples/collections-complex-assignments/service.ts b/www/src/examples/collections-complex-assignments/service.ts new file mode 100644 index 00000000..b311b29f --- /dev/null +++ b/www/src/examples/collections-complex-assignments/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employees, tasks, projectMembers } from "./entities"; + +export const TaskApp = new Service({ + employees, + tasks, + projectMembers, +}); diff --git a/www/src/examples/collections-complex-assignments/table.ts b/www/src/examples/collections-complex-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-complex-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-complex-contributions/entities.ts b/www/src/examples/collections-complex-contributions/entities.ts new file mode 100644 index 00000000..3e386a0f --- /dev/null +++ b/www/src/examples/collections-complex-contributions/entities.ts @@ -0,0 +1,151 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employees = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "contributions", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const projectMembers = new Entity( + { + model: { + entity: "projectMembers", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + members: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + projects: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-complex-contributions/example.ts b/www/src/examples/collections-complex-contributions/example.ts new file mode 100644 index 00000000..04805d72 --- /dev/null +++ b/www/src/examples/collections-complex-contributions/example.ts @@ -0,0 +1,6 @@ +import { TaskApp } from "./service"; + +// contributions +const results = await TaskApp.collections + .contributions({ employeeId: "JExotic" }) + .go(); diff --git a/www/src/examples/collections-complex-contributions/service.ts b/www/src/examples/collections-complex-contributions/service.ts new file mode 100644 index 00000000..b311b29f --- /dev/null +++ b/www/src/examples/collections-complex-contributions/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employees, tasks, projectMembers } from "./entities"; + +export const TaskApp = new Service({ + employees, + tasks, + projectMembers, +}); diff --git a/www/src/examples/collections-complex-contributions/table.ts b/www/src/examples/collections-complex-contributions/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-complex-contributions/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-entity-query-assigned/entities.ts b/www/src/examples/collections-entity-query-assigned/entities.ts new file mode 100644 index 00000000..cc66e177 --- /dev/null +++ b/www/src/examples/collections-entity-query-assigned/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-entity-query-assigned/example.ts b/www/src/examples/collections-entity-query-assigned/example.ts new file mode 100644 index 00000000..6b302ca4 --- /dev/null +++ b/www/src/examples/collections-entity-query-assigned/example.ts @@ -0,0 +1,3 @@ +import { TaskApp } from "./service"; + +await TaskApp.entities.task.query.assigned({ employeeId: "JExotic" }).go(); diff --git a/www/src/examples/collections-entity-query-assigned/service.ts b/www/src/examples/collections-entity-query-assigned/service.ts new file mode 100644 index 00000000..7c45bc5e --- /dev/null +++ b/www/src/examples/collections-entity-query-assigned/service.ts @@ -0,0 +1,7 @@ +import { Service } from "electrodb"; +import { Employee, Task } from "./entities"; + +export const TaskApp = new Service({ + employee: Employee, + task: Task, +}); diff --git a/www/src/examples/collections-entity-query-assigned/table.ts b/www/src/examples/collections-entity-query-assigned/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-entity-query-assigned/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-index-naming-staff/entity.ts b/www/src/examples/collections-index-naming-staff/entity.ts new file mode 100644 index 00000000..72efa56e --- /dev/null +++ b/www/src/examples/collections-index-naming-staff/entity.ts @@ -0,0 +1,51 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employee = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "contributions", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-index-naming-staff/example.ts b/www/src/examples/collections-index-naming-staff/example.ts new file mode 100644 index 00000000..8bd50162 --- /dev/null +++ b/www/src/examples/collections-index-naming-staff/example.ts @@ -0,0 +1,3 @@ +import { employee } from "./entity"; + +await employee.query.staff({ organizationId: "nike" }).go(); diff --git a/www/src/examples/collections-index-naming-staff/table.ts b/www/src/examples/collections-index-naming-staff/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-index-naming-staff/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-response-structure-assignments/entities.ts b/www/src/examples/collections-response-structure-assignments/entities.ts new file mode 100644 index 00000000..cc66e177 --- /dev/null +++ b/www/src/examples/collections-response-structure-assignments/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-response-structure-assignments/example.ts b/www/src/examples/collections-response-structure-assignments/example.ts new file mode 100644 index 00000000..1993d18d --- /dev/null +++ b/www/src/examples/collections-response-structure-assignments/example.ts @@ -0,0 +1,5 @@ +import { TaskApp } from "./service"; + +const results = await TaskApp.collections + .assignments({ employeeId: "JExotic" }) + .go(); diff --git a/www/src/examples/collections-response-structure-assignments/service.ts b/www/src/examples/collections-response-structure-assignments/service.ts new file mode 100644 index 00000000..7c45bc5e --- /dev/null +++ b/www/src/examples/collections-response-structure-assignments/service.ts @@ -0,0 +1,7 @@ +import { Service } from "electrodb"; +import { Employee, Task } from "./entities"; + +export const TaskApp = new Service({ + employee: Employee, + task: Task, +}); diff --git a/www/src/examples/collections-response-structure-assignments/table.ts b/www/src/examples/collections-response-structure-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-response-structure-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-simple-overview/entities.ts b/www/src/examples/collections-simple-overview/entities.ts new file mode 100644 index 00000000..3e386a0f --- /dev/null +++ b/www/src/examples/collections-simple-overview/entities.ts @@ -0,0 +1,151 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employees = new Entity( + { + model: { + entity: "employees", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "contributions", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const projectMembers = new Entity( + { + model: { + entity: "projectMembers", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + members: { + collection: "overview", + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + projects: { + collection: ["contributions", "assignments"] as const, + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-simple-overview/example.ts b/www/src/examples/collections-simple-overview/example.ts new file mode 100644 index 00000000..7765256f --- /dev/null +++ b/www/src/examples/collections-simple-overview/example.ts @@ -0,0 +1,6 @@ +import { TaskApp } from "./service"; + +// overview +const results = await TaskApp.collections + .overview({ projectId: "SD-204" }) + .go(); diff --git a/www/src/examples/collections-simple-overview/service.ts b/www/src/examples/collections-simple-overview/service.ts new file mode 100644 index 00000000..b311b29f --- /dev/null +++ b/www/src/examples/collections-simple-overview/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employees, tasks, projectMembers } from "./entities"; + +export const TaskApp = new Service({ + employees, + tasks, + projectMembers, +}); diff --git a/www/src/examples/collections-simple-overview/table.ts b/www/src/examples/collections-simple-overview/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-simple-overview/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-subcollection-assignments/entities.ts b/www/src/examples/collections-subcollection-assignments/entities.ts new file mode 100644 index 00000000..cc66e177 --- /dev/null +++ b/www/src/examples/collections-subcollection-assignments/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-subcollection-assignments/example.ts b/www/src/examples/collections-subcollection-assignments/example.ts new file mode 100644 index 00000000..1993d18d --- /dev/null +++ b/www/src/examples/collections-subcollection-assignments/example.ts @@ -0,0 +1,5 @@ +import { TaskApp } from "./service"; + +const results = await TaskApp.collections + .assignments({ employeeId: "JExotic" }) + .go(); diff --git a/www/src/examples/collections-subcollection-assignments/service.ts b/www/src/examples/collections-subcollection-assignments/service.ts new file mode 100644 index 00000000..7c45bc5e --- /dev/null +++ b/www/src/examples/collections-subcollection-assignments/service.ts @@ -0,0 +1,7 @@ +import { Service } from "electrodb"; +import { Employee, Task } from "./entities"; + +export const TaskApp = new Service({ + employee: Employee, + task: Task, +}); diff --git a/www/src/examples/collections-subcollection-assignments/table.ts b/www/src/examples/collections-subcollection-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-subcollection-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/collections-taskapp-assignments/entities.ts b/www/src/examples/collections-taskapp-assignments/entities.ts new file mode 100644 index 00000000..cc66e177 --- /dev/null +++ b/www/src/examples/collections-taskapp-assignments/entities.ts @@ -0,0 +1,103 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employeeId: { + type: "string", + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + team: { + type: ["jupiter", "mercury", "saturn"] as const, + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + employee: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + employeeId: { + type: "string", + }, + projectId: { + type: "string", + }, + title: { + type: "string", + }, + body: { + type: "string", + }, + }, + indexes: { + project: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi2", + pk: { + field: "gsi2pk", + composite: ["employeeId"], + }, + sk: { + field: "gsi2sk", + composite: ["projectId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/collections-taskapp-assignments/example.ts b/www/src/examples/collections-taskapp-assignments/example.ts new file mode 100644 index 00000000..690bd7ad --- /dev/null +++ b/www/src/examples/collections-taskapp-assignments/example.ts @@ -0,0 +1,3 @@ +import { TaskApp } from "./service"; + +await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); diff --git a/www/src/examples/collections-taskapp-assignments/service.ts b/www/src/examples/collections-taskapp-assignments/service.ts new file mode 100644 index 00000000..7c45bc5e --- /dev/null +++ b/www/src/examples/collections-taskapp-assignments/service.ts @@ -0,0 +1,7 @@ +import { Service } from "electrodb"; +import { Employee, Task } from "./entities"; + +export const TaskApp = new Service({ + employee: Employee, + task: Task, +}); diff --git a/www/src/examples/collections-taskapp-assignments/table.ts b/www/src/examples/collections-taskapp-assignments/table.ts new file mode 100644 index 00000000..86523742 --- /dev/null +++ b/www/src/examples/collections-taskapp-assignments/table.ts @@ -0,0 +1,52 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi2", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-condition-expression/entity.ts b/www/src/examples/conditions-condition-expression/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-condition-expression/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-condition-expression/example.ts b/www/src/examples/conditions-condition-expression/example.ts new file mode 100644 index 00000000..f18c2fd5 --- /dev/null +++ b/www/src/examples/conditions-condition-expression/example.ts @@ -0,0 +1,31 @@ +import { animals } from "./entity"; + +await animals + .update({ + animal: "blackbear", + name: "Isabelle", + }) + // no longer pregnant because Ernesto was born! + .set({ + isPregnant: false, + lastEvaluation: "2021-09-12", + lastEvaluationBy: "stephanie.adler", + }) + // welcome to the world Ernesto! + .append({ + offspring: [ + { + name: "Ernesto", + birthday: "2021-09-12", + note: "healthy birth, mild pollen allergy", + }, + ], + }) + // using the where clause can guard against making + // updates against stale data + .where( + ({ isPregnant, lastEvaluation }, { lt, eq }) => ` + ${eq(isPregnant, true)} AND ${lt(lastEvaluation, "2021-09-12")} + `, + ) + .go(); diff --git a/www/src/examples/conditions-condition-expression/table.ts b/www/src/examples/conditions-condition-expression/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-condition-expression/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-conditional-update/entity.ts b/www/src/examples/conditions-conditional-update/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/conditions-conditional-update/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-conditional-update/example.ts b/www/src/examples/conditions-conditional-update/example.ts new file mode 100644 index 00000000..dcfb8975 --- /dev/null +++ b/www/src/examples/conditions-conditional-update/example.ts @@ -0,0 +1,15 @@ +import { StoreLocations } from "./entity"; + +const result = await StoreLocations.patch({ + cityId: "Atlanta1", + mallId: "EastPointe", + storeId: "LatteLarrys", + buildingId: "BuildingA1", +}) + .set({ rent: "5000.00" }) + .where(({ rent }, { lt }) => lt(rent, "4000.00")) + .go({ returnOnConditionCheckFailure: "all_old" }); + +if (result.rejected) { + console.log("current rent:", result.data?.rent); +} diff --git a/www/src/examples/conditions-conditional-update/table.ts b/www/src/examples/conditions-conditional-update/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/conditions-conditional-update/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-detect-rejection-only/entity.ts b/www/src/examples/conditions-detect-rejection-only/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/conditions-detect-rejection-only/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-detect-rejection-only/example.ts b/www/src/examples/conditions-detect-rejection-only/example.ts new file mode 100644 index 00000000..308ab17b --- /dev/null +++ b/www/src/examples/conditions-detect-rejection-only/example.ts @@ -0,0 +1,18 @@ +import { StoreLocations } from "./entity"; + +const result = await StoreLocations.create({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}).go({ returnOnConditionCheckFailure: true }); + +if (result.rejected) { + console.log("store already exists"); +} else { + console.log("created:", result.data); +} diff --git a/www/src/examples/conditions-detect-rejection-only/table.ts b/www/src/examples/conditions-detect-rejection-only/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/conditions-detect-rejection-only/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-multiple-where-clauses/entity.ts b/www/src/examples/conditions-multiple-where-clauses/entity.ts new file mode 100644 index 00000000..f2f04fcc --- /dev/null +++ b/www/src/examples/conditions-multiple-where-clauses/entity.ts @@ -0,0 +1,70 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const model = { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + }, + discount: { + type: "string", + required: false, + default: "0.00", + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["mallId"], + }, + sk: { + field: "sk", + composite: ["storeId"], + }, + }, + leases: { + index: "idx2", + pk: { + field: "idx2pk", + composite: ["mallId"], + }, + sk: { + field: "idx2sk", + composite: ["leaseEndDate", "storeId"], + }, + }, + }, +} as const; + +export const MallStores = new Entity(model, { table: tableName }); diff --git a/www/src/examples/conditions-multiple-where-clauses/example.ts b/www/src/examples/conditions-multiple-where-clauses/example.ts new file mode 100644 index 00000000..f3de2d50 --- /dev/null +++ b/www/src/examples/conditions-multiple-where-clauses/example.ts @@ -0,0 +1,18 @@ +import { Entity } from "electrodb"; +import { model } from "./entity"; + +let MallStores = new Entity(model, { table: "StoreDirectory" }); +let stores = await MallStores.query + .leases({ mallId: "EastPointe" }) + .between({ leaseEndDate: "2020-04-01" }, { leaseEndDate: "2020-07-01" }) + .where( + ({ rent, discount }, { between, eq }) => ` + ${between(rent, "2000.00", "5000.00")} AND ${eq(discount, "1000.00")} + `, + ) + .where( + ({ category }, { eq }) => ` + ${eq(category, "food/coffee")} + `, + ) + .go(); diff --git a/www/src/examples/conditions-multiple-where-clauses/table.ts b/www/src/examples/conditions-multiple-where-clauses/table.ts new file mode 100644 index 00000000..3e440201 --- /dev/null +++ b/www/src/examples/conditions-multiple-where-clauses/table.ts @@ -0,0 +1,52 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "idx2pk", + AttributeType: "S", + }, + { + AttributeName: "idx2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "idx2", + KeySchema: [ + { + AttributeName: "idx2pk", + KeyType: "HASH", + }, + { + AttributeName: "idx2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-safe-create/entity.ts b/www/src/examples/conditions-safe-create/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/conditions-safe-create/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-safe-create/example.ts b/www/src/examples/conditions-safe-create/example.ts new file mode 100644 index 00000000..d439ee47 --- /dev/null +++ b/www/src/examples/conditions-safe-create/example.ts @@ -0,0 +1,18 @@ +import { StoreLocations } from "./entity"; + +const result = await StoreLocations.create({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}).go({ returnOnConditionCheckFailure: "all_old" }); + +if (result.rejected) { + console.log("already exists:", result.data); +} else { + console.log("created:", result.data); +} diff --git a/www/src/examples/conditions-safe-create/table.ts b/www/src/examples/conditions-safe-create/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/conditions-safe-create/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-chained/entity.ts b/www/src/examples/conditions-where-chained/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-chained/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-chained/example.ts b/www/src/examples/conditions-where-chained/example.ts new file mode 100644 index 00000000..9b19175b --- /dev/null +++ b/www/src/examples/conditions-where-chained/example.ts @@ -0,0 +1,16 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where( + (attr, op) => ` + ${op.eq(attr.dangerous, true)} OR ${op.notExists(attr.lastFed)} + `, + ) + .where(({ birthday }, { between }) => { + const today = Date.now(); + const lastMonth = today - 1000 * 60 * 60 * 24 * 30; + return between(birthday, String(lastMonth), String(today)); + }) + .go(); diff --git a/www/src/examples/conditions-where-chained/table.ts b/www/src/examples/conditions-where-chained/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-chained/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-destructured/entity.ts b/www/src/examples/conditions-where-destructured/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-destructured/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-destructured/example.ts b/www/src/examples/conditions-where-destructured/example.ts new file mode 100644 index 00000000..376aa4d3 --- /dev/null +++ b/www/src/examples/conditions-where-destructured/example.ts @@ -0,0 +1,7 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where(({ dangerous }, { eq }) => eq(dangerous, true)) + .go(); diff --git a/www/src/examples/conditions-where-destructured/table.ts b/www/src/examples/conditions-where-destructured/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-destructured/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-dynamic-filtering/entity.ts b/www/src/examples/conditions-where-dynamic-filtering/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-dynamic-filtering/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-dynamic-filtering/example.ts b/www/src/examples/conditions-where-dynamic-filtering/example.ts new file mode 100644 index 00000000..0400503c --- /dev/null +++ b/www/src/examples/conditions-where-dynamic-filtering/example.ts @@ -0,0 +1,21 @@ +import { animals } from "./entity"; + +type GetAnimalOptions = { + habitat: string; + keepers: string[]; +}; +function getAnimals(options: GetAnimalOptions) { + const { habitat, keepers } = options; + const query = animals.query.exhibit({ habitat }); + + for (const name of keepers) { + query.where(({ keeper }, { ne }) => ne(keeper, name)); + } + + return query.go(); +} + +const { data, cursor } = await getAnimals({ + habitat: "RainForest", + keepers: ["Joe Exotic", "Carol Baskin"], +}); diff --git a/www/src/examples/conditions-where-dynamic-filtering/table.ts b/www/src/examples/conditions-where-dynamic-filtering/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-dynamic-filtering/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-escape-function/entity.ts b/www/src/examples/conditions-where-escape-function/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-escape-function/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-escape-function/example.ts b/www/src/examples/conditions-where-escape-function/example.ts new file mode 100644 index 00000000..3d371c89 --- /dev/null +++ b/www/src/examples/conditions-where-escape-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +await animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ diet }, { size, escape }) => ` + ${size(diet)} > ${escape(2)} + `, + ) + .go(); diff --git a/www/src/examples/conditions-where-escape-function/table.ts b/www/src/examples/conditions-where-escape-function/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-escape-function/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-field-function/entity.ts b/www/src/examples/conditions-where-field-function/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-field-function/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-field-function/example.ts b/www/src/examples/conditions-where-field-function/example.ts new file mode 100644 index 00000000..bedcb86a --- /dev/null +++ b/www/src/examples/conditions-where-field-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +await animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + (_, { field, escape }) => ` + contains(${field("gsi1sk")}, ${escape("value")}) + `, + ) + .go(); diff --git a/www/src/examples/conditions-where-field-function/table.ts b/www/src/examples/conditions-where-field-function/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-field-function/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-list-attribute/entity.ts b/www/src/examples/conditions-where-list-attribute/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-list-attribute/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-list-attribute/example.ts b/www/src/examples/conditions-where-list-attribute/example.ts new file mode 100644 index 00000000..25a0fca5 --- /dev/null +++ b/www/src/examples/conditions-where-list-attribute/example.ts @@ -0,0 +1,7 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where(({ offspring }, { eq }) => eq(offspring[0].name, "Blitzen")) + .go(); diff --git a/www/src/examples/conditions-where-list-attribute/table.ts b/www/src/examples/conditions-where-list-attribute/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-list-attribute/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-map-attribute/entity.ts b/www/src/examples/conditions-where-map-attribute/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-map-attribute/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-map-attribute/example.ts b/www/src/examples/conditions-where-map-attribute/example.ts new file mode 100644 index 00000000..73300fce --- /dev/null +++ b/www/src/examples/conditions-where-map-attribute/example.ts @@ -0,0 +1,7 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where(({ veterinarian }, { eq }) => eq(veterinarian.name, "Herb Peterson")) + .go(); diff --git a/www/src/examples/conditions-where-map-attribute/table.ts b/www/src/examples/conditions-where-map-attribute/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-map-attribute/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-multiple-conditions/entity.ts b/www/src/examples/conditions-where-multiple-conditions/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-multiple-conditions/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-multiple-conditions/example.ts b/www/src/examples/conditions-where-multiple-conditions/example.ts new file mode 100644 index 00000000..163e2326 --- /dev/null +++ b/www/src/examples/conditions-where-multiple-conditions/example.ts @@ -0,0 +1,11 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where( + (attr, op) => ` + ${op.eq(attr.dangerous, true)} AND ${op.notExists(attr.lastFed)} + `, + ) + .go(); diff --git a/www/src/examples/conditions-where-multiple-conditions/table.ts b/www/src/examples/conditions-where-multiple-conditions/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-multiple-conditions/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-name-function/entity.ts b/www/src/examples/conditions-where-name-function/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-name-function/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-name-function/example.ts b/www/src/examples/conditions-where-name-function/example.ts new file mode 100644 index 00000000..d70a656e --- /dev/null +++ b/www/src/examples/conditions-where-name-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +await animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ lastFedBy, keeper }, { name }) => ` + ${name(lastFedBy)} != ${name(keeper)} + `, + ) + .go(); diff --git a/www/src/examples/conditions-where-name-function/table.ts b/www/src/examples/conditions-where-name-function/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-name-function/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-single-filter/entity.ts b/www/src/examples/conditions-where-single-filter/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-single-filter/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-single-filter/example.ts b/www/src/examples/conditions-where-single-filter/example.ts new file mode 100644 index 00000000..a09e0c8f --- /dev/null +++ b/www/src/examples/conditions-where-single-filter/example.ts @@ -0,0 +1,7 @@ +import { animals } from "./entity"; + +await animals + .update({ animal: "tiger", name: "janet" }) + .set({ keeper: "Joe Exotic" }) + .where((attr, op) => op.eq(attr.dangerous, true)) + .go(); diff --git a/www/src/examples/conditions-where-single-filter/table.ts b/www/src/examples/conditions-where-single-filter/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-single-filter/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/conditions-where-value-function/entity.ts b/www/src/examples/conditions-where-value-function/entity.ts new file mode 100644 index 00000000..163cf20d --- /dev/null +++ b/www/src/examples/conditions-where-value-function/entity.ts @@ -0,0 +1,109 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + lastEvaluation: { + type: "string", + }, + lastEvaluationBy: { + type: "string", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/conditions-where-value-function/example.ts b/www/src/examples/conditions-where-value-function/example.ts new file mode 100644 index 00000000..9de86b81 --- /dev/null +++ b/www/src/examples/conditions-where-value-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +await animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ keeper }, { name, value, eq }) => ` + ${name(keeper)} = ${value(keeper, "Tiger King")} + `, + ) + .go(); diff --git a/www/src/examples/conditions-where-value-function/table.ts b/www/src/examples/conditions-where-value-function/table.ts new file mode 100644 index 00000000..41a8cd0e --- /dev/null +++ b/www/src/examples/conditions-where-value-function/table.ts @@ -0,0 +1,52 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/create-store-location/entity.ts b/www/src/examples/create-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/create-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/create-store-location/example.ts b/www/src/examples/create-store-location/example.ts new file mode 100644 index 00000000..490ddef6 --- /dev/null +++ b/www/src/examples/create-store-location/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.create({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}) + .where((attr, op) => op.eq(attr.rent, "4500.00")) + .go(); diff --git a/www/src/examples/create-store-location/table.ts b/www/src/examples/create-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/create-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/delete-store-location/entity.ts b/www/src/examples/delete-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/delete-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/delete-store-location/example.ts b/www/src/examples/delete-store-location/example.ts new file mode 100644 index 00000000..cf39b057 --- /dev/null +++ b/www/src/examples/delete-store-location/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.delete({ + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + cityId: "Atlanta1", +}).go(); diff --git a/www/src/examples/delete-store-location/table.ts b/www/src/examples/delete-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/delete-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/executing-queries-go/entity.ts b/www/src/examples/executing-queries-go/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/executing-queries-go/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/executing-queries-go/example.ts b/www/src/examples/executing-queries-go/example.ts new file mode 100644 index 00000000..39a67010 --- /dev/null +++ b/www/src/examples/executing-queries-go/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +const storeId = "LatteLarrys"; + +const results = await StoreLocations.query + .leases({ storeId }) + .between({ leaseEndDate: "2020-06-01" }, { leaseEndDate: "2020-07-31" }) + .where(({ rent }, { lte }) => lte(rent, "5000.00")) + .go(); diff --git a/www/src/examples/executing-queries-go/table.ts b/www/src/examples/executing-queries-go/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/executing-queries-go/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/executing-queries-params/entity.ts b/www/src/examples/executing-queries-params/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/executing-queries-params/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/executing-queries-params/example.ts b/www/src/examples/executing-queries-params/example.ts new file mode 100644 index 00000000..6728ace1 --- /dev/null +++ b/www/src/examples/executing-queries-params/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +const storeId = "LatteLarrys"; + +const params = StoreLocations.query + .leases({ storeId }) + .between({ leaseEndDate: "2020-06-01" }, { leaseEndDate: "2020-07-31" }) + .where(({ rent }, { lte }) => lte(rent, "5000.00")) + .params(); diff --git a/www/src/examples/executing-queries-params/table.ts b/www/src/examples/executing-queries-params/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/executing-queries-params/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/existing-table-ignore-ownership/entity.ts b/www/src/examples/existing-table-ignore-ownership/entity.ts new file mode 100644 index 00000000..4533b993 --- /dev/null +++ b/www/src/examples/existing-table-ignore-ownership/entity.ts @@ -0,0 +1,51 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +// This entity models data that already exists in DynamoDB and was not +// originally created by ElectroDB. Use the `ignoreOwnership` execution +// option (shown in example.ts) so ElectroDB does not filter out records +// that lack its own entity/version metadata. +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/existing-table-ignore-ownership/example.ts b/www/src/examples/existing-table-ignore-ownership/example.ts new file mode 100644 index 00000000..e94270c2 --- /dev/null +++ b/www/src/examples/existing-table-ignore-ownership/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +// when querying the table +const results = await StoreLocations.get({ + cityId: "Atlanta1", + mallId: "EastPointe", + buildingId: "BuildingA1", + storeId: "LatteLarrys", +}).go({ ignoreOwnership: true }); diff --git a/www/src/examples/existing-table-ignore-ownership/table.ts b/www/src/examples/existing-table-ignore-ownership/table.ts new file mode 100644 index 00000000..89839700 --- /dev/null +++ b/www/src/examples/existing-table-ignore-ownership/table.ts @@ -0,0 +1,26 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-escape-function/entity.ts b/www/src/examples/filters-escape-function/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-escape-function/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-escape-function/example.ts b/www/src/examples/filters-escape-function/example.ts new file mode 100644 index 00000000..390d3d79 --- /dev/null +++ b/www/src/examples/filters-escape-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ diet }, { size, escape }) => ` + ${size(diet)} > ${escape(2)} + `, + ) + .go(); diff --git a/www/src/examples/filters-escape-function/table.ts b/www/src/examples/filters-escape-function/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-escape-function/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-field-function/entity.ts b/www/src/examples/filters-field-function/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-field-function/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-field-function/example.ts b/www/src/examples/filters-field-function/example.ts new file mode 100644 index 00000000..aaad7c8e --- /dev/null +++ b/www/src/examples/filters-field-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + (_, { field, escape }) => ` + contains(${field("gsi1sk")}, ${escape("value")}) + `, + ) + .go(); diff --git a/www/src/examples/filters-field-function/table.ts b/www/src/examples/filters-field-function/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-field-function/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-filter-expression/entity.ts b/www/src/examples/filters-filter-expression/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-filter-expression/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-filter-expression/example.ts b/www/src/examples/filters-filter-expression/example.ts new file mode 100644 index 00000000..608b1ec9 --- /dev/null +++ b/www/src/examples/filters-filter-expression/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa" }) + .where( + ({ isPregnant, offspring }, { exists, eq }) => ` + ${eq(isPregnant, true)} OR ${exists(offspring)} + `, + ) + .go(); diff --git a/www/src/examples/filters-filter-expression/table.ts b/www/src/examples/filters-filter-expression/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-filter-expression/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-multiple-where-clauses/entity.ts b/www/src/examples/filters-multiple-where-clauses/entity.ts new file mode 100644 index 00000000..cb405664 --- /dev/null +++ b/www/src/examples/filters-multiple-where-clauses/entity.ts @@ -0,0 +1,61 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const MallStores = new Entity( + { + model: { + service: "mallstoredirectory", + entity: "mallstore", + version: "1", + }, + attributes: { + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + }, + discount: { + type: "string", + default: "0.00", + }, + category: { + type: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["mallId"], + }, + sk: { + field: "sk", + composite: ["storeId"], + }, + }, + leases: { + index: "idx2", + pk: { + field: "idx2pk", + composite: ["mallId"], + }, + sk: { + field: "idx2sk", + composite: ["leaseEndDate", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-multiple-where-clauses/example.ts b/www/src/examples/filters-multiple-where-clauses/example.ts new file mode 100644 index 00000000..3062fdfb --- /dev/null +++ b/www/src/examples/filters-multiple-where-clauses/example.ts @@ -0,0 +1,16 @@ +import { MallStores } from "./entity"; + +let stores = await MallStores.query + .leases({ mallId: "EastPointe" }) + .between({ leaseEndDate: "2020-04-01" }, { leaseEndDate: "2020-07-01" }) + .where( + ({ rent, discount }, { between, eq }) => ` + ${between(rent, "2000.00", "5000.00")} AND ${eq(discount, "1000.00")} + `, + ) + .where( + ({ category }, { eq }) => ` + ${eq(category, "food/coffee")} + `, + ) + .go(); diff --git a/www/src/examples/filters-multiple-where-clauses/table.ts b/www/src/examples/filters-multiple-where-clauses/table.ts new file mode 100644 index 00000000..3e440201 --- /dev/null +++ b/www/src/examples/filters-multiple-where-clauses/table.ts @@ -0,0 +1,52 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "idx2pk", + AttributeType: "S", + }, + { + AttributeName: "idx2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "idx2", + KeySchema: [ + { + AttributeName: "idx2pk", + KeyType: "HASH", + }, + { + AttributeName: "idx2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-name-function/entity.ts b/www/src/examples/filters-name-function/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-name-function/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-name-function/example.ts b/www/src/examples/filters-name-function/example.ts new file mode 100644 index 00000000..bfe19adb --- /dev/null +++ b/www/src/examples/filters-name-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ lastFedBy, keeper }, { name }) => ` + ${name(lastFedBy)} != ${name(keeper)} + `, + ) + .go(); diff --git a/www/src/examples/filters-name-function/table.ts b/www/src/examples/filters-name-function/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-name-function/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-value-function/entity.ts b/www/src/examples/filters-value-function/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-value-function/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-value-function/example.ts b/www/src/examples/filters-value-function/example.ts new file mode 100644 index 00000000..92fd60f4 --- /dev/null +++ b/www/src/examples/filters-value-function/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + ({ keeper }, { name, value, eq }) => ` + ${name(keeper)} = ${value(keeper, "Tiger King")} + `, + ) + .go(); diff --git a/www/src/examples/filters-value-function/table.ts b/www/src/examples/filters-value-function/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-value-function/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-chained/entity.ts b/www/src/examples/filters-where-chained/entity.ts new file mode 100644 index 00000000..9ae25eba --- /dev/null +++ b/www/src/examples/filters-where-chained/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "number", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-chained/example.ts b/www/src/examples/filters-where-chained/example.ts new file mode 100644 index 00000000..756e4328 --- /dev/null +++ b/www/src/examples/filters-where-chained/example.ts @@ -0,0 +1,13 @@ +import { animals } from "./entity"; + +animals.query + .habitats({ habitat: "Africa", enclosure: "5b" }) + .where((attr, op) => ` + ${op.eq(attr.dangerous, true)} OR ${op.notExists(attr.lastFed)} + `) + .where(({ birthday }, { between }) => { + const today = Date.now(); + const lastMonth = today - 1000 * 60 * 60 * 24 * 30; + return between(birthday, lastMonth, today); + }) + .go(); diff --git a/www/src/examples/filters-where-chained/table.ts b/www/src/examples/filters-where-chained/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-chained/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-destructured/entity.ts b/www/src/examples/filters-where-destructured/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-destructured/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-destructured/example.ts b/www/src/examples/filters-where-destructured/example.ts new file mode 100644 index 00000000..b5233a36 --- /dev/null +++ b/www/src/examples/filters-where-destructured/example.ts @@ -0,0 +1,6 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where(({ dangerous }, { eq }) => eq(dangerous, true)) + .go(); diff --git a/www/src/examples/filters-where-destructured/table.ts b/www/src/examples/filters-where-destructured/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-destructured/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-dynamic/entity.ts b/www/src/examples/filters-where-dynamic/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-dynamic/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-dynamic/example.ts b/www/src/examples/filters-where-dynamic/example.ts new file mode 100644 index 00000000..a5099e2d --- /dev/null +++ b/www/src/examples/filters-where-dynamic/example.ts @@ -0,0 +1,19 @@ +import { animals } from "./entity"; + +type GetAnimalOptions = { + habitat: string; + keepers: string[]; +}; + +function getAnimals(options: GetAnimalOptions) { + const { habitat, keepers } = options; + return animals.query.exhibit({ habitat }) + .where(({ keeper }, { eq }) => { + return keepers.map((name) => eq(keeper, name)).join(' AND '); + }).go() +} + +const { data, cursor } = await getAnimals({ + habitat: "RainForest", + keepers: ["Joe Exotic", "Carol Baskin"], +}); diff --git a/www/src/examples/filters-where-dynamic/table.ts b/www/src/examples/filters-where-dynamic/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-dynamic/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-list-attribute/entity.ts b/www/src/examples/filters-where-list-attribute/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-list-attribute/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-list-attribute/example.ts b/www/src/examples/filters-where-list-attribute/example.ts new file mode 100644 index 00000000..7659495b --- /dev/null +++ b/www/src/examples/filters-where-list-attribute/example.ts @@ -0,0 +1,6 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Tundra" }) + .where(({ offspring }, { eq }) => eq(offspring[0].name, "Blitzen")) + .go(); diff --git a/www/src/examples/filters-where-list-attribute/table.ts b/www/src/examples/filters-where-list-attribute/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-list-attribute/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-map-attribute/entity.ts b/www/src/examples/filters-where-map-attribute/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-map-attribute/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-map-attribute/example.ts b/www/src/examples/filters-where-map-attribute/example.ts new file mode 100644 index 00000000..3c419a10 --- /dev/null +++ b/www/src/examples/filters-where-map-attribute/example.ts @@ -0,0 +1,6 @@ +import { animals } from "./entity"; + +animals.query + .farm({ habitat: "Africa" }) + .where(({ veterinarian }, { eq }) => eq(veterinarian.name, "Herb Peterson")) + .go(); diff --git a/www/src/examples/filters-where-map-attribute/table.ts b/www/src/examples/filters-where-map-attribute/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-map-attribute/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-multiple/entity.ts b/www/src/examples/filters-where-multiple/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-multiple/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-multiple/example.ts b/www/src/examples/filters-where-multiple/example.ts new file mode 100644 index 00000000..bab21a50 --- /dev/null +++ b/www/src/examples/filters-where-multiple/example.ts @@ -0,0 +1,10 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where( + (attr, op) => ` + ${op.eq(attr.dangerous, true)} AND ${op.notExists(attr.lastFed)} + `, + ) + .go(); diff --git a/www/src/examples/filters-where-multiple/table.ts b/www/src/examples/filters-where-multiple/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-multiple/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/filters-where-single/entity.ts b/www/src/examples/filters-where-single/entity.ts new file mode 100644 index 00000000..0ff8c6f1 --- /dev/null +++ b/www/src/examples/filters-where-single/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const animals = new Entity( + { + model: { + service: "zoo", + entity: "animals", + version: "1", + }, + attributes: { + animal: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + habitat: { + type: "string", + required: true, + }, + enclosure: { + type: "string", + required: true, + }, + keeper: { + type: "string", + }, + dangerous: { + type: "boolean", + }, + diet: { + type: "list", + items: { + type: "string", + }, + }, + lastFed: { + type: "string", + }, + lastFedBy: { + type: "string", + }, + birthday: { + type: "string", + }, + isPregnant: { + type: "boolean", + }, + veterinarian: { + type: "map", + properties: { + name: { + type: "string", + }, + }, + }, + offspring: { + type: "list", + items: { + type: "map", + properties: { + name: { + type: "string", + }, + birthday: { + type: "string", + }, + note: { + type: "string", + }, + }, + }, + }, + }, + indexes: { + byAnimal: { + pk: { + field: "pk", + composite: ["animal"], + }, + sk: { + field: "sk", + composite: ["name"], + }, + }, + exhibit: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["habitat"], + }, + sk: { + field: "gsi1sk", + composite: ["enclosure"], + }, + }, + habitats: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["habitat"], + }, + sk: { + field: "gsi2sk", + composite: ["enclosure"], + }, + }, + farm: { + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["habitat"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/filters-where-single/example.ts b/www/src/examples/filters-where-single/example.ts new file mode 100644 index 00000000..4cabc8f0 --- /dev/null +++ b/www/src/examples/filters-where-single/example.ts @@ -0,0 +1,6 @@ +import { animals } from "./entity"; + +animals.query + .exhibit({ habitat: "Africa", enclosure: "5b" }) + .where((attr, op) => op.eq(attr.dangerous, true)) + .go(); diff --git a/www/src/examples/filters-where-single/table.ts b/www/src/examples/filters-where-single/table.ts new file mode 100644 index 00000000..bf25d627 --- /dev/null +++ b/www/src/examples/filters-where-single/table.ts @@ -0,0 +1,100 @@ +export const tableName = "zoo_manifest"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/find-store-location/entity.ts b/www/src/examples/find-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/find-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/find-store-location/example.ts b/www/src/examples/find-store-location/example.ts new file mode 100644 index 00000000..64df49ad --- /dev/null +++ b/www/src/examples/find-store-location/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.find({ + mallId: "EastPointe", + buildingId: "BuildingA1", +}).go(); diff --git a/www/src/examples/find-store-location/table.ts b/www/src/examples/find-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/find-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-assignments/entities.ts b/www/src/examples/human-resources-assignments/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-assignments/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-assignments/example.ts b/www/src/examples/human-resources-assignments/example.ts new file mode 100644 index 00000000..92373889 --- /dev/null +++ b/www/src/examples/human-resources-assignments/example.ts @@ -0,0 +1,3 @@ +import { EmployeeApp } from "./service"; + +await EmployeeApp.collections.assignments({ employee: "CBaskin" }).go(); diff --git a/www/src/examples/human-resources-assignments/service.ts b/www/src/examples/human-resources-assignments/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-assignments/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-assignments/table.ts b/www/src/examples/human-resources-assignments/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-assignments/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-birthdays/entities.ts b/www/src/examples/human-resources-birthdays/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-birthdays/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-birthdays/service.ts b/www/src/examples/human-resources-birthdays/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-birthdays/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-birthdays/table.ts b/www/src/examples/human-resources-birthdays/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-birthdays/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-direct-reports/entities.ts b/www/src/examples/human-resources-direct-reports/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-direct-reports/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-direct-reports/service.ts b/www/src/examples/human-resources-direct-reports/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-direct-reports/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-direct-reports/table.ts b/www/src/examples/human-resources-direct-reports/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-direct-reports/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-employee-roles/entities.ts b/www/src/examples/human-resources-employee-roles/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-employee-roles/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-employee-roles/service.ts b/www/src/examples/human-resources-employee-roles/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-employee-roles/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-employee-roles/table.ts b/www/src/examples/human-resources-employee-roles/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-employee-roles/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-employee-tasks/entities.ts b/www/src/examples/human-resources-employee-tasks/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-employee-tasks/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-employee-tasks/example.ts b/www/src/examples/human-resources-employee-tasks/example.ts new file mode 100644 index 00000000..6b736ab0 --- /dev/null +++ b/www/src/examples/human-resources-employee-tasks/example.ts @@ -0,0 +1,8 @@ +import { EmployeeApp } from "./service"; +import { Task } from "./entities"; + +// on the service +await EmployeeApp.entities.tasks.query.assigned({ employee: "cbaskin" }).go(); + +// on the entity +await Task.query.assigned({ employee: "cbaskin" }).go(); diff --git a/www/src/examples/human-resources-employee-tasks/service.ts b/www/src/examples/human-resources-employee-tasks/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-employee-tasks/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-employee-tasks/table.ts b/www/src/examples/human-resources-employee-tasks/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-employee-tasks/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-office-locations/entities.ts b/www/src/examples/human-resources-office-locations/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-office-locations/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-office-locations/service.ts b/www/src/examples/human-resources-office-locations/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-office-locations/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-office-locations/table.ts b/www/src/examples/human-resources-office-locations/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-office-locations/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-project-tasks/entities.ts b/www/src/examples/human-resources-project-tasks/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-project-tasks/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-project-tasks/example.ts b/www/src/examples/human-resources-project-tasks/example.ts new file mode 100644 index 00000000..f1f2a824 --- /dev/null +++ b/www/src/examples/human-resources-project-tasks/example.ts @@ -0,0 +1,10 @@ +import { EmployeeApp } from "./service"; +import { Task } from "./entities"; + +// on the service +await EmployeeApp.entities.tasks.query + .project({ project: "Murder Carol" }) + .go(); + +// on the entity +await Task.query.project({ project: "Murder Carol" }).go(); diff --git a/www/src/examples/human-resources-project-tasks/service.ts b/www/src/examples/human-resources-project-tasks/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-project-tasks/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-project-tasks/table.ts b/www/src/examples/human-resources-project-tasks/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-project-tasks/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/human-resources-workplaces/entities.ts b/www/src/examples/human-resources-workplaces/entities.ts new file mode 100644 index 00000000..79a81b9e --- /dev/null +++ b/www/src/examples/human-resources-workplaces/entities.ts @@ -0,0 +1,229 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskapp", + }, + attributes: { + employee: { + type: "string", + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + office: { + type: "string", + }, + title: { + type: "string", + }, + team: { + type: ["development", "marketing", "finance", "product"] as const, + }, + salary: { + type: "string", + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + }, + birthday: { + type: "string", + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["title", "salary", "employee"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary", "employee"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office", "employee"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskapp", + }, + attributes: { + task: { + type: "string", + }, + project: { + type: "string", + }, + employee: { + type: "string", + }, + description: { + type: "string", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "task"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "task"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskapp", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/human-resources-workplaces/example.ts b/www/src/examples/human-resources-workplaces/example.ts new file mode 100644 index 00000000..0269e88d --- /dev/null +++ b/www/src/examples/human-resources-workplaces/example.ts @@ -0,0 +1,3 @@ +import { EmployeeApp } from "./service"; + +await EmployeeApp.collections.workplaces({ office: "big cat rescue" }).go(); diff --git a/www/src/examples/human-resources-workplaces/service.ts b/www/src/examples/human-resources-workplaces/service.ts new file mode 100644 index 00000000..8c591cf9 --- /dev/null +++ b/www/src/examples/human-resources-workplaces/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { Employee, Task, Office } from "./entities"; + +export const EmployeeApp = new Service({ + employees: Employee, + tasks: Task, + offices: Office, +}); diff --git a/www/src/examples/human-resources-workplaces/table.ts b/www/src/examples/human-resources-workplaces/table.ts new file mode 100644 index 00000000..393a7e73 --- /dev/null +++ b/www/src/examples/human-resources-workplaces/table.ts @@ -0,0 +1,148 @@ +export const tableName = "projectmanagement"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/include-projection-gsi-basic-query/entity.ts b/www/src/examples/include-projection-gsi-basic-query/entity.ts new file mode 100644 index 00000000..b941085a --- /dev/null +++ b/www/src/examples/include-projection-gsi-basic-query/entity.ts @@ -0,0 +1,67 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + priority: { + type: "number", + }, + createdAt: { + type: "number", + default: () => Date.now(), + }, + updatedAt: { + type: "number", + watch: "*", + set: () => Date.now(), + }, + }, + indexes: { + tasks: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + statusIndex: { + index: "gsi1pk-gsi1sk-index", + projection: ["name", "status", "createdAt"], + pk: { + field: "gsi1pk", + composite: ["status"], + }, + sk: { + field: "gsi1sk", + composite: ["createdAt"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/include-projection-gsi-basic-query/example.ts b/www/src/examples/include-projection-gsi-basic-query/example.ts new file mode 100644 index 00000000..e636d85b --- /dev/null +++ b/www/src/examples/include-projection-gsi-basic-query/example.ts @@ -0,0 +1,6 @@ +import { tasks } from "./entity"; + +// Only returns the projected attributes: name, status, createdAt +const { data, cursor } = await tasks.query.statusIndex({ status: "open" }).go(); + +// data will only contain: { name: string, status: string, createdAt: number }[] diff --git a/www/src/examples/include-projection-gsi-basic-query/table.ts b/www/src/examples/include-projection-gsi-basic-query/table.ts new file mode 100644 index 00000000..a879d83b --- /dev/null +++ b/www/src/examples/include-projection-gsi-basic-query/table.ts @@ -0,0 +1,53 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "INCLUDE", + NonKeyAttributes: ["name", "status", "createdAt", "__edb_e__", "__edb_v__"], + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/include-projection-gsi-filter-non-projected/entity.ts b/www/src/examples/include-projection-gsi-filter-non-projected/entity.ts new file mode 100644 index 00000000..b941085a --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-non-projected/entity.ts @@ -0,0 +1,67 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + priority: { + type: "number", + }, + createdAt: { + type: "number", + default: () => Date.now(), + }, + updatedAt: { + type: "number", + watch: "*", + set: () => Date.now(), + }, + }, + indexes: { + tasks: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + statusIndex: { + index: "gsi1pk-gsi1sk-index", + projection: ["name", "status", "createdAt"], + pk: { + field: "gsi1pk", + composite: ["status"], + }, + sk: { + field: "gsi1sk", + composite: ["createdAt"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/include-projection-gsi-filter-non-projected/example.ts b/www/src/examples/include-projection-gsi-filter-non-projected/example.ts new file mode 100644 index 00000000..2c52183b --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-non-projected/example.ts @@ -0,0 +1,8 @@ +import { tasks } from "./entity"; + +// This would not work - filtering on non-projected attributes +const { data } = await tasks.query + .statusIndex({ status: "open" }) + // @ts-expect-error - `description` is not included in the statusIndex projection + .where(({ description }, { eq }) => eq(description, "Some description")) + .go(); diff --git a/www/src/examples/include-projection-gsi-filter-non-projected/table.ts b/www/src/examples/include-projection-gsi-filter-non-projected/table.ts new file mode 100644 index 00000000..a879d83b --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-non-projected/table.ts @@ -0,0 +1,53 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "INCLUDE", + NonKeyAttributes: ["name", "status", "createdAt", "__edb_e__", "__edb_v__"], + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/include-projection-gsi-filter-projected/entity.ts b/www/src/examples/include-projection-gsi-filter-projected/entity.ts new file mode 100644 index 00000000..b941085a --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-projected/entity.ts @@ -0,0 +1,67 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + priority: { + type: "number", + }, + createdAt: { + type: "number", + default: () => Date.now(), + }, + updatedAt: { + type: "number", + watch: "*", + set: () => Date.now(), + }, + }, + indexes: { + tasks: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + statusIndex: { + index: "gsi1pk-gsi1sk-index", + projection: ["name", "status", "createdAt"], + pk: { + field: "gsi1pk", + composite: ["status"], + }, + sk: { + field: "gsi1sk", + composite: ["createdAt"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/include-projection-gsi-filter-projected/example.ts b/www/src/examples/include-projection-gsi-filter-projected/example.ts new file mode 100644 index 00000000..abc05094 --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-projected/example.ts @@ -0,0 +1,7 @@ +import { tasks } from "./entity"; + +// This works - filtering on projected attributes +const { data } = await tasks.query + .statusIndex({ status: "open" }) + .where(({ name }, { eq }) => eq(name, "Important Task")) + .go(); diff --git a/www/src/examples/include-projection-gsi-filter-projected/table.ts b/www/src/examples/include-projection-gsi-filter-projected/table.ts new file mode 100644 index 00000000..a879d83b --- /dev/null +++ b/www/src/examples/include-projection-gsi-filter-projected/table.ts @@ -0,0 +1,53 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "INCLUDE", + NonKeyAttributes: ["name", "status", "createdAt", "__edb_e__", "__edb_v__"], + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/include-projection-gsi-hydration-attributes/entity.ts b/www/src/examples/include-projection-gsi-hydration-attributes/entity.ts new file mode 100644 index 00000000..b941085a --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration-attributes/entity.ts @@ -0,0 +1,67 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + priority: { + type: "number", + }, + createdAt: { + type: "number", + default: () => Date.now(), + }, + updatedAt: { + type: "number", + watch: "*", + set: () => Date.now(), + }, + }, + indexes: { + tasks: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + statusIndex: { + index: "gsi1pk-gsi1sk-index", + projection: ["name", "status", "createdAt"], + pk: { + field: "gsi1pk", + composite: ["status"], + }, + sk: { + field: "gsi1sk", + composite: ["createdAt"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/include-projection-gsi-hydration-attributes/example.ts b/www/src/examples/include-projection-gsi-hydration-attributes/example.ts new file mode 100644 index 00000000..d4189be4 --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration-attributes/example.ts @@ -0,0 +1,11 @@ +import { tasks } from "./entity"; + +const { data } = await tasks.query + .statusIndex({ status: "open" }) + .where((attr, op) => op.eq(attr.name, "Important Task")) + .go({ + hydrate: true, + attributes: ["taskId", "name", "description"], + }); + +// data will only contain: { taskId: string, name: string, description: string }[] diff --git a/www/src/examples/include-projection-gsi-hydration-attributes/table.ts b/www/src/examples/include-projection-gsi-hydration-attributes/table.ts new file mode 100644 index 00000000..a879d83b --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration-attributes/table.ts @@ -0,0 +1,53 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "INCLUDE", + NonKeyAttributes: ["name", "status", "createdAt", "__edb_e__", "__edb_v__"], + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/include-projection-gsi-hydration/entity.ts b/www/src/examples/include-projection-gsi-hydration/entity.ts new file mode 100644 index 00000000..b941085a --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration/entity.ts @@ -0,0 +1,67 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + taskId: { + type: "string", + }, + projectId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + priority: { + type: "number", + }, + createdAt: { + type: "number", + default: () => Date.now(), + }, + updatedAt: { + type: "number", + watch: "*", + set: () => Date.now(), + }, + }, + indexes: { + tasks: { + pk: { + field: "pk", + composite: ["projectId"], + }, + sk: { + field: "sk", + composite: ["taskId"], + }, + }, + statusIndex: { + index: "gsi1pk-gsi1sk-index", + projection: ["name", "status", "createdAt"], + pk: { + field: "gsi1pk", + composite: ["status"], + }, + sk: { + field: "gsi1sk", + composite: ["createdAt"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/include-projection-gsi-hydration/example.ts b/www/src/examples/include-projection-gsi-hydration/example.ts new file mode 100644 index 00000000..00697866 --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration/example.ts @@ -0,0 +1,9 @@ +import { tasks } from "./entity"; + +// With hydration, you get all attributes but can only filter on projected ones +const { data } = await tasks.query + .statusIndex({ status: "open" }) + .where((attr, op) => op.eq(attr.name, "Important Task")) + .go({ hydrate: true }); + +// data will contain all attributes: { taskId, projectId, name, description, status, priority, createdAt, updatedAt }[] diff --git a/www/src/examples/include-projection-gsi-hydration/table.ts b/www/src/examples/include-projection-gsi-hydration/table.ts new file mode 100644 index 00000000..a879d83b --- /dev/null +++ b/www/src/examples/include-projection-gsi-hydration/table.ts @@ -0,0 +1,53 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "INCLUDE", + NonKeyAttributes: ["name", "status", "createdAt", "__edb_e__", "__edb_v__"], + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-attributes-as-indexes-get/entity.ts b/www/src/examples/indexes-attributes-as-indexes-get/entity.ts new file mode 100644 index 00000000..64ec3897 --- /dev/null +++ b/www/src/examples/indexes-attributes-as-indexes-get/entity.ts @@ -0,0 +1,37 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const myEntity = new Entity( + { + model: { + entity: "your_entity_name", + service: "your_service_name", + version: "1", + }, + attributes: { + accountId: { + type: "string", // only string types are both supported for this example + }, + organizationId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + your_access_pattern_name: { + pk: { + field: "accountId", + composite: ["accountId"], + template: "prefix_${accountId}_postfix", + }, + sk: { + field: "organizationId", + composite: ["organizationId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-attributes-as-indexes-get/example.ts b/www/src/examples/indexes-attributes-as-indexes-get/example.ts new file mode 100644 index 00000000..a4e20a84 --- /dev/null +++ b/www/src/examples/indexes-attributes-as-indexes-get/example.ts @@ -0,0 +1,8 @@ +import { myEntity } from "./entity"; + +await myEntity + .get({ + accountId: "1111-2222-3333-4444", + organizationId: "AAAA-BBBB-CCCC-DDDD", + }) + .go(); diff --git a/www/src/examples/indexes-attributes-as-indexes-get/table.ts b/www/src/examples/indexes-attributes-as-indexes-get/table.ts new file mode 100644 index 00000000..6d244218 --- /dev/null +++ b/www/src/examples/indexes-attributes-as-indexes-get/table.ts @@ -0,0 +1,26 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "accountId", + KeyType: "HASH", + }, + { + AttributeName: "organizationId", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "accountId", + AttributeType: "S", + }, + { + AttributeName: "organizationId", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-basic-query/entity.ts b/www/src/examples/indexes-multi-attribute-basic-query/entity.ts new file mode 100644 index 00000000..c09847ee --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-basic-query/entity.ts @@ -0,0 +1,74 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + field: "attr5", + }, + count: { + type: "number", + field: "attr6", + }, + name: { + type: "string", + field: "attr7", + }, + }, + indexes: { + // The main table index still uses traditional pk/sk fields + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + // A multi-attribute GSI — note: no 'field' on pk or sk + location: { + index: "gsi1", + type: "composite", + pk: { + composite: ["country", "region", "city"], + }, + sk: { + composite: ["manufacturer", "model", "count"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-basic-query/example.ts b/www/src/examples/indexes-multi-attribute-basic-query/example.ts new file mode 100644 index 00000000..e82ac5bd --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-basic-query/example.ts @@ -0,0 +1,5 @@ +import { InventoryItem } from "./entity"; + +const results = await InventoryItem.query + .location({ country: "US", region: "Georgia", city: "Atlanta" }) + .go(); diff --git a/www/src/examples/indexes-multi-attribute-basic-query/table.ts b/www/src/examples/indexes-multi-attribute-basic-query/table.ts new file mode 100644 index 00000000..63bd474e --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-basic-query/table.ts @@ -0,0 +1,34 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "S" }, + { AttributeName: "attr6", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + { AttributeName: "attr6", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-begins/entity.ts b/www/src/examples/indexes-multi-attribute-begins/entity.ts new file mode 100644 index 00000000..c09847ee --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-begins/entity.ts @@ -0,0 +1,74 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + field: "attr5", + }, + count: { + type: "number", + field: "attr6", + }, + name: { + type: "string", + field: "attr7", + }, + }, + indexes: { + // The main table index still uses traditional pk/sk fields + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + // A multi-attribute GSI — note: no 'field' on pk or sk + location: { + index: "gsi1", + type: "composite", + pk: { + composite: ["country", "region", "city"], + }, + sk: { + composite: ["manufacturer", "model", "count"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-begins/example.ts b/www/src/examples/indexes-multi-attribute-begins/example.ts new file mode 100644 index 00000000..84dab497 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-begins/example.ts @@ -0,0 +1,6 @@ +import { InventoryItem } from "./entity"; + +await InventoryItem.query + .location({ country: "US", region: "Georgia", city: "Atlanta" }) + .begins({ manufacturer: "A" }) + .go(); diff --git a/www/src/examples/indexes-multi-attribute-begins/table.ts b/www/src/examples/indexes-multi-attribute-begins/table.ts new file mode 100644 index 00000000..63bd474e --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-begins/table.ts @@ -0,0 +1,34 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "S" }, + { AttributeName: "attr6", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + { AttributeName: "attr6", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-between/entity.ts b/www/src/examples/indexes-multi-attribute-between/entity.ts new file mode 100644 index 00000000..c09847ee --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-between/entity.ts @@ -0,0 +1,74 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + field: "attr5", + }, + count: { + type: "number", + field: "attr6", + }, + name: { + type: "string", + field: "attr7", + }, + }, + indexes: { + // The main table index still uses traditional pk/sk fields + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + // A multi-attribute GSI — note: no 'field' on pk or sk + location: { + index: "gsi1", + type: "composite", + pk: { + composite: ["country", "region", "city"], + }, + sk: { + composite: ["manufacturer", "model", "count"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-between/example.ts b/www/src/examples/indexes-multi-attribute-between/example.ts new file mode 100644 index 00000000..5d322d43 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-between/example.ts @@ -0,0 +1,9 @@ +import { InventoryItem } from "./entity"; + +await InventoryItem.query + .location({ country: "US", region: "Georgia", city: "Atlanta" }) + .between( + { manufacturer: "Acme", model: "X1", count: 50 }, + { manufacturer: "Acme", model: "X1", count: 200 }, + ) + .go(); diff --git a/www/src/examples/indexes-multi-attribute-between/table.ts b/www/src/examples/indexes-multi-attribute-between/table.ts new file mode 100644 index 00000000..63bd474e --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-between/table.ts @@ -0,0 +1,34 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "S" }, + { AttributeName: "attr6", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + { AttributeName: "attr6", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-collection-begins/entities.ts b/www/src/examples/indexes-multi-attribute-collection-begins/entities.ts new file mode 100644 index 00000000..792370c2 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-begins/entities.ts @@ -0,0 +1,131 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + }, + count: { + type: "number", + field: "attr5", + }, + productName: { + type: "string", + field: "attr6", + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + location: { + index: "gsi1", + type: "composite", + collection: "inventory", + pk: { + composite: ["country", "region"], + }, + sk: { + composite: ["city", "manufacturer", "count"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Warehouse = new Entity( + { + model: { + entity: "warehouse", + version: "1", + service: "warehouse", + }, + attributes: { + warehouseId: { + type: "string", + required: true, + field: "attr4", + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + streetAddress: { + type: "string", + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["warehouseId"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + location: { + index: "gsi1", + type: "composite", + collection: "inventory", + pk: { + composite: ["country", "region"], + }, + sk: { + composite: ["city", "warehouseId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-collection-begins/example.ts b/www/src/examples/indexes-multi-attribute-collection-begins/example.ts new file mode 100644 index 00000000..4e583102 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-begins/example.ts @@ -0,0 +1,8 @@ +import { service } from "./service"; + +const filtered = await service.collections + .inventory({ country: "US", region: "Georgia" }) + .begins({ city: "A" }) + .go(); +// results.data.InventoryItem -> InventoryItem[] +// results.data.Warehouse -> Warehouse[] diff --git a/www/src/examples/indexes-multi-attribute-collection-begins/service.ts b/www/src/examples/indexes-multi-attribute-collection-begins/service.ts new file mode 100644 index 00000000..a50a491d --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-begins/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { InventoryItem, Warehouse } from "./entities"; + +export const service = new Service({ InventoryItem, Warehouse }); diff --git a/www/src/examples/indexes-multi-attribute-collection-begins/table.ts b/www/src/examples/indexes-multi-attribute-collection-begins/table.ts new file mode 100644 index 00000000..e83b7404 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-begins/table.ts @@ -0,0 +1,32 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-collection-query/entities.ts b/www/src/examples/indexes-multi-attribute-collection-query/entities.ts new file mode 100644 index 00000000..792370c2 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-query/entities.ts @@ -0,0 +1,131 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + }, + count: { + type: "number", + field: "attr5", + }, + productName: { + type: "string", + field: "attr6", + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + location: { + index: "gsi1", + type: "composite", + collection: "inventory", + pk: { + composite: ["country", "region"], + }, + sk: { + composite: ["city", "manufacturer", "count"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Warehouse = new Entity( + { + model: { + entity: "warehouse", + version: "1", + service: "warehouse", + }, + attributes: { + warehouseId: { + type: "string", + required: true, + field: "attr4", + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + streetAddress: { + type: "string", + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["warehouseId"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + location: { + index: "gsi1", + type: "composite", + collection: "inventory", + pk: { + composite: ["country", "region"], + }, + sk: { + composite: ["city", "warehouseId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-collection-query/example.ts b/www/src/examples/indexes-multi-attribute-collection-query/example.ts new file mode 100644 index 00000000..bf3b1ceb --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-query/example.ts @@ -0,0 +1,7 @@ +import { service } from "./service"; + +const results = await service.collections + .inventory({ country: "US", region: "Georgia", city: "Atlanta" }) + .go(); +// results.data.InventoryItem -> InventoryItem[] +// results.data.Warehouse -> Warehouse[] diff --git a/www/src/examples/indexes-multi-attribute-collection-query/service.ts b/www/src/examples/indexes-multi-attribute-collection-query/service.ts new file mode 100644 index 00000000..a50a491d --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-query/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { InventoryItem, Warehouse } from "./entities"; + +export const service = new Service({ InventoryItem, Warehouse }); diff --git a/www/src/examples/indexes-multi-attribute-collection-query/table.ts b/www/src/examples/indexes-multi-attribute-collection-query/table.ts new file mode 100644 index 00000000..e83b7404 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-collection-query/table.ts @@ -0,0 +1,32 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-multi-attribute-gt/entity.ts b/www/src/examples/indexes-multi-attribute-gt/entity.ts new file mode 100644 index 00000000..c09847ee --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-gt/entity.ts @@ -0,0 +1,74 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const InventoryItem = new Entity( + { + model: { + entity: "inventoryitem", + version: "1", + service: "warehouse", + }, + attributes: { + id: { + type: "string", + required: true, + }, + country: { + type: "string", + field: "attr1", + required: true, + }, + region: { + type: "string", + field: "attr2", + required: true, + }, + city: { + type: "string", + field: "attr3", + required: true, + }, + manufacturer: { + type: "string", + field: "attr4", + }, + model: { + type: "string", + field: "attr5", + }, + count: { + type: "number", + field: "attr6", + }, + name: { + type: "string", + field: "attr7", + }, + }, + indexes: { + // The main table index still uses traditional pk/sk fields + record: { + pk: { + field: "pk", + composite: ["manufacturer"], + }, + sk: { + field: "sk", + composite: ["model", "id"], + }, + }, + // A multi-attribute GSI — note: no 'field' on pk or sk + location: { + index: "gsi1", + type: "composite", + pk: { + composite: ["country", "region", "city"], + }, + sk: { + composite: ["manufacturer", "model", "count"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-multi-attribute-gt/example.ts b/www/src/examples/indexes-multi-attribute-gt/example.ts new file mode 100644 index 00000000..6dd4a4a8 --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-gt/example.ts @@ -0,0 +1,6 @@ +import { InventoryItem } from "./entity"; + +await InventoryItem.query + .location({ country: "US", region: "Georgia", city: "Atlanta" }) + .gt({ manufacturer: "Acme", model: "X1", count: 100 }) + .go(); diff --git a/www/src/examples/indexes-multi-attribute-gt/table.ts b/www/src/examples/indexes-multi-attribute-gt/table.ts new file mode 100644 index 00000000..63bd474e --- /dev/null +++ b/www/src/examples/indexes-multi-attribute-gt/table.ts @@ -0,0 +1,34 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { AttributeName: "pk", KeyType: "HASH" }, + { AttributeName: "sk", KeyType: "RANGE" }, + ], + AttributeDefinitions: [ + { AttributeName: "pk", AttributeType: "S" }, + { AttributeName: "sk", AttributeType: "S" }, + { AttributeName: "attr1", AttributeType: "S" }, + { AttributeName: "attr2", AttributeType: "S" }, + { AttributeName: "attr3", AttributeType: "S" }, + { AttributeName: "attr4", AttributeType: "S" }, + { AttributeName: "attr5", AttributeType: "S" }, + { AttributeName: "attr6", AttributeType: "N" }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1", + KeySchema: [ + { AttributeName: "attr1", KeyType: "HASH" }, + { AttributeName: "attr2", KeyType: "HASH" }, + { AttributeName: "attr3", KeyType: "RANGE" }, + { AttributeName: "attr4", KeyType: "RANGE" }, + { AttributeName: "attr5", KeyType: "RANGE" }, + { AttributeName: "attr6", KeyType: "RANGE" }, + ], + Projection: { ProjectionType: "ALL" }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-scope-with-scope/entities.ts b/www/src/examples/indexes-scope-with-scope/entities.ts new file mode 100644 index 00000000..4111d059 --- /dev/null +++ b/www/src/examples/indexes-scope-with-scope/entities.ts @@ -0,0 +1,60 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const organization = new Entity( + { + model: { + entity: "organization", + service: "taskapp", + version: "1", + }, + attributes: { + organizationId: { + type: "string", + }, + }, + indexes: { + myIndex: { + scope: "org", // <--- Scope is set to unique value "org" + pk: { + field: "pk", + composite: [], + }, + sk: { + field: "sk", + composite: ["organizationId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const user = new Entity( + { + model: { + entity: "user", + service: "taskapp", + version: "1", + }, + attributes: { + userId: { + type: "string", + }, + }, + indexes: { + myIndex: { + scope: "user", // <--- Scope is set to unique value "user" + pk: { + field: "pk", + composite: [], + }, + sk: { + field: "sk", + composite: ["userId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-scope-with-scope/example.ts b/www/src/examples/indexes-scope-with-scope/example.ts new file mode 100644 index 00000000..1ecee253 --- /dev/null +++ b/www/src/examples/indexes-scope-with-scope/example.ts @@ -0,0 +1,5 @@ +import { organization, user } from "./entities"; + +await organization.query.myIndex({ organizationId: "123" }).go(); + +await user.query.myIndex({ userId: "456" }).go(); diff --git a/www/src/examples/indexes-scope-with-scope/table.ts b/www/src/examples/indexes-scope-with-scope/table.ts new file mode 100644 index 00000000..d66a3927 --- /dev/null +++ b/www/src/examples/indexes-scope-with-scope/table.ts @@ -0,0 +1,26 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/indexes-scope-without-scope/entities.ts b/www/src/examples/indexes-scope-without-scope/entities.ts new file mode 100644 index 00000000..153d9cdd --- /dev/null +++ b/www/src/examples/indexes-scope-without-scope/entities.ts @@ -0,0 +1,58 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const organization = new Entity( + { + model: { + entity: "organization", + service: "taskapp", + version: "1", + }, + attributes: { + organizationId: { + type: "string", + }, + }, + indexes: { + myIndex: { + pk: { + field: "pk", + composite: [], + }, + sk: { + field: "sk", + composite: ["organizationId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const user = new Entity( + { + model: { + entity: "user", + service: "taskapp", + version: "1", + }, + attributes: { + userId: { + type: "string", + }, + }, + indexes: { + myIndex: { + pk: { + field: "pk", + composite: [], + }, + sk: { + field: "sk", + composite: ["userId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/indexes-scope-without-scope/example.ts b/www/src/examples/indexes-scope-without-scope/example.ts new file mode 100644 index 00000000..1ecee253 --- /dev/null +++ b/www/src/examples/indexes-scope-without-scope/example.ts @@ -0,0 +1,5 @@ +import { organization, user } from "./entities"; + +await organization.query.myIndex({ organizationId: "123" }).go(); + +await user.query.myIndex({ userId: "456" }).go(); diff --git a/www/src/examples/indexes-scope-without-scope/table.ts b/www/src/examples/indexes-scope-without-scope/table.ts new file mode 100644 index 00000000..d66a3927 --- /dev/null +++ b/www/src/examples/indexes-scope-without-scope/table.ts @@ -0,0 +1,26 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/introduction-patch-task/entity.ts b/www/src/examples/introduction-patch-task/entity.ts new file mode 100644 index 00000000..f266e3ee --- /dev/null +++ b/www/src/examples/introduction-patch-task/entity.ts @@ -0,0 +1,122 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + team: { + type: "string", + required: true, + }, + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + user: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + // use an array to type an enum + type: ["open", "in-progress", "on-hold", "closed"] as const, + default: "open", + }, + points: { + type: "number", + }, + tags: { + type: "set", + items: "string", + }, + comments: { + type: "list", + items: { + type: "map", + properties: { + user: { + type: "string", + }, + body: { + type: "string", + }, + }, + }, + }, + closed: { + type: "string", + validate: /[0-9]{4}-[0-9]{2}-[0-9]{2}/, + }, + createdAt: { + type: "number", + default: () => Date.now(), + // cannot be modified after created + readOnly: true, + }, + updatedAt: { + type: "number", + // watch for changes to any attribute + watch: "*", + // set current timestamp when updated + set: () => Date.now(), + readOnly: true, + }, + }, + indexes: { + projects: { + pk: { + field: "pk", + composite: ["team"], + }, + sk: { + field: "sk", + // create composite keys for partial sort key queries + composite: ["project", "task"], + }, + }, + assigned: { + // collections allow for queries across multiple entities + collection: "assignments", + index: "gsi1pk-gsi1sk-index", + pk: { + // map to your GSI Hash/Partition key + field: "gsi1pk", + composite: ["user"], + }, + sk: { + // map to your GSI Range/Sort key + field: "gsi1sk", + composite: ["status"], + }, + }, + backlog: { + // map to the GSI name on your DynamoDB table + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["project"], + }, + sk: { + field: "gsi2sk", + composite: ["team", "closed"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/introduction-patch-task/example.ts b/www/src/examples/introduction-patch-task/example.ts new file mode 100644 index 00000000..e2f28976 --- /dev/null +++ b/www/src/examples/introduction-patch-task/example.ts @@ -0,0 +1,15 @@ +import { tasks } from "./entity"; + +const { data } = await tasks + .patch({ + team: "core", + task: "45-662", + project: "backend", + }) + .set({ status: "open" }) + .add({ points: 5 }) + .append({ + comments: [{ user: "janet", body: "This seems half-baked." }], + }) + .where(({ status }, { eq }) => eq(status, "in-progress")) + .go(); diff --git a/www/src/examples/introduction-patch-task/table.ts b/www/src/examples/introduction-patch-task/table.ts new file mode 100644 index 00000000..42b07d29 --- /dev/null +++ b/www/src/examples/introduction-patch-task/table.ts @@ -0,0 +1,76 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/item-counters-read-select/entities.ts b/www/src/examples/item-counters-read-select/entities.ts new file mode 100644 index 00000000..53f23daa --- /dev/null +++ b/www/src/examples/item-counters-read-select/entities.ts @@ -0,0 +1,69 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const User = new Entity( + { + model: { + entity: "user", + service: "accounts", + version: "1", + }, + attributes: { + accountId: { + type: "string", + }, + userId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + account: { + collection: "members", + pk: { + field: "pk", + composite: ["accountId"], + }, + sk: { + field: "sk", + composite: ["userId"], + }, + }, + }, + }, + { table: tableName }, +); + +export const Account = new Entity( + { + model: { + entity: "account", + service: "accounts", + version: "1", + }, + attributes: { + accountId: { + type: "string", + }, + name: { + type: "string", + }, + }, + indexes: { + account: { + collection: "members", + pk: { + field: "pk", + composite: ["accountId"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/item-counters-read-select/example.ts b/www/src/examples/item-counters-read-select/example.ts new file mode 100644 index 00000000..7bdb6745 --- /dev/null +++ b/www/src/examples/item-counters-read-select/example.ts @@ -0,0 +1,133 @@ +import { AccountService } from "./service"; +import { User } from "./entities"; + +type Cursor = string | null; + +type QueryResponse = { + cursor: Cursor; + data: unknown; +}; + +type CountQueryResponse = { + cursor: Cursor; + data: { count: number }; +}; + +type CountFnOptions = { + next: Cursor; +}; + +type CountFn = (options: CountFnOptions) => Promise; + +function toCountFnResponse(resp: QueryResponse): CountQueryResponse { + const { cursor } = resp; + + const data = { count: 0 }; + if ( + typeof resp.data === "object" && + resp.data !== null && + "Count" in resp.data && + typeof resp.data.Count === "number" + ) { + data.count = resp.data.Count; + } + + return { + cursor, + data, + }; +} + +type PaginateCountQueryOptions = { + countFn: CountFn; +}; + +// this function exists to demonstrate how you might implement some indirection to accomplish this task in a generic way +async function paginateCountQuery(options: PaginateCountQueryOptions) { + const { countFn } = options; + let count = 0; + let next: Cursor = null; + do { + const { cursor, data } = await countFn({ next }); + count += data.count; + next = cursor; + } while (next); + + return count; +} + +type CreateCountFnOptions = { + accountId: string; +}; + +// count collection query +function createMembersCountFn(options: CreateCountFnOptions): CountFn { + const { accountId } = options; + return ({ next }) => { + return AccountService.collections + .members({ accountId }) + .go({ + // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) + data: "raw", + // paginate through the results using the cursor + cursor: next, + // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) + params: { Select: "COUNT" }, + // transform results + }) + .then(toCountFnResponse); + }; +} + +// count entity query +function createUsersCountFn(options: CreateCountFnOptions): CountFn { + const { accountId } = options; + return async ({ next }) => { + return User.query + .account({ accountId }) + .go({ + // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) + data: "raw", + // paginate through the results using the cursor + cursor: next, + // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) + params: { Select: "COUNT" }, + // transform results + }) + .then(toCountFnResponse); + }; +} + +function createUsersScanCountFn(options: CreateCountFnOptions): CountFn { + const { accountId } = options; + return async ({ next }) => { + return User.scan + .where((attr, op) => op.eq(attr.accountId, accountId)) + .go({ + // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) + data: "raw", + // paginate through the results using the cursor + cursor: next, + // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) + params: { Select: "COUNT" }, + // transform results + }) + .then(toCountFnResponse); + }; +} + +(async function main() { + const accountId = "1234"; + + const membersCount = await paginateCountQuery({ + countFn: createMembersCountFn({ accountId }), + }); + + const usersCount = await paginateCountQuery({ + countFn: createUsersCountFn({ accountId }), + }); + + const usersScanCount = await paginateCountQuery({ + countFn: createUsersScanCountFn({ accountId }), + }); +})().catch(console.error); diff --git a/www/src/examples/item-counters-read-select/service.ts b/www/src/examples/item-counters-read-select/service.ts new file mode 100644 index 00000000..7e91b106 --- /dev/null +++ b/www/src/examples/item-counters-read-select/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { User, Account } from "./entities"; + +export const AccountService = new Service({ User, Account }); diff --git a/www/src/examples/item-counters-read-select/table.ts b/www/src/examples/item-counters-read-select/table.ts new file mode 100644 index 00000000..e1058538 --- /dev/null +++ b/www/src/examples/item-counters-read-select/table.ts @@ -0,0 +1,26 @@ +export const tableName = "accounts"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/item-counters-write-transaction/entities.ts b/www/src/examples/item-counters-write-transaction/entities.ts new file mode 100644 index 00000000..723d3f33 --- /dev/null +++ b/www/src/examples/item-counters-write-transaction/entities.ts @@ -0,0 +1,146 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Employee = new Entity( + { + model: { + entity: "employee", + service: "directory", + version: "1", + }, + attributes: { + organizationId: { + type: "string", + }, + employeeId: { + type: "string", + }, + name: { + type: "string", + }, + teamId: { + type: "string", + }, + }, + indexes: { + employees: { + collection: "employed", + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["employeeId"], + }, + }, + }, + }, + { table: tableName }, +); + +// A counter scoped to the entire "directory" service. This entity has no +// "pk" or "sk" composite attributes, making the item it creates global. +// Be careful when using this pattern, as it can lead to hot partitions. +export const GlobalCounter = new Entity( + { + model: { + entity: "global-counter", + service: "directory", + version: "1", + }, + attributes: { + count: { + type: "number", + }, + }, + indexes: { + count: { + pk: { + field: "pk", + composite: [], + }, + sk: { + field: "sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +// A counter scoped to a more specific subset of data: "organizationId" and +// "teamId" allow counting the number of items scoped to a specific team. +export const TeamCounter = new Entity( + { + model: { + entity: "team-counter", + service: "directory", + version: "1", + }, + attributes: { + organizationId: { + type: "string", + }, + teamId: { + type: "string", + }, + count: { + type: "number", + }, + }, + indexes: { + organization: { + collection: "employed", + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["teamId"], + }, + }, + }, + }, + { table: tableName }, +); + +// A counter dynamically scoped by a "kind" attribute, allowing the +// "organizationId" partition to be further split by the kind of item +// being counted. +export const OrganizationItemCounter = new Entity( + { + model: { + entity: "member-counter", + service: "directory", + version: "1", + }, + attributes: { + organizationId: { + type: "string", + }, + kind: { + type: ["employee", "team"] as const, + }, + count: { + type: "number", + }, + }, + indexes: { + organization: { + collection: "employed", + pk: { + field: "pk", + composite: ["organizationId"], + }, + sk: { + field: "sk", + composite: ["kind"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/item-counters-write-transaction/example.ts b/www/src/examples/item-counters-write-transaction/example.ts new file mode 100644 index 00000000..210de744 --- /dev/null +++ b/www/src/examples/item-counters-write-transaction/example.ts @@ -0,0 +1,53 @@ +import { AccountService } from "./service"; + +export type CreateEmployeeOptions = { + organizationId: string; + teamId: string; + employeeId: string; + name: string; +}; + +export function createEmployee(options: CreateEmployeeOptions) { + const { organizationId, employeeId, name, teamId } = options; + + return AccountService.transaction + .write(({ Employee, OrganizationItemCounter, GlobalCounter, TeamCounter }) => [ + Employee.create({ organizationId, employeeId, name }).commit(), + + GlobalCounter.upsert({}).add({ count: 1 }).commit(), + TeamCounter.upsert({ organizationId, teamId }).add({ count: 1 }).commit(), + OrganizationItemCounter.upsert({ organizationId, kind: "employee" }) + .add({ count: 1 }) + .commit(), + ]) + .go(); +} + +export type RemoveEmployeeOptions = { + organizationId: string; + teamId: string; + employeeId: string; +}; + +export function removeEmployee(options: RemoveEmployeeOptions) { + const { organizationId, employeeId, teamId } = options; + + return AccountService.transaction + .write(({ Employee, OrganizationItemCounter, GlobalCounter, TeamCounter }) => [ + Employee.remove({ organizationId, employeeId }).commit(), + + GlobalCounter.upsert({}).subtract({ count: 1 }).commit(), + TeamCounter.upsert({ organizationId, teamId }).subtract({ count: 1 }).commit(), + OrganizationItemCounter.upsert({ organizationId, kind: "employee" }) + .subtract({ count: 1 }) + .commit(), + ]) + .go(); +} + +await createEmployee({ + organizationId: "acme-corp", + teamId: "engineering", + employeeId: "emp-001", + name: "Jane Smith", +}); diff --git a/www/src/examples/item-counters-write-transaction/service.ts b/www/src/examples/item-counters-write-transaction/service.ts new file mode 100644 index 00000000..394c2393 --- /dev/null +++ b/www/src/examples/item-counters-write-transaction/service.ts @@ -0,0 +1,14 @@ +import { Service } from "electrodb"; +import { + Employee, + OrganizationItemCounter, + TeamCounter, + GlobalCounter, +} from "./entities"; + +export const AccountService = new Service({ + Employee, + OrganizationItemCounter, + TeamCounter, + GlobalCounter, +}); diff --git a/www/src/examples/item-counters-write-transaction/table.ts b/www/src/examples/item-counters-write-transaction/table.ts new file mode 100644 index 00000000..7a0515f9 --- /dev/null +++ b/www/src/examples/item-counters-write-transaction/table.ts @@ -0,0 +1,26 @@ +export const tableName = "company-directory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/keys-only-gsi-hydrate-query/entity.ts b/www/src/examples/keys-only-gsi-hydrate-query/entity.ts new file mode 100644 index 00000000..4415658c --- /dev/null +++ b/www/src/examples/keys-only-gsi-hydrate-query/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const assets = new Entity( + { + model: { + entity: "assets", + version: "1", + service: "inventory", + }, + attributes: { + assetId: { + type: "string", + }, + accountId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + city: { + type: "string", + }, + county: { + type: "string", + }, + state: { + type: "string", + }, + zip: { + type: "string", + }, + }, + indexes: { + assets: { + pk: { + field: "pk", + composite: ["accountId"], + }, + sk: { + field: "sk", + composite: ["assetId"], + }, + }, + locations: { + collection: "geographics", + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["state"], + }, + sk: { + field: "gsi1sk", + composite: ["county", "city", "zip"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/keys-only-gsi-hydrate-query/example.ts b/www/src/examples/keys-only-gsi-hydrate-query/example.ts new file mode 100644 index 00000000..1af47e07 --- /dev/null +++ b/www/src/examples/keys-only-gsi-hydrate-query/example.ts @@ -0,0 +1,6 @@ +import { assets } from "./entity"; + +// the locations index (gsi1pk-gsi1sk-index) is a KEYS_ONLY projection +const { data, cursor } = await assets.query + .locations({ state: "Georgia" }) + .go({ hydrate: true }); diff --git a/www/src/examples/keys-only-gsi-hydrate-query/table.ts b/www/src/examples/keys-only-gsi-hydrate-query/table.ts new file mode 100644 index 00000000..e3b46142 --- /dev/null +++ b/www/src/examples/keys-only-gsi-hydrate-query/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "KEYS_ONLY", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/keys-only-gsi-include-keys/entity.ts b/www/src/examples/keys-only-gsi-include-keys/entity.ts new file mode 100644 index 00000000..4415658c --- /dev/null +++ b/www/src/examples/keys-only-gsi-include-keys/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const assets = new Entity( + { + model: { + entity: "assets", + version: "1", + service: "inventory", + }, + attributes: { + assetId: { + type: "string", + }, + accountId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + city: { + type: "string", + }, + county: { + type: "string", + }, + state: { + type: "string", + }, + zip: { + type: "string", + }, + }, + indexes: { + assets: { + pk: { + field: "pk", + composite: ["accountId"], + }, + sk: { + field: "sk", + composite: ["assetId"], + }, + }, + locations: { + collection: "geographics", + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["state"], + }, + sk: { + field: "gsi1sk", + composite: ["county", "city", "zip"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/keys-only-gsi-include-keys/example.ts b/www/src/examples/keys-only-gsi-include-keys/example.ts new file mode 100644 index 00000000..07c71756 --- /dev/null +++ b/www/src/examples/keys-only-gsi-include-keys/example.ts @@ -0,0 +1,6 @@ +import { assets } from "./entity"; + +// The elements in the `data` array are just the keys of the index, despite the typing saying otherwise. +const { data, cursor } = await assets.query + .locations({ state: "Georgia" }) + .go({ data: "includeKeys" }); diff --git a/www/src/examples/keys-only-gsi-include-keys/table.ts b/www/src/examples/keys-only-gsi-include-keys/table.ts new file mode 100644 index 00000000..e3b46142 --- /dev/null +++ b/www/src/examples/keys-only-gsi-include-keys/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "KEYS_ONLY", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/keys-only-gsi-raw-response/entity.ts b/www/src/examples/keys-only-gsi-raw-response/entity.ts new file mode 100644 index 00000000..4415658c --- /dev/null +++ b/www/src/examples/keys-only-gsi-raw-response/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const assets = new Entity( + { + model: { + entity: "assets", + version: "1", + service: "inventory", + }, + attributes: { + assetId: { + type: "string", + }, + accountId: { + type: "string", + }, + name: { + type: "string", + }, + description: { + type: "string", + }, + city: { + type: "string", + }, + county: { + type: "string", + }, + state: { + type: "string", + }, + zip: { + type: "string", + }, + }, + indexes: { + assets: { + pk: { + field: "pk", + composite: ["accountId"], + }, + sk: { + field: "sk", + composite: ["assetId"], + }, + }, + locations: { + collection: "geographics", + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["state"], + }, + sk: { + field: "gsi1sk", + composite: ["county", "city", "zip"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/keys-only-gsi-raw-response/example.ts b/www/src/examples/keys-only-gsi-raw-response/example.ts new file mode 100644 index 00000000..8000ce9e --- /dev/null +++ b/www/src/examples/keys-only-gsi-raw-response/example.ts @@ -0,0 +1,7 @@ +import { assets } from "./entity"; + +// result is the actual DynamoDB response, despite the typing saying otherwise. +const result: any = await assets.query + .locations({ state: "Georgia" }) + .go({ data: "raw" }); +const { Items, LastEvaluatedKey } = result; diff --git a/www/src/examples/keys-only-gsi-raw-response/table.ts b/www/src/examples/keys-only-gsi-raw-response/table.ts new file mode 100644 index 00000000..e3b46142 --- /dev/null +++ b/www/src/examples/keys-only-gsi-raw-response/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "KEYS_ONLY", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/match-store-location/entity.ts b/www/src/examples/match-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/match-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/match-store-location/example.ts b/www/src/examples/match-store-location/example.ts new file mode 100644 index 00000000..2b4ff057 --- /dev/null +++ b/www/src/examples/match-store-location/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.match({ + mallId: "EastPointe", + buildingId: "BuildingA1", + leaseEndDate: "2020-03-22", + rent: "1500.00", +}).go(); diff --git a/www/src/examples/match-store-location/table.ts b/www/src/examples/match-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/match-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/pagination-count/entity.ts b/www/src/examples/pagination-count/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/pagination-count/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/pagination-count/example.ts b/www/src/examples/pagination-count/example.ts new file mode 100644 index 00000000..49c5779b --- /dev/null +++ b/www/src/examples/pagination-count/example.ts @@ -0,0 +1,19 @@ +import { StoreLocations } from "./entity"; + +type GetLeasesOptions = { + storeId: string; + cursor?: string | null; + limit: number; +}; + +async function getLeases(options: GetLeasesOptions) { + const { storeId, cursor, limit } = options; + + if (limit < 1 || limit >= 200) { + throw new Error("Limit must be at least 1 and at most 200"); + } + + return StoreLocations.query.leases({ storeId }).go({ cursor, count: limit }); +} + +await getLeases({ storeId: "LatteLarrys", cursor: null, limit: 10 }); diff --git a/www/src/examples/pagination-count/table.ts b/www/src/examples/pagination-count/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/pagination-count/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/pagination-entities/entity.ts b/www/src/examples/pagination-entities/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/pagination-entities/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/pagination-entities/example.ts b/www/src/examples/pagination-entities/example.ts new file mode 100644 index 00000000..f83b1d0b --- /dev/null +++ b/www/src/examples/pagination-entities/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +const results1 = await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .go(); // no "cursor" passed to `.go()` + +const results2 = await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .go({ cursor: results1.cursor }); // Paginate by querying with the "cursor" from your first query diff --git a/www/src/examples/pagination-entities/table.ts b/www/src/examples/pagination-entities/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/pagination-entities/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/pagination-example/entity.ts b/www/src/examples/pagination-example/entity.ts new file mode 100644 index 00000000..167d7193 --- /dev/null +++ b/www/src/examples/pagination-example/entity.ts @@ -0,0 +1,50 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const users = new Entity( + { + model: { + service: "TeamDirectory", + entity: "User", + version: "1", + }, + attributes: { + username: { + type: "string", + required: true, + }, + team: { + type: "string", + required: true, + }, + email: { + type: "string", + required: true, + }, + }, + indexes: { + user: { + pk: { + field: "pk", + composite: ["username"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + members: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["team"], + }, + sk: { + field: "gsi1sk", + composite: ["username"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/pagination-example/example.ts b/www/src/examples/pagination-example/example.ts new file mode 100644 index 00000000..8e409452 --- /dev/null +++ b/www/src/examples/pagination-example/example.ts @@ -0,0 +1,25 @@ +// EntityItem is the type for a returned item +// QueryResponse is the type for the full electrodb response to a query +import type { EntityItem, QueryResponse } from "electrodb"; + +// (your entity) +import { users } from "./entity"; + +type UserItem = EntityItem; +type UserQueryResponse = QueryResponse; + +async function getTeamMembers(team: string) { + let members: UserItem[] = []; + let cursor = null; + do { + const results: UserQueryResponse = await users.query + .members({ team }) + .go({ cursor }); + members = [...members, ...results.data]; + cursor = results.cursor; + } while (cursor !== null); + + return members; +} + +await getTeamMembers("engineering"); diff --git a/www/src/examples/pagination-example/table.ts b/www/src/examples/pagination-example/table.ts new file mode 100644 index 00000000..077e8757 --- /dev/null +++ b/www/src/examples/pagination-example/table.ts @@ -0,0 +1,52 @@ +export const tableName = "TeamDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-complex-nested-set/entity.ts b/www/src/examples/patch-complex-nested-set/entity.ts new file mode 100644 index 00000000..a0d351a9 --- /dev/null +++ b/www/src/examples/patch-complex-nested-set/entity.ts @@ -0,0 +1,55 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + listAttribute: { + type: "list", + items: { + type: "map", + properties: { + setAttribute: { + type: "set", + items: "string", + }, + }, + }, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-complex-nested-set/example.ts b/www/src/examples/patch-complex-nested-set/example.ts new file mode 100644 index 00000000..e98141da --- /dev/null +++ b/www/src/examples/patch-complex-nested-set/example.ts @@ -0,0 +1,21 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +// Set values must use the DocumentClient to create a `set` +const newSetValue = StoreLocations.client.createSet("setItemValue"); + +// via Chain Method +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .add({ "listAttribute[1].setAttribute": newSetValue }) + .go(); + +// via Data Method +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .data(({ listAttribute }, { add }) => { + add(listAttribute[1].setAttribute, newSetValue); + }) + .go(); diff --git a/www/src/examples/patch-complex-nested-set/table.ts b/www/src/examples/patch-complex-nested-set/table.ts new file mode 100644 index 00000000..1b3bda34 --- /dev/null +++ b/www/src/examples/patch-complex-nested-set/table.ts @@ -0,0 +1,26 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-organization-composite/entity.ts b/www/src/examples/patch-organization-composite/entity.ts new file mode 100644 index 00000000..5077a5ad --- /dev/null +++ b/www/src/examples/patch-organization-composite/entity.ts @@ -0,0 +1,60 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Organization = new Entity( + { + model: { + entity: "organization", + service: "app", + version: "1", + }, + attributes: { + id: { + type: "string", + }, + name: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + deleted: { + type: "boolean", + required: true, + default: false, + }, + createdAt: { + type: "string", + readOnly: true, + required: true, + set: () => new Date().toISOString(), + default: () => new Date().toISOString(), + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["id"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + all: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: [], + }, + sk: { + field: "gsi1sk", + composite: ["deleted", "createdAt"], // SK has both readonly and mutable attributes + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-organization-composite/example.ts b/www/src/examples/patch-organization-composite/example.ts new file mode 100644 index 00000000..a257be41 --- /dev/null +++ b/www/src/examples/patch-organization-composite/example.ts @@ -0,0 +1,9 @@ +import { Organization } from "./entity"; + +const id = "00001"; +const existing = await Organization.get({ id }).go(); + +await Organization.patch({ id: "00001" }) + .set({ deleted: false }) + .composite({ createdAt: existing.data?.createdAt ?? new Date().toISOString() }) + .go(); diff --git a/www/src/examples/patch-organization-composite/table.ts b/www/src/examples/patch-organization-composite/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/patch-organization-composite/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-add/entity.ts b/www/src/examples/patch-store-location-add/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/patch-store-location-add/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-add/example.ts b/www/src/examples/patch-store-location-add/example.ts new file mode 100644 index 00000000..8355997b --- /dev/null +++ b/www/src/examples/patch-store-location-add/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .add({ + warnings: 1, // "number" attribute + tenants: ["larry"], // "set" attribute + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-add/table.ts b/www/src/examples/patch-store-location-add/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-add/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-append/entity.ts b/www/src/examples/patch-store-location-append/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/patch-store-location-append/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-append/example.ts b/www/src/examples/patch-store-location-append/example.ts new file mode 100644 index 00000000..af081560 --- /dev/null +++ b/www/src/examples/patch-store-location-append/example.ts @@ -0,0 +1,18 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .append({ + rentalAgreement: [ + { + type: "ammendment", + detail: "no soup for you", + }, + ], + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-append/table.ts b/www/src/examples/patch-store-location-append/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-append/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-data/entity.ts b/www/src/examples/patch-store-location-data/entity.ts new file mode 100644 index 00000000..d53d516f --- /dev/null +++ b/www/src/examples/patch-store-location-data/entity.ts @@ -0,0 +1,135 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + contact: { + type: "set", + items: "string", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + petFee: { + type: "number", + }, + fees: { + type: "number", + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-data/example.ts b/www/src/examples/patch-store-location-data/example.ts new file mode 100644 index 00000000..a0fc7327 --- /dev/null +++ b/www/src/examples/patch-store-location-data/example.ts @@ -0,0 +1,28 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .data((a, o) => { + const newTenant = o.value(a.tenants, ["larry"]); + o.set(a.category, "food/meal"); // electrodb "enum" -> dynamodb "string" + o.add(a.tenants, newTenant); // electrodb "set" -> dynamodb "set" + o.add(a.warnings, 1); // electrodb "number" -> dynamodb "number" + o.subtract(a.deposit, 200); // electrodb "number" -> dynamodb "number" + o.remove(a.discount); // electrodb "number" -> dynamodb "number" + o.append(a.rentalAgreement, [ + { + // electrodb "list" -> dynamodb "list" + type: "ammendment", // electrodb "map" -> dynamodb "map" + detail: "no soup for you", + }, + ]); + o.delete(a.tags, ["coffee"]); + o.del(a.contact, ["555-345-2222"]); // electrodb "set" -> dynamodb "set" + o.add(a.fees, o.name(a.petFee)); // electrodb "number" -> dynamodb "number" + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-data/table.ts b/www/src/examples/patch-store-location-data/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-data/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-delete/entity.ts b/www/src/examples/patch-store-location-delete/entity.ts new file mode 100644 index 00000000..02b2c112 --- /dev/null +++ b/www/src/examples/patch-store-location-delete/entity.ts @@ -0,0 +1,129 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + contact: { + type: "set", + items: "string", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-delete/example.ts b/www/src/examples/patch-store-location-delete/example.ts new file mode 100644 index 00000000..8f4fc70a --- /dev/null +++ b/www/src/examples/patch-store-location-delete/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .delete({ contact: ["555-345-2222"] }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-delete/table.ts b/www/src/examples/patch-store-location-delete/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-delete/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-remove/entity.ts b/www/src/examples/patch-store-location-remove/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/patch-store-location-remove/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-remove/example.ts b/www/src/examples/patch-store-location-remove/example.ts new file mode 100644 index 00000000..88aa3be6 --- /dev/null +++ b/www/src/examples/patch-store-location-remove/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .remove(["discount"]) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-remove/table.ts b/www/src/examples/patch-store-location-remove/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-remove/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-set/entity.ts b/www/src/examples/patch-store-location-set/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/patch-store-location-set/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-set/example.ts b/www/src/examples/patch-store-location-set/example.ts new file mode 100644 index 00000000..da4f3148 --- /dev/null +++ b/www/src/examples/patch-store-location-set/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .set({ category: "food/meal" }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-set/table.ts b/www/src/examples/patch-store-location-set/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-set/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-store-location-subtract/entity.ts b/www/src/examples/patch-store-location-subtract/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/patch-store-location-subtract/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-store-location-subtract/example.ts b/www/src/examples/patch-store-location-subtract/example.ts new file mode 100644 index 00000000..e296be29 --- /dev/null +++ b/www/src/examples/patch-store-location-subtract/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Portland"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "A34"; + +await StoreLocations.patch({ cityId, mallId, storeId, buildingId }) + .subtract({ deposit: 500 }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/patch-store-location-subtract/table.ts b/www/src/examples/patch-store-location-subtract/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/patch-store-location-subtract/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-tasks/entity.ts b/www/src/examples/patch-tasks/entity.ts new file mode 100644 index 00000000..f266e3ee --- /dev/null +++ b/www/src/examples/patch-tasks/entity.ts @@ -0,0 +1,122 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + team: { + type: "string", + required: true, + }, + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + user: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + // use an array to type an enum + type: ["open", "in-progress", "on-hold", "closed"] as const, + default: "open", + }, + points: { + type: "number", + }, + tags: { + type: "set", + items: "string", + }, + comments: { + type: "list", + items: { + type: "map", + properties: { + user: { + type: "string", + }, + body: { + type: "string", + }, + }, + }, + }, + closed: { + type: "string", + validate: /[0-9]{4}-[0-9]{2}-[0-9]{2}/, + }, + createdAt: { + type: "number", + default: () => Date.now(), + // cannot be modified after created + readOnly: true, + }, + updatedAt: { + type: "number", + // watch for changes to any attribute + watch: "*", + // set current timestamp when updated + set: () => Date.now(), + readOnly: true, + }, + }, + indexes: { + projects: { + pk: { + field: "pk", + composite: ["team"], + }, + sk: { + field: "sk", + // create composite keys for partial sort key queries + composite: ["project", "task"], + }, + }, + assigned: { + // collections allow for queries across multiple entities + collection: "assignments", + index: "gsi1pk-gsi1sk-index", + pk: { + // map to your GSI Hash/Partition key + field: "gsi1pk", + composite: ["user"], + }, + sk: { + // map to your GSI Range/Sort key + field: "gsi1sk", + composite: ["status"], + }, + }, + backlog: { + // map to the GSI name on your DynamoDB table + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["project"], + }, + sk: { + field: "gsi2sk", + composite: ["team", "closed"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-tasks/example.ts b/www/src/examples/patch-tasks/example.ts new file mode 100644 index 00000000..693fab92 --- /dev/null +++ b/www/src/examples/patch-tasks/example.ts @@ -0,0 +1,20 @@ +import { tasks } from "./entity"; + +await tasks + .patch({ + team: "core", + task: "45-662", + project: "backend", + }) + .set({ status: "open" }) + .add({ points: 5 }) + .append({ + comments: [ + { + user: "janet", + body: "This seems half-baked.", + }, + ], + }) + .where(({ status }, { eq }) => eq(status, "in-progress")) + .go(); diff --git a/www/src/examples/patch-tasks/table.ts b/www/src/examples/patch-tasks/table.ts new file mode 100644 index 00000000..42b07d29 --- /dev/null +++ b/www/src/examples/patch-tasks/table.ts @@ -0,0 +1,76 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/patch-update-composite-edgecase/entity.ts b/www/src/examples/patch-update-composite-edgecase/entity.ts new file mode 100644 index 00000000..a6210e27 --- /dev/null +++ b/www/src/examples/patch-update-composite-edgecase/entity.ts @@ -0,0 +1,53 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const entity = new Entity( + { + model: { + service: "service", + entity: "update-edgecases", + version: "1", + }, + attributes: { + attr1: { + type: "string", + required: true, + }, + attr2: { + type: "string", + required: true, + }, + attr3: { + type: "string", + required: true, + }, + attr4: { + type: "string", + }, + }, + indexes: { + accessPattern1: { + pk: { + field: "pk", + composite: ["attr1"], + }, + sk: { + field: "sk", + composite: ["attr2"], + }, + }, + accessPattern2: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["attr3"], + }, + sk: { + field: "gsi1sk", + composite: ["attr2", "attr4"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/patch-update-composite-edgecase/example.ts b/www/src/examples/patch-update-composite-edgecase/example.ts new file mode 100644 index 00000000..3d736789 --- /dev/null +++ b/www/src/examples/patch-update-composite-edgecase/example.ts @@ -0,0 +1,6 @@ +import { entity } from "./entity"; + +await entity + .patch({ attr1: "value1", attr2: "value2" }) + .set({ attr4: "value4" }) + .go(); diff --git a/www/src/examples/patch-update-composite-edgecase/table.ts b/www/src/examples/patch-update-composite-edgecase/table.ts new file mode 100644 index 00000000..e535ed44 --- /dev/null +++ b/www/src/examples/patch-update-composite-edgecase/table.ts @@ -0,0 +1,52 @@ +export const tableName = "YOUR_TABLE_NAME"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-bad-missing-pk-attribute/entity.ts b/www/src/examples/query-bad-missing-pk-attribute/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-bad-missing-pk-attribute/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-bad-missing-pk-attribute/example.ts b/www/src/examples/query-bad-missing-pk-attribute/example.ts new file mode 100644 index 00000000..b1ba7087 --- /dev/null +++ b/www/src/examples/query-bad-missing-pk-attribute/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + // @ts-expect-error - missing the `cityId` PK composite attribute + .stores({ + mallId: "EastPointe", + }) + .go(); diff --git a/www/src/examples/query-bad-missing-pk-attribute/table.ts b/www/src/examples/query-bad-missing-pk-attribute/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-bad-missing-pk-attribute/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-bad-no-pk/entity.ts b/www/src/examples/query-bad-no-pk/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-bad-no-pk/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-bad-no-pk/example.ts b/www/src/examples/query-bad-no-pk/example.ts new file mode 100644 index 00000000..a9b738a2 --- /dev/null +++ b/www/src/examples/query-bad-no-pk/example.ts @@ -0,0 +1,4 @@ +import { StoreLocations } from "./entity"; + +// @ts-expect-error - the `stores` access pattern requires at least the PK composite attributes +await StoreLocations.query.stores().go(); diff --git a/www/src/examples/query-bad-no-pk/table.ts b/www/src/examples/query-bad-no-pk/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-bad-no-pk/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-bad-out-of-order/entity.ts b/www/src/examples/query-bad-out-of-order/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-bad-out-of-order/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-bad-out-of-order/example.ts b/www/src/examples/query-bad-out-of-order/example.ts new file mode 100644 index 00000000..574ae904 --- /dev/null +++ b/www/src/examples/query-bad-out-of-order/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .stores({ + cityId: "Atlanta1", + mallId: "EastPointe", + unitId: "B24", + }) + .go(); diff --git a/www/src/examples/query-bad-out-of-order/table.ts b/www/src/examples/query-bad-out-of-order/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-bad-out-of-order/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-good-includes-all-sk/entity.ts b/www/src/examples/query-good-includes-all-sk/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-good-includes-all-sk/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-good-includes-all-sk/example.ts b/www/src/examples/query-good-includes-all-sk/example.ts new file mode 100644 index 00000000..da30c74a --- /dev/null +++ b/www/src/examples/query-good-includes-all-sk/example.ts @@ -0,0 +1,10 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .stores({ + cityId: "Atlanta1", + mallId: "EastPointe", + storeId: "LatteLarrys", + buildingId: "f34", + }) + .go(); diff --git a/www/src/examples/query-good-includes-all-sk/table.ts b/www/src/examples/query-good-includes-all-sk/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-good-includes-all-sk/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-good-includes-pk-first-sk/entity.ts b/www/src/examples/query-good-includes-pk-first-sk/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-good-includes-pk-first-sk/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-good-includes-pk-first-sk/example.ts b/www/src/examples/query-good-includes-pk-first-sk/example.ts new file mode 100644 index 00000000..531cb893 --- /dev/null +++ b/www/src/examples/query-good-includes-pk-first-sk/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .stores({ + cityId: "Atlanta1", + mallId: "EastPointe", + buildingId: "f34", + }) + .go(); diff --git a/www/src/examples/query-good-includes-pk-first-sk/table.ts b/www/src/examples/query-good-includes-pk-first-sk/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-good-includes-pk-first-sk/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-good-includes-pk/entity.ts b/www/src/examples/query-good-includes-pk/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-good-includes-pk/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-good-includes-pk/example.ts b/www/src/examples/query-good-includes-pk/example.ts new file mode 100644 index 00000000..4b746386 --- /dev/null +++ b/www/src/examples/query-good-includes-pk/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .stores({ + cityId: "Atlanta1", + mallId: "EastPointe", + }) + .go(); diff --git a/www/src/examples/query-good-includes-pk/table.ts b/www/src/examples/query-good-includes-pk/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-good-includes-pk/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-begins-year/entity.ts b/www/src/examples/query-leases-by-store-id-begins-year/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-begins-year/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-begins-year/example.ts b/www/src/examples/query-leases-by-store-id-begins-year/example.ts new file mode 100644 index 00000000..5b6d6cef --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-begins-year/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .begins({ leaseEndDate: "2020-00-00" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-begins-year/table.ts b/www/src/examples/query-leases-by-store-id-begins-year/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-begins-year/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-between/entity.ts b/www/src/examples/query-leases-by-store-id-between/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-between/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-between/example.ts b/www/src/examples/query-leases-by-store-id-between/example.ts new file mode 100644 index 00000000..dfc584d0 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-between/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .between({ leaseEndDate: "2010-00-00" }, { leaseEndDate: "2020-99-99" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-between/table.ts b/www/src/examples/query-leases-by-store-id-between/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-between/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-date/entity.ts b/www/src/examples/query-leases-by-store-id-date/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-date/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-date/example.ts b/www/src/examples/query-leases-by-store-id-date/example.ts new file mode 100644 index 00000000..25c3a013 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-date/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ + storeId: "LatteLarrys", + leaseEndDate: "2020-03-22", + }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-date/table.ts b/www/src/examples/query-leases-by-store-id-date/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-date/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-gt/entity.ts b/www/src/examples/query-leases-by-store-id-gt/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gt/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-gt/example.ts b/www/src/examples/query-leases-by-store-id-gt/example.ts new file mode 100644 index 00000000..cd2b610f --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gt/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .gt({ leaseEndDate: "2020-04-00" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-gt/table.ts b/www/src/examples/query-leases-by-store-id-gt/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gt/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-gte-where/entity.ts b/www/src/examples/query-leases-by-store-id-gte-where/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte-where/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-gte-where/example.ts b/www/src/examples/query-leases-by-store-id-gte-where/example.ts new file mode 100644 index 00000000..b8f1a901 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte-where/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .gte({ leaseEndDate: "2010-00-00" }) + .where( + (attr, op) => ` + ${op.eq(attr.cityId, "Atlanta1")} AND ${op.contains( + attr.category, + "food", + )} + `, + ) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-gte-where/table.ts b/www/src/examples/query-leases-by-store-id-gte-where/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte-where/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-gte/entity.ts b/www/src/examples/query-leases-by-store-id-gte/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-gte/example.ts b/www/src/examples/query-leases-by-store-id-gte/example.ts new file mode 100644 index 00000000..33060f47 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .gte({ leaseEndDate: "2020-03-00" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-gte/table.ts b/www/src/examples/query-leases-by-store-id-gte/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-gte/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-lt/entity.ts b/www/src/examples/query-leases-by-store-id-lt/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lt/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-lt/example.ts b/www/src/examples/query-leases-by-store-id-lt/example.ts new file mode 100644 index 00000000..13218144 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lt/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .lt({ leaseEndDate: "2021-00-00" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-lt/table.ts b/www/src/examples/query-leases-by-store-id-lt/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lt/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id-lte/entity.ts b/www/src/examples/query-leases-by-store-id-lte/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lte/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id-lte/example.ts b/www/src/examples/query-leases-by-store-id-lte/example.ts new file mode 100644 index 00000000..761721de --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lte/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query + .leases({ storeId: "LatteLarrys" }) + .lte({ leaseEndDate: "2021-02-00" }) + .go(); diff --git a/www/src/examples/query-leases-by-store-id-lte/table.ts b/www/src/examples/query-leases-by-store-id-lte/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id-lte/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-leases-by-store-id/entity.ts b/www/src/examples/query-leases-by-store-id/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-leases-by-store-id/example.ts b/www/src/examples/query-leases-by-store-id/example.ts new file mode 100644 index 00000000..1f1cc772 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id/example.ts @@ -0,0 +1,3 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.query.leases({ storeId: "LatteLarrys" }).go(); diff --git a/www/src/examples/query-leases-by-store-id/table.ts b/www/src/examples/query-leases-by-store-id/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-leases-by-store-id/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-units-example-1/entity.ts b/www/src/examples/query-units-example-1/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-units-example-1/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-units-example-1/example.ts b/www/src/examples/query-units-example-1/example.ts new file mode 100644 index 00000000..ce77dc09 --- /dev/null +++ b/www/src/examples/query-units-example-1/example.ts @@ -0,0 +1,7 @@ +import { StoreLocations } from "./entity"; + +// Example #1, access pattern `units` +await StoreLocations.query + .units({ mallId: "EastPointe", buildingId: "f34" }) + .go(); +// -----------------------^^^^^^^^^^^^^^^^^^^^^^ diff --git a/www/src/examples/query-units-example-1/table.ts b/www/src/examples/query-units-example-1/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-units-example-1/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/query-units-example-2/entity.ts b/www/src/examples/query-units-example-2/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/query-units-example-2/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/query-units-example-2/example.ts b/www/src/examples/query-units-example-2/example.ts new file mode 100644 index 00000000..f29085cb --- /dev/null +++ b/www/src/examples/query-units-example-2/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +// Example #2 +await StoreLocations.query + .units({ mallId: "EastPointe" }) + .begins({ buildingId: "f34" }) + .go(); +// ---------------------------------^^^^^^^^^^^^^^^^^^^^^ diff --git a/www/src/examples/query-units-example-2/table.ts b/www/src/examples/query-units-example-2/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/query-units-example-2/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/quick-start-books-by-author/entity.ts b/www/src/examples/quick-start-books-by-author/entity.ts new file mode 100644 index 00000000..607a6f8b --- /dev/null +++ b/www/src/examples/quick-start-books-by-author/entity.ts @@ -0,0 +1,65 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Book = new Entity( + { + model: { + entity: "book", + version: "1", + service: "store", + }, + attributes: { + storeId: { + type: "string", + }, + bookId: { + type: "string", + }, + price: { + type: "number", + required: true, + }, + title: { + type: "string", + }, + author: { + type: "string", + }, + condition: { + type: ["EXCELLENT", "GOOD", "FAIR", "POOR"] as const, + required: true, + }, + genre: { + type: "set", + items: "string", + }, + published: { + type: "string", + }, + }, + indexes: { + byLocation: { + pk: { + field: "pk", + composite: ["storeId"], + }, + sk: { + field: "sk", + composite: ["bookId"], + }, + }, + byAuthor: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["author"], + }, + sk: { + field: "gsi1sk", + composite: ["title"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/quick-start-books-by-author/example.ts b/www/src/examples/quick-start-books-by-author/example.ts new file mode 100644 index 00000000..a523b0b3 --- /dev/null +++ b/www/src/examples/quick-start-books-by-author/example.ts @@ -0,0 +1,5 @@ +import { Book } from "./entity"; + +const { data, cursor } = await Book.query + .byAuthor({ author: "Stephen King" }) + .go(); diff --git a/www/src/examples/quick-start-books-by-author/table.ts b/www/src/examples/quick-start-books-by-author/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/quick-start-books-by-author/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/quick-start-books-by-store-location/entity.ts b/www/src/examples/quick-start-books-by-store-location/entity.ts new file mode 100644 index 00000000..607a6f8b --- /dev/null +++ b/www/src/examples/quick-start-books-by-store-location/entity.ts @@ -0,0 +1,65 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Book = new Entity( + { + model: { + entity: "book", + version: "1", + service: "store", + }, + attributes: { + storeId: { + type: "string", + }, + bookId: { + type: "string", + }, + price: { + type: "number", + required: true, + }, + title: { + type: "string", + }, + author: { + type: "string", + }, + condition: { + type: ["EXCELLENT", "GOOD", "FAIR", "POOR"] as const, + required: true, + }, + genre: { + type: "set", + items: "string", + }, + published: { + type: "string", + }, + }, + indexes: { + byLocation: { + pk: { + field: "pk", + composite: ["storeId"], + }, + sk: { + field: "sk", + composite: ["bookId"], + }, + }, + byAuthor: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["author"], + }, + sk: { + field: "gsi1sk", + composite: ["title"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/quick-start-books-by-store-location/example.ts b/www/src/examples/quick-start-books-by-store-location/example.ts new file mode 100644 index 00000000..6e43368a --- /dev/null +++ b/www/src/examples/quick-start-books-by-store-location/example.ts @@ -0,0 +1,6 @@ +import { Book } from "./entity"; + +const { data, cursor } = await Book.query + .byLocation({ storeId: "pdx-45" }) + .where(({ price }, { lte }) => lte(price, 10)) + .go(); diff --git a/www/src/examples/quick-start-books-by-store-location/table.ts b/www/src/examples/quick-start-books-by-store-location/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/quick-start-books-by-store-location/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/quick-start-create-book/entity.ts b/www/src/examples/quick-start-create-book/entity.ts new file mode 100644 index 00000000..607a6f8b --- /dev/null +++ b/www/src/examples/quick-start-create-book/entity.ts @@ -0,0 +1,65 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Book = new Entity( + { + model: { + entity: "book", + version: "1", + service: "store", + }, + attributes: { + storeId: { + type: "string", + }, + bookId: { + type: "string", + }, + price: { + type: "number", + required: true, + }, + title: { + type: "string", + }, + author: { + type: "string", + }, + condition: { + type: ["EXCELLENT", "GOOD", "FAIR", "POOR"] as const, + required: true, + }, + genre: { + type: "set", + items: "string", + }, + published: { + type: "string", + }, + }, + indexes: { + byLocation: { + pk: { + field: "pk", + composite: ["storeId"], + }, + sk: { + field: "sk", + composite: ["bookId"], + }, + }, + byAuthor: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["author"], + }, + sk: { + field: "gsi1sk", + composite: ["title"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/quick-start-create-book/example.ts b/www/src/examples/quick-start-create-book/example.ts new file mode 100644 index 00000000..f5f86968 --- /dev/null +++ b/www/src/examples/quick-start-create-book/example.ts @@ -0,0 +1,12 @@ +import { Book } from "./entity"; + +await Book.create({ + bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", + storeId: "pdx-45", + author: "Stephen King", + title: "IT", + condition: "GOOD", + price: 15, + genre: ["HORROR", "THRILLER"], + published: "1986-09-15", +}).go(); diff --git a/www/src/examples/quick-start-create-book/table.ts b/www/src/examples/quick-start-create-book/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/quick-start-create-book/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/quick-start-get-book/entity.ts b/www/src/examples/quick-start-get-book/entity.ts new file mode 100644 index 00000000..607a6f8b --- /dev/null +++ b/www/src/examples/quick-start-get-book/entity.ts @@ -0,0 +1,65 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Book = new Entity( + { + model: { + entity: "book", + version: "1", + service: "store", + }, + attributes: { + storeId: { + type: "string", + }, + bookId: { + type: "string", + }, + price: { + type: "number", + required: true, + }, + title: { + type: "string", + }, + author: { + type: "string", + }, + condition: { + type: ["EXCELLENT", "GOOD", "FAIR", "POOR"] as const, + required: true, + }, + genre: { + type: "set", + items: "string", + }, + published: { + type: "string", + }, + }, + indexes: { + byLocation: { + pk: { + field: "pk", + composite: ["storeId"], + }, + sk: { + field: "sk", + composite: ["bookId"], + }, + }, + byAuthor: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["author"], + }, + sk: { + field: "gsi1sk", + composite: ["title"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/quick-start-get-book/example.ts b/www/src/examples/quick-start-get-book/example.ts new file mode 100644 index 00000000..115dccbf --- /dev/null +++ b/www/src/examples/quick-start-get-book/example.ts @@ -0,0 +1,6 @@ +import { Book } from "./entity"; + +const book = await Book.get({ + bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", + storeId: "pdx-45", +}).go(); diff --git a/www/src/examples/quick-start-get-book/table.ts b/www/src/examples/quick-start-get-book/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/quick-start-get-book/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/quick-start-update-book/entity.ts b/www/src/examples/quick-start-update-book/entity.ts new file mode 100644 index 00000000..607a6f8b --- /dev/null +++ b/www/src/examples/quick-start-update-book/entity.ts @@ -0,0 +1,65 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Book = new Entity( + { + model: { + entity: "book", + version: "1", + service: "store", + }, + attributes: { + storeId: { + type: "string", + }, + bookId: { + type: "string", + }, + price: { + type: "number", + required: true, + }, + title: { + type: "string", + }, + author: { + type: "string", + }, + condition: { + type: ["EXCELLENT", "GOOD", "FAIR", "POOR"] as const, + required: true, + }, + genre: { + type: "set", + items: "string", + }, + published: { + type: "string", + }, + }, + indexes: { + byLocation: { + pk: { + field: "pk", + composite: ["storeId"], + }, + sk: { + field: "sk", + composite: ["bookId"], + }, + }, + byAuthor: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["author"], + }, + sk: { + field: "gsi1sk", + composite: ["title"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/quick-start-update-book/example.ts b/www/src/examples/quick-start-update-book/example.ts new file mode 100644 index 00000000..6dcfc9e3 --- /dev/null +++ b/www/src/examples/quick-start-update-book/example.ts @@ -0,0 +1,11 @@ +import { Book } from "./entity"; + +await Book.patch({ + bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", + storeId: "pdx-45", +}) + .set({ + price: 10, + condition: "FAIR", + }) + .go(); diff --git a/www/src/examples/quick-start-update-book/table.ts b/www/src/examples/quick-start-update-book/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/quick-start-update-book/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/remove-store-location/entity.ts b/www/src/examples/remove-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/remove-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/remove-store-location/example.ts b/www/src/examples/remove-store-location/example.ts new file mode 100644 index 00000000..71cbcd6e --- /dev/null +++ b/www/src/examples/remove-store-location/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.remove({ + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "F34", + cityId: "Atlanta1", +}).go(); diff --git a/www/src/examples/remove-store-location/table.ts b/www/src/examples/remove-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/remove-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/scan-store-location/entity.ts b/www/src/examples/scan-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/scan-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/scan-store-location/example.ts b/www/src/examples/scan-store-location/example.ts new file mode 100644 index 00000000..16d30953 --- /dev/null +++ b/www/src/examples/scan-store-location/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.scan + .where( + ({ category }, { eq }) => ` + ${eq(category, "food/coffee")} OR ${eq(category, "spite store")} + `, + ) + .where( + ({ leaseEndDate }, { between }) => ` + ${between(leaseEndDate, "2020-03", "2020-04")} + `, + ) + .go(); diff --git a/www/src/examples/scan-store-location/table.ts b/www/src/examples/scan-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/scan-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/scan-units-index/entity.ts b/www/src/examples/scan-units-index/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/scan-units-index/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/scan-units-index/example.ts b/www/src/examples/scan-units-index/example.ts new file mode 100644 index 00000000..70645dde --- /dev/null +++ b/www/src/examples/scan-units-index/example.ts @@ -0,0 +1,3 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.scan.units.go(); diff --git a/www/src/examples/scan-units-index/table.ts b/www/src/examples/scan-units-index/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/scan-units-index/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-create-store/entity.ts b/www/src/examples/shopping-mall-directory-create-store/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-create-store/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-create-store/example.ts b/www/src/examples/shopping-mall-directory-create-store/example.ts new file mode 100644 index 00000000..9a444187 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-create-store/example.ts @@ -0,0 +1,12 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.create({ + mallId: "EastPointe", + storeId: "LatteLarrys", + buildingId: "BuildingA1", + unitId: "B47", + cityId: "Atlanta1", + category: "spite store", + leaseEndDate: "2020-02-29", + rent: "5000.00", +}).go(); diff --git a/www/src/examples/shopping-mall-directory-create-store/table.ts b/www/src/examples/shopping-mall-directory-create-store/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-create-store/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-delete-store/entity.ts b/www/src/examples/shopping-mall-directory-delete-store/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-delete-store/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-delete-store/example.ts b/www/src/examples/shopping-mall-directory-delete-store/example.ts new file mode 100644 index 00000000..bf0423b6 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-delete-store/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; +let cityId = "Atlanta1"; + +await StoreLocations.delete({ storeId, mallId, buildingId, cityId }).go(); diff --git a/www/src/examples/shopping-mall-directory-delete-store/table.ts b/www/src/examples/shopping-mall-directory-delete-store/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-delete-store/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-get-store/entity.ts b/www/src/examples/shopping-mall-directory-get-store/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-get-store/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-get-store/example.ts b/www/src/examples/shopping-mall-directory-get-store/example.ts new file mode 100644 index 00000000..61c15049 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-get-store/example.ts @@ -0,0 +1,8 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; +let cityId = "Atlanta1"; + +await StoreLocations.get({ storeId, mallId, buildingId, cityId }).go(); diff --git a/www/src/examples/shopping-mall-directory-get-store/table.ts b/www/src/examples/shopping-mall-directory-get-store/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-get-store/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-patch-lease-date/entity.ts b/www/src/examples/shopping-mall-directory-patch-lease-date/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-patch-lease-date/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-patch-lease-date/example.ts b/www/src/examples/shopping-mall-directory-patch-lease-date/example.ts new file mode 100644 index 00000000..3c0cb4af --- /dev/null +++ b/www/src/examples/shopping-mall-directory-patch-lease-date/example.ts @@ -0,0 +1,10 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; +let cityId = "Atlanta1"; + +await StoreLocations.patch({ storeId, mallId, buildingId, cityId }) + .set({ leaseEndDate: "2021-02-28" }) + .go(); diff --git a/www/src/examples/shopping-mall-directory-patch-lease-date/table.ts b/www/src/examples/shopping-mall-directory-patch-lease-date/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-patch-lease-date/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-by-category/entity.ts b/www/src/examples/shopping-mall-directory-query-by-category/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-by-category/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-by-category/example.ts b/www/src/examples/shopping-mall-directory-query-by-category/example.ts new file mode 100644 index 00000000..8e09ed62 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-by-category/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +let mallId = "EastPointe"; +let category = "food/coffee"; + +let stores = await StoreLocations.query + .units({ mallId }) + .where((attr, op) => op.eq(attr.category, category)) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-by-category/table.ts b/www/src/examples/shopping-mall-directory-query-by-category/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-by-category/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-leases-between/entity.ts b/www/src/examples/shopping-mall-directory-query-leases-between/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-between/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-leases-between/example.ts b/www/src/examples/shopping-mall-directory-query-leases-between/example.ts new file mode 100644 index 00000000..3885560a --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-between/example.ts @@ -0,0 +1,10 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let q4StartDate = "2020-10-01"; +let q4EndDate = "2020-12-31"; + +let stores = await StoreLocations.query + .leases({ storeId }) + .between({ leaseEndDate: q4StartDate }, { leaseEndDate: q4EndDate }) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-leases-between/table.ts b/www/src/examples/shopping-mall-directory-query-leases-between/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-between/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-leases-filter/entity.ts b/www/src/examples/shopping-mall-directory-query-leases-filter/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-filter/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-leases-filter/example.ts b/www/src/examples/shopping-mall-directory-query-leases-filter/example.ts new file mode 100644 index 00000000..cd9cfbf9 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-filter/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let yearStarDate = "2020-01-01"; +let yearEndDate = "2020-12-31"; + +let stores = await StoreLocations.query + .leases({ storeId }) + .between({ leaseEndDate: yearStarDate }, { leaseEndDate: yearEndDate }) + .where((attr, op) => op.eq(attr.category, "spite store")) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-leases-filter/table.ts b/www/src/examples/shopping-mall-directory-query-leases-filter/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-filter/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-leases-lt/entity.ts b/www/src/examples/shopping-mall-directory-query-leases-lt/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-lt/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-leases-lt/example.ts b/www/src/examples/shopping-mall-directory-query-leases-lt/example.ts new file mode 100644 index 00000000..0366dd3f --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-lt/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +let storeId = "LatteLarrys"; +let q2StartDate = "2020-04-01"; + +let stores = await StoreLocations.query + .leases({ storeId }) + .lt({ leaseEndDate: q2StartDate }) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-leases-lt/table.ts b/www/src/examples/shopping-mall-directory-query-leases-lt/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-leases-lt/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-units-by-building/entity.ts b/www/src/examples/shopping-mall-directory-query-units-by-building/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-building/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-building/example.ts b/www/src/examples/shopping-mall-directory-query-units-by-building/example.ts new file mode 100644 index 00000000..53f75c17 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-building/example.ts @@ -0,0 +1,6 @@ +import { StoreLocations } from "./entity"; + +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; + +let stores = await StoreLocations.query.units({ mallId, buildingId }).go(); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-building/table.ts b/www/src/examples/shopping-mall-directory-query-units-by-building/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-building/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-units-by-mall/entity.ts b/www/src/examples/shopping-mall-directory-query-units-by-mall/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-mall/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-mall/example.ts b/www/src/examples/shopping-mall-directory-query-units-by-mall/example.ts new file mode 100644 index 00000000..a6498274 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-mall/example.ts @@ -0,0 +1,5 @@ +import { StoreLocations } from "./entity"; + +let mallId = "EastPointe"; + +let stores = await StoreLocations.query.units({ mallId }).go(); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-mall/table.ts b/www/src/examples/shopping-mall-directory-query-units-by-mall/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-mall/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-units-by-unit/entity.ts b/www/src/examples/shopping-mall-directory-query-units-by-unit/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-unit/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-unit/example.ts b/www/src/examples/shopping-mall-directory-query-units-by-unit/example.ts new file mode 100644 index 00000000..e4800e6b --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-unit/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; +let unitId = "B47"; + +let stores = await StoreLocations.query + .units({ mallId, buildingId, unitId }) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-units-by-unit/table.ts b/www/src/examples/shopping-mall-directory-query-units-by-unit/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-by-unit/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/shopping-mall-directory-query-units-full/entity.ts b/www/src/examples/shopping-mall-directory-query-units-full/entity.ts new file mode 100644 index 00000000..da57f786 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-full/entity.ts @@ -0,0 +1,96 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/shopping-mall-directory-query-units-full/example.ts b/www/src/examples/shopping-mall-directory-query-units-full/example.ts new file mode 100644 index 00000000..438d975e --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-full/example.ts @@ -0,0 +1,9 @@ +import { StoreLocations } from "./entity"; + +let mallId = "EastPointe"; +let buildingId = "BuildingA1"; +let storeId = "LatteLarrys"; + +let stores = await StoreLocations.query + .units({ mallId, buildingId, storeId }) + .go(); diff --git a/www/src/examples/shopping-mall-directory-query-units-full/table.ts b/www/src/examples/shopping-mall-directory-query-units-full/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/shopping-mall-directory-query-units-full/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-assignments/entities.ts b/www/src/examples/task-manager-assignments/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-assignments/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-assignments/example.ts b/www/src/examples/task-manager-assignments/example.ts new file mode 100644 index 00000000..4ae51787 --- /dev/null +++ b/www/src/examples/task-manager-assignments/example.ts @@ -0,0 +1,5 @@ +import { taskManager } from "./service"; + +const { data, cursor } = await taskManager.collections + .assignments({ employee: "tyler.walch" }) + .go(); diff --git a/www/src/examples/task-manager-assignments/service.ts b/www/src/examples/task-manager-assignments/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-assignments/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-assignments/table.ts b/www/src/examples/task-manager-assignments/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-assignments/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-create-task/entities.ts b/www/src/examples/task-manager-create-task/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-create-task/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-create-task/example.ts b/www/src/examples/task-manager-create-task/example.ts new file mode 100644 index 00000000..71258cdb --- /dev/null +++ b/www/src/examples/task-manager-create-task/example.ts @@ -0,0 +1,17 @@ +import type { CreateEntityItem } from "electrodb"; +import { taskManager } from "./service"; +import { task } from "./entities"; + +type CreateTaskItem = CreateEntityItem; + +function createNewTask(item: CreateTaskItem) { + return taskManager.entities.task.put(item).go(); +} + +const newTask = await createNewTask({ + task: "design-review", + project: "135-53", + employee: "tyler.walch", + description: "Review the new component library designs", + points: 5, +}); diff --git a/www/src/examples/task-manager-create-task/service.ts b/www/src/examples/task-manager-create-task/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-create-task/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-create-task/table.ts b/www/src/examples/task-manager-create-task/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-create-task/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-junior-developers/entities.ts b/www/src/examples/task-manager-junior-developers/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-junior-developers/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-junior-developers/example.ts b/www/src/examples/task-manager-junior-developers/example.ts new file mode 100644 index 00000000..0b708b3e --- /dev/null +++ b/www/src/examples/task-manager-junior-developers/example.ts @@ -0,0 +1,9 @@ +import { taskManager } from "./service"; + +const title = "Junior Software Engineer"; +const salary = "100000"; + +const developers = await taskManager.entities.employee.query + .roles({ title }) + .gt({ salary }) + .go(); diff --git a/www/src/examples/task-manager-junior-developers/service.ts b/www/src/examples/task-manager-junior-developers/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-junior-developers/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-junior-developers/table.ts b/www/src/examples/task-manager-junior-developers/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-junior-developers/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-open-tasks/entities.ts b/www/src/examples/task-manager-open-tasks/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-open-tasks/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-open-tasks/example.ts b/www/src/examples/task-manager-open-tasks/example.ts new file mode 100644 index 00000000..eecb4d63 --- /dev/null +++ b/www/src/examples/task-manager-open-tasks/example.ts @@ -0,0 +1,9 @@ +import { taskManager } from "./service"; + +const status = "open"; +const project = "135-53"; + +const tasks = await taskManager.entities.task.query + .statuses({ status, project }) + .where(({ points }, { lte }) => lte(points, 13)) + .go(); diff --git a/www/src/examples/task-manager-open-tasks/service.ts b/www/src/examples/task-manager-open-tasks/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-open-tasks/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-open-tasks/table.ts b/www/src/examples/task-manager-open-tasks/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-open-tasks/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-recent-hires/entities.ts b/www/src/examples/task-manager-recent-hires/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-recent-hires/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-recent-hires/example.ts b/www/src/examples/task-manager-recent-hires/example.ts new file mode 100644 index 00000000..98ca2865 --- /dev/null +++ b/www/src/examples/task-manager-recent-hires/example.ts @@ -0,0 +1,16 @@ +import { taskManager } from "./service"; + +function yearsAgo(years: number): string { + const date = new Date(); + date.setUTCFullYear(date.getUTCFullYear() - years); + return date.toISOString().slice(0, 10); +} + +const team = "marketing"; +const twoYearsAgo = yearsAgo(2); +const fiveYearsAgo = yearsAgo(5); + +const recentHires = await taskManager.entities.employee.query + .teams({ team }) + .between({ dateHired: fiveYearsAgo }, { dateHired: twoYearsAgo }) + .go(); diff --git a/www/src/examples/task-manager-recent-hires/service.ts b/www/src/examples/task-manager-recent-hires/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-recent-hires/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-recent-hires/table.ts b/www/src/examples/task-manager-recent-hires/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-recent-hires/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/task-manager-workplace/entities.ts b/www/src/examples/task-manager-workplace/entities.ts new file mode 100644 index 00000000..97261228 --- /dev/null +++ b/www/src/examples/task-manager-workplace/entities.ts @@ -0,0 +1,287 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +function randomId(): string { + return Math.random().toString(36).slice(2, 10); +} + +function isValidDate(date: string): boolean { + return !Number.isNaN(Date.parse(date)); +} + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "taskmanager", + }, + attributes: { + employee: { + type: "string", + default: () => randomId(), + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + office: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + team: { + type: [ + "development", + "marketing", + "finance", + "product", + "cool cats and kittens", + ] as const, + required: true, + }, + salary: { + type: "string", + required: true, + }, + manager: { + type: "string", + }, + dateHired: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + birthday: { + type: "string", + validate: (date: string) => { + if (!isValidDate(date)) { + throw new Error("Invalid date format"); + } + return true; + }, + }, + }, + indexes: { + employee: { + pk: { + field: "pk", + composite: ["employee"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + coworkers: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: ["team", "title", "employee"], + }, + }, + teams: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["team"], + }, + sk: { + field: "gsi2sk", + composite: ["dateHired", "title"], + }, + }, + employeeLookup: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: [], + }, + }, + roles: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["title"], + }, + sk: { + field: "gsi4sk", + composite: ["salary"], + }, + }, + directReports: { + index: "gsi5pk-gsi5sk-index", + pk: { + field: "gsi5pk", + composite: ["manager"], + }, + sk: { + field: "gsi5sk", + composite: ["team", "office"], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "taskmanager", + }, + attributes: { + office: { + type: "string", + }, + country: { + type: "string", + }, + state: { + type: "string", + }, + city: { + type: "string", + }, + zip: { + type: "string", + }, + address: { + type: "string", + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["country", "state"], + }, + sk: { + field: "sk", + composite: ["city", "zip", "office"], + }, + }, + office: { + index: "gsi1pk-gsi1sk-index", + collection: "workplaces", + pk: { + field: "gsi1pk", + composite: ["office"], + }, + sk: { + field: "gsi1sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const task = new Entity( + { + model: { + entity: "task", + version: "1", + service: "taskmanager", + }, + attributes: { + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + employee: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + type: ["open", "in-progress", "closed"] as const, + default: "open", + }, + points: { + type: "number", + required: true, + }, + comments: { + type: "any", + }, + }, + indexes: { + task: { + pk: { + field: "pk", + composite: ["task"], + }, + sk: { + field: "sk", + composite: ["project", "employee"], + }, + }, + project: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["project"], + }, + sk: { + field: "gsi1sk", + composite: ["employee", "status"], + }, + }, + assigned: { + collection: "assignments", + index: "gsi3pk-gsi3sk-index", + pk: { + field: "gsi3pk", + composite: ["employee"], + }, + sk: { + field: "gsi3sk", + composite: ["project", "status"], + }, + }, + statuses: { + index: "gsi4pk-gsi4sk-index", + pk: { + field: "gsi4pk", + composite: ["status"], + }, + sk: { + field: "gsi4sk", + composite: ["project", "employee"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/task-manager-workplace/example.ts b/www/src/examples/task-manager-workplace/example.ts new file mode 100644 index 00000000..aaf5d13c --- /dev/null +++ b/www/src/examples/task-manager-workplace/example.ts @@ -0,0 +1,5 @@ +import { taskManager } from "./service"; + +const workplace = await taskManager.collections + .workplaces({ office: "portland" }) + .go(); diff --git a/www/src/examples/task-manager-workplace/service.ts b/www/src/examples/task-manager-workplace/service.ts new file mode 100644 index 00000000..53e37a23 --- /dev/null +++ b/www/src/examples/task-manager-workplace/service.ts @@ -0,0 +1,8 @@ +import { Service } from "electrodb"; +import { employee, task, office } from "./entities"; + +export const taskManager = new Service({ + employee, + task, + office, +}); diff --git a/www/src/examples/task-manager-workplace/table.ts b/www/src/examples/task-manager-workplace/table.ts new file mode 100644 index 00000000..94a9c8e2 --- /dev/null +++ b/www/src/examples/task-manager-workplace/table.ts @@ -0,0 +1,148 @@ +export const tableName = "taskmanager"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + { + AttributeName: "gsi3pk", + AttributeType: "S", + }, + { + AttributeName: "gsi3sk", + AttributeType: "S", + }, + { + AttributeName: "gsi4pk", + AttributeType: "S", + }, + { + AttributeName: "gsi4sk", + AttributeType: "S", + }, + { + AttributeName: "gsi5pk", + AttributeType: "S", + }, + { + AttributeName: "gsi5sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi3pk-gsi3sk-index", + KeySchema: [ + { + AttributeName: "gsi3pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi3sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi4pk-gsi4sk-index", + KeySchema: [ + { + AttributeName: "gsi4pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi4sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi5pk-gsi5sk-index", + KeySchema: [ + { + AttributeName: "gsi5pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi5sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/transact-get-employee-and-office/entities.ts b/www/src/examples/transact-get-employee-and-office/entities.ts new file mode 100644 index 00000000..af048beb --- /dev/null +++ b/www/src/examples/transact-get-employee-and-office/entities.ts @@ -0,0 +1,83 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const employee = new Entity( + { + model: { + entity: "employee", + version: "1", + service: "Workforce", + }, + attributes: { + employeeId: { + type: "string", + required: true, + }, + officeId: { + type: "string", + required: true, + }, + firstName: { + type: "string", + required: true, + }, + lastName: { + type: "string", + required: true, + }, + title: { + type: "string", + }, + }, + indexes: { + staff: { + pk: { + field: "pk", + composite: ["employeeId"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); + +export const office = new Entity( + { + model: { + entity: "office", + version: "1", + service: "Workforce", + }, + attributes: { + officeId: { + type: "string", + required: true, + }, + name: { + type: "string", + required: true, + }, + city: { + type: "string", + required: true, + }, + }, + indexes: { + locations: { + pk: { + field: "pk", + composite: ["officeId"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/transact-get-employee-and-office/example.ts b/www/src/examples/transact-get-employee-and-office/example.ts new file mode 100644 index 00000000..92997a87 --- /dev/null +++ b/www/src/examples/transact-get-employee-and-office/example.ts @@ -0,0 +1,8 @@ +import { workforce } from "./service"; + +await workforce.transaction + .get(({ employee, office }) => [ + employee.get({ employeeId: "employee-1" }).commit(), + office.get({ officeId: "office-1" }).commit(), + ]) + .go(); diff --git a/www/src/examples/transact-get-employee-and-office/service.ts b/www/src/examples/transact-get-employee-and-office/service.ts new file mode 100644 index 00000000..d6193830 --- /dev/null +++ b/www/src/examples/transact-get-employee-and-office/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { employee, office } from "./entities"; + +export const workforce = new Service({ employee, office }); diff --git a/www/src/examples/transact-get-employee-and-office/table.ts b/www/src/examples/transact-get-employee-and-office/table.ts new file mode 100644 index 00000000..1af4a71d --- /dev/null +++ b/www/src/examples/transact-get-employee-and-office/table.ts @@ -0,0 +1,26 @@ +export const tableName = "WorkforceDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/transact-write-idempotent-writes/entities.ts b/www/src/examples/transact-write-idempotent-writes/entities.ts new file mode 100644 index 00000000..e0cc62e8 --- /dev/null +++ b/www/src/examples/transact-write-idempotent-writes/entities.ts @@ -0,0 +1,100 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const agent = new Entity( + { + model: { + entity: "agent", + version: "1", + service: "MI6", + }, + attributes: { + id: { + type: "string", + }, + designation: { + type: "string", + }, + email: { + type: "string", + required: true, + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + alive: { + type: "boolean", + required: true, + }, + kills: { + type: "number", + default: 0, + }, + }, + indexes: { + operatives: { + pk: { + field: "pk", + composite: ["designation"], + }, + sk: { + field: "sk", + composite: ["id"], + }, + }, + }, + }, + { table: tableName }, +); + +// entity that owns unique constraints +export const constraint = new Entity( + { + model: { + entity: "constraint", + version: "1", + service: "MI6", + }, + attributes: { + name: { + type: "string", + required: true, + }, + value: { + type: "string", + required: true, + }, + entity: { + type: "string", + required: true, + }, + }, + indexes: { + value: { + pk: { + field: "pk", + composite: ["value"], + }, + sk: { + field: "sk", + composite: ["name", "entity"], + }, + }, + name: { + index: "gsi1pk-gsi2sk-index", + pk: { + field: "gsi1pk", + composite: ["name", "entity"], + }, + sk: { + field: "gsi1sk", + composite: ["value"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/transact-write-idempotent-writes/example.ts b/www/src/examples/transact-write-idempotent-writes/example.ts new file mode 100644 index 00000000..1a570833 --- /dev/null +++ b/www/src/examples/transact-write-idempotent-writes/example.ts @@ -0,0 +1,36 @@ +import { mi6 } from "./service"; + +type IncrementAgentKillsOptions = { + id: string; + kills: number; + token: string; + designation: string; +}; + +async function incrementAgentKills(options: IncrementAgentKillsOptions) { + const { id, designation, kills, token } = options; + + return mi6.transaction + .write(({ agent }) => [ + agent.patch({ id, designation }).add({ kills }).commit(), + ]) + .go({ token }); +} + +const token = "daily-headcount-count-2022-03-16"; + +// kills `0` -> `2` +await incrementAgentKills({ + token, + id: "7", + kills: 2, + designation: "00", +}); + +// still results in `2` +await incrementAgentKills({ + token, + id: "7", + kills: 2, + designation: "00", +}); diff --git a/www/src/examples/transact-write-idempotent-writes/service.ts b/www/src/examples/transact-write-idempotent-writes/service.ts new file mode 100644 index 00000000..6c0715ae --- /dev/null +++ b/www/src/examples/transact-write-idempotent-writes/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { agent, constraint } from "./entities"; + +export const mi6 = new Service({ constraint, agent }); diff --git a/www/src/examples/transact-write-idempotent-writes/table.ts b/www/src/examples/transact-write-idempotent-writes/table.ts new file mode 100644 index 00000000..a1a08c51 --- /dev/null +++ b/www/src/examples/transact-write-idempotent-writes/table.ts @@ -0,0 +1,52 @@ +export const tableName = "MI6"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/transact-write-unique-constraint/entities.ts b/www/src/examples/transact-write-unique-constraint/entities.ts new file mode 100644 index 00000000..e0cc62e8 --- /dev/null +++ b/www/src/examples/transact-write-unique-constraint/entities.ts @@ -0,0 +1,100 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const agent = new Entity( + { + model: { + entity: "agent", + version: "1", + service: "MI6", + }, + attributes: { + id: { + type: "string", + }, + designation: { + type: "string", + }, + email: { + type: "string", + required: true, + }, + firstName: { + type: "string", + }, + lastName: { + type: "string", + }, + alive: { + type: "boolean", + required: true, + }, + kills: { + type: "number", + default: 0, + }, + }, + indexes: { + operatives: { + pk: { + field: "pk", + composite: ["designation"], + }, + sk: { + field: "sk", + composite: ["id"], + }, + }, + }, + }, + { table: tableName }, +); + +// entity that owns unique constraints +export const constraint = new Entity( + { + model: { + entity: "constraint", + version: "1", + service: "MI6", + }, + attributes: { + name: { + type: "string", + required: true, + }, + value: { + type: "string", + required: true, + }, + entity: { + type: "string", + required: true, + }, + }, + indexes: { + value: { + pk: { + field: "pk", + composite: ["value"], + }, + sk: { + field: "sk", + composite: ["name", "entity"], + }, + }, + name: { + index: "gsi1pk-gsi2sk-index", + pk: { + field: "gsi1pk", + composite: ["name", "entity"], + }, + sk: { + field: "gsi1sk", + composite: ["value"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/transact-write-unique-constraint/example.ts b/www/src/examples/transact-write-unique-constraint/example.ts new file mode 100644 index 00000000..d123cfad --- /dev/null +++ b/www/src/examples/transact-write-unique-constraint/example.ts @@ -0,0 +1,28 @@ +import type { CreateEntityItem } from "electrodb"; +import { mi6 } from "./service"; + +type NewAgent = CreateEntityItem; + +async function createNewAgent(newAgent: NewAgent) { + return mi6.transaction + .write(({ agent, constraint }) => [ + agent.create(newAgent).commit({ response: "all_old" }), + constraint + .create({ + name: "email", + value: newAgent.email, + entity: agent.schema.model.entity, + }) + .commit(), + ]) + .go(); +} + +await createNewAgent({ + id: "7", + designation: "00", + email: "james.bond@mi6.gov.uk", + firstName: "James", + lastName: "Bond", + alive: true, +}); diff --git a/www/src/examples/transact-write-unique-constraint/service.ts b/www/src/examples/transact-write-unique-constraint/service.ts new file mode 100644 index 00000000..6c0715ae --- /dev/null +++ b/www/src/examples/transact-write-unique-constraint/service.ts @@ -0,0 +1,4 @@ +import { Service } from "electrodb"; +import { agent, constraint } from "./entities"; + +export const mi6 = new Service({ constraint, agent }); diff --git a/www/src/examples/transact-write-unique-constraint/table.ts b/www/src/examples/transact-write-unique-constraint/table.ts new file mode 100644 index 00000000..a1a08c51 --- /dev/null +++ b/www/src/examples/transact-write-unique-constraint/table.ts @@ -0,0 +1,52 @@ +export const tableName = "MI6"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-composite-attributes-edgecase/entity.ts b/www/src/examples/update-composite-attributes-edgecase/entity.ts new file mode 100644 index 00000000..944896a3 --- /dev/null +++ b/www/src/examples/update-composite-attributes-edgecase/entity.ts @@ -0,0 +1,54 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const entity = new Entity( + { + model: { + entity: "update-edgecases", + service: "service", + version: "1", + }, + attributes: { + attr1: { + type: "string", + required: true, + }, + attr2: { + type: "string", + required: true, + }, + attr3: { + type: "string", + required: true, + }, + attr4: { + type: "string", + required: true, + }, + }, + indexes: { + accessPattern1: { + pk: { + field: "pk", + composite: ["attr1"], + }, + sk: { + field: "sk", + composite: ["attr2"], + }, + }, + accessPattern2: { + index: "my-gsi", + pk: { + field: "gsi1pk", + composite: ["attr3"], + }, + sk: { + field: "gsi1sk", + composite: ["attr2", "attr4"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-composite-attributes-edgecase/example.ts b/www/src/examples/update-composite-attributes-edgecase/example.ts new file mode 100644 index 00000000..e3db55c3 --- /dev/null +++ b/www/src/examples/update-composite-attributes-edgecase/example.ts @@ -0,0 +1,6 @@ +import { entity } from "./entity"; + +await entity + .update({ attr1: "value1", attr2: "value2" }) + .set({ attr4: "value4" }) + .go(); diff --git a/www/src/examples/update-composite-attributes-edgecase/table.ts b/www/src/examples/update-composite-attributes-edgecase/table.ts new file mode 100644 index 00000000..5634db7d --- /dev/null +++ b/www/src/examples/update-composite-attributes-edgecase/table.ts @@ -0,0 +1,52 @@ +export const tableName = "YOUR_TABLE_NAME"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "my-gsi", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-list-element-remove/entity.ts b/www/src/examples/update-list-element-remove/entity.ts new file mode 100644 index 00000000..db103283 --- /dev/null +++ b/www/src/examples/update-list-element-remove/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + mapAttribute: { + type: "map", + properties: { + mapProperty: { + type: "string", + }, + }, + }, + listAttribute: { + type: "list", + items: { + type: "map", + properties: { + setAttribute: { + type: "set", + items: "string", + }, + }, + }, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-list-element-remove/example.ts b/www/src/examples/update-list-element-remove/example.ts new file mode 100644 index 00000000..c9857b4b --- /dev/null +++ b/www/src/examples/update-list-element-remove/example.ts @@ -0,0 +1,17 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +// via Chain Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + // @ts-ignore -- bracket-index attribute names are not yet supported by the TS types + .remove(["listAttribute[0]"]) + .go(); + +// via Data Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .data(({ listAttribute }, { remove }) => remove(listAttribute[0])) + .go(); diff --git a/www/src/examples/update-list-element-remove/table.ts b/www/src/examples/update-list-element-remove/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-list-element-remove/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-map-property/entity.ts b/www/src/examples/update-map-property/entity.ts new file mode 100644 index 00000000..db103283 --- /dev/null +++ b/www/src/examples/update-map-property/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + mapAttribute: { + type: "map", + properties: { + mapProperty: { + type: "string", + }, + }, + }, + listAttribute: { + type: "list", + items: { + type: "map", + properties: { + setAttribute: { + type: "set", + items: "string", + }, + }, + }, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-map-property/example.ts b/www/src/examples/update-map-property/example.ts new file mode 100644 index 00000000..412fc862 --- /dev/null +++ b/www/src/examples/update-map-property/example.ts @@ -0,0 +1,17 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +// via Chain Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + // @ts-ignore -- dot-path attribute names are not yet supported by the TS types + .set({ "mapAttribute.mapProperty": "value" }) + .go(); + +// via Data Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .data(({ mapAttribute }, { set }) => set(mapAttribute.mapProperty, "value")) + .go(); diff --git a/www/src/examples/update-map-property/table.ts b/www/src/examples/update-map-property/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-map-property/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-nested-set-add/entity.ts b/www/src/examples/update-nested-set-add/entity.ts new file mode 100644 index 00000000..db103283 --- /dev/null +++ b/www/src/examples/update-nested-set-add/entity.ts @@ -0,0 +1,63 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + mapAttribute: { + type: "map", + properties: { + mapProperty: { + type: "string", + }, + }, + }, + listAttribute: { + type: "list", + items: { + type: "map", + properties: { + setAttribute: { + type: "set", + items: "string", + }, + }, + }, + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-nested-set-add/example.ts b/www/src/examples/update-nested-set-add/example.ts new file mode 100644 index 00000000..020115bc --- /dev/null +++ b/www/src/examples/update-nested-set-add/example.ts @@ -0,0 +1,22 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +// Set values must use the DocumentClient to create a `set` +const newSetValue = StoreLocations.client.createSet("setItemValue"); + +// via Chain Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + // @ts-ignore -- bracket-index attribute names are not yet supported by the TS types + .add({ "listAttribute[1].setAttribute": newSetValue }) + .go(); + +// via Data Method +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .data(({ listAttribute }, { add }) => { + add(listAttribute[1].setAttribute, newSetValue); + }) + .go(); diff --git a/www/src/examples/update-nested-set-add/table.ts b/www/src/examples/update-nested-set-add/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-nested-set-add/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-organization-composite/entity.ts b/www/src/examples/update-organization-composite/entity.ts new file mode 100644 index 00000000..5077a5ad --- /dev/null +++ b/www/src/examples/update-organization-composite/entity.ts @@ -0,0 +1,60 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const Organization = new Entity( + { + model: { + entity: "organization", + service: "app", + version: "1", + }, + attributes: { + id: { + type: "string", + }, + name: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + deleted: { + type: "boolean", + required: true, + default: false, + }, + createdAt: { + type: "string", + readOnly: true, + required: true, + set: () => new Date().toISOString(), + default: () => new Date().toISOString(), + }, + }, + indexes: { + record: { + pk: { + field: "pk", + composite: ["id"], + }, + sk: { + field: "sk", + composite: [], + }, + }, + all: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: [], + }, + sk: { + field: "gsi1sk", + composite: ["deleted", "createdAt"], // SK has both readonly and mutable attributes + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-organization-composite/example.ts b/www/src/examples/update-organization-composite/example.ts new file mode 100644 index 00000000..87849c40 --- /dev/null +++ b/www/src/examples/update-organization-composite/example.ts @@ -0,0 +1,11 @@ +import { Organization } from "./entity"; + +const id = "00001"; +const existing = await Organization.get({ id }).go(); + +if (existing.data?.deleted) { + await Organization.update({ id: "00001" }) + .set({ deleted: false }) + .composite({ createdAt: existing.data.createdAt }) + .go(); +} diff --git a/www/src/examples/update-organization-composite/table.ts b/www/src/examples/update-organization-composite/table.ts new file mode 100644 index 00000000..d54b9469 --- /dev/null +++ b/www/src/examples/update-organization-composite/table.ts @@ -0,0 +1,52 @@ +export const tableName = "electro"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-add/entity.ts b/www/src/examples/update-store-location-add/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/update-store-location-add/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-add/example.ts b/www/src/examples/update-store-location-add/example.ts new file mode 100644 index 00000000..fb108dfb --- /dev/null +++ b/www/src/examples/update-store-location-add/example.ts @@ -0,0 +1,14 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .add({ + warnings: 1, // "number" attribute + tenants: ["larry"], // "set" attribute + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-add/table.ts b/www/src/examples/update-store-location-add/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-add/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-append/entity.ts b/www/src/examples/update-store-location-append/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/update-store-location-append/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-append/example.ts b/www/src/examples/update-store-location-append/example.ts new file mode 100644 index 00000000..71242c84 --- /dev/null +++ b/www/src/examples/update-store-location-append/example.ts @@ -0,0 +1,18 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .append({ + rentalAgreement: [ + { + type: "amendment", + detail: "no soup for you", + }, + ], + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-append/table.ts b/www/src/examples/update-store-location-append/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-append/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-data/entity.ts b/www/src/examples/update-store-location-data/entity.ts new file mode 100644 index 00000000..d53d516f --- /dev/null +++ b/www/src/examples/update-store-location-data/entity.ts @@ -0,0 +1,135 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + contact: { + type: "set", + items: "string", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + petFee: { + type: "number", + }, + fees: { + type: "number", + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-data/example.ts b/www/src/examples/update-store-location-data/example.ts new file mode 100644 index 00000000..316c7f9c --- /dev/null +++ b/www/src/examples/update-store-location-data/example.ts @@ -0,0 +1,28 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .data((a, o) => { + const newTenant = o.value(a.tenants, ["larry"]); + o.set(a.category, "food/meal"); // electrodb "enum" -> dynamodb "string" + o.add(a.tenants, newTenant); // electrodb "set" -> dynamodb "set" + o.add(a.warnings, 1); // electrodb "number" -> dynamodb "number" + o.subtract(a.deposit, 200); // electrodb "number" -> dynamodb "number" + o.remove(a.discount); // electrodb "number" -> dynamodb "number" + o.append(a.rentalAgreement, [ + { + // electrodb "list" -> dynamodb "list" + type: "amendment", // electrodb "map" -> dynamodb "map" + detail: "no soup for you", + }, + ]); + o.delete(a.tags, ["coffee"]); + o.del(a.contact, ["555-345-2222"]); // electrodb "set" -> dynamodb "set" + o.add(a.fees, o.name(a.petFee)); // electrodb "number" -> dynamodb "number" + }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-data/table.ts b/www/src/examples/update-store-location-data/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-data/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-delete/entity.ts b/www/src/examples/update-store-location-delete/entity.ts new file mode 100644 index 00000000..02b2c112 --- /dev/null +++ b/www/src/examples/update-store-location-delete/entity.ts @@ -0,0 +1,129 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + contact: { + type: "set", + items: "string", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-delete/example.ts b/www/src/examples/update-store-location-delete/example.ts new file mode 100644 index 00000000..145cd8a4 --- /dev/null +++ b/www/src/examples/update-store-location-delete/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .delete({ contact: ["555-345-2222"] }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-delete/table.ts b/www/src/examples/update-store-location-delete/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-delete/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-remove/entity.ts b/www/src/examples/update-store-location-remove/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/update-store-location-remove/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-remove/example.ts b/www/src/examples/update-store-location-remove/example.ts new file mode 100644 index 00000000..ec13420f --- /dev/null +++ b/www/src/examples/update-store-location-remove/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .remove(["discount"]) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-remove/table.ts b/www/src/examples/update-store-location-remove/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-remove/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-set/entity.ts b/www/src/examples/update-store-location-set/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/update-store-location-set/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-set/example.ts b/www/src/examples/update-store-location-set/example.ts new file mode 100644 index 00000000..12e9fd3c --- /dev/null +++ b/www/src/examples/update-store-location-set/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .set({ category: "food/meal" }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-set/table.ts b/www/src/examples/update-store-location-set/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-set/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-store-location-subtract/entity.ts b/www/src/examples/update-store-location-subtract/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/update-store-location-subtract/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-store-location-subtract/example.ts b/www/src/examples/update-store-location-subtract/example.ts new file mode 100644 index 00000000..e6f4cf65 --- /dev/null +++ b/www/src/examples/update-store-location-subtract/example.ts @@ -0,0 +1,11 @@ +import { StoreLocations } from "./entity"; + +const cityId = "Atlanta1"; +const mallId = "EastPointe"; +const storeId = "LatteLarrys"; +const buildingId = "BuildingA1"; + +await StoreLocations.update({ cityId, mallId, storeId, buildingId }) + .subtract({ deposit: 500 }) + .where((attr, op) => op.eq(attr.category, "food/coffee")) + .go(); diff --git a/www/src/examples/update-store-location-subtract/table.ts b/www/src/examples/update-store-location-subtract/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/update-store-location-subtract/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/update-tasks-set-add-append/entity.ts b/www/src/examples/update-tasks-set-add-append/entity.ts new file mode 100644 index 00000000..f266e3ee --- /dev/null +++ b/www/src/examples/update-tasks-set-add-append/entity.ts @@ -0,0 +1,122 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const tasks = new Entity( + { + model: { + entity: "tasks", + version: "1", + service: "taskapp", + }, + attributes: { + team: { + type: "string", + required: true, + }, + task: { + type: "string", + required: true, + }, + project: { + type: "string", + required: true, + }, + user: { + type: "string", + required: true, + }, + title: { + type: "string", + required: true, + }, + description: { + type: "string", + }, + status: { + // use an array to type an enum + type: ["open", "in-progress", "on-hold", "closed"] as const, + default: "open", + }, + points: { + type: "number", + }, + tags: { + type: "set", + items: "string", + }, + comments: { + type: "list", + items: { + type: "map", + properties: { + user: { + type: "string", + }, + body: { + type: "string", + }, + }, + }, + }, + closed: { + type: "string", + validate: /[0-9]{4}-[0-9]{2}-[0-9]{2}/, + }, + createdAt: { + type: "number", + default: () => Date.now(), + // cannot be modified after created + readOnly: true, + }, + updatedAt: { + type: "number", + // watch for changes to any attribute + watch: "*", + // set current timestamp when updated + set: () => Date.now(), + readOnly: true, + }, + }, + indexes: { + projects: { + pk: { + field: "pk", + composite: ["team"], + }, + sk: { + field: "sk", + // create composite keys for partial sort key queries + composite: ["project", "task"], + }, + }, + assigned: { + // collections allow for queries across multiple entities + collection: "assignments", + index: "gsi1pk-gsi1sk-index", + pk: { + // map to your GSI Hash/Partition key + field: "gsi1pk", + composite: ["user"], + }, + sk: { + // map to your GSI Range/Sort key + field: "gsi1sk", + composite: ["status"], + }, + }, + backlog: { + // map to the GSI name on your DynamoDB table + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["project"], + }, + sk: { + field: "gsi2sk", + composite: ["team", "closed"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/update-tasks-set-add-append/example.ts b/www/src/examples/update-tasks-set-add-append/example.ts new file mode 100644 index 00000000..f0a78524 --- /dev/null +++ b/www/src/examples/update-tasks-set-add-append/example.ts @@ -0,0 +1,20 @@ +import { tasks } from "./entity"; + +await tasks + .update({ + team: "core", + task: "45-662", + project: "backend", + }) + .set({ status: "open" }) + .add({ points: 5 }) + .append({ + comments: [ + { + user: "janet", + body: "This seems half-baked.", + }, + ], + }) + .where(({ status }, { eq }) => eq(status, "in-progress")) + .go(); diff --git a/www/src/examples/update-tasks-set-add-append/table.ts b/www/src/examples/update-tasks-set-add-append/table.ts new file mode 100644 index 00000000..42b07d29 --- /dev/null +++ b/www/src/examples/update-tasks-set-add-append/table.ts @@ -0,0 +1,76 @@ +export const tableName = "your_table_name"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/upsert-store-location-add-subtract-append/entity.ts b/www/src/examples/upsert-store-location-add-subtract-append/entity.ts new file mode 100644 index 00000000..0ec0b069 --- /dev/null +++ b/www/src/examples/upsert-store-location-add-subtract-append/entity.ts @@ -0,0 +1,128 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + petFee: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/upsert-store-location-add-subtract-append/example.ts b/www/src/examples/upsert-store-location-add-subtract-append/example.ts new file mode 100644 index 00000000..e1642cd4 --- /dev/null +++ b/www/src/examples/upsert-store-location-add-subtract-append/example.ts @@ -0,0 +1,24 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.upsert({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}) + .add({ deposit: 100, tenants: ["Larry David"] }) + .ifNotExists({ warnings: 0 }) + .subtract({ petFee: 250 }) + .append({ + rentalAgreement: [ + { + type: "amendment", + detail: "Larry David accepts coffee liability", + }, + ], + }) + .go(); diff --git a/www/src/examples/upsert-store-location-add-subtract-append/table.ts b/www/src/examples/upsert-store-location-add-subtract-append/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/upsert-store-location-add-subtract-append/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/examples/upsert-store-location/entity.ts b/www/src/examples/upsert-store-location/entity.ts new file mode 100644 index 00000000..d493d785 --- /dev/null +++ b/www/src/examples/upsert-store-location/entity.ts @@ -0,0 +1,125 @@ +import { Entity } from "electrodb"; +import { tableName } from "./table"; + +export const StoreLocations = new Entity( + { + model: { + service: "MallStoreDirectory", + entity: "MallStore", + version: "1", + }, + attributes: { + cityId: { + type: "string", + required: true, + }, + mallId: { + type: "string", + required: true, + }, + storeId: { + type: "string", + required: true, + }, + buildingId: { + type: "string", + required: true, + }, + unitId: { + type: "string", + required: true, + }, + category: { + type: [ + "spite store", + "food/coffee", + "food/meal", + "clothing", + "electronics", + "department", + "misc", + ], + required: true, + }, + leaseEndDate: { + type: "string", + required: true, + }, + rent: { + type: "string", + required: true, + validate: /^(\d+\.\d{2})$/, + }, + discount: { + type: "string", + required: false, + default: "0.00", + validate: /^(\d+\.\d{2})$/, + }, + tenants: { + type: "set", + items: "string", + }, + warnings: { + type: "number", + default: 0, + }, + deposit: { + type: "number", + }, + rentalAgreement: { + type: "list", + items: { + type: "map", + properties: { + type: { + type: "string", + }, + detail: { + type: "string", + }, + }, + }, + }, + tags: { + type: "set", + items: "string", + }, + }, + indexes: { + stores: { + pk: { + field: "pk", + composite: ["cityId", "mallId"], + }, + sk: { + field: "sk", + composite: ["buildingId", "storeId"], + }, + }, + units: { + index: "gsi1pk-gsi1sk-index", + pk: { + field: "gsi1pk", + composite: ["mallId"], + }, + sk: { + field: "gsi1sk", + composite: ["buildingId", "unitId"], + }, + }, + leases: { + index: "gsi2pk-gsi2sk-index", + pk: { + field: "gsi2pk", + composite: ["storeId"], + }, + sk: { + field: "gsi2sk", + composite: ["leaseEndDate"], + }, + }, + }, + }, + { table: tableName }, +); diff --git a/www/src/examples/upsert-store-location/example.ts b/www/src/examples/upsert-store-location/example.ts new file mode 100644 index 00000000..94d0c55d --- /dev/null +++ b/www/src/examples/upsert-store-location/example.ts @@ -0,0 +1,12 @@ +import { StoreLocations } from "./entity"; + +await StoreLocations.upsert({ + cityId: "Atlanta1", + storeId: "LatteLarrys", + mallId: "EastPointe", + buildingId: "BuildingA1", + unitId: "B47", + category: "food/coffee", + leaseEndDate: "2020-03-22", + rent: "4500.00", +}).go(); diff --git a/www/src/examples/upsert-store-location/table.ts b/www/src/examples/upsert-store-location/table.ts new file mode 100644 index 00000000..b0d562a8 --- /dev/null +++ b/www/src/examples/upsert-store-location/table.ts @@ -0,0 +1,76 @@ +export const tableName = "StoreDirectory"; + +export const tableDefinition = { + TableName: tableName, + KeySchema: [ + { + AttributeName: "pk", + KeyType: "HASH", + }, + { + AttributeName: "sk", + KeyType: "RANGE", + }, + ], + AttributeDefinitions: [ + { + AttributeName: "pk", + AttributeType: "S", + }, + { + AttributeName: "sk", + AttributeType: "S", + }, + { + AttributeName: "gsi1pk", + AttributeType: "S", + }, + { + AttributeName: "gsi1sk", + AttributeType: "S", + }, + { + AttributeName: "gsi2pk", + AttributeType: "S", + }, + { + AttributeName: "gsi2sk", + AttributeType: "S", + }, + ], + GlobalSecondaryIndexes: [ + { + IndexName: "gsi1pk-gsi1sk-index", + KeySchema: [ + { + AttributeName: "gsi1pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi1sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + { + IndexName: "gsi2pk-gsi2sk-index", + KeySchema: [ + { + AttributeName: "gsi2pk", + KeyType: "HASH", + }, + { + AttributeName: "gsi2sk", + KeyType: "RANGE", + }, + ], + Projection: { + ProjectionType: "ALL", + }, + }, + ], + BillingMode: "PAY_PER_REQUEST", +}; diff --git a/www/src/pages/en/core-concepts/executing-queries.mdx b/www/src/pages/en/core-concepts/executing-queries.mdx index 26e37d5a..c2018fbc 100644 --- a/www/src/pages/en/core-concepts/executing-queries.mdx +++ b/www/src/pages/en/core-concepts/executing-queries.mdx @@ -14,6 +14,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; @@ -74,35 +75,7 @@ The `params` method _ends_ a query chain, and synchronously formats your query i #### Example -```typescript -const params = MallStores.query - .leases({ mallId }) - .between({ leaseEndDate: "2020-06-01" }, { leaseEndDate: "2020-07-31" }) - .where(({ rent }, { lte }) => lte(rent, "5000.00")) - .params(); -``` - -#### Output - -```json -{ - "IndexName": "idx2", - "TableName": "electro", - "ExpressionAttributeNames": { - "#rent": "rent", - "#pk": "idx2pk", - "#sk1": "idx2sk" - }, - "ExpressionAttributeValues": { - ":rent1": "5000.00", - ":pk": "$mallstoredirectory_1#mallid_eastpointe", - ":sk1": "$mallstore#leaseenddate_2020-06-01#rent_", - ":sk2": "$mallstore#leaseenddate_2020-07-31#rent_" - }, - "KeyConditionExpression": "#pk = :pk and #sk1 BETWEEN :sk1 AND :sk2", - "FilterExpression": "#rent <= :rent1" -} -``` + ### Go @@ -112,13 +85,7 @@ The `go` method _ends_ a query chain, and asynchronously queries DynamoDB with t #### Example -```typescript -const results = await MallStores.query - .leases({ mallId }) - .between({ leaseEndDate: "2020-06-01" }, { leaseEndDate: "2020-07-31" }) - .where(({ rent }, { lte }) => lte(rent, "5000.00")) - .go(); -``` + #### Output diff --git a/www/src/pages/en/core-concepts/introduction.mdx b/www/src/pages/en/core-concepts/introduction.mdx index 8b92c19d..e8cd066f 100644 --- a/www/src/pages/en/core-concepts/introduction.mdx +++ b/www/src/pages/en/core-concepts/introduction.mdx @@ -11,64 +11,13 @@ layout: ../../../layouts/IntroductionLayout.astro import Stats from "../../../components/PageContent/Stats.astro"; import Features from "../../../components/PageContent/Features.astro"; -import Comparison from "../../../components/PageContent/Comparison.astro"; +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; - +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. - - -```typescript -const { data } = await tasks - .patch({ - team: "core", - task: "45-662", - project: "backend", - }) - .set({ status: "open" }) - .add({ points: 5 }) - .append({ - comments: [{ user: "janet", body: "This seems half-baked." }], - }) - .where(({ status }, { eq }) => eq(status, "in-progress")) - .go(); -``` - - - - - -```json -{ - "UpdateExpression": "SET #status = :status_u0, #points = #points + :points_u0, #comments = list_append(#comments, :comments_u0), #updatedAt = :updatedAt_u0, #gsi1sk = :gsi1sk_u0", - "ExpressionAttributeNames": { - "#status": "status", - "#points": "points", - "#comments": "comments", - "#updatedAt": "updatedAt", - "#gsi1sk": "gsi1sk" - }, - "ExpressionAttributeValues": { - ":status0": "in-progress", - ":status_u0": "open", - ":points_u0": 5, - ":comments_u0": [{ "user": "janet", "body": "This seems half-baked." }], - ":updatedAt_u0": 1630977029015, - ":gsi1sk_u0": "$assignments#tasks_1#status_open" - }, - "TableName": "your_table_name", - "Key": { - "pk": "$taskapp#team_core", - "sk": "$tasks_1#project_backend#task_45-662" - }, - "ConditionExpression": "attribute_exists(pk) AND attribute_exists(sk) AND #status = :status0" -} -``` - - - - + The snippet above updates a task — partially, conditionally, and with a new comment appended. ElectroDB resolves the composite keys, builds the update expression, and applies the condition. You write intent; it writes parameters. Try this exact example in the Playground → diff --git a/www/src/pages/en/core-concepts/quick-start.mdx b/www/src/pages/en/core-concepts/quick-start.mdx index fc99efdd..837d2c7f 100644 --- a/www/src/pages/en/core-concepts/quick-start.mdx +++ b/www/src/pages/en/core-concepts/quick-start.mdx @@ -11,6 +11,7 @@ layout: ../../../layouts/MainLayout.astro --- import PackageInstall from "../../../components/PageContent/PackageInstall"; +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; ## Getting Started @@ -220,55 +221,20 @@ const Book = new Entity( ### Create Book -```typescript -await Book.create({ - bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", - storeId: "pdx-45", - author: "Stephen King", - title: "IT", - condition: "GOOD", - price: 15, - genre: ["HORROR", "THRILLER"], - published: "1986-09-15", -}).go(); -``` + ### Update Book -```typescript -await Book.patch({ - bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", - storeId: "pdx-45", -}) - .set({ - price: 10, - condition: "FAIR", - }) - .go(); -``` + ### Get Book -```typescript -const book = await Book.get({ - bookId: "beedabe8-e34e-4d41-9272-0755be9a2a9f", - storeId: "pdx-45", -}).go(); -``` + ### Get Books by Author -```typescript -const { data, cursor } = await Book.query - .byAuthor({ author: "Stephen King" }) - .go(); -``` + ### Get (Cheap) Books by Store Location -```typescript -const { data, cursor } = await Book.query - .byLocation({ storeId: "pdx-45" }) - .where(({ price }, { lte }) => lte(price, 10)) - .go(); -``` + diff --git a/www/src/pages/en/examples/shopping-mall-directory.mdx b/www/src/pages/en/examples/shopping-mall-directory.mdx index a20ae201..b7bf8e54 100644 --- a/www/src/pages/en/examples/shopping-mall-directory.mdx +++ b/www/src/pages/en/examples/shopping-mall-directory.mdx @@ -14,6 +14,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Let's look at the needs of application used to manage Shopping Mall properties. The application assists employees in the day-to-day operations of multiple Shopping Malls. ## Requirements @@ -22,44 +24,13 @@ Let's look at the needs of application used to manage Shopping Mall properties. 2. As a Helpdesk Employee, I need to locate related stores in Mall locations by Store Category. 3. As a Property Manager, I need to identify upcoming leases in need of renewal. -## Example Setup - -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +> Each example below is self-contained: the **Entity** and **Table Definition** tabs show the setup that example runs against, and the generated parameters are produced live by executing the example. ## Mutations ### Add a new Store to the Mall -```typescript -await StoreLocations.create({ - mallId: "EastPointe", - storeId: "LatteLarrys", - buildingId: "BuildingA1", - unitId: "B47", - category: "spite store", - leaseEndDate: "2020-02-29", - rent: "5000.00", -}).go(); -``` - -Returns the following: - -```json -{ - "data": { - "mallId": "EastPointe", - "storeId": "LatteLarrys", - "buildingId": "BuildingA1", - "unitId": "B47", - "category": "spite store", - "leaseEndDate": "2020-02-29", - "rent": "5000.00", - "discount": "0.00" - } -} -``` + --- @@ -67,76 +38,19 @@ Returns the following: When updating a record, you must include all **Composite Attributes** associated with the table's _primary_ **PK** and **SK**. -```typescript -let storeId = "LatteLarrys"; -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; -let unitId = "B47"; - -await StoreLocations.patch({ storeId, mallId, buildingId, unitId }) - .set({ leaseEndDate: "2021-02-28" }) - .go(); -``` - -Returns the following: - -```json -{ - "data": { - "leaseEndDate": "2021-02-28" - } -} -``` + ### Retrieve a specific Store in a Mall When retrieving a specific record, you must include all **Composite Attributes** associated with the table's _primary_ **PK** and **SK**. -```typescript -let storeId = "LatteLarrys"; -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; -let unitId = "B47"; - -await StoreLocations.get({ storeId, mallId, buildingId, unitId }).go(); -``` - -Returns the following: - -```json -{ - "data": { - "mallId": "EastPointe", - "storeId": "LatteLarrys", - "buildingId": "BuildingA1", - "unitId": "B47", - "category": "spite store", - "leaseEndDate": "2021-02-28", - "rent": "5000.00", - "discount": "0.00" - } -} -``` + #### Remove a Store location from the Mall When removing a specific record, you must include all **Composite Attributes** associated with the table's _primary_ **PK** and **SK**. -```typescript -let storeId = "LatteLarrys"; -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; -let unitId = "B47"; -let storeId = "LatteLarrys"; - -await StoreLocations.delete({ storeId, mallId, buildingId, unitId }).go(); -``` - -Returns the following: - -```json -{ "data": {} } -``` + ## Queries @@ -144,106 +58,44 @@ Returns the following: Fulfilling [Requirement #1](#shopping-mall-requirements). -```typescript -let mallId = "EastPointe"; - -let stores = await StoreLocations.query.units({ mallId }).go(); -``` + ### All Stores in a particular mall building Fulfilling [Requirement #1](#shopping-mall-requirements). -```typescript -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; - -let stores = await StoreLocations.query.units({ mallId, buildingId }).go(); -``` + ### Find the store located in unit B47 Fulfilling [Requirement #1](#shopping-mall-requirements). -```typescript -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; -let unitId = "B47"; - -let stores = await StoreLocations.query - .units({ mallId, buildingId, unitId }) - .go(); -``` + ### Stores by Category at Mall Fulfilling [Requirement #2](#shopping-mall-requirements). -```typescript -let mallId = "EastPointe"; -let category = "food/coffee"; - -let stores = await StoreLocations.query - .units({ mallId }) - .where((attr, op) => op.eq(attr.category, category)) - .go(); -``` + ### Stores by upcoming lease Fulfilling [Requirement #3](#shopping-mall-requirements). -```typescript -let storeId = "LatteLarrys"; -let q2StartDate = "2020-04-01"; - -let stores = await StoreLocations.query - .leases({ storeId }) - .lt({ leaseEndDate: q2StartDate }) - .go(); -``` + ### Stores will renewals for Q4 Fulfilling [Requirement #3](#shopping-mall-requirements). -```typescript -let storeId = "LatteLarrys"; -let q4StartDate = "2020-10-01"; -let q4EndDate = "2020-12-31"; - -let stores = await StoreLocations.query - .leases({ storeId }) - .between({ leaseEndDate: q4StartDate }, { leaseEndDate: q4EndDate }) - .go(); -``` + ### Spite-stores with release renewals this year Fulfilling [Requirement #3](#shopping-mall-requirements). -```typescript -let storeId = "LatteLarrys"; -let yearStarDate = "2020-01-01"; -let yearEndDate = "2020-12-31"; -let storeId = "LatteLarrys"; - -let stores = await StoreLocations.query - .leases({ storeId }) - .between({ leaseEndDate: yearStarDate }, { leaseEndDate: yearEndDate }) - .where((attr, op) => op.eq(attr.category, "Spite Store")) - .go(); -``` + ### All Latte Larry's in a particular mall building -```typescript -let mallId = "EastPointe"; -let buildingId = "BuildingA1"; -let unitId = "B47"; -let storeId = "LatteLarrys"; - -let stores = await StoreLocations.query - .units({ mallId, buildingId, storeId }) - .go(); -``` + diff --git a/www/src/pages/en/examples/task-manager.mdx b/www/src/pages/en/examples/task-manager.mdx index 315d21bc..ab77c8d3 100644 --- a/www/src/pages/en/examples/task-manager.mdx +++ b/www/src/pages/en/examples/task-manager.mdx @@ -14,6 +14,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + In this example we will be modeling a task manager app. The app will associate employees to tasks, projects, and teams ## Table Definition @@ -363,67 +365,28 @@ export const taskManager = new Service({ Use Collections to query across entities. -```typescript -const workplace = await taskManager.collections - .workplaces({ office: "portland" }) - .go(); -``` + ### Get employee details and all assigned -```typescript -const { data, cursor } = await taskManager.collections - .assignments({ employee: "tyler.walch" }) - .go(); -``` + ### Find Junior Developers making more than 100,000 Use Entity queries to drill into specific entities. -```typescript -const title = "Junior Software Engineer"; -const salary = "100000"; - -const developers = await taskManager.entities.employee.query - .roles({ title }) - .gt({ salary }) - .go(); -``` + ### Find all open tasks for a given project less than or equal to 13 points -```typescript -const status = "open"; -const project = "135-53"; - -const tasks = await taskManager.entities.task.query - .statuses({ status, project }) - .where(({ points }, { lte }) => lte(points, 13)) - .go(); -``` + ### Find marketing team members who were hired in between two and five years ago: -```typescript -const team = "marketing"; -const twoYearsAgo = moment.utc().subtract(2, "years").format("YYYY-MM-DD"); -const fiveYearsAgo = moment.utc().subtract(5, "years").format("YYYY-MM-DD"); - -const recentHires = await taskManager.entities.employee.query - .teams({ team }) - .between({ dateHired: fiveYearsAgo }, { dateHired: twoYearsAgo }) - .go(); -``` + ### Create New Task The type `CreateEntityItem` is exported to help you type items as they are used for creation -```typescript -type CreateTaskItem = CreateEntityItem; - -function createNewTask(item: CreateTaskItem) { - return taskManager.entities.task.put(item).go(); -} -``` + diff --git a/www/src/pages/en/modeling/collections.mdx b/www/src/pages/en/modeling/collections.mdx index 6afaacdf..ee8bc631 100644 --- a/www/src/pages/en/modeling/collections.mdx +++ b/www/src/pages/en/modeling/collections.mdx @@ -14,6 +14,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + ## Overview A Collection is a grouping of Entities with the same Partition Key and allows you to make an efficient query across multiple entities. If your background is SQL, imagine Partition Keys as Foreign Keys, a Collection represents a View with multiple joined Entities. @@ -137,20 +139,9 @@ const Task = new Entity({ ### Example -```typescript -import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; -import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; - -const table = "projectmanagement"; -const client = DynamoDBDocumentClient.from(new DynamoDBClient({})); +> The **Entities** and **Service** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -const TaskApp = new Service({ - employee: Employee, - task: Task, -}); - -await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); -``` + ### Response Format @@ -164,23 +155,6 @@ await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); } ``` -### Equivalent Parameters - -```json -{ - "TableName": "projectmanagement", - "ExpressionAttributeNames": { "#pk": "gsi2pk", "#sk1": "gsi2sk" }, - "ExpressionAttributeValues": { - ":pk": "$taskapp_1#employeeid_joeexotic", - ":sk1": "$assignments" - }, - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "IndexName": "gsi2" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbzgUQHY2DAngGjgZQFMoA3YAY0LgF84AzKCEOAIkIBtDyZGATAIxYBuAFAjyEVAGd4MAIb9OcALyswjAFZcYIOajkBzQiELphYidPjGw7CFkKEpKuKkIB3FOkxYAFAhE4OBAIXg4ALkRAoLhTDGxItnA7BycWHGigkmIpYElEgEZ0zLgpYjJKRPkpAGs5MDBioOoMoLkYHmB+AFcYJ0iAmNjk+0cASV4BkqDsMEJEmShgVAMWEpaS6AM9YAAvdrzUCamhmaw5hc6VtaGNof0TE9PZ+dZF5dX11pi+uRAnoYvSIAbRYGm6YEwxHSrBMUHI3SgWBhLCk7URqBYAF11tE7nBlmEAB79KJDGRyOh0AExMA1GlDOjADiTNQ1JqnIIScAQXJ9EEsLY7fYYSQTbHTGjfcn0smc+jM9is1Hs6WnbmQPmvUE2FLjXgSznUL4lXWjV6DdUQdicbiHRJyKS5AyoEzoKQcoaEwhExIGXIAJk9tNlls5TJZfsDdODQw1vKhArNqXFWLVzXTpVDkqCEaVUeAAdqsZi8a1ILTkvxzTxIhaiDg8kUVGoAEoLJIZI3HTVnKo3J40PE-JaQmF2DS4j4qj2PWrslBcvlWEU1WVSBRXixqnUGhz8e1Oj0+lIaTvjnLAect+9riahsn9QzG9fLks77c1eoIFpuBewz8r5vFcnyfiU8ScM+QLAe+oExNWcD8KEWBQUBqIgTc8F4t83okqel5wN+v4wM+dLPrmirKjGmZckwmqJnAoJEdoqZVpmtTkQqkZvKqOZwGWDGgueBo4ka94xI6zpuKyAG0Ta2j2qwknAC6bowHOkq4QWQaZmRBGMpR2nUXxAn8oxSS2OaqaZghQQcfpMR5sq-qFsWNH8XRCZmUxmgsSJNlqsaNb1kgTZKG2ojiJ2sg9vUYAuAOBDlJu-iPk4eA7lIEViDucUAHQSPJdqdiIACQeXKapcRSKlIwpsqABSyBEhAGDkCwbZlXlBgQL4rZCEAA) - ## Collection Queries vs Entity Queries To query across entities, collection queries make use of ElectroDB's Sort Key structure, which prefixes Sort Key fields with the collection name. Unlike an Entity Query, Collection queries for [isolated indexes](/en/modeling/indexes#isolated-indexes) only leverage [Composite Attributes](/en/modeling/indexes#composite-attribute-arrays) from an access pattern's Partition Key, while Collection queries for [clustered indexes](/en/modeling/indexes#clustered-indexes) allow you to query on both Partition and Sort Keys. @@ -191,54 +165,13 @@ To better explain how Collection Queries are formed, here is a juxtaposition of #### Example -```typescript -await TaskApp.entities.task.query.assigned({ employeeId: "JExotic" }).go(); -``` - -#### Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "projectmanagement", - "ExpressionAttributeNames": { - "#pk": "gsi2pk", - "#sk1": "gsi2sk" - }, - "ExpressionAttributeValues": { - ":pk": "$taskapp#employeeid_jexotic", - ":sk1": "$assignments#tasks_1" - }, - "IndexName": "gsi2" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbzgUQHY2DAngGjgZQFMoA3YAY0LgF84AzKCEOAIkIBtDyZGATAIxYBuAFAjyEVAGd4MAIb9OcALyswjAFZcYIOajkBzQiELphYidPjGw7CFkKEpKuKkIB3FOkxYAFAhE4OBAIXg4ALkRAoLhTDGxItnA7BycWHGigkmIpYElEgEZ0zLgpYjJKRPkpAGs5MDBioOoMoLkYHmB+AFcYJ0iAmNjk+0cASV4BkqDsMEJEmShgVAMWEpaS6AM9YAAvdrzUCamhmaw5hc6VtaGNof0TE9PZ+dZF5dX11pi+uRAnoYvSIAbRYGm6YEwxHSrBMUHI3SgWBhLCk7URqBYAF11tE7nBlmEAB79KJDGRyOh0AExMA1GlDOjADiTNQ1JqnIIScAQXJ9EEsLY7fYYSQTbHTGjfcn0smc+jM9is1Hs6WnbmQPmvUE2FLjXgSznUL4lXWjV6DdUQdicbiHRJyKS5AyoEzoKQcoaEwhExIGXIAJk9tNlls5TJZfsDdODQw1vKhArNqXFWLVzXTpVDkqCEaVUeAAdqsZi8a1ILTkvxzTxIhaiDg8kUVGoAEoLJIZI3HTVnKo3J40PE-JaQmF2DS4j4qj2PWrslBcvlWEU1WVSBRXixqnUGhz8e1Oj0+lIaTvjnLAect+9riahsn9QzG9fLks77c1eoIFpuBewz8r5vFcnyfiU8ScM+QLAe+oExNWcD8KEWBQUBqIgTc8F4t83okqel5wN+v4wM+dLPrmirKjGmZckwmqJnAoJEdoqZVpmtTkQqkZvKqOZwGWDGgueBo4ka94xI6zpuKyAG0Ta2j2qwknAC6bowHOkq4QWQaZmRBGMpR2nUXxAn8oxSS2OaqaZghQQcfpMR5sq-qFsWNH8XRCZmUxmgsSJNlqsaNb1kgTZKG2ojiJ2sg9vUYAuAOBDlJu-iPk4eA7lIEViDucUAHRThgTjRHlmV5QAjt0xBYCIACQeXKS6hC8KlIwpsqABSyBEhAGDkCwbZ1XlBgQL4rZCEAA) + ### Collection Query #### Example -```typescript -await TaskApp.collections.assignments({ employeeId: "JExotic" }).go(); -``` - -#### Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "projectmanagement", - "ExpressionAttributeNames": { "#pk": "gsi2pk", "#sk1": "gsi2sk" }, - "ExpressionAttributeValues": { - ":pk": "$taskapp#employeeid_jexotic", - ":sk1": "$assignments" - }, - "IndexName": "gsi2" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbzgUQHY2DAngGjgZQFMoA3YAY0LgF84AzKCEOAIkIBtDyZGATAIxYBuAFAjyEVAGd4MAIb9OcALyswjAFZcYIOajkBzQiELphYidPjGw7CFkKEpKuKkIB3FOkxYAFAhE4OBAIXg4ALkRAoLhTDGxItnA7BycWHGigkmIpYElEgEZ0zLgpYjJKRPkpAGs5MDBioOoMoLkYHmB+AFcYJ0iAmNjk+0cASV4BkqDsMEJEmShgVAMWEpaS6AM9YAAvdrzUCamhmaw5hc6VtaGNof0TE9PZ+dZF5dX11pi+uRAnoYvSIAbRYGm6YEwxHSrBMUHI3SgWBhLCk7URqBYAF11tE7nBlmEAB79KJDGRyOh0AExMA1GlDOjADiTNQ1JqnIIScAQXJ9EEsLY7fYYSQTbHTGjfcn0smc+jM9is1Hs6WnbmQPmvUE2FLjXgSznUL4lXWjV6DdUQdicbiHRJyKS5AyoEzoKQcoaEwhExIGXIAJk9tNlls5TJZfsDdODQw1vKhArNqXFWLVzXTpVDkqCEaVUeAAdqsZi8a1ILTkvxzTxIhaiDg8kUVGoAEoLJIZI3HTVnKo3J40PE-JaQmF2DS4j4qj2PWrslBcvlWEU1WVSBRXixqnUGhz8e1Oj0+lIaTvjnLAect+9riahsn9QzG9fLks77c1eoIFpuBewz8r5vFcnyfiU8ScM+QLAe+oExNWcD8KEWBQUBqIgTc8F4t83okqel5wN+v4wM+dLPrmirKjGmZckwmqJnAoJEdoqZVpmtTkQqkZvKqOZwGWDGgueBo4ka94xI6zpuKyAG0Ta2j2qwknAC6bowHOkq4QWQaZmRBGMpR2nUXxAn8oxSS2OaqaZghQQcfpMR5sq-qFsWNH8XRCZmUxmgsSJNlqsaNb1kgTZKG2ojiJ2sg9vUYAuAOBDlJu-iPk4eA7lIEViDucUAHQSPJdqdiIACQeXKapcRSKlIwpsqABSyBEhAGDkCwbZlXlBgQL4rZCEAA) + The notable difference between the two is how much of the Sort Key is specified at query time. @@ -266,11 +199,7 @@ For example, using the "TaskApp" models defined [above](#entities), we would exp ### Example -```typescript -const results = await TaskApp.collections - .assignments({ employeeId: "JExotic" }) - .go(); -``` + ### Response Format @@ -284,21 +213,6 @@ const results = await TaskApp.collections } ``` -### Equivalent Parameters - -```json -{ - "TableName": "projectmanagement", - "ExpressionAttributeNames": { "#pk": "gsi2pk", "#sk1": "gsi2sk" }, - "ExpressionAttributeValues": { - ":pk": "$taskapp_1#employeeid_joeexotic", - ":sk1": "$assignments" - }, - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "IndexName": "gsi2" -} -``` - Because the Tasks and Employee Entities both associated their index (`gsi2`) with the same collection name (`assignments`), ElectroDB is able to associate the two entities via a shared Partition Key. As stated in the [collections section](#collections), querying across Entities by PK can be comparable to querying across a foreign key in a traditional relational database. ## Sub-Collections @@ -343,11 +257,7 @@ The following is an example of functionally identical collections, implemented a Both implementations above will create a "collections" method called `assignments` when added to a Service. -```typescript -const results = await TaskApp.collections - .assignments({ employeeId: "JExotic" }) - .go(); -``` + The advantage to using a string array to define collections is the ability to express sub-collections. Below is an example of three entities using sub-collections, followed by an explanation of their sub-collection definitions: @@ -525,8 +435,6 @@ const TaskApp = new Service( ); ``` -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoMhBQBneDACGvdnAC8zMPQBWHGCEkpJAcwIgCaJgG4BQkeLh6wrCJgIFR8uCgIB3OKnRYAFAgFw4EAhuNgAuRH8AyzQMTHCWcBs7ByZsSIDiIlFgEXiARlT0uFEiUgp4qVEAa0kwMEKAyjSAyRguYF4AVxgHcL8oy0TbewBJbj6igKwwAnjxKGAUbUEBpqLobU1gAC9WnJQxiYGpzBm59qWVqLWBrX0j4+nZ5nnF5aKbqJ7JEAeBp-CAG1JlEmMpOmAMERUnAQQEmPooGROlBMDC4S9WiiUFcBgBdOCSRzCMQwD6RT6LEIAD16EQG4kkNBofyiYCqrIGNGAbHGiiqDWOAWE4Ag2R6QKYGy2u3QIjGTDxIM+DI59KFtB5rD5TGqgqFIsg4uegIS1mGBAVSqFlA+zSiViS9k5cGErHYnH28RJ7S6crE+qiVII1Pi2myACZAwF2S6AtzeWHI+zo1FDWKoZLHRarfbVnmotU45rE8xw8AI3qCwN08agXjq3AVU2KQImog4FIZAQmwBKUwkiyVKqOBQudyeWK+SJBEKsVkGLxxZjD0SBzJQbK5ZgFAslEjkZ5MYe1er2z6tX3dOn9L5EqqHdX-U5H16XO1FbPJR+359nF4XO8+ZFEoECqJwP4ggCAELO+wH-Bg7AutBuqAbiTYFrwwTLr+XwvucsFAdcFL2sGtKiKyoHgTALpuh6-rxBAG6kG4qaxk+xwJtq8Qpo2woMEamZwKaVFqFayqNkWHFclqOpVhitZCaaw7iTaH4DES2TaC4fK4fx7pqF6wkYkwPoLH6+xrrgJmacA2n6Gga4ggSRKuuYMCNmRSYVmxap6VEXE6uWEa8QpAkZhKwlmk6lrcIqjbNgEUn+fGsneZWAp8W5op1lFokQXFDYSeSjRtrgCCdtIsiUL2JhmKScD5TAACyei8FkTjjh4MQ+Les5hBxi6xDxKhqK1IDtZu65ZEZTC7kU+5lEeJ51IKF5tOZ14UYNQzfrpUH4TBbzoc2TWQUKKFvkRjQFnczz+ZdaHqRhkRkTeRT6BNWS0RABmetuUrMTyri+cWgU8ZlYU5UpTBnYVxVCslGLgy8kMatlgmRaaX6jPDanwWyo2cNt-l0YZ27AujpkiFe-pWbCVO2fZi5OUKLnEu5nkoDS6Wg9JAVpWWyZoxqilY9FOaFQlkl+cjgtMMF8no2LJpFTaBa2qV7YVV21W1bC9UWAAKveACCdSdW4+ClIevg4w4uCrrgTXjZNog1SYg7wPbYxOMeriSKwZAABbGKYJvVObYAAHRk-9YiRLHNObXTdu7bjNWJ9oEDeP2ATRzAwcGN43CtJI8gAHwcQA9NXbloCnlluX9-pwFABAwNijjt6InSsDAohFLXtD0Iwhc9jQv02K4bzRF4PIUUUXuIPbojO0TLVtVkjv3u7Til1IJiNP2AgR1UUdJy3lmJ0zKAOQPafmntmf59nueJ+PKAl2Xlc13XZkdG6E3OOrd26dygGINuDg+4DyHnXOgDBOxF1oFPCAM8lhzwwAvUIS93KIBdlvTcO9qh7wUAfSQR8+wmCAA) - > TypeScript Note: Use `as const` syntax when defining `collection` as a string array for improved type support. The last code block above creates a Service called `TaskApp` using the Entity instances created above its declaration. By creating a Service, ElectroDB will identify and validate the sub-collections defined across all three models. The result in this case are three unique collections: "overview", "contributions", and "assignments". @@ -537,12 +445,7 @@ The simplest collection to understand is `overview`. This collection is defined #### Example -```typescript -// overview -const results = await TaskApp.collections - .overview({ projectId: "SD-204" }) - .go(); -``` + #### Response Format @@ -556,22 +459,6 @@ const results = await TaskApp.collections } ``` -#### Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "projectmanagement", - "ExpressionAttributeNames": { "#pk": "pk", "#sk1": "sk" }, - "ExpressionAttributeValues": { - ":pk": "$taskapp#projectid_sd-204", - ":sk1": "$overview" - } -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoMhBQBneDACGvdnAC8zMPQBWHGCEkpJAcwIgCaJgG4BQkeLh6wrCJgIFR8uCgIB3OKnRYAFAgFw4EAhuNgAuRH8AyzQMTHCWcBs7ByZsSIDiIlFgEXiARlT0uFEiUgp4qVEAa0kwMEKAyjSAyRguYF4AVxgHcL8oy0TbewBJbj6igKwwAnjxKGAUbUEBpqLobU1gAC9WnJQxiYGpzBm59qWVqLWBrX0j4+nZ5nnF5aKbqJ7JEAeBp-CAG1JlEmMpOmAMERUnAQQEmPooGROlBMDC4S9WiiUFcBgBdOCSRzCMQwD6RT6LEIAD16EQG4kkNBofyiYCqrIGNGAbHGiiqDWOAWE4Ag2R6QKYGy2u3QIjGTDxIM+DI59KFtB5rD5TGqgqFIsg4uegIS1mGBAVSqFlA+zSiViS9k5cGErHYnH28RJ7S6crE+qiVII1Pi2myACZAwF2S6AtzeWHI+zo1FDWKoZLHRarfbVnmotU45rE8xw8AI3qCwN08agXjq3AVU2KQImog4FIZAQmwBKUwkiyVKqOBQudyeWK+SJBEKsVkGLxxZjD0SBzJQbK5ZgFAslEjkZ5MYe1er2z6tX3dOn9L5EqqHdX-U5H16XO1FbPJR+359nF4XO8+ZFEoECqJwP4ggCAELO+wH-Bg7AutBuqAbiTYFrwwTLr+XwvucsFAdcFL2sGtKiKyoHgTALpuh6-rxBAG6kG4qaxk+xwJtq8Qpo2woMEamZwKaVFqFayqNkWHFclqOpVhitZCaaw7iTaH4DES2TaC4fK4fx7pqF6wkYkwPoLH6+xrrgJmacA2n6Gga4ggSRKuuYMCNmRSYVmxap6VEXE6uWEa8QpAkZhKwlmk6lrcIqjbNgEUn+fGsneZWAp8W5op1lFokQXFDYSeSjRtrgCCdtIsiUL2JhmKScD5TAACyei8FkTjjh4MQ+Les5hBxi6xDxKhqK1IDtZu65ZEZTC7kU+5lEeJ51IKF5tOZ14UYNQzfrpUH4TBbzoc2TWQUKKFvkRjQFnczz+ZdaHqRhkRkTeRT6BNWS0RABmetuUrMTyri+cWgU8ZlYU5UpTBnYVxVCslGLgy8kMatlgmRaaX6jPDanwWyo2cNt-l0YZ27AujpkiFe-pWbCVO2fZi5OUKLnEu5nkoDS6Wg9JAVpWWyZoxqilY9FOaFQlkl+cjgtMMF8no2LJpFTaBa2qV7YVV21W1bC9UWAAKveACCdSdW4+ClIevg4w4uCrrgTXjZNog1XVJvVObYAAHRk-9YhFL7TE224vhw-EeAACIALQRgADAALEwNXB9oEDeLVQA) - ### Complex Collections Unlike `overview`, the collections `contributions` and `assignments` are more complex. @@ -582,12 +469,7 @@ In the case of `contributions`, _all three_ entities implement this collection o #### Example -```typescript -// contributions -const results = await TaskApp.collections - .contributions({ employeeId: "JExotic" }) - .go(); -``` + #### Response Format @@ -602,23 +484,6 @@ const results = await TaskApp.collections } ``` -#### Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "projectmanagement", - "ExpressionAttributeNames": { "#pk": "gsi2pk", "#sk1": "gsi2sk" }, - "ExpressionAttributeValues": { - ":pk": "$taskapp#employeeid_jexotic", - ":sk1": "$contributions" - }, - "IndexName": "gsi2" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?ssl=158&ssc=9&pln=157&pc=1#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoMhBQBneDACGvdnAC8zMPQBWHGCEkpJAcwIgCaJgG4BQkeLh6wrCJgIFR8uCgIB3OKnRYAFAgFw4EAhuNgAuRH8AyzQMTHCWcBs7ByZsSIDiIlFgEXiARlT0uFEiUgp4qVEAa0kwMEKAyjSAyRguYF4AVxgHcL8oy0TbewBJbj6igKwwAnjxKGAUbUEBpqLobU1gAC9WnJQxiYGpzBm59qWVqLWBrX0j4+nZ5nnF5aKbqJ7JEAeBp-CAG1JlEmMpOmAMERUnAQQEmPooGROlBMDC4S9WiiUFcBgBdOCSRzCMQwD6RT6LEIAD16EQG4kkNBofyiYCqrIGNGAbHGiiqDWOAWE4Ag2R6QKYGy2u3QIjGTDxIM+DI59KFtB5rD5TGqgqFIsg4uegIS1mGBAVSqFlA+zSiViS9k5cGErHYnH28RJ7S6crE+qiVII1Pi2myACZAwF2S6AtzeWHI+zo1FDWKoZLHRarfbVnmotU45rE8xw8AI3qCwN08agXjq3AVU2KQImog4FIZAQmwBKUwkiyVKqOBQudyeWK+SJBEKsVkGLxxZjD0SBzJQbK5ZgFAslEjkZ5MYe1er2z6tX3dOn9L5EqqHdX-U5H16XO1FbPJR+359nF4XO8+ZFEoECqJwP4ggCAELO+wH-Bg7AutBuqAbiTYFrwwTLr+XwvucsFAdcFL2sGtKiKyoHgTALpuh6-rxBAG6kG4qaxk+xwJtq8Qpo2woMEamZwKaVFqFayqNkWHFclqOpVhitZCaaw7iTaH4DES2TaC4fK4fx7pqF6wkYkwPoLH6+xrrgJmacA2n6Gga4ggSRKuuYMCNmRSYVmxap6VEXE6uWEa8QpAkZhKwlmk6lrcIqjbNgEUn+fGsneZWAp8W5op1lFokQXFDYSeSjRtrgCCdtIsiUL2JhmKScD5TAACyei8FkTjjh4MQ+Les5hBxi6xDxKhqK1IDtZu65ZEZTC7kU+5lEeJ51IKF5tOZ14UYNQzfrpUH4TBbzoc2TWQUKKFvkRjQFnczz+ZdaHqRhkRkTeRT6BNWS0RABmetuUrMTyri+cWgU8ZlYU5UpTBnYVxVCslGLgy8kMatlgmRaaX6jPDanwWyo2cNt-l0YZ27AujpkiFe-pWbCVO2fZi5OUKLnEu5nkoDS6Wg9JAVpWWyZoxqilY9FOaFQlkl+cjgtMMF8no2LJpFTaBa2qV7YVV21W1bC9UWAAKveACCdSdW4+ClIevg4w4uCrrgTXjZNog1XVJvVObYAAHRk-9YiRP7NObXTdu7bj8QAFJINSEDoGQTA1cH2gQN4tVAA) - ### Complex Collections (Continued) This collection contains only the entities that share the second collection element. diff --git a/www/src/pages/en/modeling/indexes.mdx b/www/src/pages/en/modeling/indexes.mdx index 914dd047..6389ef36 100644 --- a/www/src/pages/en/modeling/indexes.mdx +++ b/www/src/pages/en/modeling/indexes.mdx @@ -14,6 +14,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + When using ElectroDB, indexes are referenced by their `AccessPatternName`. This allows you to maintain generic index names on your DynamoDB table, but reference domain specific names while using your ElectroDB Entity. These will be referenced as _"Access Patterns"_. All DynamoDB tables start with at least a PartitionKey with an optional SortKey, this can be referred to as the _"Table Index"_. The `indexes` object requires at least the definition of this _Table Index_ **Partition Key** and (if applicable) **Sort Key**. @@ -529,75 +531,15 @@ Without the use of `scope`, both entities would share the same partition key and Without a `scope` value, notice the partition key value at ExpressionAttributeValues[':pk'] is the same for both queries. This occurs when composite attribute array for a partition key matches between entities. Keep in mind that, in most cases, this is desirable because it helps enable querying across entities via [collections](/en/modeling/collections). However, in some cases, this may not be desirable which is why the `scope` property exists. -```typescript -organization.query.myIndex({organizationId: '123'}).go(); -// { -// "KeyConditionExpression": "#pk = :pk and #sk1 = :sk1", -// "TableName": "your_table_name", -// "ExpressionAttributeNames": { -// "#pk": "pk", -// "#sk1": "sk" -// }, -// "ExpressionAttributeValues": { -// ":pk": "$taskapp", -// ":sk1": "$organization_1#organizationid_org123" -// } -// } -``` +> The **Entities** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -```typescript -user.query.myIndex({userId: '456'}).go(); -// { -// "KeyConditionExpression": "#pk = :pk and #sk1 = :sk1", -// "TableName": "your_table_name", -// "ExpressionAttributeNames": { -// "#pk": "pk", -// "#sk1": "sk" -// }, -// "ExpressionAttributeValues": { -// ":pk": "$taskapp", -// ":sk1": "$organization_1#organizationid_org123" -// } -// } -``` + #### With Scope Notice the value at ExpressionAttributeValues[':pk'] now contains the `scope` value that was provided by the user on the index definition. -```typescript -organization.query.myIndex({organizationId: '123'}).go(); -// { -// "KeyConditionExpression": "#pk = :pk and #sk1 = :sk1", -// "TableName": "your_table_name", -// "ExpressionAttributeNames": { -// "#pk": "pk", -// "#sk1": "sk" -// }, -// "ExpressionAttributeValues": { -// ":pk": "$taskapp_org", -// ":sk1": "$organization_1#organizationid_org123" -// } -// } -``` - -```typescript -user.query.myIndex({userId: '456'}).go(); -// { -// "KeyConditionExpression": "#pk = :pk and #sk1 = :sk1", -// "TableName": "your_table_name", -// "ExpressionAttributeNames": { -// "#pk": "pk", -// "#sk1": "sk" -// }, -// "ExpressionAttributeValues": { -// ":pk": "$taskapp_user", -// ":sk1": "$organization_1#organizationid_org123" -// } -// } -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbzgUQHY2DAnnAvnAMyghDgCIBTAGwoGMZiATAIzIG4AoD2iVAZ3jQA5gENUwAF4iMvOAF44qCgHcU6TFgAUCDnDggIjagC5EuvXArrspssLGTpwXmQA05vXwpQAbsFoUtjAifADWImBgbh5wPt58zqi2AIxk5rjuetIMwMwArjAUfKY6FnD24lIyqACSjCUxethggeQCUMCoQmllGemZcJ1GAB5FDWUgWDWoI+NlcHw8LbbCbnAA9OtwADwAtPtwAMpLFIN8CxTwMBBweeIAjnmnPiJUT+SrjXBgoXPzhMBqPVyD9ov89DxwBAEoVTABtAC6Xz6-zCf3mBEBVGBZDCYPBkMgMNacLsUFElScvDqZCR-1wMQZegZGUQcGCzBotiwEDyUAA+hyaPzUCIQBQyHgAJScbi8AS3LxQeSKFRqDDYbTmAxGKjoqwarC2PJK-Gebx+AJBELhSJm2LxRIpHp4AbZDr5QrFMxlE3eOroppYZZtHJdF3MgYowYzCijb2lCyTaazH3zRYQENkP1QNabHb7XZHE5nC5XG53YCPZ6vd7Z01fH6BiyYoG2UEDf6E6GYEl0+bRspotP-VvY2x4zvzbvE+H1-2MWnIxnpDispBC1pkHl8wUiTkUEViiXS2UVRzVAB01agWEvydjw205XJDiqiQDcAA5MkAEwAZi-aVLyECBNBlDgc2vJ5b3vKZH2fHNPy-AAWABWAA2IDcClECwJlIA) + ### Attributes as Indexes @@ -714,30 +656,11 @@ When your `string` attribute is also an index key, and using key templates, you [![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbzgUQHY2DAnnAvnAMyghDgCIBTAGwoGMZiATAIzIG4AoD2iVAZ3jBUANwrpoOALxxUFAO4p0mLAAoEHOHBARG1AFyINmuGIzYDZLBACuUAPqnld1AEMQFMgBojmvhSjCwLQUFla2dn4BQRTObh7exnCiUHzAvBYAjGRGuAlwLjAMwMzWMBR8BuqJLrQ81ugAkoyVPsbYYCHkAlBCAOZkcAD0g3C8VDjdfXDt5flQFHDMEDAAFnB81mCQsBSMhNDTK8B8JgAebmA0rbmt0L0uqMAAXgVpqE0tiZozFpOo-dc8ppXO5Pl8fl0iv9solcDk8kJdKdymDNDU6ugKoYvsYwABrVE44wEYDUZrkO4PZ6vXhNLytIlwHjgCCpMoGADaZEpjxeGFpjDIAF0GcYboy+ATsYziaSqOSyOibI1BUCZczIGzOlylfUYHShWrGWVwFQCp0yGB5iTTnYACQIXUq3B2TUwG0wonisU5Di5RDTFzMGihGz2GBBmixdwDXAASk43F4AnytWV+r20kVtRgAFoACwAVgAzAAGdhJ-jwHnU-nvTMUqC9XMATjLWUTQlE4igWCMADowKU1KmMRnPKMm1S+W8mng4wPehAVAmuMM4HJMCsbPAnRn1ptLqTGBwu6YJP2AI7Wfx9xL9vd8NQ1mcC+OtftLleJ9d7ucbLYqGPfIThcchmAoXohD4bIzx7LArxvXsP0fZ8p15Gl63fe8IKg-g1D-RhsOMT9l1XDhfzTPV-0PIDdhA8gCGsKhxjgPFUAgORUFgkRz17RDbxQqjMTQ+4MLrJoJ0I4jNFI78gA) -ElectroDB will accept a `get` request like this: +ElectroDB will accept a `get` request like this (note the pre/postfix on `accountId` in the generated parameters below): -```typescript -await myEntity - .get({ - accountId: "1111-2222-3333-4444", - organizationId: "AAAA-BBBB-CCCC-DDDD", - }) - .go(); -``` +> ElectroDB defaults keys to lowercase, though this can be configured using [Index Casing](#index-casing). The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -Query DynamoDB with the following params (note the pre/postfix on `accountId`): - -> ElectroDB defaults keys to lowercase, though this can be configured using [Index Casing](#index-casing). - -```json -{ - "Key": { - "accountId": "prefix_1111-2222-3333-4444_postfix", - "organizationId": "aaaa-bbbb-cccc-dddd" - }, - "TableName": "your_table_name" -} -``` + When returned from a query, however, ElectroDB will return the following and trim the key of it's prefix and postfix: @@ -879,61 +802,25 @@ Querying a `composite` index works the same as other ElectroDB index types. You #### Basic Query -```typescript -const results = await InventoryItem.query - .location({ country: "US", region: "Georgia", city: "Atlanta" }) - .go(); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters (including the `KeyConditionExpression`) below are produced live by executing the example. -This generates a `KeyConditionExpression` like: - -``` -#country = :country AND #region = :region AND #city = :city -``` + #### Sort Key Operations -Sort key operations apply to the sk composite attributes in order. Preceding sk attributes are matched with equality, and the operation applies to the last provided attribute: +Sort key operations apply to the sk composite attributes in order. Preceding sk attributes are matched with equality, and the operation applies to the last provided attribute. Note that the pk composite attributes (`country`, `region`, and `city`) must always be fully provided to the `location` Access Pattern method itself; the `begins`, `gt`, and `between` operations below apply only to the sk composite attributes (`manufacturer`, `model`, `count`): -Begins with substring expression on 'manufacturer' (city matched with equality) +Begins with substring expression on 'manufacturer' -```typescript -await InventoryItem.query - .location({ country: "US", region: "Georgia", }) - .begins({ city: "Atlanta", manufacturer: "A" }) - .go(); -// KeyConditionExpression: -// #country = :country AND #region = :region AND #city = :city -// AND begins_with(#manufacturer, :manufacturer) -``` + -Greater than on 'count' (city and manufacturer matched with equality) +Greater than on 'count' (manufacturer and model matched with equality) -```typescript -await InventoryItem.query - .location({ country: "US", region: "Georgia" }) - .gt({ city: "Atlanta", manufacturer: "Acme", count: 100 }) - .go(); -// KeyConditionExpression: -// #country = :country AND #region = :region AND #city = :city -// AND #manufacturer = :manufacturer AND #count > :count -``` + -Between on 'count' (city and manufacturer matched with equality) +Between on 'count' (manufacturer and model matched with equality) -```typescript -await InventoryItem.query - .location({ country: "US", region: "Georgia" }) - .between( - { city: "Atlanta", manufacturer: "Acme", count: 50 }, - { city: "Atlanta", manufacturer: "Acme", count: 200 }, - ) - .go(); -// KeyConditionExpression: -// #country = :country AND #region = :region AND #city = :city -// AND #manufacturer = :manufacturer -// AND #count BETWEEN :count1 AND :count2 -``` + ### Multi-Attribute Indexes with Collections @@ -1072,24 +959,13 @@ const Warehouse = new Entity( const service = new Service({ InventoryItem, Warehouse }); ``` -Query across both entities via the shared collection -```typescript -const results = await service.collections - .inventory({ country: "US", region: "Georgia", city: "Atlanta" }) - .go(); -// results.data.InventoryItem -> InventoryItem[] -// results.data.Warehouse -> Warehouse[] -``` +Query across both entities via the shared collection. The **Entities**, **Service**, and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + Collection queries also support sort key operations -```typescript -const filtered = await service.collections - .inventory({ country: "US", region: "Georgia" }) - .begins({ city: "A" }) - .go(); -// results.data.InventoryItem -> InventoryItem[] -// results.data.Warehouse -> Warehouse[] -``` + + ### Constraints and Validations diff --git a/www/src/pages/en/mutations/batch-delete.mdx b/www/src/pages/en/mutations/batch-delete.mdx index 855002db..f563e808 100644 --- a/www/src/pages/en/mutations/batch-delete.mdx +++ b/www/src/pages/en/mutations/batch-delete.mdx @@ -14,9 +14,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; Provide all table index composite attributes in an array of objects to the `delete` method to batch delete records. @@ -33,22 +31,9 @@ If you set the [Execution Option](#execution-options) `concurrent` to `2`, Elect It is important to consider your Table's throughput considerations when setting this value. -```typescript -let unprocessed = await StoreLocations.delete([ - { - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - cityId: "LosAngeles1", - }, - { - storeId: "MochaJoes", - mallId: "EastPointe", - buildingId: "F35", - cityId: "LosAngeles1", - }, -]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Response Format @@ -58,33 +43,6 @@ let unprocessed = await StoreLocations.delete([ } ``` -## Equivalent Parameters - -```json -{ - "RequestItems": { - "StoreDirectory": [ - { - "DeleteRequest": { - "Key": { - "pk": "$mallstoredirectory#cityid_losangeles1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - } - } - }, - { - "DeleteRequest": { - "Key": { - "pk": "$mallstoredirectory#cityid_losangeles1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f35#storeid_mochajoes" - } - } - } - ] - } -} -``` - Elements of the `unprocessed` array are unlike results received from a query. Instead of containing all the attributes of a record, an unprocessed record only includes the composite attributes defined in the Table Index. This is in keeping with DynamoDB's practice of returning only Keys in the case of unprocessed records. For convenience, ElectroDB will return these keys as composite attributes, but you can pass the [execution option](#execution-options) `{ unprocessed:"raw" }` override this behavior and return the Keys as they came from DynamoDB. ## Execution Options diff --git a/www/src/pages/en/mutations/batch-put.mdx b/www/src/pages/en/mutations/batch-put.mdx index 4a96650c..60270417 100644 --- a/www/src/pages/en/mutations/batch-put.mdx +++ b/www/src/pages/en/mutations/batch-put.mdx @@ -13,9 +13,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; Provide all _required_ Attributes as defined in the model to create records as an _array_ to `.put()`. **ElectroDB** will enforce any defined validations, defaults, casting, and field aliasing. Another convenience ElectroDB provides, is accepting BatchWrite arrays _larger_ than the 25 record limit. This is achieved making multiple, "parallel", requests to DynamoDB for batches of 25 records at a time. A failure with any of these requests will cause the query to throw, so be mindful of your table's configured throughput. @@ -32,30 +30,9 @@ If you set the [Execution Option](#execution-options) `concurrent` to `2`, Elect It is important to consider your Table's throughput considerations when setting this value. -```typescript -const unprocessed = await StoreLocations.put([ - { - cityId: "LosAngeles1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - unitId: "a1", - category: "food/coffee", - leaseEndDate: "2022-03-22", - rent: "4500.00", - }, - { - cityId: "LosAngeles1", - storeId: "MochaJoes", - mallId: "EastPointe", - buildingId: "F35", - unitId: "a2", - category: "food/coffee", - leaseEndDate: "2021-01-22", - rent: "1500.00", - }, -]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Response Format @@ -65,63 +42,6 @@ const unprocessed = await StoreLocations.put([ } ``` -## Equivalent Parameters - -```json -{ - "RequestItems": { - "StoreDirectory": [ - { - "PutRequest": { - "Item": { - "cityId": "LosAngeles1", - "mallId": "EastPointe", - "storeId": "LatteLarrys", - "buildingId": "F34", - "unitId": "a1", - "category": "food/coffee", - "leaseEndDate": "2022-03-22", - "rent": "4500.00", - "discount": "0.00", - "pk": "$mallstoredirectory#cityid_losangeles1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys", - "gsi1pk": "$mallstoredirectory#mallid_eastpointe", - "gsi1sk": "$mallstore_1#buildingid_f34#unitid_a1", - "gsi2pk": "$mallstoredirectory#storeid_lattelarrys", - "gsi2sk": "$mallstore_1#leaseenddate_2022-03-22", - "__edb_e__": "MallStore", - "__edb_v__": "1" - } - } - }, - { - "PutRequest": { - "Item": { - "cityId": "LosAngeles1", - "mallId": "EastPointe", - "storeId": "MochaJoes", - "buildingId": "F35", - "unitId": "a2", - "category": "food/coffee", - "leaseEndDate": "2021-01-22", - "rent": "1500.00", - "discount": "0.00", - "pk": "$mallstoredirectory#cityid_losangeles1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f35#storeid_mochajoes", - "gsi1pk": "$mallstoredirectory#mallid_eastpointe", - "gsi1sk": "$mallstore_1#buildingid_f35#unitid_a2", - "gsi2pk": "$mallstoredirectory#storeid_mochajoes", - "gsi2sk": "$mallstore_1#leaseenddate_2021-01-22", - "__edb_e__": "MallStore", - "__edb_v__": "1" - } - } - } - ] - } -} -``` - Elements of the `unprocessed` array are unlike results received from a query. Instead of containing all the attributes of a record, an unprocessed record only includes the composite attributes defined in the Table Index. This is in keeping with DynamoDB's practice of returning only Keys in the case of unprocessed records. For convenience, ElectroDB will return these keys as composite attributes, but you can pass the [execution option](#execution-options) `{ unprocessed:"raw" }` override this behavior and return the Keys as they came from DynamoDB. ## Execution Options diff --git a/www/src/pages/en/mutations/conditions.mdx b/www/src/pages/en/mutations/conditions.mdx index 30e00ab8..e80ecece 100644 --- a/www/src/pages/en/mutations/conditions.mdx +++ b/www/src/pages/en/mutations/conditions.mdx @@ -11,6 +11,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Building thoughtful indexes can make queries simple and performant. Sometimes you need to filter results down further or add conditions to an update/patch/upsert/put/create/delete/remove action. ## ConditionExpressions @@ -19,73 +21,9 @@ Below is the traditional way you would add a `ConditionExpression` to Dynamo's D ### Example -```typescript -animals - .update({ - animal: "blackbear", - name: "Isabelle", - }) - // no longer pregnant because Ernesto was born! - .set({ - isPregnant: false, - lastEvaluation: "2021-09-12", - lastEvaluationBy: "stephanie.adler", - }) - // welcome to the world Ernesto! - .append({ - offspring: [ - { - name: "Ernesto", - birthday: "2021-09-12", - note: "healthy birth, mild pollen allergy", - }, - ], - }) - // using the where clause can guard against making - // updates against stale data - .where( - ({ isPregnant, lastEvaluation }, { lt, eq }) => ` - ${eq(isPregnant, true)} AND ${lt(lastEvaluation, "2021-09-12")} - `, - ) - .go(); -``` - -### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #isPregnant = :isPregnant_u0, #lastEvaluation = :lastEvaluation_u0, #lastEvaluationBy = :lastEvaluationBy_u0, #offspring = list_append(#offspring, :offspring_u0)", - "ExpressionAttributeNames": { - "#isPregnant": "isPregnant", - "#lastEvaluation": "lastEvaluation", - "#lastEvaluationBy": "lastEvaluationBy", - "#offspring": "offspring" - }, - "ExpressionAttributeValues": { - ":isPregnant0": true, - ":lastEvaluation0": "2021-09-12", - ":isPregnant_u0": false, - ":lastEvaluation_u0": "2021-09-12", - ":lastEvaluationBy_u0": "stephanie.adler", - ":offspring_u0": [ - { - "name": "Ernesto", - "birthday": "2021-09-12", - "note": "healthy birth, mild pollen allergy" - } - ] - }, - "TableName": "zoo_manifest", - "Key": { - "pk": "$zoo#animal_blackbear", - "sk": "$animals_1#name_isabelle" - }, - "ConditionExpression": "#isPregnant = :isPregnant0 AND #lastEvaluation < :lastEvaluation0" -} -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?ssl=96&ssc=50&pln=96&pc=3#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MDVCc5G1MAEqSwCgAYtA5MEwAuklecFAEAI4ZwHPcFlwZBNMJW94oZKwQYhlz5TNwVTXMElCDAObx1omhgSBypzMXjtd3D15zi8sCKtzlANjsnl4UJIQJd8h9MNUvmkUPdQhDrNxpLciBAMrlLGdPsxeK52NJfnB0YZgGIAApzW5QtDvLxEpgkiBklCCLxUuAlWAFTH+AnwxFXZGo3k7bjAAgwFnWNm2cY7anZED4pjfFE8x47CA0GhiMA3FGKyoIy5MVg01UVOAYAiai1Kq2OV5gCleU0QaqwOX4uFnQxQmGuwnuiVmqUh7YOrwCmBCyQi4Nx85R7WSvVxvlnFAQbIRsXWnWxvMJykOyhonasSQSIZA13KnN10INptAgBCaYdbZjucp9cbMCQxDkGRSURQraz5eHfK748nrGn6FEffn4uzQ7RVnRg1MAA8coqTRxQD5XWAANYlww0OWsYFMe-emYicCHJ11JgvHIkxqiODpiA+opxs+bBvuBn5eN+kCRMWcD1GGBCTDWHZeAQJ4FOkGCuseuGOLckQxPeAC0ZHADE4GUcRJ6fvej60C+b40RRd7wdYiG-ih9RFCUMApMBNYgeBrHQa+pHkXBIEIQwSF-qhLB7AcRxzD0K7NtwmFnLW0qHh4iSICJvDsI4LgQAA+q8Mg0GMTCUAAlAA3EIgHyAAdBkYCYtkejPDIrysI4FmSGQd68AQkhQBS6GOAAkmIxRsOwequVYAD02UqBAcAHCiRBwKaBCMtI8AxWQkh4gQmhQKoEgFWojb8tAKAAIRWN5Kp6HAoQ0vS5VMgqtByLYo4SBOU4ztEzAAEwAAwLTElFLQAnJRMQLRSK4zeuc0oNuEoEGARQyAQ3mSNw7DxYeLk5XlahsN+9UwAVyb1Wo0Cvg1TUfd1hjXWA1QoNw-WhIaxqmncdTpqG0LWkgjVjG4IFJimIpMMtq3rVtO2foWKFMAUsWsMmmD8ssya4CAwB-ZArDsCgcByHdtyYEuEwPU9cB4nc5xk3Aahk3McD7LVtgS9IcC3NOUDcGztwDOI8CvHedx835AU5MrqsSHAEhyPVAWSD1otEAQOh6ENDKjbg+1rhus6mQgFO4AsrlKAAfHAAAGoQACQIAsOh2yNlW4OsBAudQDQAHIACJwCHFM6E7s2biguA4yta2bdtu1x1Y-uPcDtwQDo7kCEAA) + ## Where Clause @@ -97,85 +35,26 @@ The `where()` method allow you to write a `FilterExpression` or `ConditionExpres #### A single filter operation -```typescript -animals - .update({ habitat: "Africa", enclosure: "5b" }) - .set({ keeper: "Joe Exotic" }) - .where((attr, op) => op.eq(attr.dangerous, true)) - .go(); -``` + #### A single filter operation with destructuring -```typescript -animals - .update({ animal: "tiger", name: "janet" }) - .set({ keeper: "Joe Exotic" }) - .where(({ dangerous }, { eq }) => eq(dangerous, true)) - .go(); -``` + #### Multiple conditions -```typescript -animals - .update({ animal: "tiger", name: "janet" }) - .set({ keeper: "Joe Exotic" }) - .where( - (attr, op) => ` - ${op.eq(attr.dangerous, true)} AND ${op.notExists(attr.lastFed)} - `, - ) - .go(); -``` + #### Chained usage (implicit AND) -```typescript -animals - .update({ animal: "tiger", name: "janet" }) - .set({ keeper: "Joe Exotic" }) - .where( - (attr, op) => ` - ${op.eq(attr.dangerous, true)} OR ${op.notExists(attr.lastFed)} - `, - ) - .where(({ birthday }, { between }) => { - const today = Date.now(); - const lastMonth = today - 1000 * 60 * 60 * 24 * 30; - return between(birthday, lastMonth, today); - }) - .go(); -``` + #### "dynamic" filtering -```typescript -type GetAnimalOptions = { - habitat: string; - keepers: string[]; -}; -function getAnimals(options: GetAnimalOptions) { - const { habitat, excludeKeepers } = options; - const query = animals.query.exhibit({ habitat }); - - for (const name of excludeKeepers) { - query.where(({ keeper }, { ne }) => ne(keeper, name)); - } - - return query.go(); -} - -const { data, cursor } = await getAnimals({ - habitat: "RainForest", - keepers: ["Joe Exotic", "Carol Baskin"], -}); -``` + ## Operations -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvAAWAQ14ZpMMXAC8cANpMAgnXLSmuLVE7l9zAErTgKAGLQCEpgF040pSPEwA3AKxgCcAAlZeXhVXwIIGjgZORgFMTUUAFcQXiJHb2FRCRcUUGlWJVUUAgB3OFR0LAAKBAE4OBAIbjYALkR6hq6xIlIKdqYALwgIfU6uuAI0DEwB6TyQArExiYbiIjFgUQGARhW4SmxOhS5gXiSYe3a6iZiQ6-Gu8Pa7uMUj1bgoAgBHJOBvtx2lwkgQPl1Do8pmRWBAxElvg9Ps9mBIoFYAOb7BqQibzfKsJGrFFMNGY7Fdb5-AEEIFwEFgx64rooaQgAhEiYkskoLFM8ENbjzDFECBJMScp6YPwDXgjdjzCnMhrAMQABW+GNZaElDRJcogCpQggmyrgclgkiFsw6yOlHOYyVSRBNEIFcG4wAIMF19PtAx6MApKsuIAlqNOvNdOPdAGsCAQ-FBfdzI3zTe71pd0az0fMU-6Izn027HpEaGIwMWCzLmKxVUH3SGCGHfXrC0xFmBg10qxAk+grrbPiy2Q6biOuR2eSXJ2bPhaYFbpDaJ5P27XSWnoyP56sUBBLm3idPt49PpRzxCr5eM49WK4YNZaTWHVvizuzQ+JM-uAAhVcr1TD9+XvR8kGIAokgULYUFfAMzzvCZvxgCCoJg0QAPgotySZTpmSsFoAA8hzXOBKw4UApl9MBY2PBoaC9Vg6SYWiewmERwDhDAHQ0fFFlYJwmwOYSxDo4dJ0YtgWLE9iuk4yBNiPdQmFZdknBvUCJgIIjJDODBfUInSBgxTYdlogBaUzgB2MSLKMoie1o+jaCYljrPM2M5IaBTuOUjRXgUISb1E8SyM+KTmJMszZOEjiGEUnj2g0aFYXhb5TCYFDfw0i8tJEgRDkQOJeHYAZhggAB9RY8hoewg0oABKTIAHoACo2vqNq4AANWkPN0GyOBRGiCBykwMU4DIeY4HFfwl38AADUpJCIAhFqmh85q6lqhBalq4E0cjMXYVzWGzYakwwlA4AEfilgAOiSMAhUuWp7sJZh0BFKBTDUt8ACt5m9JgmoEABIB7A1qeNEyIAYACkIH8JAiMPEwwYaB6VrW6pqhOKBcH7RqVAAPkuh7fnxmAuAeoVeVFcVcAZRrGs6B6MQgapmr2g6js2XlTsY86iEuohrrgUoDpaNEkk4BFMTuhZHue16CHe5XPqYb6XVwf6BiBkoGrZyHoYQWGk0R5GKjR9AyFBtmsZx748YQemfrFMQioQX4mrJyYfmqd3GbEZmoFBVn2c57nWoOgBZJJzuAMBTvcT1BvEOALLgRb+0WpWCTEJ6XoUdWEA+gYdd+vWxwN4HjYhqHvRhhNLeYJGUdtjHHbgbHVpd6muCJsASeUcn84mAASBB+0pwOCbp4UQ7DiPqE0AA5AAROBp9ng9UKIhsxEHqAHuy2lGtvHOe45rmeYEfa4ATpOU-8cVpBFJRIhz531rgapQAp3IBgQ6W82YfSLqrUuGsCSV2AD9P6tdmCGxBmDU2zdzat3hu3a2qN0b20xr3X+eMCbD1HuPR4u8wBzxPovBm9Amb0nDgQS+cAADyZgd4z2ofvVGR9aHn24JfToi0b7ENqIuZcmBvZpBgKUBMKA-ZjwklNbI8AYDNBXCoOAm9S4PQPKUGOjx3A5BQnHUQS5tEaOtFnOAOwAAMji4DdQAGz2OcXANxHiABMAAWDxABmex3gJjfBgAiG6sj5FTGqJI60uAzEWMkMzTRmAeY4hvtHe+j8mDcEwGpEwZ1syKxoEkFAxgRoihgJoTWx9Ao+kCMEN4uALYbHaDONQjgSYThMfAP4RBMDaIgQ9fpUBMCU10vpGAtR6lNRCbQaA-9elwH+sNKIrSoBiG6Y8UZ4zxGYLhlAb2vtyEB2qBsmu7JWbzKvmEiJcBdm3yMZeLIHg4AbKKOoToTAO423wfsJgABhfqho4B-lcLGKwggMhCCqTUwu1QmAWCsLYb4DgWlYM2c1IAA) - The `attributes` object contains every Attribute defined in the Entity's Model. The `operations` object contains the following methods: | operator | example | result | @@ -209,16 +88,7 @@ The `name()` function allows you to create a reference to an attribute's name, w This example demonstrates how you might find animals that were last fed by someone other than their "keeper". -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ lastFedBy, keeper }, { name }) => ` - ${name(lastFedBy)} != ${name(keeper)} - `, - ) - .go(); -``` + #### Value @@ -226,16 +96,7 @@ The `value()` function can be paired with `name()` as convenience when building This example shows how you can implement the `eq` operation without using the ElectroDB `eq` function -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ keeper }, { name, value, eq }) => ` - ${name(keeper)} = ${value(keeper, "Tiger King")} - `, - ) - .go(); -``` + #### Escape @@ -243,16 +104,7 @@ The `escape()` method allows you to provide any primitive to an expression witho This example shows how you might use escape to apply a filter against the `size()` of an attribute. -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ diet }, { size, escape }) => ` - ${size(diet)} > ${escape(2)} - `, - ) - .go(); -``` + #### Field @@ -260,16 +112,7 @@ The `field()` method allows you to provide and reference a field value that is n You can use both `escape()` and `field()` to template _any_ filter that DynamoDB supports. -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - (_, { field, escape }) => ` - contains(${field("gsi1sk")}, ${escape("value")}) - `, - ) - .go(); -``` + ## Handling Condition Check Failures @@ -291,54 +134,17 @@ Supported on `put`, `create`, `update`, `patch`, `delete`, `remove`, `upsert`. V ### Detect Rejection Only -```typescript -const result = await StoreLocations - .create({ cityId: "Atlanta1", storeId: "LatteLarrys", mallId: "EastPointe", buildingId: "BuildingA1", unitId: "B47", category: "food/coffee", leaseEndDate: "2020-03-22", rent: "4500.00" }) - .go({ returnOnConditionCheckFailure: true }); - -if (result.rejected) { - console.log("store already exists"); -} else { - console.log("created:", result.data); -} -``` +> The **Entity** and **Table Definition** tabs show the `StoreLocations` setup this example runs against. + + ### Safe Create -```typescript -const result = await StoreLocations - .create({ - cityId: "Atlanta1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "BuildingA1", - unitId: "B47", - category: "food/coffee", - leaseEndDate: "2020-03-22", - rent: "4500.00", - }) - .go({ returnOnConditionCheckFailure: "all_old" }); - -if (result.rejected) { - console.log("already exists:", result.data); -} else { - console.log("created:", result.data); -} -``` + ### Conditional Update -```typescript -const result = await StoreLocations - .patch({ cityId: "Atlanta1", mallId: "EastPointe", storeId: "LatteLarrys", buildingId: "BuildingA1" }) - .set({ rent: "5000.00" }) - .where(({ rent }, { lt }) => lt(rent, "4000.00")) - .go({ returnOnConditionCheckFailure: "all_old" }); - -if (result.rejected) { - console.log("current rent:", result.data?.rent); -} -``` + ### Null Data on Rejection @@ -360,71 +166,14 @@ The following are examples on how to filter on complex attributes: #### Filtering on a `map` attribute -```typescript -animals - .update({ animal: "tiger", name: "janet" }) - .set({ keeper: "Joe Exotic" }) - .where(({ veterinarian }, { eq }) => eq(veterinarian.name, "Herb Peterson")) - .go(); -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MDVCc5G1MAEqSwCgAYtA5MEwAuklecFAEAI4ZwHPcFlwZBNMJW94oZKwQYhlz5TNwVTXMElCDAObx1omhgSBypzMXjtd3D15zi8sCKtzlANjsnl4UJIQJd8h9MNUvmkUPdQhDrNxpLciBAMrlLGdPsxeK52NJfnB0YZgGIAApzW5QtDvLxEpgkiBklCCLxUuAlWAFTH+AnwxFXZGo3k7bjAAgwFnWNm2cY7anZED4pjfFE8x47CA0GhiMA3FGKyoIy5MVg01UVOAYAiai1Kq2OV5gCleU0QaqwOX4uFnQxQmGuwnuiVmqUh7YOrwCmBCyQi4Nx85R7WSvVxvlnFAQbIRsXWnWxvMJykOyhonbhbJmyQ3aSutme71wX3+9A5Eth2FVy3i7Mx3MzfM2apkYByLAl4dlnNV2tnVf60KsSQSIZAttZ8vjvlbndAgBCaYdyuX0s325gSGIcgyKSiKH3I8PdbvEkfz9fogXh+S5jmiVjooMpgAB59qKhgmhwoA+K6YAANYLrQcqsMCTBoZ2XgiOAhxOnUTAvHIkxqpSVFiOhcEhjQWE4bR+HWIRkCRMWcD1AOkw1t+XgEFBBTpBgrqQUJji3JEMRoQAtNJwAxLRckSVBnZoRhjFsDhimyahrGGOxxFcfURQlDAKSUTWNF0emZzadhUkySxVEEQwHEkdxLB7AcRxzD0J4wLu3B8WuAnUQIiSIJZvDsI4LgQAA+q8Mg0GMTCUAAlAA3EI5HyAAdIsRCYFYhVCSJFl6OZpQKu0zRkK02XlWoBREAQOh6A2RCDM2s4oNFCALNlSgAHzePMOg9U2LYoIVA64EwAASRC8HAtLyhEohMFlWXlbcEA6PtAhAA) + #### Filtering on an element in a `list` attribute -```typescript -animals - .update({ animal: "tiger", name: "janet" }) - .set({ keeper: "Joe Exotic" }) - .where(({ offspring }, { eq }) => eq(offspring[0].name, "Blitzen")) - .go(); -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?ssl=106&ssc=8&pln=103&pc=1#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MACoZKNxQrbhMAEqSwCgAYtA5MEwAuklecFAEAI4ZwIvcFlwZBHMJu94oZKwQYhmL5fNwVTXMElAjAObx1omhgSByF-PXjnePz15Fis1gQNlcoNt9q8vChJCAbvlvphqr80ignqFodZuNIHkQIBlcpZLj9mLxXOxpAC4FjDMAxAAFRYPWFoL5eUlMckQSkoQReWlwEqwAo4-zEpEo25ojEC-bcYAEGDs6yc2xTfZ07IgIlMP7o-kvfYQGg0MRge7olWVZE3JisekaipwDAEHXW1W2xwfMDUrwWiDVWCKomIy6GWHwj0kr3Sy2y8N7Z1eYUwUWScVhxNXWN6mWGxOCy4oCDZaOSu36hOF5M052UTH7cLZS2Se7SD2cn1+uABoPoHLlyMI2s2qV5+MF+ZFmzVMjAORYctjyv52sNy4bo2hViSCSjUGd3NVqeC3f70EAIUzzrVa7lO73MCQxDkGRSURQR-HJ8bj4kL5vh+ojXt+q6TpiVhYiMpgAB6DhKhjmhwoA+B6YAANbLrQiqsGCTCYT2XgiOAJyunUTDvHIMyajStFiFhiHhjQuH4QxRHWCRkCRGWcD1MOMz1n+XgELBBTpBgHowaJjgPJEMSYQAtHJwAxAxinSbBPaYdhLFsPhKkKRhHGGFxZG8fURQlDAKQ0fW9GMVmlx6XhsnyextHEQw3HkXxLCHMcpyLG09pPge3CCZuwl0QIiSIDZvDsI4LgQAA+h8Mg0JMTCUAAlAA3EIVHyAAdCsRCYFYJWieJ1l6FZpTKh0XQ9K0eVVWoBREAQOh6CaZoWo8cUIMseVKAAfN4Sw6P15rxrUAAM0wlcO-SXg6MBOD4TC5blVUPBAOi5UAA) + ### Multiple Where Clauses It is possible to include chain multiple where clauses. The resulting FilterExpressions (or ConditionExpressions) are concatenated with an implicit `AND` operator. -```typescript -let MallStores = new Entity(model, { table: "StoreDirectory" }); -let stores = await MallStores.query - .leases({ mallId: "EastPointe" }) - .between({ leaseEndDate: "2020-04-01" }, { leaseEndDate: "2020-07-01" }) - .where( - ({ rent, discount }, { between, eq }) => ` - ${between(rent, "2000.00", "5000.00")} AND ${eq(discount, "1000.00")} - `, - ) - .where( - ({ category }, { eq }) => ` - ${eq(category, "food/coffee")} - `, - ) - .go(); -``` - -```json -{ - "TableName": "StoreDirectory", - "ExpressionAttributeNames": { - "#rent": "rent", - "#discount": "discount", - "#category": "category", - "#pk": "idx2pk", - "#sk1": "idx2sk" - }, - "ExpressionAttributeValues": { - ":rent1": "2000.00", - ":rent2": "5000.00", - ":discount1": "1000.00", - ":category1": "food/coffee", - ":pk": "$mallstoredirectory_1#mallid_eastpointe", - ":sk1": "$mallstore#leaseenddate_2020-04-01#storeid_", - ":sk2": "$mallstore#leaseenddate_2020-07-01#storeid_" - }, - "KeyConditionExpression": "#pk = :pk and #sk1 BETWEEN :sk1 AND :sk2", - "IndexName": "idx2", - "FilterExpression": "(#rent between :rent1 and :rent2) AND (#discount = :discount1 AND #category = :category1)" -} -``` + diff --git a/www/src/pages/en/mutations/create.mdx b/www/src/pages/en/mutations/create.mdx index 27582893..6a8688d0 100644 --- a/www/src/pages/en/mutations/create.mdx +++ b/www/src/pages/en/mutations/create.mdx @@ -12,28 +12,15 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; In DynamoDB, `put` operations by default will overwrite a record if record being updated does not exist. In **_ElectroDB_**, the `create` method will utilize the `attribute_not_exists()` parameter to ensure records are only "created" and not overwritten when inserting new records into the table. The `create()` operation will trigger the `default`, and `set` attribute callbacks when writing to DynamoDB. By default, after writing to DynamoDB, ElectroDB will format and return the record through the same process as a Get/Query, which will invoke the `get` callback on all included attributes. If this behaviour is not desired, use the [Execution Option](#execution-options) `response:"none"` to return a null value. -```typescript -await StoreLocations.create({ - cityId: "Atlanta1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "BuildingA1", - unitId: "B47", - category: "food/coffee", - leaseEndDate: "2020-03-22", - rent: "4500.00", -}) - .where((attr, op) => op.eq(attr.rent, "4500.00")) - .go(); -``` +> This example includes an optional conditional expression. The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Response Format @@ -45,40 +32,6 @@ await StoreLocations.create({ } ``` -## Equivalent Parameters - -```json -{ - "Item": { - "cityId": "Atlanta1", - "mallId": "EastPointe", - "storeId": "LatteLarrys", - "buildingId": "BuildingA1", - "unitId": "B47", - "category": "food/coffee", - "leaseEndDate": "2020-03-22", - "rent": "4500.00", - "discount": "0.00", - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_buildinga1#storeid_lattelarrys", - "gsi1pk": "$mallstoredirectory#mallid_eastpointe", - "gsi1sk": "$mallstore_1#buildingid_buildinga1#unitid_b47", - "gsi2pk": "$mallstoredirectory#storeid_lattelarrys", - "gsi2sk": "$mallstore_1#leaseenddate_2020-03-22", - "__edb_e__": "MallStore", - "__edb_v__": "1" - }, - "TableName": "StoreDirectory", - "ConditionExpression": "attribute_not_exists(pk) AND attribute_not_exists(sk) AND #rent = :rent_w1", - "ExpressionAttributeNames": { - "#rent": "rent" - }, - "ExpressionAttributeValues": { - ":rent_w1": "4500.00" - } -} -``` - ## Execution Options import PartialExample from "../../../partials/mutation-query-options.mdx"; diff --git a/www/src/pages/en/mutations/delete.mdx b/www/src/pages/en/mutations/delete.mdx index e35fccd2..0e790b73 100644 --- a/www/src/pages/en/mutations/delete.mdx +++ b/www/src/pages/en/mutations/delete.mdx @@ -12,20 +12,13 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; Provide all Table Index composite attributes in an object to the `delete` method to delete a record. -```javascript -await StoreLocations.delete({ - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - cityId: "Atlanta1", -}).go(); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Default Response Format @@ -37,18 +30,6 @@ await StoreLocations.delete({ } ``` -## Equivalent Parameters - -```json -{ - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - }, - "TableName": "YOUR_TABLE_NAME" -} -``` - ## Execution Options import PartialExample from "../../../partials/mutation-query-options.mdx"; diff --git a/www/src/pages/en/mutations/remove.mdx b/www/src/pages/en/mutations/remove.mdx index b7b44374..bfe630ad 100644 --- a/www/src/pages/en/mutations/remove.mdx +++ b/www/src/pages/en/mutations/remove.mdx @@ -12,20 +12,13 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; A convenience method for `delete` with ConditionExpression that the item being deleted exists. If the item does not exist, ElectroDB will throw a failed condition error. Provide all Table Index composite attributes in an object to the `remove` method to remove the record. -```typescript -await StoreLocations.remove({ - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - cityId: "Atlanta1", -}).go(); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Default Response Format @@ -37,19 +30,6 @@ await StoreLocations.remove({ } ``` -## Equivalent Parameters - -```json -{ - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - }, - "TableName": "YOUR_TABLE_TABLE", - "ConditionExpression": "attribute_exists(pk) AND attribute_exists(sk)" -} -``` - ## Execution Options import PartialExample from "../../../partials/mutation-query-options.mdx"; diff --git a/www/src/pages/en/mutations/transact-write.mdx b/www/src/pages/en/mutations/transact-write.mdx index b353a1ee..41b8603a 100644 --- a/www/src/pages/en/mutations/transact-write.mdx +++ b/www/src/pages/en/mutations/transact-write.mdx @@ -12,9 +12,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import TableDefinition from "../../../partials/table-definition.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; In cases where you must keep multiple records in sync, enforce constraints across entities, and/or ensure request idempotency you can use ElectroDB's Transact [Get](/en/queries/transact-get)/[Write](/en/mutations/transact-write) methods. There are many articles and guides on use-cases for DynamoDB's Transaction APIs, resource links can be found [at the bottom of this document](#resources). This page will focus on how to use ElectroDB's transaction API. @@ -22,6 +20,8 @@ In cases where you must keep multiple records in sync, enforce constraints acros To perform `write` transactions with ElectroDB you will first need to create a [Service](/en/modeling/services). Available on the `Service` exist two methods: `transaction.get()` and `transaction.write()`. These methods accept a callback function, which is then provided with the entities of the service, should return an array of mutations. Creating mutations within a transaction is nearly identical to other mutations except instead of terminating your query with `.go()` or `.params()` you use `.commit()` instead. +> The example below demonstrates the shape of a write transaction. See the Unique Constraint example below for a runnable transaction. + ```typescript await yourService.transaction .write(({ entity1, entity2 }) => [ @@ -93,167 +93,15 @@ Calling the async `.go()` method on a transaction returns the following interfac ## Examples -The following code creates two [Entities](/en/modeling/entities), and a [Service](/en/modeling/services) to join them, that will be used in our Transact Write examples. This `Service` contains entities/information the top-secret British military intelligence organization: MI6. - -### Setup - -For the examples below, use the following imports and dependencies at the top of your file. - -
- Imports - - ```typescript - import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; - import { Entity, Service } from 'electrodb'; - - const table = 'electro'; - const client = new DynamoDBClient({}); - ``` - -
- -#### Agent entity - -The `agent` entity models records for each MI6 agents and personnel - -```typescript -const agent = new Entity( - { - model: { - entity: "agent", - version: "1", - service: "MI6", - }, - attributes: { - id: { - type: "string", - }, - designation: { - type: "string", - }, - email: { - type: "string", - required: true, - }, - firstName: { - type: "string", - }, - lastName: { - type: "string", - }, - alive: { - type: "boolean", - required: true, - }, - kills: { - type: "number", - default: 0, - }, - }, - indexes: { - operatives: { - pk: { - field: "pk", - composite: ["designation"], - }, - sk: { - field: "sk", - composite: ["id"], - }, - }, - }, - }, - { table, client }, -); -``` - -#### Constraint entity - -The `constraint` entity is a utility available to all entities within the `MI6` service. It can be used to enforce uniqueness for any property within a namespace. - -```typescript -// entity that owns unique constraints -const constraint = new Entity( - { - model: { - entity: "constraint", - version: "1", - service: "MI6", - }, - attributes: { - name: { - type: "string", - required: true, - }, - value: { - type: "string", - required: true, - }, - entity: { - type: "string", - required: true, - }, - }, - indexes: { - value: { - pk: { - field: "pk", - composite: ["value"], - }, - sk: { - field: "sk", - composite: ["name", "entity"], - }, - }, - name: { - index: "gsi1pk-gsi2sk-index", - pk: { - field: "gsi1pk", - composite: ["name", "entity"], - }, - sk: { - field: "gsi1sk", - composite: ["value"], - }, - }, - }, - }, - { table, client }, -); -``` - -#### MI6 service - -Services allow you to build namespaces with a single table, in this case we will create a service called `mi6` with our two entities. - -```typescript -const mi6 = new Service({ constraint, agent }); -``` +The following examples use two [Entities](/en/modeling/entities), and a [Service](/en/modeling/services) to join them. This `Service` contains entities/information the top-secret British military intelligence organization: MI6. The `agent` entity models records for each MI6 agent and their personnel information, and the `constraint` entity is a utility available to all entities within the `MI6` service that can be used to enforce uniqueness for any property within a namespace. Services allow you to build namespaces with a single table, in this case a service called `mi6` joins the two entities together. ### Example - Unique Constraint The following is an example of how you might implement a simple unique constraint mechanism to ensure a property (in this case email) remains unique across your service. -```typescript -import { CreateEntityItem } from "electrodb"; - -type NewAgent = CreateEntityItem; - -async function createNewAgent(newAgent: NewAgent) { - return mi6.transaction - .write(({ agent, constraint }) => [ - agent.create(newAgent).commit({ response: "all_old" }), - constraint - .create({ - name: "email", - value: newAgent.email, - entity: agent.schema.model.entity, - }) - .commit(), - ]) - .go(); -} -``` +> The **Entities** and **Service** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ### Example - Idempotent writes @@ -261,54 +109,11 @@ Architecting with idempotency in mind is one of the best ways to reduce complexi Unfortunately some operations, like incrementing a number, can easily cause our app to get out of sync. In failure scenarios where retrying or replaying is necessary, incrementing a number could result in duplicate operations. Transactions can be helpful in the situation by allowing you to provide a [ClientRequestToken](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html#API_TransactWriteItems_RequestParameters) to ensure an operation is only performed once. At the time of writing, request tokens are valid for 10 minutes, though always consult the latest documentation for more information about this feature. -Below is an example of how you might use a `ClientRequestToken` - -```typescript -type IncrementAgentKillsOptions = { - id: string; - kills: number; - token: string; - designation: string; -}; - -async function incrementAgentKills(options: IncrementAgentKillsOptions) { - const { id, designation, kills, token } = options; +Below is an example of how you might use a `ClientRequestToken`. The `token` (a `ClientRequestToken` in DynamoDB parlance) should be unique for a given command. It can be helpful to use a deterministic value (like a composite string) to ensure it is always the same for a given command. Regardless of how many times `incrementAgentKills` is called, so long as the value for `token` remains the same, and you remain within DynamoDB's timing window, your operation will not duplicate your incrementation. Using this functionality can greatly simply your retry logic in the case of failure. - return mi6.transaction - .write(({ agent }) => [ - agent.patch({ id, designation }).add({ kills }).commit(), - ]) - .go({ token }); -} -``` - -#### Token - -The `token` (a `ClientRequestToken` in DynamoDB parlance) should be unique for a given command. It can be helpful to use a deterministic value (like a composite string) to ensure it is always the same for a given command. - -```typescript -const token = "daily-headcount-count-2022-03-16"; -``` - -Regardless of how many times `incrementAgentKills` is called, so long as the value for `token` remains the same, and you remain within DynamoDB's timing window, your operation will not duplicate your incrementation. Using this functionality can greatly simply your retry logic in the case of failure. +> The **Entities** and **Service** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -```typescript -// kills `0` -> `2` -await incrementAgentKills({ - token, - id: "7", - kills: 2, - designation: "00", -}); - -// still results in `2` -await incrementAgentKills({ - token, - id: "7", - kills: 2, - designation: "00", -}); -``` + ## Execution Options diff --git a/www/src/pages/en/mutations/update.mdx b/www/src/pages/en/mutations/update.mdx index 8b178d3c..1f59a9a9 100644 --- a/www/src/pages/en/mutations/update.mdx +++ b/www/src/pages/en/mutations/update.mdx @@ -12,11 +12,9 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; import TasksModel from "../../../partials/tasks-example.entity.mdx"; - - > _NOTE: Use caution when using the `update` method. DynamoDB will create non-existent items when using `update` which can result in partial items to be written to your table. When possible, use the [patch](/en/mutations/patch) or [upsert](/en/mutations/upsert) methods. If these methods cannot be used it is strongly recommended to use conditions when using `update` to prevent accidental item creation_ The `update()` method in ElectroDB allows you to update individual properties of an item. This method utilizes the DynamoDB operation `update` under the hood. @@ -27,26 +25,9 @@ The DynamoDB method `update()` will create an item if one does not exist. Becaus -```typescript -tasks - .update({ - team: "core", - task: "45-662", - project: "backend", - }) - .set({ status: "open" }) - .add({ points: 5 }) - .append({ - comments: [ - { - user: "janet", - body: "This seems half-baked.", - }, - ], - }) - .where(({ status }, { eq }) => eq(status, "in-progress")) - .go(); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Default Response Format @@ -58,42 +39,6 @@ tasks } ``` -## Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #status = :status_u0, #points = #points + :points_u0, #comments = list_append(#comments, :comments_u0), #updatedAt = :updatedAt_u0, #gsi1sk = :gsi1sk_u0", - "ExpressionAttributeNames": { - "#status": "status", - "#points": "points", - "#comments": "comments", - "#updatedAt": "updatedAt", - "#gsi1sk": "gsi1sk" - }, - "ExpressionAttributeValues": { - ":status0": "in-progress", - ":status_u0": "open", - ":points_u0": 5, - ":comments_u0": [ - { - "user": "janet", - "body": "This seems half-baked." - } - ], - ":updatedAt_u0": 1630977029015, - ":gsi1sk_u0": "$assignments#tasks_1#status_open" - }, - "TableName": "your_table_name", - "Key": { - "pk": "$taskapp#team_core", - "sk": "$tasks_1#project_backend#task_45-662" - }, - "ConditionExpression": "attribute_exists(pk) AND attribute_exists(sk) AND #status = :status0" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/PQKgBAsg9gJgpgGzARwK5wE4Es4GcA0YuccYGeqCALgUQBYCG5YA7llXWAGbZwB2MXGBDAAUKKwBbAA5QMVMAG8wAUT5V2AT0IBlTADcsAY1IBfbhiiSwAIkRwjVSzABGNgNzijUPrgVUGFwRSAF5bTShUDAB9AKC4aL4GSTgPcVAwABUGXABrITUNKk1hMW9ffxz8sDC+OBZVdS0AClEwJTb2sElYRAAuDq6u-iLNAZsAvNwbfE6h-UxcLB9xgEYZua7iDEMTccnchmlpG03TWaGGKicsF1QqPAHFTfaH5KeXruLpOHG-bD4AHMNkMhuQ0FhyDABk50J9zp8Dh9QV9ND8-jcgSCUWQ4BCoTCMHCUQiUdJLAArBxUZE476-Wz-LBYi448GoSFwaFgWFweGsoaoba0lH0jEA4EC0Hsznc3n8xHsYIi0FixmYyWfdoygk8olwKXtUmg+C4IzYaQaFaDOlohk2JlYhUovxXIUqoZqgDaNigPz4M1szIAtOSoIDyLhpoRfXxg3QoAgYIGbEYEFBiMmALpgHJgcp+Q1deBcBiUGm2P38U4kouyZk0D2o9G2PioSQuTDYobGz0MQG4JuvO1-OBUbug9hwSSD9USmug3tdbySFLqWfPHE8ke2BBYPwToZTmdD5v2yRHQ+gsM-eQ4Dda0FCzCn0U7h0ahdbo1FlEuWBjDa35nuKzLAo+PYQWApiPjBtafOacBXFyACCFabraLY2G2HZdr+YAlmW1ADM0ACUNQAHxgAAIshAB0fBQCwZH4eQDAwAA8nwCCAfK8Eoqg0gwMhMBoaearYe2nYYFe7QsFcRh0OMICyUQY4keRIRUbRDwMUxLGPmxnHcbx+rwmcUrMvAAAejxAV0YZUo4D5btIuSvtwOBJuMbmqe0K6yEsDwDD6bySDYWawfheQeVwXncg6uR+WAwDAPmbEPPmViBVOYC5HAmhCFwchgNITAaAwSC4HICj5SUaCYPeUEBRmU4hTYjnUimBwRbBzqgjkSyAnU3IYSiqVZQgwSOMsvi5lNTHcCVDW8EIDDmhmQiSOWWDSMEYAjOwTVbt4U3UrN4yDVgw1rjQqlWXA1njAOWCrG5wYvaseTBg91mqW5HkTRe0g8lAYARFEYAAOI6AAkmAAASOR0MAAAK5VHT4eUFVBcWIAln2+fh-nZa1wVgD6z4yZFW5LkMMX2eNaXA6D4ORBg0Nw2AABKDBAnAwA6DV2OaLj8XPUsX1JcTWUyGTDI+q6VBCr1tPmZBP6dMocT7TBpGeKIE0AAZlVQilG2A+5gHu+VgEbgnCQ8FuPSYlqWwoz5CDYVw3HcDyJFAVDRI9+53aIBy4J0dGm4pzTKJsYXjN45ATkitgACwAKzBgAbDnABMgabJ1jjjC4635QIC6mKRUfEFQcdEAEyuzr6-o2NBtftHR7EwI39brgMmed1HRz+n38dDCut2zl6Y1dFT4wUnzY5Xv+MCATYmR0FbxDTkIjAIFwwbl-lMB0V+0E5p0NdRywdCYHAzTNEoStCucSh4uYmlUXizRv7QGwIYwwRjwNMUiXcwB0UBFAMi7ggA) - ## Operations Update Methods are available **_after_** the `update()` or `patch()` method is called, and allow you to perform alter an item stored dynamodb. Each Update Method corresponds to a [DynamoDB UpdateExpression clause](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html). @@ -119,14 +64,9 @@ The `set()` method will accept all attributes defined on the model. Provide a va #### Example - +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .set({ category: "food/meal" }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -138,27 +78,6 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #category = :category", - "ExpressionAttributeNames": { - "#category": "category" - }, - "ExpressionAttributeValues": { - ":category_w1": "food/coffee", - ":category": "food/meal" - }, - "TableName": "StoreDirectory", - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category_w1" -} -``` - ### Remove The `remove()` method will accept all attributes defined on the model. Unlike most other update methods, the `remove()` method accepts an array with the names of the attributes that should be removed. @@ -167,14 +86,7 @@ The `remove()` method will accept all attributes defined on the model. Unlike mo #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .remove(["discount"]) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -186,39 +98,6 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #cityId = :cityId_u0, #mallId = :mallId_u0, #buildingId = :buildingId_u0, #storeId = :storeId_u0, #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0 REMOVE #discount", - "ExpressionAttributeNames": { - "#category": "category", - "#discount": "discount", - "#cityId": "cityId", - "#mallId": "mallId", - "#buildingId": "buildingId", - "#storeId": "storeId", - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":cityId_u0": "Portland", - ":mallId_u0": "EastPointe", - ":buildingId_u0": "A34", - ":storeId_u0": "LatteLarrys", - ":__edb_e___u0": "MallStore", - ":__edb_v___u0": "1" - }, - "TableName": "electro", - "Key": { - "pk": "$mallstoredirectory#cityid_portland#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - ### Add The `add()` method will accept attributes with type `number`, `set`, and `any` defined on the model. In the case of a `number` attribute, provide a number to _add_ to the existing attribute's value on the item. @@ -227,17 +106,7 @@ If the attribute is defined as `any`, the syntax compatible with the attribute t #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .add({ - warnings: 1, // "number" attribute - tenants: ["larry"], // "set" attribute - }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -249,56 +118,13 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #cityId = :cityId_u0, #mallId = :mallId_u0, #buildingId = :buildingId_u0, #storeId = :storeId_u0, #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0 ADD #warnings :warnings_u0, #tenants :tenants_u0", - "ExpressionAttributeNames": { - "#category": "category", - "#warnings": "warnings", - "#tenants": "tenants", - "#cityId": "cityId", - "#mallId": "mallId", - "#buildingId": "buildingId", - "#storeId": "storeId", - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":warnings_u0": 1, - ":tenants_u0": ["larry"], - ":cityId_u0": "Portland", - ":mallId_u0": "EastPointe", - ":buildingId_u0": "A34", - ":storeId_u0": "LatteLarrys", - ":__edb_e___u0": "MallStore", - ":__edb_v___u0": "1" - }, - "TableName": "electro", - "Key": { - "pk": "$mallstoredirectory#cityid_portland#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - ### Subtract The `subtract()` method will accept attributes with type `number`. In the case of a `number` attribute, provide a number to _subtract_ from the existing attribute's value on the item. #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .subtract({ deposit: 500 }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -310,49 +136,13 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #deposit = #deposit - :deposit0", - "ExpressionAttributeNames": { - "#category": "category", - "#deposit": "deposit" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":deposit0": 500 - }, - "TableName": "StoreDirectory", - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - ### Append The `append()` method will accept attributes with type `any`. This is a convenience method for working with DynamoDB lists, and is notably different that [`set`](#update-method-set) because it will add an element to an existing array, rather than overwrite the existing value. #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .append({ - rentalAgreement: [ - { - type: "amendment", - detail: "no soup for you", - }, - ], - }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -364,47 +154,13 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #rentalAgreement = list_append(#rentalAgreement, :rentalAgreement0)", - "ExpressionAttributeNames": { - "#category": "category", - "#rentalAgreement": "rentalAgreement" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":rentalAgreement0": [ - { - "type": "amendment", - "detail": "no soup for you" - } - ] - }, - "TableName": "StoreDirectory", - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - ### Delete The `delete()` method will accept attributes with type `any` or `set` . This operation removes items from a the `contract` attribute, defined as a `set` attribute. #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .delete({ contact: ["555-345-2222"] }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -416,28 +172,6 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "DELETE #contact :contact0", - "ExpressionAttributeNames": { - "#category": "category", - "#contact": "contact" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":contact0": "555-345-2222" - }, - "TableName": "StoreDirectory", - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - ### Data The `data()` allows for different approach to updating your item, by accepting a callback with a similar argument signature to the [where clause](/en/mutations/conditions). @@ -464,31 +198,7 @@ As mentioned above, this method is functionally similar to the `where` clause wi #### Example - - -```javascript -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .data((a, o) => { - const newTenant = o.value(a.tenants, ["larry"]); - o.set(a.category, "food/meal"); // electrodb "enum" -> dynamodb "string" - o.add(a.tenants, newTenant); // electrodb "set" -> dynamodb "set" - o.add(a.warnings, 1); // electrodb "number" -> dynamodb "number" - o.subtract(a.deposit, 200); // electrodb "number" -> dynamodb "number" - o.remove(a.discount); // electrodb "number" -> dynamodb "number" - o.append(a.rentalAgreement, [ - { - // electrodb "list" -> dynamodb "list" - type: "amendment", // electrodb "map" -> dynamodb "map" - detail: "no soup for you", - }, - ]); - o.delete(a.tags, ["coffee"]); - o.del(a.contact, ["555-345-2222"]); // electrodb "set" -> dynamodb "set" - o.add(a.fees, o.name(a.petFee)); // electrodb "number" -> dynamodb "number" - }) - .where((attr, op) => op.eq(attr.category, "food/coffee")) - .go(); -``` + #### Default Response Format @@ -500,59 +210,6 @@ await StoreLocations.update({ cityId, mallId, storeId, buildingId }) } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #category = :category_u0, #deposit = #deposit - :deposit_u0, #rentalAgreement = list_append(#rentalAgreement, :rentalAgreement_u0), #fees = #fees + #petFee, #cityId = :cityId_u0, #mallId = :mallId_u0, #buildingId = :buildingId_u0, #storeId = :storeId_u0, #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0 REMOVE #discount ADD #tenants :tenants_u0, #warnings :warnings_u0 DELETE #tags :tags_u0, #contact :contact_u0", - "ExpressionAttributeNames": { - "#category": "category", - "#tenants": "tenants", - "#warnings": "warnings", - "#deposit": "deposit", - "#discount": "discount", - "#rentalAgreement": "rentalAgreement", - "#tags": "tags", - "#contact": "contact", - "#petFee": "petFee", - "#fees": "fees", - "#cityId": "cityId", - "#mallId": "mallId", - "#buildingId": "buildingId", - "#storeId": "storeId", - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__" - }, - "ExpressionAttributeValues": { - ":category0": "food/coffee", - ":tenants_u0": ["larry"], - ":category_u0": "food/meal", - ":warnings_u0": 1, - ":deposit_u0": 200, - ":rentalAgreement_u0": [ - { - "type": "amendment", - "detail": "no soup for you" - } - ], - ":tags_u0": ["coffee"], - ":contact_u0": ["555-345-2222"], - ":cityId_u0": "Portland", - ":mallId_u0": "EastPointe", - ":buildingId_u0": "A34", - ":storeId_u0": "LatteLarrys", - ":__edb_e___u0": "MallStore", - ":__edb_v___u0": "1" - }, - "TableName": "electro", - "Key": { - "pk": "$mallstoredirectory#cityid_portland#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_a34#storeid_lattelarrys" - }, - "ConditionExpression": "#category = :category0" -} -``` - #### Complex Data Types ElectroDB supports updating DynamoDB's complex types (`list`, `map`, `set`) with all of its Update Methods. @@ -567,53 +224,19 @@ The following are examples on how update complex attributes, using both with cha Specifying a property on a `map` attribute is expressed with dot notation. -```javascript -// via Chain Method -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .set({ "mapAttribute.mapProperty": "value" }) - .go(); - -// via Data Method -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .data(({ mapAttribute }, { set }) => set(mapAttribute.mapProperty, "value")) - .go(); -``` + #### Example 2: Removing an element from a `list` attribute Specifying an index on a `list` attribute is expressed with square brackets containing the element's index number. -```javascript -// via Chain Method -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .remove(["listAttribute[0]"]) - .go(); - -// via Data Method -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .data(({ listAttribute }, { remove }) => remove(listAttribute[0])) - .go(); -``` + #### Example 3: Adding an item to a `set` attribute, on a `map` attribute, that is an element of a `list` attribute All other complex structures are simply variations on the above two examples. -```javascript -// Set values must use the DocumentClient to create a `set` -const newSetValue = StoreLocations.client.createSet("setItemValue"); - -// via Data Method -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .add({ "listAttribute[1].setAttribute": newSetValue }) - .go(); - -await StoreLocations.update({ cityId, mallId, storeId, buildingId }) - .data(({ listAttribute }, { add }) => { - add(listAttribute[1].setAttribute, newSetValue); - }) - .go(); -``` + ### Composite @@ -699,47 +322,7 @@ const Organization = new Entity( -```javascript -const id = "00001"; -const existing = await Organization.get({ id }).go(); - -if (existing.data?.deleted) { - await Organization.update({ id: "00001" }) - .set({ deleted: false }) - .composite({ createdAt: existing.data.createdAt }) - .go(); -} -``` - -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #deleted = :deleted_u0, #gsi1sk = :gsi1sk_u0, #id = :id_u0, #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0", - "ExpressionAttributeNames": { - "#createdAt": "createdAt", - "#deleted": "deleted", - "#gsi1sk": "gsi1sk", - "#id": "id", - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__" - }, - "ExpressionAttributeValues": { - ":createdAt0": "2023-08-22T16:37:45.700Z", - ":deleted_u0": false, - ":gsi1sk_u0": "$organization_1#deleted_false#createdat_2023-08-22t16:37:45.700z", - ":id_u0": "00001", - ":__edb_e___u0": "organization", - ":__edb_v___u0": "1" - }, - "TableName": "electro", - "Key": { - "pk": "$app#id_00001", - "sk": "$organization_1" - }, - "ConditionExpression": "#createdAt = :createdAt0" -} -``` + ## Updating Composite Attributes @@ -806,12 +389,7 @@ A user could update `attr4` alone because ElectroDB is able to leverage the valu #### Example -```typescript -entity - .update({ attr1: "value1", attr2: "value2" }) - .set({ attr4: "value4" }) - .go(); -``` + #### Default Response Format @@ -823,32 +401,6 @@ entity } ``` -#### Equivalent Parameters - -```json -{ - "UpdateExpression": "SET #attr4 = :attr4_u0, #gsi1sk = :gsi1sk_u0, #attr1 = :attr1_u0, #attr2 = :attr2_u0", - "ExpressionAttributeNames": { - "#attr4": "attr4", - "#gsi1sk": "gsi1sk", - "#attr1": "attr1", - "#attr2": "attr2" - }, - "ExpressionAttributeValues": { - ":attr4_u0": "value6", - // This index was successfully built - ":gsi1sk_u0": "$update-edgecases_1#attr2_value2#attr4_value6", - ":attr1_u0": "value1", - ":attr2_u0": "value2" - }, - "TableName": "YOUR_TABLE_NAME", - "Key": { - "pk": "$service#attr1_value1", - "sk": "$entity_version#attr2_value2" - } -} -``` - > Included in the update are all attributes from the table's primary index. These values are automatically included on all updates in the event an update results in an insert. ## Execution Options diff --git a/www/src/pages/en/mutations/upsert.mdx b/www/src/pages/en/mutations/upsert.mdx index 686d7415..8dca62ff 100644 --- a/www/src/pages/en/mutations/upsert.mdx +++ b/www/src/pages/en/mutations/upsert.mdx @@ -12,26 +12,15 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; The `upsert` method is another ElectroDB exclusive method. Upsert is similar to the [put-method](/en/mutations/put) in that it will create a record if one does not exist. Unlike the `put` method, however, `upsert` perform an update if that record already exists. > _Note: `upsert` will apply a dynamodb `set` operation on all attributes provided. If an attribute is configured as `readOnly`, ElectroDB will apply a `if_not_exists` condition to prevent overwriting the existing value. The exception case is if the attribute is a composite of an index, in which case it will NOT be wrapped with `if_not_exists()`_ -```typescript -await StoreLocations.upsert({ - cityId: "Atlanta1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "BuildingA1", - unitId: "B47", - category: "food/coffee", - leaseEndDate: "2020-03-22", - rent: "4500.00", -}).go(); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Default Response Format @@ -43,53 +32,6 @@ await StoreLocations.upsert({ } ``` -## Equivalent Parameters - -```json -{ - "TableName": "StoreDirectory", - "UpdateExpression": "SET #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0, #cityId = :cityId_u0, #mallId = :mallId_u0, #storeId = :storeId_u0, #buildingId = :buildingId_u0, #unitId = :unitId_u0, #category = :category_u0, #leaseEndDate = :leaseEndDate_u0, #rent = :rent_u0, #discount = :discount_u0, #gsi1pk = :gsi1pk_u0, #gsi1sk = :gsi1sk_u0, #gsi2pk = :gsi2pk_u0, #gsi2sk = :gsi2sk_u0", - "ExpressionAttributeNames": { - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__", - "#cityId": "cityId", - "#mallId": "mallId", - "#storeId": "storeId", - "#buildingId": "buildingId", - "#unitId": "unitId", - "#category": "category", - "#leaseEndDate": "leaseEndDate", - "#rent": "rent", - "#discount": "discount", - "#gsi1pk": "gsi1pk", - "#gsi1sk": "gsi1sk", - "#gsi2pk": "gsi2pk", - "#gsi2sk": "gsi2sk" - }, - "ExpressionAttributeValues": { - ":__edb_e___u0": "MallStore", - ":__edb_v___u0": "1", - ":cityId_u0": "Atlanta1", - ":mallId_u0": "EastPointe", - ":storeId_u0": "LatteLarrys", - ":buildingId_u0": "BuildingA1", - ":unitId_u0": "B47", - ":category_u0": "food/coffee", - ":leaseEndDate_u0": "2020-03-22", - ":rent_u0": "4500.00", - ":discount_u0": "0.00", - ":gsi1pk_u0": "$mallstoredirectory#mallid_eastpointe", - ":gsi1sk_u0": "$mallstore_1#buildingid_buildinga1#unitid_b47", - ":gsi2pk_u0": "$mallstoredirectory#storeid_lattelarrys", - ":gsi2sk_u0": "$mallstore_1#leaseenddate_2020-03-22" - }, - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_buildinga1#storeid_lattelarrys" - } -} -``` - ## Add, Subtract, and Append With `upsert`, you can also perform `add`, `subtract`, `ifNotExists`, `set`, and `append` operations. These options exist as chain methods off `upsert` (similar to `update` and `patch`). In the event an upsert results in a new row, the `add` and `subtract` methods will be applied against a `0` value. @@ -98,94 +40,7 @@ With `upsert`, you can also perform `add`, `subtract`, `ifNotExists`, `set`, and ### Example -```typescript -await StoreLocations.upsert({ - cityId: "Atlanta1", - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "BuildingA1", - unitId: "B47", - category: "food/coffee", - leaseEndDate: "2020-03-22", - rent: "4500.00", -}) - .add({ deposit: 100, tenants: ["Larry David"] }) - .ifNotExists({ warnings: 0 }) - .subtract({ petFee: 250 }) - .append({ - rentalAgreement: [ - { - type: "amendment", - detail: "Larry David accepts coffee liability", - }, - ], - }) - .go(); -``` - -### Equivalent Parameters - -```json -{ - "TableName": "electro", - "UpdateExpression": "SET #__edb_e__ = :__edb_e___u0, #__edb_v__ = :__edb_v___u0, #cityId = :cityId_u0, #mallId = :mallId_u0, #storeId = :storeId_u0, #buildingId = :buildingId_u0, #unitId = :unitId_u0, #category = :category_u0, #leaseEndDate = :leaseEndDate_u0, #rent = :rent_u0, #discount = :discount_u0, #gsi1pk = :gsi1pk_u0, #gsi1sk = :gsi1sk_u0, #gsi2pk = :gsi2pk_u0, #gsi2sk = :gsi2sk_u0, #warnings = if_not_exists(#warnings, :warnings_u0), #petFee = (if_not_exists(#petFee, :petFee_default_value_u0) - :petFee_u0), #rentalAgreement = list_append(if_not_exists(#rentalAgreement, :rentalAgreement_default_value_u0), :rentalAgreement_u0) ADD #deposit :deposit_u0, #tenants :tenants_u0", - "ExpressionAttributeNames": { - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__", - "#cityId": "cityId", - "#mallId": "mallId", - "#storeId": "storeId", - "#buildingId": "buildingId", - "#unitId": "unitId", - "#category": "category", - "#leaseEndDate": "leaseEndDate", - "#rent": "rent", - "#discount": "discount", - "#gsi1pk": "gsi1pk", - "#gsi1sk": "gsi1sk", - "#gsi2pk": "gsi2pk", - "#gsi2sk": "gsi2sk", - "#deposit": "deposit", - "#tenants": "tenants", - "#warnings": "warnings", - "#petFee": "petFee", - "#rentalAgreement": "rentalAgreement" - }, - "ExpressionAttributeValues": { - ":__edb_e___u0": "MallStore", - ":__edb_v___u0": "1", - ":cityId_u0": "Atlanta", - ":mallId_u0": "EastPointe", - ":storeId_u0": "LatteLarrys", - ":buildingId_u0": "BuildingA1", - ":unitId_u0": "B47", - ":category_u0": "food/coffee", - ":leaseEndDate_u0": "2020-03-22", - ":rent_u0": "4500.00", - ":discount_u0": "0.00", - ":gsi1pk_u0": "$mallstoredirectory#mallid_eastpointe", - ":gsi1sk_u0": "$mallstore_1#buildingid_buildinga1#unitid_b47", - ":gsi2pk_u0": "$mallstoredirectory#storeid_lattelarrys", - ":gsi2sk_u0": "$mallstore_1#leaseenddate_2020-03-22", - ":deposit_u0": 100, - ":tenants_u0": ["Larry David"], - ":warnings_u0": 0, - ":petFee_u0": 250, - ":petFee_default_value_u0": 0, - ":rentalAgreement_u0": [ - { - "type": "amendment", - "detail": "Larry David accepts coffee liability" - } - ], - ":rentalAgreement_default_value_u0": [] - }, - "Key": { - "pk": "$mallstoredirectory#cityid_atlanta#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_buildinga1#storeid_lattelarrys" - } -} -``` + ## Execution Options diff --git a/www/src/pages/en/queries/batch-get.mdx b/www/src/pages/en/queries/batch-get.mdx index 41fe9b42..cd1d60b1 100644 --- a/www/src/pages/en/queries/batch-get.mdx +++ b/www/src/pages/en/queries/batch-get.mdx @@ -14,6 +14,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Provide all Table Index composite attributes in an array of objects to the `get` method to perform a BatchGet query. > When performing a BatchGet the `.params()` method will return an _array_ of parameters, rather than just the parameters for one docClient query. This is because ElectroDB BatchGet allows queries larger than the docClient's limit of 100 records @@ -30,26 +32,9 @@ It is important to consider your Table's throughput considerations when setting ## Example -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - - -```javascript -const { data, unprocessed } = await StoreLocations.get([ - { - storeId: "LatteLarrys", - mallId: "EastPointe", - buildingId: "F34", - cityId: "Atlanta1", - }, - { - storeId: "MochaJoes", - mallId: "WestEnd", - buildingId: "A21", - cityId: "Madison2", - }, -]).go({ concurrent: 1 }); // `concurrent` value is optional and default's to `1` -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Response Format @@ -60,27 +45,6 @@ const { data, unprocessed } = await StoreLocations.get([ } ``` -## Equivalent Parameters - -```json -{ - "RequestItems": { - ["YOUR_TABLE_NAME"]: { - "Keys": [ - { - "pk": "$mallstoredirectory#cityid_atlanta1#mallid_eastpointe", - "sk": "$mallstore_1#buildingid_f34#storeid_lattelarrys" - }, - { - "pk": "$mallstoredirectory#cityid_madison2#mallid_westend", - "sk": "$mallstore_1#buildingid_a21#storeid_mochajoes" - } - ] - } - } -} -``` - The `results` array are records that were returned DynamoDB as `Responses` on the BatchGet query. They will appear in the same format as other ElectroDB queries. > By default, ElectroDB will return items without concern for order. If the order returned by ElectroDB must match the order provided, the [execution option](#execution-options) `preserveBatchOrder` can be used. When enabled, ElectroDB will ensure the order returned by a batchGet will be the same as the order provided. When enabled, if a record is returned from DynamoDB as "unprocessed" ([read more here](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html)), ElectroDB will return a null value at that index. diff --git a/www/src/pages/en/queries/collection.mdx b/www/src/pages/en/queries/collection.mdx index b261bc42..a758e974 100644 --- a/www/src/pages/en/queries/collection.mdx +++ b/www/src/pages/en/queries/collection.mdx @@ -16,169 +16,21 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -Collections allow you to query across Entities. They can be used on `Service` instance. - -```javascript -const { DynamoDBClient } = require("@aws-sdk/client-dynamodb"); -const { DynamoDBDocumentClient } = require("@aws-sdk/lib-dynamodb"); -const table = "projectmanagement"; -const client = DynamoDBDocumentClient.from(new DynamoDBClient({})); +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; -const employees = new Entity( - { - model: { - entity: "employees", - version: "1", - service: "taskapp", - }, - attributes: { - employeeId: { - type: "string", - }, - organizationId: { - type: "string", - }, - name: { - type: "string", - }, - team: { - type: ["jupiter", "mercury", "saturn"], - }, - }, - indexes: { - staff: { - pk: { - field: "pk", - composite: ["organizationId"], - }, - sk: { - field: "sk", - composite: ["employeeId"], - }, - }, - employee: { - collection: "assignments", - index: "gsi2", - pk: { - field: "gsi2pk", - composite: ["employeeId"], - }, - sk: { - field: "gsi2sk", - composite: [], - }, - }, - }, - }, - { client, table }, -); +Collections allow you to query across Entities. They can be used on `Service` instance. -const tasks = new Entity( - { - model: { - entity: "tasks", - version: "1", - service: "taskapp", - }, - attributes: { - taskId: { - type: "string", - }, - employeeId: { - type: "string", - }, - projectId: { - type: "string", - }, - title: { - type: "string", - }, - body: { - type: "string", - }, - }, - indexes: { - project: { - pk: { - field: "pk", - composite: ["projectId"], - }, - sk: { - field: "sk", - composite: ["taskId"], - }, - }, - assigned: { - collection: "assignments", - index: "gsi2", - pk: { - field: "gsi2pk", - composite: ["employeeId"], - }, - sk: { - field: "gsi2sk", - composite: [], - }, - }, - }, - }, - { client, table }, -); +> The **Entities** and **Service** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -const TaskApp = new Service({ employees, tasks }); -``` + Available on your Service are two objects: `entites` and `collections`. Entities available on `entities` have the same capabilities as they would if created individually. When a Model added to a Service with `join` however, its Collections are automatically added and validated with the other Models joined to that Service. These Collections are available on `collections`. ### Example -```javascript -const results = await TaskApp.collections - .assignments({ employeeId: "JExotic" }) - .go(); -``` - -### Equivalent Parameters - -``` -{ - TableName: 'projectmanagement', - ExpressionAttributeNames: { '#pk': 'gsi2pk', '#sk1': 'gsi2sk' }, - ExpressionAttributeValues: { ':pk': '$taskapp_1#employeeid_joeexotic', ':sk1': '$assignments' }, - KeyConditionExpression: '#pk = :pk and begins_with(#sk1, :sk1)', - IndexName: 'gsi3' -} -``` - -### Example - Collections do not have the same `query` functionality and as an Entity, though it does allow for inline filters like an Entity. The `attributes` available on the filter object include **all** attributes across entities. -```typescript -const results - await TaskApp.collections - .assignments({employee: "CBaskin"}) - .where(({ project }, { notExists, contains }) => ` - ${notExists(project)} OR ${contains(project, "murder")} - `) - .go(); -``` - -### Equivalent Parameters - -```javascript -{ - TableName: 'projectmanagement', - ExpressionAttributeNames: { '#project': 'project', '#pk': 'gsi2pk', '#sk1': 'gsi2sk' }, - ExpressionAttributeValues: { - ':project1': 'murder', - ':pk': '$taskapp_1#employeeid_carolbaskin', - ':sk1': '$assignments' - }, - KeyConditionExpression: '#pk = :pk and begins_with(#sk1, :sk1)', - IndexName: 'gsi2', - FilterExpression: 'attribute_not_exists(#project) OR contains(#project, :project1)' -} -``` + ## Execution Options diff --git a/www/src/pages/en/queries/filters.mdx b/www/src/pages/en/queries/filters.mdx index 7291632e..4f0bbe83 100644 --- a/www/src/pages/en/queries/filters.mdx +++ b/www/src/pages/en/queries/filters.mdx @@ -11,6 +11,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Building thoughtful indexes can make queries simple and performant, though sometimes you need to apply further filters to your query. ## FilterExpressions @@ -19,40 +21,7 @@ Below demonstrates how to add a `FilterExpression` to Dynamo's DocumentClient di ### Example -```typescript -animals.query - .exhibit({ habitat: "Africa" }) - .where( - ({ isPregnant, offspring }, { exists, eq }) => ` - ${eq(isPregnant, true)} OR ${exists(offspring)} - `, - ) - .go(); -``` - -### Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "zoo_manifest", - "ExpressionAttributeNames": { - "#isPregnant": "isPregnant", - "#offspring": "offspring", - "#pk": "gsi1pk", - "#sk1": "gsi1sk" - }, - "ExpressionAttributeValues": { - ":isPregnant0": true, - ":pk": "$zoo#habitat_africa", - ":sk1": "$animals_1#enclosure_" - }, - "IndexName": "gsi1pk-gsi1sk-index", - "FilterExpression": "#isPregnant = :isPregnant0 OR attribute_exists(#offspring)" -} -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?ssl=91&ssc=8&pln=86&pc=1#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MDVCc5G1MAEqSwCgAYtA5MEwAuklecFAEAI4ZwHPcFlwZBNMJW94oZKwQYhlz5TNwVTXMElCDAObx1omhgSBypzMXjtd3D15zi8sCKtzlANjsnl4UJIQJd8h9MNUvmkUPdQhDrKxJBIhkD3l5PldkaivOjDJjsUCAEL+SxnAlMb4owQknbcaS3IgQDK5WnwxHMXiudjSX5wUlwYBiAAKc1uULQeOs9MFEGFKGZjx2JVgBTZNLh+IRlwZRI121C3GABBgisqRq+1tFhgwBBAPJNNyZaJ2EBoNDEYE9t1t53tzFYkvGO2d2TdIbt-KYrzATusgYg1VgVp5BrOKmhsIqefpjOJefN5cM2pgusk+qLdLDHp+Dc1rcMKAg2XjfONpbNecoraHZxHbYrEpQpgAHjlFQGOKAfCGwABrHuGGhW1jAphr1NeETgQ4uupMF5ySbRsXXsTr3nlrdsXd3g-WI+QSLduD1KEwyZFmOE6GAQ04FOkGAhoMM6OLckQxGuAC0cHADEd6IdBoGpmuG60Nuu4oQhq5voYH4nt+9RFCUMApFegG3veuZnE+O6wfBr7XoeDCfqeP4sHsBxHHMPTkjAOLcABo7elYTyJIgNG8OwjguBAAD6rwyDQYxMJQACUADcQgXvIAB0ixEJgVgmaB4HUXoVGlDa7TNGQrR6VZagFEQBA6HokoygQcrSDAuC+v6gZ3HJCCgZGYi4AselKAAfHAAAGoQACTRfMOj+bK8ohSCGy6dQADyvRwFlMUSGIOhhQGQYlVYqW6VZtwQDoBkCEAA) + ## Where Clause @@ -64,72 +33,23 @@ The `where()` method allow you to write a `FilterExpression` or `ConditionExpres #### A single filter expression -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where((attr, op) => op.eq(attr.dangerous, true)) - .go(); -``` + #### A single filter expression with destructuring -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where(({ dangerous }, { eq }) => eq(dangerous, true)) - .go(); -``` + #### Multiple filter expressions -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - (attr, op) => ` - ${op.eq(attr.dangerous, true)} AND ${op.notExists(attr.lastFed)} - `, - ) - .go(); -``` + #### Chained usage (implicit AND) -```typescript -animals.query - .habitats({ habitat: "Africa", enclosure: "5b" }) - .where((attr, op) => ` - ${op.eq(attr.dangerous, true)} OR ${op.notExists(attr.lastFed)} - `) - .where(({ birthday }, { between }) => { - const today = Date.now(); - const lastMonth = today - 1000 * 60 * 60 * 24 * 30; - return between(birthday, lastMonth, today); - }) - .go(); -``` + #### "dynamic" filtering -```typescript -type GetAnimalOptions = { - habitat: string; - keepers: string[]; -}; - -function getAnimals(options: GetAnimalOptions) { - const { habitat, keepers } = options; - return animals.query.exhibit({ habitat }) - .where(({ keeper }, { eq }) => { - return keepers.map((name) => eq(keeper, name)).join(' AND '); - }).go() -} - -const { data, cursor } = await getAnimals({ - habitat: "RainForest", - keepers: ["Joe Exotic", "Carol Baskin"], -}); -``` + ## Operations @@ -170,16 +90,7 @@ The `name()` function allows you to create a reference to an attribute's name, w This example demonstrates how you might find animals that were last fed by someone other than their "keeper". -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ lastFedBy, keeper }, { name }) => ` - ${name(lastFedBy)} != ${name(keeper)} - `, - ) - .go(); -``` + #### Value @@ -187,16 +98,7 @@ The `value()` function can be paired with `name()` as convenience when building This example shows how you can implement the `eq` operation without using the ElectroDB `eq` function -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ keeper }, { name, value, eq }) => ` - ${name(keeper)} = ${value(keeper, "Tiger King")} - `, - ) - .go(); -``` + #### Escape @@ -204,16 +106,7 @@ The `escape()` method allows you to provide any primitive to an expression witho This example shows how you might use escape to apply a filter against the `size()` of an attribute. -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - ({ diet }, { size, escape }) => ` - ${size(diet)} > ${escape(2)} - `, - ) - .go(); -``` + #### Field @@ -221,16 +114,7 @@ The `field()` method allows you to provide and reference a field value that is n You can use both `escape()` and `field()` to template _any_ filter that DynamoDB supports. -```typescript -animals.query - .exhibit({ habitat: "Africa", enclosure: "5b" }) - .where( - (_, { field, escape }) => ` - contains(${field("gsi1sk")}, ${escape("value")}) - `, - ) - .go(); -``` + ## Advanced Usage @@ -242,69 +126,14 @@ The following are examples on how to filter on complex attributes: #### Filtering on a `map` attribute -```typescript -animals.query - .farm({ habitat: "Africa" }) - .where(({ veterinarian }, { eq }) => eq(veterinarian.name, "Herb Peterson")) - .go(); -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MDVCc5G1MAEqSwCgAYtA5MEwAuklecFAEAI4ZwHPcFlwZBNMJW94oZKwQYhlz5TNwVTXMElCDAObx1omhgSBypzMXjtd3D15zi8sCKtzlANjsnl4UJIQJd8h9MNUvmkUPdQhDrNxpLciBAMrlLGdPsxeK52NJfnB0YZgGIAApzW5QtDvLxEpgkiBklCCLxUuAlWAFTH+AnwxFXZGo3k7bjAAgwFnWNm2cY7anZED4pjfFE8x47CA0GhiMA3FGKyoIy5MVg01UVOAYAiai1Kq2OV5gCleU0QaqwOX4uFnQxQmGuwnuiVmqUh7YOrwCmBCyQi4Nx85R7WSvVxvlnFAQbIRsXWnWxvMJykOyhonbhbJmyQ3aSutme71wX3+9A5Eth2FVy3i7Mx3MzfM2apkYByLAl4dlnNV2tnVf60KsSQSIZAttZ8vjvlbndAgBCaYdyuX0s325gSGIcgyKSiKH3I8PdbvEkfz9fogXh+S5jmiVjooMpgAB59qKhgmhwoA+K6YAANYLrQcqsMCTBoZ2XgiOAhxOnUTAvHIkxqpSVFiOhcEhjQWE4bR+HWIRkCRMWcD1AOkw1t+XgEFBBTpBgrqQUJji3JEMRoQAtNJwAxLRckSVBnZoRhjFsDhimyahrGGOxxFcfURQlDAKSUTWNF0emZzadhUkySxVEEQwHEkdxLB7AcRxzD0J4wLu3B8WuAnUQIiSIJZvDsI4LgQAA+q8Mg0GMTCUAAlAA3EI5HyAAdIsRCYFYhVCSJFl6OZpQKu0zRkK02XlWoBREAQOh6A2RCDM2s4oNFCALNlSgAHzePMOg9U2LYoIVA64EwAASRC8HAtLyhEohMFlWXlbcEA6PtAhAA) + #### Filtering on an element in a `list` attribute -```typescript -animals.query - .exhibit({ habitat: "Tundra" }) - .where(({ offspring }, { eq }) => eq(offspring[0].name, "Blitzen")) - .go(); -``` - -[![Try it out!](https://img.shields.io/badge/electrodb-try_out_this_example_›-%23f9bd00?style=for-the-badge&logo=amazondynamodb&labelColor=1a212a)](https://electrodb.fun/?ssl=106&ssc=8&pln=103&pc=1#code/JYWwDg9gTgLgBAbwKIDsbBgTwDRwMoCmUAbsAMYEC+cAZlBCHAEQEA2BZM9AJgEZMAoAWQgoAzvACGKUJNZi4AXjgoCAdzip0WABQIBcOCAjc2ALkQHD1sUVIULTAF4QITbFetwCaDJkfSsvLuntbERGLAoo4AjCGGlB6GkjBcwLwArjAEYhb6XgAWkrwYKXmhhlhgBBYA2kwAgnTkku7MACoZKNxQrbhMAEqSwCgAYtA5MEwAuklecFAEAI4ZwIvcFlwZBHMJu94oZKwQYhmL5fNwVTXMElAjAObx1omhgSByF-PXjnePz15Fis1gQNlcoNt9q8vChJCAbvlvphqr80ignqFodZuNIHkQIBlcpZLj9mLxXOxpAC4FjDMAxAAFRYPWFoL5eUlMckQSkoQReWlwEqwAo4-zEpEo25ojEC-bcYAEGDs6yc2xTfZ07IgIlMP7o-kvfYQGg0MRge7olWVZE3JisekaipwDAEHXW1W2xwfMDUrwWiDVWCKomIy6GWHwj0kr3Sy2y8N7Z1eYUwUWScVhxNXWN6mWGxOCy4oCDZaOSu36hOF5M052UTH7cLZS2Se7SD2cn1+uABoPoHLlyMI2s2qV5+MF+ZFmzVMjAORYctjyv52sNy4bo2hViSCSjUGd3NVqeC3f70EAIUzzrVa7lO73MCQxDkGRSURQR-HJ8bj4kL5vh+ojXt+q6TpiVhYiMpgAB6DhKhjmhwoA+B6YAANbLrQiqsGCTCYT2XgiOAJyunUTDvHIMyajStFiFhiHhjQuH4QxRHWCRkCRGWcD1MOMz1n+XgELBBTpBgHowaJjgPJEMSYQAtHJwAxAxinSbBPaYdhLFsPhKkKRhHGGFxZG8fURQlDAKQ0fW9GMVmlx6XhsnyextHEQw3HkXxLCHMcpyLG09pPge3CCZuwl0QIiSIDZvDsI4LgQAA+h8Mg0JMTCUAAlAA3EIVHyAAdCsRCYFYJWieJ1l6FZpTKh0XQ9K0eVVWoBREAQOh6CaZoWo8cUIMseVKAAfN4Sw6P15rxrUAAM0wlcO-SXg6MBOD4TC5blVUPBAOi5UAA) + ### Multiple Where Clauses It is possible to include chain multiple where clauses. The resulting FilterExpressions (or ConditionExpressions) are concatenated with an implicit `AND` operator. -```typescript -let MallStores = new Entity(model, { table: "StoreDirectory" }); -let stores = await MallStores.query - .leases({ mallId: "EastPointe" }) - .between({ leaseEndDate: "2020-04-01" }, { leaseEndDate: "2020-07-01" }) - .where( - ({ rent, discount }, { between, eq }) => ` - ${between(rent, "2000.00", "5000.00")} AND ${eq(discount, "1000.00")} - `, - ) - .where( - ({ category }, { eq }) => ` - ${eq(category, "food/coffee")} - `, - ) - .go(); -``` - -```json -{ - "TableName": "StoreDirectory", - "ExpressionAttributeNames": { - "#rent": "rent", - "#discount": "discount", - "#category": "category", - "#pk": "idx2pk", - "#sk1": "idx2sk" - }, - "ExpressionAttributeValues": { - ":rent1": "2000.00", - ":rent2": "5000.00", - ":discount1": "1000.00", - ":category1": "food/coffee", - ":pk": "$mallstoredirectory_1#mallid_eastpointe", - ":sk1": "$mallstore#leaseenddate_2020-04-01#storeid_", - ":sk2": "$mallstore#leaseenddate_2020-07-01#storeid_" - }, - "KeyConditionExpression": "#pk = :pk and #sk1 BETWEEN :sk1 AND :sk2", - "IndexName": "idx2", - "FilterExpression": "(#rent between :rent1 and :rent2) AND (#discount = :discount1 AND #category = :category1)" -} -``` + diff --git a/www/src/pages/en/queries/find.mdx b/www/src/pages/en/queries/find.mdx index 533beb49..01b2cfd6 100644 --- a/www/src/pages/en/queries/find.mdx +++ b/www/src/pages/en/queries/find.mdx @@ -12,22 +12,17 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + DynamoDB offers three methods to query records: `get`, `query`, and `scan`. In ElectroDB, there is a fourth and fifth type: `find` and `match`. Unlike `get` and `query`, the `find` method does not require you to provide keys, but under the covers it will leverage the attributes provided to choose the best index to query on. Provide the `find` method with all properties known to match a record and ElectroDB will generate the most performant query it can to locate the results. This can be helpful with highly dynamic querying needs. If an index cannot be satisfied with the attributes provided, `scan` will be used as a last resort. > The Find method is similar to the Match method with one exception: The attributes you supply directly to the `.find()` method will only be used to identify and fulfill your index access patterns. Any values supplied that do not contribute to a composite key will not be applied as query filters. Furthermore, if the values you provide do not resolve to an index access pattern, then a table scan will be performed. Use the `where()` chain method to further filter beyond keys, or use [Match](/en/queries/match) for the convenience of automatic filtering based on the values given directly to that method. The Find method is useful when the index chosen does not matter or is not known. If your secondary indexes do not contain all attributes then this method might not be right for you. The mechanism that picks the best index for a given payload is subject to improvement and change without triggering a breaking change release version. -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. - - -```typescript -await StoreLocations.find({ - mallId: "EastPointe", - buildingId: "BuildingA1", -}).go(); -``` + ## Response Format @@ -38,28 +33,6 @@ await StoreLocations.find({ } ``` -## Equivalent Parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "StoreDirectory", - "ExpressionAttributeNames": { - "#mallId": "mallId", - "#buildingId": "buildingId", - "#pk": "gsi1pk", - "#sk1": "gsi1sk" - }, - "ExpressionAttributeValues": { - ":mallId1": "EastPointe", - ":buildingId1": "BuildingA1", - ":pk": "$mallstoredirectory#mallid_eastpointe", - ":sk1": "$mallstore_1#buildingid_buildinga1#unitid_" - }, - "IndexName": "gsi1pk-gsi1sk-index" -} -``` - ## Execution Options import PartialExample from "../../../partials/query-options.mdx"; diff --git a/www/src/pages/en/queries/match.mdx b/www/src/pages/en/queries/match.mdx index 1bc6b6b9..1621efdf 100644 --- a/www/src/pages/en/queries/match.mdx +++ b/www/src/pages/en/queries/match.mdx @@ -12,24 +12,17 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Match is a convenience method based off of ElectroDB's [find](/en/queries/find) method. Similar to Find, Match does not require you to provide keys, but under the covers it will leverage the attributes provided to choose the best index to query on. > The Match method is useful when the index chosen does not matter or is not known. If your secondary indexes do not contain all attributes then this method might not be right for you. The mechanism that picks the best index for a given payload is subject to improvement and change without triggering a breaking change release version. Match differs from [Find](/en/queries/find) in that it will also include all supplied values into a query filter. -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. - - -```typescript -await StoreLocations.match({ - mallId: "EastPointe", - buildingId: "BuildingA1", - leaseEndDate: "2020-03-22", - rent: "1500.00", -}).go(); -``` + ## Response Format @@ -40,33 +33,6 @@ await StoreLocations.match({ } ``` -## Equivalent parameters - -```json -{ - "KeyConditionExpression": "#pk = :pk and begins_with(#sk1, :sk1)", - "TableName": "StoreDirectory", - "ExpressionAttributeNames": { - "#mallId": "mallId", - "#buildingId": "buildingId", - "#leaseEndDate": "leaseEndDate", - "#rent": "rent", - "#pk": "gsi1pk", - "#sk1": "gsi1sk" - }, - "ExpressionAttributeValues": { - ":mallId1": "EastPointe", - ":buildingId1": "BuildingA1", - ":leaseEndDate1": "2020-03-22", - ":rent1": "1500.00", - ":pk": "$mallstoredirectory#mallid_eastpointe", - ":sk1": "$mallstore_1#buildingid_buildinga1#unitid_" - }, - "IndexName": "gsi1pk-gsi1sk-index", - "FilterExpression": "#mallId = :mallId1 AND#buildingId = :buildingId1 AND#leaseEndDate = :leaseEndDate1 AND#rent = :rent1" -} -``` - ## Execution Options import PartialExample from "../../../partials/query-options.mdx"; diff --git a/www/src/pages/en/queries/pagination.mdx b/www/src/pages/en/queries/pagination.mdx index 54a544a5..8db6b3ea 100644 --- a/www/src/pages/en/queries/pagination.mdx +++ b/www/src/pages/en/queries/pagination.mdx @@ -12,9 +12,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; ## Cursors @@ -26,42 +24,9 @@ The terminal method `go()` accepts a `cursor` when executing a `query` or `scan` ### Entities -```typescript -const results1 = await MallStores.query.leases({ mallId }).go(); // no "cursor" passed to `.go()` - -const results2 = await MallStores.query.leases({ mallId }) - .go({ cursor: results1.cursor }); // Paginate by querying with the "cursor" from your first query -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against. The first query runs without a `cursor`; the second passes the `cursor` returned by the first to continue paginating. -```json results2 -{ - "cursor": "...", - "data": [ - { - "mall": "3010aa0d-5591-4664-8385-3503ece58b1c", - "leaseEnd": "2020-01-20", - "sector": "7d0f5c19-ec1d-4c1e-b613-a4cc07eb4db5", - "store": "MNO", - "unit": "B5", - "id": "e0705325-d735-4fe4-906e-74091a551a04", - "building": "BuildingE", - "category": "food/coffee", - "rent": "0.00" - }, - { - "mall": "3010aa0d-5591-4664-8385-3503ece58b1c", - "leaseEnd": "2020-01-20", - "sector": "7d0f5c19-ec1d-4c1e-b613-a4cc07eb4db5", - "store": "ZYX", - "unit": "B9", - "id": "f201a1d3-2126-46a2-aec9-758ade8ab2ab", - "building": "BuildingI", - "category": "food/coffee", - "rent": "0.00" - } - ] -} -``` + ### Services @@ -84,25 +49,9 @@ type GoResults = { The execution option `count` allows you to specify a specific number of items to be returned. This is often a difficult task with DynamoDB because queries do not always return a consistent number of items. If your query includes filters, and requires pagination, it can be even harder to return a specific number of items reliably. When using `count`, ElectroDB will paginate your query against DynamoDB until the number of items matches the supplied `count`, create a custom cursor, and return the items found. This option is recommend for queries with numerous and/or strict attribute filters where end-user or external pagination is necessary. -```typescript - -type GetItemsOptions = { - mallId: string; - cursor: string; - limit?: number; -} - -async function getLeases(options: GetItemsOptions) { - const { mallId, cursor, limit } = options; - - if (limit < 1 || limit >= 200) { - throw new Error('Limit must be at least 1 and at most 200'); - } +> The **Entity** and **Table Definition** tabs show the setup this example runs against. - return MallStores.query.leases({ mallId }) - .go({ cursor, count: limit }); -} -``` + ### Pages The execution option `pages` allows you to automatically perform multiple queries against DynamoDB. By default, ElectroDB queries will perform one request against DynamoDB. With `pages`, you can specify the number of queries you'd like to occur under the hood before returning. Furthermore, if you would like ElectroDB to return all results for a given query (i.e., exhausting pagination for a given query automatically) you can use the option `{pages: "all"}`. Note that while option is convenient, it may not performant for some workflows. @@ -111,28 +60,6 @@ The execution option `pages` allows you to automatically perform multiple querie Simple pagination example: -```typescript -// EntityItem is the type for a returned item -// QueryResponse is the type for the full electrodb response to a query -import { EntityItem, QueryResponse } from "electrodb"; - -// (your entity) -import { users } from "./entities"; - -type UserItem = EntityItem; -type UserQueryResponse = QueryResponse; - -async function getTeamMembers(team: string) { - let members: UserItem[] = []; - let cursor = null; - do { - const results: UserQueryResponse = await users.query - .members({ team }) - .go({ cursor }); - members = [...members, ...results.data]; - cursor = results.cursor; - } while (cursor !== null); - - return members; -} -``` \ No newline at end of file +> The **Entity** and **Table Definition** tabs show the setup this example runs against. Because the mocked query always returns an empty page, this loop exits after a single iteration below — against a real table it continues until `cursor` is `null`. + + \ No newline at end of file diff --git a/www/src/pages/en/queries/query.mdx b/www/src/pages/en/queries/query.mdx index 2a6474ed..a5c44040 100644 --- a/www/src/pages/en/queries/query.mdx +++ b/www/src/pages/en/queries/query.mdx @@ -12,6 +12,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Queries are the _**most efficient**_ way to retrieve items from DynamoDB, which is why it is recommended that you be very thoughtful when modeling your indexes. import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; @@ -34,73 +36,33 @@ While ElectroDB does abstract out the formatting of your index keys, you will st #### Good: Includes at least the PK -```typescript -await StoreLocations.query - .stores({ - cityId: "Atlanta1", - mallId: "EastPointe", - }) - .go(); -``` + #### Good: Includes at least the PK, and the first SK attribute -```typescript -await StoreLocations.query - .stores({ - cityId: "Atlanta1", - mallId: "EastPointe", - buildingId: "f34", - }) - .go(); -``` + #### Good: Includes at least the PK, and all the SK attributes -```typescript -await StoreLocations.query - .stores({ - cityId: "Atlanta1", - mallId: "EastPointe", - storeId: "LatteLarrys", - buildingId: "f34", - }) - .go(); -``` + #### Bad: No PK composite attributes specified With DynamoDB, queries require at least a Partition Key is provided. Without specifying the partition key composite attributes (`cityId` and `mallId`), ElectroDB is unable to build a key to supply to DynamoDB. This example will throw. -```typescript -await StoreLocations.query.stores().go(); -``` + #### Bad: Not All PK Composite Attributes included The ElectroDB cannot form a Partition Key without a `cityId`, this example will throw. -```typescript -await StoreLocations.query - .stores({ - mallId: "EastPointe", - }) - .go(); -``` + #### Bad: Composite Attributes not included in order This example will not throw, but will it ignore `unitId` because `storeId` was not supplied ElectroDB cannot logically build a valid sort key string without the all values being provided left to right. -```typescript -await StoreLocations.query - .stores({ - cityId: "Atlanta1", - mallId: "EastPointe", - unitId: "B24", - }) - .go(); -``` + ### Using composite attributes to make hierarchical keys @@ -161,21 +123,13 @@ The following examples will use the following Access Pattern definition for `uni The names you have given to your indexes on your entity model/schema express themselves as "Access Pattern" methods on your Entity's `query` object: -```typescript -// Example #1, access pattern `units` -StoreLocations.query.units({ mallId, buildingId }).go(); -// -----------------------^^^^^^^^^^^^^^^^^^^^^^ -``` + Data passed to the Access Pattern method is considered to be full, known, data. In the above example, we are saying we _know_ the `mallId`, `buildingId` and `unitId`. Alternatively, if you only know the start of a piece of data, use .begins(): -```typescript -// Example #2 -StoreLocations.query.units({ mallId }).begins({ buildingId }).go(); -// ---------------------------------^^^^^^^^^^^^^^^^^^^^^ -``` + Data passed to the .begins() method is considered to be partial data. In the second example, we are saying we _know_ the `mallId` and `buildingId`, but only know the beginning of `unitId`. @@ -196,91 +150,39 @@ The following examples use the Entity and table configuration defined in the sec ### Lease Agreements by StoreId -```typescript -await StoreLocations.query.leases({ storeId: "LatteLarrys" }).go(); -``` + ### Lease Agreement by StoreId for March 22nd 2020 -```typescript -await StoreLocations.query - .leases({ - storeId: "LatteLarrys", - leaseEndDate: "2020-03-22", - }) - .go(); -``` + ### Lease agreements by StoreId for 2020 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .begins({ leaseEndDate: "2020-00-00" }) - .go(); -``` + ### Lease Agreements by StoreId after March 2020 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .gt({ leaseEndDate: "2020-04-00" }) - .go(); -``` + ### Lease Agreements by StoreId after, and including, March 2020 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .gte({ leaseEndDate: "2020-03-00" }) - .go(); -``` + ### Lease Agreements by StoreId before 2021 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .lt({ leaseEndDate: "2021-00-00" }) - .go(); -``` + ### Lease Agreements by StoreId before February 2021 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .lte({ leaseEndDate: "2021-02-00" }) - .go(); -``` + ### Lease Agreements by StoreId between 2010 and 2020 -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .between({ leaseEndDate: "2010-00-00" }, { leaseEndDate: "2020-99-99" }) - .go(); -``` + ### Lease Agreements by StoreId after, and including, 2010 in the city of Atlanta and category containing food -```typescript -await StoreLocations.query - .leases({ storeId: "LatteLarrys" }) - .gte({ leaseEndDate: "2010-00-00" }) - .where( - (attr, op) => ` - ${op.eq(attr.cityId, "Atlanta1")} AND ${op.contains( - attr.category, - "food", - )} - `, - ) - .go(); -``` + ## Comparison Queries When performing comparison queries (e.g. `gt`, `gte`, `lte`, `lt`, `between`) it is often necessary to add additional filters. Understanding how a comparison query will impact the items returned can be challenging due to the unintuitive nature of sorting and multi-composite attribute Sort Keys. diff --git a/www/src/pages/en/queries/scan.mdx b/www/src/pages/en/queries/scan.mdx index cc70c82e..8c5ecf26 100644 --- a/www/src/pages/en/queries/scan.mdx +++ b/www/src/pages/en/queries/scan.mdx @@ -12,30 +12,17 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + When scanning for rows, you can use filters the same as you would any query. For more information on filters, see the [Filters](/en/queries/filters) section. The `scan` method will be scoped to your Entity. This means your results will only include records that match the Entity defined in the model. > Fun Fact! Scanning DynamoDB is one of the least effective mechanisms for retrieving items from DynamoDB. -import ExampleSetup from "../../../partials/entity-query-example-setup.mdx"; - - +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -```typescript -await StoreLocations.scan - .where( - ({ category }, { eq }) => ` - ${eq(category, "food/coffee")} OR ${eq(category, "spite store")} - `, - ) - .where( - ({ leaseEndDate }, { between }) => ` - ${between(leaseEndDate, "2020-03", "2020-04")} - `, - ) - .go(); -``` + ## Response Format @@ -46,40 +33,11 @@ await StoreLocations.scan } ``` -## Equivalent Parameters - -```json -{ - "TableName": "StoreDirectory", - "ExpressionAttributeNames": { - "#category": "category", - "#leaseEndDate": "leaseEndDate", - "#pk": "pk", - "#sk": "sk", - "#__edb_e__": "__edb_e__", - "#__edb_v__": "__edb_v__" - }, - "ExpressionAttributeValues": { - ":category_w1": "food/coffee", - ":category_w2": "spite store", - ":leaseEndDate_w1": "2020-03", - ":leaseEndDate_w2": "2020-04", - ":pk": "$mallstoredirectory#cityid_", - ":sk": "$mallstore_1#buildingid_", - ":__edb_e__": "MallStore", - ":__edb_v__": "1" - }, - "FilterExpression": "begins_with(#pk, :pk) AND #__edb_e__ = :__edb_e__ AND #__edb_v__ = :__edb_v__ AND begins_with(#sk, :sk) AND (#category = :category_w1 OR #category = :category_w2) AND (#leaseEndDate between :leaseEndDate_w1 and :leaseEndDate_w2)" -} -``` - ## Scanning an Index You can also scan a specific index by using the access pattern as a method on the scan operation: -```typescript -await StoreLocations.scan.units.go(); -``` + ### Use Cases diff --git a/www/src/pages/en/queries/transact-get.mdx b/www/src/pages/en/queries/transact-get.mdx index 93b587bc..f7ed2691 100644 --- a/www/src/pages/en/queries/transact-get.mdx +++ b/www/src/pages/en/queries/transact-get.mdx @@ -12,9 +12,7 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -import TableDefinition from "../../../partials/table-definition.mdx"; - - +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; In cases where your data is frequently changing, but you need to ensure that results retrieved from multiple `get` where not modified during retrieval, you can reach for `transaction.get()`. @@ -22,14 +20,11 @@ In cases where your data is frequently changing, but you need to ensure that res To perform `get` transactions with ElectroDB you will first need to create a [Service](/en/modeling/services). Available on the `Service` exist two methods `transaction.get()` and `transaction.write()`. These methods accept a callback function which is then provided with the entities of the service, and should return an array of queries. Creating a `get` query within a transaction is identical to performing `get` directly on an entity, only instead of terminating your query with a `.go()` or `.params()` you use `.commit()` instead. -```typescript -await yourService.transaction - .get(({ entity1, entity2 }) => [ - entity1.get({ prop1: "value1", prop2: "value2" }).commit(), - entity2.get({ prop1: "value2", prop2: "value3" }).commit(), - ]) - .go(); -``` +The example below uses a `Service` called `workforce` that joins together an `employee` entity and an `office` entity so that an employee's record and their office's record can be retrieved together, atomically. + +> The **Entities** and **Service** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ### TransactionItem diff --git a/www/src/pages/en/recipes/include-projection-gsi.mdx b/www/src/pages/en/recipes/include-projection-gsi.mdx index 4c7a9267..4c98f80d 100644 --- a/www/src/pages/en/recipes/include-projection-gsi.mdx +++ b/www/src/pages/en/recipes/include-projection-gsi.mdx @@ -16,149 +16,11 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -The `INCLUDE` projection type allows you to specify exactly which attributes are included in a Global Secondary Index. This provides a balance between the minimal storage of `KEYS_ONLY` and the complete data access of `ALL` projections. With `INCLUDE` projections, you can optimize your indexes by including only the attributes you need for your queries. +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; -## Example Setup - -
-

Example Setup

-
- Table Definition - - ```json - { - "TableName": "electro", - "KeySchema": [ - { - "AttributeName": "pk", - "KeyType": "HASH" - }, - { - "AttributeName": "sk", - "KeyType": "RANGE" - } - ], - "AttributeDefinitions": [ - { - "AttributeName": "pk", - "AttributeType": "S" - }, - { - "AttributeName": "sk", - "AttributeType": "S" - }, - { - "AttributeName": "gsi1pk", - "AttributeType": "S" - }, - { - "AttributeName": "gsi1sk", - "AttributeType": "S" - } - ], - "GlobalSecondaryIndexes": [ - { - "IndexName": "gsi1pk-gsi1sk-index", - "KeySchema": [ - { - "AttributeName": "gsi1pk", - "KeyType": "HASH" - }, - { - "AttributeName": "gsi1sk", - "KeyType": "RANGE" - } - ], - "Projection": { - "ProjectionType": "INCLUDE", - "NonKeyAttributes": ["name", "status", "createdAt", "__edb_e__", "__edb_v__"] - } - } - ], - "BillingMode": "PAY_PER_REQUEST" - } - ``` - -
- -
- Example Entity - - ```typescript - import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; - import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; - import { Entity } from 'electrodb'; - - const client = DynamoDBDocumentClient.from(new DynamoDBClient({})); - - const table = 'electro'; - - const tasks = new Entity({ - model: { - entity: 'tasks', - version: '1', - service: 'taskapp' - }, - attributes: { - taskId: { - type: 'string' - }, - projectId: { - type: 'string' - }, - name: { - type: 'string' - }, - description: { - type: 'string' - }, - status: { - type: ['open', 'in-progress', 'closed'] as const, - default: 'open' - }, - priority: { - type: 'number' - }, - createdAt: { - type: 'number', - default: () => Date.now() - }, - updatedAt: { - type: 'number', - watch: '*', - set: () => Date.now() - } - }, - indexes: { - tasks: { - pk: { - field: 'pk', - composite: ['projectId'] - }, - sk: { - field: 'sk', - composite: ['taskId'] - } - }, - statusIndex: { - index: 'gsi1pk-gsi1sk-index', - projection: ['name', 'status', 'createdAt'], - pk: { - field: 'gsi1pk', - composite: ['status'], - }, - sk: { - field: 'gsi1sk', - composite: ['createdAt'], - } - } - } - }, { table, client }); - ``` - -
+The `INCLUDE` projection type allows you to specify exactly which attributes are included in a Global Secondary Index. This provides a balance between the minimal storage of `KEYS_ONLY` and the complete data access of `ALL` projections. With `INCLUDE` projections, you can optimize your indexes by including only the attributes you need for your queries. -
+> The **Entity** and **Table Definition** tabs on each example below show the setup used throughout this page: a `tasks` entity with a `statusIndex` GSI projecting only `name`, `status`, and `createdAt`. ## Using the Project Property @@ -187,62 +49,33 @@ When querying an index with an `INCLUDE` projection, you can only access the att ### Basic Querying -```typescript -// Only returns the projected attributes: name, status, createdAt -const { data, cursor } = await tasks.query - .statusIndex({ status: "open" }) - .go(); - -// data will only contain: { name: string, status: string, createdAt: number }[] -``` + ### Filtering on Projected Attributes You can only filter on attributes that are included in the projection: -```typescript -// ✅ This works - filtering on projected attributes -const { data } = await tasks.query - .statusIndex({ status: "open" }) - .where(({ name }, { eq }) => eq(name, "Important Task")) - .go(); - -const { data } = await tasks.query - .statusIndex({ status: "open" }) -// ❌ This would not work - filtering on non-projected attributes - .where(({ description }, { eq }) => eq(description, "Some description")) - .go(); -``` +#### This works - filtering on projected attributes + + + +#### This would not work - filtering on non-projected attributes + +ElectroDB enforces this at the type level, so this example will fail to compile. + + ### Using Hydration If you need access to non-projected attributes, you can use the `hydrate` option to perform a follow-up `batchGet` operation: -```typescript -// With hydration, you get all attributes but can only filter on projected ones -const { data } = await tasks.query - .statusIndex({ status: "open" }) - .where((attr, op) => op.eq(attr.name, "Important Task")) - .go({ hydrate: true }); - -// data will contain all attributes: { taskId, projectId, name, description, status, priority, createdAt, updatedAt }[] -``` + ### Selective Attribute Retrieval with Hydration When using hydration, you can still specify which attributes to return: -```typescript -const { data } = await tasks.query - .statusIndex({ status: "open" }) - .where((attr, op) => op.eq(attr.name, "Important Task")) - .go({ - hydrate: true, - attributes: ['taskId', 'name', 'description'] - }); - -// data will only contain: { taskId: string, name: string, description: string }[] -``` + ## Benefits of INCLUDE Projections diff --git a/www/src/pages/en/recipes/item-counters.mdx b/www/src/pages/en/recipes/item-counters.mdx index bdf1534f..a54f7934 100644 --- a/www/src/pages/en/recipes/item-counters.mdx +++ b/www/src/pages/en/recipes/item-counters.mdx @@ -17,6 +17,8 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + Counting items in DynamoDB is not always a straightforward task. DynamoDB is a NoSQL database, and as such, it does not support the same types of queries that you might be used to with a relational database. DynamoDB does not support the `COUNT` operation, and as such, you must use other strategies to count items in DynamoDB. There are two main strategies for counting items in DynamoDB: counting items on write and counting items on read. Each strategy has its own pros and cons, and you should choose the strategy that best fits your use case. @@ -180,46 +182,9 @@ const OrganizationItemCounter = new Entity({ Once you have planned out your counter entity schema, you can use a DynamoDB transaction to increment and decrement the counters as you write and remove items from the table. The following example demonstrates how you might use a DynamoDB transaction to increment and decrement counters as you write and remove items from the table. -```typescript -const AccountService = new Service({ Employee, OrganizationItemCounter, TeamCounter, GlobalCounter }); - -export type CreateEmployeeOptions = { - organizationId: string; - teamId: string; - employeeId: string; - name: string; -} - -export function createEmployee(options: CreateEmployeeOptions) { - const { organizationId, employeeId, name, teamId } = options; - - return AccountService.transaction.write(({ Employee, OrganizationItemCounter, GlobalCounter, TeamCounter }) => [ - Employee.create({ organizationId, employeeId, name }).commit(), +> The **Entities** and **Table Definition** tabs show the counter entities defined above (`Employee`, `GlobalCounter`, `TeamCounter`, `OrganizationItemCounter`) combined into a `Service`. The generated parameters below are produced live by executing the example. - GlobalCounter.upsert({}).add({count: 1}).commit(), - TeamCounter.upsert({organizationId, teamId}).add({count: 1}).commit(), - OrganizationItemCounter.upsert({organizationId, kind: 'employee'}).add({count: 1}).commit(), - ]).go(); -} - -export type RemoveEmployeeOptions = { - organizationId: string; - teamId: string; - employeeId: string; -} - -export function removeEmployee(options: RemoveEmployeeOptions) { - const { organizationId, employeeId, teamId } = options; - - return AccountService.transaction.write(({ Employee, OrganizationItemCounter, GlobalCounter, TeamCounter }) => [ - Employee.remove({ organizationId, employeeId }).commit(), - - GlobalCounter.upsert({}).subtract({count: 1}).commit(), - TeamCounter.upsert({organizationId, teamId}).subtract({count: 1}).commit(), - OrganizationItemCounter.upsert({organizationId, kind: 'employee'}).subtract({count: 1}).commit(), - ]).go(); -} -``` + ## Counting items on read You can count items on read by instructing DynamoDB to return counts instead of items. DynamoDB supports the `SELECT` operation, which allows you to specify whether you want to return items or counts. You can use the `SELECT` operation to return counts instead of items which will be faster to paginate than returning items. @@ -232,193 +197,6 @@ The following example demonstrates how you might use the `SELECT` operation to r - `raw` allows you return the unprocess results directly from DynamoDB - `params` allows you to append additional parameters to the query sent to DynamoDB -```typescript -import { Entity, Service } from 'electrodb'; - -const table = "accounts"; - -const User = new Entity({ - model: { - entity: 'user', - service: 'accounts', - version: '1', - }, - attributes: { - accountId: { - type: 'string', - }, - userId: { - type: 'string', - }, - name: { - type: 'string', - }, - }, - indexes: { - account: { - collection: 'members', - pk: { - field: 'pk', - composite: ['accountId'], - }, - sk: { - field: 'sk', - composite: ['userId'], - } - }, - }, -}, { table }); - -const Account = new Entity({ - model: { - entity: 'account', - service: 'accounts', - version: '1', - }, - attributes: { - accountId: { - type: 'string', - }, - name: { - type: 'string', - }, - }, - indexes: { - account: { - collection: 'members', - pk: { - field: 'pk', - composite: ['accountId'], - }, - sk: { - field: 'sk', - composite: [], - } - }, - }, -}, { table }); - -const AccountService = new Service({ User, Account }); - -type Cursor = string | null; - -type QueryResponse = { - cursor: Cursor; - data: unknown; -} - -type CountQueryResponse = { - cursor: Cursor; - data: { count: number }; -} - -type CountFnOptions = { - next: Cursor; -} - -type CountFn = (options: CountFnOptions) => Promise; - -function toCountFnResponse(resp: QueryResponse): CountQueryResponse { - const { cursor } = resp; - - const data = { count: 0 }; - if (typeof resp.data === 'object' && resp.data !== null && 'Count' in resp.data && typeof resp.data.Count === 'number') { - data.count = resp.data.Count; - }; - - return { - cursor, - data, - }; -} - -type PaginateCountQueryOptions = { - countFn: CountFn; -} - -// this function exists to demonstrate how you might implement some indirection to accomplish this task in a generic way -async function paginateCountQuery(options: PaginateCountQueryOptions) { - const { countFn } = options; - let count = 0; - let next: Cursor = null; - do { - const { cursor, data } = await countFn({ next }); - count += data.count; - next = cursor; - } while(next); - - return count; -} - -type CreateCountFnOptions = { - accountId: string; -} - -// count collection query -function createMembersCountFn(options: CreateCountFnOptions): CountFn { - const { accountId } = options; - return ({ next }) => { - return AccountService.collections - .members({ accountId }) - .go({ - // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) - data: 'raw', - // paginate through the results using the cursor - cursor: next, - // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) - params: { Select: 'COUNT'}, - // transform results - }).then(toCountFnResponse); - }; -} - -// count entity query -function createUsersCountFn(options: CreateCountFnOptions): CountFn { - const { accountId } = options; - return async ({ next }) => { - return User.query.account({ accountId }) - .go({ - // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) - data: 'raw', - // paginate through the results using the cursor - cursor: next, - // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) - params: { Select: 'COUNT'}, - // transform results - }).then(toCountFnResponse); - }; -} - -function createUsersScanCountFn(options: CreateCountFnOptions): CountFn { - const { accountId } = options; - return async ({ next }) => { - return User.scan - .where((attr, op) => op.eq(attr.accountId, accountId)) - .go({ - // `raw` allows you return the unprocess results directly from DynamoDB (escape hatch) - data: 'raw', - // paginate through the results using the cursor - cursor: next, - // `params` allows you to append additional parameters to the DynamoDB query (escape hatch) - params: { Select: 'COUNT'}, - // transform results - }).then(toCountFnResponse); - }; -} - -(async function main() { - const accountId = '1234'; - - const membersCount = await paginateCountQuery({ - countFn: createMembersCountFn({ accountId }) - }); - - const usersCount = await paginateCountQuery({ - countFn: createUsersCountFn({ accountId }) - }); +> The **Entities** and **Table Definition** tabs show the `User` and `Account` entities (combined into a `Service`) that this example runs against, and the generated parameters below are produced live by executing the example. - const usersScanCount = await paginateCountQuery({ - countFn: createUsersScanCountFn({ accountId }) - }); -})().catch(console.error); -``` \ No newline at end of file + \ No newline at end of file diff --git a/www/src/pages/en/recipes/keys-only-gsi.mdx b/www/src/pages/en/recipes/keys-only-gsi.mdx index 74867edd..1f904f8e 100644 --- a/www/src/pages/en/recipes/keys-only-gsi.mdx +++ b/www/src/pages/en/recipes/keys-only-gsi.mdx @@ -16,144 +16,9 @@ keywords: layout: ../../../layouts/MainLayout.astro --- -It is common to define a Global Secondary Index using a `KEYS_ONLY` projection. This `ProjectionType` helps keep indexes as small as possible which can reduce cost. Unfortunately, because ElectroDB abstracts away key management, querying this index type with ElectroDB requires unique considerations. +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; -## Example Setup - -
-

Example Setup

-
- Table Definition - - ```json - { - "TableName": "electro", - "KeySchema":[ - { - "AttributeName":"pk", - "KeyType":"HASH" - }, - { - "AttributeName":"sk", - "KeyType":"RANGE" - } - ], - "AttributeDefinitions":[ - { - "AttributeName":"pk", - "AttributeType":"S" - }, - { - "AttributeName":"sk", - "AttributeType":"S" - }, - { - "AttributeName":"gsi1pk", - "AttributeType":"S" - }, - { - "AttributeName":"gsi1sk", - "AttributeType":"S" - } - ], - "GlobalSecondaryIndexes":[ - { - "IndexName":"gsi1pk-gsi1sk-index", - "KeySchema":[ - { - "AttributeName":"gsi1pk", - "KeyType":"HASH" - }, - { - "AttributeName":"gsi1sk", - "KeyType":"RANGE" - } - ], - "Projection":{ - "ProjectionType":"ALL" - } - } - ], - "BillingMode":"PAY_PER_REQUEST" - } - ``` - -
- -
- Example Entity - - ```typescript - import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; - import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; - import { Entity } from 'electrodb'; - - const client = DynamoDBDocumentClient.from(new DynamoDBClient({})); - - const table = 'electro'; - - const assets = new Entity({ - model: { - entity: 'assets', - version: '1', - service: 'inventory' - }, - attributes: { - assetId: { - type: 'string' - }, - accountId: { - type: 'string' - }, - name: { - type: 'string' - }, - description: { - type: 'string' - }, - city: { - type: 'string' - }, - county: { - type: 'string' - }, - state: { - type: 'string' - }, - zip: { - type: 'string' - } - }, - indexes: { - assets: { - pk: { - field: 'pk', - composite: ['accountId'] - }, - sk: { - field: 'sk', - composite: ['assetId'] - } - }, - locations: { - collection: 'geographics', - index: 'gsi1pk-gsi1sk-index', - pk: { - field: 'gsi1pk', - composite: ['state'], - }, - sk: { - field: 'gsi1sk', - composite: ['county', 'city', 'zip'], - } - } - } - }, { table, client }); - ``` - -
- -
+It is common to define a Global Secondary Index using a `KEYS_ONLY` projection. This `ProjectionType` helps keep indexes as small as possible which can reduce cost. Unfortunately, because ElectroDB abstracts away key management, querying this index type with ElectroDB requires unique considerations. ## Hydrating Queries @@ -161,12 +26,9 @@ The execution option `hydrate` can be used instruct ElectroDB to perform a `quer > \_Note: Without hydration, a `KEYS_ONLY` index will return empty objects as it only contains the keys, which are not returned by ElectroDB by default. To circumvent this, checkout the [Returning Keys](#returning-keys) section below. -```typescript -// the locations index (gsi1pk-gsi1sk-index) is a KEYS_ONLY projection -const { data, cursor } = await assets.query - .locations({ state: "Georgia" }) - .go({ hydrate: true }); -``` +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. + + ## Returning Keys @@ -178,24 +40,13 @@ If you do not wish to "hydrate" your query response, you still have ways you can The query execution options `{ data: 'includeKeys' }` allow you to return keys on the `data` array. -```typescript -// The elements in the `data` array are just the keys of the index, despite the typing saying otherwise. -const { data, cursor } = await assets.query - .locations({ state: "Georgia" }) - .go({ data: "includeKeys" }); -``` + ### Raw Responses The query execution option `{ data: 'raw' }` will return the raw response from DynamoDB. This is one way you can access the results of a `KEYS_ONLY` index. -```typescript -// result is the actual DynamoDB response, despite the typing saying otherwise. -const result: any = await assets.query - .locations({ state: "Georgia" }) - .go({ data: "raw" }); -const { Items, LastEvaluatedKey } = result; -``` + ## References diff --git a/www/src/pages/en/recipes/use-electrodb-with-existing-table.mdx b/www/src/pages/en/recipes/use-electrodb-with-existing-table.mdx index 816c76d7..c2282e25 100644 --- a/www/src/pages/en/recipes/use-electrodb-with-existing-table.mdx +++ b/www/src/pages/en/recipes/use-electrodb-with-existing-table.mdx @@ -10,17 +10,15 @@ keywords: layout: ../../../layouts/MainLayout.astro --- +import LiveExample from "../../../components/LiveExample/LiveExample.astro"; + When using ElectroDB with an existing table and/or data model, there are a few configurations you may need to make to your ElectroDB model. Read the sections below to see if any of the following cases fits your particular needs. Whenever using ElectroDB with existing tables/data, it is best to use the [Execution Option](/en/core-concepts/executing-queries#execution-options) `ignoreOwnership`. ElectroDB leaves some meta-data on items to help ensure data queried and returned from DynamoDB does not leak between entities. Because your data was not made by ElectroDB, these checks could impede your ability to return data. -```typescript -// when building params -.params({ ignoreOwnership: true }) +> The **Entity** and **Table Definition** tabs show the setup this example runs against, and the generated parameters below are produced live by executing the example. -// when querying the table -.go({ ignoreOwnership: true }) -``` + ### Your existing index fields have values with mixed case From a585308548ca512182af4f880eb7aacdec6b8746 Mon Sep 17 00:00:00 2001 From: ty Date: Tue, 7 Jul 2026 14:31:14 -0400 Subject: [PATCH 05/16] LiveExample: fix per-line borders and follow the site theme - The site's global inline-code rule (background, padding, and a border that repeats on every wrapped line box of an inline element) was leaking into the control's code blocks, drawing a line under every line of code; the control's now opts out entirely (all: unset), like the site's own pre.astro-code > code - The control now follows the site-level theme instead of hardcoding dark colors: theme-scoped CSS variables mirror theme.css (explicit .theme-light/ .theme-dark classes, OS preference otherwise) with a GitHub-light palette for code, tokens, output, and messages in light mode; dark mode now also tracks the site's --theme-code-bg rather than a hardcoded value --- .../components/LiveExample/LiveExample.css | 130 ++++++++++++++---- 1 file changed, 104 insertions(+), 26 deletions(-) diff --git a/www/src/components/LiveExample/LiveExample.css b/www/src/components/LiveExample/LiveExample.css index 5f8f40c2..54ff4729 100644 --- a/www/src/components/LiveExample/LiveExample.css +++ b/www/src/components/LiveExample/LiveExample.css @@ -1,4 +1,28 @@ +/* Theme variables: light by default, dark overrides below mirror the site's + theme.css pattern (explicit .theme-dark class, or OS preference when no + explicit class is set). */ .live-example { + --le-code-bg: #f6f8fa; + --le-code-text: #1f2328; + --le-source-divider: rgba(0, 0, 0, 0.08); + --le-output-heading: #57606a; + --le-output-label: #24292f; + --le-label-accent: #0550ae; + --le-inner-pre-bg: #eaeef2; + --le-msg-error-bg: rgba(207, 34, 46, 0.08); + --le-msg-error-text: #cf222e; + --le-msg-error-link: #0550ae; + --le-msg-info-bg: #eaeef2; + --le-msg-info-text: #24292f; + --le-tok-comment: #6e7781; + --le-tok-punct: #24292f; + --le-tok-property: #0550ae; + --le-tok-number: #953800; + --le-tok-keyword: #cf222e; + --le-tok-string: #0a3069; + --le-tok-variable: #953800; + --le-tok-operator: #0550ae; + margin: 1.5rem 0; border: 1px solid var(--theme-border); border-radius: 8px; @@ -6,6 +30,54 @@ box-shadow: var(--theme-shadow-sm); } +:root.theme-dark .live-example { + --le-code-bg: var(--theme-code-bg); + --le-code-text: var(--theme-code-text); + --le-source-divider: rgba(255, 255, 255, 0.08); + --le-output-heading: #8b949e; + --le-output-label: #e6edf3; + --le-label-accent: #79c0ff; + --le-inner-pre-bg: #161b22; + --le-msg-error-bg: rgba(248, 81, 73, 0.15); + --le-msg-error-text: #ffa198; + --le-msg-error-link: #79c0ff; + --le-msg-info-bg: #161b22; + --le-msg-info-text: #e6edf3; + --le-tok-comment: #8b949e; + --le-tok-punct: #c9d1d9; + --le-tok-property: #79c0ff; + --le-tok-number: #ffc107; + --le-tok-keyword: #ff7b72; + --le-tok-string: #a5d6ff; + --le-tok-variable: #ffa657; + --le-tok-operator: #67cdcc; +} + +@media (prefers-color-scheme: dark) { + :root:not(.theme-light) .live-example { + --le-code-bg: var(--theme-code-bg); + --le-code-text: var(--theme-code-text); + --le-source-divider: rgba(255, 255, 255, 0.08); + --le-output-heading: #8b949e; + --le-output-label: #e6edf3; + --le-label-accent: #79c0ff; + --le-inner-pre-bg: #161b22; + --le-msg-error-bg: rgba(248, 81, 73, 0.15); + --le-msg-error-text: #ffa198; + --le-msg-error-link: #79c0ff; + --le-msg-info-bg: #161b22; + --le-msg-info-text: #e6edf3; + --le-tok-comment: #8b949e; + --le-tok-punct: #c9d1d9; + --le-tok-property: #79c0ff; + --le-tok-number: #ffc107; + --le-tok-keyword: #ff7b72; + --le-tok-string: #a5d6ff; + --le-tok-variable: #ffa657; + --le-tok-operator: #67cdcc; + } +} + .live-example__header { display: flex; align-items: center; @@ -59,28 +131,34 @@ .live-example__code { margin: 0; padding: 1rem; - background-color: var(--theme-code-bg); - color: var(--theme-code-text); + background-color: var(--le-code-bg); + color: var(--le-code-text); overflow-x: auto; font-size: 0.8125rem; line-height: 1.5; font-family: var(--font-mono, ui-monospace, "SFMono-Regular", Menlo, monospace); + border: none; + border-radius: 0; + box-shadow: none; } -.live-example__code code { - background: none; - padding: 0; +/* The site styles inline `code` elements globally (background, padding, and + a border that repeats on every wrapped line box of an inline element); + opt out entirely, like the site's own `pre.astro-code > code`. */ +.live-example__code > code { + all: unset; + display: block; + font-family: inherit; font-size: inherit; color: inherit; - font-family: inherit; } .live-example__source { - border-bottom: 1px solid rgba(255, 255, 255, 0.08); + border-bottom: 1px solid var(--le-source-divider); } .live-example__output { - background-color: var(--theme-code-bg); + background-color: var(--le-code-bg); padding: 0.75rem 1rem 1rem; } @@ -89,12 +167,12 @@ font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; - color: #8b949e; + color: var(--le-output-heading); margin-bottom: 0.5rem; } .live-example__loading { - color: #8b949e; + color: var(--le-output-heading); font-size: 0.8125rem; font-style: italic; } @@ -105,18 +183,18 @@ .live-example__output-label { font-size: 0.8125rem; - color: #e6edf3; + color: var(--le-output-label); margin-bottom: 0.5rem; } .live-example__output-label b { - color: #79c0ff; + color: var(--le-label-accent); } .live-example__output .live-example__code { padding: 0.75rem; border-radius: 6px; - background-color: #161b22; + background-color: var(--le-inner-pre-bg); } .live-example__message { @@ -132,17 +210,17 @@ } .live-example__message--error { - background-color: rgba(248, 81, 73, 0.15); - color: #ffa198; + background-color: var(--le-msg-error-bg); + color: var(--le-msg-error-text); } .live-example__message--error a { - color: #79c0ff; + color: var(--le-msg-error-link); } .live-example__message--info { - background-color: #161b22; - color: #e6edf3; + background-color: var(--le-msg-info-bg); + color: var(--le-msg-info-text); } /* Prism token colors (the docs' fenced code blocks use build-time Shiki; @@ -153,24 +231,24 @@ .live-example .token.prolog, .live-example .token.doctype, .live-example .token.cdata { - color: #8b949e; + color: var(--le-tok-comment); } .live-example .token.punctuation { - color: #c9d1d9; + color: var(--le-tok-punct); } .live-example .token.property, .live-example .token.class-name, .live-example .token.constant, .live-example .token.symbol { - color: #79c0ff; + color: var(--le-tok-property); } .live-example .token.boolean, .live-example .token.number, .live-example .token.function { - color: #ffc107; + color: var(--le-tok-number); } .live-example .token.selector, @@ -178,24 +256,24 @@ .live-example .token.atrule, .live-example .token.keyword, .live-example .token.builtin { - color: #ff7b72; + color: var(--le-tok-keyword); } .live-example .token.string, .live-example .token.char, .live-example .token.attr-value, .live-example .token.regex { - color: #a5d6ff; + color: var(--le-tok-string); } .live-example .token.variable { - color: #ffa657; + color: var(--le-tok-variable); } .live-example .token.operator, .live-example .token.entity, .live-example .token.url { - color: #67cdcc; + color: var(--le-tok-operator); } .live-example .token.bold { From 59ea806c5553b1a94dfc426d0433200fa336b315 Mon Sep 17 00:00:00 2001 From: ty Date: Tue, 7 Jul 2026 14:52:03 -0400 Subject: [PATCH 06/16] Add docs CI: type-check, execute, and build all live examples - www/scripts/test-examples.mjs executes every src/examples//example.ts against this repository's ElectroDB with a mocked DynamoDB client (the same way the LiveExample control runs them in the browser) and fails if any example throws; examples that intentionally demonstrate an error opt in via an expected-error.txt marker, for which NOT throwing is the failure - .github/workflows/docs.yml runs `npm run check` (compile), the new `npm run test:examples`, and the full site build on changes to www/ or the library source - Fix a real bug the new test caught: the playground mock client returned UnprocessedKeys from batchWrite, but electrodb reads UnprocessedItems, so batch-put/batch-delete examples threw "unprocessed is not iterable"; rebuilt and re-vendored the browser bundle - Mark the two intentionally-failing query examples as expected errors and remove four incomplete example dirs left by an interrupted conversion --- .github/workflows/docs.yml | 47 ++++ playground/browser.js | 2 +- www/package.json | 1 + www/public/scripts/electrodb-playground.js | 2 +- www/scripts/test-examples.mjs | 210 ++++++++++++++++ www/src/examples/README.md | 12 + .../human-resources-birthdays/entities.ts | 229 ------------------ .../human-resources-birthdays/service.ts | 8 - .../human-resources-birthdays/table.ts | 148 ----------- .../entities.ts | 229 ------------------ .../human-resources-direct-reports/service.ts | 8 - .../human-resources-direct-reports/table.ts | 148 ----------- .../entities.ts | 229 ------------------ .../human-resources-employee-roles/service.ts | 8 - .../human-resources-employee-roles/table.ts | 148 ----------- .../entities.ts | 229 ------------------ .../service.ts | 8 - .../human-resources-office-locations/table.ts | 148 ----------- .../expected-error.txt | 1 + .../query-bad-no-pk/expected-error.txt | 1 + 20 files changed, 274 insertions(+), 1542 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 www/scripts/test-examples.mjs delete mode 100644 www/src/examples/human-resources-birthdays/entities.ts delete mode 100644 www/src/examples/human-resources-birthdays/service.ts delete mode 100644 www/src/examples/human-resources-birthdays/table.ts delete mode 100644 www/src/examples/human-resources-direct-reports/entities.ts delete mode 100644 www/src/examples/human-resources-direct-reports/service.ts delete mode 100644 www/src/examples/human-resources-direct-reports/table.ts delete mode 100644 www/src/examples/human-resources-employee-roles/entities.ts delete mode 100644 www/src/examples/human-resources-employee-roles/service.ts delete mode 100644 www/src/examples/human-resources-employee-roles/table.ts delete mode 100644 www/src/examples/human-resources-office-locations/entities.ts delete mode 100644 www/src/examples/human-resources-office-locations/service.ts delete mode 100644 www/src/examples/human-resources-office-locations/table.ts create mode 100644 www/src/examples/query-bad-missing-pk-attribute/expected-error.txt create mode 100644 www/src/examples/query-bad-no-pk/expected-error.txt diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..846d3164 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,47 @@ +name: docs + +on: + push: + branches: [master] + paths: + - "www/**" + - "index.js" + - "index.d.ts" + - "src/**" + - "playground/**" + - ".github/workflows/docs.yml" + pull_request: + branches: [master] + paths: + - "www/**" + - "index.js" + - "index.d.ts" + - "src/**" + - "playground/**" + - ".github/workflows/docs.yml" + +jobs: + docs: + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + # The docs examples execute against this repository's ElectroDB, so the + # library's (small) runtime dependency set is installed at the root. + - name: Install library dependencies + run: npm ci --omit=dev + - name: Install docs dependencies + run: npm ci + working-directory: www + - name: Type-check docs and examples + run: npm run check + working-directory: www + - name: Execute docs examples + run: npm run test:examples + working-directory: www + - name: Build docs site + run: npm run build + working-directory: www diff --git a/playground/browser.js b/playground/browser.js index 46adb6fb..16ea4e4b 100644 --- a/playground/browser.js +++ b/playground/browser.js @@ -217,7 +217,7 @@ class Entity extends ElectroDB.Entity { scan: () => promiseCallback({ Items: [] }), batchWrite: () => promiseCallback({ - UnprocessedKeys: { [options.table]: { Keys: [] } }, + UnprocessedItems: { [options.table]: [] }, }), batchGet: () => promiseCallback({ diff --git a/www/package.json b/www/package.json index 6d9a2004..d683a833 100644 --- a/www/package.json +++ b/www/package.json @@ -8,6 +8,7 @@ "dev:fast": "astro dev", "start": "astro dev", "check": "astro check && tsc", + "test:examples": "node scripts/test-examples.mjs", "build": "astro build && pagefind --site dist && rm -rf public/pagefind && cp -R dist/pagefind public/pagefind", "preview": "astro preview", "astro": "astro" diff --git a/www/public/scripts/electrodb-playground.js b/www/public/scripts/electrodb-playground.js index 0a3e88d0..4a6202c4 100644 --- a/www/public/scripts/electrodb-playground.js +++ b/www/public/scripts/electrodb-playground.js @@ -4101,7 +4101,7 @@ class Entity extends ElectroDB.Entity { scan: () => promiseCallback({ Items: [] }), batchWrite: () => promiseCallback({ - UnprocessedKeys: { [options.table]: { Keys: [] } }, + UnprocessedItems: { [options.table]: [] }, }), batchGet: () => promiseCallback({ diff --git a/www/scripts/test-examples.mjs b/www/scripts/test-examples.mjs new file mode 100644 index 00000000..e965b543 --- /dev/null +++ b/www/scripts/test-examples.mjs @@ -0,0 +1,210 @@ +#!/usr/bin/env node +/** + * Executes every docs example (src/examples//example.ts) against the + * repository's own ElectroDB build with a mocked DynamoDB client — the same + * way the LiveExample control runs them in the browser — and fails if any + * example throws. + * + * Examples that are SUPPOSED to throw (the docs render their error on + * purpose) opt in with an `expected-error.txt` file in their directory; for + * those, NOT throwing is the failure. + * + * Type-correctness is covered separately by `npm run check` (tsc resolves + * "electrodb" to ../index.d.ts via tsconfig paths). + */ +import { readdirSync, readFileSync, existsSync } from "node:fs"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createRequire } from "node:module"; +import ts from "typescript"; + +const here = dirname(fileURLToPath(import.meta.url)); +const examplesRoot = resolve(here, "../src/examples"); +const nodeRequire = createRequire(import.meta.url); +// The repository's ElectroDB (www/scripts -> repo root) +const ElectroDB = nodeRequire(resolve(here, "../../index.js")); + +function promiseCallback(results) { + return { promise: async () => results }; +} + +function createMockClient(table) { + return { + put: () => promiseCallback({}), + delete: () => promiseCallback({}), + update: () => promiseCallback({}), + get: () => promiseCallback({ Item: {} }), + query: () => promiseCallback({ Items: [] }), + scan: () => promiseCallback({ Items: [] }), + batchWrite: () => + promiseCallback({ UnprocessedItems: { [table]: [] } }), + batchGet: () => + promiseCallback({ + Responses: { [table]: [] }, + UnprocessedKeys: { [table]: { Keys: [] } }, + }), + transactWrite: () => ({ promise: async () => ({}), on: () => {} }), + transactGet: () => ({ + promise: async () => ({ Responses: [] }), + on: () => {}, + }), + createSet: (value) => value, + }; +} + +// Entities in example files are constructed without a client (the browser +// control injects a mocked one); do the same here so `.go()` executes. +class MockedEntity extends ElectroDB.Entity { + constructor(schema, options = {}) { + super(schema, { ...options, client: createMockClient(options.table) }); + } +} + +const electrodbModule = { + ...ElectroDB, + Entity: MockedEntity, +}; + +function transpile(source, fileName) { + const output = ts.transpileModule(source, { + fileName, + reportDiagnostics: true, + compilerOptions: { + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES2017, + esModuleInterop: true, + }, + }); + const syntaxErrors = (output.diagnostics ?? []).map((diagnostic) => + ts.flattenDiagnosticMessageText(diagnostic.messageText, " "), + ); + return { js: output.outputText, syntaxErrors }; +} + +function resolveRequest(request, moduleNames) { + if (request === "electrodb") { + return request; + } + if (!request.startsWith("./")) { + throw new Error(`Cannot find module '${request}'`); + } + const base = request.slice(2); + const candidates = [base, `${base}.ts`, `${base}.tsx`]; + const resolved = candidates.find((candidate) => moduleNames.has(candidate)); + if (resolved === undefined) { + throw new Error(`Cannot find module '${request}'`); + } + return resolved; +} + +async function executeExample(dir) { + const fileNames = readdirSync(dir).filter((name) => name.endsWith(".ts")); + const modules = new Map(); + for (const name of fileNames) { + const source = readFileSync(join(dir, name), "utf8"); + const { js, syntaxErrors } = transpile(source, name); + if (syntaxErrors.length > 0) { + throw new Error(`${name}: ${syntaxErrors.join("; ")}`); + } + modules.set(name, js); + } + if (!modules.has("example.ts")) { + throw new Error("missing example.ts"); + } + const moduleNames = new Set(modules.keys()); + const cache = new Map(); + + function requireModule(name) { + if (name === "electrodb") { + return electrodbModule; + } + const cached = cache.get(name); + if (cached) { + return cached.exports; + } + const record = { exports: {} }; + cache.set(name, record); + const localRequire = (request) => + requireModule(resolveRequest(request, moduleNames)); + const factory = new Function( + "require", + "module", + "exports", + modules.get(name), + ); + factory(localRequire, record, record.exports); + return record.exports; + } + + const record = { exports: {} }; + cache.set("example.ts", record); + const localRequire = (request) => + requireModule(resolveRequest(request, moduleNames)); + const factory = new Function( + "require", + "module", + "exports", + `return (async () => {\n${modules.get("example.ts")}\n})();`, + ); + await factory(localRequire, record, record.exports); + // Give un-awaited `.go()` calls a beat to surface rejections. + await new Promise((r) => setTimeout(r, 10)); +} + +const dirs = readdirSync(examplesRoot, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); + +let failures = 0; +const results = []; + +for (const name of dirs) { + const dir = join(examplesRoot, name); + const expectedErrorFile = join(dir, "expected-error.txt"); + const expectsError = existsSync(expectedErrorFile); + + // Attribute un-awaited rejections to the example being executed + // (examples run serially). + const rejections = []; + const onRejection = (reason) => rejections.push(reason); + process.on("unhandledRejection", onRejection); + + let thrown = null; + try { + await executeExample(dir); + } catch (err) { + thrown = err; + } + process.off("unhandledRejection", onRejection); + if (thrown === null && rejections.length > 0) { + thrown = rejections[0]; + } + + if (expectsError) { + if (thrown !== null) { + results.push(` ok ${name} (threw as documented)`); + } else { + failures += 1; + results.push( + ` FAIL ${name} — marked expected-error but completed without throwing`, + ); + } + } else if (thrown === null) { + results.push(` ok ${name}`); + } else { + failures += 1; + const message = + thrown instanceof Error ? thrown.message : String(thrown); + results.push(` FAIL ${name} — ${message.split("\n")[0]}`); + } +} + +console.log(`docs examples: ${dirs.length} executed\n`); +console.log(results.join("\n")); +console.log( + `\n${dirs.length - failures} passed, ${failures} failed`, +); +if (failures > 0) { + process.exit(1); +} diff --git a/www/src/examples/README.md b/www/src/examples/README.md index 2ad2dfbf..b3ebf1d5 100644 --- a/www/src/examples/README.md +++ b/www/src/examples/README.md @@ -30,3 +30,15 @@ step, examples cannot silently drift out of sync with the ElectroDB API: if an example stops compiling, the docs build fails. An example that needs a schema tweak can modify its own `entity.ts`/`table.ts` copies without affecting other pages. + +## Testing + +`npm run test:examples` (run in CI by `.github/workflows/docs.yml` alongside +`npm run check` and the site build) executes every example against the +repository's own ElectroDB with a mocked DynamoDB client and fails if any +example throws. + +Examples that are *supposed* to throw — pages that intentionally demonstrate +an error — opt in by adding an `expected-error.txt` file (containing a short +explanation) to their directory; for those, completing without an error is +the test failure. The file is not rendered by the control. diff --git a/www/src/examples/human-resources-birthdays/entities.ts b/www/src/examples/human-resources-birthdays/entities.ts deleted file mode 100644 index 79a81b9e..00000000 --- a/www/src/examples/human-resources-birthdays/entities.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Entity } from "electrodb"; -import { tableName } from "./table"; - -export const Employee = new Entity( - { - model: { - entity: "employee", - version: "1", - service: "taskapp", - }, - attributes: { - employee: { - type: "string", - }, - firstName: { - type: "string", - }, - lastName: { - type: "string", - }, - office: { - type: "string", - }, - title: { - type: "string", - }, - team: { - type: ["development", "marketing", "finance", "product"] as const, - }, - salary: { - type: "string", - }, - manager: { - type: "string", - }, - dateHired: { - type: "string", - }, - birthday: { - type: "string", - }, - }, - indexes: { - employee: { - pk: { - field: "pk", - composite: ["employee"], - }, - sk: { - field: "sk", - composite: [], - }, - }, - coworkers: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: ["team", "title", "employee"], - }, - }, - teams: { - index: "gsi2pk-gsi2sk-index", - pk: { - field: "gsi2pk", - composite: ["team"], - }, - sk: { - field: "gsi2sk", - composite: ["title", "salary", "employee"], - }, - }, - employeeLookup: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: [], - }, - }, - roles: { - index: "gsi4pk-gsi4sk-index", - pk: { - field: "gsi4pk", - composite: ["title"], - }, - sk: { - field: "gsi4sk", - composite: ["salary", "employee"], - }, - }, - directReports: { - index: "gsi5pk-gsi5sk-index", - pk: { - field: "gsi5pk", - composite: ["manager"], - }, - sk: { - field: "gsi5sk", - composite: ["team", "office", "employee"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Task = new Entity( - { - model: { - entity: "task", - version: "1", - service: "taskapp", - }, - attributes: { - task: { - type: "string", - }, - project: { - type: "string", - }, - employee: { - type: "string", - }, - description: { - type: "string", - }, - }, - indexes: { - task: { - pk: { - field: "pk", - composite: ["task"], - }, - sk: { - field: "sk", - composite: ["project", "employee"], - }, - }, - project: { - index: "gsi1pk-gsi1sk-index", - pk: { - field: "gsi1pk", - composite: ["project"], - }, - sk: { - field: "gsi1sk", - composite: ["employee", "task"], - }, - }, - assigned: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: ["project", "task"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Office = new Entity( - { - model: { - entity: "office", - version: "1", - service: "taskapp", - }, - attributes: { - office: { - type: "string", - }, - country: { - type: "string", - }, - state: { - type: "string", - }, - city: { - type: "string", - }, - zip: { - type: "string", - }, - address: { - type: "string", - }, - }, - indexes: { - locations: { - pk: { - field: "pk", - composite: ["country", "state"], - }, - sk: { - field: "sk", - composite: ["city", "zip", "office"], - }, - }, - office: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: [], - }, - }, - }, - }, - { table: tableName }, -); diff --git a/www/src/examples/human-resources-birthdays/service.ts b/www/src/examples/human-resources-birthdays/service.ts deleted file mode 100644 index 8c591cf9..00000000 --- a/www/src/examples/human-resources-birthdays/service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Service } from "electrodb"; -import { Employee, Task, Office } from "./entities"; - -export const EmployeeApp = new Service({ - employees: Employee, - tasks: Task, - offices: Office, -}); diff --git a/www/src/examples/human-resources-birthdays/table.ts b/www/src/examples/human-resources-birthdays/table.ts deleted file mode 100644 index 393a7e73..00000000 --- a/www/src/examples/human-resources-birthdays/table.ts +++ /dev/null @@ -1,148 +0,0 @@ -export const tableName = "projectmanagement"; - -export const tableDefinition = { - TableName: tableName, - KeySchema: [ - { - AttributeName: "pk", - KeyType: "HASH", - }, - { - AttributeName: "sk", - KeyType: "RANGE", - }, - ], - AttributeDefinitions: [ - { - AttributeName: "pk", - AttributeType: "S", - }, - { - AttributeName: "sk", - AttributeType: "S", - }, - { - AttributeName: "gsi1pk", - AttributeType: "S", - }, - { - AttributeName: "gsi1sk", - AttributeType: "S", - }, - { - AttributeName: "gsi2pk", - AttributeType: "S", - }, - { - AttributeName: "gsi2sk", - AttributeType: "S", - }, - { - AttributeName: "gsi3pk", - AttributeType: "S", - }, - { - AttributeName: "gsi3sk", - AttributeType: "S", - }, - { - AttributeName: "gsi4pk", - AttributeType: "S", - }, - { - AttributeName: "gsi4sk", - AttributeType: "S", - }, - { - AttributeName: "gsi5pk", - AttributeType: "S", - }, - { - AttributeName: "gsi5sk", - AttributeType: "S", - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: "gsi1pk-gsi1sk-index", - KeySchema: [ - { - AttributeName: "gsi1pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi1sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi2pk-gsi2sk-index", - KeySchema: [ - { - AttributeName: "gsi2pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi2sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi3pk-gsi3sk-index", - KeySchema: [ - { - AttributeName: "gsi3pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi3sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi4pk-gsi4sk-index", - KeySchema: [ - { - AttributeName: "gsi4pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi4sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi5pk-gsi5sk-index", - KeySchema: [ - { - AttributeName: "gsi5pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi5sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - ], - BillingMode: "PAY_PER_REQUEST", -}; diff --git a/www/src/examples/human-resources-direct-reports/entities.ts b/www/src/examples/human-resources-direct-reports/entities.ts deleted file mode 100644 index 79a81b9e..00000000 --- a/www/src/examples/human-resources-direct-reports/entities.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Entity } from "electrodb"; -import { tableName } from "./table"; - -export const Employee = new Entity( - { - model: { - entity: "employee", - version: "1", - service: "taskapp", - }, - attributes: { - employee: { - type: "string", - }, - firstName: { - type: "string", - }, - lastName: { - type: "string", - }, - office: { - type: "string", - }, - title: { - type: "string", - }, - team: { - type: ["development", "marketing", "finance", "product"] as const, - }, - salary: { - type: "string", - }, - manager: { - type: "string", - }, - dateHired: { - type: "string", - }, - birthday: { - type: "string", - }, - }, - indexes: { - employee: { - pk: { - field: "pk", - composite: ["employee"], - }, - sk: { - field: "sk", - composite: [], - }, - }, - coworkers: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: ["team", "title", "employee"], - }, - }, - teams: { - index: "gsi2pk-gsi2sk-index", - pk: { - field: "gsi2pk", - composite: ["team"], - }, - sk: { - field: "gsi2sk", - composite: ["title", "salary", "employee"], - }, - }, - employeeLookup: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: [], - }, - }, - roles: { - index: "gsi4pk-gsi4sk-index", - pk: { - field: "gsi4pk", - composite: ["title"], - }, - sk: { - field: "gsi4sk", - composite: ["salary", "employee"], - }, - }, - directReports: { - index: "gsi5pk-gsi5sk-index", - pk: { - field: "gsi5pk", - composite: ["manager"], - }, - sk: { - field: "gsi5sk", - composite: ["team", "office", "employee"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Task = new Entity( - { - model: { - entity: "task", - version: "1", - service: "taskapp", - }, - attributes: { - task: { - type: "string", - }, - project: { - type: "string", - }, - employee: { - type: "string", - }, - description: { - type: "string", - }, - }, - indexes: { - task: { - pk: { - field: "pk", - composite: ["task"], - }, - sk: { - field: "sk", - composite: ["project", "employee"], - }, - }, - project: { - index: "gsi1pk-gsi1sk-index", - pk: { - field: "gsi1pk", - composite: ["project"], - }, - sk: { - field: "gsi1sk", - composite: ["employee", "task"], - }, - }, - assigned: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: ["project", "task"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Office = new Entity( - { - model: { - entity: "office", - version: "1", - service: "taskapp", - }, - attributes: { - office: { - type: "string", - }, - country: { - type: "string", - }, - state: { - type: "string", - }, - city: { - type: "string", - }, - zip: { - type: "string", - }, - address: { - type: "string", - }, - }, - indexes: { - locations: { - pk: { - field: "pk", - composite: ["country", "state"], - }, - sk: { - field: "sk", - composite: ["city", "zip", "office"], - }, - }, - office: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: [], - }, - }, - }, - }, - { table: tableName }, -); diff --git a/www/src/examples/human-resources-direct-reports/service.ts b/www/src/examples/human-resources-direct-reports/service.ts deleted file mode 100644 index 8c591cf9..00000000 --- a/www/src/examples/human-resources-direct-reports/service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Service } from "electrodb"; -import { Employee, Task, Office } from "./entities"; - -export const EmployeeApp = new Service({ - employees: Employee, - tasks: Task, - offices: Office, -}); diff --git a/www/src/examples/human-resources-direct-reports/table.ts b/www/src/examples/human-resources-direct-reports/table.ts deleted file mode 100644 index 393a7e73..00000000 --- a/www/src/examples/human-resources-direct-reports/table.ts +++ /dev/null @@ -1,148 +0,0 @@ -export const tableName = "projectmanagement"; - -export const tableDefinition = { - TableName: tableName, - KeySchema: [ - { - AttributeName: "pk", - KeyType: "HASH", - }, - { - AttributeName: "sk", - KeyType: "RANGE", - }, - ], - AttributeDefinitions: [ - { - AttributeName: "pk", - AttributeType: "S", - }, - { - AttributeName: "sk", - AttributeType: "S", - }, - { - AttributeName: "gsi1pk", - AttributeType: "S", - }, - { - AttributeName: "gsi1sk", - AttributeType: "S", - }, - { - AttributeName: "gsi2pk", - AttributeType: "S", - }, - { - AttributeName: "gsi2sk", - AttributeType: "S", - }, - { - AttributeName: "gsi3pk", - AttributeType: "S", - }, - { - AttributeName: "gsi3sk", - AttributeType: "S", - }, - { - AttributeName: "gsi4pk", - AttributeType: "S", - }, - { - AttributeName: "gsi4sk", - AttributeType: "S", - }, - { - AttributeName: "gsi5pk", - AttributeType: "S", - }, - { - AttributeName: "gsi5sk", - AttributeType: "S", - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: "gsi1pk-gsi1sk-index", - KeySchema: [ - { - AttributeName: "gsi1pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi1sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi2pk-gsi2sk-index", - KeySchema: [ - { - AttributeName: "gsi2pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi2sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi3pk-gsi3sk-index", - KeySchema: [ - { - AttributeName: "gsi3pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi3sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi4pk-gsi4sk-index", - KeySchema: [ - { - AttributeName: "gsi4pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi4sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi5pk-gsi5sk-index", - KeySchema: [ - { - AttributeName: "gsi5pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi5sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - ], - BillingMode: "PAY_PER_REQUEST", -}; diff --git a/www/src/examples/human-resources-employee-roles/entities.ts b/www/src/examples/human-resources-employee-roles/entities.ts deleted file mode 100644 index 79a81b9e..00000000 --- a/www/src/examples/human-resources-employee-roles/entities.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Entity } from "electrodb"; -import { tableName } from "./table"; - -export const Employee = new Entity( - { - model: { - entity: "employee", - version: "1", - service: "taskapp", - }, - attributes: { - employee: { - type: "string", - }, - firstName: { - type: "string", - }, - lastName: { - type: "string", - }, - office: { - type: "string", - }, - title: { - type: "string", - }, - team: { - type: ["development", "marketing", "finance", "product"] as const, - }, - salary: { - type: "string", - }, - manager: { - type: "string", - }, - dateHired: { - type: "string", - }, - birthday: { - type: "string", - }, - }, - indexes: { - employee: { - pk: { - field: "pk", - composite: ["employee"], - }, - sk: { - field: "sk", - composite: [], - }, - }, - coworkers: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: ["team", "title", "employee"], - }, - }, - teams: { - index: "gsi2pk-gsi2sk-index", - pk: { - field: "gsi2pk", - composite: ["team"], - }, - sk: { - field: "gsi2sk", - composite: ["title", "salary", "employee"], - }, - }, - employeeLookup: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: [], - }, - }, - roles: { - index: "gsi4pk-gsi4sk-index", - pk: { - field: "gsi4pk", - composite: ["title"], - }, - sk: { - field: "gsi4sk", - composite: ["salary", "employee"], - }, - }, - directReports: { - index: "gsi5pk-gsi5sk-index", - pk: { - field: "gsi5pk", - composite: ["manager"], - }, - sk: { - field: "gsi5sk", - composite: ["team", "office", "employee"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Task = new Entity( - { - model: { - entity: "task", - version: "1", - service: "taskapp", - }, - attributes: { - task: { - type: "string", - }, - project: { - type: "string", - }, - employee: { - type: "string", - }, - description: { - type: "string", - }, - }, - indexes: { - task: { - pk: { - field: "pk", - composite: ["task"], - }, - sk: { - field: "sk", - composite: ["project", "employee"], - }, - }, - project: { - index: "gsi1pk-gsi1sk-index", - pk: { - field: "gsi1pk", - composite: ["project"], - }, - sk: { - field: "gsi1sk", - composite: ["employee", "task"], - }, - }, - assigned: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: ["project", "task"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Office = new Entity( - { - model: { - entity: "office", - version: "1", - service: "taskapp", - }, - attributes: { - office: { - type: "string", - }, - country: { - type: "string", - }, - state: { - type: "string", - }, - city: { - type: "string", - }, - zip: { - type: "string", - }, - address: { - type: "string", - }, - }, - indexes: { - locations: { - pk: { - field: "pk", - composite: ["country", "state"], - }, - sk: { - field: "sk", - composite: ["city", "zip", "office"], - }, - }, - office: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: [], - }, - }, - }, - }, - { table: tableName }, -); diff --git a/www/src/examples/human-resources-employee-roles/service.ts b/www/src/examples/human-resources-employee-roles/service.ts deleted file mode 100644 index 8c591cf9..00000000 --- a/www/src/examples/human-resources-employee-roles/service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Service } from "electrodb"; -import { Employee, Task, Office } from "./entities"; - -export const EmployeeApp = new Service({ - employees: Employee, - tasks: Task, - offices: Office, -}); diff --git a/www/src/examples/human-resources-employee-roles/table.ts b/www/src/examples/human-resources-employee-roles/table.ts deleted file mode 100644 index 393a7e73..00000000 --- a/www/src/examples/human-resources-employee-roles/table.ts +++ /dev/null @@ -1,148 +0,0 @@ -export const tableName = "projectmanagement"; - -export const tableDefinition = { - TableName: tableName, - KeySchema: [ - { - AttributeName: "pk", - KeyType: "HASH", - }, - { - AttributeName: "sk", - KeyType: "RANGE", - }, - ], - AttributeDefinitions: [ - { - AttributeName: "pk", - AttributeType: "S", - }, - { - AttributeName: "sk", - AttributeType: "S", - }, - { - AttributeName: "gsi1pk", - AttributeType: "S", - }, - { - AttributeName: "gsi1sk", - AttributeType: "S", - }, - { - AttributeName: "gsi2pk", - AttributeType: "S", - }, - { - AttributeName: "gsi2sk", - AttributeType: "S", - }, - { - AttributeName: "gsi3pk", - AttributeType: "S", - }, - { - AttributeName: "gsi3sk", - AttributeType: "S", - }, - { - AttributeName: "gsi4pk", - AttributeType: "S", - }, - { - AttributeName: "gsi4sk", - AttributeType: "S", - }, - { - AttributeName: "gsi5pk", - AttributeType: "S", - }, - { - AttributeName: "gsi5sk", - AttributeType: "S", - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: "gsi1pk-gsi1sk-index", - KeySchema: [ - { - AttributeName: "gsi1pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi1sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi2pk-gsi2sk-index", - KeySchema: [ - { - AttributeName: "gsi2pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi2sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi3pk-gsi3sk-index", - KeySchema: [ - { - AttributeName: "gsi3pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi3sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi4pk-gsi4sk-index", - KeySchema: [ - { - AttributeName: "gsi4pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi4sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi5pk-gsi5sk-index", - KeySchema: [ - { - AttributeName: "gsi5pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi5sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - ], - BillingMode: "PAY_PER_REQUEST", -}; diff --git a/www/src/examples/human-resources-office-locations/entities.ts b/www/src/examples/human-resources-office-locations/entities.ts deleted file mode 100644 index 79a81b9e..00000000 --- a/www/src/examples/human-resources-office-locations/entities.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Entity } from "electrodb"; -import { tableName } from "./table"; - -export const Employee = new Entity( - { - model: { - entity: "employee", - version: "1", - service: "taskapp", - }, - attributes: { - employee: { - type: "string", - }, - firstName: { - type: "string", - }, - lastName: { - type: "string", - }, - office: { - type: "string", - }, - title: { - type: "string", - }, - team: { - type: ["development", "marketing", "finance", "product"] as const, - }, - salary: { - type: "string", - }, - manager: { - type: "string", - }, - dateHired: { - type: "string", - }, - birthday: { - type: "string", - }, - }, - indexes: { - employee: { - pk: { - field: "pk", - composite: ["employee"], - }, - sk: { - field: "sk", - composite: [], - }, - }, - coworkers: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: ["team", "title", "employee"], - }, - }, - teams: { - index: "gsi2pk-gsi2sk-index", - pk: { - field: "gsi2pk", - composite: ["team"], - }, - sk: { - field: "gsi2sk", - composite: ["title", "salary", "employee"], - }, - }, - employeeLookup: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: [], - }, - }, - roles: { - index: "gsi4pk-gsi4sk-index", - pk: { - field: "gsi4pk", - composite: ["title"], - }, - sk: { - field: "gsi4sk", - composite: ["salary", "employee"], - }, - }, - directReports: { - index: "gsi5pk-gsi5sk-index", - pk: { - field: "gsi5pk", - composite: ["manager"], - }, - sk: { - field: "gsi5sk", - composite: ["team", "office", "employee"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Task = new Entity( - { - model: { - entity: "task", - version: "1", - service: "taskapp", - }, - attributes: { - task: { - type: "string", - }, - project: { - type: "string", - }, - employee: { - type: "string", - }, - description: { - type: "string", - }, - }, - indexes: { - task: { - pk: { - field: "pk", - composite: ["task"], - }, - sk: { - field: "sk", - composite: ["project", "employee"], - }, - }, - project: { - index: "gsi1pk-gsi1sk-index", - pk: { - field: "gsi1pk", - composite: ["project"], - }, - sk: { - field: "gsi1sk", - composite: ["employee", "task"], - }, - }, - assigned: { - collection: "assignments", - index: "gsi3pk-gsi3sk-index", - pk: { - field: "gsi3pk", - composite: ["employee"], - }, - sk: { - field: "gsi3sk", - composite: ["project", "task"], - }, - }, - }, - }, - { table: tableName }, -); - -export const Office = new Entity( - { - model: { - entity: "office", - version: "1", - service: "taskapp", - }, - attributes: { - office: { - type: "string", - }, - country: { - type: "string", - }, - state: { - type: "string", - }, - city: { - type: "string", - }, - zip: { - type: "string", - }, - address: { - type: "string", - }, - }, - indexes: { - locations: { - pk: { - field: "pk", - composite: ["country", "state"], - }, - sk: { - field: "sk", - composite: ["city", "zip", "office"], - }, - }, - office: { - index: "gsi1pk-gsi1sk-index", - collection: "workplaces", - pk: { - field: "gsi1pk", - composite: ["office"], - }, - sk: { - field: "gsi1sk", - composite: [], - }, - }, - }, - }, - { table: tableName }, -); diff --git a/www/src/examples/human-resources-office-locations/service.ts b/www/src/examples/human-resources-office-locations/service.ts deleted file mode 100644 index 8c591cf9..00000000 --- a/www/src/examples/human-resources-office-locations/service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Service } from "electrodb"; -import { Employee, Task, Office } from "./entities"; - -export const EmployeeApp = new Service({ - employees: Employee, - tasks: Task, - offices: Office, -}); diff --git a/www/src/examples/human-resources-office-locations/table.ts b/www/src/examples/human-resources-office-locations/table.ts deleted file mode 100644 index 393a7e73..00000000 --- a/www/src/examples/human-resources-office-locations/table.ts +++ /dev/null @@ -1,148 +0,0 @@ -export const tableName = "projectmanagement"; - -export const tableDefinition = { - TableName: tableName, - KeySchema: [ - { - AttributeName: "pk", - KeyType: "HASH", - }, - { - AttributeName: "sk", - KeyType: "RANGE", - }, - ], - AttributeDefinitions: [ - { - AttributeName: "pk", - AttributeType: "S", - }, - { - AttributeName: "sk", - AttributeType: "S", - }, - { - AttributeName: "gsi1pk", - AttributeType: "S", - }, - { - AttributeName: "gsi1sk", - AttributeType: "S", - }, - { - AttributeName: "gsi2pk", - AttributeType: "S", - }, - { - AttributeName: "gsi2sk", - AttributeType: "S", - }, - { - AttributeName: "gsi3pk", - AttributeType: "S", - }, - { - AttributeName: "gsi3sk", - AttributeType: "S", - }, - { - AttributeName: "gsi4pk", - AttributeType: "S", - }, - { - AttributeName: "gsi4sk", - AttributeType: "S", - }, - { - AttributeName: "gsi5pk", - AttributeType: "S", - }, - { - AttributeName: "gsi5sk", - AttributeType: "S", - }, - ], - GlobalSecondaryIndexes: [ - { - IndexName: "gsi1pk-gsi1sk-index", - KeySchema: [ - { - AttributeName: "gsi1pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi1sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi2pk-gsi2sk-index", - KeySchema: [ - { - AttributeName: "gsi2pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi2sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi3pk-gsi3sk-index", - KeySchema: [ - { - AttributeName: "gsi3pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi3sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi4pk-gsi4sk-index", - KeySchema: [ - { - AttributeName: "gsi4pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi4sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - { - IndexName: "gsi5pk-gsi5sk-index", - KeySchema: [ - { - AttributeName: "gsi5pk", - KeyType: "HASH", - }, - { - AttributeName: "gsi5sk", - KeyType: "RANGE", - }, - ], - Projection: { - ProjectionType: "ALL", - }, - }, - ], - BillingMode: "PAY_PER_REQUEST", -}; diff --git a/www/src/examples/query-bad-missing-pk-attribute/expected-error.txt b/www/src/examples/query-bad-missing-pk-attribute/expected-error.txt new file mode 100644 index 00000000..6d768010 --- /dev/null +++ b/www/src/examples/query-bad-missing-pk-attribute/expected-error.txt @@ -0,0 +1 @@ +This example intentionally omits the "cityId" partition key composite attribute; ElectroDB cannot build a key and throws. The docs render this error on purpose. diff --git a/www/src/examples/query-bad-no-pk/expected-error.txt b/www/src/examples/query-bad-no-pk/expected-error.txt new file mode 100644 index 00000000..decfa197 --- /dev/null +++ b/www/src/examples/query-bad-no-pk/expected-error.txt @@ -0,0 +1 @@ +This example intentionally omits all partition key composite attributes; ElectroDB cannot build a key and throws. The docs render this error on purpose. From 1b5932bdf54439afb959b6e540492cb0c49ecd9c Mon Sep 17 00:00:00 2001 From: Ty Walch Date: Thu, 23 Jul 2026 13:36:18 -0400 Subject: [PATCH 07/16] Fixes netlify build error --- www/.nvmrc | 1 + www/package.json | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 www/.nvmrc diff --git a/www/.nvmrc b/www/.nvmrc new file mode 100644 index 00000000..2bd5a0a9 --- /dev/null +++ b/www/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/www/package.json b/www/package.json index d683a833..d2a60aa7 100644 --- a/www/package.json +++ b/www/package.json @@ -3,6 +3,9 @@ "type": "module", "version": "0.0.1", "private": true, + "engines": { + "node": "^18.20.8 || ^20.3.0 || >=22.0.0" + }, "scripts": { "dev": "astro build && pagefind --site dist && rm -rf public/pagefind && cp -R dist/pagefind public/pagefind && astro dev", "dev:fast": "astro dev", From 83f7a722de9901826796069bae975e3d42846d64 Mon Sep 17 00:00:00 2001 From: Ty Walch Date: Thu, 23 Jul 2026 14:32:10 -0400 Subject: [PATCH 08/16] Replace logo --- www/src/components/Header/Header.astro | 73 +++++++++++++++--------- www/src/layouts/IntroductionLayout.astro | 60 +++++++++++++------ 2 files changed, 90 insertions(+), 43 deletions(-) diff --git a/www/src/components/Header/Header.astro b/www/src/components/Header/Header.astro index 3c372fe1..b701572e 100644 --- a/www/src/components/Header/Header.astro +++ b/www/src/components/Header/Header.astro @@ -6,9 +6,11 @@ import Search from './Search'; type Props = { currentPage: string; + /** Hide the wordmark in the nav (e.g. the intro page shows it in the hero). */ + hideBrand?: boolean; }; -const { currentPage } = Astro.props as Props; +const { currentPage, hideBrand = false } = Astro.props as Props; ---
@@ -18,14 +20,24 @@ const { currentPage } = Astro.props as Props; - - - - ElectroDB - - + {!hideBrand && ( + + + + + )}
@@ -105,38 +117,47 @@ const { currentPage } = Astro.props as Props; .brand { display: inline-flex; align-items: center; - gap: 0.5rem; text-decoration: none; - font-weight: 700; - font-size: 1rem; - color: var(--theme-text); - letter-spacing: -0.02em; padding: 0.25rem; margin: -0.25rem; border-radius: var(--radius); - transition: color 120ms ease; + transition: opacity 120ms ease; } .brand:hover { - color: var(--theme-text-accent); + opacity: 0.8; text-decoration: none; } - .brand-icon { - width: 20px; - height: 20px; - color: var(--theme-accent); + .brand-logo { + height: 1.75rem; + width: auto; + display: block; flex-shrink: 0; } - .brand-electro { - font-style: italic; - font-weight: 800; + /* Show the dark-text wordmark in light mode, the light-text one in dark + mode — same explicit-class / OS-preference logic as ThemeToggleButton. */ + .brand-logo-dark { + display: none; + } + + :root.theme-dark .brand-logo-light { + display: none; } - .brand-db { - font-weight: 800; - letter-spacing: -0.04em; + :root.theme-dark .brand-logo-dark { + display: block; + } + + @media (prefers-color-scheme: dark) { + :root:not(.theme-light):not(.theme-dark) .brand-logo-light { + display: none; + } + + :root:not(.theme-light):not(.theme-dark) .brand-logo-dark { + display: block; + } } .search-slot { diff --git a/www/src/layouts/IntroductionLayout.astro b/www/src/layouts/IntroductionLayout.astro index 8e688210..9a223342 100644 --- a/www/src/layouts/IntroductionLayout.astro +++ b/www/src/layouts/IntroductionLayout.astro @@ -84,27 +84,40 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`; } .hero-title { - font-size: clamp(2.75rem, 11vw, 6.5rem); - font-weight: 800; - letter-spacing: -0.045em; line-height: 1; margin: 0 auto 1.25rem; - color: var(--theme-text); } - .hero-title .electro { - font-style: italic; - background: linear-gradient(135deg, var(--brand-blue), var(--brand-blue-deep)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; + .hero-logo { + display: block; + width: clamp(16rem, 60vw, 32rem); + max-width: 100%; + height: auto; + margin: 0 auto; + } + + /* Dark-text wordmark in light mode, light-text one in dark mode — + same explicit-class / OS-preference logic as the header. */ + .hero-logo-dark { + display: none; + } + + :root.theme-dark .hero-logo-light { + display: none; + } + + :root.theme-dark .hero-logo-dark { + display: block; } - :root.theme-dark .hero-title .electro { - background: linear-gradient(135deg, var(--brand-blue-soft), var(--brand-blue)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; + @media (prefers-color-scheme: dark) { + :root:not(.theme-light):not(.theme-dark) .hero-logo-light { + display: none; + } + + :root:not(.theme-light):not(.theme-dark) .hero-logo-dark { + display: block; + } } .hero-tagline { @@ -322,7 +335,7 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`; -
+