initialised trigger.dev for migrations
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -145,3 +145,5 @@ TAKEHOME.md
|
||||
AGENTS.md
|
||||
|
||||
server/.turbo
|
||||
|
||||
.trigger
|
||||
241
bun.lock
241
bun.lock
@@ -8,6 +8,7 @@
|
||||
"@aws-sdk/client-sqs": "^3.985.0",
|
||||
"@better-auth/core": "catalog:",
|
||||
"@better-auth/oauth-provider": "catalog:",
|
||||
"@trigger.dev/sdk": "4.4.5",
|
||||
"@wooorm/starry-night": "^3.8.0",
|
||||
"ag-charts-react": "^12.3.0",
|
||||
"better-auth": "catalog:",
|
||||
@@ -19,6 +20,7 @@
|
||||
"devDependencies": {
|
||||
"@better-auth/cli": "^1.4.21",
|
||||
"@biomejs/biome": "^2.2.7",
|
||||
"@trigger.dev/build": "4.4.5",
|
||||
"@types/node": "^24.9.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"dotenv": "^16.6.1",
|
||||
@@ -526,6 +528,7 @@
|
||||
"date-fns": "^3.6.0",
|
||||
"decimal.js": "^10.5.0",
|
||||
"input-otp": "^1.4.2",
|
||||
"json5": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.562.0",
|
||||
"motion": "^12.26.1",
|
||||
@@ -952,6 +955,8 @@
|
||||
|
||||
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.12.0", "", {}, "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA=="],
|
||||
|
||||
"@bugsnag/cuid": ["@bugsnag/cuid@3.2.2", "", {}, "sha512-7onuYLTMqMmHE9BBPG0YER4nFsU1rB+me1/YIeMusqcLbVbKKuG9u9+BDVDpje5e0llkkrVNOKYwmzM9DRIo7A=="],
|
||||
|
||||
"@canvas/image-data": ["@canvas/image-data@1.1.0", "", {}, "sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA=="],
|
||||
|
||||
"@cfworker/json-schema": ["@cfworker/json-schema@4.1.1", "", {}, "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og=="],
|
||||
@@ -994,6 +999,8 @@
|
||||
|
||||
"@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="],
|
||||
|
||||
"@electric-sql/client": ["@electric-sql/client@1.0.14", "", { "dependencies": { "@microsoft/fetch-event-source": "^2.0.1" }, "optionalDependencies": { "@rollup/rollup-darwin-arm64": "^4.18.1" } }, "sha512-LtPAfeMxXRiYS0hyDQ5hue2PjljUiK9stvzsVyVb4nwxWQxfOWTSF42bHTs/o5i3x1T4kAQ7mwHpxa4A+f8X7Q=="],
|
||||
|
||||
"@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="],
|
||||
@@ -1088,6 +1095,8 @@
|
||||
|
||||
"@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@0.2.6", "", { "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", "react": "^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-mtBFIi1UsYQo7rYonYFkjgYKGoL8T+fEH6NGUpvuqtY3ytMsAoDaPo5rk25KuMtKDipY4bGYM/CkmCHA1N3FUg=="],
|
||||
|
||||
"@google-cloud/precise-date": ["@google-cloud/precise-date@4.0.0", "", {}, "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA=="],
|
||||
|
||||
"@google/genai": ["@google/genai@1.50.1", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-YbkX7H9+1Pt8wOt7DDREy8XSoiL6fRDzZQRyaVBarFf8MR3zHGqVdvM4cLbDXqPhxqvegZShgfxb8kw9C7YhAQ=="],
|
||||
|
||||
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="],
|
||||
@@ -1238,6 +1247,8 @@
|
||||
|
||||
"@jsep-plugin/ternary": ["@jsep-plugin/ternary@1.1.4", "", { "peerDependencies": { "jsep": "^0.4.0||^1.0.0" } }, "sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg=="],
|
||||
|
||||
"@jsonhero/path": ["@jsonhero/path@1.0.21", "", {}, "sha512-gVUDj/92acpVoJwsVJ/RuWOaHyG4oFzn898WNGQItLCTQ+hOaVlEaImhwE1WqOTf+l3dGOUkbSiVKlb3q1hd1Q=="],
|
||||
|
||||
"@keyv/serialize": ["@keyv/serialize@1.1.1", "", {}, "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA=="],
|
||||
|
||||
"@kubiks/otel-drizzle": ["@kubiks/otel-drizzle@2.1.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "drizzle-orm": ">=0.28.0" } }, "sha512-9UHb0od3jwa6zTWMyEYPIZcUq5PDaziCmQLMLakSK2zeqy12SFZ3SAGWXJTgEr8valn/Wa+DKVs+Z3aqKQUpvg=="],
|
||||
@@ -1260,6 +1271,8 @@
|
||||
|
||||
"@mermaid-js/parser": ["@mermaid-js/parser@1.1.0", "", { "dependencies": { "langium": "^4.0.0" } }, "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw=="],
|
||||
|
||||
"@microsoft/fetch-event-source": ["@microsoft/fetch-event-source@2.0.1", "", {}, "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="],
|
||||
|
||||
"@mintlify/cli": ["@mintlify/cli@4.0.1134", "", { "dependencies": { "@inquirer/prompts": "7.9.0", "@mintlify/common": "1.0.865", "@mintlify/link-rot": "3.0.1043", "@mintlify/prebuild": "1.0.1008", "@mintlify/previewing": "4.0.1069", "@mintlify/validation": "0.1.676", "adm-zip": "0.5.16", "chalk": "5.2.0", "color": "4.2.3", "detect-port": "1.5.1", "front-matter": "4.0.2", "fs-extra": "11.2.0", "ink": "6.3.0", "inquirer": "12.3.0", "js-yaml": "4.1.0", "mdast-util-mdx-jsx": "3.2.0", "open": "^8.4.2", "openid-client": "^6.8.2", "posthog-node": "5.17.2", "react": "19.2.3", "semver": "7.7.2", "unist-util-visit": "5.0.0", "yargs": "17.7.1", "zod": "^4.3.6" }, "optionalDependencies": { "keytar": "^7.9.0" }, "bin": { "mint": "bin/index.js", "mintlify": "bin/index.js" } }, "sha512-BTDUtv15RiqyN9ci/4zPKKpYWdnSvR57WAAlWXxCBCk2nNMYMKBTSVCmmJ91CriYOyUrXrKXrAI1UMiWBrWvzQ=="],
|
||||
|
||||
"@mintlify/common": ["@mintlify/common@1.0.865", "", { "dependencies": { "@asyncapi/parser": "3.4.0", "@asyncapi/specs": "6.8.1", "@mintlify/mdx": "^3.0.4", "@mintlify/models": "0.0.296", "@mintlify/openapi-parser": "^0.0.8", "@mintlify/validation": "0.1.676", "@sindresorhus/slugify": "2.2.0", "@types/mdast": "4.0.4", "acorn": "8.11.2", "acorn-jsx": "5.3.2", "color-blend": "4.0.0", "estree-util-to-js": "2.0.0", "estree-walker": "3.0.3", "front-matter": "4.0.2", "hast-util-from-html": "2.0.3", "hast-util-to-html": "9.0.4", "hast-util-to-text": "4.0.2", "hex-rgb": "5.0.0", "ignore": "7.0.5", "js-yaml": "4.1.0", "lodash": "4.18.1", "mdast-util-from-markdown": "2.0.2", "mdast-util-gfm": "3.0.0", "mdast-util-mdx": "3.0.0", "mdast-util-mdx-jsx": "3.1.3", "micromark-extension-gfm": "3.0.0", "micromark-extension-mdx-jsx": "3.0.1", "micromark-extension-mdxjs": "3.0.0", "openapi-types": "12.1.3", "postcss": "8.5.6", "rehype-stringify": "10.0.1", "remark": "15.0.1", "remark-frontmatter": "5.0.0", "remark-gfm": "4.0.0", "remark-math": "6.0.0", "remark-mdx": "3.1.0", "remark-parse": "11.0.0", "remark-rehype": "11.1.1", "remark-stringify": "11.0.0", "sucrase": "^3.34.0", "tailwindcss": "^3.4.17", "unified": "11.0.5", "unist-builder": "4.0.0", "unist-util-map": "4.0.0", "unist-util-remove": "4.0.0", "unist-util-remove-position": "5.0.0", "unist-util-visit": "5.0.0", "unist-util-visit-parents": "6.0.1", "vfile": "6.0.3", "xss": "1.0.15" } }, "sha512-p+mDIOwdtSGhgiRvr3mVNBT/PeXB3x2klkmX10SmRdePoyKheDtCqwao67f+4Av2bOeCUX3nti8Ccz6XTW/4BQ=="],
|
||||
@@ -1390,6 +1403,8 @@
|
||||
|
||||
"@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-a9eeyHIipfdxzCfc2XPrE+/TI3wmrZUDFtG2RRXHSbZZULAny7SyybSvaDvS77a7iib5MPiAvluwVvbGTsHxsw=="],
|
||||
|
||||
"@opentelemetry/host-metrics": ["@opentelemetry/host-metrics@0.37.0", "", { "dependencies": { "systeminformation": "5.23.8" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-gf6nRFci0PTni9R1QQKjZ2uZE4Y6olLKhlwdM0qqLbbn3SBVKyP2jyBMiosBTHtRNLjY7s8hzQ44eLdK5wkGNQ=="],
|
||||
|
||||
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.202.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.202.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Uz3BxZWPgDwgHM2+vCKEQRh0R8WKrd/q6Tus1vThRClhlPO39Dyz7mDrOr6KuqGXAlBQ1e5Tnymzri4RMZNaWA=="],
|
||||
|
||||
"@opentelemetry/instrumentation-amqplib": ["@opentelemetry/instrumentation-amqplib@0.58.0", "", { "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/instrumentation": "^0.211.0", "@opentelemetry/semantic-conventions": "^1.33.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-fjpQtH18J6GxzUZ+cwNhWUpb71u+DzT7rFkg5pLssDGaEber91Y2WNGdpVpwGivfEluMlNMZumzjEqfg8DeKXQ=="],
|
||||
@@ -1606,8 +1621,12 @@
|
||||
|
||||
"@prisma/client": ["@prisma/client@5.22.0", "", { "peerDependencies": { "prisma": "*" }, "optionalPeers": ["prisma"] }, "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA=="],
|
||||
|
||||
"@prisma/config": ["@prisma/config@6.19.3", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.21.0", "empathic": "2.0.0" } }, "sha512-CBPT44BjlQxEt8kiMEauji2WHTDoVBOKl7UlewXmUgBPnr/oPRZC3psci5chJnYmH0ivEIog2OU9PGWoki3DLQ=="],
|
||||
|
||||
"@prisma/instrumentation": ["@prisma/instrumentation@7.2.0", "", { "dependencies": { "@opentelemetry/instrumentation": "^0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.8" } }, "sha512-Rh9Z4x5kEj1OdARd7U18AtVrnL6rmLSI0qYShaB4W7Wx5BKbgzndWF+QnuzMb7GLfVdlT5aYCXoPQVYuYtVu0g=="],
|
||||
|
||||
"@protobuf-ts/runtime": ["@protobuf-ts/runtime@2.11.1", "", {}, "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ=="],
|
||||
|
||||
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
||||
|
||||
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
||||
@@ -1850,6 +1869,8 @@
|
||||
|
||||
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
|
||||
|
||||
"@s2-dev/streamstore": ["@s2-dev/streamstore@0.22.5", "", { "dependencies": { "@protobuf-ts/runtime": "^2.11.1", "debug": "^4.4.3" } }, "sha512-GqdOKIbIoIxT+40fnKzHbrsHB6gBqKdECmFe7D3Ojk4FoN1Hu0LhFzZv6ZmVMjoHHU+55debS1xSWjZwQmbIyQ=="],
|
||||
|
||||
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
|
||||
|
||||
"@selderee/plugin-htmlparser2": ["@selderee/plugin-htmlparser2@0.11.0", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="],
|
||||
@@ -2162,6 +2183,12 @@
|
||||
|
||||
"@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
|
||||
|
||||
"@trigger.dev/build": ["@trigger.dev/build@4.4.5", "", { "dependencies": { "@prisma/config": "^6.10.0", "@trigger.dev/core": "4.4.5", "mlly": "^1.7.1", "pkg-types": "^1.1.3", "resolve": "^1.22.8", "tinyglobby": "^0.2.2", "tsconfck": "3.1.3" } }, "sha512-45l8cv59JERkDrC5tADkKVDJriZjPtCtkAHVWvCZXRJMlm93Ao8deTHdtOf++TqdsqdG9Tk5cxhupY1COq4muA=="],
|
||||
|
||||
"@trigger.dev/core": ["@trigger.dev/core@4.4.5", "", { "dependencies": { "@bugsnag/cuid": "^3.1.1", "@electric-sql/client": "1.0.14", "@google-cloud/precise-date": "^4.0.0", "@jsonhero/path": "^1.0.21", "@opentelemetry/api": "1.9.0", "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/exporter-logs-otlp-http": "0.203.0", "@opentelemetry/exporter-metrics-otlp-http": "0.203.0", "@opentelemetry/exporter-trace-otlp-http": "0.203.0", "@opentelemetry/host-metrics": "^0.37.0", "@opentelemetry/instrumentation": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "@opentelemetry/sdk-trace-node": "2.0.1", "@opentelemetry/semantic-conventions": "1.36.0", "@s2-dev/streamstore": "0.22.5", "dequal": "^2.0.3", "eventsource": "^3.0.5", "eventsource-parser": "^3.0.0", "execa": "^8.0.1", "humanize-duration": "^3.27.3", "jose": "^5.4.0", "nanoid": "3.3.8", "prom-client": "^15.1.0", "socket.io": "4.7.4", "socket.io-client": "4.7.5", "std-env": "^3.8.1", "tinyexec": "^0.3.2", "uncrypto": "^0.1.3", "zod": "3.25.76", "zod-error": "1.5.0", "zod-validation-error": "^1.5.0" } }, "sha512-VI4AjX5ivbm+E8RMdP2kjuo/ph8cTCQTNkZSx6UknnAxyu2mihqPbcYWl2tqZCGbbX/HIlzhEtM2NM3a01Juxg=="],
|
||||
|
||||
"@trigger.dev/sdk": ["@trigger.dev/sdk@4.4.5", "", { "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/semantic-conventions": "1.36.0", "@trigger.dev/core": "4.4.5", "chalk": "^5.2.0", "cronstrue": "^2.21.0", "debug": "^4.3.4", "evt": "^2.4.13", "slug": "^6.0.0", "ulid": "^2.3.0", "uncrypto": "^0.1.3", "ws": "^8.11.0" }, "peerDependencies": { "ai": "^4.2.0 || ^5.0.0 || ^6.0.0", "zod": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["ai"] }, "sha512-iXjEWQQy+Dc7WDdjOtGLTlHIcVdcg00GUYL/hTr5FwMlY/Aswvfe0Snfn+7XECtls2tgZTPJ+rnTP4mo77o5eg=="],
|
||||
|
||||
"@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="],
|
||||
|
||||
"@tsconfig/node10": ["@tsconfig/node10@1.0.12", "", {}, "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ=="],
|
||||
@@ -2210,6 +2237,8 @@
|
||||
|
||||
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
||||
|
||||
"@types/cookie": ["@types/cookie@0.4.1", "", {}, "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="],
|
||||
|
||||
"@types/cookiejar": ["@types/cookiejar@2.1.5", "", {}, "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q=="],
|
||||
|
||||
"@types/cors": ["@types/cors@2.8.19", "", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="],
|
||||
@@ -2874,6 +2903,8 @@
|
||||
|
||||
"ci-parallel-vars": ["ci-parallel-vars@1.0.1", "", {}, "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg=="],
|
||||
|
||||
"citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
|
||||
|
||||
"cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="],
|
||||
|
||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
||||
@@ -2992,6 +3023,8 @@
|
||||
|
||||
"cron-parser": ["cron-parser@4.9.0", "", { "dependencies": { "luxon": "^3.2.1" } }, "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q=="],
|
||||
|
||||
"cronstrue": ["cronstrue@2.61.0", "", { "bin": { "cronstrue": "bin/cli.js" } }, "sha512-ootN5bvXbIQI9rW94+QsXN5eROtXWwew6NkdGxIRpS/UFWRggL0G5Al7a9GTBFEsuvVhJ2K3CntIIVt7L2ILhA=="],
|
||||
|
||||
"cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="],
|
||||
|
||||
"cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="],
|
||||
@@ -3146,6 +3179,8 @@
|
||||
|
||||
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||
|
||||
"deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="],
|
||||
|
||||
"default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="],
|
||||
|
||||
"default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
|
||||
@@ -3262,6 +3297,8 @@
|
||||
|
||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||
|
||||
"effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="],
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.344", "", {}, "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg=="],
|
||||
@@ -3270,6 +3307,8 @@
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
|
||||
|
||||
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||
|
||||
"encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="],
|
||||
@@ -3278,7 +3317,7 @@
|
||||
|
||||
"engine.io": ["engine.io@6.6.7", "", { "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "@types/ws": "^8.5.12", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3" } }, "sha512-DgOngfDKM2EviOH3Mr9m7ks1q8roetLy/IMmYthAYzbpInMbYc/GS+fWFA3rl1gvwKVsQrVV61fo5emD1y3OJQ=="],
|
||||
|
||||
"engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="],
|
||||
"engine.io-client": ["engine.io-client@6.5.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.0.0" } }, "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ=="],
|
||||
|
||||
"engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="],
|
||||
|
||||
@@ -3436,6 +3475,8 @@
|
||||
|
||||
"eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="],
|
||||
|
||||
"evt": ["evt@2.5.9", "", { "dependencies": { "minimal-polyfills": "^2.2.3", "run-exclusive": "^2.2.19", "tsafe": "^1.8.5" } }, "sha512-GpjX476FSlttEGWHT8BdVMoI8wGXQGbEOtKcP4E+kggg+yJzXBZN2n4x7TS/zPBJ1DZqWI+rguZZApjjzQ0HpA=="],
|
||||
|
||||
"execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="],
|
||||
|
||||
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||
@@ -3454,6 +3495,8 @@
|
||||
|
||||
"extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
|
||||
|
||||
"fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
|
||||
|
||||
"fast-copy": ["fast-copy@4.0.3", "", {}, "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
@@ -3778,6 +3821,8 @@
|
||||
|
||||
"human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
|
||||
|
||||
"humanize-duration": ["humanize-duration@3.33.2", "", {}, "sha512-K7Ny/ULO1hDm2nnhvAY+SJV1skxFb61fd073SG1IWJl+D44ULrruCuTyjHKjBVVcSuTlnY99DKtgEG39CM5QOQ=="],
|
||||
|
||||
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||
|
||||
"husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="],
|
||||
@@ -4396,6 +4441,8 @@
|
||||
|
||||
"min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
|
||||
|
||||
"minimal-polyfills": ["minimal-polyfills@2.2.3", "", {}, "sha512-oxdmJ9cL+xV72h0xYxp4tP2d5/fTBpP45H8DIOn9pASuF8a3IYTf+25fMGDYGiWW+MFsuog6KD6nfmhZJQ+uUw=="],
|
||||
|
||||
"minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
@@ -4500,6 +4547,8 @@
|
||||
|
||||
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
|
||||
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.38", "", {}, "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw=="],
|
||||
@@ -4524,6 +4573,8 @@
|
||||
|
||||
"nuqs": ["nuqs@2.8.9", "", { "dependencies": { "@standard-schema/spec": "1.0.0" }, "peerDependencies": { "@remix-run/react": ">=2", "@tanstack/react-router": "^1", "next": ">=14.2.0", "react": ">=18.2.0 || ^19.0.0-0", "react-router": "^5 || ^6 || ^7", "react-router-dom": "^5 || ^6 || ^7" }, "optionalPeers": ["@remix-run/react", "@tanstack/react-router", "next", "react-router", "react-router-dom"] }, "sha512-8ou6AEwsxMWSYo2qkfZtYFVzngwbKmg4c00HVxC1fF6CEJv3Fwm6eoZmfVPALB+vw8Udo7KL5uy96PFcYe1BIQ=="],
|
||||
|
||||
"nypm": ["nypm@0.6.6", "", { "dependencies": { "citty": "^0.2.2", "pathe": "^2.0.3", "tinyexec": "^1.1.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q=="],
|
||||
|
||||
"oauth4webapi": ["oauth4webapi@3.8.5", "", {}, "sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg=="],
|
||||
|
||||
"obj-props": ["obj-props@1.4.0", "", {}, "sha512-p7p/7ltzPDiBs6DqxOrIbtRdwxxVRBj5ROukeNb9RgA+fawhrz5n2hpNz8DDmYR//tviJSj7nUnlppGmONkjiQ=="],
|
||||
@@ -4556,7 +4607,7 @@
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
|
||||
|
||||
"oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="],
|
||||
|
||||
@@ -4712,7 +4763,7 @@
|
||||
|
||||
"pkg-dir": ["pkg-dir@5.0.0", "", { "dependencies": { "find-up": "^5.0.0" } }, "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA=="],
|
||||
|
||||
"pkg-types": ["pkg-types@2.3.1", "", { "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg=="],
|
||||
"pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"playwright": ["playwright@1.59.1", "", { "dependencies": { "playwright-core": "1.59.1" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw=="],
|
||||
|
||||
@@ -4820,6 +4871,8 @@
|
||||
|
||||
"puppeteer-core": ["puppeteer-core@24.42.0", "", { "dependencies": { "@puppeteer/browsers": "2.13.0", "chromium-bidi": "14.0.0", "debug": "^4.4.3", "devtools-protocol": "0.0.1595872", "typed-query-selector": "^2.12.1", "webdriver-bidi-protocol": "0.4.1", "ws": "^8.19.0" } }, "sha512-T4zXokk/izH01fYPhyyev1A4piWiOKrYq7CUFpdoYQxmOnXoV6YjUabmfIjCYkNspSoAXIxRid3Tw+Vg0fthYg=="],
|
||||
|
||||
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
||||
|
||||
"qs": ["qs@6.15.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg=="],
|
||||
|
||||
"query-selector-shadow-dom": ["query-selector-shadow-dom@1.0.1", "", {}, "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw=="],
|
||||
@@ -4994,7 +5047,7 @@
|
||||
|
||||
"resend": ["resend@4.8.0", "", { "dependencies": { "@react-email/render": "1.1.2" } }, "sha512-R8eBOFQDO6dzRTDmaMEdpqrkmgSjPpVXt4nGfWsZdYOet0kqra0xgbvTES6HmCriZEXbmGk3e0DiGIaLFTFSHA=="],
|
||||
|
||||
"resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="],
|
||||
"resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
|
||||
|
||||
@@ -5044,6 +5097,8 @@
|
||||
|
||||
"run-async": ["run-async@4.0.6", "", {}, "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ=="],
|
||||
|
||||
"run-exclusive": ["run-exclusive@2.2.19", "", { "dependencies": { "minimal-polyfills": "^2.2.3" } }, "sha512-K3mdoAi7tjJ/qT7Flj90L7QyPozwUaAG+CVhkdDje4HLKXUYC3N/Jzkau3flHVDLQVhiHBtcimVodMjN9egYbA=="],
|
||||
|
||||
"run-jxa": ["run-jxa@3.0.0", "", { "dependencies": { "execa": "^5.1.1", "macos-version": "^6.0.0", "subsume": "^4.0.0", "type-fest": "^2.0.0" } }, "sha512-4f2CrY7H+sXkKXJn/cE6qRA3z+NMVO7zvlZ/nUV0e62yWftpiLAfw5eV9ZdomzWd2TXWwEIiGjAT57+lWIzzvA=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
@@ -5142,6 +5197,8 @@
|
||||
|
||||
"slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="],
|
||||
|
||||
"slug": ["slug@6.1.0", "", {}, "sha512-x6vLHCMasg4DR2LPiyFGI0gJJhywY6DTiGhCrOMzb3SOk/0JVLIaL4UhyFSHu04SD3uAavrKY/K3zZ3i6iRcgA=="],
|
||||
|
||||
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
|
||||
|
||||
"smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="],
|
||||
@@ -5150,7 +5207,7 @@
|
||||
|
||||
"socket.io-adapter": ["socket.io-adapter@2.5.6", "", { "dependencies": { "debug": "~4.4.1", "ws": "~8.18.3" } }, "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ=="],
|
||||
|
||||
"socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="],
|
||||
"socket.io-client": ["socket.io-client@4.7.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", "engine.io-client": "~6.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ=="],
|
||||
|
||||
"socket.io-parser": ["socket.io-parser@4.2.6", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg=="],
|
||||
|
||||
@@ -5202,6 +5259,8 @@
|
||||
|
||||
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||
|
||||
"std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
|
||||
|
||||
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
|
||||
|
||||
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
||||
@@ -5292,6 +5351,8 @@
|
||||
|
||||
"system-architecture": ["system-architecture@0.1.0", "", {}, "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA=="],
|
||||
|
||||
"systeminformation": ["systeminformation@5.23.8", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-Osd24mNKe6jr/YoXLLK3k8TMdzaxDffhpCxgkfgBHcapykIkd50HXThM3TCEuHO2pPuCsSx2ms/SunqhU5MmsQ=="],
|
||||
|
||||
"tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="],
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
|
||||
@@ -5436,9 +5497,11 @@
|
||||
|
||||
"ts-to-zod": ["ts-to-zod@5.1.0", "", { "dependencies": { "@clack/prompts": "1.0.0-alpha.4", "@oclif/core": "^4.5.4", "@typescript/vfs": "^1.5.0", "chokidar": "^4.0.3", "listr2": "^9.0.4", "slash": "^5.1.0", "text-case": "^1.2.4", "tslib": "^2.3.1", "tsutils": "^3.21.0", "typescript": "^5.2.2", "zod": "^4.1.5" }, "bin": { "ts-to-zod": "bin/run" } }, "sha512-giqqlvRHunlJqG9tBL/KAO3wWIVZGF//mZiWLKm/fdQnKnz4EN2mtiK5cugN9slytBkdMEXQIaLvMzIScbhhFw=="],
|
||||
|
||||
"tsafe": ["tsafe@1.8.12", "", {}, "sha512-nFRqW0ttu/2o6XTXsHiVZWJBCOaxhVqZLg7dgs3coZNsCMPXPfwz+zPHAQA+70fNnVJLAPg1EgGIqK9Q84tvAw=="],
|
||||
|
||||
"tsc-alias": ["tsc-alias@1.8.16", "", { "dependencies": { "chokidar": "^3.5.3", "commander": "^9.0.0", "get-tsconfig": "^4.10.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", "plimit-lit": "^1.2.6" }, "bin": { "tsc-alias": "dist/bin/index.js" } }, "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g=="],
|
||||
|
||||
"tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="],
|
||||
"tsconfck": ["tsconfck@3.1.3", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ=="],
|
||||
|
||||
"tsconfig-paths": ["tsconfig-paths@4.2.0", "", { "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg=="],
|
||||
|
||||
@@ -5486,6 +5549,8 @@
|
||||
|
||||
"uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
|
||||
|
||||
"ulid": ["ulid@2.4.0", "", { "bin": { "ulid": "bin/cli.js" } }, "sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg=="],
|
||||
|
||||
"unbash": ["unbash@3.0.0", "", {}, "sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA=="],
|
||||
|
||||
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
|
||||
@@ -5684,7 +5749,7 @@
|
||||
|
||||
"xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
|
||||
|
||||
"xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="],
|
||||
"xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.0.0", "", {}, "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="],
|
||||
|
||||
"xo": ["xo@0.53.1", "", { "dependencies": { "@eslint/eslintrc": "^1.3.3", "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "arrify": "^3.0.0", "cosmiconfig": "^7.1.0", "define-lazy-prop": "^3.0.0", "eslint": "^8.27.0", "eslint-config-prettier": "^8.5.0", "eslint-config-xo": "^0.43.1", "eslint-config-xo-typescript": "^0.55.0", "eslint-formatter-pretty": "^4.1.0", "eslint-import-resolver-webpack": "^0.13.2", "eslint-plugin-ava": "^13.2.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.5.1", "eslint-plugin-no-use-extend-native": "^0.5.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-unicorn": "^44.0.2", "esm-utils": "^4.1.0", "find-cache-dir": "^4.0.0", "find-up": "^6.3.0", "get-stdin": "^9.0.0", "globby": "^13.1.2", "imurmurhash": "^0.1.4", "json-stable-stringify-without-jsonify": "^1.0.1", "json5": "^2.2.1", "lodash-es": "^4.17.21", "meow": "^11.0.0", "micromatch": "^4.0.5", "open-editor": "^4.0.0", "prettier": "^2.7.1", "semver": "^7.3.8", "slash": "^5.0.0", "to-absolute-glob": "^2.0.2", "typescript": "^4.9.3" }, "bin": { "xo": "cli.js" } }, "sha512-/2R8SPehv1UhiIqJ9uSvrAjslcoygICNsUlEb/Zf2V6rMtr7YCoggc6hlt6b/kbncpR989Roqt6AvEO779dFxw=="],
|
||||
|
||||
@@ -5724,11 +5789,13 @@
|
||||
|
||||
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"zod-error": ["zod-error@1.5.0", "", { "dependencies": { "zod": "^3.20.2" } }, "sha512-zzopKZ/skI9iXpqCEPj+iLCKl9b88E43ehcU+sbRoHuwGd9F1IDVGQ70TyO6kmfiRL1g4IXkjsXK+g1gLYl4WQ=="],
|
||||
|
||||
"zod-openapi": ["zod-openapi@5.4.6", "", { "peerDependencies": { "zod": "^3.25.74 || ^4.0.0" } }, "sha512-P2jsOOBAq/6hCwUsMCjUATZ8szkMsV5VAwZENfyxp2Hc/XPJQpVwAgevWZc65xZauCwWB9LAn7zYeiCJFAEL+A=="],
|
||||
|
||||
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||
|
||||
"zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
|
||||
"zod-validation-error": ["zod-validation-error@1.5.0", "", { "peerDependencies": { "zod": "^3.18.0" } }, "sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw=="],
|
||||
|
||||
"zustand": ["zustand@5.0.12", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g=="],
|
||||
|
||||
@@ -5748,6 +5815,8 @@
|
||||
|
||||
"@artilleryio/int-core/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
|
||||
|
||||
"@artilleryio/int-core/socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="],
|
||||
|
||||
"@artilleryio/int-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
||||
|
||||
"@asyncapi/parser/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||
@@ -6428,6 +6497,8 @@
|
||||
|
||||
"@posthog/ai/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"@prisma/config/c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="],
|
||||
|
||||
"@prisma/instrumentation/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.207.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "import-in-the-middle": "^2.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
@@ -6534,6 +6605,40 @@
|
||||
|
||||
"@tailwindcss/vite/tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.203.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/core": ["@opentelemetry/core@2.0.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/sdk-logs": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-s0hys1ljqlMTbXx2XiplmMJg9wG570Z5lH7wMvrZX6lcODI56sG4HL03jklF63tBeyNwK2RV1/ntXGo3HgG4Qw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-metrics": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-HFSW10y8lY6BTZecGNpV3GpoSy7eaO0Z6GATwZasnT4bEsILp8UJXNG5OmEsz4SdwCSYvyCbTJdNbZP3/8LGCQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-exporter-base": "0.203.0", "@opentelemetry/otlp-transformer": "0.203.0", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ZDiaswNYo0yq/cy1bBLJFe691izEJ6IgNmkjm4C6kE9ub/OMQqDXORx2D2j8fzTBTxONyzusbaZlqtfmyqURPw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-vM2+rPq0Vi3nYA5akQD2f3QwossDnTDLvKbea6u/A2NZ3XDkPxMfo/PNrDoXhDUD/0pPo2CdH5ce/thn9K0kLw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.36.0", "", {}, "sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ=="],
|
||||
|
||||
"@trigger.dev/core/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
|
||||
|
||||
"@trigger.dev/core/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
|
||||
|
||||
"@trigger.dev/core/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
|
||||
|
||||
"@trigger.dev/core/socket.io": ["socket.io@4.7.4", "", { "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", "engine.io": "~6.5.2", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw=="],
|
||||
|
||||
"@trigger.dev/sdk/@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
|
||||
|
||||
"@trigger.dev/sdk/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.36.0", "", {}, "sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ=="],
|
||||
|
||||
"@ts-morph/common/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"@types/body-parser/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
||||
@@ -6712,6 +6817,8 @@
|
||||
|
||||
"c12/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
|
||||
|
||||
"c12/pkg-types": ["pkg-types@2.3.1", "", { "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg=="],
|
||||
|
||||
"cacheable-request/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
|
||||
|
||||
"cacheable-request/mimic-response": ["mimic-response@4.0.0", "", {}, "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="],
|
||||
@@ -6792,7 +6899,9 @@
|
||||
|
||||
"engine.io/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
"engine.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||
|
||||
"engine.io-client/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
|
||||
|
||||
"escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
@@ -6816,10 +6925,14 @@
|
||||
|
||||
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
|
||||
"eslint-import-resolver-node/resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="],
|
||||
|
||||
"eslint-import-resolver-webpack/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
|
||||
"eslint-import-resolver-webpack/enhanced-resolve": ["enhanced-resolve@0.9.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "memory-fs": "^0.2.0", "tapable": "^0.1.8" } }, "sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw=="],
|
||||
|
||||
"eslint-import-resolver-webpack/resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="],
|
||||
|
||||
"eslint-import-resolver-webpack/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="],
|
||||
|
||||
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
|
||||
@@ -6844,10 +6957,10 @@
|
||||
|
||||
"eslint-plugin-n/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
|
||||
|
||||
"eslint-plugin-n/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"eslint-plugin-react/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
|
||||
|
||||
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.6", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "node-exports-info": "^1.6.0", "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA=="],
|
||||
|
||||
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"eslint-plugin-unicorn/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
|
||||
@@ -6886,8 +6999,6 @@
|
||||
|
||||
"filing-cabinet/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
|
||||
|
||||
"filing-cabinet/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"find-cache-dir/pkg-dir": ["pkg-dir@7.0.0", "", { "dependencies": { "find-up": "^6.3.0" } }, "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA=="],
|
||||
@@ -6988,8 +7099,6 @@
|
||||
|
||||
"mixpanel/https-proxy-agent": ["https-proxy-agent@5.0.0", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA=="],
|
||||
|
||||
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"mocha/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"mocha/js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||
@@ -7034,7 +7143,9 @@
|
||||
|
||||
"nuqs/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||
|
||||
"onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
"nypm/citty": ["citty@0.2.2", "", {}, "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w=="],
|
||||
|
||||
"nypm/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
||||
|
||||
"open-editor/execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
@@ -7078,12 +7189,12 @@
|
||||
|
||||
"pkg-conf/find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="],
|
||||
|
||||
"pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
|
||||
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"postcss-import/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"postcss-load-config/lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||
|
||||
"postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||
@@ -7156,12 +7267,12 @@
|
||||
|
||||
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"require-in-the-middle/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"requirejs-config-file/stringify-object": ["stringify-object@3.3.0", "", { "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", "is-regexp": "^1.0.0" } }, "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="],
|
||||
|
||||
"resolve-import/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||
|
||||
"restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"rimraf/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
|
||||
|
||||
"router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
|
||||
@@ -7212,6 +7323,8 @@
|
||||
|
||||
"socket.io-adapter/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"socket.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||
|
||||
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="],
|
||||
@@ -7274,6 +7387,8 @@
|
||||
|
||||
"unplugin/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"vite-tsconfig-paths/tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="],
|
||||
|
||||
"webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
|
||||
|
||||
"whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
@@ -7406,6 +7521,8 @@
|
||||
|
||||
"@artilleryio/int-core/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||
|
||||
"@artilleryio/int-core/socket.io-client/engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="],
|
||||
|
||||
"@asyncapi/parser/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"@asyncapi/parser/js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
@@ -7596,6 +7713,8 @@
|
||||
|
||||
"@dotenvx/dotenvx/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"@dotenvx/dotenvx/execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"@dotenvx/dotenvx/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"@dotenvx/dotenvx/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
|
||||
@@ -7698,8 +7817,6 @@
|
||||
|
||||
"@mintlify/common/tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||
|
||||
"@mintlify/common/tailwindcss/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"@mintlify/common/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
|
||||
|
||||
"@mintlify/link-rot/unist-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
@@ -8060,6 +8177,14 @@
|
||||
|
||||
"@opentelemetry/sdk-trace-node/@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw=="],
|
||||
|
||||
"@prisma/config/c12/giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
|
||||
|
||||
"@prisma/config/c12/perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
|
||||
|
||||
"@prisma/config/c12/pkg-types": ["pkg-types@2.3.1", "", { "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", "pathe": "^2.0.3" } }, "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg=="],
|
||||
|
||||
"@prisma/config/c12/rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
|
||||
|
||||
"@prisma/instrumentation/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.207.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ=="],
|
||||
|
||||
"@prisma/instrumentation/@opentelemetry/instrumentation/import-in-the-middle": ["import-in-the-middle@2.0.6", "", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw=="],
|
||||
@@ -8112,6 +8237,40 @@
|
||||
|
||||
"@tailwindcss/postcss/@tailwindcss/oxide/@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.4", "", { "os": "win32", "cpu": "x64" }, "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/api-logs/@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.203.0", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/otlp-transformer": "0.203.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.203.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.203.0", "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1", "@opentelemetry/sdk-logs": "0.203.0", "@opentelemetry/sdk-metrics": "2.0.1", "@opentelemetry/sdk-trace-base": "2.0.1", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/resources/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||
|
||||
"@trigger.dev/core/@opentelemetry/sdk-trace-base/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
||||
|
||||
"@trigger.dev/core/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
|
||||
|
||||
"@trigger.dev/core/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
|
||||
|
||||
"@trigger.dev/core/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
|
||||
|
||||
"@trigger.dev/core/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"@trigger.dev/core/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io": ["engine.io@6.5.5", "", { "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1" } }, "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA=="],
|
||||
|
||||
"@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="],
|
||||
|
||||
"@types/body-parser/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
||||
@@ -8386,6 +8545,8 @@
|
||||
|
||||
"eslint-config-next/eslint-plugin-react-hooks/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||
|
||||
"eslint-config-next/eslint-plugin-react-hooks/zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
|
||||
|
||||
"eslint-formatter-pretty/ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
|
||||
|
||||
"eslint-formatter-pretty/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
@@ -8546,8 +8707,6 @@
|
||||
|
||||
"mixpanel/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||
|
||||
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"mocha/js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"msw/@inquirer/confirm/@inquirer/core": ["@inquirer/core@11.1.9", "", { "dependencies": { "@inquirer/ansi": "^2.0.5", "@inquirer/figures": "^2.0.5", "@inquirer/type": "^4.0.5", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-BDE4fG22uYh1bGSifcj7JSx119TVYNViMhMu85usp4Fswrzh6M0DV3yld64jA98uOAa2GSQ4Bg4bZRm2d2cwSg=="],
|
||||
@@ -8590,6 +8749,8 @@
|
||||
|
||||
"open-editor/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"open-editor/execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"open-editor/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"open-editor/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
|
||||
@@ -8696,8 +8857,6 @@
|
||||
|
||||
"read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="],
|
||||
|
||||
"read-pkg/normalize-package-data/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"read-pkg/normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="],
|
||||
|
||||
"requirejs-config-file/stringify-object/is-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="],
|
||||
@@ -8708,6 +8867,8 @@
|
||||
|
||||
"resolve-import/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
|
||||
"restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"rimraf/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"rimraf/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
@@ -8720,6 +8881,8 @@
|
||||
|
||||
"run-jxa/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"run-jxa/execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"run-jxa/execa/strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
@@ -8880,6 +9043,10 @@
|
||||
|
||||
"@artilleryio/int-core/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||
|
||||
"@artilleryio/int-core/socket.io-client/engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"@artilleryio/int-core/socket.io-client/engine.io-client/xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="],
|
||||
|
||||
"@autumn/server/ink/@alcalzone/ansi-tokenize/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="],
|
||||
|
||||
"@autumn/server/ink/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="],
|
||||
@@ -8958,6 +9125,8 @@
|
||||
|
||||
"@aws-sdk/signature-v4/@smithy/signature-v4/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@1.1.0", "", { "dependencies": { "@smithy/is-array-buffer": "^1.1.0", "tslib": "^2.5.0" } }, "sha512-9m6NXE0ww+ra5HKHCHig20T+FAwxBAm7DIdwc/767uGWbRcY720ybgPacQNB96JMOI7xVr/CDa3oMzKmW4a+kw=="],
|
||||
|
||||
"@dotenvx/dotenvx/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"@infisical/sdk/@aws-sdk/credential-providers/@aws-sdk/client-cognito-identity/@aws-sdk/core": ["@aws-sdk/core@3.598.0", "", { "dependencies": { "@smithy/core": "^2.2.1", "@smithy/protocol-http": "^4.0.1", "@smithy/signature-v4": "^3.1.0", "@smithy/smithy-client": "^3.1.2", "@smithy/types": "^3.1.0", "fast-xml-parser": "4.2.5", "tslib": "^2.6.2" } }, "sha512-HaSjt7puO5Cc7cOlrXFCW0rtA0BM9lvzjl56x0A20Pt+0wxXGeTOZZOkXQIepbrFkV2e/HYukuT9e99vXDm59g=="],
|
||||
|
||||
"@infisical/sdk/@aws-sdk/credential-providers/@aws-sdk/client-cognito-identity/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.598.0", "", { "dependencies": { "@aws-sdk/types": "3.598.0", "@smithy/protocol-http": "^4.0.1", "@smithy/types": "^3.1.0", "tslib": "^2.6.2" } }, "sha512-WiaG059YBQwQraNejLIi0gMNkX7dfPZ8hDIhvMr5aVPRbaHH8AYF3iNSsXYCHvA2Cfa1O9haYXsuMF9flXnCmA=="],
|
||||
@@ -9184,8 +9353,6 @@
|
||||
|
||||
"@mintlify/scraping/@mintlify/common/tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
|
||||
|
||||
"@mintlify/scraping/@mintlify/common/tailwindcss/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"@mintlify/scraping/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"@mintlify/scraping/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
@@ -9290,6 +9457,14 @@
|
||||
|
||||
"@tailwindcss/postcss/@tailwindcss/oxide/@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@trigger.dev/core/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io/cookie": ["cookie@0.4.2", "", {}, "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="],
|
||||
|
||||
"@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
@@ -9458,6 +9633,10 @@
|
||||
|
||||
"nodemon/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
|
||||
|
||||
"open-editor/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"ora/cli-cursor/restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"ora/log-symbols/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
|
||||
"ora/log-symbols/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
||||
@@ -9500,6 +9679,8 @@
|
||||
|
||||
"rimraf/glob/minimatch/brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="],
|
||||
|
||||
"run-jxa/execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"sdk-test/next/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"shadcn/cosmiconfig/js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
@@ -9684,6 +9865,8 @@
|
||||
|
||||
"@mintlify/scraping/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
||||
|
||||
"artillery-plugin-ensure/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
||||
|
||||
"artillery-plugin-publish-metrics/@opentelemetry/exporter-metrics-otlp-grpc/@opentelemetry/otlp-transformer/protobufjs/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
||||
@@ -9726,6 +9909,8 @@
|
||||
|
||||
"meow/read-pkg-up/read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="],
|
||||
|
||||
"ora/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"ora/log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
|
||||
"ora/log-symbols/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
"@aws-sdk/client-sqs": "^3.985.0",
|
||||
"@better-auth/core": "catalog:",
|
||||
"@better-auth/oauth-provider": "catalog:",
|
||||
"@trigger.dev/sdk": "4.4.5",
|
||||
"@wooorm/starry-night": "^3.8.0",
|
||||
"ag-charts-react": "^12.3.0",
|
||||
"better-auth": "catalog:",
|
||||
@@ -139,6 +140,7 @@
|
||||
"devDependencies": {
|
||||
"@better-auth/cli": "^1.4.21",
|
||||
"@biomejs/biome": "^2.2.7",
|
||||
"@trigger.dev/build": "4.4.5",
|
||||
"@types/node": "^24.9.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"dotenv": "^16.6.1",
|
||||
|
||||
@@ -174,6 +174,14 @@ async function startDev() {
|
||||
? `"cd server && bun ${workersScript}"`
|
||||
: `"cd server && bun ${workersScript}"`,
|
||||
);
|
||||
|
||||
names.push("trigger");
|
||||
colors.push("cyan");
|
||||
cmds.push(
|
||||
isWindows
|
||||
? `"bunx trigger.dev@latest dev"`
|
||||
: `"bunx trigger.dev@latest dev"`,
|
||||
);
|
||||
}
|
||||
|
||||
names.push("vite", "checkout");
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AppEnv } from "@autumn/shared";
|
||||
import {
|
||||
buildCustomerCount,
|
||||
buildCustomerSelect,
|
||||
} from "@autumn/shared/api/migrations/compiler/buildCustomerQuery.js";
|
||||
} from "@/internal/migrations/v2/filters/customers/buildCustomerSelect.js";
|
||||
import type { CustomerFilter } from "@autumn/shared/api/migrations/filters/customerFilter.js";
|
||||
import { sql, type SQL } from "drizzle-orm";
|
||||
import { PgDialect } from "drizzle-orm/pg-core";
|
||||
|
||||
38
server/src/external/autumn/autumnCli.ts
vendored
38
server/src/external/autumn/autumnCli.ts
vendored
@@ -47,9 +47,9 @@ import {
|
||||
type UpdateBalanceParamsV0,
|
||||
type UpdateSubscriptionV0Params,
|
||||
} from "@autumn/shared";
|
||||
import type { PrepareResponse } from "@/internal/migrations/v2/prepare/types";
|
||||
import { defaultApiVersion } from "@tests/constants.js";
|
||||
import { timeout } from "@tests/utils/genUtils";
|
||||
import type { PrepareResponse } from "@/internal/migrations/v2/prepare/types";
|
||||
|
||||
export default class AutumnError extends Error {
|
||||
message: string;
|
||||
@@ -956,6 +956,27 @@ export class AutumnInt {
|
||||
const data = await this.post(`/migrations.update`, params);
|
||||
return data as Migration;
|
||||
},
|
||||
delete: async (params: { id: string }): Promise<Migration> => {
|
||||
const data = await this.post(`/migrations.delete`, params);
|
||||
return data as Migration;
|
||||
},
|
||||
/**
|
||||
* Idempotent setup helper for tests / scripts: best-effort deletes
|
||||
* the migration if it exists, then creates a fresh one with the
|
||||
* given filter + operations. Avoids the (org_id, env, id) unique
|
||||
* constraint when reseeding fixtures.
|
||||
*/
|
||||
deleteAndCreate: async (params: {
|
||||
id: string;
|
||||
filter?: MigrationFilter | null;
|
||||
operations?: Operations | null;
|
||||
}): Promise<Migration> => {
|
||||
try {
|
||||
await this.post(`/migrations.delete`, { id: params.id });
|
||||
} catch {}
|
||||
const data = await this.post(`/migrations.create`, params);
|
||||
return data as Migration;
|
||||
},
|
||||
prepare: async (params: {
|
||||
id: string;
|
||||
dry_run: boolean;
|
||||
@@ -963,6 +984,21 @@ export class AutumnInt {
|
||||
const data = await this.post(`/migrations.prepare`, params);
|
||||
return data as PrepareResponse;
|
||||
},
|
||||
run: async (params: {
|
||||
id: string;
|
||||
dry_run?: boolean;
|
||||
}): Promise<{
|
||||
migration_id: string;
|
||||
dry_run: boolean;
|
||||
run_id: string;
|
||||
}> => {
|
||||
const data = await this.post(`/migrations.run`, params);
|
||||
return data as {
|
||||
migration_id: string;
|
||||
dry_run: boolean;
|
||||
run_id: string;
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
balances = {
|
||||
|
||||
115
server/src/external/infisical/fetchInfisicalSecrets.ts
vendored
Normal file
115
server/src/external/infisical/fetchInfisicalSecrets.ts
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Pure REST fetcher for Infisical secrets. Used at trigger.dev DEPLOY
|
||||
* time via `syncEnvVars` to push secrets to the cloud env. Kept SDK-free
|
||||
* so trigger.config.ts can import it without bloating the build.
|
||||
*
|
||||
* Runtime code uses `initInfisical` (SDK-based, populates process.env).
|
||||
*/
|
||||
|
||||
export type InfisicalSyncEnvVar = { name: string; value: string };
|
||||
|
||||
export type FetchInfisicalSecretsArgs = {
|
||||
clientId?: string | null;
|
||||
clientSecret?: string | null;
|
||||
projectId?: string | null;
|
||||
/** Defaults to "prod" if not set. */
|
||||
environment?: string | null;
|
||||
secretPath?: string;
|
||||
recursive?: boolean;
|
||||
includeImports?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticate via Universal Auth, fetch secrets at the given path, and
|
||||
* return them as `{ name, value }[]`. Imported groups are flattened in
|
||||
* after primary secrets, with first-write-wins de-duplication.
|
||||
*/
|
||||
export const fetchInfisicalSecrets = async ({
|
||||
clientId,
|
||||
clientSecret,
|
||||
projectId,
|
||||
environment,
|
||||
secretPath = "/",
|
||||
recursive = true,
|
||||
includeImports = true,
|
||||
}: FetchInfisicalSecretsArgs): Promise<InfisicalSyncEnvVar[]> => {
|
||||
const env = environment ?? "prod";
|
||||
|
||||
if (!clientId || !clientSecret || !projectId) {
|
||||
throw new Error(
|
||||
"Missing Infisical credentials. Set INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET, INFISICAL_PROJECT_ID.",
|
||||
);
|
||||
}
|
||||
|
||||
const authRes = await fetch(
|
||||
"https://app.infisical.com/api/v1/auth/universal-auth/login",
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ clientId, clientSecret }),
|
||||
},
|
||||
);
|
||||
if (!authRes.ok)
|
||||
throw new Error(
|
||||
`Infisical auth failed: ${authRes.status} ${await authRes.text()}`,
|
||||
);
|
||||
const { accessToken } = (await authRes.json()) as { accessToken: string };
|
||||
|
||||
const params = new URLSearchParams({
|
||||
environment: env,
|
||||
workspaceId: projectId,
|
||||
secretPath,
|
||||
recursive: String(recursive),
|
||||
includeImports: String(includeImports),
|
||||
});
|
||||
const secretsRes = await fetch(
|
||||
`https://app.infisical.com/api/v3/secrets/raw?${params}`,
|
||||
{ headers: { Authorization: `Bearer ${accessToken}` } },
|
||||
);
|
||||
if (!secretsRes.ok)
|
||||
throw new Error(
|
||||
`Infisical secrets failed: ${secretsRes.status} ${await secretsRes.text()}`,
|
||||
);
|
||||
const data = (await secretsRes.json()) as {
|
||||
secrets: Array<{ secretKey: string; secretValue: string }>;
|
||||
imports?: Array<{
|
||||
secrets: Array<{ secretKey: string; secretValue: string }>;
|
||||
}>;
|
||||
};
|
||||
|
||||
const envVars: InfisicalSyncEnvVar[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
const push = (key: string, value: string) => {
|
||||
if (!key || !value || seen.has(key)) return;
|
||||
envVars.push({ name: key, value });
|
||||
seen.add(key);
|
||||
};
|
||||
|
||||
for (const secret of data.secrets) push(secret.secretKey, secret.secretValue);
|
||||
for (const importGroup of data.imports ?? [])
|
||||
for (const secret of importGroup.secrets)
|
||||
push(secret.secretKey, secret.secretValue);
|
||||
|
||||
console.log(
|
||||
`[fetchInfisicalSecrets] Synced ${envVars.length} secrets from Infisical (env=${env}, path=${secretPath})`,
|
||||
);
|
||||
return envVars;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the four credential vars (`INFISICAL_CLIENT_ID`, `_SECRET`,
|
||||
* `_PROJECT_ID`, `_ENVIRONMENT`) from the local process env first then
|
||||
* trigger.dev's deploy-time `ctx.env`. Convenience for `syncEnvVars`.
|
||||
*/
|
||||
export const fetchInfisicalSecretsFromEnv = (
|
||||
ctxEnv: Record<string, string | undefined> = {},
|
||||
): Promise<InfisicalSyncEnvVar[]> =>
|
||||
fetchInfisicalSecrets({
|
||||
clientId: process.env.INFISICAL_CLIENT_ID ?? ctxEnv.INFISICAL_CLIENT_ID,
|
||||
clientSecret:
|
||||
process.env.INFISICAL_CLIENT_SECRET ?? ctxEnv.INFISICAL_CLIENT_SECRET,
|
||||
projectId: process.env.INFISICAL_PROJECT_ID ?? ctxEnv.INFISICAL_PROJECT_ID,
|
||||
environment:
|
||||
process.env.INFISICAL_ENVIRONMENT ?? ctxEnv.INFISICAL_ENVIRONMENT,
|
||||
});
|
||||
64
server/src/external/logtail/logtailUtils.ts
vendored
64
server/src/external/logtail/logtailUtils.ts
vendored
@@ -1,5 +1,6 @@
|
||||
import "dotenv/config";
|
||||
|
||||
import type pino from "pino";
|
||||
import { initLogger } from "@/utils/logging/initLogger";
|
||||
|
||||
const pinoLogger = initLogger();
|
||||
@@ -72,34 +73,45 @@ const createLogMethod = (pinoMethod: any, logtailMethod?: any) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const createLogger = () => {
|
||||
// Helper function to create logger structure recursively
|
||||
const createLoggerStructure = (basePinoLogger: any) => {
|
||||
return {
|
||||
debug: createLogMethod(basePinoLogger.debug.bind(basePinoLogger)),
|
||||
info: createLogMethod(basePinoLogger.info.bind(basePinoLogger)),
|
||||
warn: createLogMethod(basePinoLogger.warn.bind(basePinoLogger)),
|
||||
error: createLogMethod(basePinoLogger.error.bind(basePinoLogger)),
|
||||
child: ({
|
||||
context,
|
||||
onlyProd = false,
|
||||
}: {
|
||||
context: any;
|
||||
onlyProd?: boolean;
|
||||
}) => {
|
||||
if (onlyProd && process.env.NODE_ENV !== "production") {
|
||||
return createLoggerStructure(basePinoLogger);
|
||||
}
|
||||
const createLoggerStructure = (basePinoLogger: pino.Logger): Logger => ({
|
||||
debug: createLogMethod(basePinoLogger.debug.bind(basePinoLogger)),
|
||||
info: createLogMethod(basePinoLogger.info.bind(basePinoLogger)),
|
||||
warn: createLogMethod(basePinoLogger.warn.bind(basePinoLogger)),
|
||||
error: createLogMethod(basePinoLogger.error.bind(basePinoLogger)),
|
||||
child: ({
|
||||
context,
|
||||
onlyProd = false,
|
||||
}: {
|
||||
context: any;
|
||||
onlyProd?: boolean;
|
||||
}) => {
|
||||
if (onlyProd && process.env.NODE_ENV !== "production") {
|
||||
return createLoggerStructure(basePinoLogger);
|
||||
}
|
||||
|
||||
const childPinoLogger = basePinoLogger.child(context);
|
||||
return createLoggerStructure(childPinoLogger);
|
||||
},
|
||||
};
|
||||
};
|
||||
const childPinoLogger = basePinoLogger.child(context);
|
||||
return createLoggerStructure(childPinoLogger);
|
||||
},
|
||||
});
|
||||
|
||||
// Create the root logger using the helper function
|
||||
return createLoggerStructure(pinoLogger);
|
||||
export const createLogger = () => createLoggerStructure(pinoLogger);
|
||||
|
||||
/**
|
||||
* Lazy dual-output logger (stdout JSON + axiom). Used only by long-running
|
||||
* trigger.dev tasks so their lines surface in both the trigger run UI and
|
||||
* our axiom store. Default `logger` / `createLogger` are unaffected.
|
||||
*/
|
||||
let dualPinoLogger: pino.Logger | null = null;
|
||||
export const createDualLogger = () => {
|
||||
if (!dualPinoLogger) dualPinoLogger = initLogger({ mode: "dual" });
|
||||
return createLoggerStructure(dualPinoLogger);
|
||||
};
|
||||
|
||||
export const logger = createLogger();
|
||||
export type Logger = ReturnType<typeof createLogger>;
|
||||
export type Logger = {
|
||||
debug: (...args: any[]) => void;
|
||||
info: (...args: any[]) => void;
|
||||
warn: (...args: any[]) => void;
|
||||
error: (...args: any[]) => void;
|
||||
child: (args: { context: any; onlyProd?: boolean }) => Logger;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ import "./internal/misc/edgeConfig/orgLimitsStore.js";
|
||||
import "./internal/misc/stripeSync/stripeSyncStore.js";
|
||||
import "./internal/misc/redisV2Cache/redisV2CacheStore.js";
|
||||
import "./internal/misc/jobQueues/jobQueueStore.js";
|
||||
// Side-effect: configures trigger.dev SDK to use TRIGGER_SERVER_SECRET_KEY.
|
||||
import "./trigger/configureTrigger.js";
|
||||
import { closeStripeSyncEngine } from "@autumn/stripe-sync";
|
||||
import {
|
||||
startRedisMonitor,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Higher-level migration business logic (preview, run, idempotency,
|
||||
* billing-path bridging). Empty in phase 1 — phase 1 is pure CRUD on the
|
||||
* migration entity, handled directly via `migrationRepo`. Phase 2+ adds
|
||||
* verbs here as ops grow runtime semantics.
|
||||
*/
|
||||
export const migrationActions = {} as const;
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { CustomerFilter } from "@autumn/shared";
|
||||
import { compileFilter } from "@autumn/shared/api/migrations/compiler/compileFilter.js";
|
||||
import type { ResolutionContext } from "@autumn/shared/api/migrations/compiler/filterToIr/resolutionContext.js";
|
||||
import { type SQL, sql } from "drizzle-orm";
|
||||
import { rawWithParamsToDrizzle } from "../rawWithParamsToDrizzle.js";
|
||||
|
||||
export type CustomerQueryArgs = {
|
||||
orgId: string;
|
||||
env: string;
|
||||
filter: CustomerFilter;
|
||||
ctx: ResolutionContext;
|
||||
};
|
||||
|
||||
const compileWhere = ({ orgId, env, filter, ctx }: CustomerQueryArgs): SQL =>
|
||||
rawWithParamsToDrizzle(
|
||||
compileFilter({ filter, ctx, ambient: { orgId, env } }),
|
||||
);
|
||||
|
||||
/**
|
||||
* Full SELECT. Returns `{ internal_id, id }` rows newest-first via keyset
|
||||
* pagination on `c.internal_id DESC`, so successive iterations over an
|
||||
* unchanged customer set yield rows in the same order.
|
||||
*/
|
||||
export const buildCustomerSelect = ({
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
limit,
|
||||
afterInternalId,
|
||||
}: CustomerQueryArgs & {
|
||||
limit?: number;
|
||||
afterInternalId?: string;
|
||||
}): SQL => {
|
||||
const where = compileWhere({ orgId, env, filter, ctx });
|
||||
const cursor = afterInternalId
|
||||
? sql`AND c.internal_id < ${afterInternalId}`
|
||||
: sql``;
|
||||
const limitClause = limit !== undefined ? sql`LIMIT ${limit}` : sql``;
|
||||
return sql`
|
||||
SELECT c.internal_id, c.id
|
||||
FROM customers c
|
||||
WHERE (${where}) ${cursor}
|
||||
ORDER BY c.internal_id DESC
|
||||
${limitClause}
|
||||
`;
|
||||
};
|
||||
|
||||
/** COUNT(*) applying the same filter. */
|
||||
export const buildCustomerCount = ({
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
}: CustomerQueryArgs): SQL => {
|
||||
const where = compileWhere({ orgId, env, filter, ctx });
|
||||
return sql`
|
||||
SELECT COUNT(*)::bigint AS count
|
||||
FROM customers c
|
||||
WHERE (${where})
|
||||
`;
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { CustomerFilter } from "@autumn/shared";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import { iterateOverFilterResults } from "../iterateOverFilterResults.js";
|
||||
import {
|
||||
buildCustomerCount,
|
||||
buildCustomerSelect,
|
||||
} from "./buildCustomerSelect.js";
|
||||
|
||||
export type CustomerRow = { internal_id: string; id: string | null };
|
||||
|
||||
/**
|
||||
* Pure inner: takes a CustomerFilter directly. Used by `runFilter` shim
|
||||
* (Migration-fed) and reusable from scripts that don't have a Migration.
|
||||
*/
|
||||
export const filterCustomers = ({
|
||||
ctx,
|
||||
filter,
|
||||
batchSize,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
filter: CustomerFilter;
|
||||
batchSize?: number;
|
||||
}): AsyncGenerator<CustomerRow[]> => {
|
||||
const args = {
|
||||
orgId: ctx.org.id,
|
||||
env: ctx.env,
|
||||
filter,
|
||||
ctx: { features: ctx.features },
|
||||
};
|
||||
return iterateOverFilterResults<CustomerRow>({
|
||||
db: ctx.db,
|
||||
buildSelect: ({ limit, afterInternalId }) =>
|
||||
buildCustomerSelect({ ...args, limit, afterInternalId }),
|
||||
batchSize,
|
||||
});
|
||||
};
|
||||
|
||||
/** Count of customers matching `filter`. */
|
||||
export const countCustomers = async ({
|
||||
ctx,
|
||||
filter,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
filter: CustomerFilter;
|
||||
}): Promise<number> => {
|
||||
const [{ count }] = (await ctx.db.execute(
|
||||
buildCustomerCount({
|
||||
orgId: ctx.org.id,
|
||||
env: ctx.env,
|
||||
filter,
|
||||
ctx: { features: ctx.features },
|
||||
}),
|
||||
)) as Array<{ count: bigint | number }>;
|
||||
return Number(count);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./buildCustomerSelect.js";
|
||||
export * from "./filterCustomers.js";
|
||||
24
server/src/internal/migrations/v2/filters/getFilterCount.ts
Normal file
24
server/src/internal/migrations/v2/filters/getFilterCount.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import type { RunScopeKind } from "../run/types/runScope.js";
|
||||
import { countCustomers } from "./customers/filterCustomers.js";
|
||||
|
||||
/** Migration-fed shim. Delegates to per-kind pure counters. */
|
||||
export const getFilterCount = async ({
|
||||
ctx,
|
||||
migration,
|
||||
kind,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
kind: RunScopeKind;
|
||||
}): Promise<number> => {
|
||||
if (kind !== "customer")
|
||||
throw new Error(
|
||||
`getFilterCount: scope kind "${kind}" not supported yet (phase 2+)`,
|
||||
);
|
||||
return countCustomers({
|
||||
ctx,
|
||||
filter: migration.filter?.customer ?? {},
|
||||
});
|
||||
};
|
||||
5
server/src/internal/migrations/v2/filters/index.ts
Normal file
5
server/src/internal/migrations/v2/filters/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from "./customers/index.js";
|
||||
export * from "./getFilterCount.js";
|
||||
export * from "./iterateOverFilterResults.js";
|
||||
export * from "./rawWithParamsToDrizzle.js";
|
||||
export * from "./runFilter.js";
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { SQL } from "drizzle-orm";
|
||||
|
||||
export const DEFAULT_BATCH_SIZE = 10_000;
|
||||
|
||||
/**
|
||||
* Iterate keyset-paginated rows in batches. Caller supplies a `buildSelect`
|
||||
* closure that returns the SQL for the next page given a cursor; rows
|
||||
* MUST include `internal_id` for the cursor to advance.
|
||||
*/
|
||||
export async function* iterateOverFilterResults<
|
||||
TRow extends { internal_id: string },
|
||||
>({
|
||||
db,
|
||||
buildSelect,
|
||||
batchSize = DEFAULT_BATCH_SIZE,
|
||||
}: {
|
||||
db: { execute: (query: SQL) => Promise<unknown> };
|
||||
buildSelect: (args: { limit: number; afterInternalId?: string }) => SQL;
|
||||
batchSize?: number;
|
||||
}): AsyncGenerator<TRow[]> {
|
||||
let cursor: string | undefined;
|
||||
while (true) {
|
||||
const query = buildSelect({ limit: batchSize, afterInternalId: cursor });
|
||||
const rows = (await db.execute(query)) as unknown as TRow[];
|
||||
if (rows.length === 0) return;
|
||||
yield rows;
|
||||
if (rows.length < batchSize) return;
|
||||
cursor = rows[rows.length - 1].internal_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { type SQL, sql } from "drizzle-orm";
|
||||
|
||||
/** Convert the compiler's `{ sql, params }` output to a Drizzle SQL chunk. */
|
||||
export const rawWithParamsToDrizzle = ({
|
||||
sql: raw,
|
||||
params,
|
||||
}: {
|
||||
sql: string;
|
||||
params: readonly unknown[];
|
||||
}): SQL => {
|
||||
const parts = raw.split("?");
|
||||
if (parts.length - 1 !== params.length)
|
||||
throw new Error(
|
||||
`Placeholder/param count mismatch: ${parts.length - 1} placeholders vs ${params.length} params`,
|
||||
);
|
||||
const chunks: SQL[] = [];
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
chunks.push(sql.raw(parts[i]));
|
||||
if (i < params.length) chunks.push(sql`${params[i]}`);
|
||||
}
|
||||
return sql.join(chunks, sql.raw(""));
|
||||
};
|
||||
48
server/src/internal/migrations/v2/filters/runFilter.ts
Normal file
48
server/src/internal/migrations/v2/filters/runFilter.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { AutumnContext } from "../../../../honoUtils/HonoEnv.js";
|
||||
import type { RunScopeItem, RunScopeKind } from "../run/types/runScope.js";
|
||||
import {
|
||||
countCustomers,
|
||||
filterCustomers,
|
||||
} from "./customers/filterCustomers.js";
|
||||
|
||||
/**
|
||||
* Migration-fed shim. Dispatches by scope kind, unwraps the relevant
|
||||
* filter from `migration.filter`, and delegates to the pure inner fns
|
||||
* (`countCustomers` / `filterCustomers`). Empty filter ⇒ whole org+env.
|
||||
*/
|
||||
export const runFilter = async ({
|
||||
ctx,
|
||||
migration,
|
||||
kind,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
kind: RunScopeKind;
|
||||
}): Promise<{
|
||||
kind: RunScopeKind;
|
||||
count: number;
|
||||
iterate: () => AsyncGenerator<RunScopeItem[]>;
|
||||
}> => {
|
||||
if (kind !== "customer")
|
||||
throw new Error(
|
||||
`runFilter: scope kind "${kind}" not supported yet (phase 2+)`,
|
||||
);
|
||||
|
||||
const filter = migration.filter?.customer ?? {};
|
||||
const count = await countCustomers({ ctx, filter });
|
||||
|
||||
const iterate = async function* () {
|
||||
for await (const batch of filterCustomers({ ctx, filter })) {
|
||||
yield batch.map(
|
||||
(row): RunScopeItem => ({
|
||||
kind: "customer",
|
||||
internal_id: row.internal_id,
|
||||
id: row.id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return { kind, count, iterate };
|
||||
};
|
||||
@@ -21,6 +21,6 @@ export const handleCreateMigration = createRoute({
|
||||
|
||||
const migration = await migrationRepo.insert({ ctx, insert });
|
||||
|
||||
return c.json(migration, 201);
|
||||
return c.json(migration);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ErrCode, RecaseError, Scopes } from "@autumn/shared";
|
||||
import { z } from "zod/v4";
|
||||
import { createRoute } from "@/honoMiddlewares/routeHandler";
|
||||
import { migrationRepo } from "@/internal/migrations/v2/repos/index.js";
|
||||
|
||||
const DeleteMigrationBody = z.object({
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
/** POST /migrations.delete — delete by user `id`. */
|
||||
export const handleDeleteMigration = createRoute({
|
||||
scopes: [Scopes.Migrations.Write],
|
||||
body: DeleteMigrationBody,
|
||||
handler: async (c) => {
|
||||
const ctx = c.get("ctx");
|
||||
const { id } = c.req.valid("json");
|
||||
|
||||
const deleted = await migrationRepo.delete({ ctx, id });
|
||||
if (!deleted)
|
||||
throw new RecaseError({
|
||||
message: `Migration ${id} not found`,
|
||||
code: ErrCode.MigrationNotFound,
|
||||
statusCode: 404,
|
||||
});
|
||||
|
||||
return c.json(deleted);
|
||||
},
|
||||
});
|
||||
@@ -17,13 +17,7 @@ export const handlePrepareMigration = createRoute({
|
||||
const ctx = c.get("ctx");
|
||||
const { id, dry_run } = c.req.valid("json");
|
||||
|
||||
const [migration] = await migrationRepo.get({ ctx, id });
|
||||
if (!migration)
|
||||
throw new RecaseError({
|
||||
message: `Migration ${id} not found`,
|
||||
code: ErrCode.MigrationNotFound,
|
||||
statusCode: 404,
|
||||
});
|
||||
const migration = await migrationRepo.find({ ctx, id });
|
||||
|
||||
if (!migration.operations)
|
||||
throw new RecaseError({
|
||||
@@ -32,7 +26,7 @@ export const handlePrepareMigration = createRoute({
|
||||
statusCode: 400,
|
||||
});
|
||||
|
||||
const response = await runPrepare({ ctx, migration, dry_run });
|
||||
const { response } = await runPrepare({ ctx, migration, dry_run });
|
||||
return c.json(response);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { ErrCode, RecaseError, Scopes } from "@autumn/shared";
|
||||
import { z } from "zod/v4";
|
||||
import { createRoute } from "@/honoMiddlewares/routeHandler";
|
||||
import { migrationRepo } from "@/internal/migrations/v2/repos/index.js";
|
||||
import { runMigrationTask } from "@/trigger/migrations/runMigrationTask.js";
|
||||
|
||||
const RunMigrationBody = z.object({
|
||||
id: z.string(),
|
||||
dry_run: z.boolean().default(false),
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /migrations.run — kick off a migration on trigger.dev. Returns the
|
||||
* trigger run handle so the dashboard can poll status. In dev we route
|
||||
* to EU so dev runs don't touch the production US region.
|
||||
*/
|
||||
export const handleRunMigration = createRoute({
|
||||
scopes: [Scopes.Migrations.Write],
|
||||
body: RunMigrationBody,
|
||||
handler: async (c) => {
|
||||
const ctx = c.get("ctx");
|
||||
const { id, dry_run } = c.req.valid("json");
|
||||
|
||||
const migration = await migrationRepo.find({ ctx, id });
|
||||
|
||||
if (!migration.operations)
|
||||
throw new RecaseError({
|
||||
message: `Migration ${id} has no operations to run`,
|
||||
code: ErrCode.InvalidRequest,
|
||||
statusCode: 400,
|
||||
});
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
|
||||
const handle = await runMigrationTask.trigger(
|
||||
{
|
||||
orgId: ctx.org.id,
|
||||
env: ctx.env,
|
||||
migrationId: id,
|
||||
dryRun: dry_run,
|
||||
},
|
||||
isDev ? { region: "eu-west-1" } : undefined,
|
||||
);
|
||||
|
||||
return c.json({
|
||||
migration_id: id,
|
||||
dry_run,
|
||||
run_id: handle.id,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Hono } from "hono";
|
||||
import type { HonoEnv } from "@/honoUtils/HonoEnv.js";
|
||||
import { handleCreateMigration } from "./handlers/handleCreateMigration/handleCreateMigration.js";
|
||||
import { handleListMigrations } from "./handlers/handleListMigrations/handleListMigrations.js";
|
||||
import { handlePatchMigration } from "./handlers/handlePatchMigration/handlePatchMigration.js";
|
||||
import { handlePrepareMigration } from "./handlers/handlePrepareMigration/handlePrepareMigration.js";
|
||||
import { handleCreateMigration } from "./handlers/handleCreateMigration.js";
|
||||
import { handleDeleteMigration } from "./handlers/handleDeleteMigration.js";
|
||||
import { handleListMigrations } from "./handlers/handleListMigrations.js";
|
||||
import { handlePatchMigration } from "./handlers/handlePatchMigration.js";
|
||||
import { handlePrepareMigration } from "./handlers/handlePrepareMigration.js";
|
||||
import { handleRunMigration } from "./handlers/handleRunMigration.js";
|
||||
|
||||
/**
|
||||
* V2 user-facing migrations RPC router. Distinct from the legacy
|
||||
@@ -15,4 +17,6 @@ export const migrationRpcRouter = new Hono<HonoEnv>();
|
||||
migrationRpcRouter.post("/migrations.create", ...handleCreateMigration);
|
||||
migrationRpcRouter.post("/migrations.list", ...handleListMigrations);
|
||||
migrationRpcRouter.post("/migrations.update", ...handlePatchMigration);
|
||||
migrationRpcRouter.post("/migrations.delete", ...handleDeleteMigration);
|
||||
migrationRpcRouter.post("/migrations.prepare", ...handlePrepareMigration);
|
||||
migrationRpcRouter.post("/migrations.run", ...handleRunMigration);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./inferImplicitPrep.js";
|
||||
export * from "./modules/ensurePricesAndEntitlements/index.js";
|
||||
export * from "./runPrepare.js";
|
||||
export * from "./runPrepareModules.js";
|
||||
export * from "./types/index.js";
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { Migration, Operations } from "@autumn/shared";
|
||||
import {
|
||||
ensurePricesAndEntitlements,
|
||||
type EnsurePricesAndEntitlementsInput,
|
||||
ensurePricesAndEntitlements,
|
||||
} from "./modules/ensurePricesAndEntitlements/index.js";
|
||||
|
||||
/**
|
||||
* One instance of a prep module to run. The orchestrator calls each
|
||||
* instance's `plan` / `apply` in order.
|
||||
*/
|
||||
/** One instance of a prep module to run. */
|
||||
export type ImplicitPrepInstance = {
|
||||
key: string;
|
||||
module: typeof ensurePricesAndEntitlements;
|
||||
@@ -15,18 +12,17 @@ export type ImplicitPrepInstance = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Walk the migration's operations and derive which prep modules need to
|
||||
* run. Phase 1 only emits `ensure_prices_and_entitlements` from
|
||||
* `update_plans[].add_items[]`.
|
||||
*
|
||||
* Module key format: `<kind>:<feature_id>:<plan_id>` so distinct
|
||||
* (target, feature) pairs get distinct prep entries.
|
||||
* Pure walker. Takes an `operations` object directly so scripts (and
|
||||
* any other caller) can derive prep instances without a Migration row.
|
||||
* Module key format: `<kind>:<feature_id>:<plan_id>`.
|
||||
*/
|
||||
export const inferImplicitPrep = (
|
||||
migration: Migration,
|
||||
): ImplicitPrepInstance[] => {
|
||||
export const inferPrepareModules = ({
|
||||
operations,
|
||||
}: {
|
||||
operations: Operations | null | undefined;
|
||||
}): ImplicitPrepInstance[] => {
|
||||
const instances: ImplicitPrepInstance[] = [];
|
||||
const updatePlans = migration.operations?.customer?.update_plans ?? [];
|
||||
const updatePlans = operations?.customer?.update_plans ?? [];
|
||||
|
||||
for (const op of updatePlans) {
|
||||
const planId =
|
||||
@@ -35,20 +31,23 @@ export const inferImplicitPrep = (
|
||||
|
||||
for (const item of op.add_items ?? []) {
|
||||
if (!item.feature_id) continue;
|
||||
// Phase 1 constraint: only entitlement-only items. Priced items
|
||||
// will be handled by the same module in phase 2+.
|
||||
// Phase 1 constraint: entitlement-only items. Priced items will be
|
||||
// handled by the same module in phase 2+.
|
||||
if (item.price) continue;
|
||||
|
||||
instances.push({
|
||||
key: `ensure_prices_and_entitlements:${item.feature_id}:${planId}`,
|
||||
module: ensurePricesAndEntitlements,
|
||||
input: {
|
||||
target_plan_id: planId,
|
||||
feature_id: item.feature_id,
|
||||
},
|
||||
input: { target_plan_id: planId, feature_id: item.feature_id },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return instances;
|
||||
};
|
||||
|
||||
/** Migration-fed shim. */
|
||||
export const inferImplicitPrep = (
|
||||
migration: Migration,
|
||||
): ImplicitPrepInstance[] =>
|
||||
inferPrepareModules({ operations: migration.operations });
|
||||
|
||||
@@ -13,17 +13,20 @@ export type EnsurePricesAndEntitlementsInput = {
|
||||
feature_id: string;
|
||||
};
|
||||
|
||||
/** Deterministic ID per (migration, product version, feature). Idempotent across runs. */
|
||||
/**
|
||||
* Deterministic ID per (scope, product version, feature). Migration
|
||||
* scopes pass `scopeId = mig_<internal_id>` to preserve the original
|
||||
* `ent_mig_<id>_<...>` format; scripts pass their own prefix.
|
||||
*/
|
||||
export const entitlementIdFor = ({
|
||||
migrationInternalId,
|
||||
scopeId,
|
||||
productInternalId,
|
||||
internalFeatureId,
|
||||
}: {
|
||||
migrationInternalId: string;
|
||||
scopeId: string;
|
||||
productInternalId: string;
|
||||
internalFeatureId: string;
|
||||
}): string =>
|
||||
`ent_mig_${migrationInternalId}_${productInternalId}_${internalFeatureId}`;
|
||||
}): string => `ent_${scopeId}_${productInternalId}_${internalFeatureId}`;
|
||||
|
||||
export const ensurePricesAndEntitlements: PrepareModule<
|
||||
EnsurePricesAndEntitlementsInput,
|
||||
@@ -31,7 +34,7 @@ export const ensurePricesAndEntitlements: PrepareModule<
|
||||
> = {
|
||||
kind: "ensure_prices_and_entitlements",
|
||||
|
||||
async plan({ ctx, migration, input }) {
|
||||
async plan({ ctx, scope_id, input }) {
|
||||
const feature = ctx.features.find((f) => f.id === input.feature_id);
|
||||
if (!feature)
|
||||
throw new Error(
|
||||
@@ -50,7 +53,7 @@ export const ensurePricesAndEntitlements: PrepareModule<
|
||||
|
||||
const desired: EntitlementItemRef[] = matchingProducts.map((product) => ({
|
||||
entitlement_id: entitlementIdFor({
|
||||
migrationInternalId: migration.internal_id,
|
||||
scopeId: scope_id,
|
||||
productInternalId: product.internal_id,
|
||||
internalFeatureId: feature.internal_id,
|
||||
}),
|
||||
@@ -67,7 +70,7 @@ export const ensurePricesAndEntitlements: PrepareModule<
|
||||
const desired = planned.entitlements;
|
||||
const ids = desired.map((d) => d.entitlement_id);
|
||||
|
||||
// Skip rows that already exist in DB. Deterministic IDs make this safe.
|
||||
// Deterministic IDs let us skip rows already present in DB.
|
||||
const existing = ids.length
|
||||
? await ctx.db
|
||||
.select({ id: entitlements.id })
|
||||
|
||||
@@ -2,18 +2,18 @@ import type { Migration } from "@autumn/shared";
|
||||
import type { AutumnContext } from "../../../../honoUtils/HonoEnv.js";
|
||||
import { migrationRepo } from "../repos/index.js";
|
||||
import { inferImplicitPrep } from "./inferImplicitPrep.js";
|
||||
import type {
|
||||
PrepareModuleResult,
|
||||
PrepareResponse,
|
||||
PreparedState,
|
||||
} from "./types/index.js";
|
||||
import { runPrepareModules } from "./runPrepareModules.js";
|
||||
import type { PreparedState, PrepareResponse } from "./types/index.js";
|
||||
|
||||
/** Stable scope_id for a Migration. Preserves the historical entitlement ID format. */
|
||||
const scopeIdFor = (migration: Migration): string =>
|
||||
`mig_${migration.internal_id}`;
|
||||
|
||||
/**
|
||||
* Orchestrate a migration's prepare phase. Walks implicit prep modules,
|
||||
* runs plan → apply per module, persists prepared_state.
|
||||
*
|
||||
* On `dry_run: true`, plan runs but apply is skipped and prepared_state
|
||||
* is not written.
|
||||
* Migration-fed shim around `runPrepareModules`. Walks implicit prep
|
||||
* modules from `migration.operations`, runs the pure orchestrator, then
|
||||
* persists the new `prepared_state` back to the migrations row (skipped
|
||||
* on dry-run).
|
||||
*/
|
||||
export const runPrepare = async ({
|
||||
ctx,
|
||||
@@ -23,40 +23,32 @@ export const runPrepare = async ({
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
dry_run: boolean;
|
||||
}): Promise<PrepareResponse> => {
|
||||
const instances = inferImplicitPrep(migration);
|
||||
const warnings: string[] = [];
|
||||
const modules: PrepareModuleResult[] = [];
|
||||
const nextState: PreparedState = { ...(migration.prepared_state ?? {}) };
|
||||
}): Promise<{ response: PrepareResponse; prepared_state: PreparedState }> => {
|
||||
const modules = inferImplicitPrep(migration);
|
||||
|
||||
for (const { key, module, input } of instances) {
|
||||
const planned = await module.plan({ ctx, migration, input });
|
||||
|
||||
if (planned.entitlements.length === 0) {
|
||||
warnings.push(`No products matched target for ${key}`);
|
||||
}
|
||||
|
||||
const result = dry_run
|
||||
? planned
|
||||
: await module.apply({ ctx, migration, input, planned });
|
||||
|
||||
if (!dry_run) nextState[key] = result;
|
||||
|
||||
modules.push({ key, kind: module.kind, result });
|
||||
}
|
||||
const { results, prepared_state } = await runPrepareModules({
|
||||
ctx,
|
||||
scope_id: scopeIdFor(migration),
|
||||
modules,
|
||||
dry_run,
|
||||
prior_state: migration.prepared_state ?? {},
|
||||
});
|
||||
|
||||
if (!dry_run) {
|
||||
await migrationRepo.update({
|
||||
ctx,
|
||||
id: migration.id,
|
||||
updates: { prepared_state: nextState },
|
||||
updates: { prepared_state },
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
migration_id: migration.id,
|
||||
dry_run,
|
||||
modules,
|
||||
warnings,
|
||||
response: {
|
||||
migration_id: migration.id,
|
||||
dry_run,
|
||||
modules: results,
|
||||
warnings: [],
|
||||
},
|
||||
prepared_state,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { AutumnContext } from "../../../../honoUtils/HonoEnv.js";
|
||||
import type { ImplicitPrepInstance } from "./inferImplicitPrep.js";
|
||||
import type { PreparedState, PrepareModuleResult } from "./types/index.js";
|
||||
|
||||
/**
|
||||
* Pure orchestrator. Walks a list of prep module instances under a
|
||||
* given `scope_id`, runs plan → apply per module (apply skipped on
|
||||
* dry-run), threads `prepared_state` through. No DB reads/writes
|
||||
* outside what the modules themselves do — script-callable.
|
||||
*/
|
||||
export const runPrepareModules = async ({
|
||||
ctx,
|
||||
scope_id,
|
||||
modules,
|
||||
dry_run,
|
||||
prior_state = {},
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
scope_id: string;
|
||||
modules: ImplicitPrepInstance[];
|
||||
dry_run: boolean;
|
||||
prior_state?: PreparedState;
|
||||
}): Promise<{
|
||||
results: PrepareModuleResult[];
|
||||
prepared_state: PreparedState;
|
||||
}> => {
|
||||
const results: PrepareModuleResult[] = [];
|
||||
const next_state: PreparedState = { ...prior_state };
|
||||
|
||||
for (const { key, module, input } of modules) {
|
||||
const planned = await module.plan({ ctx, scope_id, input });
|
||||
const result = dry_run
|
||||
? planned
|
||||
: await module.apply({ ctx, scope_id, input, planned });
|
||||
if (!dry_run) next_state[key] = result;
|
||||
results.push({ key, kind: module.kind, result });
|
||||
}
|
||||
|
||||
return { results, prepared_state: next_state };
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from "./preparedState.js";
|
||||
export * from "./prepareModule.js";
|
||||
export * from "./prepareModuleResult.js";
|
||||
export * from "./prepareResponse.js";
|
||||
export * from "./preparedState.js";
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { AutumnContext } from "../../../../../honoUtils/HonoEnv";
|
||||
|
||||
/**
|
||||
* Common shape every prepare module implements. `Input` and `Result`
|
||||
* are module-specific (see `modules/<kind>/types.ts`). The orchestrator
|
||||
* wraps the returned `Result` in the loose `{ key, kind, result }`
|
||||
* envelope before persistence / response.
|
||||
* are module-specific. The orchestrator wraps the returned `Result` in
|
||||
* the loose `{ key, kind, result }` envelope.
|
||||
*
|
||||
* `scope_id` is the namespace under which deterministic catalog rows
|
||||
* are created — `mig_<internal_id>` for migrations, or any other prefix
|
||||
* for ad-hoc script invocations.
|
||||
*/
|
||||
export type PrepareModule<Input, Result> = {
|
||||
kind: string;
|
||||
@@ -13,14 +15,14 @@ export type PrepareModule<Input, Result> = {
|
||||
/** Pure planning. No writes. */
|
||||
plan: (args: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
scope_id: string;
|
||||
input: Input;
|
||||
}) => Promise<Result>;
|
||||
|
||||
/** Persist the desired set. Idempotent (deterministic IDs). */
|
||||
apply: (args: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
scope_id: string;
|
||||
input: Input;
|
||||
planned: Result;
|
||||
}) => Promise<Result>;
|
||||
|
||||
24
server/src/internal/migrations/v2/repos/deleteMigration.ts
Normal file
24
server/src/internal/migrations/v2/repos/deleteMigration.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { type Migration, migrations } from "@autumn/shared";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import type { RepoContext } from "@/db/repoContext.js";
|
||||
|
||||
/** Delete by user `id`, scoped to the current org + env. */
|
||||
export const deleteMigration = async ({
|
||||
ctx,
|
||||
id,
|
||||
}: {
|
||||
ctx: RepoContext;
|
||||
id: string;
|
||||
}): Promise<Migration | null> => {
|
||||
const [row] = await ctx.db
|
||||
.delete(migrations)
|
||||
.where(
|
||||
and(
|
||||
eq(migrations.id, id),
|
||||
eq(migrations.org_id, ctx.org.id),
|
||||
eq(migrations.env, ctx.env),
|
||||
),
|
||||
)
|
||||
.returning();
|
||||
return row ?? null;
|
||||
};
|
||||
39
server/src/internal/migrations/v2/repos/findMigration.ts
Normal file
39
server/src/internal/migrations/v2/repos/findMigration.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { ErrCode, type Migration, RecaseError } from "@autumn/shared";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import type { RepoContext } from "@/db/repoContext.js";
|
||||
|
||||
/**
|
||||
* Single-row lookup by user `id` (or `internal_id`), scoped to the
|
||||
* current org + env. Throws `MigrationNotFound` if missing — callers
|
||||
* that need a nullable result use `migrationRepo.get(...)` instead.
|
||||
*/
|
||||
export const findMigration = async ({
|
||||
ctx,
|
||||
id,
|
||||
internalId,
|
||||
}: {
|
||||
ctx: RepoContext;
|
||||
id?: string;
|
||||
internalId?: string;
|
||||
}): Promise<Migration> => {
|
||||
if (!id && !internalId)
|
||||
throw new Error("findMigration: pass either `id` or `internalId`");
|
||||
|
||||
const row = await ctx.db.query.migrations.findFirst({
|
||||
where: (m) =>
|
||||
and(
|
||||
eq(m.org_id, ctx.org.id),
|
||||
eq(m.env, ctx.env),
|
||||
id !== undefined ? eq(m.id, id) : eq(m.internal_id, internalId!),
|
||||
),
|
||||
});
|
||||
|
||||
if (!row)
|
||||
throw new RecaseError({
|
||||
message: `Migration ${id ?? internalId} not found`,
|
||||
code: ErrCode.MigrationNotFound,
|
||||
statusCode: 404,
|
||||
});
|
||||
|
||||
return row;
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import { deleteMigration } from "./deleteMigration.js";
|
||||
import { findMigration } from "./findMigration.js";
|
||||
import { getMigration } from "./getMigration.js";
|
||||
import { insertMigration } from "./insertMigration.js";
|
||||
import { updateMigration } from "./updateMigration.js";
|
||||
@@ -5,5 +7,7 @@ import { updateMigration } from "./updateMigration.js";
|
||||
export const migrationRepo = {
|
||||
insert: insertMigration,
|
||||
get: getMigration,
|
||||
find: findMigration,
|
||||
update: updateMigration,
|
||||
delete: deleteMigration,
|
||||
};
|
||||
|
||||
4
server/src/internal/migrations/v2/run/index.ts
Normal file
4
server/src/internal/migrations/v2/run/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./orchestrators/index.js";
|
||||
export * from "./perItem/index.js";
|
||||
export * from "./runMigration.js";
|
||||
export * from "./types/index.js";
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./iterateScope.js";
|
||||
export * from "./runPreparation.js";
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { RunScopeItem } from "../types/runScope.js";
|
||||
|
||||
export type IterateScopeItemResult<T> =
|
||||
| { status: "ok"; item: RunScopeItem; value: T }
|
||||
| { status: "failed"; item: RunScopeItem; error: Error };
|
||||
|
||||
export type IterateScopeSummary<T> = {
|
||||
processed: number;
|
||||
succeeded: number;
|
||||
failed: number;
|
||||
results: IterateScopeItemResult<T>[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic iteration over any kind-tagged scope iterator. Calls `perItem`
|
||||
* for every item, collecting per-item results into a summary. Sequential
|
||||
* by default; concurrency layer is intentionally out of scope here.
|
||||
*
|
||||
* On error: keeps going with `onError: "continue"` (default), or rethrows
|
||||
* the first error with `onError: "throw"`. Either way every visited
|
||||
* item shows up in `results` so callers see the full audit trail.
|
||||
*/
|
||||
export const iterateScope = async <T>({
|
||||
iterate,
|
||||
perItem,
|
||||
onError = "continue",
|
||||
}: {
|
||||
iterate: () => AsyncGenerator<RunScopeItem[]>;
|
||||
perItem: (item: RunScopeItem) => Promise<T>;
|
||||
onError?: "throw" | "continue";
|
||||
}): Promise<IterateScopeSummary<T>> => {
|
||||
const results: IterateScopeItemResult<T>[] = [];
|
||||
let succeeded = 0;
|
||||
let failed = 0;
|
||||
|
||||
for await (const batch of iterate()) {
|
||||
for (const item of batch) {
|
||||
try {
|
||||
const value = await perItem(item);
|
||||
results.push({ status: "ok", item, value });
|
||||
succeeded++;
|
||||
} catch (raw) {
|
||||
const error = raw instanceof Error ? raw : new Error(String(raw));
|
||||
results.push({ status: "failed", item, error });
|
||||
failed++;
|
||||
if (onError === "throw") throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { processed: succeeded + failed, succeeded, failed, results };
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { AutumnContext } from "../../../../../honoUtils/HonoEnv.js";
|
||||
import { runPrepare } from "../../prepare/runPrepare.js";
|
||||
import type {
|
||||
PreparedState,
|
||||
PrepareResponse,
|
||||
} from "../../prepare/types/index.js";
|
||||
|
||||
/**
|
||||
* Run-phase wrapper around the prepare orchestrator. Returns the
|
||||
* freshly written `prepared_state` so per-item handlers can read it
|
||||
* without re-fetching the migration row.
|
||||
*
|
||||
* On `dry_run: true` this still computes and returns the planned
|
||||
* `prepared_state` shape (so dry-run end-to-end can show what each
|
||||
* customer would see) — but the migrations row is not updated.
|
||||
*/
|
||||
export const runPreparation = async ({
|
||||
ctx,
|
||||
migration,
|
||||
dry_run,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
dry_run: boolean;
|
||||
}): Promise<{ response: PrepareResponse; prepared_state: PreparedState }> =>
|
||||
runPrepare({ ctx, migration, dry_run });
|
||||
105
server/src/internal/migrations/v2/run/perItem/applyAddItem.ts
Normal file
105
server/src/internal/migrations/v2/run/perItem/applyAddItem.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { CreatePlanItemParamsV1, FullCusProduct } from "@autumn/shared";
|
||||
import { customerEntitlements } from "@autumn/shared";
|
||||
import { inArray } from "drizzle-orm";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import { CusEntService } from "@/internal/customers/cusProducts/cusEnts/CusEntitlementService.js";
|
||||
import type { EnsurePricesAndEntitlementsResult } from "@/internal/migrations/v2/prepare/modules/ensurePricesAndEntitlements/types.js";
|
||||
import type { PreparedState } from "@/internal/migrations/v2/prepare/types/index.js";
|
||||
|
||||
export type ApplyAddItemResult =
|
||||
| { status: "added"; customer_entitlement_id: string }
|
||||
| { status: "already_present"; customer_entitlement_id: string }
|
||||
| {
|
||||
status: "skipped";
|
||||
reason: "no_prepared_entitlement" | "priced_item_unsupported";
|
||||
};
|
||||
|
||||
/** Customer-entitlement deterministic ID per (scope, cusproduct, entitlement). */
|
||||
const customerEntitlementIdFor = ({
|
||||
scopeId,
|
||||
cusProductInternalId,
|
||||
entitlementId,
|
||||
}: {
|
||||
scopeId: string;
|
||||
cusProductInternalId: string;
|
||||
entitlementId: string;
|
||||
}): string => `cusent_${scopeId}_${cusProductInternalId}_${entitlementId}`;
|
||||
|
||||
/**
|
||||
* Apply ONE add_item to ONE matched cusproduct. Phase 1 handles
|
||||
* entitlement-only items; priced items will route through the same
|
||||
* flow once `ensurePricesAndEntitlements` provisions Stripe prices.
|
||||
*/
|
||||
export const applyAddItem = async ({
|
||||
ctx,
|
||||
scope_id,
|
||||
cusProduct,
|
||||
addItem,
|
||||
prepared_state,
|
||||
dry_run,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
scope_id: string;
|
||||
cusProduct: FullCusProduct;
|
||||
addItem: CreatePlanItemParamsV1;
|
||||
prepared_state: PreparedState;
|
||||
dry_run: boolean;
|
||||
}): Promise<ApplyAddItemResult> => {
|
||||
if (addItem.price)
|
||||
return { status: "skipped", reason: "priced_item_unsupported" };
|
||||
if (!addItem.feature_id)
|
||||
return { status: "skipped", reason: "no_prepared_entitlement" };
|
||||
|
||||
// Look up the prepared entitlement for (feature, target plan) keyed
|
||||
// `ensure_prices_and_entitlements:<feature_id>:<plan_id>`. The
|
||||
// matching `entitlement_id` is whichever ref points at this
|
||||
// cusproduct's product version.
|
||||
const stateKey = `ensure_prices_and_entitlements:${addItem.feature_id}:${cusProduct.product_id}`;
|
||||
const slot = prepared_state[stateKey] as
|
||||
| EnsurePricesAndEntitlementsResult
|
||||
| undefined;
|
||||
const ref = slot?.entitlements.find(
|
||||
(e) => e.product_internal_id === cusProduct.internal_product_id,
|
||||
);
|
||||
if (!ref) return { status: "skipped", reason: "no_prepared_entitlement" };
|
||||
|
||||
const customerEntitlementId = customerEntitlementIdFor({
|
||||
scopeId: scope_id,
|
||||
cusProductInternalId: cusProduct.id,
|
||||
entitlementId: ref.entitlement_id,
|
||||
});
|
||||
|
||||
const existing = await ctx.db
|
||||
.select({ id: customerEntitlements.id })
|
||||
.from(customerEntitlements)
|
||||
.where(inArray(customerEntitlements.id, [customerEntitlementId]));
|
||||
if (existing.length > 0)
|
||||
return {
|
||||
status: "already_present",
|
||||
customer_entitlement_id: customerEntitlementId,
|
||||
};
|
||||
|
||||
if (dry_run)
|
||||
return { status: "added", customer_entitlement_id: customerEntitlementId };
|
||||
|
||||
await CusEntService.insert({
|
||||
ctx,
|
||||
data: [
|
||||
{
|
||||
id: customerEntitlementId,
|
||||
customer_product_id: cusProduct.id,
|
||||
entitlement_id: ref.entitlement_id,
|
||||
internal_customer_id: cusProduct.internal_customer_id,
|
||||
internal_feature_id: ref.internal_feature_id,
|
||||
feature_id: ref.feature_id,
|
||||
customer_id: cusProduct.customer_id ?? null,
|
||||
balance: 0,
|
||||
created_at: Date.now(),
|
||||
usage_allowed: false,
|
||||
unlimited: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return { status: "added", customer_entitlement_id: customerEntitlementId };
|
||||
};
|
||||
4
server/src/internal/migrations/v2/run/perItem/index.ts
Normal file
4
server/src/internal/migrations/v2/run/perItem/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./applyAddItem.js";
|
||||
export * from "./matchPlanFilter.js";
|
||||
export * from "./matchStringMatcher.js";
|
||||
export * from "./runOpsForCustomer.js";
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { FullCusProduct, PlanFilter } from "@autumn/shared";
|
||||
import { matchStringMatcher } from "./matchStringMatcher.js";
|
||||
|
||||
/**
|
||||
* JS-side PlanFilter matcher against a single FullCusProduct. Phase 1
|
||||
* supports `plan_id` only — `price`, `paid`, `recurring`, `item`, `$or`
|
||||
* throw `not_supported_in_matcher` so callers see the gap explicitly.
|
||||
*/
|
||||
export const matchPlanFilter = (
|
||||
filter: PlanFilter,
|
||||
cusProduct: FullCusProduct,
|
||||
): boolean => {
|
||||
if (filter.plan_id !== undefined) {
|
||||
if (!matchStringMatcher(filter.plan_id, cusProduct.product_id))
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsupported = ["price", "paid", "recurring", "item", "$or"] as const;
|
||||
for (const key of unsupported) {
|
||||
if ((filter as Record<string, unknown>)[key] !== undefined)
|
||||
throw new Error(
|
||||
`matchPlanFilter: target.${key} not supported in JS matcher yet`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/** Returns the cusproducts on a customer that match `target`. */
|
||||
export const matchCustomerProductsByTarget = ({
|
||||
cusProducts,
|
||||
target,
|
||||
}: {
|
||||
cusProducts: FullCusProduct[];
|
||||
target: PlanFilter;
|
||||
}): FullCusProduct[] => cusProducts.filter((cp) => matchPlanFilter(target, cp));
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { StringMatcher } from "@autumn/shared";
|
||||
|
||||
/** Phase 1 ops only: bare value, $eq, $ne, $in, $nin. */
|
||||
export const matchStringMatcher = (
|
||||
matcher: StringMatcher | undefined,
|
||||
value: string | null | undefined,
|
||||
): boolean => {
|
||||
if (matcher === undefined) return true;
|
||||
if (matcher === null) return value === null || value === undefined;
|
||||
if (typeof matcher === "string") return value === matcher;
|
||||
|
||||
if ("$eq" in matcher && matcher.$eq !== undefined) {
|
||||
if (matcher.$eq === null) return value === null || value === undefined;
|
||||
if (value !== matcher.$eq) return false;
|
||||
}
|
||||
if ("$ne" in matcher && matcher.$ne !== undefined) {
|
||||
if (matcher.$ne === null) {
|
||||
if (value === null || value === undefined) return false;
|
||||
} else if (value === matcher.$ne) return false;
|
||||
}
|
||||
if (matcher.$in && !matcher.$in.includes(value ?? "")) return false;
|
||||
if (matcher.$nin && matcher.$nin.includes(value ?? "")) return false;
|
||||
|
||||
const unsupported = ["$regex", "$startsWith"] as const;
|
||||
for (const op of unsupported) {
|
||||
if (op in matcher && (matcher as Record<string, unknown>)[op] !== undefined)
|
||||
throw new Error(
|
||||
`matchStringMatcher: operator ${op} not supported in JS matcher yet`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { Operations } from "@autumn/shared";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import { CusService } from "@/internal/customers/CusService.js";
|
||||
import type { PreparedState } from "@/internal/migrations/v2/prepare/types/index.js";
|
||||
import { type ApplyAddItemResult, applyAddItem } from "./applyAddItem.js";
|
||||
import { matchCustomerProductsByTarget } from "./matchPlanFilter.js";
|
||||
|
||||
export type RunOpsForCustomerResult = {
|
||||
internal_customer_id: string;
|
||||
matched_cusproducts: number;
|
||||
add_items: ApplyAddItemResult[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Walk a customer's matching cusproducts × the migration's update_plans
|
||||
* × add_items. Phase 1 only — delete_items + priced add_items will be
|
||||
* routed in here as their handlers ship.
|
||||
*/
|
||||
export const runOpsForCustomer = async ({
|
||||
ctx,
|
||||
scope_id,
|
||||
internal_customer_id,
|
||||
operations,
|
||||
prepared_state,
|
||||
dry_run,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
scope_id: string;
|
||||
internal_customer_id: string;
|
||||
operations: Operations;
|
||||
prepared_state: PreparedState;
|
||||
dry_run: boolean;
|
||||
}): Promise<RunOpsForCustomerResult> => {
|
||||
const fullCustomer = await CusService.getFull({
|
||||
ctx,
|
||||
idOrInternalId: internal_customer_id,
|
||||
});
|
||||
|
||||
const updatePlans = operations.customer?.update_plans ?? [];
|
||||
let matched = 0;
|
||||
const addItemResults: ApplyAddItemResult[] = [];
|
||||
|
||||
for (const op of updatePlans) {
|
||||
const cps = matchCustomerProductsByTarget({
|
||||
cusProducts: fullCustomer.customer_products,
|
||||
target: op.target,
|
||||
});
|
||||
matched += cps.length;
|
||||
|
||||
for (const cusProduct of cps) {
|
||||
for (const addItem of op.add_items ?? []) {
|
||||
const result = await applyAddItem({
|
||||
ctx,
|
||||
scope_id,
|
||||
cusProduct,
|
||||
addItem,
|
||||
prepared_state,
|
||||
dry_run,
|
||||
});
|
||||
addItemResults.push(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
internal_customer_id,
|
||||
matched_cusproducts: matched,
|
||||
add_items: addItemResults,
|
||||
};
|
||||
};
|
||||
74
server/src/internal/migrations/v2/run/runMigration.ts
Normal file
74
server/src/internal/migrations/v2/run/runMigration.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import type { Migration, Operations } from "@autumn/shared";
|
||||
import type { AutumnContext } from "../../../../honoUtils/HonoEnv.js";
|
||||
import { runFilter } from "../filters/runFilter.js";
|
||||
import { iterateScope, runPreparation } from "./orchestrators/index.js";
|
||||
import { runOpsForCustomer } from "./perItem/runOpsForCustomer.js";
|
||||
import type {
|
||||
RunMigrationResponse,
|
||||
RunMigrationScopeResult,
|
||||
} from "./types/runMigrationResponse.js";
|
||||
import type { RunScopeKind } from "./types/runScope.js";
|
||||
|
||||
/** Top-level migration run: prepare → per-scope filter+iterate → per-item ops. */
|
||||
export const runMigration = async ({
|
||||
ctx,
|
||||
migration,
|
||||
dry_run,
|
||||
}: {
|
||||
ctx: AutumnContext;
|
||||
migration: Migration;
|
||||
dry_run: boolean;
|
||||
}): Promise<RunMigrationResponse> => {
|
||||
const { response: prepareResponse, prepared_state } = await runPreparation({
|
||||
ctx,
|
||||
migration,
|
||||
dry_run,
|
||||
});
|
||||
|
||||
const scope_id = `mig_${migration.internal_id}`;
|
||||
const operations: Operations = migration.operations ?? {};
|
||||
|
||||
const scopeResults: RunMigrationScopeResult[] = [];
|
||||
|
||||
for (const kind of scopesForRun(migration)) {
|
||||
const { count, iterate } = await runFilter({ ctx, migration, kind });
|
||||
ctx.logger.info(`run-migration: iterating scope`, {
|
||||
data: { kind, count, dry_run },
|
||||
});
|
||||
|
||||
const summary = await iterateScope({
|
||||
iterate,
|
||||
perItem: async (item) => {
|
||||
if (item.kind !== "customer")
|
||||
throw new Error(
|
||||
`runMigration: per-item handler missing for kind "${item.kind}"`,
|
||||
);
|
||||
return runOpsForCustomer({
|
||||
ctx,
|
||||
scope_id,
|
||||
internal_customer_id: item.internal_id,
|
||||
operations,
|
||||
prepared_state,
|
||||
dry_run,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
scopeResults.push({ kind, count, summary });
|
||||
}
|
||||
|
||||
return {
|
||||
migration_id: migration.id,
|
||||
dry_run,
|
||||
prepare_warnings: prepareResponse.warnings,
|
||||
scopes: scopeResults,
|
||||
};
|
||||
};
|
||||
|
||||
/** Active scopes = top-level keys present in `migration.operations`. */
|
||||
const scopesForRun = (migration: Migration): RunScopeKind[] => {
|
||||
const scopes: RunScopeKind[] = [];
|
||||
if (migration.operations?.customer) scopes.push("customer");
|
||||
// future: if (migration.operations?.plan) scopes.push("plan");
|
||||
return scopes;
|
||||
};
|
||||
2
server/src/internal/migrations/v2/run/types/index.ts
Normal file
2
server/src/internal/migrations/v2/run/types/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./runMigrationResponse.js";
|
||||
export * from "./runScope.js";
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { IterateScopeSummary } from "../orchestrators/iterateScope.js";
|
||||
import type { RunOpsForCustomerResult } from "../perItem/runOpsForCustomer.js";
|
||||
import type { RunScopeKind } from "./runScope.js";
|
||||
|
||||
/** One scope's portion of a run — kind-tagged for phase-2 multi-scope. */
|
||||
export type RunMigrationScopeResult = {
|
||||
kind: RunScopeKind;
|
||||
count: number;
|
||||
summary: IterateScopeSummary<RunOpsForCustomerResult>;
|
||||
};
|
||||
|
||||
export type RunMigrationResponse = {
|
||||
migration_id: string;
|
||||
dry_run: boolean;
|
||||
prepare_warnings: string[];
|
||||
scopes: RunMigrationScopeResult[];
|
||||
};
|
||||
9
server/src/internal/migrations/v2/run/types/runScope.ts
Normal file
9
server/src/internal/migrations/v2/run/types/runScope.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/** Resource kind being iterated. Phase 2+ adds catalog-rooted kinds. */
|
||||
export type RunScopeKind = "customer" | "plan";
|
||||
|
||||
/** One iterated item, kind-tagged for generic dispatch. */
|
||||
export type RunScopeItem = {
|
||||
kind: RunScopeKind;
|
||||
internal_id: string;
|
||||
id: string | null;
|
||||
};
|
||||
18
server/src/trigger/configureTrigger.ts
Normal file
18
server/src/trigger/configureTrigger.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { configure } from "@trigger.dev/sdk/v3";
|
||||
|
||||
/**
|
||||
* Point the trigger.dev SDK at autumn's project key.
|
||||
*
|
||||
* autumn and autumn-cloud each have their own trigger.dev project. We
|
||||
* keep autumn's secret under `TRIGGER_SERVER_SECRET_KEY` so the two
|
||||
* never collide in a shared shell — the SDK's default `TRIGGER_SECRET_KEY`
|
||||
* is left to autumn-cloud.
|
||||
*
|
||||
* Module side-effect: this `configure` call runs once on first import.
|
||||
* Anything that triggers tasks server-side imports from
|
||||
* `@/trigger/migrations/...`, which re-exports from this file's siblings,
|
||||
* so the configure happens before any `.trigger()` call.
|
||||
*/
|
||||
if (process.env.TRIGGER_SERVER_SECRET_KEY) {
|
||||
configure({ secretKey: process.env.TRIGGER_SERVER_SECRET_KEY });
|
||||
}
|
||||
52
server/src/trigger/migrations/runMigrationTask.ts
Normal file
52
server/src/trigger/migrations/runMigrationTask.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { AppEnv } from "@autumn/shared";
|
||||
import { task } from "@trigger.dev/sdk/v3";
|
||||
import { z } from "zod/v4";
|
||||
import { migrationRepo } from "@/internal/migrations/v2/repos/index.js";
|
||||
import { runMigration } from "@/internal/migrations/v2/run/runMigration.js";
|
||||
import { createTriggerContext } from "@/trigger/utils/createTriggerContext.js";
|
||||
|
||||
const PayloadSchema = z.object({
|
||||
orgId: z.string(),
|
||||
env: z.enum(AppEnv),
|
||||
migrationId: z.string(),
|
||||
dryRun: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export type RunMigrationPayload = z.infer<typeof PayloadSchema>;
|
||||
|
||||
/** trigger.dev task for long-running migrations (deploys kill api workers). */
|
||||
export const runMigrationTask = task({
|
||||
id: "run-migration",
|
||||
maxDuration: 3600,
|
||||
run: async (rawPayload: unknown, { ctx: triggerCtx }) => {
|
||||
const { orgId, env, migrationId, dryRun } = PayloadSchema.parse(rawPayload);
|
||||
|
||||
const { ctx, logger } = await createTriggerContext({
|
||||
orgId,
|
||||
env,
|
||||
triggerCtx,
|
||||
});
|
||||
|
||||
logger.info("run-migration: starting", {
|
||||
data: { migrationId, dryRun },
|
||||
});
|
||||
|
||||
const migration = await migrationRepo.find({ ctx, id: migrationId });
|
||||
|
||||
const result = await runMigration({ ctx, migration, dry_run: dryRun });
|
||||
|
||||
logger.info("run-migration: done", {
|
||||
data: {
|
||||
migration_id: result.migration_id,
|
||||
dry_run: result.dry_run,
|
||||
scopes: result.scopes.map((s) => ({
|
||||
kind: s.kind,
|
||||
count: s.count,
|
||||
succeeded: s.summary.succeeded,
|
||||
failed: s.summary.failed,
|
||||
})),
|
||||
},
|
||||
});
|
||||
return result;
|
||||
},
|
||||
});
|
||||
46
server/src/trigger/utils/createTriggerContext.ts
Normal file
46
server/src/trigger/utils/createTriggerContext.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { AppEnv } from "@autumn/shared";
|
||||
import type { Context as TriggerRunContext } from "@trigger.dev/sdk/v3";
|
||||
import { db } from "@/db/initDrizzle.js";
|
||||
import {
|
||||
createDualLogger,
|
||||
type Logger,
|
||||
} from "@/external/logtail/logtailUtils.js";
|
||||
import type { AutumnContext } from "@/honoUtils/HonoEnv.js";
|
||||
import { createWorkerContext } from "@/queue/createWorkerContext.js";
|
||||
import { addTriggerToLogs } from "@/utils/logging/addContextToLogs.js";
|
||||
|
||||
/**
|
||||
* Build an `AutumnContext` for a trigger.dev task run. Uses the dual
|
||||
* logger (stdout + axiom) and tags every line with run/task/attempt ids.
|
||||
*/
|
||||
export const createTriggerContext = async ({
|
||||
orgId,
|
||||
env,
|
||||
triggerCtx,
|
||||
}: {
|
||||
orgId: string;
|
||||
env: AppEnv;
|
||||
triggerCtx: TriggerRunContext;
|
||||
}): Promise<{ ctx: AutumnContext; logger: Logger }> => {
|
||||
const logger = addTriggerToLogs({
|
||||
logger: createDualLogger(),
|
||||
triggerContext: {
|
||||
run_id: triggerCtx.run.id,
|
||||
task_id: triggerCtx.task.id,
|
||||
attempt_number: triggerCtx.attempt.number,
|
||||
},
|
||||
});
|
||||
|
||||
const ctx = await createWorkerContext({
|
||||
db,
|
||||
payload: { orgId, env, requestId: triggerCtx.run.id },
|
||||
logger,
|
||||
});
|
||||
|
||||
if (!ctx)
|
||||
throw new Error(
|
||||
`createTriggerContext: failed to build context for org=${orgId} env=${env}`,
|
||||
);
|
||||
|
||||
return { ctx, logger };
|
||||
};
|
||||
1
server/src/trigger/utils/index.ts
Normal file
1
server/src/trigger/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./createTriggerContext.js";
|
||||
@@ -1,17 +1,36 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { config } from "dotenv";
|
||||
|
||||
let hasLoadedLocalEnv = false;
|
||||
const shouldLogLocalEnvLoading = false;
|
||||
|
||||
/**
|
||||
* Resolve the directory holding `.env`, robust to cwd:
|
||||
* - cwd already a `server/` dir
|
||||
* - cwd is `autumn/` (typical workspace root)
|
||||
* - cwd is the monorepo root (one level above `autumn/`) — happens with
|
||||
* `bun test autumn/...` invocations from VSCode tasks
|
||||
*/
|
||||
const resolveServerDir = (): string => {
|
||||
const cwd = process.cwd();
|
||||
const candidates = [
|
||||
cwd,
|
||||
join(cwd, "server"),
|
||||
join(cwd, "autumn", "server"),
|
||||
];
|
||||
for (const dir of candidates) {
|
||||
if (existsSync(join(dir, "package.json"))) return dir;
|
||||
}
|
||||
// Fall back to first guess so dotenv silently no-ops if missing.
|
||||
return cwd.includes("server") ? cwd : join(cwd, "server");
|
||||
};
|
||||
|
||||
export const loadLocalEnv = ({ force = false }: { force?: boolean } = {}) => {
|
||||
if (hasLoadedLocalEnv && !force) return;
|
||||
hasLoadedLocalEnv = true;
|
||||
|
||||
const processDir = process.cwd();
|
||||
const serverDir = processDir.includes("server")
|
||||
? processDir
|
||||
: join(processDir, "server");
|
||||
const serverDir = resolveServerDir();
|
||||
|
||||
// Determine which env file to load based on ENV_FILE environment variable
|
||||
// Defaults to .env if not specified
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
LogRedisData,
|
||||
LogRequestContext,
|
||||
LogStripeEventContext,
|
||||
LogTriggerContext,
|
||||
LogWorkflowContext,
|
||||
} from "./loggerTypes.js";
|
||||
|
||||
@@ -47,6 +48,16 @@ export const addWorkflowToLogs = ({
|
||||
return logger.child({ context: { workflow: workflowContext } });
|
||||
};
|
||||
|
||||
export const addTriggerToLogs = ({
|
||||
logger,
|
||||
triggerContext,
|
||||
}: {
|
||||
logger: Logger;
|
||||
triggerContext: LogTriggerContext;
|
||||
}): Logger => {
|
||||
return logger.child({ context: { trigger: triggerContext } });
|
||||
};
|
||||
|
||||
export const addRedisToLogs = ({
|
||||
logger,
|
||||
redisData,
|
||||
|
||||
@@ -2,58 +2,84 @@ import { Writable } from "node:stream";
|
||||
import pino from "pino";
|
||||
import { getAwsTaskIdentity } from "@/external/aws/ecs/awsTaskIdentity.js";
|
||||
|
||||
// Custom log formatter for Bun compatibility
|
||||
const createDevLogStream = () => {
|
||||
const colors = {
|
||||
reset: "\x1b[0m",
|
||||
bright: "\x1b[1m",
|
||||
dim: "\x1b[2m",
|
||||
red: "\x1b[31m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
blue: "\x1b[34m",
|
||||
magenta: "\x1b[35m",
|
||||
cyan: "\x1b[36m",
|
||||
white: "\x1b[37m",
|
||||
gray: "\x1b[90m",
|
||||
bgRed: "\x1b[41m",
|
||||
};
|
||||
/**
|
||||
* Fields that don't render in the formatted dev/local console output
|
||||
* (they still go to JSON sinks). Trim noise like trigger metadata,
|
||||
* request envelopes, and high-cardinality structured data.
|
||||
*/
|
||||
const FORMATTED_LOG_EXCLUDE_FIELDS = new Set([
|
||||
// pino housekeeping
|
||||
"time",
|
||||
"level",
|
||||
"msg",
|
||||
"pid",
|
||||
"hostname",
|
||||
// request / response envelopes
|
||||
"req",
|
||||
"res",
|
||||
"statusCode",
|
||||
"body",
|
||||
"query",
|
||||
"durationMs",
|
||||
// app-context blocks (added via `addContextToLogs`)
|
||||
"context",
|
||||
"workflow",
|
||||
"trigger",
|
||||
"stripe_event",
|
||||
"worker",
|
||||
"extras",
|
||||
"type",
|
||||
// structured payloads
|
||||
"data",
|
||||
// AWS task identity (mixin)
|
||||
"aws",
|
||||
]);
|
||||
|
||||
const levelColors: Record<number | string, string> = {
|
||||
// Numeric levels
|
||||
10: colors.gray, // trace
|
||||
20: colors.blue, // debug
|
||||
30: colors.green, // info
|
||||
40: colors.yellow, // warn
|
||||
50: colors.red, // error
|
||||
60: colors.bgRed, // fatal
|
||||
// String levels
|
||||
TRACE: colors.gray,
|
||||
DEBUG: colors.blue,
|
||||
INFO: colors.green,
|
||||
WARN: colors.yellow,
|
||||
ERROR: colors.red,
|
||||
FATAL: colors.bgRed,
|
||||
};
|
||||
const colors = {
|
||||
reset: "\x1b[0m",
|
||||
bright: "\x1b[1m",
|
||||
red: "\x1b[31m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
blue: "\x1b[34m",
|
||||
white: "\x1b[37m",
|
||||
gray: "\x1b[90m",
|
||||
bgRed: "\x1b[41m",
|
||||
};
|
||||
|
||||
const levelNames: Record<number | string, string> = {
|
||||
// Numeric levels
|
||||
10: "TRACE",
|
||||
20: "DEBUG",
|
||||
30: "INFO",
|
||||
40: "WARN",
|
||||
50: "ERROR",
|
||||
60: "FATAL",
|
||||
// String levels (pass through)
|
||||
TRACE: "TRACE",
|
||||
DEBUG: "DEBUG",
|
||||
INFO: "INFO",
|
||||
WARN: "WARN",
|
||||
ERROR: "ERROR",
|
||||
FATAL: "FATAL",
|
||||
};
|
||||
const levelColors: Record<number | string, string> = {
|
||||
10: colors.gray,
|
||||
20: colors.blue,
|
||||
30: colors.green,
|
||||
40: colors.yellow,
|
||||
50: colors.red,
|
||||
60: colors.bgRed,
|
||||
TRACE: colors.gray,
|
||||
DEBUG: colors.blue,
|
||||
INFO: colors.green,
|
||||
WARN: colors.yellow,
|
||||
ERROR: colors.red,
|
||||
FATAL: colors.bgRed,
|
||||
};
|
||||
|
||||
return new Writable({
|
||||
const levelNames: Record<number | string, string> = {
|
||||
10: "TRACE",
|
||||
20: "DEBUG",
|
||||
30: "INFO",
|
||||
40: "WARN",
|
||||
50: "ERROR",
|
||||
60: "FATAL",
|
||||
TRACE: "TRACE",
|
||||
DEBUG: "DEBUG",
|
||||
INFO: "INFO",
|
||||
WARN: "WARN",
|
||||
ERROR: "ERROR",
|
||||
FATAL: "FATAL",
|
||||
};
|
||||
|
||||
/** Bun-friendly pino sink that prints `<ts> <LEVEL> <msg> <extras>`. */
|
||||
const createDevLogStream = () =>
|
||||
new Writable({
|
||||
write(chunk, _encoding, callback) {
|
||||
try {
|
||||
const log = JSON.parse(chunk.toString());
|
||||
@@ -66,44 +92,22 @@ const createDevLogStream = () => {
|
||||
const levelName =
|
||||
levelNames[level] || (typeof level === "string" ? level : "UNKNOWN");
|
||||
|
||||
// Format the message
|
||||
let message = log.msg || "";
|
||||
|
||||
// Add any additional fields (excluding standard pino fields)
|
||||
const excludeFields = [
|
||||
"time",
|
||||
"level",
|
||||
"msg",
|
||||
"pid",
|
||||
"hostname",
|
||||
"res",
|
||||
"statusCode",
|
||||
"worker",
|
||||
"context",
|
||||
"req",
|
||||
"data",
|
||||
"body",
|
||||
"query",
|
||||
|
||||
"workflow",
|
||||
"stripe_event",
|
||||
"extras",
|
||||
"type",
|
||||
|
||||
"durationMs",
|
||||
];
|
||||
const additionalFields = Object.keys(log)
|
||||
.filter((key) => !excludeFields.includes(key))
|
||||
.reduce((acc, key) => {
|
||||
acc[key] = log[key];
|
||||
return acc;
|
||||
}, {} as any);
|
||||
.filter((key) => !FORMATTED_LOG_EXCLUDE_FIELDS.has(key))
|
||||
.reduce(
|
||||
(acc, key) => {
|
||||
acc[key] = log[key];
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, unknown>,
|
||||
);
|
||||
|
||||
if (Object.keys(additionalFields).length > 0) {
|
||||
message += ` ${JSON.stringify(additionalFields, null, 2)}`;
|
||||
}
|
||||
|
||||
// Format the final log line
|
||||
const formattedLog = `${colors.gray}${timestamp}${colors.reset} ${levelColor}${colors.bright}${levelName}${colors.reset} ${message}\n`;
|
||||
|
||||
process.stdout.write(formattedLog);
|
||||
@@ -115,47 +119,79 @@ const createDevLogStream = () => {
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* `mode: "dual"` is opt-in only — used by trigger.dev tasks so logs hit
|
||||
* both stdout (trigger run UI) and axiom (long-term store).
|
||||
*
|
||||
* In dev/test the stdout stream uses the formatted dev sink so trigger
|
||||
* pane lines look like server lines. In prod it stays raw JSON so
|
||||
* trigger.dev's cloud UI gets structured logs.
|
||||
*
|
||||
* `mode: "default"` preserves existing prod behavior verbatim.
|
||||
*/
|
||||
export type InitLoggerOptions = {
|
||||
mode?: "default" | "dual";
|
||||
};
|
||||
|
||||
export const initLogger = () => {
|
||||
// Create separate streams for console and HyperDX
|
||||
const streams: pino.StreamEntry[] = [];
|
||||
export const initLogger = (options: InitLoggerOptions = {}) => {
|
||||
const { mode = "default" } = options;
|
||||
|
||||
const streams: pino.StreamEntry[] = [];
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const isTest = process.env.NODE_ENV === "test";
|
||||
const isDevOrTest = isDev || isTest;
|
||||
|
||||
// Enable dev logging for development OR test environments
|
||||
if (isDev || isTest) {
|
||||
if (mode === "dual") {
|
||||
streams.push({
|
||||
level: "debug",
|
||||
stream: createDevLogStream(),
|
||||
level: isDevOrTest ? "debug" : "info",
|
||||
stream: isDevOrTest ? createDevLogStream() : process.stdout,
|
||||
});
|
||||
}
|
||||
if (process.env.AXIOM_TOKEN) {
|
||||
streams.push({
|
||||
level: "info",
|
||||
stream: pino.transport({
|
||||
target: "@axiomhq/pino",
|
||||
options: {
|
||||
dataset: "express",
|
||||
token: process.env.AXIOM_TOKEN,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// DEFAULT FLOW — exact prior behavior. DO NOT MODIFY.
|
||||
if (isDev || isTest) {
|
||||
streams.push({
|
||||
level: "debug",
|
||||
stream: createDevLogStream(),
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.AXIOM_TOKEN) {
|
||||
streams.push({
|
||||
level: "info",
|
||||
stream: pino.transport({
|
||||
target: "@axiomhq/pino",
|
||||
options: {
|
||||
dataset: "express",
|
||||
token: process.env.AXIOM_TOKEN,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (process.env.AXIOM_TOKEN) {
|
||||
streams.push({
|
||||
level: "info",
|
||||
stream: pino.transport({
|
||||
target: "@axiomhq/pino",
|
||||
options: {
|
||||
dataset: "express",
|
||||
token: process.env.AXIOM_TOKEN,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// Fallback: if no streams configured, add dev stream anyway
|
||||
if (streams.length === 0) {
|
||||
streams.push({
|
||||
level: "info",
|
||||
stream: createDevLogStream(),
|
||||
});
|
||||
if (streams.length === 0) {
|
||||
streams.push({
|
||||
level: "info",
|
||||
stream: createDevLogStream(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const logger = pino(
|
||||
{
|
||||
level: isDev || isTest ? "debug" : "info",
|
||||
level: isDev || isTest || mode === "dual" ? "debug" : "info",
|
||||
// Tag every log line with this process's AWS task identity so Axiom
|
||||
// can distinguish blue/green task sets. Returns {} until
|
||||
// `resolveAwsTaskIdentity` finishes (~100ms after boot) and on
|
||||
@@ -179,7 +215,6 @@ export const initLogger = () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Use multistream to send logs to multiple destinations
|
||||
pino.multistream(streams),
|
||||
);
|
||||
|
||||
|
||||
@@ -52,6 +52,13 @@ export type LogWorkflowContext = {
|
||||
name: string; // workflow / job name
|
||||
};
|
||||
|
||||
/** trigger.dev run context — goes under context.trigger */
|
||||
export type LogTriggerContext = {
|
||||
run_id: string;
|
||||
task_id: string;
|
||||
attempt_number?: number;
|
||||
};
|
||||
|
||||
/** Redis slow-command context - goes under context.redis.data (map field) */
|
||||
export type LogRedisData = {
|
||||
operation: string;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
/**
|
||||
* Migrations V2 — add_items
|
||||
* Migrations V2 — add_items end-to-end (integration).
|
||||
*
|
||||
* Phase 1 acceptance: a user can create a migration definition whose
|
||||
* filter selects customers on a given plan and whose operation adds a
|
||||
* plan item to their matching cusproducts.
|
||||
*
|
||||
* This test only verifies the CREATE path (storing the migration
|
||||
* definition end-to-end). Execution / preview is phase 2+.
|
||||
* Seeds 5 customers, parallel-attaches them all to a `free` product,
|
||||
* creates a migration adding the Dashboard feature, and triggers
|
||||
* `migrations.run`. Verifies the API call dispatches; downstream
|
||||
* trigger.dev side effects are out of scope here.
|
||||
*/
|
||||
|
||||
import { expect, test } from "bun:test";
|
||||
@@ -15,57 +13,56 @@ import { products } from "@tests/utils/fixtures/products";
|
||||
import { initScenario, s } from "@tests/utils/testInitUtils/initScenario";
|
||||
import chalk from "chalk";
|
||||
|
||||
test.concurrent(
|
||||
`${chalk.yellowBright("migrations-v2 add-items: create migration on free customers adding a feature item")}`,
|
||||
async () => {
|
||||
const customerId = "migrations-v2-add-items";
|
||||
test.concurrent(`${chalk.yellowBright("migrations-v2 add-items: triggers run for 5 customers on free")}`, async () => {
|
||||
const customerId = "migration-run-add-items";
|
||||
const otherIds = [1, 2, 3, 4].map((i) => `${customerId}-c${i}`);
|
||||
const free = products.base({ id: "free", items: [], isDefault: true });
|
||||
|
||||
// Default free product so the seeded customer auto-attaches to it.
|
||||
const free = products.base({ id: "free", items: [], isDefault: true });
|
||||
|
||||
const { autumnV2_2 } = await initScenario({
|
||||
const { autumnV1, autumnV2_2, customer, otherCustomers } = await initScenario(
|
||||
{
|
||||
customerId,
|
||||
setup: [
|
||||
s.customer({ paymentMethod: "success" }),
|
||||
s.products({ list: [free] }),
|
||||
s.otherCustomers(
|
||||
otherIds.map((id) => ({ id, paymentMethod: "success" as const })),
|
||||
),
|
||||
],
|
||||
});
|
||||
actions: [],
|
||||
},
|
||||
);
|
||||
|
||||
// migrationId reuses the suffixed customerId so it's unique per concurrent
|
||||
// test run without needing a Date.now() hack.
|
||||
const created = await autumnV2_2.migrationsV2.create({
|
||||
id: customerId,
|
||||
filter: {
|
||||
customer: {
|
||||
plan: { plan_id: free.id },
|
||||
},
|
||||
expect(customer).toBeTruthy();
|
||||
expect(otherCustomers.size).toBe(4);
|
||||
|
||||
// Explicit parallel attach of all 5 customers to free. `free.id` was
|
||||
// mutated by initProductsV0 to include the prefix.
|
||||
const allCustomerIds = [customerId, ...otherIds];
|
||||
await Promise.all(
|
||||
allCustomerIds.map((id) =>
|
||||
autumnV1.attach({ customer_id: id, product_id: free.id }),
|
||||
),
|
||||
);
|
||||
|
||||
await autumnV2_2.migrationsV2.deleteAndCreate({
|
||||
id: customerId,
|
||||
filter: { customer: { plan: { plan_id: free.id } } },
|
||||
operations: {
|
||||
customer: {
|
||||
update_plans: [
|
||||
{
|
||||
target: { plan_id: free.id },
|
||||
add_items: [{ feature_id: TestFeature.Dashboard }],
|
||||
},
|
||||
],
|
||||
},
|
||||
operations: {
|
||||
customer: {
|
||||
update_plans: [
|
||||
{
|
||||
target: { plan_id: free.id },
|
||||
add_items: [
|
||||
{
|
||||
feature_id: TestFeature.Dashboard,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
expect(created.id).toBe(customerId);
|
||||
expect(created.internal_id).toBeTruthy();
|
||||
expect(created.filter?.customer?.plan).toMatchObject({ plan_id: free.id });
|
||||
expect(created.operations?.customer?.update_plans?.[0]).toMatchObject({
|
||||
target: { plan_id: free.id },
|
||||
add_items: [{ feature_id: TestFeature.Dashboard }],
|
||||
});
|
||||
|
||||
// Round-trip: list and confirm presence.
|
||||
const { list } = await autumnV2_2.migrationsV2.list();
|
||||
expect(list.some((m) => m.id === customerId)).toBe(true);
|
||||
},
|
||||
);
|
||||
const runHandle = await autumnV2_2.migrationsV2.run({
|
||||
id: customerId,
|
||||
dry_run: false,
|
||||
});
|
||||
expect(runHandle.run_id).toBeTruthy();
|
||||
expect(runHandle.dry_run).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1094,25 +1094,27 @@ export async function initScenario({
|
||||
customer = result.customer;
|
||||
}
|
||||
|
||||
// 2.5. Other customers — share the primary's test clock.
|
||||
// 2.5. Other customers — share the primary's test clock. Created in
|
||||
// parallel since they're independent (each gets its own Stripe customer);
|
||||
// the shared `testClockId` is read-only here so concurrency is safe.
|
||||
const otherCustomersMap = new Map<string, OtherCustomerResult>();
|
||||
for (const otherCusConfig of config.otherCustomers) {
|
||||
const otherResult = await initCustomerV3({
|
||||
ctx,
|
||||
customerId: otherCusConfig.id,
|
||||
customerData: otherCusConfig.data,
|
||||
attachPm: otherCusConfig.paymentMethod,
|
||||
withTestClock: false,
|
||||
...(testClockId ? { existingTestClockId: testClockId } : {}),
|
||||
withDefault: false,
|
||||
defaultGroup: productPrefix,
|
||||
skipWebhooks: config.skipWebhooks,
|
||||
});
|
||||
otherCustomersMap.set(otherCusConfig.id, {
|
||||
id: otherCusConfig.id,
|
||||
customer: otherResult.customer,
|
||||
});
|
||||
}
|
||||
const otherCustomersResults = await Promise.all(
|
||||
config.otherCustomers.map(async (otherCusConfig) => {
|
||||
const otherResult = await initCustomerV3({
|
||||
ctx,
|
||||
customerId: otherCusConfig.id,
|
||||
customerData: otherCusConfig.data,
|
||||
attachPm: otherCusConfig.paymentMethod,
|
||||
withTestClock: false,
|
||||
...(testClockId ? { existingTestClockId: testClockId } : {}),
|
||||
withDefault: false,
|
||||
defaultGroup: productPrefix,
|
||||
skipWebhooks: config.skipWebhooks,
|
||||
});
|
||||
return { id: otherCusConfig.id, customer: otherResult.customer };
|
||||
}),
|
||||
);
|
||||
for (const r of otherCustomersResults) otherCustomersMap.set(r.id, r);
|
||||
|
||||
// 3. Create autumn clients
|
||||
const autumnV0 = new AutumnInt({
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
import { type SQL, sql } from "drizzle-orm";
|
||||
import type { CustomerFilter } from "../filters/customerFilter.js";
|
||||
import { compileFilter } from "./compileFilter.js";
|
||||
import type { ResolutionContext } from "./filterToIr/resolutionContext.js";
|
||||
|
||||
/**
|
||||
* Top-level query builders for customer-rooted migration filters.
|
||||
*
|
||||
* `compileFilter` returns the full WHERE expression (including org/env
|
||||
* pushdown via the registry's ambient predicates). These helpers wrap it
|
||||
* into a complete, parameterized Drizzle `SQL` with cursor-based
|
||||
* pagination for iteration over large customer sets.
|
||||
*/
|
||||
|
||||
export const DEFAULT_BATCH_SIZE = 10_000;
|
||||
|
||||
/** Convert the compiler's `{ sql, params }` output to a Drizzle SQL chunk. */
|
||||
function rawWithParamsToDrizzle({
|
||||
sql: raw,
|
||||
params,
|
||||
}: {
|
||||
sql: string;
|
||||
params: readonly unknown[];
|
||||
}): SQL {
|
||||
const parts = raw.split("?");
|
||||
if (parts.length - 1 !== params.length)
|
||||
throw new Error(
|
||||
`Placeholder/param count mismatch: ${parts.length - 1} placeholders vs ${params.length} params`,
|
||||
);
|
||||
const chunks: SQL[] = [];
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
chunks.push(sql.raw(parts[i]));
|
||||
if (i < params.length) chunks.push(sql`${params[i]}`);
|
||||
}
|
||||
return sql.join(chunks, sql.raw(""));
|
||||
}
|
||||
|
||||
type BuildArgs = {
|
||||
orgId: string;
|
||||
env: string;
|
||||
filter: CustomerFilter;
|
||||
ctx: ResolutionContext;
|
||||
};
|
||||
|
||||
const compileWhere = ({ orgId, env, filter, ctx }: BuildArgs): SQL =>
|
||||
rawWithParamsToDrizzle(
|
||||
compileFilter({ filter, ctx, ambient: { orgId, env } }),
|
||||
);
|
||||
|
||||
/** Full SELECT. Returns `{ internal_id, id }` rows. */
|
||||
export function buildCustomerSelect({
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
limit,
|
||||
afterInternalId,
|
||||
}: BuildArgs & { limit?: number; afterInternalId?: string }): SQL {
|
||||
const where = compileWhere({ orgId, env, filter, ctx });
|
||||
const cursor = afterInternalId
|
||||
? sql`AND c.internal_id > ${afterInternalId}`
|
||||
: sql``;
|
||||
const limitClause = limit !== undefined ? sql`LIMIT ${limit}` : sql``;
|
||||
return sql`
|
||||
SELECT c.internal_id, c.id
|
||||
FROM customers c
|
||||
WHERE (${where}) ${cursor}
|
||||
ORDER BY c.internal_id
|
||||
${limitClause}
|
||||
`;
|
||||
}
|
||||
|
||||
/** COUNT(*) applying the same filter. */
|
||||
export function buildCustomerCount({
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
}: BuildArgs): SQL {
|
||||
const where = compileWhere({ orgId, env, filter, ctx });
|
||||
return sql`
|
||||
SELECT COUNT(*)::bigint AS count
|
||||
FROM customers c
|
||||
WHERE (${where})
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate matching customers in batches (default 10k per step) using
|
||||
* keyset pagination on `c.internal_id`. Yields one batch at a time so
|
||||
* callers can stream-process without loading the full result set.
|
||||
*/
|
||||
export async function* iterateCustomers({
|
||||
db,
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
batchSize = DEFAULT_BATCH_SIZE,
|
||||
}: BuildArgs & {
|
||||
db: { execute: (query: SQL) => Promise<unknown> };
|
||||
batchSize?: number;
|
||||
}): AsyncGenerator<Array<{ internal_id: string; id: string | null }>> {
|
||||
let cursor: string | undefined;
|
||||
while (true) {
|
||||
const query = buildCustomerSelect({
|
||||
orgId,
|
||||
env,
|
||||
filter,
|
||||
ctx,
|
||||
limit: batchSize,
|
||||
afterInternalId: cursor,
|
||||
});
|
||||
const rows = (await db.execute(query)) as unknown as Array<{
|
||||
internal_id: string;
|
||||
id: string | null;
|
||||
}>;
|
||||
if (rows.length === 0) return;
|
||||
yield rows;
|
||||
if (rows.length < batchSize) return;
|
||||
cursor = rows[rows.length - 1].internal_id;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from "./buildCustomerQuery.js";
|
||||
export * from "./compileFilter.js";
|
||||
export * from "./compilePlanFilter.js";
|
||||
export * from "./filterToIr/index.js";
|
||||
|
||||
@@ -38,6 +38,8 @@ import { migrationErrorRelations } from "../models/migrationModels/migrationErro
|
||||
import { migrationErrors } from "../models/migrationModels/migrationErrorTable.js";
|
||||
// Migration Tables
|
||||
import { migrationJobs } from "../models/migrationModels/migrationJobTable.js";
|
||||
// Migrations V2
|
||||
import { migrations } from "../models/migrationV2Models/migrationTable.js";
|
||||
/* RELATIONS */
|
||||
import { organizationsRelations } from "../models/orgModels/orgRelations.js";
|
||||
import { organizations } from "../models/orgModels/orgTable.js";
|
||||
@@ -88,76 +90,77 @@ import {
|
||||
} from "./auth-schema.js";
|
||||
|
||||
export {
|
||||
// Tables
|
||||
organizations,
|
||||
account,
|
||||
actions,
|
||||
apiKeyRelations,
|
||||
apiKeys,
|
||||
autoTopupLimitStates as autoTopupLimits,
|
||||
chatResults,
|
||||
checkouts,
|
||||
freeTrials,
|
||||
entitlements,
|
||||
prices,
|
||||
features,
|
||||
products,
|
||||
customerProducts,
|
||||
customerPrices,
|
||||
checkoutsRelations,
|
||||
customerEntitlements,
|
||||
invoices,
|
||||
invoiceLineItems,
|
||||
customerEntitlementsRelations,
|
||||
customerPrices,
|
||||
customerPricesRelations,
|
||||
customerProducts,
|
||||
customerProductsRelations,
|
||||
customers,
|
||||
autoTopupLimitStates as autoTopupLimits,
|
||||
customersRelations,
|
||||
entities,
|
||||
apiKeys,
|
||||
metadata,
|
||||
subscriptions,
|
||||
rewards,
|
||||
rewardPrograms,
|
||||
referralCodes,
|
||||
rewardRedemptions,
|
||||
migrationJobs,
|
||||
migrationErrors,
|
||||
actions,
|
||||
entitiesRelations,
|
||||
entitlements,
|
||||
entitlementsRelations,
|
||||
events,
|
||||
replaceables,
|
||||
rollovers,
|
||||
schedules,
|
||||
schedulePhases,
|
||||
vercelResources,
|
||||
revenuecatMappings as revcatMappings,
|
||||
// Auth
|
||||
user,
|
||||
session,
|
||||
account,
|
||||
verification,
|
||||
member,
|
||||
featureRelations,
|
||||
features,
|
||||
freeTrialRelations,
|
||||
freeTrials,
|
||||
invitation,
|
||||
inviteRelations,
|
||||
invoiceLineItems,
|
||||
invoiceRelations,
|
||||
invoices,
|
||||
// OAuth Provider
|
||||
jwks,
|
||||
oauthClient,
|
||||
member,
|
||||
memberRelations,
|
||||
metadata,
|
||||
migrationErrorRelations,
|
||||
migrationErrors,
|
||||
migrationJobs,
|
||||
migrations,
|
||||
oauthAccessToken,
|
||||
oauthRefreshToken,
|
||||
oauthClient,
|
||||
oauthConsent,
|
||||
oauthRefreshToken,
|
||||
// Tables
|
||||
organizations,
|
||||
// Relations
|
||||
organizationsRelations,
|
||||
entitlementsRelations,
|
||||
featureRelations,
|
||||
priceRelations,
|
||||
prices,
|
||||
productRelations,
|
||||
freeTrialRelations,
|
||||
customerProductsRelations,
|
||||
customerPricesRelations,
|
||||
customerEntitlementsRelations,
|
||||
customersRelations,
|
||||
entitiesRelations,
|
||||
apiKeyRelations,
|
||||
rewardProgramRelations,
|
||||
products,
|
||||
referralCodeRelations,
|
||||
rewardRedemptionRelations,
|
||||
migrationErrorRelations,
|
||||
referralCodes,
|
||||
replaceableRelations,
|
||||
invoiceRelations,
|
||||
replaceables,
|
||||
revenuecatMappings as revcatMappings,
|
||||
rewardProgramRelations,
|
||||
rewardPrograms,
|
||||
rewardRedemptionRelations,
|
||||
rewardRedemptions,
|
||||
rewards,
|
||||
rolloverRelations,
|
||||
checkoutsRelations,
|
||||
rollovers,
|
||||
schedulePhases,
|
||||
schedules,
|
||||
session,
|
||||
subscriptions,
|
||||
// Auth
|
||||
user,
|
||||
// Auth Relations
|
||||
userRelations,
|
||||
memberRelations,
|
||||
inviteRelations,
|
||||
vercelResources,
|
||||
verification,
|
||||
};
|
||||
|
||||
78
trigger.config.ts
Normal file
78
trigger.config.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
additionalPackages,
|
||||
aptGet,
|
||||
syncEnvVars,
|
||||
} from "@trigger.dev/build/extensions/core";
|
||||
import { defineConfig } from "@trigger.dev/sdk/v3";
|
||||
import { fetchInfisicalSecretsFromEnv } from "./server/src/external/infisical/fetchInfisicalSecrets.js";
|
||||
|
||||
export default defineConfig({
|
||||
project: "proj_cwiutfmpdzfcshxevkok",
|
||||
runtime: "node",
|
||||
logLevel: "log",
|
||||
maxDuration: 3600,
|
||||
retries: {
|
||||
enabledInDev: true,
|
||||
default: {
|
||||
maxAttempts: 3,
|
||||
minTimeoutInMs: 1000,
|
||||
maxTimeoutInMs: 10000,
|
||||
factor: 2,
|
||||
randomize: true,
|
||||
},
|
||||
},
|
||||
dirs: ["server/src/trigger"],
|
||||
build: {
|
||||
// Native / heavy deps stay external — bundling them inflates the deploy
|
||||
// and breaks platform-specific binaries (pg, ioredis, etc.).
|
||||
external: [
|
||||
"@aws-sdk/client-s3",
|
||||
"@google-cloud/bigquery",
|
||||
"ioredis",
|
||||
"pino",
|
||||
"@axiomhq/pino",
|
||||
"drizzle-orm",
|
||||
"postgres",
|
||||
"pg",
|
||||
"zod",
|
||||
],
|
||||
extensions: [
|
||||
// Server runtime imports `*.lua` as raw text via Bun's loader. esbuild
|
||||
// (used by the trigger build) doesn't see bunfig — register a plugin
|
||||
// that reads .lua files as text so the same imports work post-bundle.
|
||||
{
|
||||
name: "lua-text-loader",
|
||||
onBuildStart: async (context) => {
|
||||
context.registerPlugin({
|
||||
name: "lua-text-loader-plugin",
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.lua$/ }, async (args) => {
|
||||
const { readFileSync } = await import("node:fs");
|
||||
return {
|
||||
contents: readFileSync(args.path, "utf-8"),
|
||||
loader: "text",
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
aptGet({ packages: ["pkg-config", "liblzma-dev"] }),
|
||||
additionalPackages({
|
||||
packages: [
|
||||
"@axiomhq/pino",
|
||||
"postgres",
|
||||
"pg",
|
||||
"drizzle-orm",
|
||||
"ioredis",
|
||||
"zod",
|
||||
],
|
||||
}),
|
||||
// In DEV: `bun d` runs `bunx trigger.dev dev` under
|
||||
// `infisical run --env=dev --recursive --`, so the trigger CLI
|
||||
// inherits secrets from process.env directly. `syncEnvVars` only
|
||||
// runs at DEPLOY time (pushes Infisical secrets to trigger cloud).
|
||||
syncEnvVars(async (ctx) => fetchInfisicalSecretsFromEnv(ctx.env)),
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -67,6 +67,7 @@
|
||||
"date-fns": "^3.6.0",
|
||||
"decimal.js": "^10.5.0",
|
||||
"input-otp": "^1.4.2",
|
||||
"json5": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.562.0",
|
||||
"motion": "^12.26.1",
|
||||
|
||||
@@ -1,18 +1,66 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { MigrationFilter } from "@autumn/shared/api/migrations/filters/migrationFilter.js";
|
||||
import type { Operations } from "@autumn/shared/api/migrations/operations/operations.js";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQueryKeyFactory } from "@/hooks/common/useQueryKeyFactory";
|
||||
import { MigrationService } from "@/services/MigrationService";
|
||||
import { useAxiosInstance } from "@/services/useAxiosInstance";
|
||||
|
||||
export const useMigrationsQuery = () => {
|
||||
const axiosInstance = useAxiosInstance();
|
||||
const buildKey = useQueryKeyFactory();
|
||||
const queryClient = useQueryClient();
|
||||
const queryKey = buildKey(["migrations"]);
|
||||
|
||||
const { data, isLoading, error, refetch } = useQuery<{
|
||||
list: Migration[];
|
||||
}>({
|
||||
queryKey: buildKey(["migrations"]),
|
||||
queryFn: () => MigrationService.list(axiosInstance),
|
||||
const { data, isLoading, error, refetch } = useQuery<{ list: Migration[] }>({
|
||||
queryKey,
|
||||
queryFn: async () => {
|
||||
const { data } = await axiosInstance.post<{ list: Migration[] }>(
|
||||
"/migrations.list",
|
||||
);
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
const invalidate = () => queryClient.invalidateQueries({ queryKey });
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: async (body: { id: string }) => {
|
||||
const { data } = await axiosInstance.post<Migration>(
|
||||
"/migrations.create",
|
||||
body,
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: invalidate,
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: async (body: {
|
||||
id: string;
|
||||
updates: {
|
||||
id?: string;
|
||||
filter?: MigrationFilter | null;
|
||||
operations?: Operations | null;
|
||||
};
|
||||
}) => {
|
||||
const { data } = await axiosInstance.post<Migration>(
|
||||
"/migrations.update",
|
||||
body,
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: invalidate,
|
||||
});
|
||||
|
||||
const runMutation = useMutation({
|
||||
mutationFn: async (body: { id: string; dry_run?: boolean }) => {
|
||||
const { data } = await axiosInstance.post<{
|
||||
migration_id: string;
|
||||
dry_run: boolean;
|
||||
run_id: string;
|
||||
}>("/migrations.run", body);
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -20,5 +68,11 @@ export const useMigrationsQuery = () => {
|
||||
isLoading,
|
||||
error,
|
||||
refetch,
|
||||
createMigration: createMutation.mutateAsync,
|
||||
isCreating: createMutation.isPending,
|
||||
updateMigration: updateMutation.mutateAsync,
|
||||
isUpdating: updateMutation.isPending,
|
||||
runMigration: runMutation.mutateAsync,
|
||||
isRunning: runMutation.isPending,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import type { AxiosInstance } from "axios";
|
||||
|
||||
export const MigrationService = {
|
||||
list: async (axiosInstance: AxiosInstance) => {
|
||||
const { data } = await axiosInstance.post<{ list: Migration[] }>(
|
||||
"/migrations.list",
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
create: async (axiosInstance: AxiosInstance, body: { id: string }) => {
|
||||
const { data } = await axiosInstance.post<Migration>(
|
||||
"/migrations.create",
|
||||
body,
|
||||
);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
@@ -2,8 +2,10 @@ import { MigrationListTable } from "./migration-list/MigrationListTable";
|
||||
|
||||
export const MigrationsView = () => {
|
||||
return (
|
||||
<div className="h-fit max-h-full px-4 sm:px-10">
|
||||
<MigrationListTable />
|
||||
<div className="flex flex-col gap-4 h-fit relative w-full pb-8 max-w-5xl mx-auto pt-4 sm:pt-8">
|
||||
<div className="h-fit max-h-full px-4 sm:px-10">
|
||||
<MigrationListTable />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,8 +10,6 @@ import {
|
||||
} from "@/components/v2/sheets/SharedSheetComponents";
|
||||
import { Sheet, SheetContent } from "@/components/v2/sheets/Sheet";
|
||||
import { useMigrationsQuery } from "@/hooks/queries/useMigrationsQuery";
|
||||
import { MigrationService } from "@/services/MigrationService";
|
||||
import { useAxiosInstance } from "@/services/useAxiosInstance";
|
||||
import { getBackendErr } from "@/utils/genUtils";
|
||||
|
||||
function CreateMigrationSheet({
|
||||
@@ -23,15 +21,13 @@ function CreateMigrationSheet({
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
onSuccess?: (migrationId: string) => void;
|
||||
} = {}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [internalOpen, setInternalOpen] = useState(false);
|
||||
const [id, setId] = useState("");
|
||||
|
||||
const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
|
||||
const setOpen = controlledOnOpenChange || setInternalOpen;
|
||||
|
||||
const axiosInstance = useAxiosInstance();
|
||||
const { refetch } = useMigrationsQuery();
|
||||
const { createMigration, isCreating } = useMigrationsQuery();
|
||||
|
||||
const handleCreateMigration = async () => {
|
||||
if (!id.trim()) {
|
||||
@@ -39,12 +35,8 @@ function CreateMigrationSheet({
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const created = await MigrationService.create(axiosInstance, {
|
||||
id: id.trim(),
|
||||
});
|
||||
await refetch();
|
||||
const created = await createMigration({ id: id.trim() });
|
||||
toast.success("Migration created");
|
||||
setOpen(false);
|
||||
onSuccess?.(created.id);
|
||||
@@ -52,8 +44,6 @@ function CreateMigrationSheet({
|
||||
toast.error(
|
||||
getBackendErr(error as AxiosError, "Failed to create migration"),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,7 +84,7 @@ function CreateMigrationSheet({
|
||||
className="w-full"
|
||||
onClick={handleCreateMigration}
|
||||
metaShortcut="enter"
|
||||
isLoading={loading}
|
||||
isLoading={isCreating}
|
||||
>
|
||||
Create migration
|
||||
</ShortcutButton>
|
||||
|
||||
216
vite/src/views/migrations/components/EditMigrationSheet.tsx
Normal file
216
vite/src/views/migrations/components/EditMigrationSheet.tsx
Normal file
@@ -0,0 +1,216 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import Editor, { type Monaco } from "@monaco-editor/react";
|
||||
import { PlayIcon } from "@phosphor-icons/react";
|
||||
import type { AxiosError } from "axios";
|
||||
import JSON5 from "json5";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/v2/buttons/Button";
|
||||
import { ShortcutButton } from "@/components/v2/buttons/ShortcutButton";
|
||||
import {
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetSection,
|
||||
} from "@/components/v2/sheets/SharedSheetComponents";
|
||||
import { Sheet, SheetContent } from "@/components/v2/sheets/Sheet";
|
||||
import { useMigrationsQuery } from "@/hooks/queries/useMigrationsQuery";
|
||||
import { getBackendErr } from "@/utils/genUtils";
|
||||
|
||||
const EMPTY_FILTER = `{
|
||||
customer: {},
|
||||
}
|
||||
`;
|
||||
|
||||
const EMPTY_OPERATIONS = `{
|
||||
customer: {},
|
||||
}
|
||||
`;
|
||||
|
||||
function stringify(value: unknown, fallback: string) {
|
||||
if (value === null || value === undefined) return fallback;
|
||||
// JSON5.stringify with no quotes around safe identifier keys
|
||||
return JSON5.stringify(value, { space: 2, quote: '"' });
|
||||
}
|
||||
|
||||
function tryParse(text: string) {
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return { value: null as unknown, error: null as string | null };
|
||||
try {
|
||||
return { value: JSON5.parse(trimmed), error: null };
|
||||
} catch (err) {
|
||||
return {
|
||||
value: null,
|
||||
error: err instanceof Error ? err.message : "Invalid syntax",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Disable TS diagnostics so bare object literals like `{ a: 1 }` don't squiggle.
|
||||
function configureMonaco(monaco: Monaco) {
|
||||
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: true,
|
||||
noSuggestionDiagnostics: true,
|
||||
});
|
||||
}
|
||||
|
||||
const EDITOR_OPTIONS = {
|
||||
minimap: { enabled: false },
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: 12,
|
||||
tabSize: 2,
|
||||
wordWrap: "on" as const,
|
||||
formatOnPaste: true,
|
||||
formatOnType: true,
|
||||
glyphMargin: false,
|
||||
folding: false,
|
||||
lineNumbersMinChars: 2,
|
||||
lineDecorationsWidth: 4,
|
||||
padding: { top: 8, bottom: 8 },
|
||||
};
|
||||
|
||||
function EditMigrationSheet({
|
||||
migration,
|
||||
open,
|
||||
onOpenChange,
|
||||
}: {
|
||||
migration: Migration | null;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) {
|
||||
const { updateMigration, isUpdating, runMigration, isRunning } =
|
||||
useMigrationsQuery();
|
||||
|
||||
const [filterText, setFilterText] = useState("");
|
||||
const [operationsText, setOperationsText] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!migration) return;
|
||||
setFilterText(stringify(migration.filter, EMPTY_FILTER));
|
||||
setOperationsText(stringify(migration.operations, EMPTY_OPERATIONS));
|
||||
}, [migration]);
|
||||
|
||||
const filterParsed = useMemo(() => tryParse(filterText), [filterText]);
|
||||
const operationsParsed = useMemo(
|
||||
() => tryParse(operationsText),
|
||||
[operationsText],
|
||||
);
|
||||
|
||||
const canSave = !filterParsed.error && !operationsParsed.error;
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!migration || !canSave) return;
|
||||
try {
|
||||
await updateMigration({
|
||||
id: migration.id,
|
||||
updates: {
|
||||
filter: filterParsed.value as null,
|
||||
operations: operationsParsed.value as null,
|
||||
},
|
||||
});
|
||||
toast.success("Migration saved");
|
||||
onOpenChange(false);
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
getBackendErr(error as AxiosError, "Failed to save migration"),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRun = async () => {
|
||||
if (!migration) return;
|
||||
try {
|
||||
const result = await runMigration({ id: migration.id, dry_run: true });
|
||||
toast.success(`Migration triggered (run ${result.run_id})`);
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
getBackendErr(error as AxiosError, "Failed to run migration"),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||
<SheetContent className="flex flex-col overflow-hidden sm:max-w-[640px]">
|
||||
<SheetHeader
|
||||
title={migration?.id ?? "Migration"}
|
||||
description="Edit the filter that selects rows and the operations applied to each match. Object literal syntax (TypeScript-style) is supported."
|
||||
action={
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={handleRun}
|
||||
isLoading={isRunning}
|
||||
disabled={!migration?.operations && !operationsText.trim()}
|
||||
>
|
||||
<PlayIcon size={14} weight="fill" />
|
||||
Run
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<SheetSection title="Filter">
|
||||
<div className="rounded-md border border-border overflow-hidden">
|
||||
<Editor
|
||||
height="240px"
|
||||
language="typescript"
|
||||
value={filterText}
|
||||
onChange={(value) => setFilterText(value ?? "")}
|
||||
beforeMount={configureMonaco}
|
||||
options={EDITOR_OPTIONS}
|
||||
theme="vs-dark"
|
||||
/>
|
||||
</div>
|
||||
{filterParsed.error && (
|
||||
<div className="mt-2 text-xs text-red-500">
|
||||
{filterParsed.error}
|
||||
</div>
|
||||
)}
|
||||
</SheetSection>
|
||||
|
||||
<SheetSection title="Operations" withSeparator={false}>
|
||||
<div className="rounded-md border border-border overflow-hidden">
|
||||
<Editor
|
||||
height="280px"
|
||||
language="typescript"
|
||||
value={operationsText}
|
||||
onChange={(value) => setOperationsText(value ?? "")}
|
||||
beforeMount={configureMonaco}
|
||||
options={EDITOR_OPTIONS}
|
||||
theme="vs-dark"
|
||||
/>
|
||||
</div>
|
||||
{operationsParsed.error && (
|
||||
<div className="mt-2 text-xs text-red-500">
|
||||
{operationsParsed.error}
|
||||
</div>
|
||||
)}
|
||||
</SheetSection>
|
||||
</div>
|
||||
|
||||
<SheetFooter>
|
||||
<ShortcutButton
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
onClick={() => onOpenChange(false)}
|
||||
singleShortcut="escape"
|
||||
>
|
||||
Cancel
|
||||
</ShortcutButton>
|
||||
<ShortcutButton
|
||||
className="w-full"
|
||||
onClick={handleSave}
|
||||
metaShortcut="enter"
|
||||
isLoading={isUpdating}
|
||||
disabled={!canSave}
|
||||
>
|
||||
Save
|
||||
</ShortcutButton>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditMigrationSheet;
|
||||
@@ -1,14 +1,18 @@
|
||||
import type { Migration } from "@autumn/shared";
|
||||
import { ArrowsClockwiseIcon } from "@phosphor-icons/react";
|
||||
import { useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Table } from "@/components/general/table";
|
||||
import { EmptyState } from "@/components/v2/empty-states/EmptyState";
|
||||
import { useMigrationsQuery } from "@/hooks/queries/useMigrationsQuery";
|
||||
import { useProductTable } from "@/views/products/hooks/useProductTable";
|
||||
import EditMigrationSheet from "../components/EditMigrationSheet";
|
||||
import { createMigrationListColumns } from "./MigrationListColumns";
|
||||
import { MigrationListCreateButton } from "./MigrationListCreateButton";
|
||||
|
||||
export function MigrationListTable() {
|
||||
const { migrations, isLoading } = useMigrationsQuery();
|
||||
const [selected, setSelected] = useState<Migration | null>(null);
|
||||
const [sheetOpen, setSheetOpen] = useState(false);
|
||||
|
||||
const columns = useMemo(() => createMigrationListColumns(), []);
|
||||
|
||||
@@ -23,6 +27,11 @@ export function MigrationListTable() {
|
||||
|
||||
const hasRows = table.getRowModel().rows.length > 0;
|
||||
|
||||
const handleRowClick = (row: Migration) => {
|
||||
setSelected(row);
|
||||
setSheetOpen(true);
|
||||
};
|
||||
|
||||
if (!isLoading && !hasRows) {
|
||||
return (
|
||||
<EmptyState
|
||||
@@ -33,40 +42,51 @@ export function MigrationListTable() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Table.Provider
|
||||
config={{
|
||||
table,
|
||||
numberOfColumns: columns.length,
|
||||
enableSorting: false,
|
||||
isLoading,
|
||||
rowClassName: "h-10",
|
||||
}}
|
||||
>
|
||||
<Table.Toolbar>
|
||||
<div className="flex w-full justify-between items-center">
|
||||
<Table.Heading>
|
||||
<ArrowsClockwiseIcon
|
||||
size={16}
|
||||
weight="fill"
|
||||
className="text-subtle"
|
||||
/>
|
||||
Migrations
|
||||
</Table.Heading>
|
||||
<Table.Actions>
|
||||
<div className="flex items-center gap-2">
|
||||
<MigrationListCreateButton />
|
||||
</div>
|
||||
</Table.Actions>
|
||||
<>
|
||||
<Table.Provider
|
||||
config={{
|
||||
table,
|
||||
numberOfColumns: columns.length,
|
||||
enableSorting: false,
|
||||
isLoading,
|
||||
rowClassName: "h-10",
|
||||
onRowClick: handleRowClick,
|
||||
}}
|
||||
>
|
||||
<Table.Toolbar>
|
||||
<div className="flex w-full justify-between items-center">
|
||||
<Table.Heading>
|
||||
<ArrowsClockwiseIcon
|
||||
size={16}
|
||||
weight="fill"
|
||||
className="text-subtle"
|
||||
/>
|
||||
Migrations
|
||||
</Table.Heading>
|
||||
<Table.Actions>
|
||||
<div className="flex items-center gap-2">
|
||||
<MigrationListCreateButton />
|
||||
</div>
|
||||
</Table.Actions>
|
||||
</div>
|
||||
</Table.Toolbar>
|
||||
<div>
|
||||
<Table.Container>
|
||||
<Table.Content>
|
||||
<Table.Header />
|
||||
<Table.Body />
|
||||
</Table.Content>
|
||||
</Table.Container>
|
||||
</div>
|
||||
</Table.Toolbar>
|
||||
<div>
|
||||
<Table.Container>
|
||||
<Table.Content>
|
||||
<Table.Header />
|
||||
<Table.Body />
|
||||
</Table.Content>
|
||||
</Table.Container>
|
||||
</div>
|
||||
</Table.Provider>
|
||||
</Table.Provider>
|
||||
<EditMigrationSheet
|
||||
migration={selected}
|
||||
open={sheetOpen}
|
||||
onOpenChange={(open) => {
|
||||
setSheetOpen(open);
|
||||
if (!open) setSelected(null);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user