cvx-kit 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +3 -0
- package/dist/components/approvals/_generated/api.d.mts +2 -0
- package/dist/components/approvals/_generated/api.mjs.map +1 -1
- package/dist/components/approvals/_generated/component.d.mts +7 -0
- package/dist/components/approvals/_generated/dataModel.d.mts +1 -1
- package/dist/components/approvals/client.d.mts +4 -4
- package/dist/components/approvals/client.mjs +1 -1
- package/dist/components/approvals/client.mjs.map +1 -1
- package/dist/components/approvals/constants.d.mts +8 -2
- package/dist/components/approvals/constants.mjs +1 -1
- package/dist/components/approvals/constants.mjs.map +1 -1
- package/dist/components/approvals/decisions.mjs +1 -1
- package/dist/components/approvals/decisions.mjs.map +1 -1
- package/dist/components/approvals/health.d.mts +15 -0
- package/dist/components/approvals/health.mjs +2 -0
- package/dist/components/approvals/health.mjs.map +1 -0
- package/dist/components/approvals/requests.mjs +1 -1
- package/dist/components/approvals/requests.mjs.map +1 -1
- package/dist/components/approvals/schema.js +1 -0
- package/dist/components/approvals/validators.d.mts +119 -2
- package/dist/components/approvals/validators.mjs +1 -1
- package/dist/components/approvals/validators.mjs.map +1 -1
- package/dist/components/approvals/workflow_steps.d.mts +2 -25
- package/dist/components/approvals/workflow_steps.mjs.map +1 -1
- package/dist/components/foundation/_generated/dataModel.d.mts +1 -1
- package/dist/components/foundation/{schema.mjs → schema.js} +0 -1
- package/docs/approvals.md +50 -2
- package/docs/upgrading.md +23 -0
- package/package.json +5 -2
- package/scripts/convex-config-bridge.mjs +41 -3
- package/scripts/smoke-packed-components.mjs +374 -0
- package/src/test.ts +2 -2
- package/dist/components/approvals/schema.mjs +0 -2
- package/dist/components/approvals/schema.mjs.map +0 -1
- package/dist/components/foundation/schema.mjs.map +0 -1
- /package/dist/components/approvals/{schema.d.mts → schema.d.ts} +0 -0
- /package/dist/components/foundation/{schema.d.mts → schema.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
declare namespace validators_d_exports {
|
|
3
|
-
export { ApprovalActor, ApprovalMetadata, ApprovalWorkflowDescriptor, approvalActionCallback, approvalActor, approvalBranchStep, approvalCallback, approvalCallbackKind, approvalCallbackStep, approvalDecision, approvalDecisionDocument, approvalDecisionStep, approvalMetadata, approvalMutationCallback, approvalName, approvalNotifyStep, approvalQuorum, approvalQuorumKind, approvalReason, approvalReference, approvalRunDocument, approvalRunState, approvalStepKind, approvalWorkflowDescriptor, approvalWorkflowStep };
|
|
3
|
+
export { ApprovalActor, ApprovalCallbackInput, ApprovalMetadata, ApprovalWorkflowDescriptor, approvalActionCallback, approvalActor, approvalBranchStep, approvalCallback, approvalCallbackArgs, approvalCallbackInput, approvalCallbackKind, approvalCallbackStep, approvalDecision, approvalDecisionDocument, approvalDecisionStep, approvalMetadata, approvalMutationCallback, approvalName, approvalNotifyStep, approvalQuorum, approvalQuorumKind, approvalReason, approvalReference, approvalRunDocument, approvalRunState, approvalStepKind, approvalWorkflowDescriptor, approvalWorkflowStep };
|
|
4
4
|
}
|
|
5
5
|
declare const approvalRunState: z.ZodEnum<{
|
|
6
6
|
approved: "approved";
|
|
@@ -31,6 +31,122 @@ declare const approvalReference: z.ZodString;
|
|
|
31
31
|
declare const approvalName: z.ZodString;
|
|
32
32
|
declare const approvalReason: z.ZodString;
|
|
33
33
|
declare const approvalMetadata: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
34
|
+
declare const approvalCallbackInput: z.ZodObject<{
|
|
35
|
+
runId: z.ZodString;
|
|
36
|
+
scopeRef: z.ZodString;
|
|
37
|
+
resourceType: z.ZodString;
|
|
38
|
+
resourceRef: z.ZodString;
|
|
39
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
40
|
+
decision: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
stepKey: z.ZodString;
|
|
42
|
+
outcome: z.ZodUnion<readonly [z.ZodEnum<{
|
|
43
|
+
approved: "approved";
|
|
44
|
+
rejected: "rejected";
|
|
45
|
+
}>, z.ZodLiteral<"expired">]>;
|
|
46
|
+
evidence: z.ZodArray<z.ZodObject<{
|
|
47
|
+
stepKey: z.ZodString;
|
|
48
|
+
actorRef: z.ZodString;
|
|
49
|
+
decision: z.ZodEnum<{
|
|
50
|
+
approved: "approved";
|
|
51
|
+
rejected: "rejected";
|
|
52
|
+
}>;
|
|
53
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
54
|
+
decidedAt: z.ZodNumber;
|
|
55
|
+
}, z.core.$strict>>;
|
|
56
|
+
terminalEvidence: z.ZodOptional<z.ZodObject<{
|
|
57
|
+
actorRef: z.ZodString;
|
|
58
|
+
decision: z.ZodEnum<{
|
|
59
|
+
approved: "approved";
|
|
60
|
+
rejected: "rejected";
|
|
61
|
+
}>;
|
|
62
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
63
|
+
decidedAt: z.ZodNumber;
|
|
64
|
+
}, z.core.$strict>>;
|
|
65
|
+
}, z.core.$strict>>;
|
|
66
|
+
}, z.core.$strict>;
|
|
67
|
+
/** Convex argument validator for approval mutation, action, and notify callbacks. */
|
|
68
|
+
declare const approvalCallbackArgs: import("convex/values").VObject<{
|
|
69
|
+
runId: string;
|
|
70
|
+
scopeRef: string;
|
|
71
|
+
resourceType: string;
|
|
72
|
+
resourceRef: string;
|
|
73
|
+
metadata?: {
|
|
74
|
+
[x: string]: string;
|
|
75
|
+
} | undefined;
|
|
76
|
+
decision?: {
|
|
77
|
+
stepKey: string;
|
|
78
|
+
outcome: "approved" | "expired" | "rejected";
|
|
79
|
+
evidence: {
|
|
80
|
+
stepKey: string;
|
|
81
|
+
actorRef: string;
|
|
82
|
+
decision: "approved" | "rejected";
|
|
83
|
+
reason?: string | undefined;
|
|
84
|
+
decidedAt: number;
|
|
85
|
+
}[];
|
|
86
|
+
terminalEvidence?: {
|
|
87
|
+
actorRef: string;
|
|
88
|
+
decision: "approved" | "rejected";
|
|
89
|
+
reason?: string | undefined;
|
|
90
|
+
decidedAt: number;
|
|
91
|
+
} | undefined;
|
|
92
|
+
} | undefined;
|
|
93
|
+
}, {
|
|
94
|
+
runId: import("convex/values").VString<string, "required">;
|
|
95
|
+
scopeRef: import("convex/values").VString<string, "required">;
|
|
96
|
+
resourceType: import("convex/values").VString<string, "required">;
|
|
97
|
+
resourceRef: import("convex/values").VString<string, "required">;
|
|
98
|
+
metadata: import("convex/values").VRecord<Record<string, string> | undefined, import("convex/values").VString<string, "required">, import("convex/values").VString<string, "required">, "optional", string>;
|
|
99
|
+
decision: import("convex/values").VObject<{
|
|
100
|
+
stepKey: string;
|
|
101
|
+
outcome: "approved" | "expired" | "rejected";
|
|
102
|
+
evidence: {
|
|
103
|
+
stepKey: string;
|
|
104
|
+
actorRef: string;
|
|
105
|
+
decision: "approved" | "rejected";
|
|
106
|
+
reason?: string | undefined;
|
|
107
|
+
decidedAt: number;
|
|
108
|
+
}[];
|
|
109
|
+
terminalEvidence?: {
|
|
110
|
+
actorRef: string;
|
|
111
|
+
decision: "approved" | "rejected";
|
|
112
|
+
reason?: string | undefined;
|
|
113
|
+
decidedAt: number;
|
|
114
|
+
} | undefined;
|
|
115
|
+
} | undefined, {
|
|
116
|
+
stepKey: import("convex/values").VString<string, "required">;
|
|
117
|
+
outcome: import("convex/values").VUnion<"approved" | "expired" | "rejected", [import("convex/values").VUnion<"approved" | "rejected", (import("convex/values").VLiteral<"approved", "required"> | import("convex/values").VLiteral<"rejected", "required">)[], "required", never>, import("convex/values").VLiteral<"expired", "required">], "required", never>;
|
|
118
|
+
evidence: import("convex/values").VArray<{
|
|
119
|
+
stepKey: string;
|
|
120
|
+
actorRef: string;
|
|
121
|
+
decision: "approved" | "rejected";
|
|
122
|
+
reason?: string | undefined;
|
|
123
|
+
decidedAt: number;
|
|
124
|
+
}[], import("convex/values").VObject<{
|
|
125
|
+
stepKey: string;
|
|
126
|
+
actorRef: string;
|
|
127
|
+
decision: "approved" | "rejected";
|
|
128
|
+
reason?: string | undefined;
|
|
129
|
+
decidedAt: number;
|
|
130
|
+
}, {
|
|
131
|
+
stepKey: import("convex/values").VString<string, "required">;
|
|
132
|
+
actorRef: import("convex/values").VString<string, "required">;
|
|
133
|
+
decision: import("convex/values").VUnion<"approved" | "rejected", (import("convex/values").VLiteral<"approved", "required"> | import("convex/values").VLiteral<"rejected", "required">)[], "required", never>;
|
|
134
|
+
reason: import("convex/values").VString<string | undefined, "optional">;
|
|
135
|
+
decidedAt: import("convex/values").VFloat64<number, "required">;
|
|
136
|
+
}, "required", "actorRef" | "decidedAt" | "decision" | "reason" | "stepKey">, "required">;
|
|
137
|
+
terminalEvidence: import("convex/values").VObject<{
|
|
138
|
+
actorRef: string;
|
|
139
|
+
decision: "approved" | "rejected";
|
|
140
|
+
reason?: string | undefined;
|
|
141
|
+
decidedAt: number;
|
|
142
|
+
} | undefined, {
|
|
143
|
+
actorRef: import("convex/values").VString<string, "required">;
|
|
144
|
+
decision: import("convex/values").VUnion<"approved" | "rejected", (import("convex/values").VLiteral<"approved", "required"> | import("convex/values").VLiteral<"rejected", "required">)[], "required", never>;
|
|
145
|
+
reason: import("convex/values").VString<string | undefined, "optional">;
|
|
146
|
+
decidedAt: import("convex/values").VFloat64<number, "required">;
|
|
147
|
+
}, "optional", "actorRef" | "decidedAt" | "decision" | "reason">;
|
|
148
|
+
}, "optional", "evidence" | "outcome" | "stepKey" | "terminalEvidence" | "terminalEvidence.actorRef" | "terminalEvidence.decidedAt" | "terminalEvidence.decision" | "terminalEvidence.reason">;
|
|
149
|
+
}, "required", "decision" | "decision.evidence" | "decision.outcome" | "decision.stepKey" | "decision.terminalEvidence" | "decision.terminalEvidence.actorRef" | "decision.terminalEvidence.decidedAt" | "decision.terminalEvidence.decision" | "decision.terminalEvidence.reason" | "metadata" | "resourceRef" | "resourceType" | "runId" | "scopeRef" | `metadata.${string}`>;
|
|
34
150
|
declare const approvalActor: z.ZodObject<{
|
|
35
151
|
actorRef: z.ZodString;
|
|
36
152
|
capabilities: z.ZodArray<z.ZodString>;
|
|
@@ -297,6 +413,7 @@ declare const approvalDecisionDocument: z.ZodObject<{
|
|
|
297
413
|
type ApprovalWorkflowDescriptor = z.infer<typeof approvalWorkflowDescriptor>;
|
|
298
414
|
type ApprovalActor = z.infer<typeof approvalActor>;
|
|
299
415
|
type ApprovalMetadata = z.infer<typeof approvalMetadata>;
|
|
416
|
+
type ApprovalCallbackInput = Readonly<z.infer<typeof approvalCallbackInput>>;
|
|
300
417
|
//#endregion
|
|
301
|
-
export { ApprovalActor, ApprovalMetadata, ApprovalWorkflowDescriptor, approvalActionCallback, approvalActor, approvalBranchStep, approvalCallback, approvalCallbackKind, approvalCallbackStep, approvalDecision, approvalDecisionDocument, approvalDecisionStep, approvalMetadata, approvalMutationCallback, approvalName, approvalNotifyStep, approvalQuorum, approvalQuorumKind, approvalReason, approvalReference, approvalRunDocument, approvalRunState, approvalStepKind, approvalWorkflowDescriptor, approvalWorkflowStep, validators_d_exports };
|
|
418
|
+
export { ApprovalActor, ApprovalCallbackInput, ApprovalMetadata, ApprovalWorkflowDescriptor, approvalActionCallback, approvalActor, approvalBranchStep, approvalCallback, approvalCallbackArgs, approvalCallbackInput, approvalCallbackKind, approvalCallbackStep, approvalDecision, approvalDecisionDocument, approvalDecisionStep, approvalMetadata, approvalMutationCallback, approvalName, approvalNotifyStep, approvalQuorum, approvalQuorumKind, approvalReason, approvalReference, approvalRunDocument, approvalRunState, approvalStepKind, approvalWorkflowDescriptor, approvalWorkflowStep, validators_d_exports };
|
|
302
419
|
//# sourceMappingURL=validators.d.mts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{APPROVAL_CALLBACK_KINDS as e,APPROVAL_DECISIONS as t,APPROVAL_QUORUM_KINDS as n,APPROVAL_RUN_STATES as r,APPROVAL_STEP_KINDS as i}from"./constants.mjs";import{zid as a}from"convex-helpers/server/zod4";import{z as
|
|
1
|
+
import{APPROVAL_CALLBACK_KINDS as e,APPROVAL_DECISIONS as t,APPROVAL_QUORUM_KINDS as n,APPROVAL_RUN_STATES as r,APPROVAL_STEP_KINDS as i}from"./constants.mjs";import{zid as a,zodToConvex as o}from"convex-helpers/server/zod4";import{z as s}from"zod";const c=s.enum(r),l=s.enum(t),u=s.enum(i),d=s.enum(e),f=s.enum(n),p=s.string().trim().min(1).max(256),m=s.string().trim().min(1).max(96).regex(/^[A-Za-z][A-Za-z0-9._-]*$/),h=s.string().trim().min(1).max(500),g=s.record(s.string().min(1).max(64).regex(/^(?![$_])[\x20-\x7E]+$/),s.string().max(512)).refine(e=>Object.keys(e).length<=32,`Metadata may contain at most 32 entries`),_=s.object({stepKey:m,actorRef:p,decision:l,reason:h.optional(),decidedAt:s.number()}).strict(),v=_.omit({stepKey:!0}),y=s.object({runId:p,scopeRef:p,resourceType:m,resourceRef:p,metadata:g.optional(),decision:s.object({stepKey:m,outcome:s.union([l,s.literal(`expired`)]),evidence:s.array(_),terminalEvidence:v.optional()}).strict().optional()}).strict(),b=o(y),x=s.object({actorRef:p,capabilities:s.array(m).max(32),metadata:g.optional()}).strict(),S=s.object({kind:s.literal(`mutation`),handle:p,retry:s.boolean()}).strict(),C=s.object({kind:s.literal(`action`),handle:p,retry:s.boolean()}).strict(),w=s.discriminatedUnion(`kind`,[S,C]),T=s.object({kind:f,approvals:s.number().int().positive().max(8)}).strict(),E=s.discriminatedUnion(`kind`,[s.object({kind:s.literal(`mutation`),key:m,callback:S}).strict(),s.object({kind:s.literal(`action`),key:m,callback:C}).strict()]),D=s.object({kind:s.literal(`notify`),key:m,callback:C}).strict(),O=s.object({kind:s.literal(`decision`),key:m,decisions:s.array(l).min(1).max(8),quorum:T,makerChecker:s.boolean(),expiresAfterMs:s.number().int().positive().optional()}).strict(),k=s.object({kind:s.literal(`branch`),key:m,approvedStepKey:m,rejectedStepKey:m}).strict(),A=s.discriminatedUnion(`kind`,[E,D,O,k]),j=s.object({schemaVersion:s.literal(1),compatibilityKey:m,name:m,steps:s.array(A).min(1).max(32)}).strict().superRefine((e,t)=>{let n=new Set,r=new Map(e.steps.map(e=>[e.key,e])),i=new Map;for(let[r,i]of e.steps.entries())n.has(i.key)&&t.addIssue({code:`custom`,message:`Duplicate workflow step key: ${i.key}`,path:[`steps`,r,`key`]}),n.add(i.key),i.kind===`decision`&&new Set(i.decisions).size!==i.decisions.length&&t.addIssue({code:`custom`,message:`Duplicate decision value in step: ${i.key}`,path:[`steps`,r,`decisions`]});for(let[n,a]of e.steps.entries())if(a.kind===`branch`){e.steps[n-1]?.kind!==`decision`&&t.addIssue({code:`custom`,message:`Branch must immediately follow a decision: ${a.key}`,path:[`steps`,n]});for(let o of[a.approvedStepKey,a.rejectedStepKey]){let a=r.get(o),s=e.steps.findIndex(e=>e.key===o);a?a.kind!==`mutation`&&a.kind!==`action`&&a.kind!==`notify`?t.addIssue({code:`custom`,message:`Branch target must be a callback step: ${o}`,path:[`steps`,n]}):s<=n&&t.addIssue({code:`custom`,message:`Branch target must be declared after its branch: ${o}`,path:[`steps`,n]}):t.addIssue({code:`custom`,message:`Unknown branch target: ${o}`,path:[`steps`,n]}),i.set(o,(i.get(o)??0)+1)}}for(let[e,n]of i)n!==1&&t.addIssue({code:`custom`,message:`Branch callback must belong to exactly one branch: ${e}`,path:[`steps`]})}),M=s.object({scopeRef:p,resourceType:m,resourceRef:p,requester:x,metadata:g.optional(),workflow:j,state:c,currentStepKey:m.optional(),executionFailedStepKey:m.optional(),expiresAt:s.number().optional(),workflowId:p.optional(),createdAt:s.number(),updatedAt:s.number(),terminalAt:s.number().optional()}).strict(),N=s.object({runId:a(`approvalRuns`),stepKey:m,actor:x,decision:l,reason:h.optional(),decidedAt:s.number()}).strict();export{C as approvalActionCallback,x as approvalActor,k as approvalBranchStep,w as approvalCallback,b as approvalCallbackArgs,y as approvalCallbackInput,d as approvalCallbackKind,E as approvalCallbackStep,l as approvalDecision,N as approvalDecisionDocument,O as approvalDecisionStep,g as approvalMetadata,S as approvalMutationCallback,m as approvalName,D as approvalNotifyStep,T as approvalQuorum,f as approvalQuorumKind,h as approvalReason,p as approvalReference,M as approvalRunDocument,c as approvalRunState,u as approvalStepKind,j as approvalWorkflowDescriptor,A as approvalWorkflowStep};
|
|
2
2
|
//# sourceMappingURL=validators.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validators.mjs","names":[],"sources":["../../../src/components/approvals/validators.ts"],"sourcesContent":["import { zid } from 'convex-helpers/server/zod4'\nimport { z } from 'zod'\n\nimport {\n\tAPPROVAL_CALLBACK_KINDS,\n\tAPPROVAL_DECISIONS,\n\tAPPROVAL_DESCRIPTOR_SCHEMA_VERSION,\n\tAPPROVAL_QUORUM_KINDS,\n\tAPPROVAL_RUN_STATES,\n\tAPPROVAL_STEP_KINDS,\n\tMAX_APPROVAL_CAPABILITIES,\n\tMAX_APPROVAL_DECISIONS_PER_STEP,\n\tMAX_APPROVAL_METADATA_ENTRIES,\n\tMAX_APPROVAL_METADATA_KEY_LENGTH,\n\tMAX_APPROVAL_METADATA_VALUE_LENGTH,\n\tMAX_APPROVAL_NAME_LENGTH,\n\tMAX_APPROVAL_REASON_LENGTH,\n\tMAX_APPROVAL_REFERENCE_LENGTH,\n\tMAX_APPROVAL_WORKFLOW_STEPS,\n} from './constants'\n\nexport const approvalRunState = z.enum(APPROVAL_RUN_STATES)\nexport const approvalDecision = z.enum(APPROVAL_DECISIONS)\nexport const approvalStepKind = z.enum(APPROVAL_STEP_KINDS)\nexport const approvalCallbackKind = z.enum(APPROVAL_CALLBACK_KINDS)\nexport const approvalQuorumKind = z.enum(APPROVAL_QUORUM_KINDS)\n\nexport const approvalReference = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_REFERENCE_LENGTH)\n\nexport const approvalName = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_NAME_LENGTH)\n\t.regex(/^[A-Za-z][A-Za-z0-9._-]*$/)\n\nexport const approvalReason = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_REASON_LENGTH)\n\nexport const approvalMetadata = z\n\t.record(\n\t\tz\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_METADATA_KEY_LENGTH)\n\t\t\t.regex(/^(?![$_])[\\x20-\\x7E]+$/),\n\t\tz.string().max(MAX_APPROVAL_METADATA_VALUE_LENGTH),\n\t)\n\t.refine(\n\t\t(value) => Object.keys(value).length <= MAX_APPROVAL_METADATA_ENTRIES,\n\t\t`Metadata may contain at most ${MAX_APPROVAL_METADATA_ENTRIES} entries`,\n\t)\n\nexport const approvalActor = z\n\t.object({\n\t\tactorRef: approvalReference,\n\t\tcapabilities: z.array(approvalName).max(MAX_APPROVAL_CAPABILITIES),\n\t\tmetadata: approvalMetadata.optional(),\n\t})\n\t.strict()\n\nexport const approvalMutationCallback = z\n\t.object({\n\t\tkind: z.literal('mutation'),\n\t\thandle: approvalReference,\n\t\tretry: z.boolean(),\n\t})\n\t.strict()\n\nexport const approvalActionCallback = z\n\t.object({\n\t\tkind: z.literal('action'),\n\t\thandle: approvalReference,\n\t\tretry: z.boolean(),\n\t})\n\t.strict()\n\nexport const approvalCallback = z.discriminatedUnion('kind', [\n\tapprovalMutationCallback,\n\tapprovalActionCallback,\n])\n\nexport const approvalQuorum = z\n\t.object({\n\t\tkind: approvalQuorumKind,\n\t\tapprovals: z.number().int().positive().max(MAX_APPROVAL_DECISIONS_PER_STEP),\n\t})\n\t.strict()\n\nexport const approvalCallbackStep = z.discriminatedUnion('kind', [\n\tz\n\t\t.object({\n\t\t\tkind: z.literal('mutation'),\n\t\t\tkey: approvalName,\n\t\t\tcallback: approvalMutationCallback,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\tkind: z.literal('action'),\n\t\t\tkey: approvalName,\n\t\t\tcallback: approvalActionCallback,\n\t\t})\n\t\t.strict(),\n])\n\nexport const approvalNotifyStep = z\n\t.object({\n\t\tkind: z.literal('notify'),\n\t\tkey: approvalName,\n\t\tcallback: approvalActionCallback,\n\t})\n\t.strict()\n\nexport const approvalDecisionStep = z\n\t.object({\n\t\tkind: z.literal('decision'),\n\t\tkey: approvalName,\n\t\tdecisions: z\n\t\t\t.array(approvalDecision)\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_DECISIONS_PER_STEP),\n\t\tquorum: approvalQuorum,\n\t\tmakerChecker: z.boolean(),\n\t\texpiresAfterMs: z.number().int().positive().optional(),\n\t})\n\t.strict()\n\nexport const approvalBranchStep = z\n\t.object({\n\t\tkind: z.literal('branch'),\n\t\tkey: approvalName,\n\t\tapprovedStepKey: approvalName,\n\t\trejectedStepKey: approvalName,\n\t})\n\t.strict()\n\nexport const approvalWorkflowStep = z.discriminatedUnion('kind', [\n\tapprovalCallbackStep,\n\tapprovalNotifyStep,\n\tapprovalDecisionStep,\n\tapprovalBranchStep,\n])\n\nexport const approvalWorkflowDescriptor = z\n\t.object({\n\t\tschemaVersion: z.literal(APPROVAL_DESCRIPTOR_SCHEMA_VERSION),\n\t\tcompatibilityKey: approvalName,\n\t\tname: approvalName,\n\t\tsteps: z\n\t\t\t.array(approvalWorkflowStep)\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_WORKFLOW_STEPS),\n\t})\n\t.strict()\n\t.superRefine((descriptor, context) => {\n\t\tconst keys = new Set<string>()\n\t\tconst stepsByKey = new Map(\n\t\t\tdescriptor.steps.map((step) => [step.key, step] as const),\n\t\t)\n\t\tconst branchTargetOwners = new Map<string, number>()\n\t\tfor (const [index, step] of descriptor.steps.entries()) {\n\t\t\tif (keys.has(step.key))\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Duplicate workflow step key: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index, 'key'],\n\t\t\t\t})\n\t\t\tkeys.add(step.key)\n\t\t\tif (\n\t\t\t\tstep.kind === 'decision' &&\n\t\t\t\tnew Set(step.decisions).size !== step.decisions.length\n\t\t\t)\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Duplicate decision value in step: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index, 'decisions'],\n\t\t\t\t})\n\t\t}\n\t\tfor (const [index, step] of descriptor.steps.entries()) {\n\t\t\tif (step.kind !== 'branch') continue\n\t\t\tif (descriptor.steps[index - 1]?.kind !== 'decision')\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Branch must immediately follow a decision: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t})\n\t\t\tfor (const target of [step.approvedStepKey, step.rejectedStepKey]) {\n\t\t\t\tconst targetStep = stepsByKey.get(target)\n\t\t\t\tconst targetIndex = descriptor.steps.findIndex(\n\t\t\t\t\t(candidate) => candidate.key === target,\n\t\t\t\t)\n\t\t\t\tif (!targetStep)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Unknown branch target: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\telse if (\n\t\t\t\t\ttargetStep.kind !== 'mutation' &&\n\t\t\t\t\ttargetStep.kind !== 'action' &&\n\t\t\t\t\ttargetStep.kind !== 'notify'\n\t\t\t\t)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Branch target must be a callback step: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\telse if (targetIndex <= index)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Branch target must be declared after its branch: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\tbranchTargetOwners.set(\n\t\t\t\t\ttarget,\n\t\t\t\t\t(branchTargetOwners.get(target) ?? 0) + 1,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tfor (const [target, owners] of branchTargetOwners) {\n\t\t\tif (owners !== 1)\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Branch callback must belong to exactly one branch: ${target}`,\n\t\t\t\t\tpath: ['steps'],\n\t\t\t\t})\n\t\t}\n\t})\n\nexport const approvalRunDocument = z\n\t.object({\n\t\tscopeRef: approvalReference,\n\t\tresourceType: approvalName,\n\t\tresourceRef: approvalReference,\n\t\trequester: approvalActor,\n\t\tmetadata: approvalMetadata.optional(),\n\t\tworkflow: approvalWorkflowDescriptor,\n\t\tstate: approvalRunState,\n\t\tcurrentStepKey: approvalName.optional(),\n\t\texecutionFailedStepKey: approvalName.optional(),\n\t\texpiresAt: z.number().optional(),\n\t\tworkflowId: approvalReference.optional(),\n\t\tcreatedAt: z.number(),\n\t\tupdatedAt: z.number(),\n\t\tterminalAt: z.number().optional(),\n\t})\n\t.strict()\n\nexport const approvalDecisionDocument = z\n\t.object({\n\t\trunId: zid('approvalRuns'),\n\t\tstepKey: approvalName,\n\t\tactor: approvalActor,\n\t\tdecision: approvalDecision,\n\t\treason: approvalReason.optional(),\n\t\tdecidedAt: z.number(),\n\t})\n\t.strict()\n\nexport type ApprovalWorkflowDescriptor = z.infer<\n\ttypeof approvalWorkflowDescriptor\n>\nexport type ApprovalActor = z.infer<typeof approvalActor>\nexport type ApprovalMetadata = z.infer<typeof approvalMetadata>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validators.mjs","names":[],"sources":["../../../src/components/approvals/validators.ts"],"sourcesContent":["import { zid, zodToConvex } from 'convex-helpers/server/zod4'\nimport { z } from 'zod'\n\nimport {\n\tAPPROVAL_CALLBACK_KINDS,\n\tAPPROVAL_DECISIONS,\n\tAPPROVAL_DESCRIPTOR_SCHEMA_VERSION,\n\tAPPROVAL_QUORUM_KINDS,\n\tAPPROVAL_RUN_STATES,\n\tAPPROVAL_STEP_KINDS,\n\tMAX_APPROVAL_CAPABILITIES,\n\tMAX_APPROVAL_DECISIONS_PER_STEP,\n\tMAX_APPROVAL_METADATA_ENTRIES,\n\tMAX_APPROVAL_METADATA_KEY_LENGTH,\n\tMAX_APPROVAL_METADATA_VALUE_LENGTH,\n\tMAX_APPROVAL_NAME_LENGTH,\n\tMAX_APPROVAL_REASON_LENGTH,\n\tMAX_APPROVAL_REFERENCE_LENGTH,\n\tMAX_APPROVAL_WORKFLOW_STEPS,\n} from './constants'\n\nexport const approvalRunState = z.enum(APPROVAL_RUN_STATES)\nexport const approvalDecision = z.enum(APPROVAL_DECISIONS)\nexport const approvalStepKind = z.enum(APPROVAL_STEP_KINDS)\nexport const approvalCallbackKind = z.enum(APPROVAL_CALLBACK_KINDS)\nexport const approvalQuorumKind = z.enum(APPROVAL_QUORUM_KINDS)\n\nexport const approvalReference = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_REFERENCE_LENGTH)\n\nexport const approvalName = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_NAME_LENGTH)\n\t.regex(/^[A-Za-z][A-Za-z0-9._-]*$/)\n\nexport const approvalReason = z\n\t.string()\n\t.trim()\n\t.min(1)\n\t.max(MAX_APPROVAL_REASON_LENGTH)\n\nexport const approvalMetadata = z\n\t.record(\n\t\tz\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_METADATA_KEY_LENGTH)\n\t\t\t.regex(/^(?![$_])[\\x20-\\x7E]+$/),\n\t\tz.string().max(MAX_APPROVAL_METADATA_VALUE_LENGTH),\n\t)\n\t.refine(\n\t\t(value) => Object.keys(value).length <= MAX_APPROVAL_METADATA_ENTRIES,\n\t\t`Metadata may contain at most ${MAX_APPROVAL_METADATA_ENTRIES} entries`,\n\t)\n\nconst approvalCallbackEvidence = z\n\t.object({\n\t\tstepKey: approvalName,\n\t\tactorRef: approvalReference,\n\t\tdecision: approvalDecision,\n\t\treason: approvalReason.optional(),\n\t\tdecidedAt: z.number(),\n\t})\n\t.strict()\n\nconst approvalCallbackTerminalEvidence = approvalCallbackEvidence.omit({\n\tstepKey: true,\n})\n\nexport const approvalCallbackInput = z\n\t.object({\n\t\trunId: approvalReference,\n\t\tscopeRef: approvalReference,\n\t\tresourceType: approvalName,\n\t\tresourceRef: approvalReference,\n\t\tmetadata: approvalMetadata.optional(),\n\t\tdecision: z\n\t\t\t.object({\n\t\t\t\tstepKey: approvalName,\n\t\t\t\toutcome: z.union([approvalDecision, z.literal('expired')]),\n\t\t\t\tevidence: z.array(approvalCallbackEvidence),\n\t\t\t\tterminalEvidence: approvalCallbackTerminalEvidence.optional(),\n\t\t\t})\n\t\t\t.strict()\n\t\t\t.optional(),\n\t})\n\t.strict()\n\n/** Convex argument validator for approval mutation, action, and notify callbacks. */\nexport const approvalCallbackArgs = zodToConvex(approvalCallbackInput)\n\nexport const approvalActor = z\n\t.object({\n\t\tactorRef: approvalReference,\n\t\tcapabilities: z.array(approvalName).max(MAX_APPROVAL_CAPABILITIES),\n\t\tmetadata: approvalMetadata.optional(),\n\t})\n\t.strict()\n\nexport const approvalMutationCallback = z\n\t.object({\n\t\tkind: z.literal('mutation'),\n\t\thandle: approvalReference,\n\t\tretry: z.boolean(),\n\t})\n\t.strict()\n\nexport const approvalActionCallback = z\n\t.object({\n\t\tkind: z.literal('action'),\n\t\thandle: approvalReference,\n\t\tretry: z.boolean(),\n\t})\n\t.strict()\n\nexport const approvalCallback = z.discriminatedUnion('kind', [\n\tapprovalMutationCallback,\n\tapprovalActionCallback,\n])\n\nexport const approvalQuorum = z\n\t.object({\n\t\tkind: approvalQuorumKind,\n\t\tapprovals: z.number().int().positive().max(MAX_APPROVAL_DECISIONS_PER_STEP),\n\t})\n\t.strict()\n\nexport const approvalCallbackStep = z.discriminatedUnion('kind', [\n\tz\n\t\t.object({\n\t\t\tkind: z.literal('mutation'),\n\t\t\tkey: approvalName,\n\t\t\tcallback: approvalMutationCallback,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\tkind: z.literal('action'),\n\t\t\tkey: approvalName,\n\t\t\tcallback: approvalActionCallback,\n\t\t})\n\t\t.strict(),\n])\n\nexport const approvalNotifyStep = z\n\t.object({\n\t\tkind: z.literal('notify'),\n\t\tkey: approvalName,\n\t\tcallback: approvalActionCallback,\n\t})\n\t.strict()\n\nexport const approvalDecisionStep = z\n\t.object({\n\t\tkind: z.literal('decision'),\n\t\tkey: approvalName,\n\t\tdecisions: z\n\t\t\t.array(approvalDecision)\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_DECISIONS_PER_STEP),\n\t\tquorum: approvalQuorum,\n\t\tmakerChecker: z.boolean(),\n\t\texpiresAfterMs: z.number().int().positive().optional(),\n\t})\n\t.strict()\n\nexport const approvalBranchStep = z\n\t.object({\n\t\tkind: z.literal('branch'),\n\t\tkey: approvalName,\n\t\tapprovedStepKey: approvalName,\n\t\trejectedStepKey: approvalName,\n\t})\n\t.strict()\n\nexport const approvalWorkflowStep = z.discriminatedUnion('kind', [\n\tapprovalCallbackStep,\n\tapprovalNotifyStep,\n\tapprovalDecisionStep,\n\tapprovalBranchStep,\n])\n\nexport const approvalWorkflowDescriptor = z\n\t.object({\n\t\tschemaVersion: z.literal(APPROVAL_DESCRIPTOR_SCHEMA_VERSION),\n\t\tcompatibilityKey: approvalName,\n\t\tname: approvalName,\n\t\tsteps: z\n\t\t\t.array(approvalWorkflowStep)\n\t\t\t.min(1)\n\t\t\t.max(MAX_APPROVAL_WORKFLOW_STEPS),\n\t})\n\t.strict()\n\t.superRefine((descriptor, context) => {\n\t\tconst keys = new Set<string>()\n\t\tconst stepsByKey = new Map(\n\t\t\tdescriptor.steps.map((step) => [step.key, step] as const),\n\t\t)\n\t\tconst branchTargetOwners = new Map<string, number>()\n\t\tfor (const [index, step] of descriptor.steps.entries()) {\n\t\t\tif (keys.has(step.key))\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Duplicate workflow step key: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index, 'key'],\n\t\t\t\t})\n\t\t\tkeys.add(step.key)\n\t\t\tif (\n\t\t\t\tstep.kind === 'decision' &&\n\t\t\t\tnew Set(step.decisions).size !== step.decisions.length\n\t\t\t)\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Duplicate decision value in step: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index, 'decisions'],\n\t\t\t\t})\n\t\t}\n\t\tfor (const [index, step] of descriptor.steps.entries()) {\n\t\t\tif (step.kind !== 'branch') continue\n\t\t\tif (descriptor.steps[index - 1]?.kind !== 'decision')\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Branch must immediately follow a decision: ${step.key}`,\n\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t})\n\t\t\tfor (const target of [step.approvedStepKey, step.rejectedStepKey]) {\n\t\t\t\tconst targetStep = stepsByKey.get(target)\n\t\t\t\tconst targetIndex = descriptor.steps.findIndex(\n\t\t\t\t\t(candidate) => candidate.key === target,\n\t\t\t\t)\n\t\t\t\tif (!targetStep)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Unknown branch target: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\telse if (\n\t\t\t\t\ttargetStep.kind !== 'mutation' &&\n\t\t\t\t\ttargetStep.kind !== 'action' &&\n\t\t\t\t\ttargetStep.kind !== 'notify'\n\t\t\t\t)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Branch target must be a callback step: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\telse if (targetIndex <= index)\n\t\t\t\t\tcontext.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Branch target must be declared after its branch: ${target}`,\n\t\t\t\t\t\tpath: ['steps', index],\n\t\t\t\t\t})\n\t\t\t\tbranchTargetOwners.set(\n\t\t\t\t\ttarget,\n\t\t\t\t\t(branchTargetOwners.get(target) ?? 0) + 1,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tfor (const [target, owners] of branchTargetOwners) {\n\t\t\tif (owners !== 1)\n\t\t\t\tcontext.addIssue({\n\t\t\t\t\tcode: 'custom',\n\t\t\t\t\tmessage: `Branch callback must belong to exactly one branch: ${target}`,\n\t\t\t\t\tpath: ['steps'],\n\t\t\t\t})\n\t\t}\n\t})\n\nexport const approvalRunDocument = z\n\t.object({\n\t\tscopeRef: approvalReference,\n\t\tresourceType: approvalName,\n\t\tresourceRef: approvalReference,\n\t\trequester: approvalActor,\n\t\tmetadata: approvalMetadata.optional(),\n\t\tworkflow: approvalWorkflowDescriptor,\n\t\tstate: approvalRunState,\n\t\tcurrentStepKey: approvalName.optional(),\n\t\texecutionFailedStepKey: approvalName.optional(),\n\t\texpiresAt: z.number().optional(),\n\t\tworkflowId: approvalReference.optional(),\n\t\tcreatedAt: z.number(),\n\t\tupdatedAt: z.number(),\n\t\tterminalAt: z.number().optional(),\n\t})\n\t.strict()\n\nexport const approvalDecisionDocument = z\n\t.object({\n\t\trunId: zid('approvalRuns'),\n\t\tstepKey: approvalName,\n\t\tactor: approvalActor,\n\t\tdecision: approvalDecision,\n\t\treason: approvalReason.optional(),\n\t\tdecidedAt: z.number(),\n\t})\n\t.strict()\n\nexport type ApprovalWorkflowDescriptor = z.infer<\n\ttypeof approvalWorkflowDescriptor\n>\nexport type ApprovalActor = z.infer<typeof approvalActor>\nexport type ApprovalMetadata = z.infer<typeof approvalMetadata>\nexport type ApprovalCallbackInput = Readonly<\n\tz.infer<typeof approvalCallbackInput>\n>\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApprovalDecision } from "./constants.mjs";
|
|
2
|
-
import { ApprovalWorkflowDescriptor } from "./validators.mjs";
|
|
2
|
+
import { ApprovalCallbackInput, ApprovalWorkflowDescriptor } from "./validators.mjs";
|
|
3
3
|
import { FunctionReference, FunctionType } from "convex/server";
|
|
4
4
|
declare namespace workflow_steps_d_exports {
|
|
5
5
|
export { ApprovalActionStep, ApprovalBranchStep, ApprovalCallbackInput, ApprovalDecisionEvidence, ApprovalDecisionStep, ApprovalDefinition, ApprovalMutationStep, ApprovalNotifyStep, ApprovalWorkflowStep, CreateApprovalHandle, approvalDecisionEventName, callbackReference, compileApprovalDescriptor, evaluateDecisionOutcome, resolveWorkflowStepIndex };
|
|
@@ -50,34 +50,11 @@ type ApprovalDecisionEvidence = Readonly<{
|
|
|
50
50
|
actorRef: string;
|
|
51
51
|
decision: ApprovalDecision;
|
|
52
52
|
}>;
|
|
53
|
-
type ApprovalCallbackInput = Readonly<{
|
|
54
|
-
runId: string;
|
|
55
|
-
scopeRef: string;
|
|
56
|
-
resourceType: string;
|
|
57
|
-
resourceRef: string;
|
|
58
|
-
metadata?: Readonly<Record<string, string>>;
|
|
59
|
-
decision?: Readonly<{
|
|
60
|
-
stepKey: string;
|
|
61
|
-
outcome: ApprovalDecision | 'expired';
|
|
62
|
-
evidence: readonly Readonly<{
|
|
63
|
-
actorRef: string;
|
|
64
|
-
decision: ApprovalDecision;
|
|
65
|
-
reason?: string;
|
|
66
|
-
decidedAt: number;
|
|
67
|
-
}>[];
|
|
68
|
-
terminalEvidence?: Readonly<{
|
|
69
|
-
actorRef: string;
|
|
70
|
-
decision: ApprovalDecision;
|
|
71
|
-
reason?: string;
|
|
72
|
-
decidedAt: number;
|
|
73
|
-
}>;
|
|
74
|
-
}>;
|
|
75
|
-
}>;
|
|
76
53
|
declare function approvalDecisionEventName(runId: string, stepKey: string): string;
|
|
77
54
|
declare function evaluateDecisionOutcome(decisions: readonly ApprovalDecisionEvidence[], approvalsRequired: number): ApprovalDecision | null;
|
|
78
55
|
declare function resolveWorkflowStepIndex(stepKeys: readonly string[], targetKey: string): number;
|
|
79
56
|
declare function callbackReference<Type extends FunctionType>(handle: string): FunctionReference<Type, 'internal', ApprovalCallbackInput, unknown>;
|
|
80
57
|
declare function compileApprovalDescriptor(definition: ApprovalDefinition, createHandle?: CreateApprovalHandle): Promise<Readonly<ApprovalWorkflowDescriptor>>;
|
|
81
58
|
//#endregion
|
|
82
|
-
export { ApprovalActionStep, ApprovalBranchStep, ApprovalCallbackInput, ApprovalDecisionEvidence, ApprovalDecisionStep, ApprovalDefinition, ApprovalMutationStep, ApprovalNotifyStep, ApprovalWorkflowStep, CreateApprovalHandle, approvalDecisionEventName, callbackReference, compileApprovalDescriptor, evaluateDecisionOutcome, resolveWorkflowStepIndex, workflow_steps_d_exports };
|
|
59
|
+
export { ApprovalActionStep, ApprovalBranchStep, type ApprovalCallbackInput, ApprovalDecisionEvidence, ApprovalDecisionStep, ApprovalDefinition, ApprovalMutationStep, ApprovalNotifyStep, ApprovalWorkflowStep, CreateApprovalHandle, approvalDecisionEventName, callbackReference, compileApprovalDescriptor, evaluateDecisionOutcome, resolveWorkflowStepIndex, workflow_steps_d_exports };
|
|
83
60
|
//# sourceMappingURL=workflow_steps.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow_steps.mjs","names":[],"sources":["../../../src/components/approvals/workflow_steps.ts"],"sourcesContent":["import {\n\tcreateFunctionHandle,\n\ttype FunctionReference,\n\ttype FunctionType,\n} from 'convex/server'\n\nimport type { ApprovalDecision } from './constants'\nimport {\n\tapprovalWorkflowDescriptor,\n\ttype ApprovalWorkflowDescriptor,\n} from './validators'\n\nexport type ApprovalMutationStep = Readonly<{\n\tkind: 'mutation'\n\tkey: string\n\thandler: FunctionReference<'mutation', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalActionStep = Readonly<{\n\tkind: 'action'\n\tkey: string\n\thandler: FunctionReference<'action', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalNotifyStep = Readonly<{\n\tkind: 'notify'\n\tkey: string\n\thandler: FunctionReference<'action', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalDecisionStep = Readonly<{\n\tkind: 'decision'\n\tkey: string\n\tdecisions: readonly ApprovalDecision[]\n\tquorum: Readonly<{ kind: 'count'; approvals: number }>\n\tmakerChecker: boolean\n\texpiresAfterMs?: number\n}>\n\nexport type ApprovalBranchStep = Readonly<{\n\tkind: 'branch'\n\tkey: string\n\tapprovedStepKey: string\n\trejectedStepKey: string\n}>\n\nexport type ApprovalWorkflowStep =\n\t| ApprovalMutationStep\n\t| ApprovalActionStep\n\t| ApprovalNotifyStep\n\t| ApprovalDecisionStep\n\t| ApprovalBranchStep\n\nexport type ApprovalDefinition = Readonly<{\n\tname: string\n\tcompatibilityKey: string\n\tsteps: readonly ApprovalWorkflowStep[]\n}>\n\nexport type CreateApprovalHandle = (\n\treference: FunctionReference<'mutation' | 'action', 'internal'>,\n) => Promise<string>\n\nexport type ApprovalDecisionEvidence = Readonly<{\n\tactorRef: string\n\tdecision: ApprovalDecision\n}>\n\nexport
|
|
1
|
+
{"version":3,"file":"workflow_steps.mjs","names":[],"sources":["../../../src/components/approvals/workflow_steps.ts"],"sourcesContent":["import {\n\tcreateFunctionHandle,\n\ttype FunctionReference,\n\ttype FunctionType,\n} from 'convex/server'\n\nimport type { ApprovalDecision } from './constants'\nimport {\n\tapprovalWorkflowDescriptor,\n\ttype ApprovalCallbackInput,\n\ttype ApprovalWorkflowDescriptor,\n} from './validators'\n\nexport type { ApprovalCallbackInput } from './validators'\n\nexport type ApprovalMutationStep = Readonly<{\n\tkind: 'mutation'\n\tkey: string\n\thandler: FunctionReference<'mutation', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalActionStep = Readonly<{\n\tkind: 'action'\n\tkey: string\n\thandler: FunctionReference<'action', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalNotifyStep = Readonly<{\n\tkind: 'notify'\n\tkey: string\n\thandler: FunctionReference<'action', 'internal'>\n\tretry: boolean\n}>\n\nexport type ApprovalDecisionStep = Readonly<{\n\tkind: 'decision'\n\tkey: string\n\tdecisions: readonly ApprovalDecision[]\n\tquorum: Readonly<{ kind: 'count'; approvals: number }>\n\tmakerChecker: boolean\n\texpiresAfterMs?: number\n}>\n\nexport type ApprovalBranchStep = Readonly<{\n\tkind: 'branch'\n\tkey: string\n\tapprovedStepKey: string\n\trejectedStepKey: string\n}>\n\nexport type ApprovalWorkflowStep =\n\t| ApprovalMutationStep\n\t| ApprovalActionStep\n\t| ApprovalNotifyStep\n\t| ApprovalDecisionStep\n\t| ApprovalBranchStep\n\nexport type ApprovalDefinition = Readonly<{\n\tname: string\n\tcompatibilityKey: string\n\tsteps: readonly ApprovalWorkflowStep[]\n}>\n\nexport type CreateApprovalHandle = (\n\treference: FunctionReference<'mutation' | 'action', 'internal'>,\n) => Promise<string>\n\nexport type ApprovalDecisionEvidence = Readonly<{\n\tactorRef: string\n\tdecision: ApprovalDecision\n}>\n\nexport function approvalDecisionEventName(\n\trunId: string,\n\tstepKey: string,\n): string {\n\treturn `approval:${runId}:${stepKey}`\n}\n\nexport function evaluateDecisionOutcome(\n\tdecisions: readonly ApprovalDecisionEvidence[],\n\tapprovalsRequired: number,\n): ApprovalDecision | null {\n\tif (decisions.some((decision) => decision.decision === 'rejected'))\n\t\treturn 'rejected'\n\treturn decisions.filter((decision) => decision.decision === 'approved')\n\t\t.length >= approvalsRequired\n\t\t? 'approved'\n\t\t: null\n}\n\nexport function resolveWorkflowStepIndex(\n\tstepKeys: readonly string[],\n\ttargetKey: string,\n): number {\n\tconst index = stepKeys.indexOf(targetKey)\n\tif (index === -1)\n\t\tthrow new Error(`Unknown approval workflow step: ${targetKey}`)\n\treturn index\n}\n\nexport function callbackReference<Type extends FunctionType>(\n\thandle: string,\n): FunctionReference<Type, 'internal', ApprovalCallbackInput, unknown> {\n\treturn handle as unknown as FunctionReference<\n\t\tType,\n\t\t'internal',\n\t\tApprovalCallbackInput,\n\t\tunknown\n\t>\n}\n\nexport async function compileApprovalDescriptor(\n\tdefinition: ApprovalDefinition,\n\tcreateHandle: CreateApprovalHandle = createFunctionHandle,\n): Promise<Readonly<ApprovalWorkflowDescriptor>> {\n\tconst steps = await Promise.all(\n\t\tdefinition.steps.map(async (step) => {\n\t\t\tif (step.kind === 'mutation' || step.kind === 'action') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: step.kind,\n\t\t\t\t\tkey: step.key,\n\t\t\t\t\tcallback: {\n\t\t\t\t\t\tkind: step.kind,\n\t\t\t\t\t\thandle: await createHandle(step.handler),\n\t\t\t\t\t\tretry: step.retry,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (step.kind === 'notify') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: step.kind,\n\t\t\t\t\tkey: step.key,\n\t\t\t\t\tcallback: {\n\t\t\t\t\t\tkind: 'action' as const,\n\t\t\t\t\t\thandle: await createHandle(step.handler),\n\t\t\t\t\t\tretry: step.retry,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (step.kind === 'decision') {\n\t\t\t\treturn {\n\t\t\t\t\t...step,\n\t\t\t\t\tdecisions: [...step.decisions],\n\t\t\t\t\tquorum: { ...step.quorum },\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...step }\n\t\t}),\n\t)\n\tconst descriptor = approvalWorkflowDescriptor.parse({\n\t\tschemaVersion: 1,\n\t\tcompatibilityKey: definition.compatibilityKey,\n\t\tname: definition.name,\n\t\tsteps,\n\t})\n\treturn deepFreeze(descriptor)\n}\n\nfunction deepFreeze<Value>(value: Value): Readonly<Value> {\n\tif (value && typeof value === 'object') {\n\t\tObject.freeze(value)\n\t\tfor (const nested of Object.values(value)) deepFreeze(nested)\n\t}\n\treturn value\n}\n"],"mappings":"mHA0EA,SAAgB,EACf,EACA,EACS,CACT,MAAO,YAAY,EAAM,GAAG,GAC7B,CAEA,SAAgB,EACf,EACA,EAC0B,CAG1B,OAFI,EAAU,KAAM,GAAa,EAAS,WAAa,UAAU,EACzD,WACD,EAAU,OAAQ,GAAa,EAAS,WAAa,UAAU,CAAC,CACrE,QAAU,EACT,WACA,IACJ,CAEA,SAAgB,EACf,EACA,EACS,CACT,IAAM,EAAQ,EAAS,QAAQ,CAAS,EACxC,GAAI,IAAU,GACb,MAAU,MAAM,mCAAmC,GAAW,EAC/D,OAAO,CACR,CAEA,SAAgB,EACf,EACsE,CACtE,OAAO,CAMR,CAEA,eAAsB,EACrB,EACA,EAAqC,EACW,CAChD,IAAM,EAAQ,MAAM,QAAQ,IAC3B,EAAW,MAAM,IAAI,KAAO,IACvB,EAAK,OAAS,YAAc,EAAK,OAAS,SACtC,CACN,KAAM,EAAK,KACX,IAAK,EAAK,IACV,SAAU,CACT,KAAM,EAAK,KACX,OAAQ,MAAM,EAAa,EAAK,OAAO,EACvC,MAAO,EAAK,KACb,CACD,EAEG,EAAK,OAAS,SACV,CACN,KAAM,EAAK,KACX,IAAK,EAAK,IACV,SAAU,CACT,KAAM,SACN,OAAQ,MAAM,EAAa,EAAK,OAAO,EACvC,MAAO,EAAK,KACb,CACD,EAEG,EAAK,OAAS,WACV,CACN,GAAG,EACH,UAAW,CAAC,GAAG,EAAK,SAAS,EAC7B,OAAQ,CAAE,GAAG,EAAK,MAAO,CAC1B,EAEM,CAAE,GAAG,CAAK,CACjB,CACF,EAOA,OAAO,EANY,EAA2B,MAAM,CACnD,cAAe,EACf,iBAAkB,EAAW,iBAC7B,KAAM,EAAW,KACjB,OACD,CAC2B,CAAC,CAC7B,CAEA,SAAS,EAAkB,EAA+B,CACzD,GAAI,GAAS,OAAO,GAAU,SAAU,CACvC,OAAO,OAAO,CAAK,EACnB,IAAK,IAAM,KAAU,OAAO,OAAO,CAAK,EAAG,EAAW,CAAM,CAC7D,CACA,OAAO,CACR"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import _default from "../schema.
|
|
1
|
+
import _default from "../schema.js";
|
|
2
2
|
import { DataModelFromSchemaDefinition, DocumentByName, SystemTableNames, TableNamesInDataModel } from "convex/server";
|
|
3
3
|
import { GenericId } from "convex/values";
|
|
4
4
|
//#region src/components/foundation/_generated/dataModel.d.ts
|
package/docs/approvals.md
CHANGED
|
@@ -16,6 +16,20 @@ import approvals from 'cvx-kit/components/approvals/convex.config'
|
|
|
16
16
|
app.use(approvals)
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
After installation or upgrade, deploy once and run the component health query
|
|
20
|
+
from a host wrapper:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
return ctx.runQuery(components.approvals.health.check, {})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
It returns the installed approvals schema version and required index names. It
|
|
27
|
+
also executes reads through
|
|
28
|
+
`approvalDecisions.by_runId_and_decidedAt` and
|
|
29
|
+
`approvalDecisions.by_runId_and_stepKey_and_actor_actorRef`, failing with an
|
|
30
|
+
installation-specific diagnostic if the packaged component schema was not
|
|
31
|
+
deployed.
|
|
32
|
+
|
|
19
33
|
The component mounts its own private `workflow` and `auditLog` children. Do
|
|
20
34
|
**not** re-register those children at the app root under the same identity,
|
|
21
35
|
and never reach into `components.approvals.workflow` / `.auditLog` from host
|
|
@@ -99,10 +113,14 @@ const { runId } = await publishApproval.start(ctx, {
|
|
|
99
113
|
// decide — a manager approves or rejects
|
|
100
114
|
await publishApproval.decide(ctx, { runId, decision: 'approved', reason }, ctx.actor)
|
|
101
115
|
|
|
102
|
-
// observe
|
|
116
|
+
// observe from a host query
|
|
103
117
|
await publishApproval.status(ctx, runId) // pending | approved | rejected | expired | canceled
|
|
104
118
|
await publishApproval.evidence(ctx, runId) // per-step decision evidence
|
|
105
|
-
await publishApproval.list(ctx, {
|
|
119
|
+
await publishApproval.list(ctx, {
|
|
120
|
+
scopeRef,
|
|
121
|
+
state: 'pending',
|
|
122
|
+
paginationOpts: { cursor: null, numItems: 20 },
|
|
123
|
+
})
|
|
106
124
|
|
|
107
125
|
// manage
|
|
108
126
|
await publishApproval.cancel(ctx, runId, ctx.actor)
|
|
@@ -119,6 +137,8 @@ Because the component cannot know your tables, the handler must re-establish
|
|
|
119
137
|
trust:
|
|
120
138
|
|
|
121
139
|
```ts
|
|
140
|
+
import { approvalCallbackArgs } from 'cvx-kit/components/approvals'
|
|
141
|
+
|
|
122
142
|
export const applyDecision = systemMutation({
|
|
123
143
|
args: approvalCallbackArgs,
|
|
124
144
|
handler: async (ctx, input) => {
|
|
@@ -136,6 +156,34 @@ export const applyDecision = systemMutation({
|
|
|
136
156
|
That `approvalRunId` check is the idempotency/staleness guard from the origin
|
|
137
157
|
app — copy it.
|
|
138
158
|
|
|
159
|
+
For branch callbacks, `decision.evidence` contains
|
|
160
|
+
`{ stepKey, actorRef, decision, reason?, decidedAt }` items. Use the exported
|
|
161
|
+
`approvalCallbackArgs` validator instead of duplicating that protocol boundary.
|
|
162
|
+
|
|
163
|
+
### Paginated inboxes
|
|
164
|
+
|
|
165
|
+
Expose the configured workflow through a host query; component pagination uses
|
|
166
|
+
`convex-helpers` internally because Convex's built-in `.paginate()` is not
|
|
167
|
+
available inside components:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
export const approvalInbox = authQuery({
|
|
171
|
+
args: {
|
|
172
|
+
state: z.enum(['pending', 'approved', 'rejected', 'expired', 'canceled']).optional(),
|
|
173
|
+
paginationOpts: convexToZod(paginationOptsValidator),
|
|
174
|
+
},
|
|
175
|
+
handler: (ctx, args) => publishApproval.list(ctx, {
|
|
176
|
+
scopeRef: ctx.org.organizationId,
|
|
177
|
+
...args,
|
|
178
|
+
}),
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The result keeps Convex's standard pagination shape, so React consumers can
|
|
183
|
+
call `usePaginatedQuery(api.approvals.approvalInbox, { state: 'pending' },
|
|
184
|
+
{ initialNumItems: 20 })`. Pass each returned cursor only back to the same
|
|
185
|
+
scope/state query.
|
|
186
|
+
|
|
139
187
|
## Rules and footguns
|
|
140
188
|
|
|
141
189
|
1. Root facade (`convex/approvals.ts`) instantiates the client; workflow
|
package/docs/upgrading.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Upgrading to 0.1.0 — the new way of things
|
|
2
2
|
|
|
3
|
+
## Approvals packaging repair (0.1.x patch)
|
|
4
|
+
|
|
5
|
+
`cvx-kit@0.1.0` published component schemas as `schema.mjs`, which Convex does
|
|
6
|
+
not discover for packaged components. Upgrade to the patch containing this
|
|
7
|
+
repair, remove any `patchedDependencies` entry that copied or renamed the
|
|
8
|
+
approvals schema, reinstall from a clean lockfile state, and run one normal
|
|
9
|
+
deployment:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun install
|
|
13
|
+
bunx convex dev --once
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The repaired package publishes only `schema.js` and `schema.d.ts` for each
|
|
17
|
+
component. Do not retain both `.mjs` and `.js`; Convex canonicalizes them to the
|
|
18
|
+
same module and rejects the deployment with `CanonicalizationConflict`.
|
|
19
|
+
|
|
20
|
+
This upgrade does not change table fields or index definitions, so a second
|
|
21
|
+
deployment is not required for staged index backfills. Existing deployments
|
|
22
|
+
that never received the component schema will create the tables and indexes on
|
|
23
|
+
the first repaired deployment. Confirm readiness through
|
|
24
|
+
`components.approvals.health.check` before resuming approval traffic.
|
|
25
|
+
|
|
3
26
|
The migration file for consumers on 0.0.x. Each section: the old way you were
|
|
4
27
|
hand-writing, the 0.1.0 way, and what stays unchanged. Nothing existing
|
|
5
28
|
breaks in this release except one boundary-mask improvement (see the last
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cvx-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Reusable Convex application kit: foundation kernels, approvals component, zod table boundaries, WorkOS-backed auth function constructors, and audited command protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -90,7 +90,10 @@
|
|
|
90
90
|
"scripts": {
|
|
91
91
|
"build": "vp pack && node scripts/convex-config-bridge.mjs && publint",
|
|
92
92
|
"typecheck": "tsc --noEmit",
|
|
93
|
-
"test": "vp test run",
|
|
93
|
+
"test": "vp test run --exclude test/package-contents.test.mjs",
|
|
94
|
+
"test:package": "bun run build && vp test run test/package-contents.test.mjs",
|
|
95
|
+
"test:package:smoke:bun": "bun scripts/smoke-packed-components.mjs bun",
|
|
96
|
+
"test:package:smoke:npm": "node scripts/smoke-packed-components.mjs npm",
|
|
94
97
|
"docs:sync": "rm -f docs/*.md && cp src/docs/*.md docs/",
|
|
95
98
|
"prepublishOnly": "bun run build && bun run typecheck && bun run test && bun run docs:sync",
|
|
96
99
|
"build:codegen": "convex codegen --component-dir ./src/components/foundation && convex codegen --component-dir ./src/components/approvals && vp pack",
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
// is literally named `convex.config.js` (see DEFINITION_FILENAME_JS in the
|
|
3
3
|
// convex CLI). vp pack emits .mjs, so this postbuild step materializes the
|
|
4
4
|
// compiled definition as convex.config.js in each component's dist directory.
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
readFileSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
renameSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from 'node:fs'
|
|
6
12
|
import { dirname, join } from 'node:path'
|
|
7
13
|
import { fileURLToPath } from 'node:url'
|
|
8
14
|
|
|
@@ -10,8 +16,40 @@ const root = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
|
10
16
|
|
|
11
17
|
for (const component of ['foundation', 'approvals']) {
|
|
12
18
|
const directory = join(root, 'dist', 'components', component)
|
|
13
|
-
const
|
|
19
|
+
const config = readFileSync(join(directory, 'convex.config.mjs'), 'utf8')
|
|
14
20
|
.replace(/\/\/# sourceMappingURL=.*\n?/, '')
|
|
15
|
-
writeFileSync(join(directory, 'convex.config.js'),
|
|
21
|
+
writeFileSync(join(directory, 'convex.config.js'), config)
|
|
22
|
+
|
|
23
|
+
// Component implementations are discovered from schema.ts/schema.js only.
|
|
24
|
+
// Keeping schema.mjs beside schema.js is also invalid because Convex
|
|
25
|
+
// canonicalizes both extensions to the same module path.
|
|
26
|
+
const schema = readFileSync(join(directory, 'schema.mjs'), 'utf8').replace(
|
|
27
|
+
/\/\/# sourceMappingURL=.*\n?/,
|
|
28
|
+
'',
|
|
29
|
+
)
|
|
30
|
+
writeFileSync(join(directory, 'schema.js'), schema)
|
|
31
|
+
for (const filename of readdirSync(directory)) {
|
|
32
|
+
if (!filename.endsWith('.mjs')) continue
|
|
33
|
+
const path = join(directory, filename)
|
|
34
|
+
const source = readFileSync(path, 'utf8')
|
|
35
|
+
const bridged = source.replaceAll('./schema.mjs', './schema.js')
|
|
36
|
+
if (bridged !== source) writeFileSync(path, bridged)
|
|
37
|
+
}
|
|
38
|
+
renameSync(join(directory, 'schema.d.mts'), join(directory, 'schema.d.ts'))
|
|
39
|
+
const dataModelDeclaration = join(
|
|
40
|
+
directory,
|
|
41
|
+
'_generated',
|
|
42
|
+
'dataModel.d.mts',
|
|
43
|
+
)
|
|
44
|
+
writeFileSync(
|
|
45
|
+
dataModelDeclaration,
|
|
46
|
+
readFileSync(dataModelDeclaration, 'utf8').replace(
|
|
47
|
+
'../schema.mjs',
|
|
48
|
+
'../schema.js',
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
rmSync(join(directory, 'schema.mjs'))
|
|
52
|
+
rmSync(join(directory, 'schema.mjs.map'))
|
|
16
53
|
console.log(`bridged dist/components/${component}/convex.config.js`)
|
|
54
|
+
console.log(`bridged dist/components/${component}/schema.js`)
|
|
17
55
|
}
|