From d3b33720e08ab2c2afb4c0f79a73117f6c700235 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 12:15:44 -0700 Subject: [PATCH 01/18] gracefully bail onComplete when canceled --- src/component/model.ts | 7 +++-- src/component/pool.ts | 58 +++++++++++++++++++++++------------------ src/component/schema.ts | 2 +- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/component/model.ts b/src/component/model.ts index 2e28d92..d1102c6 100644 --- a/src/component/model.ts +++ b/src/component/model.ts @@ -3,7 +3,7 @@ import { QueryCtx } from "./_generated/server.js"; export async function getWorkflow( ctx: QueryCtx, workflowIdStr: string, - expectedGenerationNumber: number, + expectedGenerationNumber: number | null, ) { const workflowId = ctx.db.normalizeId("workflows", workflowIdStr); if (!workflowId) { @@ -13,7 +13,10 @@ export async function getWorkflow( if (!workflow) { throw new Error(`Workflow not found: ${workflowId}`); } - if (workflow.generationNumber !== expectedGenerationNumber) { + if ( + expectedGenerationNumber !== null && + workflow.generationNumber !== expectedGenerationNumber + ) { throw new Error(`Invalid generation number: ${expectedGenerationNumber}`); } return workflow; diff --git a/src/component/pool.ts b/src/component/pool.ts index 955d602..6b0116f 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -60,6 +60,7 @@ export const onCompleteContext = v.object({ export type OnCompleteContext = Infer; +// For a single step export const onComplete = internalMutation({ args: { workId: workIdValidator, @@ -97,17 +98,8 @@ export const onComplete = internalMutation({ return; } const { generationNumber } = args.context; - const workflow = await getWorkflow(ctx, workflowId, generationNumber); journalEntry.step.inProgress = false; journalEntry.step.completedAt = Date.now(); - console.event("stepCompleted", { - workflowId, - workflowName: workflow.name, - status: args.result.kind, - stepName: journalEntry.step.name, - stepNumber: journalEntry.stepNumber, - durationMs: journalEntry.step.completedAt - journalEntry.step.startedAt, - }); switch (args.result.kind) { case "success": journalEntry.step.runResult = { @@ -129,25 +121,40 @@ export const onComplete = internalMutation({ } await ctx.db.replace(journalEntry._id, journalEntry); console.debug(`Completed execution of ${stepId}`, journalEntry); - if (workflow.runResult === undefined) { - // TODO: Technically this doesn't obey the workpool, but... - // it's better than calling it directly, and enqueuing can now happen - // in the root component. - const workpool = await getWorkpool(ctx, args.context.workpoolOptions); - await workpool.enqueueMutation( - ctx, - workflow.workflowHandle as FunctionHandle<"mutation">, - { workflowId: workflow._id, generationNumber }, - { - onComplete: internal.pool.handlerOnComplete, - context: { workflowId, generationNumber }, - }, - ); - } else { + + const workflow = await getWorkflow(ctx, workflowId, null); + console.event("stepCompleted", { + workflowId, + workflowName: workflow.name, + status: args.result.kind, + stepName: journalEntry.step.name, + stepNumber: journalEntry.stepNumber, + durationMs: journalEntry.step.completedAt - journalEntry.step.startedAt, + }); + if (workflow.runResult !== undefined) { + if (workflow.runResult.kind !== "canceled") { + console.error( + `Workflow: ${workflowId} already ${workflow.runResult.kind} when completing ${stepId} with status ${args.result.kind}`, + ); + } + return; + } + if (workflow.generationNumber !== generationNumber) { console.error( - `Workflow not running: ${workflowId} when completing ${stepId}`, + `Workflow: ${workflowId} already has generation number ${workflow.generationNumber} when completing ${stepId}`, ); + return; } + const workpool = await getWorkpool(ctx, args.context.workpoolOptions); + await workpool.enqueueMutation( + ctx, + workflow.workflowHandle as FunctionHandle<"mutation">, + { workflowId: workflow._id, generationNumber }, + { + onComplete: internal.pool.handlerOnComplete, + context: { workflowId, generationNumber }, + }, + ); }, }); @@ -165,6 +172,7 @@ const handlerOnCompleteContext = v.object({ generationNumber: v.number(), }); +// For the workflow handler export const handlerOnComplete = internalMutation({ args: { workId: workIdValidator, diff --git a/src/component/schema.ts b/src/component/schema.ts index bb2512e..4396a21 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -42,7 +42,7 @@ const workflowObject = { logLevel: deprecated, startedAt: deprecated, state: deprecated, - // undefined + // undefined until it's completed runResult: v.optional(vResultValidator), // Internal execution status, used to totally order mutations. From 5ea64ee221719e36cf7ecd24c42c0e39cc1d452a Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 12:25:47 -0700 Subject: [PATCH 02/18] capture onComplete failures for workflow --- src/component/schema.ts | 19 ++++++++++++++----- src/component/workflow.ts | 30 +++++++++++++++++++----------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/component/schema.ts b/src/component/schema.ts index bb2512e..7838093 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -122,9 +122,18 @@ export default defineSchema({ steps: defineTable(journalObject) .index("workflow", ["workflowId", "stepNumber"]) .index("inProgress", ["step.inProgress", "workflowId"]), - onCompleteFailures: defineTable({ - workId: workIdValidator, - result: resultValidator, - context: v.any(), - }), + onCompleteFailures: defineTable( + v.union( + v.object({ + workId: workIdValidator, + result: resultValidator, + context: v.any(), + }), + v.object({ + workflowId: v.id("workflows"), + generationNumber: v.number(), + stepId: v.id("steps"), + }), + ), + ), }); diff --git a/src/component/workflow.ts b/src/component/workflow.ts index 41175f4..5233ed5 100644 --- a/src/component/workflow.ts +++ b/src/component/workflow.ts @@ -141,17 +141,25 @@ export const complete = mutation({ overallDurationMs: Date.now() - workflow._creationTime, }); if (workflow.onComplete) { - await ctx.runMutation( - workflow.onComplete.fnHandle as FunctionHandle< - "mutation", - OnCompleteArgs - >, - { - workflowId: workflow._id as unknown as WorkflowId, - result: workflow.runResult, - context: workflow.onComplete.context, - }, - ); + try { + await ctx.runMutation( + workflow.onComplete.fnHandle as FunctionHandle< + "mutation", + OnCompleteArgs + >, + { + workflowId: workflow._id as unknown as WorkflowId, + result: workflow.runResult, + context: workflow.onComplete.context, + }, + ); + } catch (error) { + console.error("Error calling onComplete", error); + await ctx.db.insert("onCompleteFailures", { + ...args, + error: error instanceof Error ? error.message : String(error), + }); + } } // TODO: delete everything unless ttl is set console.debug(`Completed workflow ${workflow._id}:`, workflow); From c71e9c62cbbcd7afe8d5d8af7fe3ba02a644076e Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 12:27:15 -0700 Subject: [PATCH 03/18] pkg-pr-new --- .github/workflows/node.js.yml | 1 + package-lock.json | 546 ++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 548 insertions(+) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 4b8b1d2..6802d80 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -17,3 +17,4 @@ jobs: - run: npm run typecheck - run: cd example && npm run lint && cd .. - run: npm test + - run: npx pkg-pr-new publish diff --git a/package-lock.json b/package-lock.json index 6b5f154..1760714 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "globals": "^15.9.0", "npm-run-all2": "^7.0.2", "openai": "^4.54.0", + "pkg-pr-new": "^0.0.54", "prettier": "3.2.5", "typescript": "~5.5.0", "typescript-eslint": "^7.18.0", @@ -565,6 +566,22 @@ "dev": true, "license": "MIT" }, + "node_modules/@jsdevtools/ez-spawn": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@jsdevtools/ez-spawn/-/ez-spawn-3.0.4.tgz", + "integrity": "sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-me-maybe": "^1.0.1", + "cross-spawn": "^7.0.3", + "string-argv": "^0.3.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -600,6 +617,278 @@ "node": ">= 8" } }, + "node_modules/@octokit/action": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/action/-/action-6.1.0.tgz", + "integrity": "sha512-lo+nHx8kAV86bxvOVOI3vFjX3gXPd/L7guAUbvs3pUvnR2KC+R7yjBkA1uACt4gYhs4LcWP3AXSGQzsbeN2XXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-action": "^4.0.0", + "@octokit/core": "^5.0.0", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-rest-endpoint-methods": "^10.0.0", + "@octokit/types": "^12.0.0", + "undici": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-action": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-4.1.0.tgz", + "integrity": "sha512-m+3t7K46IYyMk7Bl6/lF4Rv09GqDZjYmNg8IWycJ2Fa3YE3DE7vQcV6G2hUPmR9NDqenefNJwVtlisMjzymPiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-action/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/auth-action/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.1.tgz", + "integrity": "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.4.1", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/core/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/endpoint/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", + "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^8.4.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/graphql/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", + "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", + "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^12.6.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "5" + } + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/request-error/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/request/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/request/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.44.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", @@ -1442,6 +1731,13 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1506,6 +1802,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1725,6 +2028,13 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, "node_modules/convex": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/convex/-/convex-1.22.0.tgz", @@ -1940,6 +2250,16 @@ "node": ">=0.10.0" } }, + "node_modules/decode-uri-component": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz", + "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -1982,6 +2302,13 @@ "node": ">=0.4.0" } }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true, + "license": "ISC" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2419,6 +2746,19 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz", + "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2829,6 +3169,19 @@ "node": ">=8" } }, + "node_modules/isbinaryfile": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.4.tgz", + "integrity": "sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3055,6 +3408,19 @@ "node": "*" } }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3521,6 +3887,37 @@ "node": ">=0.10" } }, + "node_modules/pkg-pr-new": { + "version": "0.0.54", + "resolved": "https://registry.npmjs.org/pkg-pr-new/-/pkg-pr-new-0.0.54.tgz", + "integrity": "sha512-NkmmZbe3HrElqWcgvbwTuVm7wzHN+vpz1NFhBNcAKT33Co8YE95IiA/Vq7E+cka6z+qybI2pVYVidT5dhW+jMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ez-spawn": "^3.0.4", + "@octokit/action": "^6.1.0", + "ignore": "^5.3.1", + "isbinaryfile": "^5.0.2", + "pkg-types": "^1.1.1", + "query-registry": "^3.0.1", + "tinyglobby": "^0.2.9" + }, + "bin": { + "pkg-pr-new": "bin/cli.js" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3598,6 +3995,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-registry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/query-registry/-/query-registry-3.0.1.tgz", + "integrity": "sha512-M9RxRITi2mHMVPU5zysNjctUT8bAPx6ltEXo/ir9+qmiM47Y7f0Ir3+OxUO5OjYAWdicBQRew7RtHtqUXydqlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "query-string": "^9.0.0", + "quick-lru": "^7.0.0", + "url-join": "^5.0.0", + "validate-npm-package-name": "^5.0.1", + "zod": "^3.23.8", + "zod-package-json": "^1.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/query-string": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.2.2.tgz", + "integrity": "sha512-pDSIZJ9sFuOp6VnD+5IkakSVf+rICAuuU88Hcsr6AKL0QtxSIfVuKiVP2oahFI7tk3CRSexwV+Ya6MOoTxzg9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.4.1", + "filter-obj": "^5.1.0", + "split-on-first": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3618,6 +4051,19 @@ } ] }, + "node_modules/quick-lru": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.1.tgz", + "integrity": "sha512-kLjThirJMkWKutUKbZ8ViqFc09tDQhlbQo2MNuVeLWbRauqYP96Sm6nzlQ24F0HFjUNZ4i9+AgldJ9H6DZXi7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/read-package-json-fast": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", @@ -3873,6 +4319,19 @@ "node": ">=0.10.0" } }, + "node_modules/split-on-first": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz", + "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -3886,6 +4345,16 @@ "dev": true, "license": "MIT" }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -4108,6 +4577,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4160,12 +4639,36 @@ } } }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "dev": true, + "license": "ISC" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4175,6 +4678,26 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -4647,6 +5170,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-package-json/-/zod-package-json-1.2.0.tgz", + "integrity": "sha512-tamtgPM3MkP+obfO2dLr/G+nYoYkpJKmuHdYEy6IXRKfLybruoJ5NUj0lM0LxwOpC9PpoGLbll1ecoeyj43Wsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^3.25.64" + }, + "engines": { + "node": ">=20" + } } } } diff --git a/package.json b/package.json index 568958d..f1d2046 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "globals": "^15.9.0", "npm-run-all2": "^7.0.2", "openai": "^4.54.0", + "pkg-pr-new": "^0.0.54", "prettier": "3.2.5", "typescript": "~5.5.0", "typescript-eslint": "^7.18.0", From 2f9d769c8741062a17884d1773e18b646a786db3 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 12:27:33 -0700 Subject: [PATCH 04/18] vitest.config.ts --- vitest.config.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 vitest.config.ts diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..28ce6fa --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "edge-runtime", + }, +}); From 13ed8ac8f9b930a7f33574309881219f30035621 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 12:30:04 -0700 Subject: [PATCH 05/18] schema --- src/component/schema.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/component/schema.ts b/src/component/schema.ts index 7838093..82337cd 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -132,7 +132,9 @@ export default defineSchema({ v.object({ workflowId: v.id("workflows"), generationNumber: v.number(), - stepId: v.id("steps"), + runResult: vResultValidator, + now: v.number(), + error: v.string(), }), ), ), From a0f3c2d0cde710fe9c11ed308ed970e7ac4c0a7b Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 17:51:31 -0700 Subject: [PATCH 06/18] don't return inProgress --- src/client/workflowMutation.ts | 7 +++++-- src/component/journal.ts | 13 +++++-------- src/component/schema.ts | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/client/workflowMutation.ts b/src/client/workflowMutation.ts index a0cf3fa..713fb80 100644 --- a/src/client/workflowMutation.ts +++ b/src/client/workflowMutation.ts @@ -44,8 +44,11 @@ export function workflowMutation( throw new Error(INVALID_WORKFLOW_MESSAGE); } const { workflowId, generationNumber } = args; - const { workflow, inProgress, logLevel, journalEntries, ok } = - await ctx.runQuery(component.journal.load, { workflowId }); + const { workflow, logLevel, journalEntries, ok } = await ctx.runQuery( + component.journal.load, + { workflowId }, + ); + const inProgress = journalEntries.filter(({ step }) => step.inProgress); const console = createLogger(logLevel); if (!ok) { console.error(`Failed to load journal for ${workflowId}`); diff --git a/src/component/journal.ts b/src/component/journal.ts index a6cb05b..42dc382 100644 --- a/src/component/journal.ts +++ b/src/component/journal.ts @@ -10,7 +10,6 @@ import { import { getWorkflow } from "./model.js"; import { logLevel } from "./logging.js"; import { vRetryBehavior, WorkId } from "@convex-dev/workpool"; -import { getStatusHandler } from "./workflow.js"; import { getWorkpool, OnCompleteContext, workpoolOptions } from "./pool.js"; import { internal } from "./_generated/api.js"; import { FunctionHandle } from "convex/server"; @@ -23,15 +22,14 @@ export const load = query({ }, returns: v.object({ workflow: workflowDocument, - inProgress: v.array(journalDocument), journalEntries: v.array(journalDocument), ok: v.boolean(), logLevel, }), handler: async (ctx, { workflowId }) => { - const { workflow, inProgress, logLevel } = await getStatusHandler(ctx, { - workflowId, - }); + const workflow = await ctx.db.get(workflowId); + assert(workflow, `Workflow not found: ${workflowId}`); + const { logLevel } = await getDefaultLogger(ctx); const journalEntries: JournalEntry[] = []; let sizeSoFar = 0; for await (const entry of ctx.db @@ -40,14 +38,13 @@ export const load = query({ journalEntries.push(entry); sizeSoFar += journalEntrySize(entry); if (sizeSoFar > 4 * 1024 * 1024) { - return { journalEntries, ok: false, workflow, inProgress, logLevel }; + return { journalEntries, ok: false, workflow, logLevel }; } } - return { journalEntries, ok: true, workflow, inProgress, logLevel }; + return { journalEntries, ok: true, workflow, logLevel }; }, }); -// TODO: have it also start the step export const startStep = mutation({ args: { workflowId: v.string(), diff --git a/src/component/schema.ts b/src/component/schema.ts index 4396a21..bbd668f 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -80,7 +80,6 @@ function stepSize(step: Step): number { } size += step.functionType.length; size += step.handle.length; - // TODO: start time, for scheduled steps size += 8 + step.argsSize; if (step.runResult) { size += resultSize(step.runResult); From df711597cb41e4a632d10fb5aa0ab255379cd803 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 18:32:05 -0700 Subject: [PATCH 07/18] call completeHandler when canceling --- src/client/workflowMutation.ts | 2 - src/component/pool.ts | 54 +++++----- src/component/schema.ts | 1 - src/component/workflow.ts | 181 +++++++++++++++++---------------- 4 files changed, 123 insertions(+), 115 deletions(-) diff --git a/src/client/workflowMutation.ts b/src/client/workflowMutation.ts index 713fb80..7f411be 100644 --- a/src/client/workflowMutation.ts +++ b/src/client/workflowMutation.ts @@ -56,7 +56,6 @@ export function workflowMutation( workflowId, generationNumber, runResult: { kind: "failed", error: "Failed to load journal" }, - now: Date.now(), }); return; } @@ -135,7 +134,6 @@ export function workflowMutation( workflowId, generationNumber, runResult: result.runResult, - now: originalEnv.Date.now(), }); break; } diff --git a/src/component/pool.ts b/src/component/pool.ts index 6b0116f..fb34209 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -18,6 +18,7 @@ import { internalMutation, MutationCtx } from "./_generated/server.js"; import { logLevel } from "./logging.js"; import { getWorkflow } from "./model.js"; import { getDefaultLogger } from "./utils.js"; +import { completeHandler } from "./workflow.js"; export const workpoolOptions = v.object({ logLevel: v.optional(logLevel), @@ -181,32 +182,37 @@ export const handlerOnComplete = internalMutation({ }, returns: v.null(), handler: async (ctx, args) => { - if (args.result.kind !== "success") { - const console = await getDefaultLogger(ctx); - if (!validate(handlerOnCompleteContext, args.context)) { - console.error("Invalid handlerOnComplete context", args.context); - if ( - validate(v.id("workflows"), args.context.workflowId, { db: ctx.db }) - ) { - await ctx.db.patch(args.context.workflowId, { - runResult: { - kind: "failed", - error: - "Invalid handlerOnComplete context: " + - JSON.stringify(args.context), - }, - }); - } - return; + if (args.result.kind === "success") { + return; + } + const console = await getDefaultLogger(ctx); + if (!validate(handlerOnCompleteContext, args.context)) { + console.error("Invalid handlerOnComplete context", args.context); + if ( + validate(v.id("workflows"), args.context.workflowId, { db: ctx.db }) + ) { + await ctx.db.insert("onCompleteFailures", args); + await completeHandler(ctx, { + workflowId: args.context.workflowId, + generationNumber: args.context.generationNumber, + runResult: { + kind: "failed", + error: + "Invalid handlerOnComplete context: " + + JSON.stringify(args.context), + }, + }).catch((error) => { + console.error("Error calling completeHandler", error); + }); } - const { workflowId, generationNumber } = args.context; - await ctx.runMutation(api.workflow.complete, { - workflowId, - generationNumber, - runResult: args.result, - now: Date.now(), - }); + return; } + const { workflowId, generationNumber } = args.context; + await completeHandler(ctx, { + workflowId, + generationNumber, + runResult: args.result, + }); }, }); // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/component/schema.ts b/src/component/schema.ts index ef5f057..baacec2 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -132,7 +132,6 @@ export default defineSchema({ workflowId: v.id("workflows"), generationNumber: v.number(), runResult: vResultValidator, - now: v.number(), error: v.string(), }), ), diff --git a/src/component/workflow.ts b/src/component/workflow.ts index 5233ed5..1c524f4 100644 --- a/src/component/workflow.ts +++ b/src/component/workflow.ts @@ -1,13 +1,12 @@ import { vOnComplete, vResultValidator } from "@convex-dev/workpool"; import { assert } from "convex-helpers"; import { FunctionHandle } from "convex/server"; -import { v } from "convex/values"; -import { Id } from "./_generated/dataModel.js"; -import { mutation, MutationCtx, query, QueryCtx } from "./_generated/server.js"; -import { createLogger, Logger, logLevel } from "./logging.js"; +import { Infer, v } from "convex/values"; +import { mutation, MutationCtx, query } from "./_generated/server.js"; +import { Logger, logLevel } from "./logging.js"; import { getWorkflow } from "./model.js"; import { getWorkpool } from "./pool.js"; -import { journalDocument, JournalEntry, workflowDocument } from "./schema.js"; +import { journalDocument, workflowDocument } from "./schema.js"; import { getDefaultLogger } from "./utils.js"; import { WorkflowId, OnCompleteArgs } from "../types.js"; @@ -64,28 +63,21 @@ export const getStatus = query({ inProgress: v.array(journalDocument), logLevel: logLevel, }), - handler: getStatusHandler, -}); - -export async function getStatusHandler( - ctx: QueryCtx, - args: { workflowId: Id<"workflows"> }, -) { - const workflow = await ctx.db.get(args.workflowId); - assert(workflow, `Workflow not found: ${args.workflowId}`); - const console = await getDefaultLogger(ctx); + handler: async (ctx, args) => { + const workflow = await ctx.db.get(args.workflowId); + assert(workflow, `Workflow not found: ${args.workflowId}`); + const console = await getDefaultLogger(ctx); - const result: JournalEntry[] = []; - const inProgressEntries = await ctx.db - .query("steps") - .withIndex("inProgress", (q) => - q.eq("step.inProgress", true).eq("workflowId", args.workflowId), - ) - .collect(); - result.push(...inProgressEntries); - console.debug(`${args.workflowId} blocked by`, result); - return { workflow, inProgress: result, logLevel: console.logLevel }; -} + const inProgress = await ctx.db + .query("steps") + .withIndex("inProgress", (q) => + q.eq("step.inProgress", true).eq("workflowId", args.workflowId), + ) + .collect(); + console.debug(`${args.workflowId} blocked by`, inProgress); + return { workflow, inProgress, logLevel: console.logLevel }; + }, +}); export const cancel = mutation({ args: { @@ -93,10 +85,57 @@ export const cancel = mutation({ }, returns: v.null(), handler: async (ctx, { workflowId }) => { - const { workflow, inProgress, logLevel } = await getStatusHandler(ctx, { + const workflow = await ctx.db.get(workflowId); + assert(workflow, `Workflow not found: ${workflowId}`); + await completeHandler(ctx, { workflowId, + generationNumber: workflow.generationNumber, + runResult: { kind: "canceled" }, }); - const console = createLogger(logLevel); + }, +}); + +const completeArgs = v.object({ + workflowId: v.id("workflows"), + generationNumber: v.number(), + runResult: vResultValidator, +}); + +export const complete = mutation({ + args: completeArgs, + returns: v.null(), + handler: completeHandler, +}); + +export async function completeHandler( + ctx: MutationCtx, + args: Infer, +) { + const workflow = await getWorkflow( + ctx, + args.workflowId, + args.generationNumber, + ); + const console = await getDefaultLogger(ctx); + if (workflow.runResult) { + throw new Error(`Workflow not running: ${workflow}`); + } + workflow.runResult = args.runResult; + console.event("completed", { + workflowId: workflow._id, + name: workflow.name, + status: workflow.runResult.kind, + overallDurationMs: Date.now() - workflow._creationTime, + }); + if (workflow.runResult.kind === "canceled") { + // We bump it so no in-flight steps succeed / we don't race to complete. + workflow.generationNumber += 1; + const inProgress = await ctx.db + .query("steps") + .withIndex("inProgress", (q) => + q.eq("step.inProgress", true).eq("workflowId", args.workflowId), + ) + .collect(); if (inProgress.length > 0) { const workpool = await getWorkpool(ctx, {}); for (const step of inProgress) { @@ -105,67 +144,33 @@ export const cancel = mutation({ } } } - assert(workflow.runResult === undefined, `Not running: ${workflowId}`); - workflow.runResult = { kind: "canceled" }; - workflow.generationNumber += 1; - console.debug(`Canceled workflow ${workflowId}:`, workflow); - // TODO: Call onComplete hook - // TODO: delete everything unless ttl is set - await ctx.db.replace(workflow._id, workflow); - }, -}); - -export const complete = mutation({ - args: { - workflowId: v.id("workflows"), - generationNumber: v.number(), - runResult: vResultValidator, - now: v.number(), - }, - returns: v.null(), - handler: async (ctx, args) => { - const workflow = await getWorkflow( - ctx, - args.workflowId, - args.generationNumber, - ); - const console = await getDefaultLogger(ctx); - if (workflow.runResult) { - throw new Error(`Workflow not running: ${workflow}`); - } - workflow.runResult = args.runResult; - console.event("completed", { - workflowId: workflow._id, - name: workflow.name, - status: workflow.runResult.kind, - overallDurationMs: Date.now() - workflow._creationTime, - }); - if (workflow.onComplete) { - try { - await ctx.runMutation( - workflow.onComplete.fnHandle as FunctionHandle< - "mutation", - OnCompleteArgs - >, - { - workflowId: workflow._id as unknown as WorkflowId, - result: workflow.runResult, - context: workflow.onComplete.context, - }, - ); - } catch (error) { - console.error("Error calling onComplete", error); - await ctx.db.insert("onCompleteFailures", { - ...args, - error: error instanceof Error ? error.message : String(error), - }); - } + console.debug(`Canceled workflow:`, workflow); + } + if (workflow.onComplete) { + try { + await ctx.runMutation( + workflow.onComplete.fnHandle as FunctionHandle< + "mutation", + OnCompleteArgs + >, + { + workflowId: workflow._id as unknown as WorkflowId, + result: workflow.runResult, + context: workflow.onComplete.context, + }, + ); + } catch (error) { + console.error("Error calling onComplete", error); + await ctx.db.insert("onCompleteFailures", { + ...args, + error: error instanceof Error ? error.message : String(error), + }); } - // TODO: delete everything unless ttl is set - console.debug(`Completed workflow ${workflow._id}:`, workflow); - await ctx.db.replace(workflow._id, workflow); - }, -}); + } + // TODO: delete everything unless ttl is set + console.debug(`Completed workflow ${workflow._id}:`, workflow); + await ctx.db.replace(workflow._id, workflow); +} export const cleanup = mutation({ args: { From b786c6453c0d2f4b4d2096dac51ad5057b2ddf5e Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 18:33:29 -0700 Subject: [PATCH 08/18] make component public on thick client --- src/client/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/index.ts b/src/client/index.ts index 191e0ed..be7c327 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -127,7 +127,7 @@ export type WorkflowStatus = export class WorkflowManager { constructor( - private component: UseApi, + public component: UseApi, public options?: { workpoolOptions: WorkpoolOptions; }, From 11eea9863b3f9901890b7d5a5883044b31b4c4ac Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 18:34:10 -0700 Subject: [PATCH 09/18] f --- example/convex/_generated/api.d.ts | 1 - src/component/_generated/api.d.ts | 1 - src/component/pool.ts | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts index 6f97b83..738f9cc 100644 --- a/example/convex/_generated/api.d.ts +++ b/example/convex/_generated/api.d.ts @@ -190,7 +190,6 @@ export declare const components: { "internal", { generationNumber: number; - now: number; runResult: | { kind: "success"; returnValue: any } | { error: string; kind: "failed" } diff --git a/src/component/_generated/api.d.ts b/src/component/_generated/api.d.ts index ba5f709..4c21e1e 100644 --- a/src/component/_generated/api.d.ts +++ b/src/component/_generated/api.d.ts @@ -184,7 +184,6 @@ export type Mounts = { "public", { generationNumber: number; - now: number; runResult: | { kind: "success"; returnValue: any } | { error: string; kind: "failed" } diff --git a/src/component/pool.ts b/src/component/pool.ts index fb34209..0593690 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -13,7 +13,7 @@ import { RegisteredAction, } from "convex/server"; import { Infer, v } from "convex/values"; -import { api, components, internal } from "./_generated/api.js"; +import { components, internal } from "./_generated/api.js"; import { internalMutation, MutationCtx } from "./_generated/server.js"; import { logLevel } from "./logging.js"; import { getWorkflow } from "./model.js"; From 9bff0e79f5e909c1376866cbf7a506e5e3956d45 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 18:34:32 -0700 Subject: [PATCH 10/18] codegen-noinprog --- example/convex/_generated/api.d.ts | 21 --------------------- src/component/_generated/api.d.ts | 21 --------------------- 2 files changed, 42 deletions(-) diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts index 738f9cc..31f6ecd 100644 --- a/example/convex/_generated/api.d.ts +++ b/example/convex/_generated/api.d.ts @@ -50,27 +50,6 @@ export declare const components: { "internal", { workflowId: string }, { - inProgress: Array<{ - _creationTime: number; - _id: string; - step: { - args: any; - argsSize: number; - completedAt?: number; - functionType: "query" | "mutation" | "action"; - handle: string; - inProgress: boolean; - name: string; - runResult?: - | { kind: "success"; returnValue: any } - | { error: string; kind: "failed" } - | { kind: "canceled" }; - startedAt: number; - workId?: string; - }; - stepNumber: number; - workflowId: string; - }>; journalEntries: Array<{ _creationTime: number; _id: string; diff --git a/src/component/_generated/api.d.ts b/src/component/_generated/api.d.ts index 4c21e1e..ced29e6 100644 --- a/src/component/_generated/api.d.ts +++ b/src/component/_generated/api.d.ts @@ -44,27 +44,6 @@ export type Mounts = { "public", { workflowId: string }, { - inProgress: Array<{ - _creationTime: number; - _id: string; - step: { - args: any; - argsSize: number; - completedAt?: number; - functionType: "query" | "mutation" | "action"; - handle: string; - inProgress: boolean; - name: string; - runResult?: - | { kind: "success"; returnValue: any } - | { error: string; kind: "failed" } - | { kind: "canceled" }; - startedAt: number; - workId?: string; - }; - stepNumber: number; - workflowId: string; - }>; journalEntries: Array<{ _creationTime: number; _id: string; From aa77191b4b5b3354ea40e4b878855dc17a046aeb Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 18:39:09 -0700 Subject: [PATCH 11/18] fix custom condition --- example/package-lock.json | 3 ++- package.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/example/package-lock.json b/example/package-lock.json index 5ee0f85..4c37aea 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -20,7 +20,7 @@ }, "..": { "name": "@convex-dev/workflow", - "version": "0.2.4", + "version": "0.2.5-alpha.0", "license": "Apache-2.0", "dependencies": { "async-channel": "^0.2.0" @@ -38,6 +38,7 @@ "globals": "^15.9.0", "npm-run-all2": "^7.0.2", "openai": "^4.54.0", + "pkg-pr-new": "^0.0.54", "prettier": "3.2.5", "typescript": "~5.5.0", "typescript-eslint": "^7.18.0", diff --git a/package.json b/package.json index f1d2046..cdb4095 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "exports": { "./package.json": "./package.json", ".": { + "@convex-dev/component-source": "./src/client/index.ts", "types": "./dist/client/index.d.ts", "default": "./dist/client/index.js" }, From b2bfc237dbbdf4580dda6a4ac7fd28f617d32741 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:21:46 -0700 Subject: [PATCH 12/18] renovate --- renovate.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..8e3387d --- /dev/null +++ b/renovate.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "packageRules": [ + { + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "automerge": true + }, + { + "matchDepTypes": ["devDependencies"], + "automerge": true + } + ], + "extends": ["config:best-practices"] +} From 5e1b4f999c08224fd3b5c81627e27ba928ef8c40 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:22:34 -0700 Subject: [PATCH 13/18] convex-test --- package-lock.json | 30 +++++++++++++--- package.json | 5 +-- src/client/setup.test.ts | 28 +++++++++++++++ src/component/setup.test.ts | 14 ++++++++ src/component/workflow.test.ts | 66 ++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 src/client/setup.test.ts create mode 100644 src/component/workflow.test.ts diff --git a/package-lock.json b/package-lock.json index 1760714..f044091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", "chokidar-cli": "^3.0.0", + "convex-test": "^0.0.38", "cpy-cli": "^5.0.0", "eslint": "^8.57.1", "globals": "^15.9.0", @@ -33,7 +34,7 @@ "peerDependencies": { "@convex-dev/workpool": "^0.2.9", "convex": ">=1.21.0 <1.35.0", - "convex-helpers": "^0.1.77" + "convex-helpers": "^0.1.99" } }, "node_modules/@convex-dev/workpool": { @@ -2074,31 +2075,50 @@ } }, "node_modules/convex-helpers": { - "version": "0.1.77", - "resolved": "https://registry.npmjs.org/convex-helpers/-/convex-helpers-0.1.77.tgz", - "integrity": "sha512-+XXzSET5r41LOIIb0dTJcWvr41X/WmEmdaUuK6Oz71s33c/iG+WTCoMzuWexGYNY1wRTg6m8MQa0BJDfdGHESw==", + "version": "0.1.99", + "resolved": "https://registry.npmjs.org/convex-helpers/-/convex-helpers-0.1.99.tgz", + "integrity": "sha512-W4sV9676vWWIwfYvG76Dxf7biDgpYggvwTLW5fJgLhXIb/XUCacO2AOXu+HrW85GvPRb1LLjhWgWPH8byHiTsw==", + "license": "Apache-2.0", "peer": true, "bin": { "convex-helpers": "bin.cjs" }, "peerDependencies": { + "@standard-schema/spec": "^1.0.0", "convex": "^1.13.0", "hono": "^4.0.5", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "typescript": "^5.5", "zod": "^3.22.4" }, "peerDependenciesMeta": { + "@standard-schema/spec": { + "optional": true + }, "hono": { "optional": true }, "react": { "optional": true }, + "typescript": { + "optional": true + }, "zod": { "optional": true } } }, + "node_modules/convex-test": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/convex-test/-/convex-test-0.0.38.tgz", + "integrity": "sha512-1o/3GvUR9gMLjiqq7SxchI/0OYQaWwbQC4INmB1SNt1WLBjUgEM8+brgpqrZwJ+Vb1DdGZokCVeihwT5IPk49w==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "convex": "^1.16.4" + } + }, "node_modules/convex/node_modules/prettier": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", @@ -4603,7 +4623,7 @@ "version": "5.5.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index cdb4095..5048781 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,8 @@ }, "peerDependencies": { "@convex-dev/workpool": "^0.2.9", - "convex": ">=1.21.0 <1.35.0", - "convex-helpers": "^0.1.77" + "convex": ">=1.25.0 <1.35.0", + "convex-helpers": "^0.1.99" }, "dependencies": { "async-channel": "^0.2.0" @@ -65,6 +65,7 @@ "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", "chokidar-cli": "^3.0.0", + "convex-test": "^0.0.38", "cpy-cli": "^5.0.0", "eslint": "^8.57.1", "globals": "^15.9.0", diff --git a/src/client/setup.test.ts b/src/client/setup.test.ts new file mode 100644 index 0000000..eda2f5a --- /dev/null +++ b/src/client/setup.test.ts @@ -0,0 +1,28 @@ +/// +import { test } from "vitest"; +import { convexTest } from "convex-test"; +export const modules = import.meta.glob("./**/*.*s"); + +import { + defineSchema, + type GenericSchema, + type SchemaDefinition, +} from "convex/server"; +import { type WorkflowManager } from "./index.js"; +import { componentsGeneric } from "convex/server"; +export { componentSchema }; +import componentSchema from "../component/schema.js"; +export const componentModules = import.meta.glob("../component/**/*.ts"); + +export function initConvexTest< + Schema extends SchemaDefinition, +>(schema?: Schema) { + const t = convexTest(schema ?? defineSchema({}), modules); + t.registerComponent("workflow", componentSchema, componentModules); + return t; +} +export const components = componentsGeneric() as unknown as { + workflow: WorkflowManager; +}; + +test("setup", () => {}); diff --git a/src/component/setup.test.ts b/src/component/setup.test.ts index c53e1e4..8cbd7dd 100644 --- a/src/component/setup.test.ts +++ b/src/component/setup.test.ts @@ -1,5 +1,19 @@ /// import { test } from "vitest"; +import { convexTest } from "convex-test"; +import schema from "./schema.js"; export const modules = import.meta.glob("./**/*.*s"); +// set up nested workpool +import componentSchema from "../../node_modules/@convex-dev/workpool/src/component/schema.js"; +export { componentSchema }; +export const componentModules = import.meta.glob( + "../../node_modules/@convex-dev/workpool/src/component/**/*.ts", +); +export function initConvexTest() { + const t = convexTest(schema, modules); + t.registerComponent("workpool", componentSchema, componentModules); + return t; +} + test("setup", () => {}); diff --git a/src/component/workflow.test.ts b/src/component/workflow.test.ts new file mode 100644 index 0000000..dd876cd --- /dev/null +++ b/src/component/workflow.test.ts @@ -0,0 +1,66 @@ +/// + +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; +import { api } from "./_generated/api.js"; +import { initConvexTest } from "./setup.test.js"; + +describe("workflow", () => { + beforeEach(async () => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + test("can create a workflow async", async () => { + const t = initConvexTest(); + const id = await t.mutation(api.workflow.create, { + workflowName: "test", + workflowHandle: "function://internal.example.exampleWorkflow", + workflowArgs: { location: "San Francisco" }, + startAsync: true, + }); + const workflow = await t.query(api.workflow.getStatus, { workflowId: id }); + expect(workflow.workflow.name).toBe("test"); + expect(workflow.workflow.args).toEqual({ location: "San Francisco" }); + expect(workflow.workflow.runResult).toBeUndefined(); + expect(workflow.inProgress).toHaveLength(0); + }); + + test("can cancel a workflow", async () => { + const t = initConvexTest(); + const id = await t.mutation(api.workflow.create, { + workflowName: "test", + workflowHandle: "function://internal.example.exampleWorkflow", + workflowArgs: { location: "San Francisco" }, + startAsync: true, + }); + const workflow = await t.query(api.workflow.getStatus, { workflowId: id }); + expect(workflow.workflow.runResult).toBeUndefined(); + await t.mutation(api.workflow.cancel, { workflowId: id }); + const workflow2 = await t.query(api.workflow.getStatus, { workflowId: id }); + expect(workflow2.workflow.runResult).toMatchObject({ kind: "canceled" }); + }); + + test("cleaning up a workflow", async () => { + const t = initConvexTest(); + const id = await t.mutation(api.workflow.create, { + workflowName: "test", + workflowHandle: "function://internal.example.exampleWorkflow", + workflowArgs: { location: "San Francisco" }, + startAsync: true, + }); + const workflow = await t.query(api.workflow.getStatus, { workflowId: id }); + expect(workflow.workflow.runResult).toBeUndefined(); + await t.mutation(api.workflow.cancel, { workflowId: id }); + const workflow2 = await t.query(api.workflow.getStatus, { workflowId: id }); + expect(workflow2.workflow.runResult).toMatchObject({ kind: "canceled" }); + const cleaned = await t.mutation(api.workflow.cleanup, { workflowId: id }); + expect(cleaned).toBe(true); + await t.run(async (ctx) => { + const workflow = await ctx.db.get(id); + expect(workflow).toBeNull(); + }); + }); +}); From 5fb11c82436430292b0bdd58865bad4460e75d05 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:31:04 -0700 Subject: [PATCH 14/18] dumb hack to use the same version of convex --- example/package-lock.json | 514 +++----------------------------------- example/package.json | 2 +- package-lock.json | 271 +++++++++++--------- package.json | 2 +- 4 files changed, 189 insertions(+), 600 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index 4c37aea..b4c3881 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@convex-dev/workflow": "file:..", - "convex": "^1.16.5" + "convex": "file:../node_modules/convex" }, "devDependencies": { "@types/node": "^22.14.0", @@ -33,6 +33,7 @@ "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", "chokidar-cli": "^3.0.0", + "convex-test": "^0.0.38", "cpy-cli": "^5.0.0", "eslint": "^8.57.1", "globals": "^15.9.0", @@ -45,389 +46,46 @@ "vitest": "^3.2.4" }, "peerDependencies": { - "@convex-dev/workpool": "^0.2.9", - "convex": ">=1.21.0 <1.35.0", - "convex-helpers": "^0.1.77" + "@convex-dev/workpool": "^0.2.16", + "convex": ">=1.25.0 <1.35.0", + "convex-helpers": "^0.1.99" } }, - "node_modules/@convex-dev/workflow": { - "resolved": "..", - "link": true - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", - "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", - "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", - "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", - "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", - "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", - "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", - "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", - "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", - "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", - "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", - "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", - "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", - "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", - "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", - "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", - "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", - "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", - "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", - "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", - "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", - "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], + "../node_modules/convex": { + "version": "1.25.2", + "license": "Apache-2.0", + "dependencies": { + "esbuild": "0.25.4", + "jwt-decode": "^4.0.0", + "prettier": "3.5.3" + }, + "bin": { + "convex": "bin/main.js" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "@auth0/auth0-react": "^2.0.1", + "@clerk/clerk-react": "^4.12.8 || ^5.0.0", + "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@auth0/auth0-react": { + "optional": true + }, + "@clerk/clerk-react": { + "optional": true + }, + "react": { + "optional": true + } } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", - "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "node_modules/@convex-dev/workflow": { + "resolved": "..", + "link": true }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", @@ -718,41 +376,8 @@ "dev": true }, "node_modules/convex": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.22.0.tgz", - "integrity": "sha512-zHDagTUO8SftALBX7MsE90aZ+CpPEV3xkRgmZReN4k3KnM1R6q4qPReY5yUFpKPUwlmSeIXLKtivz4XEaBvj+g==", - "dependencies": { - "esbuild": "0.25.1", - "jwt-decode": "^4.0.0", - "prettier": "3.5.1" - }, - "bin": { - "convex": "bin/main.js" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=7.0.0" - }, - "peerDependencies": { - "@auth0/auth0-react": "^2.0.1", - "@clerk/clerk-react": "^4.12.8 || ^5.0.0", - "react": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0", - "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@auth0/auth0-react": { - "optional": true - }, - "@clerk/clerk-react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } + "resolved": "../node_modules/convex", + "link": true }, "node_modules/convex-test": { "version": "0.0.36", @@ -812,45 +437,6 @@ "node": ">=6.0.0" } }, - "node_modules/esbuild": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", - "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.1", - "@esbuild/android-arm": "0.25.1", - "@esbuild/android-arm64": "0.25.1", - "@esbuild/android-x64": "0.25.1", - "@esbuild/darwin-arm64": "0.25.1", - "@esbuild/darwin-x64": "0.25.1", - "@esbuild/freebsd-arm64": "0.25.1", - "@esbuild/freebsd-x64": "0.25.1", - "@esbuild/linux-arm": "0.25.1", - "@esbuild/linux-arm64": "0.25.1", - "@esbuild/linux-ia32": "0.25.1", - "@esbuild/linux-loong64": "0.25.1", - "@esbuild/linux-mips64el": "0.25.1", - "@esbuild/linux-ppc64": "0.25.1", - "@esbuild/linux-riscv64": "0.25.1", - "@esbuild/linux-s390x": "0.25.1", - "@esbuild/linux-x64": "0.25.1", - "@esbuild/netbsd-arm64": "0.25.1", - "@esbuild/netbsd-x64": "0.25.1", - "@esbuild/openbsd-arm64": "0.25.1", - "@esbuild/openbsd-x64": "0.25.1", - "@esbuild/sunos-x64": "0.25.1", - "@esbuild/win32-arm64": "0.25.1", - "@esbuild/win32-ia32": "0.25.1", - "@esbuild/win32-x64": "0.25.1" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1266,14 +852,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/jwt-decode": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", - "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", - "engines": { - "node": ">=18" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -1445,20 +1023,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", - "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/example/package.json b/example/package.json index e693840..c19e502 100644 --- a/example/package.json +++ b/example/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@convex-dev/workflow": "file:..", - "convex": "^1.16.5" + "convex": "file:../node_modules/convex" }, "devDependencies": { "@types/node": "^22.14.0", diff --git a/package-lock.json b/package-lock.json index f044091..c0847db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,19 +32,20 @@ "vitest": "^3.2.4" }, "peerDependencies": { - "@convex-dev/workpool": "^0.2.9", - "convex": ">=1.21.0 <1.35.0", + "@convex-dev/workpool": "^0.2.16", + "convex": ">=1.25.0 <1.35.0", "convex-helpers": "^0.1.99" } }, "node_modules/@convex-dev/workpool": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@convex-dev/workpool/-/workpool-0.2.9.tgz", - "integrity": "sha512-gVCGAaqvG+e7JTrQ2tncQzlzopp/SmSHJkyUOn+YKBlXgIDO/rqMUNkxscTuO49PGUFMtL6tNvqdgDkwYQpEdQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/@convex-dev/workpool/-/workpool-0.2.16.tgz", + "integrity": "sha512-p4sQjWeHFZ9j4sosS2jDF2sHHmWqNttk2WlNWdPFitP6fOd98p+c8VR3BcltqNMaKSH9nSOkGlVFwtwvnciTLg==", + "license": "Apache-2.0", "peer": true, "peerDependencies": { - "convex": ">=1.17.0 <1.25.0", - "convex-helpers": "^0.1.71" + "convex": ">=1.17.0 <1.35.0", + "convex-helpers": "^0.1.94" } }, "node_modules/@edge-runtime/primitives": { @@ -71,12 +72,13 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", - "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "aix" @@ -86,12 +88,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", - "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -101,12 +104,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", - "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -116,12 +120,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", - "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -131,12 +136,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", - "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -146,12 +152,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", - "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -161,12 +168,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", - "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -176,12 +184,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", - "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -191,12 +200,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", - "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -206,12 +216,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", - "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -221,12 +232,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", - "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -236,12 +248,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", - "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -251,12 +264,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", - "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -266,12 +280,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", - "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -281,12 +296,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -296,12 +312,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -311,12 +328,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -326,12 +344,13 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", - "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -341,12 +360,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", - "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -356,12 +376,13 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", - "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -371,12 +392,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", - "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -386,12 +408,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", - "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" @@ -401,12 +424,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", - "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -416,12 +440,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", - "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -431,12 +456,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", - "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -2037,14 +2063,15 @@ "license": "MIT" }, "node_modules/convex": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.22.0.tgz", - "integrity": "sha512-zHDagTUO8SftALBX7MsE90aZ+CpPEV3xkRgmZReN4k3KnM1R6q4qPReY5yUFpKPUwlmSeIXLKtivz4XEaBvj+g==", + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/convex/-/convex-1.25.2.tgz", + "integrity": "sha512-4r3Lsln9ceOOQ8OqQM13yQtZ6rXWcW1BCfqVkP7LXI8sovpbKzEn6CusT9bE2Rv3STqAHYu153adAj37pZm34A==", + "license": "Apache-2.0", "peer": true, "dependencies": { - "esbuild": "0.25.1", + "esbuild": "0.25.4", "jwt-decode": "^4.0.0", - "prettier": "3.5.1" + "prettier": "3.5.3" }, "bin": { "convex": "bin/main.js" @@ -2056,8 +2083,7 @@ "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", - "react": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0", - "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0" + "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "peerDependenciesMeta": { "@auth0/auth0-react": { @@ -2068,9 +2094,6 @@ }, "react": { "optional": true - }, - "react-dom": { - "optional": true } } }, @@ -2120,9 +2143,10 @@ } }, "node_modules/convex/node_modules/prettier": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", - "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "license": "MIT", "peer": true, "bin": { "prettier": "bin/prettier.cjs" @@ -2389,10 +2413,11 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", - "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2400,31 +2425,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.1", - "@esbuild/android-arm": "0.25.1", - "@esbuild/android-arm64": "0.25.1", - "@esbuild/android-x64": "0.25.1", - "@esbuild/darwin-arm64": "0.25.1", - "@esbuild/darwin-x64": "0.25.1", - "@esbuild/freebsd-arm64": "0.25.1", - "@esbuild/freebsd-x64": "0.25.1", - "@esbuild/linux-arm": "0.25.1", - "@esbuild/linux-arm64": "0.25.1", - "@esbuild/linux-ia32": "0.25.1", - "@esbuild/linux-loong64": "0.25.1", - "@esbuild/linux-mips64el": "0.25.1", - "@esbuild/linux-ppc64": "0.25.1", - "@esbuild/linux-riscv64": "0.25.1", - "@esbuild/linux-s390x": "0.25.1", - "@esbuild/linux-x64": "0.25.1", - "@esbuild/netbsd-arm64": "0.25.1", - "@esbuild/netbsd-x64": "0.25.1", - "@esbuild/openbsd-arm64": "0.25.1", - "@esbuild/openbsd-x64": "0.25.1", - "@esbuild/sunos-x64": "0.25.1", - "@esbuild/win32-arm64": "0.25.1", - "@esbuild/win32-ia32": "0.25.1", - "@esbuild/win32-x64": "0.25.1" + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" } }, "node_modules/escape-string-regexp": { diff --git a/package.json b/package.json index 5048781..1517d3b 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ } }, "peerDependencies": { - "@convex-dev/workpool": "^0.2.9", + "@convex-dev/workpool": "^0.2.16", "convex": ">=1.25.0 <1.35.0", "convex-helpers": "^0.1.99" }, From a298dd7c93c200c9696ad4ddc05441f256dbb9b8 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:31:14 -0700 Subject: [PATCH 15/18] update workflow types --- src/component/workflow.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/component/workflow.ts b/src/component/workflow.ts index 1c524f4..6124ed5 100644 --- a/src/component/workflow.ts +++ b/src/component/workflow.ts @@ -20,7 +20,7 @@ export const create = mutation({ startAsync: v.optional(v.boolean()), // TODO: ttl }, - returns: v.string(), + returns: v.id("workflows"), handler: async (ctx, args) => { const console = await getDefaultLogger(ctx); await updateMaxParallelism(ctx, console, args.maxParallelism); @@ -50,7 +50,7 @@ export const create = mutation({ generationNumber: 0, }); } - return workflowId as string; + return workflowId; }, }); From 28f9dc93abc45801a7e4ca08501f500d394ec3cb Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:31:29 -0700 Subject: [PATCH 16/18] ensure onComplete can observe the workflow status --- src/component/workflow.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/component/workflow.ts b/src/component/workflow.ts index 6124ed5..014d37e 100644 --- a/src/component/workflow.ts +++ b/src/component/workflow.ts @@ -146,6 +146,8 @@ export async function completeHandler( } console.debug(`Canceled workflow:`, workflow); } + // Write the workflow so the onComplete can observe the updated status. + await ctx.db.replace(workflow._id, workflow); if (workflow.onComplete) { try { await ctx.runMutation( @@ -169,7 +171,6 @@ export async function completeHandler( } // TODO: delete everything unless ttl is set console.debug(`Completed workflow ${workflow._id}:`, workflow); - await ctx.db.replace(workflow._id, workflow); } export const cleanup = mutation({ From 90597db7f1e3908869f5c8efb8e5c3531da821c1 Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:31:36 -0700 Subject: [PATCH 17/18] allow cleaning up non-success --- src/component/workflow.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/component/workflow.ts b/src/component/workflow.ts index 014d37e..38ab8ff 100644 --- a/src/component/workflow.ts +++ b/src/component/workflow.ts @@ -188,7 +188,8 @@ export const cleanup = mutation({ return false; } const logger = await getDefaultLogger(ctx); - if (workflow.runResult?.kind !== "success") { + // TODO: allow cleaning up a workflow from inside it / in the onComplete hook + if (!workflow.runResult) { logger.debug( `Can't clean up workflow ${workflowId} since it hasn't completed.`, ); From 9a049710db16825705cf273e62a2691ad6ec1acb Mon Sep 17 00:00:00 2001 From: Ian Macartney Date: Wed, 9 Jul 2025 19:38:14 -0700 Subject: [PATCH 18/18] clean up in the example --- example/convex/example.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/example/convex/example.ts b/example/convex/example.ts index a02f4ba..a0d8983 100644 --- a/example/convex/example.ts +++ b/example/convex/example.ts @@ -98,6 +98,7 @@ export const flowCompleted = internalMutation({ await ctx.db.patch(flow._id, { out: args.result, }); + await workflow.cleanup(ctx, args.workflowId); }, });