├── .github └── workflows │ ├── cd.yaml │ └── ci.yaml ├── .gitignore ├── LICENSE ├── README.md ├── biome.json ├── examples ├── using-decorators │ ├── .editorconfig │ ├── .gitignore │ ├── .prettierrc │ ├── README.md │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ ├── worker-configuration.d.ts │ └── wrangler.toml └── using-state │ ├── .editorconfig │ ├── .gitignore │ ├── .prettierrc │ ├── README.md │ ├── package.json │ ├── src │ └── index.ts │ ├── tsconfig.json │ ├── worker-configuration.d.ts │ └── wrangler.toml ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── src ├── decorator.ts ├── index.ts ├── observable.ts ├── sqlite.ts ├── tracker.ts └── util.ts ├── tests ├── decorator.test.ts ├── global.d.ts ├── helper.ts ├── index.test.ts ├── observable.test.ts ├── sqlite.test.ts └── worker.ts ├── tsconfig.build.json ├── tsconfig.json └── vitest.config.ts /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | name: Publish to NPM 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: pnpm/action-setup@v3 11 | with: 12 | version: 8 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: "20.x" 16 | registry-url: "https://registry.npmjs.org" 17 | - run: pnpm install 18 | - run: pnpm build 19 | - run: pnpm publish --no-git-checks 20 | env: 21 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | node-version: [22] 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: pnpm/action-setup@v3 20 | with: 21 | version: 9 22 | 23 | - name: Use Node.js 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | cache: "pnpm" 28 | 29 | - name: Install dependencies 30 | run: pnpm install --frozen-lockfile 31 | 32 | - name: Biome format check 33 | run: pnpm check:format 34 | 35 | - name: Biome lint 36 | run: pnpm check:lint 37 | 38 | - name: Run tests 39 | run: pnpm test 40 | 41 | - name: Build 42 | run: pnpm build 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Zebulon Piasecki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

diffable-objects

2 | 3 |

4 | A package for dynamic state tracking for Cloudflare's Durable Objects using SQLite. 5 |

6 | 7 |

8 | 9 | downloads 10 | 11 | 12 | npm version 13 | 14 | 15 | MIT license 16 | 17 |

18 | 19 | ## Installation 20 | 21 | ``` 22 | # NPM 23 | $ npm install --save diffable-objects 24 | # Yarn 25 | $ yarn add diffable-objects 26 | # PNPM 27 | $ pnpm add diffable-objects 28 | # Bun 29 | $ bun add diffable-objects 30 | ``` 31 | 32 | ## Example 33 | 34 | > For complete examples see the [examples](./examples/) directory. 35 | 36 | Basic example of `diffable-objects`. 37 | 38 | ```typescript 39 | import { DurableObject } from "cloudflare:workers"; 40 | export { diffable, state } from "diffable-objects"; 41 | 42 | export class SampleObject extends DurableObject { 43 | // Within a durale object we can register a property to 44 | // have its values automatically tracked and persisted. 45 | #state = state(this.ctx, "state", { count: 0 }); 46 | 47 | increment() { 48 | this.#state.count++; 49 | } 50 | } 51 | 52 | // Currently requires wrangler@next 53 | export class DecoratorObject extends DurableObject { 54 | // You can also use decorators if you'd prefer a simpler 55 | // (but more magic) syntax. 56 | @diffable 57 | #state = { count: 0 }; 58 | 59 | // Snapshot policies are configrable via an options object. 60 | @diffable({ snapshotPolicy: "every-change" }) 61 | #stateWithOptions = { count: 0 }; 62 | 63 | increment() { 64 | this.#state.count++; 65 | this.#stateWithOptions.count++; 66 | } 67 | } 68 | ``` 69 | 70 | ## License 71 | 72 | Distributed under the MIT License. See [LICENSE](LICENSE) for more information. 73 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": false, 5 | "clientKind": "git", 6 | "useIgnoreFile": false 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": ["dist/**/*", "node_modules/**/*", "examples/**/*"] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "indentStyle": "space", 15 | "indentWidth": 2 16 | }, 17 | "organizeImports": { 18 | "enabled": true 19 | }, 20 | "linter": { 21 | "enabled": true, 22 | "rules": { 23 | "recommended": true, 24 | "suspicious": { 25 | "noExplicitAny": "off" 26 | } 27 | } 28 | }, 29 | "javascript": { 30 | "formatter": { 31 | "quoteStyle": "double" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/using-decorators/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /examples/using-decorators/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | 3 | logs 4 | _.log 5 | npm-debug.log_ 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | 13 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 14 | 15 | # Runtime data 16 | 17 | pids 18 | _.pid 19 | _.seed 20 | \*.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | 28 | coverage 29 | \*.lcov 30 | 31 | # nyc test coverage 32 | 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | 41 | bower_components 42 | 43 | # node-waf configuration 44 | 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | 49 | build/Release 50 | 51 | # Dependency directories 52 | 53 | node_modules/ 54 | jspm_packages/ 55 | 56 | # Snowpack dependency directory (https://snowpack.dev/) 57 | 58 | web_modules/ 59 | 60 | # TypeScript cache 61 | 62 | \*.tsbuildinfo 63 | 64 | # Optional npm cache directory 65 | 66 | .npm 67 | 68 | # Optional eslint cache 69 | 70 | .eslintcache 71 | 72 | # Optional stylelint cache 73 | 74 | .stylelintcache 75 | 76 | # Microbundle cache 77 | 78 | .rpt2_cache/ 79 | .rts2_cache_cjs/ 80 | .rts2_cache_es/ 81 | .rts2_cache_umd/ 82 | 83 | # Optional REPL history 84 | 85 | .node_repl_history 86 | 87 | # Output of 'npm pack' 88 | 89 | \*.tgz 90 | 91 | # Yarn Integrity file 92 | 93 | .yarn-integrity 94 | 95 | # dotenv environment variable files 96 | 97 | .env 98 | .env.development.local 99 | .env.test.local 100 | .env.production.local 101 | .env.local 102 | 103 | # parcel-bundler cache (https://parceljs.org/) 104 | 105 | .cache 106 | .parcel-cache 107 | 108 | # Next.js build output 109 | 110 | .next 111 | out 112 | 113 | # Nuxt.js build / generate output 114 | 115 | .nuxt 116 | dist 117 | 118 | # Gatsby files 119 | 120 | .cache/ 121 | 122 | # Comment in the public line in if your project uses Gatsby and not Next.js 123 | 124 | # https://nextjs.org/blog/next-9-1#public-directory-support 125 | 126 | # public 127 | 128 | # vuepress build output 129 | 130 | .vuepress/dist 131 | 132 | # vuepress v2.x temp and cache directory 133 | 134 | .temp 135 | .cache 136 | 137 | # Docusaurus cache and generated files 138 | 139 | .docusaurus 140 | 141 | # Serverless directories 142 | 143 | .serverless/ 144 | 145 | # FuseBox cache 146 | 147 | .fusebox/ 148 | 149 | # DynamoDB Local files 150 | 151 | .dynamodb/ 152 | 153 | # TernJS port file 154 | 155 | .tern-port 156 | 157 | # Stores VSCode versions used for testing VSCode extensions 158 | 159 | .vscode-test 160 | 161 | # yarn v2 162 | 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.\* 168 | 169 | # wrangler project 170 | 171 | .dev.vars 172 | .wrangler/ 173 | -------------------------------------------------------------------------------- /examples/using-decorators/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "singleQuote": true, 4 | "semi": true, 5 | "useTabs": true 6 | } 7 | -------------------------------------------------------------------------------- /examples/using-decorators/README.md: -------------------------------------------------------------------------------- 1 | # using-decorators 2 | 3 | This sample updates the [Hello World Durable Object](https://github.com/cloudflare/workers-sdk/tree/main/packages/create-cloudflare/templates/hello-world-durable-object/ts) template from Cloudflare to use `diffable-objects` using decorators. 4 | 5 | ## Note 6 | 7 | Because `wrangler`, Cloudflare's Workers CLI, uses an older version of `esbuild` you must use `wrangler@next` in your Worker until the next major release. 8 | 9 | ## Try it out 10 | 11 | ``` 12 | pnpm dev 13 | ``` -------------------------------------------------------------------------------- /examples/using-decorators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "using-decorators", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "cf-typegen": "wrangler types" 10 | }, 11 | "devDependencies": { 12 | "@cloudflare/workers-types": "^4.20241224.0", 13 | "typescript": "^5.5.2", 14 | "wrangler": "0.0.0-dc669c404" 15 | }, 16 | "dependencies": { 17 | "diffable-objects": "^0.1.1" 18 | } 19 | } -------------------------------------------------------------------------------- /examples/using-decorators/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@cloudflare/workers-types': 12 | specifier: ^4.20241224.0 13 | version: 4.20241224.0 14 | typescript: 15 | specifier: ^5.5.2 16 | version: 5.7.2 17 | wrangler: 18 | specifier: ^3.60.3 19 | version: 3.99.0(@cloudflare/workers-types@4.20241224.0) 20 | 21 | packages: 22 | 23 | '@cloudflare/kv-asset-handler@0.3.4': 24 | resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} 25 | engines: {node: '>=16.13'} 26 | 27 | '@cloudflare/workerd-darwin-64@1.20241218.0': 28 | resolution: {integrity: sha512-8rveQoxtUvlmORKqTWgjv2ycM8uqWox0u9evn3zd2iWKdou5sncFwH517ZRLI3rq9P31ZLmCQBZ0gloFsTeY6w==} 29 | engines: {node: '>=16'} 30 | cpu: [x64] 31 | os: [darwin] 32 | 33 | '@cloudflare/workerd-darwin-arm64@1.20241218.0': 34 | resolution: {integrity: sha512-be59Ad9nmM9lCkhHqmTs/uZ3JVZt8NJ9Z0PY+B0xnc5z6WwmV2lj0RVLtq7xJhQsQJA189zt5rXqDP6J+2mu7Q==} 35 | engines: {node: '>=16'} 36 | cpu: [arm64] 37 | os: [darwin] 38 | 39 | '@cloudflare/workerd-linux-64@1.20241218.0': 40 | resolution: {integrity: sha512-MzpSBcfZXRxrYWxQ4pVDYDrUbkQuM62ssl4ZtHH8J35OAeGsWFAYji6MkS2SpVwVcvacPwJXIF4JSzp4xKImKw==} 41 | engines: {node: '>=16'} 42 | cpu: [x64] 43 | os: [linux] 44 | 45 | '@cloudflare/workerd-linux-arm64@1.20241218.0': 46 | resolution: {integrity: sha512-RIuJjPxpNqvwIs52vQsXeRMttvhIjgg9NLjjFa3jK8Ijnj8c3ZDru9Wqi48lJP07yDFIRr4uDMMqh/y29YQi2A==} 47 | engines: {node: '>=16'} 48 | cpu: [arm64] 49 | os: [linux] 50 | 51 | '@cloudflare/workerd-windows-64@1.20241218.0': 52 | resolution: {integrity: sha512-tO1VjlvK3F6Yb2d1jgEy/QBYl//9Pyv3K0j+lq8Eu7qdfm0IgKwSRgDWLept84/qmNsQfausZ4JdNGxTf9xsxQ==} 53 | engines: {node: '>=16'} 54 | cpu: [x64] 55 | os: [win32] 56 | 57 | '@cloudflare/workers-types@4.20241224.0': 58 | resolution: {integrity: sha512-1ZmFc8qqM7S/HUGmLplc4P8n8DoMqiJmc47r9Lr7VbuaotoqCXVljz09w1V1mc4K3pbFPgvqSy4XYStZ08HrlQ==} 59 | 60 | '@cspotcode/source-map-support@0.8.1': 61 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 62 | engines: {node: '>=12'} 63 | 64 | '@esbuild-plugins/node-globals-polyfill@0.2.3': 65 | resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} 66 | peerDependencies: 67 | esbuild: '*' 68 | 69 | '@esbuild-plugins/node-modules-polyfill@0.2.2': 70 | resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} 71 | peerDependencies: 72 | esbuild: '*' 73 | 74 | '@esbuild/android-arm64@0.17.19': 75 | resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} 76 | engines: {node: '>=12'} 77 | cpu: [arm64] 78 | os: [android] 79 | 80 | '@esbuild/android-arm@0.17.19': 81 | resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} 82 | engines: {node: '>=12'} 83 | cpu: [arm] 84 | os: [android] 85 | 86 | '@esbuild/android-x64@0.17.19': 87 | resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} 88 | engines: {node: '>=12'} 89 | cpu: [x64] 90 | os: [android] 91 | 92 | '@esbuild/darwin-arm64@0.17.19': 93 | resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} 94 | engines: {node: '>=12'} 95 | cpu: [arm64] 96 | os: [darwin] 97 | 98 | '@esbuild/darwin-x64@0.17.19': 99 | resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} 100 | engines: {node: '>=12'} 101 | cpu: [x64] 102 | os: [darwin] 103 | 104 | '@esbuild/freebsd-arm64@0.17.19': 105 | resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} 106 | engines: {node: '>=12'} 107 | cpu: [arm64] 108 | os: [freebsd] 109 | 110 | '@esbuild/freebsd-x64@0.17.19': 111 | resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} 112 | engines: {node: '>=12'} 113 | cpu: [x64] 114 | os: [freebsd] 115 | 116 | '@esbuild/linux-arm64@0.17.19': 117 | resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} 118 | engines: {node: '>=12'} 119 | cpu: [arm64] 120 | os: [linux] 121 | 122 | '@esbuild/linux-arm@0.17.19': 123 | resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} 124 | engines: {node: '>=12'} 125 | cpu: [arm] 126 | os: [linux] 127 | 128 | '@esbuild/linux-ia32@0.17.19': 129 | resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} 130 | engines: {node: '>=12'} 131 | cpu: [ia32] 132 | os: [linux] 133 | 134 | '@esbuild/linux-loong64@0.17.19': 135 | resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} 136 | engines: {node: '>=12'} 137 | cpu: [loong64] 138 | os: [linux] 139 | 140 | '@esbuild/linux-mips64el@0.17.19': 141 | resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} 142 | engines: {node: '>=12'} 143 | cpu: [mips64el] 144 | os: [linux] 145 | 146 | '@esbuild/linux-ppc64@0.17.19': 147 | resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} 148 | engines: {node: '>=12'} 149 | cpu: [ppc64] 150 | os: [linux] 151 | 152 | '@esbuild/linux-riscv64@0.17.19': 153 | resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} 154 | engines: {node: '>=12'} 155 | cpu: [riscv64] 156 | os: [linux] 157 | 158 | '@esbuild/linux-s390x@0.17.19': 159 | resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} 160 | engines: {node: '>=12'} 161 | cpu: [s390x] 162 | os: [linux] 163 | 164 | '@esbuild/linux-x64@0.17.19': 165 | resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} 166 | engines: {node: '>=12'} 167 | cpu: [x64] 168 | os: [linux] 169 | 170 | '@esbuild/netbsd-x64@0.17.19': 171 | resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} 172 | engines: {node: '>=12'} 173 | cpu: [x64] 174 | os: [netbsd] 175 | 176 | '@esbuild/openbsd-x64@0.17.19': 177 | resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} 178 | engines: {node: '>=12'} 179 | cpu: [x64] 180 | os: [openbsd] 181 | 182 | '@esbuild/sunos-x64@0.17.19': 183 | resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} 184 | engines: {node: '>=12'} 185 | cpu: [x64] 186 | os: [sunos] 187 | 188 | '@esbuild/win32-arm64@0.17.19': 189 | resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} 190 | engines: {node: '>=12'} 191 | cpu: [arm64] 192 | os: [win32] 193 | 194 | '@esbuild/win32-ia32@0.17.19': 195 | resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} 196 | engines: {node: '>=12'} 197 | cpu: [ia32] 198 | os: [win32] 199 | 200 | '@esbuild/win32-x64@0.17.19': 201 | resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} 202 | engines: {node: '>=12'} 203 | cpu: [x64] 204 | os: [win32] 205 | 206 | '@fastify/busboy@2.1.1': 207 | resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} 208 | engines: {node: '>=14'} 209 | 210 | '@jridgewell/resolve-uri@3.1.2': 211 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 212 | engines: {node: '>=6.0.0'} 213 | 214 | '@jridgewell/sourcemap-codec@1.5.0': 215 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 216 | 217 | '@jridgewell/trace-mapping@0.3.9': 218 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 219 | 220 | '@types/node-forge@1.3.11': 221 | resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} 222 | 223 | '@types/node@22.10.2': 224 | resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} 225 | 226 | acorn-walk@8.3.4: 227 | resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} 228 | engines: {node: '>=0.4.0'} 229 | 230 | acorn@8.14.0: 231 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} 232 | engines: {node: '>=0.4.0'} 233 | hasBin: true 234 | 235 | as-table@1.0.55: 236 | resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} 237 | 238 | blake3-wasm@2.1.5: 239 | resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} 240 | 241 | capnp-ts@0.7.0: 242 | resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} 243 | 244 | chokidar@4.0.3: 245 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 246 | engines: {node: '>= 14.16.0'} 247 | 248 | cookie@0.7.2: 249 | resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} 250 | engines: {node: '>= 0.6'} 251 | 252 | data-uri-to-buffer@2.0.2: 253 | resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} 254 | 255 | date-fns@4.1.0: 256 | resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} 257 | 258 | debug@4.4.0: 259 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 260 | engines: {node: '>=6.0'} 261 | peerDependencies: 262 | supports-color: '*' 263 | peerDependenciesMeta: 264 | supports-color: 265 | optional: true 266 | 267 | defu@6.1.4: 268 | resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} 269 | 270 | esbuild@0.17.19: 271 | resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} 272 | engines: {node: '>=12'} 273 | hasBin: true 274 | 275 | escape-string-regexp@4.0.0: 276 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 277 | engines: {node: '>=10'} 278 | 279 | estree-walker@0.6.1: 280 | resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} 281 | 282 | exit-hook@2.2.1: 283 | resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} 284 | engines: {node: '>=6'} 285 | 286 | fsevents@2.3.3: 287 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 288 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 289 | os: [darwin] 290 | 291 | function-bind@1.1.2: 292 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 293 | 294 | get-source@2.0.12: 295 | resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} 296 | 297 | glob-to-regexp@0.4.1: 298 | resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} 299 | 300 | hasown@2.0.2: 301 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 302 | engines: {node: '>= 0.4'} 303 | 304 | is-core-module@2.16.1: 305 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 306 | engines: {node: '>= 0.4'} 307 | 308 | itty-time@1.0.6: 309 | resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} 310 | 311 | magic-string@0.25.9: 312 | resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} 313 | 314 | mime@3.0.0: 315 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 316 | engines: {node: '>=10.0.0'} 317 | hasBin: true 318 | 319 | miniflare@3.20241218.0: 320 | resolution: {integrity: sha512-spYFDArH0wd+wJSTrzBrWrXJrbyJhRMJa35mat947y1jYhVV8I5V8vnD3LwjfpLr0SaEilojz1OIW7ekmnRe+w==} 321 | engines: {node: '>=16.13'} 322 | hasBin: true 323 | 324 | ms@2.1.3: 325 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 326 | 327 | mustache@4.2.0: 328 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 329 | hasBin: true 330 | 331 | nanoid@3.3.8: 332 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 333 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 334 | hasBin: true 335 | 336 | node-forge@1.3.1: 337 | resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} 338 | engines: {node: '>= 6.13.0'} 339 | 340 | ohash@1.1.4: 341 | resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} 342 | 343 | path-parse@1.0.7: 344 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 345 | 346 | path-to-regexp@6.3.0: 347 | resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} 348 | 349 | pathe@1.1.2: 350 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} 351 | 352 | printable-characters@1.0.42: 353 | resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} 354 | 355 | readdirp@4.0.2: 356 | resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} 357 | engines: {node: '>= 14.16.0'} 358 | 359 | resolve@1.22.10: 360 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 361 | engines: {node: '>= 0.4'} 362 | hasBin: true 363 | 364 | rollup-plugin-inject@3.0.2: 365 | resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} 366 | deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. 367 | 368 | rollup-plugin-node-polyfills@0.2.1: 369 | resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} 370 | 371 | rollup-pluginutils@2.8.2: 372 | resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} 373 | 374 | selfsigned@2.4.1: 375 | resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} 376 | engines: {node: '>=10'} 377 | 378 | source-map@0.6.1: 379 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 380 | engines: {node: '>=0.10.0'} 381 | 382 | sourcemap-codec@1.4.8: 383 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 384 | deprecated: Please use @jridgewell/sourcemap-codec instead 385 | 386 | stacktracey@2.1.8: 387 | resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} 388 | 389 | stoppable@1.1.0: 390 | resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} 391 | engines: {node: '>=4', npm: '>=6'} 392 | 393 | supports-preserve-symlinks-flag@1.0.0: 394 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 395 | engines: {node: '>= 0.4'} 396 | 397 | tslib@2.8.1: 398 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 399 | 400 | typescript@5.7.2: 401 | resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} 402 | engines: {node: '>=14.17'} 403 | hasBin: true 404 | 405 | ufo@1.5.4: 406 | resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} 407 | 408 | undici-types@6.20.0: 409 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 410 | 411 | undici@5.28.4: 412 | resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} 413 | engines: {node: '>=14.0'} 414 | 415 | unenv-nightly@2.0.0-20241204-140205-a5d5190: 416 | resolution: {integrity: sha512-jpmAytLeiiW01pl5bhVn9wYJ4vtiLdhGe10oXlJBuQEX8mxjxO8BlEXGHU4vr4yEikjFP1wsomTHt/CLU8kUwg==} 417 | 418 | workerd@1.20241218.0: 419 | resolution: {integrity: sha512-7Z3D4vOVChMz9mWDffE299oQxUWm/pbkeAWx1btVamPcAK/2IuoNBhwflWo3jyuKuxvYuFAdIucgYxc8ICqXiA==} 420 | engines: {node: '>=16'} 421 | hasBin: true 422 | 423 | wrangler@3.99.0: 424 | resolution: {integrity: sha512-k0x4rT3G/QCbxcoZY7CHRVlAIS8WMmKdga6lf4d2c3gXFqssh44vwlTDuARA9QANBxKJTcA7JPTJRfUDhd9QBA==} 425 | engines: {node: '>=16.17.0'} 426 | hasBin: true 427 | peerDependencies: 428 | '@cloudflare/workers-types': ^4.20241218.0 429 | peerDependenciesMeta: 430 | '@cloudflare/workers-types': 431 | optional: true 432 | 433 | ws@8.18.0: 434 | resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} 435 | engines: {node: '>=10.0.0'} 436 | peerDependencies: 437 | bufferutil: ^4.0.1 438 | utf-8-validate: '>=5.0.2' 439 | peerDependenciesMeta: 440 | bufferutil: 441 | optional: true 442 | utf-8-validate: 443 | optional: true 444 | 445 | xxhash-wasm@1.1.0: 446 | resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} 447 | 448 | youch@3.3.4: 449 | resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} 450 | 451 | zod@3.24.1: 452 | resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} 453 | 454 | snapshots: 455 | 456 | '@cloudflare/kv-asset-handler@0.3.4': 457 | dependencies: 458 | mime: 3.0.0 459 | 460 | '@cloudflare/workerd-darwin-64@1.20241218.0': 461 | optional: true 462 | 463 | '@cloudflare/workerd-darwin-arm64@1.20241218.0': 464 | optional: true 465 | 466 | '@cloudflare/workerd-linux-64@1.20241218.0': 467 | optional: true 468 | 469 | '@cloudflare/workerd-linux-arm64@1.20241218.0': 470 | optional: true 471 | 472 | '@cloudflare/workerd-windows-64@1.20241218.0': 473 | optional: true 474 | 475 | '@cloudflare/workers-types@4.20241224.0': {} 476 | 477 | '@cspotcode/source-map-support@0.8.1': 478 | dependencies: 479 | '@jridgewell/trace-mapping': 0.3.9 480 | 481 | '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': 482 | dependencies: 483 | esbuild: 0.17.19 484 | 485 | '@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19)': 486 | dependencies: 487 | esbuild: 0.17.19 488 | escape-string-regexp: 4.0.0 489 | rollup-plugin-node-polyfills: 0.2.1 490 | 491 | '@esbuild/android-arm64@0.17.19': 492 | optional: true 493 | 494 | '@esbuild/android-arm@0.17.19': 495 | optional: true 496 | 497 | '@esbuild/android-x64@0.17.19': 498 | optional: true 499 | 500 | '@esbuild/darwin-arm64@0.17.19': 501 | optional: true 502 | 503 | '@esbuild/darwin-x64@0.17.19': 504 | optional: true 505 | 506 | '@esbuild/freebsd-arm64@0.17.19': 507 | optional: true 508 | 509 | '@esbuild/freebsd-x64@0.17.19': 510 | optional: true 511 | 512 | '@esbuild/linux-arm64@0.17.19': 513 | optional: true 514 | 515 | '@esbuild/linux-arm@0.17.19': 516 | optional: true 517 | 518 | '@esbuild/linux-ia32@0.17.19': 519 | optional: true 520 | 521 | '@esbuild/linux-loong64@0.17.19': 522 | optional: true 523 | 524 | '@esbuild/linux-mips64el@0.17.19': 525 | optional: true 526 | 527 | '@esbuild/linux-ppc64@0.17.19': 528 | optional: true 529 | 530 | '@esbuild/linux-riscv64@0.17.19': 531 | optional: true 532 | 533 | '@esbuild/linux-s390x@0.17.19': 534 | optional: true 535 | 536 | '@esbuild/linux-x64@0.17.19': 537 | optional: true 538 | 539 | '@esbuild/netbsd-x64@0.17.19': 540 | optional: true 541 | 542 | '@esbuild/openbsd-x64@0.17.19': 543 | optional: true 544 | 545 | '@esbuild/sunos-x64@0.17.19': 546 | optional: true 547 | 548 | '@esbuild/win32-arm64@0.17.19': 549 | optional: true 550 | 551 | '@esbuild/win32-ia32@0.17.19': 552 | optional: true 553 | 554 | '@esbuild/win32-x64@0.17.19': 555 | optional: true 556 | 557 | '@fastify/busboy@2.1.1': {} 558 | 559 | '@jridgewell/resolve-uri@3.1.2': {} 560 | 561 | '@jridgewell/sourcemap-codec@1.5.0': {} 562 | 563 | '@jridgewell/trace-mapping@0.3.9': 564 | dependencies: 565 | '@jridgewell/resolve-uri': 3.1.2 566 | '@jridgewell/sourcemap-codec': 1.5.0 567 | 568 | '@types/node-forge@1.3.11': 569 | dependencies: 570 | '@types/node': 22.10.2 571 | 572 | '@types/node@22.10.2': 573 | dependencies: 574 | undici-types: 6.20.0 575 | 576 | acorn-walk@8.3.4: 577 | dependencies: 578 | acorn: 8.14.0 579 | 580 | acorn@8.14.0: {} 581 | 582 | as-table@1.0.55: 583 | dependencies: 584 | printable-characters: 1.0.42 585 | 586 | blake3-wasm@2.1.5: {} 587 | 588 | capnp-ts@0.7.0: 589 | dependencies: 590 | debug: 4.4.0 591 | tslib: 2.8.1 592 | transitivePeerDependencies: 593 | - supports-color 594 | 595 | chokidar@4.0.3: 596 | dependencies: 597 | readdirp: 4.0.2 598 | 599 | cookie@0.7.2: {} 600 | 601 | data-uri-to-buffer@2.0.2: {} 602 | 603 | date-fns@4.1.0: {} 604 | 605 | debug@4.4.0: 606 | dependencies: 607 | ms: 2.1.3 608 | 609 | defu@6.1.4: {} 610 | 611 | esbuild@0.17.19: 612 | optionalDependencies: 613 | '@esbuild/android-arm': 0.17.19 614 | '@esbuild/android-arm64': 0.17.19 615 | '@esbuild/android-x64': 0.17.19 616 | '@esbuild/darwin-arm64': 0.17.19 617 | '@esbuild/darwin-x64': 0.17.19 618 | '@esbuild/freebsd-arm64': 0.17.19 619 | '@esbuild/freebsd-x64': 0.17.19 620 | '@esbuild/linux-arm': 0.17.19 621 | '@esbuild/linux-arm64': 0.17.19 622 | '@esbuild/linux-ia32': 0.17.19 623 | '@esbuild/linux-loong64': 0.17.19 624 | '@esbuild/linux-mips64el': 0.17.19 625 | '@esbuild/linux-ppc64': 0.17.19 626 | '@esbuild/linux-riscv64': 0.17.19 627 | '@esbuild/linux-s390x': 0.17.19 628 | '@esbuild/linux-x64': 0.17.19 629 | '@esbuild/netbsd-x64': 0.17.19 630 | '@esbuild/openbsd-x64': 0.17.19 631 | '@esbuild/sunos-x64': 0.17.19 632 | '@esbuild/win32-arm64': 0.17.19 633 | '@esbuild/win32-ia32': 0.17.19 634 | '@esbuild/win32-x64': 0.17.19 635 | 636 | escape-string-regexp@4.0.0: {} 637 | 638 | estree-walker@0.6.1: {} 639 | 640 | exit-hook@2.2.1: {} 641 | 642 | fsevents@2.3.3: 643 | optional: true 644 | 645 | function-bind@1.1.2: {} 646 | 647 | get-source@2.0.12: 648 | dependencies: 649 | data-uri-to-buffer: 2.0.2 650 | source-map: 0.6.1 651 | 652 | glob-to-regexp@0.4.1: {} 653 | 654 | hasown@2.0.2: 655 | dependencies: 656 | function-bind: 1.1.2 657 | 658 | is-core-module@2.16.1: 659 | dependencies: 660 | hasown: 2.0.2 661 | 662 | itty-time@1.0.6: {} 663 | 664 | magic-string@0.25.9: 665 | dependencies: 666 | sourcemap-codec: 1.4.8 667 | 668 | mime@3.0.0: {} 669 | 670 | miniflare@3.20241218.0: 671 | dependencies: 672 | '@cspotcode/source-map-support': 0.8.1 673 | acorn: 8.14.0 674 | acorn-walk: 8.3.4 675 | capnp-ts: 0.7.0 676 | exit-hook: 2.2.1 677 | glob-to-regexp: 0.4.1 678 | stoppable: 1.1.0 679 | undici: 5.28.4 680 | workerd: 1.20241218.0 681 | ws: 8.18.0 682 | youch: 3.3.4 683 | zod: 3.24.1 684 | transitivePeerDependencies: 685 | - bufferutil 686 | - supports-color 687 | - utf-8-validate 688 | 689 | ms@2.1.3: {} 690 | 691 | mustache@4.2.0: {} 692 | 693 | nanoid@3.3.8: {} 694 | 695 | node-forge@1.3.1: {} 696 | 697 | ohash@1.1.4: {} 698 | 699 | path-parse@1.0.7: {} 700 | 701 | path-to-regexp@6.3.0: {} 702 | 703 | pathe@1.1.2: {} 704 | 705 | printable-characters@1.0.42: {} 706 | 707 | readdirp@4.0.2: {} 708 | 709 | resolve@1.22.10: 710 | dependencies: 711 | is-core-module: 2.16.1 712 | path-parse: 1.0.7 713 | supports-preserve-symlinks-flag: 1.0.0 714 | 715 | rollup-plugin-inject@3.0.2: 716 | dependencies: 717 | estree-walker: 0.6.1 718 | magic-string: 0.25.9 719 | rollup-pluginutils: 2.8.2 720 | 721 | rollup-plugin-node-polyfills@0.2.1: 722 | dependencies: 723 | rollup-plugin-inject: 3.0.2 724 | 725 | rollup-pluginutils@2.8.2: 726 | dependencies: 727 | estree-walker: 0.6.1 728 | 729 | selfsigned@2.4.1: 730 | dependencies: 731 | '@types/node-forge': 1.3.11 732 | node-forge: 1.3.1 733 | 734 | source-map@0.6.1: {} 735 | 736 | sourcemap-codec@1.4.8: {} 737 | 738 | stacktracey@2.1.8: 739 | dependencies: 740 | as-table: 1.0.55 741 | get-source: 2.0.12 742 | 743 | stoppable@1.1.0: {} 744 | 745 | supports-preserve-symlinks-flag@1.0.0: {} 746 | 747 | tslib@2.8.1: {} 748 | 749 | typescript@5.7.2: {} 750 | 751 | ufo@1.5.4: {} 752 | 753 | undici-types@6.20.0: {} 754 | 755 | undici@5.28.4: 756 | dependencies: 757 | '@fastify/busboy': 2.1.1 758 | 759 | unenv-nightly@2.0.0-20241204-140205-a5d5190: 760 | dependencies: 761 | defu: 6.1.4 762 | ohash: 1.1.4 763 | pathe: 1.1.2 764 | ufo: 1.5.4 765 | 766 | workerd@1.20241218.0: 767 | optionalDependencies: 768 | '@cloudflare/workerd-darwin-64': 1.20241218.0 769 | '@cloudflare/workerd-darwin-arm64': 1.20241218.0 770 | '@cloudflare/workerd-linux-64': 1.20241218.0 771 | '@cloudflare/workerd-linux-arm64': 1.20241218.0 772 | '@cloudflare/workerd-windows-64': 1.20241218.0 773 | 774 | wrangler@3.99.0(@cloudflare/workers-types@4.20241224.0): 775 | dependencies: 776 | '@cloudflare/kv-asset-handler': 0.3.4 777 | '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) 778 | '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) 779 | blake3-wasm: 2.1.5 780 | chokidar: 4.0.3 781 | date-fns: 4.1.0 782 | esbuild: 0.17.19 783 | itty-time: 1.0.6 784 | miniflare: 3.20241218.0 785 | nanoid: 3.3.8 786 | path-to-regexp: 6.3.0 787 | resolve: 1.22.10 788 | selfsigned: 2.4.1 789 | source-map: 0.6.1 790 | unenv: unenv-nightly@2.0.0-20241204-140205-a5d5190 791 | workerd: 1.20241218.0 792 | xxhash-wasm: 1.1.0 793 | optionalDependencies: 794 | '@cloudflare/workers-types': 4.20241224.0 795 | fsevents: 2.3.3 796 | transitivePeerDependencies: 797 | - bufferutil 798 | - supports-color 799 | - utf-8-validate 800 | 801 | ws@8.18.0: {} 802 | 803 | xxhash-wasm@1.1.0: {} 804 | 805 | youch@3.3.4: 806 | dependencies: 807 | cookie: 0.7.2 808 | mustache: 4.2.0 809 | stacktracey: 2.1.8 810 | 811 | zod@3.24.1: {} 812 | -------------------------------------------------------------------------------- /examples/using-decorators/src/index.ts: -------------------------------------------------------------------------------- 1 | import { DurableObject } from "cloudflare:workers"; 2 | import { diffable } from "diffable-objects"; 3 | 4 | /** 5 | * Welcome to Cloudflare Workers! This is your first Durable Objects application. 6 | * 7 | * - Run `npm run dev` in your terminal to start a development server 8 | * - Open a browser tab at http://localhost:8787/ to see your Durable Object in action 9 | * - Run `npm run deploy` to publish your application 10 | * 11 | * Bind resources to your worker in `wrangler.toml`. After adding bindings, a type definition for the 12 | * `Env` object can be regenerated with `npm run cf-typegen`. 13 | * 14 | * Learn more at https://developers.cloudflare.com/durable-objects 15 | */ 16 | 17 | /** A Durable Object's behavior is defined in an exported Javascript class */ 18 | export class MyDurableObject extends DurableObject { 19 | /** 20 | * The state of a Durable Object is defined using the `diffable` decorator 21 | */ 22 | @diffable 23 | #state = { count: 0 }; 24 | 25 | /** 26 | * The constructor is invoked once upon creation of the Durable Object, i.e. the first call to 27 | * `DurableObjectStub::get` for a given identifier (no-op constructors can be omitted) 28 | * 29 | * @param ctx - The interface for interacting with Durable Object state 30 | * @param env - The interface to reference bindings declared in wrangler.toml 31 | */ 32 | constructor(ctx: DurableObjectState, env: Env) { 33 | super(ctx, env); 34 | } 35 | 36 | /** 37 | * The Durable Object exposes an RPC method increment which will be invoked when when a Durable 38 | * Object instance receives a request from a Worker via the same method invocation on the stub 39 | * 40 | * @returns The number of times the method has been called on this Durable Object instance 41 | */ 42 | async increment(): Promise { 43 | this.#state.count++; 44 | return this.#state.count; 45 | } 46 | } 47 | 48 | export default { 49 | /** 50 | * This is the standard fetch handler for a Cloudflare Worker 51 | * 52 | * @param request - The request submitted to the Worker from the client 53 | * @param env - The interface to reference bindings declared in wrangler.toml 54 | * @param ctx - The execution context of the Worker 55 | * @returns The response to be sent back to the client 56 | */ 57 | async fetch(request, env, ctx): Promise { 58 | // We will create a `DurableObjectId` using the pathname from the Worker request 59 | // This id refers to a unique instance of our 'MyDurableObject' class above 60 | const id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName(new URL(request.url).pathname); 61 | 62 | // This stub creates a communication channel with the Durable Object instance 63 | // The Durable Object constructor will be invoked upon the first call for a given id 64 | const stub = env.MY_DURABLE_OBJECT.get(id); 65 | 66 | // We call the `increment()` RPC method on the stub to invoke the method on the remote 67 | // Durable Object instance 68 | const count = await stub.increment(); 69 | 70 | return Response.json({ count }); 71 | }, 72 | } satisfies ExportedHandler; 73 | -------------------------------------------------------------------------------- /examples/using-decorators/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 6 | "target": "es2021", 7 | /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 8 | "lib": ["es2021"], 9 | /* Specify what JSX code is generated. */ 10 | "jsx": "react-jsx", 11 | 12 | /* Specify what module code is generated. */ 13 | "module": "es2022", 14 | /* Specify how TypeScript looks up a file from a given module specifier. */ 15 | "moduleResolution": "node", 16 | /* Specify type package names to be included without being referenced in a source file. */ 17 | "types": [ 18 | "@cloudflare/workers-types/2023-07-01" 19 | ], 20 | /* Enable importing .json files */ 21 | "resolveJsonModule": true, 22 | 23 | /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 24 | "allowJs": true, 25 | /* Enable error reporting in type-checked JavaScript files. */ 26 | "checkJs": false, 27 | 28 | /* Disable emitting files from a compilation. */ 29 | "noEmit": true, 30 | 31 | /* Ensure that each file can be safely transpiled without relying on other imports. */ 32 | "isolatedModules": true, 33 | /* Allow 'import x from y' when a module doesn't have a default export. */ 34 | "allowSyntheticDefaultImports": true, 35 | /* Ensure that casing is correct in imports. */ 36 | "forceConsistentCasingInFileNames": true, 37 | 38 | /* Enable all strict type-checking options. */ 39 | "strict": true, 40 | 41 | /* Skip type checking all .d.ts files. */ 42 | "skipLibCheck": true 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/using-decorators/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env { 4 | MY_DURABLE_OBJECT: DurableObjectNamespace; 5 | } 6 | -------------------------------------------------------------------------------- /examples/using-decorators/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "using-decorators" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-12-24" 5 | 6 | # Workers Logs 7 | # Docs: https://developers.cloudflare.com/workers/observability/logs/workers-logs/ 8 | # Configuration: https://developers.cloudflare.com/workers/observability/logs/workers-logs/#enable-workers-logs 9 | [observability] 10 | enabled = true 11 | 12 | # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. 13 | # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. 14 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects 15 | [[durable_objects.bindings]] 16 | name = "MY_DURABLE_OBJECT" 17 | class_name = "MyDurableObject" 18 | 19 | # Durable Object migrations. 20 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations 21 | [[migrations]] 22 | tag = "v1" 23 | new_sqlite_classes = ["MyDurableObject"] # diffable-objects requires a class to use sqlite 24 | -------------------------------------------------------------------------------- /examples/using-state/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.yml] 12 | indent_style = space 13 | -------------------------------------------------------------------------------- /examples/using-state/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | 3 | logs 4 | _.log 5 | npm-debug.log_ 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | 13 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 14 | 15 | # Runtime data 16 | 17 | pids 18 | _.pid 19 | _.seed 20 | \*.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | 28 | coverage 29 | \*.lcov 30 | 31 | # nyc test coverage 32 | 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | 37 | .grunt 38 | 39 | # Bower dependency directory (https://bower.io/) 40 | 41 | bower_components 42 | 43 | # node-waf configuration 44 | 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | 49 | build/Release 50 | 51 | # Dependency directories 52 | 53 | node_modules/ 54 | jspm_packages/ 55 | 56 | # Snowpack dependency directory (https://snowpack.dev/) 57 | 58 | web_modules/ 59 | 60 | # TypeScript cache 61 | 62 | \*.tsbuildinfo 63 | 64 | # Optional npm cache directory 65 | 66 | .npm 67 | 68 | # Optional eslint cache 69 | 70 | .eslintcache 71 | 72 | # Optional stylelint cache 73 | 74 | .stylelintcache 75 | 76 | # Microbundle cache 77 | 78 | .rpt2_cache/ 79 | .rts2_cache_cjs/ 80 | .rts2_cache_es/ 81 | .rts2_cache_umd/ 82 | 83 | # Optional REPL history 84 | 85 | .node_repl_history 86 | 87 | # Output of 'npm pack' 88 | 89 | \*.tgz 90 | 91 | # Yarn Integrity file 92 | 93 | .yarn-integrity 94 | 95 | # dotenv environment variable files 96 | 97 | .env 98 | .env.development.local 99 | .env.test.local 100 | .env.production.local 101 | .env.local 102 | 103 | # parcel-bundler cache (https://parceljs.org/) 104 | 105 | .cache 106 | .parcel-cache 107 | 108 | # Next.js build output 109 | 110 | .next 111 | out 112 | 113 | # Nuxt.js build / generate output 114 | 115 | .nuxt 116 | dist 117 | 118 | # Gatsby files 119 | 120 | .cache/ 121 | 122 | # Comment in the public line in if your project uses Gatsby and not Next.js 123 | 124 | # https://nextjs.org/blog/next-9-1#public-directory-support 125 | 126 | # public 127 | 128 | # vuepress build output 129 | 130 | .vuepress/dist 131 | 132 | # vuepress v2.x temp and cache directory 133 | 134 | .temp 135 | .cache 136 | 137 | # Docusaurus cache and generated files 138 | 139 | .docusaurus 140 | 141 | # Serverless directories 142 | 143 | .serverless/ 144 | 145 | # FuseBox cache 146 | 147 | .fusebox/ 148 | 149 | # DynamoDB Local files 150 | 151 | .dynamodb/ 152 | 153 | # TernJS port file 154 | 155 | .tern-port 156 | 157 | # Stores VSCode versions used for testing VSCode extensions 158 | 159 | .vscode-test 160 | 161 | # yarn v2 162 | 163 | .yarn/cache 164 | .yarn/unplugged 165 | .yarn/build-state.yml 166 | .yarn/install-state.gz 167 | .pnp.\* 168 | 169 | # wrangler project 170 | 171 | .dev.vars 172 | .wrangler/ 173 | -------------------------------------------------------------------------------- /examples/using-state/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "singleQuote": true, 4 | "semi": true, 5 | "useTabs": true 6 | } 7 | -------------------------------------------------------------------------------- /examples/using-state/README.md: -------------------------------------------------------------------------------- 1 | # using-decorators 2 | 3 | This sample updates the [Hello World Durable Object](https://github.com/cloudflare/workers-sdk/tree/main/packages/create-cloudflare/templates/hello-world-durable-object/ts) template from Cloudflare to use `diffable-objects` using the `state` function. 4 | 5 | ## Try it out 6 | 7 | ``` 8 | pnpm dev 9 | ``` -------------------------------------------------------------------------------- /examples/using-state/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "using-state", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev", 8 | "start": "wrangler dev", 9 | "cf-typegen": "wrangler types" 10 | }, 11 | "devDependencies": { 12 | "@cloudflare/workers-types": "^4.20241224.0", 13 | "typescript": "^5.5.2", 14 | "wrangler": "^3.60.3" 15 | }, 16 | "dependencies": { 17 | "diffable-objects": "0.1.1" 18 | } 19 | } -------------------------------------------------------------------------------- /examples/using-state/src/index.ts: -------------------------------------------------------------------------------- 1 | import { DurableObject } from "cloudflare:workers"; 2 | import { state } from "diffable-objects"; 3 | 4 | /** 5 | * Welcome to Cloudflare Workers! This is your first Durable Objects application. 6 | * 7 | * - Run `npm run dev` in your terminal to start a development server 8 | * - Open a browser tab at http://localhost:8787/ to see your Durable Object in action 9 | * - Run `npm run deploy` to publish your application 10 | * 11 | * Bind resources to your worker in `wrangler.toml`. After adding bindings, a type definition for the 12 | * `Env` object can be regenerated with `npm run cf-typegen`. 13 | * 14 | * Learn more at https://developers.cloudflare.com/durable-objects 15 | */ 16 | 17 | /** A Durable Object's behavior is defined in an exported Javascript class */ 18 | export class MyDurableObject extends DurableObject { 19 | #state = state(this.ctx, "state", { count: 0 }); 20 | 21 | /** 22 | * The constructor is invoked once upon creation of the Durable Object, i.e. the first call to 23 | * `DurableObjectStub::get` for a given identifier (no-op constructors can be omitted) 24 | * 25 | * @param ctx - The interface for interacting with Durable Object state 26 | * @param env - The interface to reference bindings declared in wrangler.toml 27 | */ 28 | constructor(ctx: DurableObjectState, env: Env) { 29 | super(ctx, env); 30 | } 31 | 32 | /** 33 | * The Durable Object exposes an RPC method increment which will be invoked when when a Durable 34 | * Object instance receives a request from a Worker via the same method invocation on the stub 35 | * 36 | * @returns The number of times the method has been called on this Durable Object instance 37 | */ 38 | async increment(): Promise { 39 | this.#state.count++; 40 | return this.#state.count; 41 | } 42 | } 43 | 44 | export default { 45 | /** 46 | * This is the standard fetch handler for a Cloudflare Worker 47 | * 48 | * @param request - The request submitted to the Worker from the client 49 | * @param env - The interface to reference bindings declared in wrangler.toml 50 | * @param ctx - The execution context of the Worker 51 | * @returns The response to be sent back to the client 52 | */ 53 | async fetch(request, env, ctx): Promise { 54 | // We will create a `DurableObjectId` using the pathname from the Worker request 55 | // This id refers to a unique instance of our 'MyDurableObject' class above 56 | const id: DurableObjectId = env.MY_DURABLE_OBJECT.idFromName(new URL(request.url).pathname); 57 | 58 | // This stub creates a communication channel with the Durable Object instance 59 | // The Durable Object constructor will be invoked upon the first call for a given id 60 | const stub = env.MY_DURABLE_OBJECT.get(id); 61 | 62 | // We call the `increment()` RPC method on the stub to invoke the method on the remote 63 | // Durable Object instance 64 | const count = await stub.increment(); 65 | 66 | return Response.json({ count }); 67 | }, 68 | } satisfies ExportedHandler; 69 | -------------------------------------------------------------------------------- /examples/using-state/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 6 | "target": "es2021", 7 | /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 8 | "lib": ["es2021"], 9 | /* Specify what JSX code is generated. */ 10 | "jsx": "react-jsx", 11 | 12 | /* Specify what module code is generated. */ 13 | "module": "es2022", 14 | /* Specify how TypeScript looks up a file from a given module specifier. */ 15 | "moduleResolution": "node", 16 | /* Specify type package names to be included without being referenced in a source file. */ 17 | "types": [ 18 | "@cloudflare/workers-types/2023-07-01" 19 | ], 20 | /* Enable importing .json files */ 21 | "resolveJsonModule": true, 22 | 23 | /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 24 | "allowJs": true, 25 | /* Enable error reporting in type-checked JavaScript files. */ 26 | "checkJs": false, 27 | 28 | /* Disable emitting files from a compilation. */ 29 | "noEmit": true, 30 | 31 | /* Ensure that each file can be safely transpiled without relying on other imports. */ 32 | "isolatedModules": true, 33 | /* Allow 'import x from y' when a module doesn't have a default export. */ 34 | "allowSyntheticDefaultImports": true, 35 | /* Ensure that casing is correct in imports. */ 36 | "forceConsistentCasingInFileNames": true, 37 | 38 | /* Enable all strict type-checking options. */ 39 | "strict": true, 40 | 41 | /* Skip type checking all .d.ts files. */ 42 | "skipLibCheck": true 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/using-state/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env { 4 | MY_DURABLE_OBJECT: DurableObjectNamespace; 5 | } 6 | -------------------------------------------------------------------------------- /examples/using-state/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "using-state" 3 | main = "src/index.ts" 4 | compatibility_date = "2024-12-24" 5 | 6 | # Workers Logs 7 | # Docs: https://developers.cloudflare.com/workers/observability/logs/workers-logs/ 8 | # Configuration: https://developers.cloudflare.com/workers/observability/logs/workers-logs/#enable-workers-logs 9 | [observability] 10 | enabled = true 11 | 12 | # Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model. 13 | # Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps. 14 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects 15 | [[durable_objects.bindings]] 16 | name = "MY_DURABLE_OBJECT" 17 | class_name = "MyDurableObject" 18 | 19 | # Durable Object migrations. 20 | # Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations 21 | [[migrations]] 22 | tag = "v1" 23 | new_sqlite_classes = ["MyDurableObject"] # diffable-objects requires a class to use sqlite 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "diffable-objects", 3 | "version": "0.1.1", 4 | "description": "A package for dynamic state tracking for Cloudflare's Durable Objects using SQLite", 5 | "author": "Zeb Piasecki ", 6 | "repository": "https://github.com/zebp/diffable-objects", 7 | "license": "MIT", 8 | "keywords": ["cloudflare", "workers", "durable-objects", "sqlite"], 9 | "type": "module", 10 | "main": "dist/index.js", 11 | "types": "dist/index.d.ts", 12 | "exports": { 13 | ".": { 14 | "import": "./dist/index.js", 15 | "types": "./dist/index.d.ts" 16 | } 17 | }, 18 | "scripts": { 19 | "build": "tsc -p tsconfig.build.json", 20 | "build:watch": "tsc -p tsconfig.build.json -w", 21 | "format": "biome format ./**/*.ts --write", 22 | "check:lint": "biome lint ./**/*.ts", 23 | "check:format": "biome format ./**/*.ts", 24 | "test": "vitest run" 25 | }, 26 | "devDependencies": { 27 | "@biomejs/biome": "1.9.4", 28 | "@cloudflare/vitest-pool-workers": "^0.5.40", 29 | "@cloudflare/workers-types": "^4.20241224.0", 30 | "typescript": "^5.7.2", 31 | "vitest": "2.1.8" 32 | }, 33 | "dependencies": { 34 | "json-diff-ts": "^4.1.0" 35 | }, 36 | "pnpm": { 37 | "overrides": { 38 | "lodash": "npm:@technically/lodash" 39 | } 40 | }, 41 | "files": [ 42 | "dist", 43 | "LICENSE" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | overrides: 8 | lodash: npm:@technically/lodash 9 | 10 | importers: 11 | 12 | .: 13 | dependencies: 14 | json-diff-ts: 15 | specifier: ^4.1.0 16 | version: 4.1.0 17 | devDependencies: 18 | '@biomejs/biome': 19 | specifier: 1.9.4 20 | version: 1.9.4 21 | '@cloudflare/vitest-pool-workers': 22 | specifier: ^0.5.40 23 | version: 0.5.40(@cloudflare/workers-types@4.20241224.0)(@vitest/runner@2.1.8)(@vitest/snapshot@2.1.8)(vitest@2.1.8(@types/node@22.10.2)) 24 | '@cloudflare/workers-types': 25 | specifier: ^4.20241224.0 26 | version: 4.20241224.0 27 | typescript: 28 | specifier: ^5.7.2 29 | version: 5.7.2 30 | vitest: 31 | specifier: 2.1.8 32 | version: 2.1.8(@types/node@22.10.2) 33 | 34 | examples/using-decorators: 35 | dependencies: 36 | diffable-objects: 37 | specifier: ^0.1.1 38 | version: 0.1.1 39 | devDependencies: 40 | '@cloudflare/workers-types': 41 | specifier: ^4.20241224.0 42 | version: 4.20241224.0 43 | typescript: 44 | specifier: ^5.5.2 45 | version: 5.7.2 46 | wrangler: 47 | specifier: 0.0.0-dc669c404 48 | version: 0.0.0-dc669c404(@cloudflare/workers-types@4.20241224.0) 49 | 50 | examples/using-state: 51 | dependencies: 52 | diffable-objects: 53 | specifier: 0.1.1 54 | version: 0.1.1 55 | devDependencies: 56 | '@cloudflare/workers-types': 57 | specifier: ^4.20241224.0 58 | version: 4.20241224.0 59 | typescript: 60 | specifier: ^5.5.2 61 | version: 5.7.2 62 | wrangler: 63 | specifier: ^3.60.3 64 | version: 3.99.0(@cloudflare/workers-types@4.20241224.0) 65 | 66 | packages: 67 | 68 | '@biomejs/biome@1.9.4': 69 | resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} 70 | engines: {node: '>=14.21.3'} 71 | hasBin: true 72 | 73 | '@biomejs/cli-darwin-arm64@1.9.4': 74 | resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} 75 | engines: {node: '>=14.21.3'} 76 | cpu: [arm64] 77 | os: [darwin] 78 | 79 | '@biomejs/cli-darwin-x64@1.9.4': 80 | resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} 81 | engines: {node: '>=14.21.3'} 82 | cpu: [x64] 83 | os: [darwin] 84 | 85 | '@biomejs/cli-linux-arm64-musl@1.9.4': 86 | resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} 87 | engines: {node: '>=14.21.3'} 88 | cpu: [arm64] 89 | os: [linux] 90 | 91 | '@biomejs/cli-linux-arm64@1.9.4': 92 | resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} 93 | engines: {node: '>=14.21.3'} 94 | cpu: [arm64] 95 | os: [linux] 96 | 97 | '@biomejs/cli-linux-x64-musl@1.9.4': 98 | resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} 99 | engines: {node: '>=14.21.3'} 100 | cpu: [x64] 101 | os: [linux] 102 | 103 | '@biomejs/cli-linux-x64@1.9.4': 104 | resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} 105 | engines: {node: '>=14.21.3'} 106 | cpu: [x64] 107 | os: [linux] 108 | 109 | '@biomejs/cli-win32-arm64@1.9.4': 110 | resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} 111 | engines: {node: '>=14.21.3'} 112 | cpu: [arm64] 113 | os: [win32] 114 | 115 | '@biomejs/cli-win32-x64@1.9.4': 116 | resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} 117 | engines: {node: '>=14.21.3'} 118 | cpu: [x64] 119 | os: [win32] 120 | 121 | '@cloudflare/kv-asset-handler@0.3.4': 122 | resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} 123 | engines: {node: '>=16.13'} 124 | 125 | '@cloudflare/vitest-pool-workers@0.5.40': 126 | resolution: {integrity: sha512-aBHNj55l6G07+ZJuhJsuElDYOEKcGJ4nEdE+X7XmyCRxiw7eRjc1iPQOfEFqprzKQ/2tPEOO8hL0mgRIgt8K3g==} 127 | peerDependencies: 128 | '@vitest/runner': 2.0.x - 2.1.x 129 | '@vitest/snapshot': 2.0.x - 2.1.x 130 | vitest: 2.0.x - 2.1.x 131 | 132 | '@cloudflare/workerd-darwin-64@1.20241106.1': 133 | resolution: {integrity: sha512-zxvaToi1m0qzAScrxFt7UvFVqU8DxrCO2CinM1yQkv5no7pA1HolpIrwZ0xOhR3ny64Is2s/J6BrRjpO5dM9Zw==} 134 | engines: {node: '>=16'} 135 | cpu: [x64] 136 | os: [darwin] 137 | 138 | '@cloudflare/workerd-darwin-64@1.20241218.0': 139 | resolution: {integrity: sha512-8rveQoxtUvlmORKqTWgjv2ycM8uqWox0u9evn3zd2iWKdou5sncFwH517ZRLI3rq9P31ZLmCQBZ0gloFsTeY6w==} 140 | engines: {node: '>=16'} 141 | cpu: [x64] 142 | os: [darwin] 143 | 144 | '@cloudflare/workerd-darwin-arm64@1.20241106.1': 145 | resolution: {integrity: sha512-j3dg/42D/bPgfNP3cRUBxF+4waCKO/5YKwXNj+lnVOwHxDu+ne5pFw9TIkKYcWTcwn0ZUkbNZNM5rhJqRn4xbg==} 146 | engines: {node: '>=16'} 147 | cpu: [arm64] 148 | os: [darwin] 149 | 150 | '@cloudflare/workerd-darwin-arm64@1.20241218.0': 151 | resolution: {integrity: sha512-be59Ad9nmM9lCkhHqmTs/uZ3JVZt8NJ9Z0PY+B0xnc5z6WwmV2lj0RVLtq7xJhQsQJA189zt5rXqDP6J+2mu7Q==} 152 | engines: {node: '>=16'} 153 | cpu: [arm64] 154 | os: [darwin] 155 | 156 | '@cloudflare/workerd-linux-64@1.20241106.1': 157 | resolution: {integrity: sha512-Ih+Ye8E1DMBXcKrJktGfGztFqHKaX1CeByqshmTbODnWKHt6O65ax3oTecUwyC0+abuyraOpAtdhHNpFMhUkmw==} 158 | engines: {node: '>=16'} 159 | cpu: [x64] 160 | os: [linux] 161 | 162 | '@cloudflare/workerd-linux-64@1.20241218.0': 163 | resolution: {integrity: sha512-MzpSBcfZXRxrYWxQ4pVDYDrUbkQuM62ssl4ZtHH8J35OAeGsWFAYji6MkS2SpVwVcvacPwJXIF4JSzp4xKImKw==} 164 | engines: {node: '>=16'} 165 | cpu: [x64] 166 | os: [linux] 167 | 168 | '@cloudflare/workerd-linux-arm64@1.20241106.1': 169 | resolution: {integrity: sha512-mdQFPk4+14Yywn7n1xIzI+6olWM8Ybz10R7H3h+rk0XulMumCWUCy1CzIDauOx6GyIcSgKIibYMssVHZR30ObA==} 170 | engines: {node: '>=16'} 171 | cpu: [arm64] 172 | os: [linux] 173 | 174 | '@cloudflare/workerd-linux-arm64@1.20241218.0': 175 | resolution: {integrity: sha512-RIuJjPxpNqvwIs52vQsXeRMttvhIjgg9NLjjFa3jK8Ijnj8c3ZDru9Wqi48lJP07yDFIRr4uDMMqh/y29YQi2A==} 176 | engines: {node: '>=16'} 177 | cpu: [arm64] 178 | os: [linux] 179 | 180 | '@cloudflare/workerd-windows-64@1.20241106.1': 181 | resolution: {integrity: sha512-4rtcss31E/Rb/PeFocZfr+B9i1MdrkhsTBWizh8siNR4KMmkslU2xs2wPaH1z8+ErxkOsHrKRa5EPLh5rIiFeg==} 182 | engines: {node: '>=16'} 183 | cpu: [x64] 184 | os: [win32] 185 | 186 | '@cloudflare/workerd-windows-64@1.20241218.0': 187 | resolution: {integrity: sha512-tO1VjlvK3F6Yb2d1jgEy/QBYl//9Pyv3K0j+lq8Eu7qdfm0IgKwSRgDWLept84/qmNsQfausZ4JdNGxTf9xsxQ==} 188 | engines: {node: '>=16'} 189 | cpu: [x64] 190 | os: [win32] 191 | 192 | '@cloudflare/workers-shared@0.8.0': 193 | resolution: {integrity: sha512-1OvFkNtslaMZAJsaocTmbACApgmWv55uLpNj50Pn2MGcxdAjpqykXJFQw5tKc+lGV9TDZh9oO3Rsk17IEQDzIg==} 194 | engines: {node: '>=16.7.0'} 195 | 196 | '@cloudflare/workers-types@4.20241224.0': 197 | resolution: {integrity: sha512-1ZmFc8qqM7S/HUGmLplc4P8n8DoMqiJmc47r9Lr7VbuaotoqCXVljz09w1V1mc4K3pbFPgvqSy4XYStZ08HrlQ==} 198 | 199 | '@cspotcode/source-map-support@0.8.1': 200 | resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} 201 | engines: {node: '>=12'} 202 | 203 | '@esbuild-plugins/node-globals-polyfill@0.2.3': 204 | resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} 205 | peerDependencies: 206 | esbuild: '*' 207 | 208 | '@esbuild-plugins/node-modules-polyfill@0.2.2': 209 | resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} 210 | peerDependencies: 211 | esbuild: '*' 212 | 213 | '@esbuild/aix-ppc64@0.21.5': 214 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} 215 | engines: {node: '>=12'} 216 | cpu: [ppc64] 217 | os: [aix] 218 | 219 | '@esbuild/aix-ppc64@0.24.0': 220 | resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} 221 | engines: {node: '>=18'} 222 | cpu: [ppc64] 223 | os: [aix] 224 | 225 | '@esbuild/android-arm64@0.17.19': 226 | resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} 227 | engines: {node: '>=12'} 228 | cpu: [arm64] 229 | os: [android] 230 | 231 | '@esbuild/android-arm64@0.21.5': 232 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} 233 | engines: {node: '>=12'} 234 | cpu: [arm64] 235 | os: [android] 236 | 237 | '@esbuild/android-arm64@0.24.0': 238 | resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} 239 | engines: {node: '>=18'} 240 | cpu: [arm64] 241 | os: [android] 242 | 243 | '@esbuild/android-arm@0.17.19': 244 | resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} 245 | engines: {node: '>=12'} 246 | cpu: [arm] 247 | os: [android] 248 | 249 | '@esbuild/android-arm@0.21.5': 250 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} 251 | engines: {node: '>=12'} 252 | cpu: [arm] 253 | os: [android] 254 | 255 | '@esbuild/android-arm@0.24.0': 256 | resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} 257 | engines: {node: '>=18'} 258 | cpu: [arm] 259 | os: [android] 260 | 261 | '@esbuild/android-x64@0.17.19': 262 | resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} 263 | engines: {node: '>=12'} 264 | cpu: [x64] 265 | os: [android] 266 | 267 | '@esbuild/android-x64@0.21.5': 268 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} 269 | engines: {node: '>=12'} 270 | cpu: [x64] 271 | os: [android] 272 | 273 | '@esbuild/android-x64@0.24.0': 274 | resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} 275 | engines: {node: '>=18'} 276 | cpu: [x64] 277 | os: [android] 278 | 279 | '@esbuild/darwin-arm64@0.17.19': 280 | resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} 281 | engines: {node: '>=12'} 282 | cpu: [arm64] 283 | os: [darwin] 284 | 285 | '@esbuild/darwin-arm64@0.21.5': 286 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} 287 | engines: {node: '>=12'} 288 | cpu: [arm64] 289 | os: [darwin] 290 | 291 | '@esbuild/darwin-arm64@0.24.0': 292 | resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} 293 | engines: {node: '>=18'} 294 | cpu: [arm64] 295 | os: [darwin] 296 | 297 | '@esbuild/darwin-x64@0.17.19': 298 | resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} 299 | engines: {node: '>=12'} 300 | cpu: [x64] 301 | os: [darwin] 302 | 303 | '@esbuild/darwin-x64@0.21.5': 304 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} 305 | engines: {node: '>=12'} 306 | cpu: [x64] 307 | os: [darwin] 308 | 309 | '@esbuild/darwin-x64@0.24.0': 310 | resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} 311 | engines: {node: '>=18'} 312 | cpu: [x64] 313 | os: [darwin] 314 | 315 | '@esbuild/freebsd-arm64@0.17.19': 316 | resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} 317 | engines: {node: '>=12'} 318 | cpu: [arm64] 319 | os: [freebsd] 320 | 321 | '@esbuild/freebsd-arm64@0.21.5': 322 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} 323 | engines: {node: '>=12'} 324 | cpu: [arm64] 325 | os: [freebsd] 326 | 327 | '@esbuild/freebsd-arm64@0.24.0': 328 | resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} 329 | engines: {node: '>=18'} 330 | cpu: [arm64] 331 | os: [freebsd] 332 | 333 | '@esbuild/freebsd-x64@0.17.19': 334 | resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} 335 | engines: {node: '>=12'} 336 | cpu: [x64] 337 | os: [freebsd] 338 | 339 | '@esbuild/freebsd-x64@0.21.5': 340 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} 341 | engines: {node: '>=12'} 342 | cpu: [x64] 343 | os: [freebsd] 344 | 345 | '@esbuild/freebsd-x64@0.24.0': 346 | resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} 347 | engines: {node: '>=18'} 348 | cpu: [x64] 349 | os: [freebsd] 350 | 351 | '@esbuild/linux-arm64@0.17.19': 352 | resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} 353 | engines: {node: '>=12'} 354 | cpu: [arm64] 355 | os: [linux] 356 | 357 | '@esbuild/linux-arm64@0.21.5': 358 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} 359 | engines: {node: '>=12'} 360 | cpu: [arm64] 361 | os: [linux] 362 | 363 | '@esbuild/linux-arm64@0.24.0': 364 | resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} 365 | engines: {node: '>=18'} 366 | cpu: [arm64] 367 | os: [linux] 368 | 369 | '@esbuild/linux-arm@0.17.19': 370 | resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} 371 | engines: {node: '>=12'} 372 | cpu: [arm] 373 | os: [linux] 374 | 375 | '@esbuild/linux-arm@0.21.5': 376 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} 377 | engines: {node: '>=12'} 378 | cpu: [arm] 379 | os: [linux] 380 | 381 | '@esbuild/linux-arm@0.24.0': 382 | resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} 383 | engines: {node: '>=18'} 384 | cpu: [arm] 385 | os: [linux] 386 | 387 | '@esbuild/linux-ia32@0.17.19': 388 | resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} 389 | engines: {node: '>=12'} 390 | cpu: [ia32] 391 | os: [linux] 392 | 393 | '@esbuild/linux-ia32@0.21.5': 394 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} 395 | engines: {node: '>=12'} 396 | cpu: [ia32] 397 | os: [linux] 398 | 399 | '@esbuild/linux-ia32@0.24.0': 400 | resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} 401 | engines: {node: '>=18'} 402 | cpu: [ia32] 403 | os: [linux] 404 | 405 | '@esbuild/linux-loong64@0.17.19': 406 | resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} 407 | engines: {node: '>=12'} 408 | cpu: [loong64] 409 | os: [linux] 410 | 411 | '@esbuild/linux-loong64@0.21.5': 412 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} 413 | engines: {node: '>=12'} 414 | cpu: [loong64] 415 | os: [linux] 416 | 417 | '@esbuild/linux-loong64@0.24.0': 418 | resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} 419 | engines: {node: '>=18'} 420 | cpu: [loong64] 421 | os: [linux] 422 | 423 | '@esbuild/linux-mips64el@0.17.19': 424 | resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} 425 | engines: {node: '>=12'} 426 | cpu: [mips64el] 427 | os: [linux] 428 | 429 | '@esbuild/linux-mips64el@0.21.5': 430 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} 431 | engines: {node: '>=12'} 432 | cpu: [mips64el] 433 | os: [linux] 434 | 435 | '@esbuild/linux-mips64el@0.24.0': 436 | resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} 437 | engines: {node: '>=18'} 438 | cpu: [mips64el] 439 | os: [linux] 440 | 441 | '@esbuild/linux-ppc64@0.17.19': 442 | resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} 443 | engines: {node: '>=12'} 444 | cpu: [ppc64] 445 | os: [linux] 446 | 447 | '@esbuild/linux-ppc64@0.21.5': 448 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} 449 | engines: {node: '>=12'} 450 | cpu: [ppc64] 451 | os: [linux] 452 | 453 | '@esbuild/linux-ppc64@0.24.0': 454 | resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} 455 | engines: {node: '>=18'} 456 | cpu: [ppc64] 457 | os: [linux] 458 | 459 | '@esbuild/linux-riscv64@0.17.19': 460 | resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} 461 | engines: {node: '>=12'} 462 | cpu: [riscv64] 463 | os: [linux] 464 | 465 | '@esbuild/linux-riscv64@0.21.5': 466 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} 467 | engines: {node: '>=12'} 468 | cpu: [riscv64] 469 | os: [linux] 470 | 471 | '@esbuild/linux-riscv64@0.24.0': 472 | resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} 473 | engines: {node: '>=18'} 474 | cpu: [riscv64] 475 | os: [linux] 476 | 477 | '@esbuild/linux-s390x@0.17.19': 478 | resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} 479 | engines: {node: '>=12'} 480 | cpu: [s390x] 481 | os: [linux] 482 | 483 | '@esbuild/linux-s390x@0.21.5': 484 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} 485 | engines: {node: '>=12'} 486 | cpu: [s390x] 487 | os: [linux] 488 | 489 | '@esbuild/linux-s390x@0.24.0': 490 | resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} 491 | engines: {node: '>=18'} 492 | cpu: [s390x] 493 | os: [linux] 494 | 495 | '@esbuild/linux-x64@0.17.19': 496 | resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} 497 | engines: {node: '>=12'} 498 | cpu: [x64] 499 | os: [linux] 500 | 501 | '@esbuild/linux-x64@0.21.5': 502 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} 503 | engines: {node: '>=12'} 504 | cpu: [x64] 505 | os: [linux] 506 | 507 | '@esbuild/linux-x64@0.24.0': 508 | resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} 509 | engines: {node: '>=18'} 510 | cpu: [x64] 511 | os: [linux] 512 | 513 | '@esbuild/netbsd-x64@0.17.19': 514 | resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} 515 | engines: {node: '>=12'} 516 | cpu: [x64] 517 | os: [netbsd] 518 | 519 | '@esbuild/netbsd-x64@0.21.5': 520 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} 521 | engines: {node: '>=12'} 522 | cpu: [x64] 523 | os: [netbsd] 524 | 525 | '@esbuild/netbsd-x64@0.24.0': 526 | resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} 527 | engines: {node: '>=18'} 528 | cpu: [x64] 529 | os: [netbsd] 530 | 531 | '@esbuild/openbsd-arm64@0.24.0': 532 | resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} 533 | engines: {node: '>=18'} 534 | cpu: [arm64] 535 | os: [openbsd] 536 | 537 | '@esbuild/openbsd-x64@0.17.19': 538 | resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} 539 | engines: {node: '>=12'} 540 | cpu: [x64] 541 | os: [openbsd] 542 | 543 | '@esbuild/openbsd-x64@0.21.5': 544 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} 545 | engines: {node: '>=12'} 546 | cpu: [x64] 547 | os: [openbsd] 548 | 549 | '@esbuild/openbsd-x64@0.24.0': 550 | resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} 551 | engines: {node: '>=18'} 552 | cpu: [x64] 553 | os: [openbsd] 554 | 555 | '@esbuild/sunos-x64@0.17.19': 556 | resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} 557 | engines: {node: '>=12'} 558 | cpu: [x64] 559 | os: [sunos] 560 | 561 | '@esbuild/sunos-x64@0.21.5': 562 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} 563 | engines: {node: '>=12'} 564 | cpu: [x64] 565 | os: [sunos] 566 | 567 | '@esbuild/sunos-x64@0.24.0': 568 | resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} 569 | engines: {node: '>=18'} 570 | cpu: [x64] 571 | os: [sunos] 572 | 573 | '@esbuild/win32-arm64@0.17.19': 574 | resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} 575 | engines: {node: '>=12'} 576 | cpu: [arm64] 577 | os: [win32] 578 | 579 | '@esbuild/win32-arm64@0.21.5': 580 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} 581 | engines: {node: '>=12'} 582 | cpu: [arm64] 583 | os: [win32] 584 | 585 | '@esbuild/win32-arm64@0.24.0': 586 | resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} 587 | engines: {node: '>=18'} 588 | cpu: [arm64] 589 | os: [win32] 590 | 591 | '@esbuild/win32-ia32@0.17.19': 592 | resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} 593 | engines: {node: '>=12'} 594 | cpu: [ia32] 595 | os: [win32] 596 | 597 | '@esbuild/win32-ia32@0.21.5': 598 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} 599 | engines: {node: '>=12'} 600 | cpu: [ia32] 601 | os: [win32] 602 | 603 | '@esbuild/win32-ia32@0.24.0': 604 | resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} 605 | engines: {node: '>=18'} 606 | cpu: [ia32] 607 | os: [win32] 608 | 609 | '@esbuild/win32-x64@0.17.19': 610 | resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} 611 | engines: {node: '>=12'} 612 | cpu: [x64] 613 | os: [win32] 614 | 615 | '@esbuild/win32-x64@0.21.5': 616 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} 617 | engines: {node: '>=12'} 618 | cpu: [x64] 619 | os: [win32] 620 | 621 | '@esbuild/win32-x64@0.24.0': 622 | resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} 623 | engines: {node: '>=18'} 624 | cpu: [x64] 625 | os: [win32] 626 | 627 | '@fastify/busboy@2.1.1': 628 | resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} 629 | engines: {node: '>=14'} 630 | 631 | '@jridgewell/resolve-uri@3.1.2': 632 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 633 | engines: {node: '>=6.0.0'} 634 | 635 | '@jridgewell/sourcemap-codec@1.5.0': 636 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 637 | 638 | '@jridgewell/trace-mapping@0.3.9': 639 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 640 | 641 | '@rollup/rollup-android-arm-eabi@4.29.1': 642 | resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} 643 | cpu: [arm] 644 | os: [android] 645 | 646 | '@rollup/rollup-android-arm64@4.29.1': 647 | resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} 648 | cpu: [arm64] 649 | os: [android] 650 | 651 | '@rollup/rollup-darwin-arm64@4.29.1': 652 | resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} 653 | cpu: [arm64] 654 | os: [darwin] 655 | 656 | '@rollup/rollup-darwin-x64@4.29.1': 657 | resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} 658 | cpu: [x64] 659 | os: [darwin] 660 | 661 | '@rollup/rollup-freebsd-arm64@4.29.1': 662 | resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} 663 | cpu: [arm64] 664 | os: [freebsd] 665 | 666 | '@rollup/rollup-freebsd-x64@4.29.1': 667 | resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} 668 | cpu: [x64] 669 | os: [freebsd] 670 | 671 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 672 | resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} 673 | cpu: [arm] 674 | os: [linux] 675 | 676 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 677 | resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} 678 | cpu: [arm] 679 | os: [linux] 680 | 681 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 682 | resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} 683 | cpu: [arm64] 684 | os: [linux] 685 | 686 | '@rollup/rollup-linux-arm64-musl@4.29.1': 687 | resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} 688 | cpu: [arm64] 689 | os: [linux] 690 | 691 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 692 | resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} 693 | cpu: [loong64] 694 | os: [linux] 695 | 696 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 697 | resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} 698 | cpu: [ppc64] 699 | os: [linux] 700 | 701 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 702 | resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} 703 | cpu: [riscv64] 704 | os: [linux] 705 | 706 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 707 | resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} 708 | cpu: [s390x] 709 | os: [linux] 710 | 711 | '@rollup/rollup-linux-x64-gnu@4.29.1': 712 | resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} 713 | cpu: [x64] 714 | os: [linux] 715 | 716 | '@rollup/rollup-linux-x64-musl@4.29.1': 717 | resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} 718 | cpu: [x64] 719 | os: [linux] 720 | 721 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 722 | resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} 723 | cpu: [arm64] 724 | os: [win32] 725 | 726 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 727 | resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} 728 | cpu: [ia32] 729 | os: [win32] 730 | 731 | '@rollup/rollup-win32-x64-msvc@4.29.1': 732 | resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} 733 | cpu: [x64] 734 | os: [win32] 735 | 736 | '@technically/lodash@4.17.0': 737 | resolution: {integrity: sha512-x0dRMAZbdv7HOyaayrW0Tua9V0k8Sdr+NDgsNRRfPada2+MlCE6esmYoSL7KJeCh13O3up5dlq8VbcQBTW+wqg==} 738 | 739 | '@types/estree@1.0.6': 740 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 741 | 742 | '@types/lodash-es@4.17.12': 743 | resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} 744 | 745 | '@types/lodash@4.17.13': 746 | resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} 747 | 748 | '@types/node-forge@1.3.11': 749 | resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} 750 | 751 | '@types/node@22.10.2': 752 | resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} 753 | 754 | '@vitest/expect@2.1.8': 755 | resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} 756 | 757 | '@vitest/mocker@2.1.8': 758 | resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} 759 | peerDependencies: 760 | msw: ^2.4.9 761 | vite: ^5.0.0 762 | peerDependenciesMeta: 763 | msw: 764 | optional: true 765 | vite: 766 | optional: true 767 | 768 | '@vitest/pretty-format@2.1.8': 769 | resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} 770 | 771 | '@vitest/runner@2.1.8': 772 | resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} 773 | 774 | '@vitest/snapshot@2.1.8': 775 | resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} 776 | 777 | '@vitest/spy@2.1.8': 778 | resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} 779 | 780 | '@vitest/utils@2.1.8': 781 | resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} 782 | 783 | acorn-walk@8.3.4: 784 | resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} 785 | engines: {node: '>=0.4.0'} 786 | 787 | acorn@8.14.0: 788 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} 789 | engines: {node: '>=0.4.0'} 790 | hasBin: true 791 | 792 | as-table@1.0.55: 793 | resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} 794 | 795 | assertion-error@2.0.1: 796 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 797 | engines: {node: '>=12'} 798 | 799 | birpc@0.2.14: 800 | resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==} 801 | 802 | blake3-wasm@2.1.5: 803 | resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} 804 | 805 | cac@6.7.14: 806 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 807 | engines: {node: '>=8'} 808 | 809 | capnp-ts@0.7.0: 810 | resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} 811 | 812 | chai@5.1.2: 813 | resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} 814 | engines: {node: '>=12'} 815 | 816 | check-error@2.1.1: 817 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 818 | engines: {node: '>= 16'} 819 | 820 | chokidar@4.0.3: 821 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 822 | engines: {node: '>= 14.16.0'} 823 | 824 | cjs-module-lexer@1.4.1: 825 | resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} 826 | 827 | cookie@0.7.2: 828 | resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} 829 | engines: {node: '>= 0.6'} 830 | 831 | data-uri-to-buffer@2.0.2: 832 | resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} 833 | 834 | date-fns@4.1.0: 835 | resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} 836 | 837 | debug@4.4.0: 838 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 839 | engines: {node: '>=6.0'} 840 | peerDependencies: 841 | supports-color: '*' 842 | peerDependenciesMeta: 843 | supports-color: 844 | optional: true 845 | 846 | deep-eql@5.0.2: 847 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 848 | engines: {node: '>=6'} 849 | 850 | defu@6.1.4: 851 | resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} 852 | 853 | devalue@4.3.3: 854 | resolution: {integrity: sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg==} 855 | 856 | diffable-objects@0.1.1: 857 | resolution: {integrity: sha512-vk6VMf4Jjt49ls4FdwYNU1BesPxIqsk6jSihFuU/qr17nMcZ+hGguC5aE+EKsI/M5qaj0+A9O53zTh5gN3MSpQ==} 858 | 859 | es-module-lexer@1.5.4: 860 | resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} 861 | 862 | esbuild@0.17.19: 863 | resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} 864 | engines: {node: '>=12'} 865 | hasBin: true 866 | 867 | esbuild@0.21.5: 868 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} 869 | engines: {node: '>=12'} 870 | hasBin: true 871 | 872 | esbuild@0.24.0: 873 | resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} 874 | engines: {node: '>=18'} 875 | hasBin: true 876 | 877 | escape-string-regexp@4.0.0: 878 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 879 | engines: {node: '>=10'} 880 | 881 | estree-walker@0.6.1: 882 | resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} 883 | 884 | estree-walker@3.0.3: 885 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 886 | 887 | exit-hook@2.2.1: 888 | resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} 889 | engines: {node: '>=6'} 890 | 891 | expect-type@1.1.0: 892 | resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} 893 | engines: {node: '>=12.0.0'} 894 | 895 | fsevents@2.3.3: 896 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 897 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 898 | os: [darwin] 899 | 900 | function-bind@1.1.2: 901 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 902 | 903 | get-source@2.0.12: 904 | resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} 905 | 906 | glob-to-regexp@0.4.1: 907 | resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} 908 | 909 | hasown@2.0.2: 910 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 911 | engines: {node: '>= 0.4'} 912 | 913 | is-core-module@2.16.1: 914 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 915 | engines: {node: '>= 0.4'} 916 | 917 | itty-time@1.0.6: 918 | resolution: {integrity: sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==} 919 | 920 | json-diff-ts@4.1.0: 921 | resolution: {integrity: sha512-WriM1FhU8xnvlvDsmoB5YgwkL2uOy/p4rKPmJz0Bo221nHHEQbh6WspTowEl2qxy9yP5gGYv0pUQ7kNnjrn/TQ==} 922 | 923 | lodash-es@4.17.21: 924 | resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} 925 | 926 | loupe@3.1.2: 927 | resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} 928 | 929 | magic-string@0.25.9: 930 | resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} 931 | 932 | magic-string@0.30.17: 933 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 934 | 935 | mime@3.0.0: 936 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 937 | engines: {node: '>=10.0.0'} 938 | hasBin: true 939 | 940 | miniflare@0.0.0-dc669c404: 941 | resolution: {integrity: sha512-Qu6XmE81AQdAnki9b9bOBs8kwltgAnuobiwiz+X+oNNzN9n+LrpGELudwDJPerfDq3cNLnH5P5FiKMmwLNBLYg==} 942 | engines: {node: '>=18.0.0'} 943 | hasBin: true 944 | 945 | miniflare@3.20241218.0: 946 | resolution: {integrity: sha512-spYFDArH0wd+wJSTrzBrWrXJrbyJhRMJa35mat947y1jYhVV8I5V8vnD3LwjfpLr0SaEilojz1OIW7ekmnRe+w==} 947 | engines: {node: '>=16.13'} 948 | hasBin: true 949 | 950 | ms@2.1.3: 951 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 952 | 953 | mustache@4.2.0: 954 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 955 | hasBin: true 956 | 957 | nanoid@3.3.8: 958 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 959 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 960 | hasBin: true 961 | 962 | node-forge@1.3.1: 963 | resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} 964 | engines: {node: '>= 6.13.0'} 965 | 966 | ohash@1.1.4: 967 | resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} 968 | 969 | path-parse@1.0.7: 970 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 971 | 972 | path-to-regexp@6.3.0: 973 | resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} 974 | 975 | pathe@1.1.2: 976 | resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} 977 | 978 | pathval@2.0.0: 979 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} 980 | engines: {node: '>= 14.16'} 981 | 982 | picocolors@1.1.1: 983 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 984 | 985 | postcss@8.4.49: 986 | resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} 987 | engines: {node: ^10 || ^12 || >=14} 988 | 989 | printable-characters@1.0.42: 990 | resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} 991 | 992 | readdirp@4.0.2: 993 | resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} 994 | engines: {node: '>= 14.16.0'} 995 | 996 | resolve.exports@2.0.3: 997 | resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} 998 | engines: {node: '>=10'} 999 | 1000 | resolve@1.22.10: 1001 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 1002 | engines: {node: '>= 0.4'} 1003 | hasBin: true 1004 | 1005 | rollup-plugin-inject@3.0.2: 1006 | resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} 1007 | deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. 1008 | 1009 | rollup-plugin-node-polyfills@0.2.1: 1010 | resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} 1011 | 1012 | rollup-pluginutils@2.8.2: 1013 | resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} 1014 | 1015 | rollup@4.29.1: 1016 | resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} 1017 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1018 | hasBin: true 1019 | 1020 | selfsigned@2.4.1: 1021 | resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} 1022 | engines: {node: '>=10'} 1023 | 1024 | semver@7.6.3: 1025 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 1026 | engines: {node: '>=10'} 1027 | hasBin: true 1028 | 1029 | siginfo@2.0.0: 1030 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1031 | 1032 | source-map-js@1.2.1: 1033 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1034 | engines: {node: '>=0.10.0'} 1035 | 1036 | source-map@0.6.1: 1037 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1038 | engines: {node: '>=0.10.0'} 1039 | 1040 | sourcemap-codec@1.4.8: 1041 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 1042 | deprecated: Please use @jridgewell/sourcemap-codec instead 1043 | 1044 | stackback@0.0.2: 1045 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1046 | 1047 | stacktracey@2.1.8: 1048 | resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} 1049 | 1050 | std-env@3.8.0: 1051 | resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} 1052 | 1053 | stoppable@1.1.0: 1054 | resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} 1055 | engines: {node: '>=4', npm: '>=6'} 1056 | 1057 | supports-preserve-symlinks-flag@1.0.0: 1058 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1059 | engines: {node: '>= 0.4'} 1060 | 1061 | tinybench@2.9.0: 1062 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1063 | 1064 | tinyexec@0.3.1: 1065 | resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} 1066 | 1067 | tinypool@1.0.2: 1068 | resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} 1069 | engines: {node: ^18.0.0 || >=20.0.0} 1070 | 1071 | tinyrainbow@1.2.0: 1072 | resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} 1073 | engines: {node: '>=14.0.0'} 1074 | 1075 | tinyspy@3.0.2: 1076 | resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} 1077 | engines: {node: '>=14.0.0'} 1078 | 1079 | tslib@2.8.1: 1080 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1081 | 1082 | typescript@5.7.2: 1083 | resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} 1084 | engines: {node: '>=14.17'} 1085 | hasBin: true 1086 | 1087 | ufo@1.5.4: 1088 | resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} 1089 | 1090 | undici-types@6.20.0: 1091 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 1092 | 1093 | undici@5.28.4: 1094 | resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} 1095 | engines: {node: '>=14.0'} 1096 | 1097 | unenv-nightly@2.0.0-20241121-161142-806b5c0: 1098 | resolution: {integrity: sha512-RnFOasE/O0Q55gBkNB1b84OgKttgLEijGO0JCWpbn+O4XxpyCQg89NmcqQ5RGUiy4y+rMIrKzePTquQcLQF5pQ==} 1099 | 1100 | unenv-nightly@2.0.0-20241204-140205-a5d5190: 1101 | resolution: {integrity: sha512-jpmAytLeiiW01pl5bhVn9wYJ4vtiLdhGe10oXlJBuQEX8mxjxO8BlEXGHU4vr4yEikjFP1wsomTHt/CLU8kUwg==} 1102 | 1103 | vite-node@2.1.8: 1104 | resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} 1105 | engines: {node: ^18.0.0 || >=20.0.0} 1106 | hasBin: true 1107 | 1108 | vite@5.4.11: 1109 | resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} 1110 | engines: {node: ^18.0.0 || >=20.0.0} 1111 | hasBin: true 1112 | peerDependencies: 1113 | '@types/node': ^18.0.0 || >=20.0.0 1114 | less: '*' 1115 | lightningcss: ^1.21.0 1116 | sass: '*' 1117 | sass-embedded: '*' 1118 | stylus: '*' 1119 | sugarss: '*' 1120 | terser: ^5.4.0 1121 | peerDependenciesMeta: 1122 | '@types/node': 1123 | optional: true 1124 | less: 1125 | optional: true 1126 | lightningcss: 1127 | optional: true 1128 | sass: 1129 | optional: true 1130 | sass-embedded: 1131 | optional: true 1132 | stylus: 1133 | optional: true 1134 | sugarss: 1135 | optional: true 1136 | terser: 1137 | optional: true 1138 | 1139 | vitest@2.1.8: 1140 | resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} 1141 | engines: {node: ^18.0.0 || >=20.0.0} 1142 | hasBin: true 1143 | peerDependencies: 1144 | '@edge-runtime/vm': '*' 1145 | '@types/node': ^18.0.0 || >=20.0.0 1146 | '@vitest/browser': 2.1.8 1147 | '@vitest/ui': 2.1.8 1148 | happy-dom: '*' 1149 | jsdom: '*' 1150 | peerDependenciesMeta: 1151 | '@edge-runtime/vm': 1152 | optional: true 1153 | '@types/node': 1154 | optional: true 1155 | '@vitest/browser': 1156 | optional: true 1157 | '@vitest/ui': 1158 | optional: true 1159 | happy-dom: 1160 | optional: true 1161 | jsdom: 1162 | optional: true 1163 | 1164 | why-is-node-running@2.3.0: 1165 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1166 | engines: {node: '>=8'} 1167 | hasBin: true 1168 | 1169 | workerd@1.20241106.1: 1170 | resolution: {integrity: sha512-1GdKl0kDw8rrirr/ThcK66Kbl4/jd4h8uHx5g7YHBrnenY5SX1UPuop2cnCzYUxlg55kPjzIqqYslz1muRFgFw==} 1171 | engines: {node: '>=16'} 1172 | hasBin: true 1173 | 1174 | workerd@1.20241218.0: 1175 | resolution: {integrity: sha512-7Z3D4vOVChMz9mWDffE299oQxUWm/pbkeAWx1btVamPcAK/2IuoNBhwflWo3jyuKuxvYuFAdIucgYxc8ICqXiA==} 1176 | engines: {node: '>=16'} 1177 | hasBin: true 1178 | 1179 | wrangler@0.0.0-dc669c404: 1180 | resolution: {integrity: sha512-NXu1FQBaRBSkSG73ze4o6+lHaQcu+DNZCNLeBHXUVGjU17IW2+uL76Rq9Nopj9VIw4YFwgEsJJN2dD7tBPji0w==} 1181 | engines: {node: '>=18.0.0'} 1182 | hasBin: true 1183 | peerDependencies: 1184 | '@cloudflare/workers-types': ^4.20241106.0 1185 | peerDependenciesMeta: 1186 | '@cloudflare/workers-types': 1187 | optional: true 1188 | 1189 | wrangler@3.99.0: 1190 | resolution: {integrity: sha512-k0x4rT3G/QCbxcoZY7CHRVlAIS8WMmKdga6lf4d2c3gXFqssh44vwlTDuARA9QANBxKJTcA7JPTJRfUDhd9QBA==} 1191 | engines: {node: '>=16.17.0'} 1192 | hasBin: true 1193 | peerDependencies: 1194 | '@cloudflare/workers-types': ^4.20241218.0 1195 | peerDependenciesMeta: 1196 | '@cloudflare/workers-types': 1197 | optional: true 1198 | 1199 | ws@8.18.0: 1200 | resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} 1201 | engines: {node: '>=10.0.0'} 1202 | peerDependencies: 1203 | bufferutil: ^4.0.1 1204 | utf-8-validate: '>=5.0.2' 1205 | peerDependenciesMeta: 1206 | bufferutil: 1207 | optional: true 1208 | utf-8-validate: 1209 | optional: true 1210 | 1211 | xxhash-wasm@1.1.0: 1212 | resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} 1213 | 1214 | youch@3.3.4: 1215 | resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} 1216 | 1217 | zod@3.24.1: 1218 | resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} 1219 | 1220 | snapshots: 1221 | 1222 | '@biomejs/biome@1.9.4': 1223 | optionalDependencies: 1224 | '@biomejs/cli-darwin-arm64': 1.9.4 1225 | '@biomejs/cli-darwin-x64': 1.9.4 1226 | '@biomejs/cli-linux-arm64': 1.9.4 1227 | '@biomejs/cli-linux-arm64-musl': 1.9.4 1228 | '@biomejs/cli-linux-x64': 1.9.4 1229 | '@biomejs/cli-linux-x64-musl': 1.9.4 1230 | '@biomejs/cli-win32-arm64': 1.9.4 1231 | '@biomejs/cli-win32-x64': 1.9.4 1232 | 1233 | '@biomejs/cli-darwin-arm64@1.9.4': 1234 | optional: true 1235 | 1236 | '@biomejs/cli-darwin-x64@1.9.4': 1237 | optional: true 1238 | 1239 | '@biomejs/cli-linux-arm64-musl@1.9.4': 1240 | optional: true 1241 | 1242 | '@biomejs/cli-linux-arm64@1.9.4': 1243 | optional: true 1244 | 1245 | '@biomejs/cli-linux-x64-musl@1.9.4': 1246 | optional: true 1247 | 1248 | '@biomejs/cli-linux-x64@1.9.4': 1249 | optional: true 1250 | 1251 | '@biomejs/cli-win32-arm64@1.9.4': 1252 | optional: true 1253 | 1254 | '@biomejs/cli-win32-x64@1.9.4': 1255 | optional: true 1256 | 1257 | '@cloudflare/kv-asset-handler@0.3.4': 1258 | dependencies: 1259 | mime: 3.0.0 1260 | 1261 | '@cloudflare/vitest-pool-workers@0.5.40(@cloudflare/workers-types@4.20241224.0)(@vitest/runner@2.1.8)(@vitest/snapshot@2.1.8)(vitest@2.1.8(@types/node@22.10.2))': 1262 | dependencies: 1263 | '@vitest/runner': 2.1.8 1264 | '@vitest/snapshot': 2.1.8 1265 | birpc: 0.2.14 1266 | cjs-module-lexer: 1.4.1 1267 | devalue: 4.3.3 1268 | esbuild: 0.17.19 1269 | miniflare: 3.20241218.0 1270 | semver: 7.6.3 1271 | vitest: 2.1.8(@types/node@22.10.2) 1272 | wrangler: 3.99.0(@cloudflare/workers-types@4.20241224.0) 1273 | zod: 3.24.1 1274 | transitivePeerDependencies: 1275 | - '@cloudflare/workers-types' 1276 | - bufferutil 1277 | - supports-color 1278 | - utf-8-validate 1279 | 1280 | '@cloudflare/workerd-darwin-64@1.20241106.1': 1281 | optional: true 1282 | 1283 | '@cloudflare/workerd-darwin-64@1.20241218.0': 1284 | optional: true 1285 | 1286 | '@cloudflare/workerd-darwin-arm64@1.20241106.1': 1287 | optional: true 1288 | 1289 | '@cloudflare/workerd-darwin-arm64@1.20241218.0': 1290 | optional: true 1291 | 1292 | '@cloudflare/workerd-linux-64@1.20241106.1': 1293 | optional: true 1294 | 1295 | '@cloudflare/workerd-linux-64@1.20241218.0': 1296 | optional: true 1297 | 1298 | '@cloudflare/workerd-linux-arm64@1.20241106.1': 1299 | optional: true 1300 | 1301 | '@cloudflare/workerd-linux-arm64@1.20241218.0': 1302 | optional: true 1303 | 1304 | '@cloudflare/workerd-windows-64@1.20241106.1': 1305 | optional: true 1306 | 1307 | '@cloudflare/workerd-windows-64@1.20241218.0': 1308 | optional: true 1309 | 1310 | '@cloudflare/workers-shared@0.8.0': 1311 | dependencies: 1312 | mime: 3.0.0 1313 | zod: 3.24.1 1314 | 1315 | '@cloudflare/workers-types@4.20241224.0': {} 1316 | 1317 | '@cspotcode/source-map-support@0.8.1': 1318 | dependencies: 1319 | '@jridgewell/trace-mapping': 0.3.9 1320 | 1321 | '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': 1322 | dependencies: 1323 | esbuild: 0.17.19 1324 | 1325 | '@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19)': 1326 | dependencies: 1327 | esbuild: 0.17.19 1328 | escape-string-regexp: 4.0.0 1329 | rollup-plugin-node-polyfills: 0.2.1 1330 | 1331 | '@esbuild/aix-ppc64@0.21.5': 1332 | optional: true 1333 | 1334 | '@esbuild/aix-ppc64@0.24.0': 1335 | optional: true 1336 | 1337 | '@esbuild/android-arm64@0.17.19': 1338 | optional: true 1339 | 1340 | '@esbuild/android-arm64@0.21.5': 1341 | optional: true 1342 | 1343 | '@esbuild/android-arm64@0.24.0': 1344 | optional: true 1345 | 1346 | '@esbuild/android-arm@0.17.19': 1347 | optional: true 1348 | 1349 | '@esbuild/android-arm@0.21.5': 1350 | optional: true 1351 | 1352 | '@esbuild/android-arm@0.24.0': 1353 | optional: true 1354 | 1355 | '@esbuild/android-x64@0.17.19': 1356 | optional: true 1357 | 1358 | '@esbuild/android-x64@0.21.5': 1359 | optional: true 1360 | 1361 | '@esbuild/android-x64@0.24.0': 1362 | optional: true 1363 | 1364 | '@esbuild/darwin-arm64@0.17.19': 1365 | optional: true 1366 | 1367 | '@esbuild/darwin-arm64@0.21.5': 1368 | optional: true 1369 | 1370 | '@esbuild/darwin-arm64@0.24.0': 1371 | optional: true 1372 | 1373 | '@esbuild/darwin-x64@0.17.19': 1374 | optional: true 1375 | 1376 | '@esbuild/darwin-x64@0.21.5': 1377 | optional: true 1378 | 1379 | '@esbuild/darwin-x64@0.24.0': 1380 | optional: true 1381 | 1382 | '@esbuild/freebsd-arm64@0.17.19': 1383 | optional: true 1384 | 1385 | '@esbuild/freebsd-arm64@0.21.5': 1386 | optional: true 1387 | 1388 | '@esbuild/freebsd-arm64@0.24.0': 1389 | optional: true 1390 | 1391 | '@esbuild/freebsd-x64@0.17.19': 1392 | optional: true 1393 | 1394 | '@esbuild/freebsd-x64@0.21.5': 1395 | optional: true 1396 | 1397 | '@esbuild/freebsd-x64@0.24.0': 1398 | optional: true 1399 | 1400 | '@esbuild/linux-arm64@0.17.19': 1401 | optional: true 1402 | 1403 | '@esbuild/linux-arm64@0.21.5': 1404 | optional: true 1405 | 1406 | '@esbuild/linux-arm64@0.24.0': 1407 | optional: true 1408 | 1409 | '@esbuild/linux-arm@0.17.19': 1410 | optional: true 1411 | 1412 | '@esbuild/linux-arm@0.21.5': 1413 | optional: true 1414 | 1415 | '@esbuild/linux-arm@0.24.0': 1416 | optional: true 1417 | 1418 | '@esbuild/linux-ia32@0.17.19': 1419 | optional: true 1420 | 1421 | '@esbuild/linux-ia32@0.21.5': 1422 | optional: true 1423 | 1424 | '@esbuild/linux-ia32@0.24.0': 1425 | optional: true 1426 | 1427 | '@esbuild/linux-loong64@0.17.19': 1428 | optional: true 1429 | 1430 | '@esbuild/linux-loong64@0.21.5': 1431 | optional: true 1432 | 1433 | '@esbuild/linux-loong64@0.24.0': 1434 | optional: true 1435 | 1436 | '@esbuild/linux-mips64el@0.17.19': 1437 | optional: true 1438 | 1439 | '@esbuild/linux-mips64el@0.21.5': 1440 | optional: true 1441 | 1442 | '@esbuild/linux-mips64el@0.24.0': 1443 | optional: true 1444 | 1445 | '@esbuild/linux-ppc64@0.17.19': 1446 | optional: true 1447 | 1448 | '@esbuild/linux-ppc64@0.21.5': 1449 | optional: true 1450 | 1451 | '@esbuild/linux-ppc64@0.24.0': 1452 | optional: true 1453 | 1454 | '@esbuild/linux-riscv64@0.17.19': 1455 | optional: true 1456 | 1457 | '@esbuild/linux-riscv64@0.21.5': 1458 | optional: true 1459 | 1460 | '@esbuild/linux-riscv64@0.24.0': 1461 | optional: true 1462 | 1463 | '@esbuild/linux-s390x@0.17.19': 1464 | optional: true 1465 | 1466 | '@esbuild/linux-s390x@0.21.5': 1467 | optional: true 1468 | 1469 | '@esbuild/linux-s390x@0.24.0': 1470 | optional: true 1471 | 1472 | '@esbuild/linux-x64@0.17.19': 1473 | optional: true 1474 | 1475 | '@esbuild/linux-x64@0.21.5': 1476 | optional: true 1477 | 1478 | '@esbuild/linux-x64@0.24.0': 1479 | optional: true 1480 | 1481 | '@esbuild/netbsd-x64@0.17.19': 1482 | optional: true 1483 | 1484 | '@esbuild/netbsd-x64@0.21.5': 1485 | optional: true 1486 | 1487 | '@esbuild/netbsd-x64@0.24.0': 1488 | optional: true 1489 | 1490 | '@esbuild/openbsd-arm64@0.24.0': 1491 | optional: true 1492 | 1493 | '@esbuild/openbsd-x64@0.17.19': 1494 | optional: true 1495 | 1496 | '@esbuild/openbsd-x64@0.21.5': 1497 | optional: true 1498 | 1499 | '@esbuild/openbsd-x64@0.24.0': 1500 | optional: true 1501 | 1502 | '@esbuild/sunos-x64@0.17.19': 1503 | optional: true 1504 | 1505 | '@esbuild/sunos-x64@0.21.5': 1506 | optional: true 1507 | 1508 | '@esbuild/sunos-x64@0.24.0': 1509 | optional: true 1510 | 1511 | '@esbuild/win32-arm64@0.17.19': 1512 | optional: true 1513 | 1514 | '@esbuild/win32-arm64@0.21.5': 1515 | optional: true 1516 | 1517 | '@esbuild/win32-arm64@0.24.0': 1518 | optional: true 1519 | 1520 | '@esbuild/win32-ia32@0.17.19': 1521 | optional: true 1522 | 1523 | '@esbuild/win32-ia32@0.21.5': 1524 | optional: true 1525 | 1526 | '@esbuild/win32-ia32@0.24.0': 1527 | optional: true 1528 | 1529 | '@esbuild/win32-x64@0.17.19': 1530 | optional: true 1531 | 1532 | '@esbuild/win32-x64@0.21.5': 1533 | optional: true 1534 | 1535 | '@esbuild/win32-x64@0.24.0': 1536 | optional: true 1537 | 1538 | '@fastify/busboy@2.1.1': {} 1539 | 1540 | '@jridgewell/resolve-uri@3.1.2': {} 1541 | 1542 | '@jridgewell/sourcemap-codec@1.5.0': {} 1543 | 1544 | '@jridgewell/trace-mapping@0.3.9': 1545 | dependencies: 1546 | '@jridgewell/resolve-uri': 3.1.2 1547 | '@jridgewell/sourcemap-codec': 1.5.0 1548 | 1549 | '@rollup/rollup-android-arm-eabi@4.29.1': 1550 | optional: true 1551 | 1552 | '@rollup/rollup-android-arm64@4.29.1': 1553 | optional: true 1554 | 1555 | '@rollup/rollup-darwin-arm64@4.29.1': 1556 | optional: true 1557 | 1558 | '@rollup/rollup-darwin-x64@4.29.1': 1559 | optional: true 1560 | 1561 | '@rollup/rollup-freebsd-arm64@4.29.1': 1562 | optional: true 1563 | 1564 | '@rollup/rollup-freebsd-x64@4.29.1': 1565 | optional: true 1566 | 1567 | '@rollup/rollup-linux-arm-gnueabihf@4.29.1': 1568 | optional: true 1569 | 1570 | '@rollup/rollup-linux-arm-musleabihf@4.29.1': 1571 | optional: true 1572 | 1573 | '@rollup/rollup-linux-arm64-gnu@4.29.1': 1574 | optional: true 1575 | 1576 | '@rollup/rollup-linux-arm64-musl@4.29.1': 1577 | optional: true 1578 | 1579 | '@rollup/rollup-linux-loongarch64-gnu@4.29.1': 1580 | optional: true 1581 | 1582 | '@rollup/rollup-linux-powerpc64le-gnu@4.29.1': 1583 | optional: true 1584 | 1585 | '@rollup/rollup-linux-riscv64-gnu@4.29.1': 1586 | optional: true 1587 | 1588 | '@rollup/rollup-linux-s390x-gnu@4.29.1': 1589 | optional: true 1590 | 1591 | '@rollup/rollup-linux-x64-gnu@4.29.1': 1592 | optional: true 1593 | 1594 | '@rollup/rollup-linux-x64-musl@4.29.1': 1595 | optional: true 1596 | 1597 | '@rollup/rollup-win32-arm64-msvc@4.29.1': 1598 | optional: true 1599 | 1600 | '@rollup/rollup-win32-ia32-msvc@4.29.1': 1601 | optional: true 1602 | 1603 | '@rollup/rollup-win32-x64-msvc@4.29.1': 1604 | optional: true 1605 | 1606 | '@technically/lodash@4.17.0': 1607 | dependencies: 1608 | '@types/lodash-es': 4.17.12 1609 | lodash-es: 4.17.21 1610 | 1611 | '@types/estree@1.0.6': {} 1612 | 1613 | '@types/lodash-es@4.17.12': 1614 | dependencies: 1615 | '@types/lodash': 4.17.13 1616 | 1617 | '@types/lodash@4.17.13': {} 1618 | 1619 | '@types/node-forge@1.3.11': 1620 | dependencies: 1621 | '@types/node': 22.10.2 1622 | 1623 | '@types/node@22.10.2': 1624 | dependencies: 1625 | undici-types: 6.20.0 1626 | 1627 | '@vitest/expect@2.1.8': 1628 | dependencies: 1629 | '@vitest/spy': 2.1.8 1630 | '@vitest/utils': 2.1.8 1631 | chai: 5.1.2 1632 | tinyrainbow: 1.2.0 1633 | 1634 | '@vitest/mocker@2.1.8(vite@5.4.11(@types/node@22.10.2))': 1635 | dependencies: 1636 | '@vitest/spy': 2.1.8 1637 | estree-walker: 3.0.3 1638 | magic-string: 0.30.17 1639 | optionalDependencies: 1640 | vite: 5.4.11(@types/node@22.10.2) 1641 | 1642 | '@vitest/pretty-format@2.1.8': 1643 | dependencies: 1644 | tinyrainbow: 1.2.0 1645 | 1646 | '@vitest/runner@2.1.8': 1647 | dependencies: 1648 | '@vitest/utils': 2.1.8 1649 | pathe: 1.1.2 1650 | 1651 | '@vitest/snapshot@2.1.8': 1652 | dependencies: 1653 | '@vitest/pretty-format': 2.1.8 1654 | magic-string: 0.30.17 1655 | pathe: 1.1.2 1656 | 1657 | '@vitest/spy@2.1.8': 1658 | dependencies: 1659 | tinyspy: 3.0.2 1660 | 1661 | '@vitest/utils@2.1.8': 1662 | dependencies: 1663 | '@vitest/pretty-format': 2.1.8 1664 | loupe: 3.1.2 1665 | tinyrainbow: 1.2.0 1666 | 1667 | acorn-walk@8.3.4: 1668 | dependencies: 1669 | acorn: 8.14.0 1670 | 1671 | acorn@8.14.0: {} 1672 | 1673 | as-table@1.0.55: 1674 | dependencies: 1675 | printable-characters: 1.0.42 1676 | 1677 | assertion-error@2.0.1: {} 1678 | 1679 | birpc@0.2.14: {} 1680 | 1681 | blake3-wasm@2.1.5: {} 1682 | 1683 | cac@6.7.14: {} 1684 | 1685 | capnp-ts@0.7.0: 1686 | dependencies: 1687 | debug: 4.4.0 1688 | tslib: 2.8.1 1689 | transitivePeerDependencies: 1690 | - supports-color 1691 | 1692 | chai@5.1.2: 1693 | dependencies: 1694 | assertion-error: 2.0.1 1695 | check-error: 2.1.1 1696 | deep-eql: 5.0.2 1697 | loupe: 3.1.2 1698 | pathval: 2.0.0 1699 | 1700 | check-error@2.1.1: {} 1701 | 1702 | chokidar@4.0.3: 1703 | dependencies: 1704 | readdirp: 4.0.2 1705 | 1706 | cjs-module-lexer@1.4.1: {} 1707 | 1708 | cookie@0.7.2: {} 1709 | 1710 | data-uri-to-buffer@2.0.2: {} 1711 | 1712 | date-fns@4.1.0: {} 1713 | 1714 | debug@4.4.0: 1715 | dependencies: 1716 | ms: 2.1.3 1717 | 1718 | deep-eql@5.0.2: {} 1719 | 1720 | defu@6.1.4: {} 1721 | 1722 | devalue@4.3.3: {} 1723 | 1724 | diffable-objects@0.1.1: 1725 | dependencies: 1726 | json-diff-ts: 4.1.0 1727 | 1728 | es-module-lexer@1.5.4: {} 1729 | 1730 | esbuild@0.17.19: 1731 | optionalDependencies: 1732 | '@esbuild/android-arm': 0.17.19 1733 | '@esbuild/android-arm64': 0.17.19 1734 | '@esbuild/android-x64': 0.17.19 1735 | '@esbuild/darwin-arm64': 0.17.19 1736 | '@esbuild/darwin-x64': 0.17.19 1737 | '@esbuild/freebsd-arm64': 0.17.19 1738 | '@esbuild/freebsd-x64': 0.17.19 1739 | '@esbuild/linux-arm': 0.17.19 1740 | '@esbuild/linux-arm64': 0.17.19 1741 | '@esbuild/linux-ia32': 0.17.19 1742 | '@esbuild/linux-loong64': 0.17.19 1743 | '@esbuild/linux-mips64el': 0.17.19 1744 | '@esbuild/linux-ppc64': 0.17.19 1745 | '@esbuild/linux-riscv64': 0.17.19 1746 | '@esbuild/linux-s390x': 0.17.19 1747 | '@esbuild/linux-x64': 0.17.19 1748 | '@esbuild/netbsd-x64': 0.17.19 1749 | '@esbuild/openbsd-x64': 0.17.19 1750 | '@esbuild/sunos-x64': 0.17.19 1751 | '@esbuild/win32-arm64': 0.17.19 1752 | '@esbuild/win32-ia32': 0.17.19 1753 | '@esbuild/win32-x64': 0.17.19 1754 | 1755 | esbuild@0.21.5: 1756 | optionalDependencies: 1757 | '@esbuild/aix-ppc64': 0.21.5 1758 | '@esbuild/android-arm': 0.21.5 1759 | '@esbuild/android-arm64': 0.21.5 1760 | '@esbuild/android-x64': 0.21.5 1761 | '@esbuild/darwin-arm64': 0.21.5 1762 | '@esbuild/darwin-x64': 0.21.5 1763 | '@esbuild/freebsd-arm64': 0.21.5 1764 | '@esbuild/freebsd-x64': 0.21.5 1765 | '@esbuild/linux-arm': 0.21.5 1766 | '@esbuild/linux-arm64': 0.21.5 1767 | '@esbuild/linux-ia32': 0.21.5 1768 | '@esbuild/linux-loong64': 0.21.5 1769 | '@esbuild/linux-mips64el': 0.21.5 1770 | '@esbuild/linux-ppc64': 0.21.5 1771 | '@esbuild/linux-riscv64': 0.21.5 1772 | '@esbuild/linux-s390x': 0.21.5 1773 | '@esbuild/linux-x64': 0.21.5 1774 | '@esbuild/netbsd-x64': 0.21.5 1775 | '@esbuild/openbsd-x64': 0.21.5 1776 | '@esbuild/sunos-x64': 0.21.5 1777 | '@esbuild/win32-arm64': 0.21.5 1778 | '@esbuild/win32-ia32': 0.21.5 1779 | '@esbuild/win32-x64': 0.21.5 1780 | 1781 | esbuild@0.24.0: 1782 | optionalDependencies: 1783 | '@esbuild/aix-ppc64': 0.24.0 1784 | '@esbuild/android-arm': 0.24.0 1785 | '@esbuild/android-arm64': 0.24.0 1786 | '@esbuild/android-x64': 0.24.0 1787 | '@esbuild/darwin-arm64': 0.24.0 1788 | '@esbuild/darwin-x64': 0.24.0 1789 | '@esbuild/freebsd-arm64': 0.24.0 1790 | '@esbuild/freebsd-x64': 0.24.0 1791 | '@esbuild/linux-arm': 0.24.0 1792 | '@esbuild/linux-arm64': 0.24.0 1793 | '@esbuild/linux-ia32': 0.24.0 1794 | '@esbuild/linux-loong64': 0.24.0 1795 | '@esbuild/linux-mips64el': 0.24.0 1796 | '@esbuild/linux-ppc64': 0.24.0 1797 | '@esbuild/linux-riscv64': 0.24.0 1798 | '@esbuild/linux-s390x': 0.24.0 1799 | '@esbuild/linux-x64': 0.24.0 1800 | '@esbuild/netbsd-x64': 0.24.0 1801 | '@esbuild/openbsd-arm64': 0.24.0 1802 | '@esbuild/openbsd-x64': 0.24.0 1803 | '@esbuild/sunos-x64': 0.24.0 1804 | '@esbuild/win32-arm64': 0.24.0 1805 | '@esbuild/win32-ia32': 0.24.0 1806 | '@esbuild/win32-x64': 0.24.0 1807 | 1808 | escape-string-regexp@4.0.0: {} 1809 | 1810 | estree-walker@0.6.1: {} 1811 | 1812 | estree-walker@3.0.3: 1813 | dependencies: 1814 | '@types/estree': 1.0.6 1815 | 1816 | exit-hook@2.2.1: {} 1817 | 1818 | expect-type@1.1.0: {} 1819 | 1820 | fsevents@2.3.3: 1821 | optional: true 1822 | 1823 | function-bind@1.1.2: {} 1824 | 1825 | get-source@2.0.12: 1826 | dependencies: 1827 | data-uri-to-buffer: 2.0.2 1828 | source-map: 0.6.1 1829 | 1830 | glob-to-regexp@0.4.1: {} 1831 | 1832 | hasown@2.0.2: 1833 | dependencies: 1834 | function-bind: 1.1.2 1835 | 1836 | is-core-module@2.16.1: 1837 | dependencies: 1838 | hasown: 2.0.2 1839 | 1840 | itty-time@1.0.6: {} 1841 | 1842 | json-diff-ts@4.1.0: 1843 | dependencies: 1844 | lodash: '@technically/lodash@4.17.0' 1845 | 1846 | lodash-es@4.17.21: {} 1847 | 1848 | loupe@3.1.2: {} 1849 | 1850 | magic-string@0.25.9: 1851 | dependencies: 1852 | sourcemap-codec: 1.4.8 1853 | 1854 | magic-string@0.30.17: 1855 | dependencies: 1856 | '@jridgewell/sourcemap-codec': 1.5.0 1857 | 1858 | mime@3.0.0: {} 1859 | 1860 | miniflare@0.0.0-dc669c404: 1861 | dependencies: 1862 | '@cspotcode/source-map-support': 0.8.1 1863 | acorn: 8.14.0 1864 | acorn-walk: 8.3.4 1865 | capnp-ts: 0.7.0 1866 | exit-hook: 2.2.1 1867 | glob-to-regexp: 0.4.1 1868 | stoppable: 1.1.0 1869 | undici: 5.28.4 1870 | workerd: 1.20241106.1 1871 | ws: 8.18.0 1872 | youch: 3.3.4 1873 | zod: 3.24.1 1874 | transitivePeerDependencies: 1875 | - bufferutil 1876 | - supports-color 1877 | - utf-8-validate 1878 | 1879 | miniflare@3.20241218.0: 1880 | dependencies: 1881 | '@cspotcode/source-map-support': 0.8.1 1882 | acorn: 8.14.0 1883 | acorn-walk: 8.3.4 1884 | capnp-ts: 0.7.0 1885 | exit-hook: 2.2.1 1886 | glob-to-regexp: 0.4.1 1887 | stoppable: 1.1.0 1888 | undici: 5.28.4 1889 | workerd: 1.20241218.0 1890 | ws: 8.18.0 1891 | youch: 3.3.4 1892 | zod: 3.24.1 1893 | transitivePeerDependencies: 1894 | - bufferutil 1895 | - supports-color 1896 | - utf-8-validate 1897 | 1898 | ms@2.1.3: {} 1899 | 1900 | mustache@4.2.0: {} 1901 | 1902 | nanoid@3.3.8: {} 1903 | 1904 | node-forge@1.3.1: {} 1905 | 1906 | ohash@1.1.4: {} 1907 | 1908 | path-parse@1.0.7: {} 1909 | 1910 | path-to-regexp@6.3.0: {} 1911 | 1912 | pathe@1.1.2: {} 1913 | 1914 | pathval@2.0.0: {} 1915 | 1916 | picocolors@1.1.1: {} 1917 | 1918 | postcss@8.4.49: 1919 | dependencies: 1920 | nanoid: 3.3.8 1921 | picocolors: 1.1.1 1922 | source-map-js: 1.2.1 1923 | 1924 | printable-characters@1.0.42: {} 1925 | 1926 | readdirp@4.0.2: {} 1927 | 1928 | resolve.exports@2.0.3: {} 1929 | 1930 | resolve@1.22.10: 1931 | dependencies: 1932 | is-core-module: 2.16.1 1933 | path-parse: 1.0.7 1934 | supports-preserve-symlinks-flag: 1.0.0 1935 | 1936 | rollup-plugin-inject@3.0.2: 1937 | dependencies: 1938 | estree-walker: 0.6.1 1939 | magic-string: 0.25.9 1940 | rollup-pluginutils: 2.8.2 1941 | 1942 | rollup-plugin-node-polyfills@0.2.1: 1943 | dependencies: 1944 | rollup-plugin-inject: 3.0.2 1945 | 1946 | rollup-pluginutils@2.8.2: 1947 | dependencies: 1948 | estree-walker: 0.6.1 1949 | 1950 | rollup@4.29.1: 1951 | dependencies: 1952 | '@types/estree': 1.0.6 1953 | optionalDependencies: 1954 | '@rollup/rollup-android-arm-eabi': 4.29.1 1955 | '@rollup/rollup-android-arm64': 4.29.1 1956 | '@rollup/rollup-darwin-arm64': 4.29.1 1957 | '@rollup/rollup-darwin-x64': 4.29.1 1958 | '@rollup/rollup-freebsd-arm64': 4.29.1 1959 | '@rollup/rollup-freebsd-x64': 4.29.1 1960 | '@rollup/rollup-linux-arm-gnueabihf': 4.29.1 1961 | '@rollup/rollup-linux-arm-musleabihf': 4.29.1 1962 | '@rollup/rollup-linux-arm64-gnu': 4.29.1 1963 | '@rollup/rollup-linux-arm64-musl': 4.29.1 1964 | '@rollup/rollup-linux-loongarch64-gnu': 4.29.1 1965 | '@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 1966 | '@rollup/rollup-linux-riscv64-gnu': 4.29.1 1967 | '@rollup/rollup-linux-s390x-gnu': 4.29.1 1968 | '@rollup/rollup-linux-x64-gnu': 4.29.1 1969 | '@rollup/rollup-linux-x64-musl': 4.29.1 1970 | '@rollup/rollup-win32-arm64-msvc': 4.29.1 1971 | '@rollup/rollup-win32-ia32-msvc': 4.29.1 1972 | '@rollup/rollup-win32-x64-msvc': 4.29.1 1973 | fsevents: 2.3.3 1974 | 1975 | selfsigned@2.4.1: 1976 | dependencies: 1977 | '@types/node-forge': 1.3.11 1978 | node-forge: 1.3.1 1979 | 1980 | semver@7.6.3: {} 1981 | 1982 | siginfo@2.0.0: {} 1983 | 1984 | source-map-js@1.2.1: {} 1985 | 1986 | source-map@0.6.1: {} 1987 | 1988 | sourcemap-codec@1.4.8: {} 1989 | 1990 | stackback@0.0.2: {} 1991 | 1992 | stacktracey@2.1.8: 1993 | dependencies: 1994 | as-table: 1.0.55 1995 | get-source: 2.0.12 1996 | 1997 | std-env@3.8.0: {} 1998 | 1999 | stoppable@1.1.0: {} 2000 | 2001 | supports-preserve-symlinks-flag@1.0.0: {} 2002 | 2003 | tinybench@2.9.0: {} 2004 | 2005 | tinyexec@0.3.1: {} 2006 | 2007 | tinypool@1.0.2: {} 2008 | 2009 | tinyrainbow@1.2.0: {} 2010 | 2011 | tinyspy@3.0.2: {} 2012 | 2013 | tslib@2.8.1: {} 2014 | 2015 | typescript@5.7.2: {} 2016 | 2017 | ufo@1.5.4: {} 2018 | 2019 | undici-types@6.20.0: {} 2020 | 2021 | undici@5.28.4: 2022 | dependencies: 2023 | '@fastify/busboy': 2.1.1 2024 | 2025 | unenv-nightly@2.0.0-20241121-161142-806b5c0: 2026 | dependencies: 2027 | defu: 6.1.4 2028 | ohash: 1.1.4 2029 | pathe: 1.1.2 2030 | ufo: 1.5.4 2031 | 2032 | unenv-nightly@2.0.0-20241204-140205-a5d5190: 2033 | dependencies: 2034 | defu: 6.1.4 2035 | ohash: 1.1.4 2036 | pathe: 1.1.2 2037 | ufo: 1.5.4 2038 | 2039 | vite-node@2.1.8(@types/node@22.10.2): 2040 | dependencies: 2041 | cac: 6.7.14 2042 | debug: 4.4.0 2043 | es-module-lexer: 1.5.4 2044 | pathe: 1.1.2 2045 | vite: 5.4.11(@types/node@22.10.2) 2046 | transitivePeerDependencies: 2047 | - '@types/node' 2048 | - less 2049 | - lightningcss 2050 | - sass 2051 | - sass-embedded 2052 | - stylus 2053 | - sugarss 2054 | - supports-color 2055 | - terser 2056 | 2057 | vite@5.4.11(@types/node@22.10.2): 2058 | dependencies: 2059 | esbuild: 0.21.5 2060 | postcss: 8.4.49 2061 | rollup: 4.29.1 2062 | optionalDependencies: 2063 | '@types/node': 22.10.2 2064 | fsevents: 2.3.3 2065 | 2066 | vitest@2.1.8(@types/node@22.10.2): 2067 | dependencies: 2068 | '@vitest/expect': 2.1.8 2069 | '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.10.2)) 2070 | '@vitest/pretty-format': 2.1.8 2071 | '@vitest/runner': 2.1.8 2072 | '@vitest/snapshot': 2.1.8 2073 | '@vitest/spy': 2.1.8 2074 | '@vitest/utils': 2.1.8 2075 | chai: 5.1.2 2076 | debug: 4.4.0 2077 | expect-type: 1.1.0 2078 | magic-string: 0.30.17 2079 | pathe: 1.1.2 2080 | std-env: 3.8.0 2081 | tinybench: 2.9.0 2082 | tinyexec: 0.3.1 2083 | tinypool: 1.0.2 2084 | tinyrainbow: 1.2.0 2085 | vite: 5.4.11(@types/node@22.10.2) 2086 | vite-node: 2.1.8(@types/node@22.10.2) 2087 | why-is-node-running: 2.3.0 2088 | optionalDependencies: 2089 | '@types/node': 22.10.2 2090 | transitivePeerDependencies: 2091 | - less 2092 | - lightningcss 2093 | - msw 2094 | - sass 2095 | - sass-embedded 2096 | - stylus 2097 | - sugarss 2098 | - supports-color 2099 | - terser 2100 | 2101 | why-is-node-running@2.3.0: 2102 | dependencies: 2103 | siginfo: 2.0.0 2104 | stackback: 0.0.2 2105 | 2106 | workerd@1.20241106.1: 2107 | optionalDependencies: 2108 | '@cloudflare/workerd-darwin-64': 1.20241106.1 2109 | '@cloudflare/workerd-darwin-arm64': 1.20241106.1 2110 | '@cloudflare/workerd-linux-64': 1.20241106.1 2111 | '@cloudflare/workerd-linux-arm64': 1.20241106.1 2112 | '@cloudflare/workerd-windows-64': 1.20241106.1 2113 | 2114 | workerd@1.20241218.0: 2115 | optionalDependencies: 2116 | '@cloudflare/workerd-darwin-64': 1.20241218.0 2117 | '@cloudflare/workerd-darwin-arm64': 1.20241218.0 2118 | '@cloudflare/workerd-linux-64': 1.20241218.0 2119 | '@cloudflare/workerd-linux-arm64': 1.20241218.0 2120 | '@cloudflare/workerd-windows-64': 1.20241218.0 2121 | 2122 | wrangler@0.0.0-dc669c404(@cloudflare/workers-types@4.20241224.0): 2123 | dependencies: 2124 | '@cloudflare/kv-asset-handler': 0.3.4 2125 | '@cloudflare/workers-shared': 0.8.0 2126 | blake3-wasm: 2.1.5 2127 | chokidar: 4.0.3 2128 | date-fns: 4.1.0 2129 | esbuild: 0.24.0 2130 | itty-time: 1.0.6 2131 | miniflare: 0.0.0-dc669c404 2132 | nanoid: 3.3.8 2133 | path-to-regexp: 6.3.0 2134 | resolve: 1.22.10 2135 | resolve.exports: 2.0.3 2136 | selfsigned: 2.4.1 2137 | source-map: 0.6.1 2138 | unenv: unenv-nightly@2.0.0-20241121-161142-806b5c0 2139 | workerd: 1.20241106.1 2140 | xxhash-wasm: 1.1.0 2141 | optionalDependencies: 2142 | '@cloudflare/workers-types': 4.20241224.0 2143 | fsevents: 2.3.3 2144 | transitivePeerDependencies: 2145 | - bufferutil 2146 | - supports-color 2147 | - utf-8-validate 2148 | 2149 | wrangler@3.99.0(@cloudflare/workers-types@4.20241224.0): 2150 | dependencies: 2151 | '@cloudflare/kv-asset-handler': 0.3.4 2152 | '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) 2153 | '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) 2154 | blake3-wasm: 2.1.5 2155 | chokidar: 4.0.3 2156 | date-fns: 4.1.0 2157 | esbuild: 0.17.19 2158 | itty-time: 1.0.6 2159 | miniflare: 3.20241218.0 2160 | nanoid: 3.3.8 2161 | path-to-regexp: 6.3.0 2162 | resolve: 1.22.10 2163 | selfsigned: 2.4.1 2164 | source-map: 0.6.1 2165 | unenv: unenv-nightly@2.0.0-20241204-140205-a5d5190 2166 | workerd: 1.20241218.0 2167 | xxhash-wasm: 1.1.0 2168 | optionalDependencies: 2169 | '@cloudflare/workers-types': 4.20241224.0 2170 | fsevents: 2.3.3 2171 | transitivePeerDependencies: 2172 | - bufferutil 2173 | - supports-color 2174 | - utf-8-validate 2175 | 2176 | ws@8.18.0: {} 2177 | 2178 | xxhash-wasm@1.1.0: {} 2179 | 2180 | youch@3.3.4: 2181 | dependencies: 2182 | cookie: 0.7.2 2183 | mustache: 4.2.0 2184 | stacktracey: 2.1.8 2185 | 2186 | zod@3.24.1: {} 2187 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - examples/* -------------------------------------------------------------------------------- /src/decorator.ts: -------------------------------------------------------------------------------- 1 | import type { DurableObject } from "cloudflare:workers"; 2 | import { type SnapshotPolicy, state } from "./index.js"; 3 | import { unreachable } from "./util.js"; 4 | 5 | type FieldDecoratorFactoryReturn = ( 6 | value: T, 7 | metadata: { kind: string; name: string }, 8 | ) => FieldDecoratorReturn; 9 | 10 | type FieldDecoratorReturn = (this: DurableObject, initialValue: T) => T; 11 | 12 | type DiffableArgs = 13 | | [] 14 | | [DiffableOpts] 15 | | [name?: string] 16 | | [_: any, { kind: string; name: string }]; 17 | 18 | type DiffableOpts = { 19 | /** 20 | * The name of the state, typically the name of the field. 21 | */ 22 | name?: string; 23 | /** 24 | * Diffable-objects will automatically snapshot the state perodically based on this policy to minimize 25 | * the number of diffs that must be applied to restore the state when the Durable Object is restarted. 26 | */ 27 | snapshotPolicy?: SnapshotPolicy; 28 | }; 29 | 30 | /** 31 | * Dynamically create a state object that persists changes to durable storage using Proxy and SQLite. 32 | * 33 | * ``` 34 | * import { DurableObject } from "cloudflare:workers"; 35 | * import { diffable } from "diffable-objects"; 36 | * 37 | * class Counter extends DurableObject { 38 | * @diffable 39 | * #state = { count: 0 }; 40 | * 41 | * async fetch(request) { 42 | * this.#state.count += 1; 43 | * return new Response(`Count: ${this.#state.count}`); 44 | * } 45 | * } 46 | * ``` 47 | */ 48 | export function diffable( 49 | _: any, 50 | { kind, name }: { kind: string; name: string }, 51 | ): FieldDecoratorReturn; 52 | /** 53 | * Dynamically create a state object that persists changes to durable storage using Proxy and SQLite. 54 | * 55 | * ``` 56 | * import { DurableObject } from "cloudflare:workers"; 57 | * import { diffable } from "diffable-objects"; 58 | * 59 | * class Counter extends DurableObject { 60 | * @diffable("counter") 61 | * #state = { count: 0 }; 62 | * 63 | * async fetch(request) { 64 | * this.#state.count += 1; 65 | * return new Response(`Count: ${this.#state.count}`); 66 | * } 67 | * } 68 | * ``` 69 | */ 70 | export function diffable(name?: string): FieldDecoratorFactoryReturn; 71 | /** 72 | * Dynamically create a state object that persists changes to durable storage using Proxy and SQLite. 73 | * 74 | * ``` 75 | * import { DurableObject } from "cloudflare:workers"; 76 | * import { diffable } from "diffable-objects"; 77 | * 78 | * class Counter extends DurableObject { 79 | * @diffable({ name: "counter", snapshotPolicy: "never" }) 80 | * #state = { count: 0 }; 81 | * 82 | * async fetch(request) { 83 | * this.#state.count += 1; 84 | * return new Response(`Count: ${this.#state.count}`); 85 | * } 86 | * } 87 | * ``` 88 | */ 89 | export function diffable( 90 | options: DiffableOpts, 91 | ): FieldDecoratorFactoryReturn; 92 | export function diffable(): 93 | | FieldDecoratorReturn 94 | | FieldDecoratorFactoryReturn { 95 | // biome-ignore lint/style/noArguments: 96 | const args = arguments as unknown as DiffableArgs; 97 | const fn = 98 | (opts: DiffableOpts = {}) => 99 | (_: any, { kind, name: fieldName }: { kind: string; name: string }) => { 100 | if (kind === "field") { 101 | return function (this: DurableObject, initialValue: any) { 102 | const fieldNameNonPrivate = fieldName.replace(/^#/, ""); 103 | return state( 104 | this.ctx, 105 | opts.name ?? fieldNameNonPrivate, 106 | initialValue, 107 | { 108 | snapshotPolicy: opts.snapshotPolicy ?? { changes: 10 }, 109 | }, 110 | ); 111 | }; 112 | } 113 | 114 | throw new Error("Only fields can be persistable"); 115 | }; 116 | 117 | if (args.length === 0) { 118 | return fn(); 119 | } 120 | 121 | if (args.length === 1) { 122 | const [optsOrName] = args; 123 | 124 | if (typeof optsOrName === "object") { 125 | return fn(optsOrName); 126 | } 127 | 128 | return fn(optsOrName ? { name: optsOrName } : {}); 129 | } 130 | 131 | const [value, metadata] = args; 132 | return fn()(value, metadata ?? unreachable()); 133 | } 134 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { recursivelyObservable } from "./observable.js"; 2 | import { SqliteState } from "./sqlite.js"; 3 | import { unreachable } from "./util.js"; 4 | 5 | export * from "./decorator.js"; 6 | 7 | export type SnapshotPolicy = "never" | "every-change" | { changes: number }; 8 | 9 | export type StateOptions = { 10 | /** 11 | * Diffable-objects will automatically snapshot the state perodically based on this policy to minimize the 12 | * number of diffs that must be applied to restore the state when the Durable Object is restarted. 13 | */ 14 | snapshotPolicy?: SnapshotPolicy; 15 | }; 16 | 17 | /** 18 | * Dynamically create a state object that persists changes to durable storage using Proxy and SQLite. 19 | * 20 | * @example 21 | * ``` 22 | * import { DurableObject } from "cloudflare:workers"; 23 | * import { state } from "diffable-objects"; 24 | * 25 | * class Counter extends DurableObject { 26 | * #state = state(this, "counter", { count: 0 }); 27 | * 28 | * async fetch(request) { 29 | * this.#state.count += 1; 30 | * return new Response(`Count: ${this.#state.count}`); 31 | * } 32 | * } 33 | * ``` 34 | * 35 | * @param ctx the DurableObject state. 36 | * @param name the name of the state, typically the name of the field. 37 | * @param initialState the initial state of this object, this must be the same every time the DO is created. 38 | * @param options options for configuring how the state is persisted. 39 | * @returns a copy of state that will persist changes. 40 | */ 41 | export function state( 42 | ctx: DurableObjectState, 43 | name: string, 44 | initialState: T, 45 | options: StateOptions = { 46 | snapshotPolicy: { changes: 10 }, 47 | }, 48 | ): T { 49 | const state = new SqliteState(name, ctx.storage); 50 | const data = state.resume(initialState); 51 | return recursivelyObservable(data, { 52 | onUpdate(changes, data) { 53 | state.appendChanges(changes); 54 | maybeSnapshot(data, state, options.snapshotPolicy ?? { changes: 10 }); 55 | }, 56 | }); 57 | } 58 | 59 | function maybeSnapshot( 60 | data: T, 61 | state: SqliteState, 62 | snapshotPolicy: SnapshotPolicy, 63 | ) { 64 | if (snapshotPolicy === "every-change") { 65 | state.snapshot(data); 66 | } else if ( 67 | typeof snapshotPolicy === "object" && 68 | "changes" in snapshotPolicy 69 | ) { 70 | const latest = state.latestChange() ?? unreachable(); 71 | if (latest.id % snapshotPolicy.changes === 0) { 72 | state.snapshot(data); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/observable.ts: -------------------------------------------------------------------------------- 1 | import { atomizeChangeset, diff, type IAtomicChange } from "json-diff-ts"; 2 | 3 | type ProcessUpdateFn = (applyChanges: () => void) => void; 4 | 5 | type RecursivelyObservableOptions = { 6 | processUpdate?: ProcessUpdateFn; 7 | onUpdate: (changes: IAtomicChange[], data: T) => void; 8 | }; 9 | 10 | export function recursivelyObservable( 11 | data: T, 12 | opts: RecursivelyObservableOptions, 13 | ): T { 14 | const processUpdate = 15 | opts.processUpdate ?? 16 | ((applyChanges) => { 17 | const old = structuredClone(data); 18 | applyChanges(); 19 | const diffs = diff(old, data); 20 | const atomicChanges = atomizeChangeset(diffs); 21 | if (atomicChanges.length > 0) { 22 | opts.onUpdate(atomicChanges, data); 23 | } 24 | }); 25 | 26 | const proxyOpts: ProxyHandler = { 27 | get(target, p) { 28 | const property = target[p as keyof T]; 29 | if (property !== null && typeof property === "object") { 30 | // @ts-ignore TODO 31 | return recursivelyObservable(property, { 32 | ...opts, 33 | processUpdate, 34 | }); 35 | } 36 | return target[p as keyof T]; 37 | }, 38 | set(target, p, newValue) { 39 | processUpdate(() => { 40 | target[p as keyof T] = newValue; 41 | }); 42 | return true; 43 | }, 44 | }; 45 | 46 | return new Proxy(data, proxyOpts) as T; 47 | } 48 | -------------------------------------------------------------------------------- /src/sqlite.ts: -------------------------------------------------------------------------------- 1 | import type { IAtomicChange, Operation } from "json-diff-ts"; 2 | import { replay, type TrackerActions } from "./tracker.js"; 3 | 4 | const INITIAL_QUERY = ` 5 | CREATE TABLE IF NOT EXISTS changes ( 6 | id INTEGER PRIMARY KEY AUTOINCREMENT, 7 | state TEXT NOT NULL, 8 | type TEXT NOT NULL, 9 | key TEXT NOT NULL, 10 | path TEXT NOT NULL, 11 | valueType TEXT, 12 | value TEXT, 13 | oldValue TEXT 14 | ); 15 | 16 | CREATE TABLE IF NOT EXISTS snapshots ( 17 | id INTEGER PRIMARY KEY AUTOINCREMENT, 18 | state TEXT NOT NULL, 19 | value TEXT NOT NULL, 20 | changes_id INTEGER NOT NULL, 21 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 22 | ); 23 | `; 24 | 25 | type Change = { 26 | type: string; 27 | key: string; 28 | path: string; 29 | valueType: string | null; 30 | value: string | null; 31 | oldValue: string | null; 32 | }; 33 | 34 | export class SqliteState { 35 | #name: string; 36 | #storage: DurableObjectStorage; 37 | #db: SqlStorage; 38 | 39 | constructor(name: string, storage: DurableObjectStorage) { 40 | this.#name = name; 41 | this.#storage = storage; 42 | this.#db = storage.sql; 43 | this.#db.exec(INITIAL_QUERY); 44 | } 45 | 46 | resume(initialValue: T): T { 47 | const results = this.#db.exec<{ value: string; changes_id: number }>( 48 | "SELECT value, changes_id FROM snapshots WHERE state = ? ORDER BY created_at DESC LIMIT 1", 49 | this.#name, 50 | ); 51 | const result = results.next(); 52 | 53 | const mapChanges = (changes: Change[]) => 54 | changes.map( 55 | (change) => 56 | ({ 57 | type: "change", 58 | atomicChange: { 59 | type: change.type as Operation, 60 | key: change.key, 61 | path: change.path, 62 | valueType: change.valueType, 63 | value: change.value ? JSON.parse(change.value) : undefined, 64 | oldValue: change.oldValue 65 | ? JSON.parse(change.oldValue) 66 | : undefined, 67 | }, 68 | }) as const, 69 | ); 70 | 71 | if (!result.done) { 72 | const { value, changes_id } = result.value; 73 | const changes = this.#db 74 | .exec( 75 | "SELECT * FROM changes WHERE id > ? AND state = ?", 76 | changes_id, 77 | this.#name, 78 | ) 79 | .toArray(); 80 | 81 | const actions: TrackerActions = [ 82 | { 83 | type: "snapshot", 84 | value: JSON.parse(value), 85 | }, 86 | ...mapChanges(changes), 87 | ]; 88 | return replay(actions, initialValue); 89 | } 90 | 91 | const changes = this.#db 92 | .exec("SELECT * FROM changes WHERE state = ?", this.#name) 93 | .toArray(); 94 | return replay(mapChanges(changes), initialValue); 95 | } 96 | 97 | appendChanges(changes: IAtomicChange[]): void { 98 | if (changes.length === 0) { 99 | return; 100 | } 101 | 102 | this.#storage.transactionSync(() => { 103 | for (const { type, key, path, valueType, value, oldValue } of changes) { 104 | this.#db.exec( 105 | "INSERT INTO changes (state, type, key, path, valueType, value, oldValue) VALUES (?, ?, ?, ?, ?, ?, ?)", 106 | this.#name, 107 | type, 108 | key, 109 | path, 110 | valueType, 111 | value ? JSON.stringify(value) : null, 112 | oldValue ? JSON.stringify(oldValue) : null, 113 | ); 114 | } 115 | }); 116 | } 117 | 118 | latestChange(): { id: number } | null { 119 | const result = this.#db 120 | .exec<{ id: number }>( 121 | "SELECT id FROM changes WHERE state = ? ORDER BY id DESC LIMIT 1", 122 | this.#name, 123 | ) 124 | .next(); 125 | 126 | if (result.done) { 127 | return null; 128 | } 129 | 130 | return { id: result.value.id }; 131 | } 132 | 133 | latestSnapshot(): Date | null { 134 | const result = this.#db 135 | .exec<{ created_at: string }>( 136 | "SELECT created_at FROM snapshots WHERE state = ? ORDER BY created_at DESC LIMIT 1", 137 | this.#name, 138 | ) 139 | .next(); 140 | 141 | if (result.done) { 142 | return null; 143 | } 144 | 145 | return new Date(result.value.created_at); 146 | } 147 | 148 | snapshot(snapshot: T): void { 149 | const { id } = this.#db 150 | .exec<{ id: number }>( 151 | "SELECT id FROM changes WHERE state = ? ORDER BY id DESC LIMIT 1", 152 | this.#name, 153 | ) 154 | .one(); 155 | 156 | // TODO: assert there are changes in the DB before we can snapshot. 157 | 158 | this.#db.exec( 159 | "INSERT INTO snapshots (state, value, changes_id) VALUES (?, ?, ?)", 160 | this.#name, 161 | JSON.stringify(snapshot), 162 | id, 163 | ); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/tracker.ts: -------------------------------------------------------------------------------- 1 | import { 2 | applyChangeset, 3 | unatomizeChangeset, 4 | type IAtomicChange, 5 | } from "json-diff-ts"; 6 | 7 | type Snapshot = { 8 | type: "snapshot"; 9 | value: unknown; 10 | }; 11 | 12 | type Change = { 13 | type: "change"; 14 | atomicChange: IAtomicChange; 15 | }; 16 | 17 | export type TrackerActions = [Snapshot, ...Change[]] | Change[]; 18 | 19 | export function replay( 20 | actions: TrackerActions, 21 | initialValue: T, 22 | ): T { 23 | if (actions.length === 0) { 24 | return initialValue; 25 | } 26 | 27 | let data = 28 | actions[0].type === "snapshot" ? (actions[0].value as T) : initialValue; 29 | assertChanges(actions); 30 | 31 | const atomicChanges = actions.map((it) => it.atomicChange); 32 | const changeSet = unatomizeChangeset(atomicChanges); 33 | data = applyChangeset(data, changeSet); 34 | 35 | return data; 36 | } 37 | 38 | function assertChanges(actions: TrackerActions): asserts actions is Change[] { 39 | if (actions.length === 0) { 40 | throw new Error("No changes to assert"); 41 | } 42 | 43 | if (actions[0].type === "snapshot") { 44 | actions.shift(); 45 | } 46 | 47 | actions.forEach((it, i) => { 48 | if (it.type !== "change") { 49 | throw new Error(`Expected changes, but got snapshot at index ${i}`); 50 | } 51 | }); 52 | } 53 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | export function unreachable(): never { 2 | throw new Error("unreachable"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/decorator.test.ts: -------------------------------------------------------------------------------- 1 | import { diffable } from "../src/index.js"; 2 | import { describe, expect } from "vitest"; 3 | import { durableIt, snapshots } from "./helper.js"; 4 | import { DurableObject } from "cloudflare:workers"; 5 | import { env } from "cloudflare:test"; 6 | 7 | describe("state tracking with decorators", () => { 8 | durableIt("should track with no args", (objectState) => { 9 | class TestObject extends DurableObject { 10 | @diffable 11 | state = { count: 0 }; 12 | } 13 | 14 | const obj = new TestObject(objectState, env); 15 | for (let i = 0; i < 20; i++) { 16 | obj.state.count++; 17 | } 18 | 19 | const snapshowRows = snapshots(objectState.storage.sql); 20 | expect(snapshowRows).toMatchInlineSnapshot(` 21 | [ 22 | { 23 | "changes_id": 10, 24 | "id": 1, 25 | "state": "state", 26 | "value": { 27 | "count": 10, 28 | }, 29 | }, 30 | { 31 | "changes_id": 20, 32 | "id": 2, 33 | "state": "state", 34 | "value": { 35 | "count": 20, 36 | }, 37 | }, 38 | ] 39 | `); 40 | }); 41 | 42 | durableIt("should track with empty args", (objectState) => { 43 | class TestObject extends DurableObject { 44 | @diffable() 45 | state = { count: 0 }; 46 | } 47 | 48 | const obj = new TestObject(objectState, env); 49 | for (let i = 0; i < 20; i++) { 50 | obj.state.count++; 51 | } 52 | 53 | const snapshowRows = snapshots(objectState.storage.sql); 54 | expect(snapshowRows).toMatchInlineSnapshot(` 55 | [ 56 | { 57 | "changes_id": 10, 58 | "id": 1, 59 | "state": "state", 60 | "value": { 61 | "count": 10, 62 | }, 63 | }, 64 | { 65 | "changes_id": 20, 66 | "id": 2, 67 | "state": "state", 68 | "value": { 69 | "count": 20, 70 | }, 71 | }, 72 | ] 73 | `); 74 | }); 75 | 76 | durableIt("should track with named args", (objectState) => { 77 | class TestObject extends DurableObject { 78 | @diffable("foo") 79 | state = { count: 0 }; 80 | } 81 | 82 | const obj = new TestObject(objectState, env); 83 | for (let i = 0; i < 20; i++) { 84 | obj.state.count++; 85 | } 86 | 87 | const snapshowRows = snapshots(objectState.storage.sql); 88 | expect(snapshowRows).toMatchInlineSnapshot(` 89 | [ 90 | { 91 | "changes_id": 10, 92 | "id": 1, 93 | "state": "foo", 94 | "value": { 95 | "count": 10, 96 | }, 97 | }, 98 | { 99 | "changes_id": 20, 100 | "id": 2, 101 | "state": "foo", 102 | "value": { 103 | "count": 20, 104 | }, 105 | }, 106 | ] 107 | `); 108 | }); 109 | 110 | durableIt("should track with options", (objectState) => { 111 | class TestObject extends DurableObject { 112 | @diffable({ name: "foo", snapshotPolicy: "every-change" }) 113 | state = { count: 0 }; 114 | } 115 | 116 | const obj = new TestObject(objectState, env); 117 | obj.state.count++; 118 | obj.state.count++; 119 | 120 | const snapshowRows = snapshots(objectState.storage.sql); 121 | expect(snapshowRows).toMatchInlineSnapshot(` 122 | [ 123 | { 124 | "changes_id": 1, 125 | "id": 1, 126 | "state": "foo", 127 | "value": { 128 | "count": 1, 129 | }, 130 | }, 131 | { 132 | "changes_id": 2, 133 | "id": 2, 134 | "state": "foo", 135 | "value": { 136 | "count": 2, 137 | }, 138 | }, 139 | ] 140 | `); 141 | }); 142 | }); 143 | -------------------------------------------------------------------------------- /tests/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "cloudflare:test" { 2 | interface ProvidedEnv { 3 | test: DurableObjectNamespace; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/helper.ts: -------------------------------------------------------------------------------- 1 | import { env, runInDurableObject } from "cloudflare:test"; 2 | import { it } from "vitest"; 3 | 4 | export async function runInTestDurableObject( 5 | fn: (objectState: DurableObjectState) => void, 6 | ) { 7 | const id = env.test.idFromName("test"); 8 | const stub = env.test.get(id); 9 | await runInDurableObject(stub, async (_, objectState) => { 10 | fn(objectState); 11 | }); 12 | } 13 | 14 | export function durableIt( 15 | name: string, 16 | fn: (objectState: DurableObjectState) => void, 17 | ) { 18 | it(name, async () => { 19 | await runInTestDurableObject(fn); 20 | }); 21 | } 22 | 23 | type SnapshotRow = { 24 | id: number; 25 | state: string; 26 | value: string; 27 | changes_id: number; 28 | created_at?: string; 29 | }; 30 | 31 | export function snapshots(sql: SqlStorage) { 32 | return sql 33 | .exec("SELECT * FROM snapshots") 34 | .toArray() 35 | .map((row) => { 36 | // biome-ignore lint/performance/noDelete: 37 | delete row.created_at; 38 | return { 39 | ...row, 40 | value: JSON.parse(row.value), 41 | }; 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /tests/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect } from "vitest"; 2 | import { durableIt, snapshots } from "./helper.js"; 3 | import * as diffable from "../src/index.js"; 4 | 5 | describe("state tracking", () => { 6 | durableIt("should be able to track changes in root object", (objectState) => { 7 | const state = diffable.state(objectState, "test", { a: 1, b: 2 }); 8 | state.a = 3; 9 | expect(state).toEqual({ a: 3, b: 2 }); 10 | 11 | const newCopyOfState = diffable.state(objectState, "test", { a: 1, b: 2 }); 12 | expect(newCopyOfState).toEqual({ a: 3, b: 2 }); 13 | }); 14 | 15 | durableIt("should never snapshot", (objectState) => { 16 | const state = diffable.state( 17 | objectState, 18 | "test", 19 | { count: 0 }, 20 | { 21 | snapshotPolicy: "never", 22 | }, 23 | ); 24 | 25 | for (let i = 0; i < 500; i++) { 26 | state.count++; 27 | } 28 | 29 | const snapshotRows = snapshots(objectState.storage.sql); 30 | expect(snapshotRows).toEqual([]); 31 | }); 32 | 33 | durableIt( 34 | "should automatically snapshot after every change", 35 | (objectState) => { 36 | const state = diffable.state( 37 | objectState, 38 | "test", 39 | { count: 0 }, 40 | { 41 | snapshotPolicy: "every-change", 42 | }, 43 | ); 44 | 45 | state.count++; 46 | state.count++; 47 | state.count++; 48 | 49 | const snapshotRows = snapshots(objectState.storage.sql); 50 | expect(snapshotRows).toMatchInlineSnapshot(` 51 | [ 52 | { 53 | "changes_id": 1, 54 | "id": 1, 55 | "state": "test", 56 | "value": { 57 | "count": 1, 58 | }, 59 | }, 60 | { 61 | "changes_id": 2, 62 | "id": 2, 63 | "state": "test", 64 | "value": { 65 | "count": 2, 66 | }, 67 | }, 68 | { 69 | "changes_id": 3, 70 | "id": 3, 71 | "state": "test", 72 | "value": { 73 | "count": 3, 74 | }, 75 | }, 76 | ] 77 | `); 78 | }, 79 | ); 80 | 81 | durableIt("should automatically snapshot after 2 changes", (objectState) => { 82 | const state = diffable.state( 83 | objectState, 84 | "test", 85 | { count: 0 }, 86 | { 87 | snapshotPolicy: { changes: 2 }, 88 | }, 89 | ); 90 | 91 | for (let i = 0; i < 5; i++) { 92 | state.count++; 93 | } 94 | 95 | const snapshotRows = snapshots(objectState.storage.sql); 96 | expect(snapshotRows).toMatchInlineSnapshot(` 97 | [ 98 | { 99 | "changes_id": 2, 100 | "id": 1, 101 | "state": "test", 102 | "value": { 103 | "count": 2, 104 | }, 105 | }, 106 | { 107 | "changes_id": 4, 108 | "id": 2, 109 | "state": "test", 110 | "value": { 111 | "count": 4, 112 | }, 113 | }, 114 | ] 115 | `); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /tests/observable.test.ts: -------------------------------------------------------------------------------- 1 | import { vitest, describe, expect, it } from "vitest"; 2 | import { recursivelyObservable } from "../src/observable.js"; 3 | 4 | describe("recursively observable", () => { 5 | it("should be able to observe changes in root object", () => { 6 | const data = { a: 1, b: 2 }; 7 | const onUpdate = vitest.fn(); 8 | const observable = recursivelyObservable(data, { onUpdate }); 9 | observable.a = 3; 10 | 11 | expect(onUpdate).toHaveBeenCalledWith( 12 | [ 13 | { 14 | key: "a", 15 | value: 3, 16 | oldValue: 1, 17 | valueType: "Number", 18 | type: "UPDATE", 19 | path: "$.a", 20 | }, 21 | ], 22 | { a: 3, b: 2 }, 23 | ); 24 | }); 25 | 26 | it("should be able to observe changes in nested object", () => { 27 | const data = { a: { b: 1 } }; 28 | const onUpdate = vitest.fn(); 29 | const observable = recursivelyObservable(data, { onUpdate }); 30 | observable.a.b = 2; 31 | 32 | expect(onUpdate).toHaveBeenCalledWith( 33 | [ 34 | { 35 | key: "b", 36 | path: "$.a.b", 37 | value: 2, 38 | oldValue: 1, 39 | valueType: "Number", 40 | type: "UPDATE", 41 | }, 42 | ], 43 | { a: { b: 2 } }, 44 | ); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /tests/sqlite.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect } from "vitest"; 2 | import { SqliteState } from "../src/sqlite.js"; 3 | import { type IAtomicChange, Operation } from "json-diff-ts"; 4 | import { durableIt } from "./helper.js"; 5 | 6 | const saveChange = (sql: SqlStorage, change: IAtomicChange) => 7 | sql.exec( 8 | `INSERT INTO changes (state, key, value, oldValue, valueType, type, path) VALUES ( 9 | ?, ?, ?, ?, ?, ?, ?)`, 10 | "test", 11 | change.key, 12 | change.value ? JSON.stringify(change.value) : null, 13 | change.oldValue ? JSON.stringify(change.oldValue) : null, 14 | change.valueType, 15 | change.type, 16 | change.path, 17 | ); 18 | 19 | describe("sqlite state", () => { 20 | durableIt("doesn't throw", (objectState) => { 21 | void new SqliteState("test", objectState.storage); 22 | }); 23 | 24 | durableIt("can resume unnested objects", (objectState) => { 25 | const { sql } = objectState.storage; 26 | const state = new SqliteState<{ a: number }>("test", objectState.storage); 27 | 28 | saveChange(sql, { 29 | key: "a", 30 | value: 3, 31 | oldValue: 1, 32 | valueType: "Number", 33 | type: Operation.UPDATE, 34 | path: "$.a", 35 | }); 36 | 37 | const data = state.resume({ a: 1 }); 38 | expect(data).toEqual({ a: 3 }); 39 | }); 40 | 41 | durableIt("can resume nested objects", (objectState) => { 42 | const { sql } = objectState.storage; 43 | const state = new SqliteState<{ a: { b: number } }>( 44 | "test", 45 | objectState.storage, 46 | ); 47 | 48 | saveChange(sql, { 49 | key: "b", 50 | path: "$.a.b", 51 | value: 2, 52 | oldValue: 1, 53 | valueType: "Number", 54 | type: Operation.UPDATE, 55 | }); 56 | 57 | const data = state.resume({ a: { b: 1 } }); 58 | expect(data).toEqual({ a: { b: 2 } }); 59 | }); 60 | 61 | durableIt("can resume with snapshot", (objectState) => { 62 | const { sql } = objectState.storage; 63 | const state = new SqliteState<{ a: number }>("test", objectState.storage); 64 | 65 | saveChange(sql, { 66 | key: "a", 67 | value: 3, 68 | oldValue: 1, 69 | valueType: "Number", 70 | type: Operation.UPDATE, 71 | path: "$.a", 72 | }); 73 | 74 | sql.exec( 75 | `INSERT INTO snapshots (state, value, changes_id) 76 | VALUES ('test', ?, (SELECT MAX(id) FROM changes WHERE state = 'test'))`, 77 | JSON.stringify({ a: 3 }), 78 | ); 79 | 80 | const data = state.resume({ a: 1 }); 81 | expect(data).toEqual({ a: 3 }); 82 | }); 83 | 84 | durableIt("can append changes", (objectState) => { 85 | const { sql } = objectState.storage; 86 | const state = new SqliteState<{ a: number }>("test", objectState.storage); 87 | 88 | state.appendChanges([ 89 | { 90 | key: "a", 91 | value: 3, 92 | oldValue: 1, 93 | valueType: "Number", 94 | type: Operation.UPDATE, 95 | path: "$.a", 96 | }, 97 | { 98 | type: Operation.ADD, 99 | key: "b", 100 | value: 2, 101 | valueType: "Number", 102 | path: "$.b", 103 | }, 104 | ]); 105 | 106 | const changes = sql.exec("SELECT * FROM changes").toArray(); 107 | expect(changes).toEqual([ 108 | { 109 | id: 1, 110 | key: "a", 111 | path: "$.a", 112 | value: "3", 113 | oldValue: "1", 114 | valueType: "Number", 115 | type: Operation.UPDATE, 116 | state: "test", 117 | }, 118 | { 119 | id: 2, 120 | key: "b", 121 | oldValue: null, 122 | path: "$.b", 123 | type: Operation.ADD, 124 | value: "2", 125 | valueType: "Number", 126 | state: "test", 127 | }, 128 | ]); 129 | }); 130 | 131 | durableIt("can snapshot", (objectState) => { 132 | const { sql } = objectState.storage; 133 | const state = new SqliteState<{ a: number }>("test", objectState.storage); 134 | 135 | saveChange(sql, { 136 | key: "a", 137 | value: 3, 138 | oldValue: 1, 139 | valueType: "Number", 140 | type: Operation.UPDATE, 141 | path: "$.a", 142 | }); 143 | 144 | state.snapshot({ a: 3 }); 145 | 146 | const { value } = sql 147 | .exec<{ value: string }>("SELECT * FROM snapshots") 148 | .one(); 149 | expect(value).toEqual('{"a":3}'); 150 | }); 151 | }); 152 | -------------------------------------------------------------------------------- /tests/worker.ts: -------------------------------------------------------------------------------- 1 | import { DurableObject, WorkerEntrypoint } from "cloudflare:workers"; 2 | 3 | export class TestDurableObject extends DurableObject {} 4 | 5 | export default class Main extends WorkerEntrypoint {} 6 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*.ts"], 4 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "NodeNext" /* Specify what module code is generated. */, 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | "types": [ 36 | "@cloudflare/workers-types", 37 | "@cloudflare/vitest-pool-workers" 38 | ] /* Specify type package names to be included without being referenced in a source file. */, 39 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 40 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 41 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 42 | // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ 43 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 44 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 45 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 46 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ 47 | // "resolveJsonModule": true, /* Enable importing .json files. */ 48 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 49 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 50 | 51 | /* JavaScript Support */ 52 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 53 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 54 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 55 | 56 | /* Emit */ 57 | "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, 58 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 59 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 60 | // "sourceMap": true /* Create source map files for emitted JavaScript files. */, 61 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 62 | // "noEmit": true, /* Disable emitting files from a compilation. */ 63 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 64 | "outDir": "./dist" /* Specify an output folder for all emitted files. */, 65 | // "removeComments": true, /* Disable emitting comments. */ 66 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 67 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 68 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 69 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 70 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 71 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 72 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 73 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 74 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 75 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 76 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 77 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 78 | 79 | /* Interop Constraints */ 80 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 81 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 82 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 83 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 84 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 85 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 86 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 87 | 88 | /* Type Checking */ 89 | "strict": true /* Enable all strict type-checking options. */, 90 | "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, 91 | "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, 92 | "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, 93 | "strictBindCallApply": true /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */, 94 | "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, 95 | "strictBuiltinIteratorReturn": true /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */, 96 | "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, 97 | "useUnknownInCatchVariables": true /* Default catch clause variables as 'unknown' instead of 'any'. */, 98 | "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, 99 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 100 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 101 | "exactOptionalPropertyTypes": true /* Interpret optional property types as written, rather than adding 'undefined'. */, 102 | "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, 103 | "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, 104 | "noUncheckedIndexedAccess": true /* Add 'undefined' to a type when accessed using an index. */, 105 | "noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */, 106 | "noPropertyAccessFromIndexSignature": true /* Enforces using indexed accessors for keys declared using an indexed type. */, 107 | "allowUnusedLabels": true /* Disable error reporting for unused labels. */, 108 | "allowUnreachableCode": true /* Disable error reporting for unreachable code. */, 109 | 110 | /* Completeness */ 111 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 112 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; 2 | 3 | export default defineWorkersConfig({ 4 | test: { 5 | poolOptions: { 6 | workers: { 7 | main: "./tests/worker.ts", 8 | miniflare: { 9 | compatibilityDate: "2024-12-18", 10 | compatibilityFlags: ["nodejs_compat", "nodejs_compat_v2"], 11 | durableObjects: { 12 | test: { 13 | className: "TestDurableObject", 14 | useSQLite: true, 15 | }, 16 | }, 17 | }, 18 | }, 19 | }, 20 | }, 21 | }); 22 | --------------------------------------------------------------------------------