cvx-kit 0.1.6 → 0.1.8

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.
Files changed (116) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +63 -38
  3. package/dist/agent-tools.d.mts +2 -1
  4. package/dist/agent-tools.mjs +1 -1
  5. package/dist/agent-tools.mjs.map +1 -1
  6. package/dist/components/approvals/audit.mjs +1 -1
  7. package/dist/components/foundation/client.d.mts +16 -7
  8. package/dist/components/foundation/client.mjs +1 -1
  9. package/dist/components/foundation/client.mjs.map +1 -1
  10. package/dist/components/foundation/modules/command/command.d.mts +50 -10
  11. package/dist/components/foundation/modules/command/command.mjs +1 -1
  12. package/dist/components/foundation/modules/command/command.mjs.map +1 -1
  13. package/dist/components/foundation/modules/command/lifecycle.d.mts +81 -0
  14. package/dist/components/foundation/modules/command/lifecycle.mjs +2 -0
  15. package/dist/components/foundation/modules/command/lifecycle.mjs.map +1 -0
  16. package/dist/components/foundation/modules/observability/observability.d.mts +8 -0
  17. package/dist/components/foundation/modules/observability/observability.mjs +1 -1
  18. package/dist/components/foundation/modules/observability/observability.mjs.map +1 -1
  19. package/dist/components/foundation/operation.d.mts +6 -6
  20. package/dist/components/foundation/operation.mjs.map +1 -1
  21. package/dist/contracts.d.mts +4 -0
  22. package/dist/contracts.mjs +1 -0
  23. package/dist/crud.d.mts +2 -2
  24. package/dist/crud.mjs.map +1 -1
  25. package/dist/effect.d.mts +12 -0
  26. package/dist/effect.mjs +1 -0
  27. package/dist/errors.d.mts +2 -1
  28. package/dist/errors.mjs +1 -1
  29. package/dist/errors.mjs.map +1 -1
  30. package/dist/idempotency.d.mts +2 -0
  31. package/dist/idempotency.mjs +1 -0
  32. package/dist/modules/contracts/contract.d.mts +70 -0
  33. package/dist/modules/contracts/contract.mjs +2 -0
  34. package/dist/modules/contracts/contract.mjs.map +1 -0
  35. package/dist/modules/contracts/convex.d.mts +22 -0
  36. package/dist/modules/contracts/convex.mjs +2 -0
  37. package/dist/modules/contracts/convex.mjs.map +1 -0
  38. package/dist/modules/contracts/errors.d.mts +44 -0
  39. package/dist/modules/contracts/errors.mjs +2 -0
  40. package/dist/modules/contracts/errors.mjs.map +1 -0
  41. package/dist/modules/contracts/exposure.d.mts +105 -0
  42. package/dist/modules/contracts/exposure.mjs +2 -0
  43. package/dist/modules/contracts/exposure.mjs.map +1 -0
  44. package/dist/modules/contracts/idempotency.d.mts +87 -0
  45. package/dist/modules/contracts/idempotency.mjs +2 -0
  46. package/dist/modules/contracts/idempotency.mjs.map +1 -0
  47. package/dist/modules/contracts/standard.d.mts +16 -0
  48. package/dist/modules/contracts/standard.mjs +2 -0
  49. package/dist/modules/contracts/standard.mjs.map +1 -0
  50. package/dist/modules/contracts/workflow.d.mts +167 -0
  51. package/dist/modules/contracts/workflow.mjs +2 -0
  52. package/dist/modules/contracts/workflow.mjs.map +1 -0
  53. package/dist/modules/effect/agent-tools.d.mts +2 -0
  54. package/dist/modules/effect/agent-tools.mjs +1 -0
  55. package/dist/modules/effect/api-runtime.d.mts +38 -0
  56. package/dist/modules/effect/api-runtime.mjs +2 -0
  57. package/dist/modules/effect/api-runtime.mjs.map +1 -0
  58. package/dist/modules/effect/api-zod.d.mts +35 -0
  59. package/dist/modules/effect/api-zod.mjs +2 -0
  60. package/dist/modules/effect/api-zod.mjs.map +1 -0
  61. package/dist/modules/effect/api.d.mts +21 -0
  62. package/dist/modules/effect/api.mjs +2 -0
  63. package/dist/modules/effect/api.mjs.map +1 -0
  64. package/dist/modules/effect/client.d.mts +11 -0
  65. package/dist/modules/effect/client.mjs +1 -0
  66. package/dist/modules/effect/command.d.mts +63 -0
  67. package/dist/modules/effect/command.mjs +2 -0
  68. package/dist/modules/effect/command.mjs.map +1 -0
  69. package/dist/modules/effect/crud.d.mts +785 -0
  70. package/dist/modules/effect/crud.mjs +2 -0
  71. package/dist/modules/effect/crud.mjs.map +1 -0
  72. package/dist/modules/effect/errors.d.mts +8 -0
  73. package/dist/modules/effect/errors.mjs +2 -0
  74. package/dist/modules/effect/errors.mjs.map +1 -0
  75. package/dist/modules/effect/foundation.d.mts +21 -0
  76. package/dist/modules/effect/foundation.mjs +2 -0
  77. package/dist/modules/effect/foundation.mjs.map +1 -0
  78. package/dist/modules/effect/idempotency.d.mts +31 -0
  79. package/dist/modules/effect/idempotency.mjs +2 -0
  80. package/dist/modules/effect/idempotency.mjs.map +1 -0
  81. package/dist/modules/effect/normalize.d.mts +10 -0
  82. package/dist/modules/effect/normalize.mjs +2 -0
  83. package/dist/modules/effect/normalize.mjs.map +1 -0
  84. package/dist/modules/effect/operation.d.mts +141 -0
  85. package/dist/modules/effect/operation.mjs +2 -0
  86. package/dist/modules/effect/operation.mjs.map +1 -0
  87. package/dist/modules/effect/query.d.mts +69 -0
  88. package/dist/modules/effect/query.mjs +2 -0
  89. package/dist/modules/effect/query.mjs.map +1 -0
  90. package/dist/modules/effect/schema.d.mts +33 -0
  91. package/dist/modules/effect/schema.mjs +2 -0
  92. package/dist/modules/effect/schema.mjs.map +1 -0
  93. package/dist/modules/effect/workflow.d.mts +77 -0
  94. package/dist/modules/effect/workflow.mjs +2 -0
  95. package/dist/modules/effect/workflow.mjs.map +1 -0
  96. package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +79 -0
  97. package/dist/workflow.d.mts +2 -0
  98. package/dist/workflow.mjs +1 -0
  99. package/docs/architecture.md +3 -3
  100. package/docs/auth.md +71 -0
  101. package/docs/command-context.md +150 -0
  102. package/docs/commands-legacy.md +511 -0
  103. package/docs/commands.md +143 -363
  104. package/docs/conventions.md +15 -5
  105. package/docs/crud.md +4 -0
  106. package/docs/domain-operations.md +615 -0
  107. package/docs/effect.md +395 -0
  108. package/docs/llms.md +69 -45
  109. package/docs/migration.md +1 -1
  110. package/docs/upgrading.md +9 -0
  111. package/package.json +33 -1
  112. package/scripts/convex-smoke-env.mjs +33 -0
  113. package/scripts/smoke-packed-components.mjs +9 -2
  114. package/scripts/smoke-packed-effect.mjs +439 -0
  115. package/scripts/test-packed-effect.mjs +460 -0
  116. package/scripts/test-packed-ids.mjs +1 -0
@@ -0,0 +1,105 @@
1
+ import { ContractInput, ContractOutput, ContractSchema } from "./contract.mjs";
2
+ import { DecodedFailure, ErrorContract, ErrorDefinitions, UnknownFailure } from "./errors.mjs";
3
+ //#region src/modules/contracts/exposure.d.ts
4
+ declare const selectedTypes: unique symbol;
5
+ declare const executorTypes: unique symbol;
6
+ type Definition = {
7
+ input: ContractSchema;
8
+ result: ContractSchema;
9
+ wire?: {
10
+ schema: ContractSchema;
11
+ };
12
+ };
13
+ type OperationPublicResult<D extends Definition> = D extends {
14
+ wire: {
15
+ schema: infer Schema extends ContractSchema;
16
+ };
17
+ } ? ContractInput<Schema> : ContractOutput<D['result']>;
18
+ /** Only the selected input/public contracts are exposed, never handlers or other operations. */
19
+ type SelectedOperation<Owner extends symbol, Key extends string, Input extends ContractSchema, Public> = Readonly<{
20
+ owner: Owner;
21
+ key: Key;
22
+ kind: 'mutation' | 'query';
23
+ input: Input;
24
+ result: ContractSchema;
25
+ readonly [selectedTypes]: {
26
+ readonly input: ContractInput<Input>;
27
+ readonly public: Public;
28
+ };
29
+ }>;
30
+ type Selection = Readonly<{
31
+ owner: symbol;
32
+ key: string;
33
+ kind: 'mutation' | 'query';
34
+ input: ContractSchema;
35
+ result: ContractSchema;
36
+ readonly [selectedTypes]: {
37
+ readonly input: unknown;
38
+ readonly public: unknown;
39
+ };
40
+ }>;
41
+ type InputOf<S extends Selection> = S[typeof selectedTypes]['input'];
42
+ type PublicOf<S extends Selection> = S[typeof selectedTypes]['public'];
43
+ /** Registry integrators must check membership before selecting their own definition. */
44
+ declare function selectOperation<const Owner extends symbol, const Key extends string, const D extends Definition>(owner: Owner, kind: 'mutation' | 'query', key: Key, definition: D): SelectedOperation<Owner, Key, D['input'], OperationPublicResult<D>>;
45
+ type OperationExecutor<S extends Selection> = Readonly<{
46
+ owner: S['owner'];
47
+ key: S['key'];
48
+ readonly [executorTypes]: S;
49
+ }>;
50
+ /** The host captures authority in an already authorized native Promise call. */
51
+ declare function bindOperationExecutor<const S extends Selection>(selected: S, configuration: {
52
+ owner: NoInfer<S['owner']>;
53
+ key: NoInfer<S['key']>;
54
+ execute: (raw: NoInfer<InputOf<S>>) => Promise<NoInfer<PublicOf<S>>>;
55
+ }): OperationExecutor<S>;
56
+ declare const operationToolDialect: 'https://json-schema.org/draft/2020-12/schema';
57
+ type Json = null | boolean | number | string | readonly Json[] | {
58
+ readonly [key: string]: Json;
59
+ };
60
+ type OperationToolJsonSchema = Readonly<{
61
+ [keyword: string]: Json;
62
+ }>;
63
+ type OperationToolConverter<Input extends ContractSchema = ContractSchema> = Readonly<{
64
+ dialect: typeof operationToolDialect;
65
+ /** Represent raw transport input. Unsupported IDs/transforms must throw, never be approximated. */
66
+ convert: (input: Input) => OperationToolJsonSchema;
67
+ }>;
68
+ type OperationToolDefinition<S extends Selection = Selection, Errors extends ErrorDefinitions = ErrorDefinitions> = Readonly<{
69
+ operation: S;
70
+ executor: OperationExecutor<S>;
71
+ description: string;
72
+ converter: OperationToolConverter<S['input']>;
73
+ errors?: Pick<ErrorContract<Errors>, 'decode'>;
74
+ }>;
75
+ type ToolConstraint = Readonly<{
76
+ operation: Selection;
77
+ executor: OperationExecutor<Selection>;
78
+ description: string;
79
+ converter: {
80
+ dialect: typeof operationToolDialect;
81
+ convert: (input: never) => OperationToolJsonSchema;
82
+ };
83
+ errors?: Pick<ErrorContract<ErrorDefinitions>, 'decode'>;
84
+ }>;
85
+ type Checked<T extends ToolConstraint> = T & OperationToolDefinition<T['operation']>;
86
+ type FailureOf<T> = T extends {
87
+ errors: Pick<ErrorContract<infer E>, 'decode'>;
88
+ } ? DecodedFailure<E> : UnknownFailure;
89
+ type OperationToolOutcome<Public, Failure = UnknownFailure> = Readonly<{
90
+ _tag: 'Success';
91
+ value: Public;
92
+ }> | Failure;
93
+ type OperationTool<T extends ToolConstraint> = Readonly<{
94
+ name: string;
95
+ description: string;
96
+ args: OperationToolJsonSchema;
97
+ invoke: (raw: InputOf<T['operation']>) => Promise<OperationToolOutcome<PublicOf<T['operation']>, FailureOf<T>>>;
98
+ }>;
99
+ declare function createOperationTools<const T extends Readonly<Record<string, ToolConstraint>>>(definitions: T & { [K in keyof T]: Checked<T[K]>; }): Readonly<{ [K in keyof T]: OperationTool<T[K]>; }>;
100
+ declare function createOperationTools<const T extends readonly (ToolConstraint & {
101
+ name: string;
102
+ })[]>(definitions: T & { [K in keyof T]: Checked<T[K]>; }): Readonly<{ [D in T[number] as D['name']]: OperationTool<D>; }>;
103
+ //#endregion
104
+ export { OperationExecutor, OperationPublicResult, OperationTool, OperationToolConverter, OperationToolDefinition, OperationToolJsonSchema, OperationToolOutcome, SelectedOperation, bindOperationExecutor, createOperationTools, operationToolDialect, selectOperation };
105
+ //# sourceMappingURL=exposure.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{ConvexError as e}from"convex/values";const t=new WeakSet,n=new WeakMap;function r(e,n,r,i){if(typeof e!=`symbol`||!r||n!==`mutation`&&n!==`query`||!i?.input||!i.result)throw Error(`Invalid selected operation`);let a=Object.freeze({owner:e,key:r,kind:n,input:i.input,result:i.wire?.schema??i.result});return t.add(a),a}function i(e,r){if(!t.has(e)||r.owner!==e.owner||r.key!==e.key||typeof r.execute!=`function`)throw Error(`Executor does not own the selected operation`);let i=Object.freeze({owner:e.owner,key:e.key});return n.set(i,{selection:e,execute:r.execute}),i}const a=`https://json-schema.org/draft/2020-12/schema`;function o(r){let i=Array.isArray(r)?r.map(e=>[e.name,e]):Object.entries(r),a=Object.create(null);for(let[r,o]of i){if(!r||Object.hasOwn(a,r))throw Error(`Duplicate or empty operation tool name`);let i=o.executor&&n.get(o.executor);if(!t.has(o.operation)||!i||i.selection!==o.operation)throw Error(`Tool requires its selected operation executor`);if(!o.description||o.converter?.dialect!==`https://json-schema.org/draft/2020-12/schema`||typeof o.converter.convert!=`function`)throw Error(`Unsupported operation tool converter`);let s=p(o.converter.convert(o.operation.input)),c=o.errors;a[r]=Object.freeze({name:r,description:o.description,args:s,async invoke(t){try{return{_tag:`Success`,value:await i.execute(t)}}catch(t){try{if(t instanceof e&&c)return c.decode(t.data)}catch{}return{_tag:`UnknownFailure`,version:1}}}})}return Object.freeze(a)}const s=new Set([`properties`,`$defs`,`items`,`additionalProperties`,`anyOf`,`oneOf`,`allOf`,`not`,`required`,`enum`,`const`,`default`,`examples`]),c=new Set([`object`,`array`,`string`,`number`,`integer`,`boolean`,`null`]),l=new Set([`title`,`description`,`format`,`pattern`,`$ref`,`$id`,`x-convex-table`]),u=new Set([`minLength`,`maxLength`,`minItems`,`maxItems`,`minProperties`,`maxProperties`]),d=new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`,`multipleOf`]),f=new Set([...l,...u,...d,`type`,`uniqueItems`,`$schema`]);function p(e){let t=new Set;function n(e){if(e===null||typeof e==`string`||typeof e==`boolean`||typeof e==`number`&&Number.isFinite(e))return e;if(typeof e!=`object`||t.has(e))throw Error(`Converter schema must be JSON safe`);t.add(e);try{if(Array.isArray(e))return Object.freeze(e.map(n));if(!m(e))throw Error(`Converter schema must be a plain JSON object`);return Object.freeze(Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)])))}finally{t.delete(e)}}function r(e){if(typeof e!=`boolean`){if(!m(e))throw Error(`Unsupported JSON Schema shape`);for(let[t,n]of Object.entries(e)){if(!f.has(t)&&!s.has(t))throw Error(`Unsupported JSON Schema keyword`);if(l.has(t)&&typeof n!=`string`)throw Error(`Invalid JSON Schema text keyword`);if(u.has(t)&&(typeof n!=`number`||!Number.isInteger(n)||n<0))throw Error(`Invalid JSON Schema count keyword`);if(d.has(t)&&(typeof n!=`number`||!Number.isFinite(n)||t===`multipleOf`&&n<=0))throw Error(`Invalid JSON Schema number keyword`);if(t===`uniqueItems`&&typeof n!=`boolean`)throw Error(`Invalid JSON Schema boolean keyword`);if(t===`pattern`)try{new RegExp(n)}catch{throw Error(`Invalid JSON Schema pattern`)}if((t===`enum`||t===`examples`)&&!Array.isArray(n))throw Error(`Invalid JSON Schema array keyword`);if(t===`enum`&&Array.isArray(n)&&!n.length)throw Error(`Invalid JSON Schema enum`);if(t===`$schema`&&n!==`https://json-schema.org/draft/2020-12/schema`)throw Error(`Unsupported JSON Schema dialect`);if(t===`type`&&!(typeof n==`string`&&c.has(n))&&!(Array.isArray(n)&&n.length>0&&n.every(e=>typeof e==`string`&&c.has(e))))throw Error(`Unsupported JSON Schema type`);if(t===`properties`||t===`$defs`){if(!m(n))throw Error(`Unsupported JSON Schema properties`);Object.values(n).forEach(r)}else if(t===`items`||t===`not`||t===`additionalProperties`)r(n);else if(t===`anyOf`||t===`oneOf`||t===`allOf`){if(!Array.isArray(n)||!n.length)throw Error(`Unsupported JSON Schema alternatives`);n.forEach(r)}else if(t===`required`&&(!Array.isArray(n)||n.some(e=>typeof e!=`string`)||new Set(n).size!==n.length))throw Error(`Unsupported JSON Schema required fields`)}}}let i=n(e);if(!m(i)||i.type!==`object`)throw Error(`Operation tool arguments require an object JSON Schema`);return r(i),i}function m(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}export{i as bindOperationExecutor,o as createOperationTools,a as operationToolDialect,r as selectOperation};
2
+ //# sourceMappingURL=exposure.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exposure.mjs","names":[],"sources":["../../../src/modules/contracts/exposure.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-type-aliases, anti-slop/no-runtime-typeof, anti-slop/no-unsafe-dictionary-type -- Selected native transport boundaries validate opaque identities and converter JSON without decoding domain inputs. */\nimport { ConvexError } from 'convex/values'\nimport type { ContractInput, ContractOutput, ContractSchema } from './contract'\nimport type { DecodedFailure, ErrorContract, ErrorDefinitions, UnknownFailure } from './errors'\n\ndeclare const selectedTypes: unique symbol\ndeclare const executorTypes: unique symbol\n\ntype Definition = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\twire?: { schema: ContractSchema }\n}\nexport type OperationPublicResult<D extends Definition> = D extends {\n\twire: { schema: infer Schema extends ContractSchema }\n}\n\t? ContractInput<Schema>\n\t: ContractOutput<D['result']>\n\n/** Only the selected input/public contracts are exposed, never handlers or other operations. */\nexport type SelectedOperation<\n\tOwner extends symbol,\n\tKey extends string,\n\tInput extends ContractSchema,\n\tPublic,\n> = Readonly<{\n\towner: Owner\n\tkey: Key\n\tkind: 'mutation' | 'query'\n\tinput: Input\n\tresult: ContractSchema\n\treadonly [selectedTypes]: { readonly input: ContractInput<Input>; readonly public: Public }\n}>\ntype Selection = Readonly<{\n\towner: symbol\n\tkey: string\n\tkind: 'mutation' | 'query'\n\tinput: ContractSchema\n\tresult: ContractSchema\n\treadonly [selectedTypes]: { readonly input: unknown; readonly public: unknown }\n}>\ntype InputOf<S extends Selection> = S[typeof selectedTypes]['input']\ntype PublicOf<S extends Selection> = S[typeof selectedTypes]['public']\n\nconst selections = new WeakSet<object>()\nconst executors = new WeakMap<\n\tobject,\n\t{\n\t\tselection: Selection\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Private heterogeneous storage erases public result types; selected identity checks recover the exact raw/public pair at invocation.\n\t\texecute: (input: never) => Promise<unknown>\n\t}\n>()\n\n/** Registry integrators must check membership before selecting their own definition. */\nexport function selectOperation<\n\tconst Owner extends symbol,\n\tconst Key extends string,\n\tconst D extends Definition,\n>(\n\towner: Owner,\n\tkind: 'mutation' | 'query',\n\tkey: Key,\n\tdefinition: D,\n): SelectedOperation<Owner, Key, D['input'], OperationPublicResult<D>> {\n\tif (\n\t\ttypeof owner !== 'symbol' ||\n\t\t!key ||\n\t\t(kind !== 'mutation' && kind !== 'query') ||\n\t\t!definition?.input ||\n\t\t!definition.result\n\t) {\n\t\tthrow Error('Invalid selected operation')\n\t}\n\t// SAFETY: private identity records this exact paired schema; its type-only slots are never read at runtime.\n\tconst selected = Object.freeze({\n\t\towner,\n\t\tkey,\n\t\tkind,\n\t\tinput: definition.input,\n\t\tresult: definition.wire?.schema ?? definition.result,\n\t}) as SelectedOperation<Owner, Key, D['input'], OperationPublicResult<D>>\n\tselections.add(selected)\n\treturn selected\n}\n\nexport type OperationExecutor<S extends Selection> = Readonly<{\n\towner: S['owner']\n\tkey: S['key']\n\treadonly [executorTypes]: S\n}>\n\n/** The host captures authority in an already authorized native Promise call. */\nexport function bindOperationExecutor<const S extends Selection>(\n\tselected: S,\n\tconfiguration: {\n\t\towner: NoInfer<S['owner']>\n\t\tkey: NoInfer<S['key']>\n\t\texecute: (raw: NoInfer<InputOf<S>>) => Promise<NoInfer<PublicOf<S>>>\n\t},\n): OperationExecutor<S> {\n\tif (\n\t\t!selections.has(selected) ||\n\t\tconfiguration.owner !== selected.owner ||\n\t\tconfiguration.key !== selected.key ||\n\t\ttypeof configuration.execute !== 'function'\n\t) {\n\t\tthrow Error('Executor does not own the selected operation')\n\t}\n\t// SAFETY: the private map restores the concrete selected raw/public pair only after identity checks.\n\tconst executor = Object.freeze({\n\t\towner: selected.owner,\n\t\tkey: selected.key,\n\t}) as OperationExecutor<S>\n\texecutors.set(executor, {\n\t\tselection: selected,\n\t\texecute: configuration.execute,\n\t})\n\treturn executor\n}\n\nexport const operationToolDialect = 'https://json-schema.org/draft/2020-12/schema' as const\ntype Json = null | boolean | number | string | readonly Json[] | { readonly [key: string]: Json }\nexport type OperationToolJsonSchema = Readonly<{ [keyword: string]: Json }>\nexport type OperationToolConverter<Input extends ContractSchema = ContractSchema> = Readonly<{\n\tdialect: typeof operationToolDialect\n\t/** Represent raw transport input. Unsupported IDs/transforms must throw, never be approximated. */\n\tconvert: (input: Input) => OperationToolJsonSchema\n}>\nexport type OperationToolDefinition<\n\tS extends Selection = Selection,\n\tErrors extends ErrorDefinitions = ErrorDefinitions,\n> = Readonly<{\n\toperation: S\n\texecutor: OperationExecutor<S>\n\tdescription: string\n\tconverter: OperationToolConverter<S['input']>\n\terrors?: Pick<ErrorContract<Errors>, 'decode'>\n}>\ntype ToolConstraint = Readonly<{\n\toperation: Selection\n\texecutor: OperationExecutor<Selection>\n\tdescription: string\n\tconverter: {\n\t\tdialect: typeof operationToolDialect\n\t\tconvert: (input: never) => OperationToolJsonSchema\n\t}\n\terrors?: Pick<ErrorContract<ErrorDefinitions>, 'decode'>\n}>\ntype Checked<T extends ToolConstraint> = T & OperationToolDefinition<T['operation']>\ntype FailureOf<T> = T extends { errors: Pick<ErrorContract<infer E>, 'decode'> }\n\t? DecodedFailure<E>\n\t: UnknownFailure\nexport type OperationToolOutcome<Public, Failure = UnknownFailure> =\n\t| Readonly<{ _tag: 'Success'; value: Public }>\n\t| Failure\nexport type OperationTool<T extends ToolConstraint> = Readonly<{\n\tname: string\n\tdescription: string\n\targs: OperationToolJsonSchema\n\tinvoke: (\n\t\traw: InputOf<T['operation']>,\n\t) => Promise<OperationToolOutcome<PublicOf<T['operation']>, FailureOf<T>>>\n}>\n\nexport function createOperationTools<const T extends Readonly<Record<string, ToolConstraint>>>(\n\tdefinitions: T & { [K in keyof T]: Checked<T[K]> },\n): Readonly<{ [K in keyof T]: OperationTool<T[K]> }>\nexport function createOperationTools<\n\tconst T extends readonly (ToolConstraint & { name: string })[],\n>(\n\tdefinitions: T & { [K in keyof T]: Checked<T[K]> },\n): Readonly<{ [D in T[number] as D['name']]: OperationTool<D> }>\nexport function createOperationTools(\n\tdefinitions:\n\t\t| Readonly<Record<string, ToolConstraint>>\n\t\t| readonly (ToolConstraint & { name: string })[],\n): Readonly<Record<string, OperationTool<ToolConstraint>>> {\n\tconst entries = Array.isArray(definitions)\n\t\t? definitions.map((definition) => [definition.name, definition] as const)\n\t\t: Object.entries(definitions)\n\tconst tools: Record<string, OperationTool<ToolConstraint>> = Object.create(null)\n\tfor (const [name, definition] of entries) {\n\t\tif (!name || Object.hasOwn(tools, name)) throw Error('Duplicate or empty operation tool name')\n\t\tconst paired = definition.executor && executors.get(definition.executor)\n\t\tif (\n\t\t\t!selections.has(definition.operation) ||\n\t\t\t!paired ||\n\t\t\tpaired.selection !== definition.operation\n\t\t)\n\t\t\tthrow Error('Tool requires its selected operation executor')\n\t\tif (\n\t\t\t!definition.description ||\n\t\t\tdefinition.converter?.dialect !== operationToolDialect ||\n\t\t\ttypeof definition.converter.convert !== 'function'\n\t\t)\n\t\t\tthrow Error('Unsupported operation tool converter')\n\t\t// Conversion never executes the input decoder, and invocation never executes conversion.\n\t\t// SAFETY: the checked tool overload pairs the converter with this selected input schema; the never cast bridges heterogeneous iteration without changing the schema.\n\t\tconst args = schemaSnapshot(definition.converter.convert(definition.operation.input as never))\n\t\tconst errors = definition.errors\n\t\ttools[name] = Object.freeze({\n\t\t\tname,\n\t\t\tdescription: definition.description,\n\t\t\targs,\n\t\t\tasync invoke(raw: unknown) {\n\t\t\t\ttry {\n\t\t\t\t\t// SAFETY: binding owns this raw/public pair and its native boundary performs decoding/policy/projection.\n\t\t\t\t\treturn { _tag: 'Success' as const, value: await paired.execute(raw as never) }\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// This catch runs only after the native call rejects. Native mutations retain rollback semantics.\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (error instanceof ConvexError && errors) return errors.decode(error.data)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* Invalid host error decoders cannot publish diagnostics. */\n\t\t\t\t\t}\n\t\t\t\t\treturn { _tag: 'UnknownFailure' as const, version: 1 as const }\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\treturn Object.freeze(tools)\n}\n\nconst schemaKeywords = new Set([\n\t'properties',\n\t'$defs',\n\t'items',\n\t'additionalProperties',\n\t'anyOf',\n\t'oneOf',\n\t'allOf',\n\t'not',\n\t'required',\n\t'enum',\n\t'const',\n\t'default',\n\t'examples',\n])\nconst types = new Set(['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'])\nconst textKeywords = new Set([\n\t'title',\n\t'description',\n\t'format',\n\t'pattern',\n\t'$ref',\n\t'$id',\n\t'x-convex-table',\n])\nconst countKeywords = new Set([\n\t'minLength',\n\t'maxLength',\n\t'minItems',\n\t'maxItems',\n\t'minProperties',\n\t'maxProperties',\n])\nconst numberKeywords = new Set([\n\t'minimum',\n\t'maximum',\n\t'exclusiveMinimum',\n\t'exclusiveMaximum',\n\t'multipleOf',\n])\nconst scalarKeywords = new Set([\n\t...textKeywords,\n\t...countKeywords,\n\t...numberKeywords,\n\t'type',\n\t'uniqueItems',\n\t'$schema',\n])\n\nfunction schemaSnapshot(value: OperationToolJsonSchema): OperationToolJsonSchema {\n\tconst seen = new Set<object>()\n\tfunction copy(value: Json): Json {\n\t\tif (value === null || typeof value === 'string' || typeof value === 'boolean') return value\n\t\tif (typeof value === 'number' && Number.isFinite(value)) return value\n\t\tif (typeof value !== 'object' || seen.has(value))\n\t\t\tthrow Error('Converter schema must be JSON safe')\n\t\tseen.add(value)\n\t\ttry {\n\t\t\tif (Array.isArray(value)) return Object.freeze(value.map(copy))\n\t\t\tif (!isRecord(value)) throw Error('Converter schema must be a plain JSON object')\n\t\t\treturn Object.freeze(\n\t\t\t\tObject.fromEntries(Object.entries(value).map(([key, item]) => [key, copy(item)])),\n\t\t\t)\n\t\t} finally {\n\t\t\tseen.delete(value)\n\t\t}\n\t}\n\tfunction check(schema: Json): void {\n\t\tif (typeof schema === 'boolean') return\n\t\tif (!isRecord(schema)) throw Error('Unsupported JSON Schema shape')\n\t\tfor (const [key, child] of Object.entries(schema)) {\n\t\t\tif (!scalarKeywords.has(key) && !schemaKeywords.has(key))\n\t\t\t\tthrow Error('Unsupported JSON Schema keyword')\n\t\t\tif (textKeywords.has(key) && typeof child !== 'string')\n\t\t\t\tthrow Error('Invalid JSON Schema text keyword')\n\t\t\tif (\n\t\t\t\tcountKeywords.has(key) &&\n\t\t\t\t(typeof child !== 'number' || !Number.isInteger(child) || child < 0)\n\t\t\t)\n\t\t\t\tthrow Error('Invalid JSON Schema count keyword')\n\t\t\tif (\n\t\t\t\tnumberKeywords.has(key) &&\n\t\t\t\t(typeof child !== 'number' ||\n\t\t\t\t\t!Number.isFinite(child) ||\n\t\t\t\t\t(key === 'multipleOf' && child <= 0))\n\t\t\t)\n\t\t\t\tthrow Error('Invalid JSON Schema number keyword')\n\t\t\tif (key === 'uniqueItems' && typeof child !== 'boolean')\n\t\t\t\tthrow Error('Invalid JSON Schema boolean keyword')\n\t\t\tif (key === 'pattern') {\n\t\t\t\ttry {\n\t\t\t\t\t// SAFETY: pattern belongs to textKeywords and passed the string check above; this validates syntax without matching input.\n\t\t\t\t\tnew RegExp(child as string)\n\t\t\t\t} catch {\n\t\t\t\t\tthrow Error('Invalid JSON Schema pattern')\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ((key === 'enum' || key === 'examples') && !Array.isArray(child))\n\t\t\t\tthrow Error('Invalid JSON Schema array keyword')\n\t\t\tif (key === 'enum' && Array.isArray(child) && !child.length)\n\t\t\t\tthrow Error('Invalid JSON Schema enum')\n\t\t\tif (key === '$schema' && child !== operationToolDialect)\n\t\t\t\tthrow Error('Unsupported JSON Schema dialect')\n\t\t\tif (\n\t\t\t\tkey === 'type' &&\n\t\t\t\t!(typeof child === 'string' && types.has(child)) &&\n\t\t\t\t!(\n\t\t\t\t\tArray.isArray(child) &&\n\t\t\t\t\tchild.length > 0 &&\n\t\t\t\t\tchild.every((type) => typeof type === 'string' && types.has(type))\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tthrow Error('Unsupported JSON Schema type')\n\t\t\tif (key === 'properties' || key === '$defs') {\n\t\t\t\tif (!isRecord(child)) throw Error('Unsupported JSON Schema properties')\n\t\t\t\tObject.values(child).forEach(check)\n\t\t\t} else if (key === 'items' || key === 'not' || key === 'additionalProperties') check(child)\n\t\t\telse if (key === 'anyOf' || key === 'oneOf' || key === 'allOf') {\n\t\t\t\tif (!Array.isArray(child) || !child.length)\n\t\t\t\t\tthrow Error('Unsupported JSON Schema alternatives')\n\t\t\t\tchild.forEach(check)\n\t\t\t} else if (\n\t\t\t\tkey === 'required' &&\n\t\t\t\t(!Array.isArray(child) ||\n\t\t\t\t\tchild.some((field) => typeof field !== 'string') ||\n\t\t\t\t\tnew Set(child).size !== child.length)\n\t\t\t)\n\t\t\t\tthrow Error('Unsupported JSON Schema required fields')\n\t\t}\n\t}\n\tconst snapshot = copy(value)\n\tif (!isRecord(snapshot) || snapshot.type !== 'object')\n\t\tthrow Error('Operation tool arguments require an object JSON Schema')\n\tcheck(snapshot)\n\treturn snapshot\n}\nfunction isRecord(value: Json): value is { readonly [key: string]: Json } {\n\tif (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n\tconst prototype = Object.getPrototypeOf(value)\n\treturn prototype === Object.prototype || prototype === null\n}\n"],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { ContractInput, ContractOutput, NeutralSchema } from "./contract.mjs";
2
+ //#region src/modules/contracts/idempotency.d.ts
3
+ type IdempotencyErrorCode = 'unsupported-binding' | 'invalid-input' | 'corrupt' | 'ambiguous' | 'pending' | 'stale' | 'conflict';
4
+ declare class IdempotencyError extends Error {
5
+ readonly code: IdempotencyErrorCode;
6
+ readonly _tag = "IdempotencyError";
7
+ constructor(code: IdempotencyErrorCode, message: string);
8
+ }
9
+ interface IdempotencyIdentity {
10
+ readonly operation: string;
11
+ /** Stable trusted tenant/principal or delegated-capability scope, supplied by the host. */
12
+ readonly scope: string;
13
+ readonly key: string;
14
+ }
15
+ interface IdempotencyVersions {
16
+ readonly operation: string;
17
+ readonly contract: string;
18
+ readonly binding: string;
19
+ readonly fingerprintPolicy: string;
20
+ }
21
+ interface IdempotencyReceipt {
22
+ readonly versions: IdempotencyVersions;
23
+ readonly fingerprint: string;
24
+ readonly state: 'pending' | 'completed';
25
+ readonly result?: unknown;
26
+ }
27
+ interface CanonicalConvexBounds {
28
+ readonly maxDepth: number;
29
+ readonly maxNodes: number;
30
+ readonly maxBytes: number;
31
+ readonly maxArrayLength: number;
32
+ readonly maxObjectFields: number;
33
+ }
34
+ /** Bounded transport encoding, using the pinned Convex integer/binary/float representation. */
35
+ declare function canonicalConvexBytes(value: unknown, bounds: CanonicalConvexBounds): string;
36
+ declare const invocationBytes: unique symbol;
37
+ interface IdempotencyInvocation {
38
+ readonly identity: IdempotencyIdentity;
39
+ readonly versions: IdempotencyVersions;
40
+ readonly [invocationBytes]: string;
41
+ }
42
+ interface IdempotencyCapture {
43
+ readonly binding: {
44
+ readonly kind: 'mutation';
45
+ readonly atomicity: 'same-mutation';
46
+ };
47
+ readonly identity: IdempotencyIdentity;
48
+ readonly versions: IdempotencyVersions;
49
+ readonly rawInput: unknown;
50
+ readonly canonical: {
51
+ readonly bounds: CanonicalConvexBounds;
52
+ /** Explicit deterministic equivalence; the host versions this policy in fingerprintPolicy. */
53
+ readonly normalize?: (raw: unknown) => unknown;
54
+ };
55
+ }
56
+ /** Call at the trusted native handler before domain decoding, once per invocation (including nested calls). */
57
+ declare function captureIdempotencyInvocation(capture: IdempotencyCapture): IdempotencyInvocation;
58
+ /** Shared protocol checks have no Effect dependency and never decode final wire data. */
59
+ declare function retainedIdempotencyReceipt(rows: readonly unknown[], invocation: IdempotencyInvocation): IdempotencyReceipt | undefined;
60
+ declare function idempotencyCanonicalInput(invocation: IdempotencyInvocation): string;
61
+ declare function idempotencyFingerprint(value: string, receipt?: IdempotencyReceipt): string;
62
+ type IdempotencyPreparation<Result> = {
63
+ readonly kind: 'replay';
64
+ readonly result: unknown;
65
+ } | {
66
+ readonly kind: 'execute';
67
+ readonly complete: (result: Result) => Promise<void>;
68
+ };
69
+ type NeutralValue<A> = A | PromiseLike<A>;
70
+ /** Host callbacks close over the same secured mutation writer; native OCC/rollback remains host-owned. */
71
+ declare function transactionalIdempotency<const Replay extends NeutralSchema, Claim>(configuration: {
72
+ readonly final: {
73
+ readonly replayResult: Replay;
74
+ readonly encode: (result: ContractOutput<Replay>) => NeutralValue<ContractInput<Replay>>;
75
+ };
76
+ readonly authorize: (invocation: IdempotencyInvocation) => NeutralValue<void>;
77
+ readonly lookup: (identity: IdempotencyIdentity) => NeutralValue<readonly unknown[]>;
78
+ readonly fingerprint: (canonicalBytes: string) => NeutralValue<string>;
79
+ readonly claim: (identity: IdempotencyIdentity, receipt: IdempotencyReceipt) => NeutralValue<Claim>;
80
+ readonly complete: (claim: Claim, receipt: IdempotencyReceipt) => NeutralValue<void>;
81
+ }): {
82
+ replayResult: Replay;
83
+ prepare(invocation: IdempotencyInvocation): Promise<IdempotencyPreparation<ContractOutput<Replay>>>;
84
+ };
85
+ //#endregion
86
+ export { CanonicalConvexBounds, IdempotencyCapture, IdempotencyError, IdempotencyErrorCode, IdempotencyIdentity, IdempotencyInvocation, IdempotencyPreparation, IdempotencyReceipt, IdempotencyVersions, canonicalConvexBytes, captureIdempotencyInvocation, idempotencyCanonicalInput, idempotencyFingerprint, retainedIdempotencyReceipt, transactionalIdempotency };
87
+ //# sourceMappingURL=idempotency.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{convexToJson as e}from"convex/values";var t=class extends Error{code;_tag=`IdempotencyError`;constructor(e,t){super(t),this.code=e,this.name=`IdempotencyError`}};const n=new TextEncoder;function r(t,r){for(let e of[r.maxDepth,r.maxNodes,r.maxBytes,r.maxArrayLength,r.maxObjectFields])(!Number.isSafeInteger(e)||e<1)&&d(`Canonical bounds must be positive safe integers`);let i=new Set,a=0,o=0;function s(e){o+=e,o>r.maxBytes&&d(`Canonical input exceeds byte bound`)}function c(e){return e.length>r.maxBytes&&d(`Canonical input exceeds byte bound`),n.encode(e).length}function l(e,t){if((++a>r.maxNodes||t>r.maxDepth)&&d(`Canonical input exceeds traversal bound`),e===null||typeof e==`boolean`){s(1);return}if(typeof e==`number`){s(9);return}if(typeof e==`bigint`){(e<-(1n<<63n)||e>(1n<<63n)-1n)&&d(`Convex integer exceeds signed int64`),s(9);return}if(typeof e==`string`){s(2+c(e));return}if(e instanceof ArrayBuffer){s(2+e.byteLength);return}typeof e!=`object`&&d(`Unsupported canonical Convex value`),i.has(e)&&d(`Cyclic canonical input`),i.add(e);try{if(Array.isArray(e)){e.length>r.maxArrayLength&&d(`Canonical array exceeds length bound`),s(2);for(let n of e)l(n,t+1);return}let n=Object.getPrototypeOf(e);n!==Object.prototype&&n!==null&&d(`Canonical input requires plain objects`),Object.getOwnPropertySymbols(e).length&&d(`Unsupported canonical symbol keys`);let i=Object.keys(e);i.length>r.maxObjectFields&&d(`Canonical object exceeds field bound`),s(2);for(let n of i){(n.length>1024||n.startsWith(`$`)||/[^\x20-\x7e]/.test(n))&&d(`Invalid Convex object key`);let r=Object.getOwnPropertyDescriptor(e,n);`value`in r||d(`Canonical input cannot contain accessors`),r.value!==void 0&&(s(c(n)+1),l(r.value,t+1))}}finally{i.delete(e)}}l(t,0);function u(t){if(Array.isArray(t))return t.map(u);if(typeof t==`object`&&t&&!(t instanceof ArrayBuffer)){let e=Object.create(null);for(let n of Object.keys(t).sort()){let r=t[n];r!==void 0&&(e[n]=u(r))}return e}return e(t)}let f=JSON.stringify(u(t));return n.encode(f).length>r.maxBytes&&d(`Canonical encoding exceeds byte bound`),f}const i=[`operation`,`contract`,`binding`,`fingerprintPolicy`],a=Symbol(`idempotency invocation bytes`);function o(e){if(e.binding.kind!==`mutation`||e.binding.atomicity!==`same-mutation`)throw new t(`unsupported-binding`,`Idempotency requires the current native mutation transaction`);let n=Object.freeze({operation:e.identity.operation,scope:e.identity.scope,key:e.identity.key}),i=Object.freeze({operation:e.versions.operation,contract:e.versions.contract,binding:e.versions.binding,fingerprintPolicy:e.versions.fingerprintPolicy});(!f(n)||!p(i))&&d(`Invalid trusted idempotency metadata`);let o=r(e.canonical.normalize?e.canonical.normalize(e.rawInput):e.rawInput,e.canonical.bounds);return Object.freeze({identity:n,versions:i,[a]:o})}function s(e,n){if(!Array.isArray(e))throw new t(`corrupt`,`Receipt lookup must return rows`);if(e.length>1)throw new t(`ambiguous`,`Multiple receipts match the stable identity`);if(e.length===0)return;let r=e[0];if(typeof r!=`object`||!r||!Object.hasOwn(r,`versions`)||!Object.hasOwn(r,`fingerprint`)||!Object.hasOwn(r,`state`))throw new t(`corrupt`,`Malformed retained receipt`);let a=r;if(!p(a.versions)||typeof a.fingerprint!=`string`||![`pending`,`completed`].includes(a.state)||a.state===`completed`&&!Object.hasOwn(a,`result`))throw new t(`corrupt`,`Malformed retained receipt`);if(i.some(e=>a.versions[e]!==n.versions[e]))throw new t(`stale`,`Retained receipt version differs from the current operation`);if(a.state===`pending`)throw new t(`pending`,`Retained receipt is incomplete`);return a}function c(e){if(!Object.hasOwn(e,a))throw new t(`unsupported-binding`,`Missing trusted invocation capture`);return e[a]}function l(e,n){if(typeof e!=`string`||e.length===0)throw new t(`invalid-input`,`Fingerprint policy must return a nonempty string`);if(n&&n.fingerprint!==e)throw new t(`conflict`,`Caller key was already used with different input`);return e}function u(e){return{replayResult:e.final.replayResult,async prepare(t){let n=c(t);await e.authorize(t);let r=s(await e.lookup(t.identity),t),i=l(await e.fingerprint(n),r);if(r)return{kind:`replay`,result:r.result};let a=await e.claim(t.identity,{state:`pending`,versions:t.versions,fingerprint:i});return{kind:`execute`,complete:async n=>{let r=await e.final.encode(n);await e.complete(a,{state:`completed`,versions:t.versions,fingerprint:i,result:r})}}}}}function d(e){throw new t(`invalid-input`,e)}function f(e){return[e.operation,e.scope,e.key].every(e=>typeof e==`string`&&e.length>0)}function p(e){if(typeof e!=`object`||!e)return!1;let t=e;return i.every(e=>{let n=t[e];return Object.hasOwn(t,e)&&typeof n==`string`&&n.length>0})}export{t as IdempotencyError,r as canonicalConvexBytes,o as captureIdempotencyInvocation,c as idempotencyCanonicalInput,l as idempotencyFingerprint,s as retainedIdempotencyReceipt,u as transactionalIdempotency};
2
+ //# sourceMappingURL=idempotency.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.mjs","names":[],"sources":["../../../src/modules/contracts/idempotency.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-runtime-typeof -- Canonical transport and retained receipts are explicit untrusted value boundaries. */\nimport { convexToJson, type Value, type JSONValue } from 'convex/values'\nimport type { ContractInput, ContractOutput, NeutralSchema } from './contract'\n\nexport type IdempotencyErrorCode =\n\t| 'unsupported-binding'\n\t| 'invalid-input'\n\t| 'corrupt'\n\t| 'ambiguous'\n\t| 'pending'\n\t| 'stale'\n\t| 'conflict'\nexport class IdempotencyError extends Error {\n\treadonly _tag = 'IdempotencyError'\n\tconstructor(\n\t\treadonly code: IdempotencyErrorCode,\n\t\tmessage: string,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'IdempotencyError'\n\t}\n}\nexport interface IdempotencyIdentity {\n\treadonly operation: string\n\t/** Stable trusted tenant/principal or delegated-capability scope, supplied by the host. */\n\treadonly scope: string\n\treadonly key: string\n}\nexport interface IdempotencyVersions {\n\treadonly operation: string\n\treadonly contract: string\n\treadonly binding: string\n\treadonly fingerprintPolicy: string\n}\nexport interface IdempotencyReceipt {\n\treadonly versions: IdempotencyVersions\n\treadonly fingerprint: string\n\treadonly state: 'pending' | 'completed'\n\treadonly result?: unknown\n}\nexport interface CanonicalConvexBounds {\n\treadonly maxDepth: number\n\treadonly maxNodes: number\n\treadonly maxBytes: number\n\treadonly maxArrayLength: number\n\treadonly maxObjectFields: number\n}\n\nconst encoder = new TextEncoder()\n/** Bounded transport encoding, using the pinned Convex integer/binary/float representation. */\nexport function canonicalConvexBytes(value: unknown, bounds: CanonicalConvexBounds): string {\n\tfor (const bound of [\n\t\tbounds.maxDepth,\n\t\tbounds.maxNodes,\n\t\tbounds.maxBytes,\n\t\tbounds.maxArrayLength,\n\t\tbounds.maxObjectFields,\n\t])\n\t\tif (!Number.isSafeInteger(bound) || bound < 1)\n\t\t\tinvalid('Canonical bounds must be positive safe integers')\n\tconst ancestors = new Set<object>()\n\tlet nodes = 0\n\tlet bytes = 0\n\tfunction spend(amount: number) {\n\t\tbytes += amount\n\t\tif (bytes > bounds.maxBytes) invalid('Canonical input exceeds byte bound')\n\t}\n\tfunction textBytes(text: string) {\n\t\tif (text.length > bounds.maxBytes) invalid('Canonical input exceeds byte bound')\n\t\treturn encoder.encode(text).length\n\t}\n\tfunction visit(current: unknown, depth: number): void {\n\t\tif (++nodes > bounds.maxNodes || depth > bounds.maxDepth)\n\t\t\tinvalid('Canonical input exceeds traversal bound')\n\t\tif (current === null || typeof current === 'boolean') {\n\t\t\tspend(1)\n\t\t\treturn\n\t\t}\n\t\tif (typeof current === 'number') {\n\t\t\tspend(9)\n\t\t\treturn\n\t\t}\n\t\tif (typeof current === 'bigint') {\n\t\t\tif (current < -(1n << 63n) || current > (1n << 63n) - 1n)\n\t\t\t\tinvalid('Convex integer exceeds signed int64')\n\t\t\tspend(9)\n\t\t\treturn\n\t\t}\n\t\tif (typeof current === 'string') {\n\t\t\tspend(2 + textBytes(current))\n\t\t\treturn\n\t\t}\n\t\tif (current instanceof ArrayBuffer) {\n\t\t\tspend(2 + current.byteLength)\n\t\t\treturn\n\t\t}\n\t\tif (typeof current !== 'object') invalid('Unsupported canonical Convex value')\n\t\tif (ancestors.has(current)) invalid('Cyclic canonical input')\n\t\tancestors.add(current)\n\t\ttry {\n\t\t\tif (Array.isArray(current)) {\n\t\t\t\tif (current.length > bounds.maxArrayLength) invalid('Canonical array exceeds length bound')\n\t\t\t\tspend(2)\n\t\t\t\tfor (const item of current) visit(item, depth + 1)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst prototype = Object.getPrototypeOf(current)\n\t\t\tif (prototype !== Object.prototype && prototype !== null)\n\t\t\t\tinvalid('Canonical input requires plain objects')\n\t\t\tif (Object.getOwnPropertySymbols(current).length) invalid('Unsupported canonical symbol keys')\n\t\t\tconst keys = Object.keys(current)\n\t\t\tif (keys.length > bounds.maxObjectFields) invalid('Canonical object exceeds field bound')\n\t\t\tspend(2)\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (key.length > 1024 || key.startsWith('$') || /[^\\x20-\\x7e]/.test(key))\n\t\t\t\t\tinvalid('Invalid Convex object key')\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(current, key)!\n\t\t\t\tif (!('value' in descriptor)) invalid('Canonical input cannot contain accessors')\n\t\t\t\tif (descriptor.value === undefined) continue\n\t\t\t\tspend(textBytes(key) + 1)\n\t\t\t\tvisit(descriptor.value, depth + 1)\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(current)\n\t\t}\n\t}\n\tvisit(value, 0)\n\t// Object projection retains own __proto__ keys which the SDK's assignment-based object converter drops.\n\t// Scalars still use the pinned SDK's exact integer/binary/float representation.\n\tfunction project(current: Value): JSONValue {\n\t\tif (Array.isArray(current)) return current.map(project)\n\t\tif (current !== null && typeof current === 'object' && !(current instanceof ArrayBuffer)) {\n\t\t\tconst output: Record<string, JSONValue> = Object.create(null)\n\t\t\tfor (const key of Object.keys(current).sort()) {\n\t\t\t\t// SAFETY: prior bounded traversal excluded every object type except plain Convex dictionaries.\n\t\t\t\tconst item = (current as Record<string, Value | undefined>)[key]\n\t\t\t\tif (item !== undefined) output[key] = project(item)\n\t\t\t}\n\t\t\treturn output\n\t\t}\n\t\treturn convexToJson(current)\n\t}\n\t// SAFETY: the traversal validates the bounded supported Convex value subset before SDK conversion.\n\tconst encoded = JSON.stringify(project(value as Value))\n\tif (encoder.encode(encoded).length > bounds.maxBytes)\n\t\tinvalid('Canonical encoding exceeds byte bound')\n\treturn encoded\n}\n\nconst versionFields = ['operation', 'contract', 'binding', 'fingerprintPolicy'] as const\nconst invocationBytes: unique symbol = Symbol('idempotency invocation bytes')\nexport interface IdempotencyInvocation {\n\treadonly identity: IdempotencyIdentity\n\treadonly versions: IdempotencyVersions\n\treadonly [invocationBytes]: string\n}\nexport interface IdempotencyCapture {\n\treadonly binding: { readonly kind: 'mutation'; readonly atomicity: 'same-mutation' }\n\treadonly identity: IdempotencyIdentity\n\treadonly versions: IdempotencyVersions\n\treadonly rawInput: unknown\n\treadonly canonical: {\n\t\treadonly bounds: CanonicalConvexBounds\n\t\t/** Explicit deterministic equivalence; the host versions this policy in fingerprintPolicy. */\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- The explicit normalized transport policy is validated by canonicalConvexBytes before capture.\n\t\treadonly normalize?: (raw: unknown) => unknown\n\t}\n}\n/** Call at the trusted native handler before domain decoding, once per invocation (including nested calls). */\nexport function captureIdempotencyInvocation(capture: IdempotencyCapture): IdempotencyInvocation {\n\tif (capture.binding.kind !== 'mutation' || capture.binding.atomicity !== 'same-mutation')\n\t\tthrow new IdempotencyError(\n\t\t\t'unsupported-binding',\n\t\t\t'Idempotency requires the current native mutation transaction',\n\t\t)\n\tconst identity = Object.freeze({\n\t\toperation: capture.identity.operation,\n\t\tscope: capture.identity.scope,\n\t\tkey: capture.identity.key,\n\t})\n\tconst versions = Object.freeze({\n\t\toperation: capture.versions.operation,\n\t\tcontract: capture.versions.contract,\n\t\tbinding: capture.versions.binding,\n\t\tfingerprintPolicy: capture.versions.fingerprintPolicy,\n\t})\n\tif (!validIdentity(identity) || !validVersions(versions))\n\t\tinvalid('Invalid trusted idempotency metadata')\n\tconst bytes = canonicalConvexBytes(\n\t\tcapture.canonical.normalize ? capture.canonical.normalize(capture.rawInput) : capture.rawInput,\n\t\tcapture.canonical.bounds,\n\t)\n\treturn Object.freeze({ identity, versions, [invocationBytes]: bytes })\n}\n/** Shared protocol checks have no Effect dependency and never decode final wire data. */\nexport function retainedIdempotencyReceipt(\n\trows: readonly unknown[],\n\tinvocation: IdempotencyInvocation,\n): IdempotencyReceipt | undefined {\n\tif (!Array.isArray(rows)) throw new IdempotencyError('corrupt', 'Receipt lookup must return rows')\n\tif (rows.length > 1)\n\t\tthrow new IdempotencyError('ambiguous', 'Multiple receipts match the stable identity')\n\tif (rows.length === 0) return undefined\n\tconst receipt = rows[0]\n\tif (\n\t\ttypeof receipt !== 'object' ||\n\t\treceipt === null ||\n\t\t!Object.hasOwn(receipt, 'versions') ||\n\t\t!Object.hasOwn(receipt, 'fingerprint') ||\n\t\t!Object.hasOwn(receipt, 'state')\n\t)\n\t\tthrow new IdempotencyError('corrupt', 'Malformed retained receipt')\n\t// SAFETY: this temporary retained-row view is fully checked below before returning or using metadata.\n\tconst candidate = receipt as IdempotencyReceipt\n\tif (\n\t\t!validVersions(candidate.versions) ||\n\t\ttypeof candidate.fingerprint !== 'string' ||\n\t\t!['pending', 'completed'].includes(candidate.state) ||\n\t\t(candidate.state === 'completed' && !Object.hasOwn(candidate, 'result'))\n\t)\n\t\tthrow new IdempotencyError('corrupt', 'Malformed retained receipt')\n\tif (versionFields.some((key) => candidate.versions[key] !== invocation.versions[key]))\n\t\tthrow new IdempotencyError(\n\t\t\t'stale',\n\t\t\t'Retained receipt version differs from the current operation',\n\t\t)\n\tif (candidate.state === 'pending')\n\t\tthrow new IdempotencyError('pending', 'Retained receipt is incomplete')\n\treturn candidate\n}\nexport function idempotencyCanonicalInput(invocation: IdempotencyInvocation): string {\n\tif (!Object.hasOwn(invocation, invocationBytes))\n\t\tthrow new IdempotencyError('unsupported-binding', 'Missing trusted invocation capture')\n\treturn invocation[invocationBytes]\n}\nexport function idempotencyFingerprint(value: string, receipt?: IdempotencyReceipt): string {\n\tif (typeof value !== 'string' || value.length === 0)\n\t\tthrow new IdempotencyError('invalid-input', 'Fingerprint policy must return a nonempty string')\n\tif (receipt && receipt.fingerprint !== value)\n\t\tthrow new IdempotencyError('conflict', 'Caller key was already used with different input')\n\treturn value\n}\nexport type IdempotencyPreparation<Result> =\n\t| { readonly kind: 'replay'; readonly result: unknown }\n\t| { readonly kind: 'execute'; readonly complete: (result: Result) => Promise<void> }\ntype NeutralValue<A> = A | PromiseLike<A>\n/** Host callbacks close over the same secured mutation writer; native OCC/rollback remains host-owned. */\nexport function transactionalIdempotency<const Replay extends NeutralSchema, Claim>(configuration: {\n\treadonly final: {\n\t\treadonly replayResult: Replay\n\t\treadonly encode: (result: ContractOutput<Replay>) => NeutralValue<ContractInput<Replay>>\n\t}\n\treadonly authorize: (invocation: IdempotencyInvocation) => NeutralValue<void>\n\treadonly lookup: (identity: IdempotencyIdentity) => NeutralValue<readonly unknown[]>\n\treadonly fingerprint: (canonicalBytes: string) => NeutralValue<string>\n\treadonly claim: (\n\t\tidentity: IdempotencyIdentity,\n\t\treceipt: IdempotencyReceipt,\n\t) => NeutralValue<Claim>\n\treadonly complete: (claim: Claim, receipt: IdempotencyReceipt) => NeutralValue<void>\n}) {\n\treturn {\n\t\treplayResult: configuration.final.replayResult,\n\t\tasync prepare(\n\t\t\tinvocation: IdempotencyInvocation,\n\t\t): Promise<IdempotencyPreparation<ContractOutput<Replay>>> {\n\t\t\tconst canonical = idempotencyCanonicalInput(invocation)\n\t\t\tawait configuration.authorize(invocation)\n\t\t\tconst retained = retainedIdempotencyReceipt(\n\t\t\t\tawait configuration.lookup(invocation.identity),\n\t\t\t\tinvocation,\n\t\t\t)\n\t\t\tconst fingerprint = idempotencyFingerprint(\n\t\t\t\tawait configuration.fingerprint(canonical),\n\t\t\t\tretained,\n\t\t\t)\n\t\t\tif (retained) return { kind: 'replay', result: retained.result }\n\t\t\tconst claim = await configuration.claim(invocation.identity, {\n\t\t\t\tstate: 'pending',\n\t\t\t\tversions: invocation.versions,\n\t\t\t\tfingerprint,\n\t\t\t})\n\t\t\treturn {\n\t\t\t\tkind: 'execute',\n\t\t\t\tcomplete: async (result) => {\n\t\t\t\t\tconst wire = await configuration.final.encode(result)\n\t\t\t\t\tawait configuration.complete(claim, {\n\t\t\t\t\t\tstate: 'completed',\n\t\t\t\t\t\tversions: invocation.versions,\n\t\t\t\t\t\tfingerprint,\n\t\t\t\t\t\tresult: wire,\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunction invalid(message: string): never {\n\tthrow new IdempotencyError('invalid-input', message)\n}\nfunction validIdentity(value: IdempotencyIdentity): boolean {\n\treturn [value.operation, value.scope, value.key].every(\n\t\t(field) => typeof field === 'string' && field.length > 0,\n\t)\n}\nfunction validVersions(value: unknown): value is IdempotencyVersions {\n\tif (typeof value !== 'object' || value === null) return false\n\t// SAFETY: this temporary metadata view is checked field by field before the predicate certifies it.\n\tconst candidate = value as Partial<IdempotencyVersions>\n\treturn versionFields.every((field) => {\n\t\tconst item = candidate[field]\n\t\treturn Object.hasOwn(candidate, field) && typeof item === 'string' && item.length > 0\n\t})\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { ContractInput, ContractOutput, Decoder, StandardSchema, ValidationResult } from "./contract.mjs";
2
+ import { z } from "zod";
3
+ //#region src/modules/contracts/standard.d.ts
4
+ /** Standard Schema validation executes exactly the validator supplied by its author. */
5
+ declare function standardContract<const S extends StandardSchema<unknown, unknown>>(schema: S): Decoder<ContractInput<S>, ContractOutput<S>, ValidationResult<ContractOutput<S>> | Promise<ValidationResult<ContractOutput<S>>>> & {
6
+ readonly kind: 'contract';
7
+ readonly schema: S;
8
+ };
9
+ /** Zod's Standard bridge probes sync first; safeParseAsync executes transforms once. */
10
+ declare function zodContract<const S extends z.ZodType>(schema: S): Decoder<z.input<S>, z.output<S>, Promise<ValidationResult<z.output<S>>>> & {
11
+ readonly kind: 'contract';
12
+ readonly schema: S;
13
+ };
14
+ //#endregion
15
+ export { standardContract, zodContract };
16
+ //# sourceMappingURL=standard.d.mts.map
@@ -0,0 +1,2 @@
1
+ function e(e){return{kind:`contract`,schema:e,decode:t=>e[`~standard`].validate(t)}}function t(e){return{kind:`contract`,schema:e,decode:async t=>{let n=await e.safeParseAsync(t);return n.success?{value:n.data}:{issues:n.error.issues}}}}export{e as standardContract,t as zodContract};
2
+ //# sourceMappingURL=standard.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard.mjs","names":[],"sources":["../../../src/modules/contracts/standard.ts"],"sourcesContent":["import type {\n\tContractInput,\n\tContractOutput,\n\tDecoder,\n\tStandardSchema,\n\tValidationResult,\n} from './contract'\nimport type { z } from 'zod'\n\n/** Standard Schema validation executes exactly the validator supplied by its author. */\nexport function standardContract<const S extends StandardSchema<unknown, unknown>>(\n\tschema: S,\n): Decoder<\n\tContractInput<S>,\n\tContractOutput<S>,\n\tValidationResult<ContractOutput<S>> | Promise<ValidationResult<ContractOutput<S>>>\n> & { readonly kind: 'contract'; readonly schema: S } {\n\treturn {\n\t\tkind: 'contract',\n\t\tschema,\n\t\t// SAFETY: structural Standard Schema inference associates validate's output with S.\n\t\tdecode: (value) =>\n\t\t\tschema['~standard'].validate(value) as\n\t\t\t\t| ValidationResult<ContractOutput<S>>\n\t\t\t\t| Promise<ValidationResult<ContractOutput<S>>>,\n\t}\n}\n\n/** Zod's Standard bridge probes sync first; safeParseAsync executes transforms once. */\nexport function zodContract<const S extends z.ZodType>(\n\tschema: S,\n): Decoder<z.input<S>, z.output<S>, Promise<ValidationResult<z.output<S>>>> & {\n\treadonly kind: 'contract'\n\treadonly schema: S\n} {\n\treturn {\n\t\tkind: 'contract',\n\t\tschema,\n\t\tdecode: async (value) => {\n\t\t\tconst result = await schema.safeParseAsync(value)\n\t\t\treturn result.success ? { value: result.data } : { issues: result.error.issues }\n\t\t},\n\t}\n}\n"],"mappings":"AAUA,SAAgB,EACf,EAKqD,CACrD,MAAO,CACN,KAAM,WACN,SAEA,OAAS,GACR,EAAO,YAAY,CAAC,SAAS,CAAK,CAGpC,CACD,CAGA,SAAgB,EACf,EAIC,CACD,MAAO,CACN,KAAM,WACN,SACA,OAAQ,KAAO,IAAU,CACxB,IAAM,EAAS,MAAM,EAAO,eAAe,CAAK,EAChD,OAAO,EAAO,QAAU,CAAE,MAAO,EAAO,IAAK,EAAI,CAAE,OAAQ,EAAO,MAAM,MAAO,CAChF,CACD,CACD"}
@@ -0,0 +1,167 @@
1
+ import { ContractInput, ContractOutput, NeutralSchema } from "./contract.mjs";
2
+ import { CanonicalConvexBounds, IdempotencyInvocation, IdempotencyPreparation } from "./idempotency.mjs";
3
+ import { FunctionReference, FunctionType, FunctionVisibility } from "convex/server";
4
+ import { WorkflowCtx } from "@convex-dev/workflow";
5
+ //#region src/modules/contracts/workflow.d.ts
6
+ declare class WorkflowBindingError extends Error {
7
+ readonly _tag = "WorkflowBindingError";
8
+ constructor(message: string);
9
+ }
10
+ interface WorkflowExecution<Args = unknown> {
11
+ readonly version: 1;
12
+ readonly operation: string;
13
+ readonly operationVersion: string;
14
+ readonly contractVersion: string;
15
+ readonly bindingVersion: string;
16
+ /** Host-issued business-run identity. Recovery preserves it. */
17
+ readonly run: string;
18
+ /** Opaque host capability; never caller-supplied principal or tenant authority. */
19
+ readonly capability: string;
20
+ /** Logical occurrence, distinct for each repeated loop step. */
21
+ readonly occurrence: string;
22
+ readonly args: Args;
23
+ }
24
+ type WorkflowStepArguments<Args> = {
25
+ execution: WorkflowExecution<Args>;
26
+ };
27
+ /** Strict plain, versioned transport. Validity does not confer authority; the host resolves capability anew. */
28
+ declare function workflowExecution<Args>(value: WorkflowExecution<Args>): WorkflowExecution<Args>;
29
+ declare function workflowExecution(value: unknown): WorkflowExecution;
30
+ interface WorkflowBinding<Kind extends FunctionType, Args extends NeutralSchema, Result extends NeutralSchema> {
31
+ readonly kind: Kind;
32
+ readonly operation: string;
33
+ readonly operationVersion: string;
34
+ readonly contractVersion: string;
35
+ readonly bindingVersion: string;
36
+ readonly args: Args;
37
+ readonly result: Result;
38
+ readonly reference: FunctionReference<NoInfer<Kind>, FunctionVisibility, WorkflowStepArguments<NoInfer<ContractInput<Args>>>, NoInfer<ContractInput<Result>>>;
39
+ /** Host explicitly lists deployed descriptor versions whose semantics remain compatible. */
40
+ readonly compatibleVersions?: readonly {
41
+ operationVersion: string;
42
+ contractVersion: string;
43
+ bindingVersion: string;
44
+ }[];
45
+ }
46
+ /** Both phantom reference args and results must match the explicit wire contracts. */
47
+ declare function workflowBinding<Kind extends FunctionType, const Args extends NeutralSchema, const Result extends NeutralSchema>(binding: WorkflowBinding<Kind, Args, Result>): WorkflowBinding<Kind, Args, Result>;
48
+ type WorkflowStepOptions = {
49
+ name?: string;
50
+ retry?: NonNullable<Parameters<WorkflowCtx['withOptions']>[0]['retry']>;
51
+ } & ({
52
+ inline?: false;
53
+ runAt?: number;
54
+ runAfter?: number;
55
+ } | {
56
+ inline: true;
57
+ runAt?: never;
58
+ runAfter?: never;
59
+ });
60
+ /** A structural seam allows invocation-scoped native WorkflowCtx without creating another durability runtime. */
61
+ interface WorkflowStepRunner {
62
+ runQuery?: (reference: FunctionReference<'query', FunctionVisibility>, args: WorkflowStepArguments<unknown>, options?: WorkflowStepOptions) => Promise<unknown>;
63
+ runMutation?: (reference: FunctionReference<'mutation', FunctionVisibility>, args: WorkflowStepArguments<unknown>, options?: WorkflowStepOptions) => Promise<unknown>;
64
+ runAction?: (reference: FunctionReference<'action', FunctionVisibility>, args: WorkflowStepArguments<unknown>, options?: WorkflowStepOptions) => Promise<unknown>;
65
+ }
66
+ declare function runWorkflowStep<Kind extends FunctionType, Args extends NeutralSchema, Result extends NeutralSchema>(step: WorkflowCtx | WorkflowStepRunner, binding: WorkflowBinding<Kind, Args, Result>, input: WorkflowExecution<ContractInput<Args>>, options?: WorkflowStepOptions): Promise<ContractInput<Result>>;
67
+ declare function workflowDecode<S extends NeutralSchema>(schema: S, value: unknown): Promise<ContractOutput<S>>;
68
+ type Ordinary<A> = A | PromiseLike<A>;
69
+ /** This helper belongs inside a registered native function, never in the replaying workflow handler. */
70
+ declare function workflowAttempt<Args, Authority, Result>(configuration: {
71
+ authorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>;
72
+ execute: (execution: WorkflowExecution<Args>, authority: Authority) => Ordinary<Result>;
73
+ }): (input: WorkflowExecution<Args>) => Promise<Result>;
74
+ type WorkflowOutcome<Result = unknown, Failure = unknown> = {
75
+ readonly version: 1;
76
+ readonly kind: 'succeeded';
77
+ readonly value: Result;
78
+ } | {
79
+ readonly version: 1;
80
+ readonly kind: 'failed';
81
+ readonly error: Failure;
82
+ };
83
+ declare const protectedMutation: unique symbol;
84
+ interface ReceiptProtectedWorkflowMutation<Args, Result> {
85
+ readonly [protectedMutation]: {
86
+ args: Args;
87
+ result: Result;
88
+ };
89
+ readonly handler: (execution: WorkflowExecution<Args>) => Promise<Result>;
90
+ }
91
+ interface WorkflowReceiptAdapter<S extends NeutralSchema> {
92
+ readonly replayResult: S;
93
+ readonly prepare: (invocation: IdempotencyInvocation) => Promise<IdempotencyPreparation<ContractOutput<S>>>;
94
+ }
95
+ /** Host registers this handler as the inner native mutation. All callbacks share its transaction. */
96
+ declare function receiptWorkflowMutation<Args, Authority, const Replay extends NeutralSchema>(configuration: {
97
+ authorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>;
98
+ receipt: (authority: Authority) => WorkflowReceiptAdapter<Replay>;
99
+ invocation: (execution: WorkflowExecution<Args>, authority: Authority) => IdempotencyInvocation;
100
+ execute: (execution: WorkflowExecution<Args>, authority: Authority) => Ordinary<ContractOutput<Replay>>;
101
+ }): ReceiptProtectedWorkflowMutation<Args, ContractOutput<Replay>>;
102
+ declare function workflowReceiptInvocation(execution: WorkflowExecution, options: {
103
+ scope: string;
104
+ fingerprintPolicy: string;
105
+ bounds: CanonicalConvexBounds;
106
+ }): IdempotencyInvocation;
107
+ type TerminalMode<Args> = {
108
+ kind: 'mutation';
109
+ /** Assertion supplied only after host native rollback/journaling acceptance. */ atomicJournalProof: 'host-verified';
110
+ } | {
111
+ kind: 'action';
112
+ protectedMutation: ReceiptProtectedWorkflowMutation<Args, unknown>;
113
+ };
114
+ /** The native inner mutation rejection must cross its transaction boundary before terminal mapping. */
115
+ declare function terminalWorkflowAttempt<Args, Authority, const Result extends NeutralSchema, const Failure extends NeutralSchema>(configuration: TerminalMode<Args> & {
116
+ authorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>;
117
+ invokeMutation: (execution: WorkflowExecution<Args>, authority: Authority) => Promise<ContractInput<Result>>;
118
+ terminal: (error: unknown) => Ordinary<ContractInput<Failure> | undefined>;
119
+ result: Result;
120
+ failure: Failure;
121
+ }): (input: WorkflowExecution<Args>) => Promise<WorkflowOutcome<ContractInput<Result>, ContractOutput<Failure>>>;
122
+ type WorkflowNativeStatus = 'running' | 'succeeded' | 'failed' | 'canceled';
123
+ interface WorkflowHostState<Result = unknown, Failure = unknown> {
124
+ readonly generation: number;
125
+ readonly status: WorkflowNativeStatus;
126
+ readonly nativeStatus: WorkflowNativeStatus;
127
+ readonly outcome?: WorkflowOutcome<Result, Failure>;
128
+ }
129
+ interface WorkflowHostUpdate<Result = unknown, Failure = unknown> {
130
+ readonly generation: number;
131
+ readonly nativeStatus: WorkflowNativeStatus;
132
+ readonly outcome?: WorkflowOutcome<Result, Failure>;
133
+ }
134
+ type WorkflowTransition<Result = unknown, Failure = unknown> = {
135
+ readonly kind: 'applied' | 'ignored';
136
+ readonly state: WorkflowHostState<Result, Failure>;
137
+ };
138
+ /** Call within a host transaction or compare-and-set. A late operation failure refines host success; cancellation and terminal native status stay fenced. */
139
+ declare function workflowTransition<Result, Failure>(current: WorkflowHostState<Result, Failure>, update: WorkflowHostUpdate<Result, Failure>): WorkflowTransition<Result, Failure>;
140
+ declare function workflowCancel<Result, Failure>(current: WorkflowHostState<Result, Failure>, expectedGeneration: number): WorkflowTransition<Result, Failure>;
141
+ /** Host calls after an authorized native restart. Receipt identity remains run plus occurrence. */
142
+ declare function workflowRestart<Result, Failure>(current: WorkflowHostState<Result, Failure>): WorkflowHostState<Result, Failure>;
143
+ /** Host closures capture the trusted run, secured storage and manager. `write` must enforce expected generation atomically. */
144
+ declare function workflowStatusBindings<Result, Failure>(configuration: {
145
+ authorize: () => Ordinary<void>;
146
+ read: () => Ordinary<WorkflowHostState<Result, Failure>>;
147
+ write: (expectedGeneration: number, state: WorkflowHostState<Result, Failure>) => Ordinary<void>;
148
+ nativeStatus: () => Ordinary<WorkflowNativeStatus>;
149
+ receiptOutcome: () => Ordinary<WorkflowOutcome<Result, Failure> | undefined>;
150
+ /** Host calls the manager in the same transaction as its guarded state write. */
151
+ cancelNative: () => Ordinary<void>;
152
+ restartNative: () => Ordinary<void>;
153
+ }): {
154
+ callback(expectedGeneration: number, nativeStatus: WorkflowNativeStatus, outcome?: WorkflowOutcome<Result, Failure>): Promise<WorkflowTransition<Result, Failure>>;
155
+ reconcile(expectedGeneration: number): Promise<WorkflowTransition<Result, Failure>>;
156
+ cancel(expectedGeneration: number): Promise<WorkflowTransition<Result, Failure>>;
157
+ restart(expectedGeneration: number): Promise<{
158
+ kind: 'ignored';
159
+ state: WorkflowHostState<Result, Failure>;
160
+ } | {
161
+ kind: 'applied';
162
+ state: WorkflowHostState<Result, Failure>;
163
+ }>;
164
+ };
165
+ //#endregion
166
+ export { ReceiptProtectedWorkflowMutation, WorkflowBinding, WorkflowBindingError, WorkflowExecution, WorkflowHostState, WorkflowHostUpdate, WorkflowNativeStatus, WorkflowOutcome, WorkflowReceiptAdapter, WorkflowStepArguments, WorkflowStepOptions, WorkflowStepRunner, WorkflowTransition, receiptWorkflowMutation, runWorkflowStep, terminalWorkflowAttempt, workflowAttempt, workflowBinding, workflowCancel, workflowDecode, workflowExecution, workflowReceiptInvocation, workflowRestart, workflowStatusBindings, workflowTransition };
167
+ //# sourceMappingURL=workflow.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{decodeContract as e}from"./contract.mjs";import{canonicalConvexBytes as t,captureIdempotencyInvocation as n}from"./idempotency.mjs";var r=class extends Error{_tag=`WorkflowBindingError`;constructor(e){super(e),this.name=`WorkflowBindingError`}};const i=[`version`,`operation`,`operationVersion`,`contractVersion`,`bindingVersion`,`run`,`capability`,`occurrence`,`args`],a={maxDepth:64,maxNodes:1e5,maxBytes:1e6,maxArrayLength:1e5,maxObjectFields:1e5};function o(e){if(!e||typeof e!=`object`||Object.getPrototypeOf(e)!==Object.prototype||Reflect.ownKeys(e).length!==i.length||i.some(t=>!Object.hasOwn(e,t)))throw new r(`Execution requires exact plain descriptor fields`);let n=e;for(let t of i)if(!(`value`in Object.getOwnPropertyDescriptor(e,t)))throw new r(`Execution cannot contain accessors`);if(n.version!==1||i.filter(e=>e!==`version`&&e!==`args`).some(e=>typeof n[e]!=`string`||n[e].length===0))throw new r(`Invalid execution descriptor version or identity`);try{t(n.args,a)}catch{throw new r(`Execution args require plain Convex data`)}return n}function s(e){let t=e.compatibleVersions?.map(e=>Object.freeze({...e})),n={...e};return t!==void 0&&(n.compatibleVersions=Object.freeze(t)),Object.freeze(n)}async function c(e,t,n,i={}){let a=e,s=o(n),c=[t,...t.compatibleVersions??[]];if(s.operation!==t.operation||!c.some(e=>e.operationVersion===s.operationVersion&&e.contractVersion===s.contractVersion&&e.bindingVersion===s.bindingVersion))throw new r(`Incompatible workflow operation version`);let l={...i,name:i.name??`${s.operation}:${s.occurrence}`},u;switch(t.kind){case`query`:if(!a.runQuery)throw new r(`Native query runner missing`);u=await a.runQuery(t.reference,{execution:s},l);break;case`mutation`:if(!a.runMutation)throw new r(`Native mutation runner missing`);u=await a.runMutation(t.reference,{execution:s},l);break;case`action`:if(!a.runAction)throw new r(`Native action runner missing`);if(i.inline)throw new r(`Actions cannot execute inline`);u=await a.runAction(t.reference,{execution:s},{...l,retry:i.retry??!1})}return u}async function l(t,n){let i=await e(t,n);if(i.issues)throw new r(`Workflow contract validation failed`);return i.value}function u(e){return async t=>{let n=o(t),r=await e.authorize(n);return e.execute(n,r)}}function d(e){return{handler:u({authorize:e.authorize,execute:async(t,n)=>{let r=e.receipt(n),i=await r.prepare(e.invocation(t,n));if(i.kind===`replay`)return l(r.replayResult,i.result);let a=await e.execute(t,n);return await i.complete(a),a}})}}function f(e,t){let r=o(e);return n({binding:{kind:`mutation`,atomicity:`same-mutation`},identity:{operation:r.operation,scope:t.scope,key:JSON.stringify([r.run,r.occurrence])},versions:{operation:r.operationVersion,contract:r.contractVersion,binding:r.bindingVersion,fingerprintPolicy:t.fingerprintPolicy},rawInput:r.args,canonical:{bounds:t.bounds}})}function p(e){return u({authorize:e.authorize,execute:async(n,r)=>{let i;try{i=await e.invokeMutation(n,r)}catch(n){let r=await e.terminal(n);if(r===void 0)throw n;let i=await l(e.failure,r);return t(i,a),{version:1,kind:`failed`,error:i}}return await l(e.result,i),t(i,a),{version:1,kind:`succeeded`,value:i}}})}function m(e,t){if(v(e.generation),v(t.generation),e.generation!==t.generation)return{kind:`ignored`,state:e};let n=e.nativeStatus===`running`?t.nativeStatus:e.nativeStatus,r=e.outcome??t.outcome,i=(e.status===`running`||e.status===`succeeded`)&&n===`succeeded`&&r?.kind===`failed`?`failed`:e.status===`running`?n:e.status,a={generation:e.generation,status:i,nativeStatus:n};return{kind:`applied`,state:r===void 0?a:{...a,outcome:r}}}function h(e,t){return v(t),e.generation===t?{kind:`applied`,state:{...e,status:e.status===`running`?`canceled`:e.status}}:{kind:`ignored`,state:e}}function g(e){v(e.generation),v(e.generation+1);let t={generation:e.generation+1,status:`running`,nativeStatus:`running`};return e.outcome?.kind===`succeeded`?{...t,outcome:e.outcome}:t}function _(e){async function t(t,n,r){let i={generation:t,nativeStatus:n},a=m(await e.read(),r===void 0?i:{...i,outcome:r});return a.kind===`applied`&&await e.write(t,a.state),a}return{async callback(n,r,i){return await e.authorize(),t(n,r,i)},async reconcile(n){return await e.authorize(),t(n,await e.nativeStatus(),await e.receiptOutcome())},async cancel(t){await e.authorize();let n=await e.read(),r=h(n,t);return r.kind===`applied`&&n.status===`running`&&(await e.cancelNative(),await e.write(t,r.state)),r},async restart(t){await e.authorize();let n=await e.read();if(n.generation!==t)return{kind:`ignored`,state:n};let r=g(n);return await e.restartNative(),await e.write(t,r),{kind:`applied`,state:r}}}}function v(e){if(!Number.isSafeInteger(e)||e<0)throw new r(`Invalid host execution generation`)}export{r as WorkflowBindingError,d as receiptWorkflowMutation,c as runWorkflowStep,p as terminalWorkflowAttempt,u as workflowAttempt,s as workflowBinding,h as workflowCancel,l as workflowDecode,o as workflowExecution,f as workflowReceiptInvocation,g as workflowRestart,_ as workflowStatusBindings,m as workflowTransition};
2
+ //# sourceMappingURL=workflow.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.mjs","names":[],"sources":["../../../src/modules/contracts/workflow.ts"],"sourcesContent":["import type { FunctionReference, FunctionVisibility, FunctionType } from 'convex/server'\nimport type { WorkflowCtx } from '@convex-dev/workflow'\nimport {\n\tdecodeContract,\n\ttype ContractInput,\n\ttype ContractOutput,\n\ttype NeutralSchema,\n} from './contract'\nimport {\n\tcanonicalConvexBytes,\n\tcaptureIdempotencyInvocation,\n\ttype CanonicalConvexBounds,\n\ttype IdempotencyInvocation,\n\ttype IdempotencyPreparation,\n} from './idempotency'\n\nexport class WorkflowBindingError extends Error {\n\treadonly _tag = 'WorkflowBindingError'\n\tconstructor(message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'WorkflowBindingError'\n\t}\n}\nexport interface WorkflowExecution<Args = unknown> {\n\treadonly version: 1\n\treadonly operation: string\n\treadonly operationVersion: string\n\treadonly contractVersion: string\n\treadonly bindingVersion: string\n\t/** Host-issued business-run identity. Recovery preserves it. */\n\treadonly run: string\n\t/** Opaque host capability; never caller-supplied principal or tenant authority. */\n\treadonly capability: string\n\t/** Logical occurrence, distinct for each repeated loop step. */\n\treadonly occurrence: string\n\treadonly args: Args\n}\nexport type WorkflowStepArguments<Args> = { execution: WorkflowExecution<Args> }\nconst fields = [\n\t'version',\n\t'operation',\n\t'operationVersion',\n\t'contractVersion',\n\t'bindingVersion',\n\t'run',\n\t'capability',\n\t'occurrence',\n\t'args',\n] as const\nconst descriptorBounds = {\n\tmaxDepth: 64,\n\tmaxNodes: 100000,\n\tmaxBytes: 1000000,\n\tmaxArrayLength: 100000,\n\tmaxObjectFields: 100000,\n}\n/** Strict plain, versioned transport. Validity does not confer authority; the host resolves capability anew. */\n/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-runtime-typeof -- This decoder validates an untrusted execution descriptor before it enters the native workflow boundary. */\nexport function workflowExecution<Args>(value: WorkflowExecution<Args>): WorkflowExecution<Args>\nexport function workflowExecution(value: unknown): WorkflowExecution\nexport function workflowExecution(value: unknown): WorkflowExecution {\n\tif (\n\t\t!value ||\n\t\ttypeof value !== 'object' ||\n\t\tObject.getPrototypeOf(value) !== Object.prototype ||\n\t\tReflect.ownKeys(value).length !== fields.length ||\n\t\tfields.some((field) => !Object.hasOwn(value, field))\n\t)\n\t\tthrow new WorkflowBindingError('Execution requires exact plain descriptor fields')\n\t// SAFETY: the exact field set is checked above; values and accessors are checked before use below.\n\tconst descriptor = value as WorkflowExecution\n\tfor (const field of fields)\n\t\tif (!('value' in Object.getOwnPropertyDescriptor(value, field)!))\n\t\t\tthrow new WorkflowBindingError('Execution cannot contain accessors')\n\tif (\n\t\tdescriptor.version !== 1 ||\n\t\tfields\n\t\t\t.filter((field) => field !== 'version' && field !== 'args')\n\t\t\t.some((field) => typeof descriptor[field] !== 'string' || descriptor[field].length === 0)\n\t)\n\t\tthrow new WorkflowBindingError('Invalid execution descriptor version or identity')\n\ttry {\n\t\tcanonicalConvexBytes(descriptor.args, descriptorBounds)\n\t} catch {\n\t\tthrow new WorkflowBindingError('Execution args require plain Convex data')\n\t}\n\treturn descriptor\n}\n/* oxlint-enable anti-slop/no-unknown-parameters, anti-slop/no-runtime-typeof */\nexport interface WorkflowBinding<\n\tKind extends FunctionType,\n\tArgs extends NeutralSchema,\n\tResult extends NeutralSchema,\n> {\n\treadonly kind: Kind\n\treadonly operation: string\n\treadonly operationVersion: string\n\treadonly contractVersion: string\n\treadonly bindingVersion: string\n\treadonly args: Args\n\treadonly result: Result\n\treadonly reference: FunctionReference<\n\t\tNoInfer<Kind>,\n\t\tFunctionVisibility,\n\t\tWorkflowStepArguments<NoInfer<ContractInput<Args>>>,\n\t\tNoInfer<ContractInput<Result>>\n\t>\n\t/** Host explicitly lists deployed descriptor versions whose semantics remain compatible. */\n\treadonly compatibleVersions?: readonly {\n\t\toperationVersion: string\n\t\tcontractVersion: string\n\t\tbindingVersion: string\n\t}[]\n}\n/** Both phantom reference args and results must match the explicit wire contracts. */\nexport function workflowBinding<\n\tKind extends FunctionType,\n\tconst Args extends NeutralSchema,\n\tconst Result extends NeutralSchema,\n>(binding: WorkflowBinding<Kind, Args, Result>): WorkflowBinding<Kind, Args, Result> {\n\tconst compatibleVersions = binding.compatibleVersions?.map((version) =>\n\t\tObject.freeze({ ...version }),\n\t)\n\tconst snapshot = { ...binding }\n\tif (compatibleVersions !== undefined)\n\t\tsnapshot.compatibleVersions = Object.freeze(compatibleVersions)\n\treturn Object.freeze(snapshot)\n}\nexport type WorkflowStepOptions = {\n\tname?: string\n\tretry?: NonNullable<Parameters<WorkflowCtx['withOptions']>[0]['retry']>\n} & (\n\t| { inline?: false; runAt?: number; runAfter?: number }\n\t| { inline: true; runAt?: never; runAfter?: never }\n)\n/** A structural seam allows invocation-scoped native WorkflowCtx without creating another durability runtime. */\nexport interface WorkflowStepRunner {\n\t/* oxlint-disable anti-slop/no-unknown-returns -- Native runner results stay opaque here; runWorkflowStep correlates them with the binding's raw result contract without replay decoding. */\n\trunQuery?: (\n\t\treference: FunctionReference<'query', FunctionVisibility>,\n\t\targs: WorkflowStepArguments<unknown>,\n\t\toptions?: WorkflowStepOptions,\n\t) => Promise<unknown>\n\trunMutation?: (\n\t\treference: FunctionReference<'mutation', FunctionVisibility>,\n\t\targs: WorkflowStepArguments<unknown>,\n\t\toptions?: WorkflowStepOptions,\n\t) => Promise<unknown>\n\trunAction?: (\n\t\treference: FunctionReference<'action', FunctionVisibility>,\n\t\targs: WorkflowStepArguments<unknown>,\n\t\toptions?: WorkflowStepOptions,\n\t) => Promise<unknown>\n\t/* oxlint-enable anti-slop/no-unknown-returns */\n}\nexport async function runWorkflowStep<\n\tKind extends FunctionType,\n\tArgs extends NeutralSchema,\n\tResult extends NeutralSchema,\n>(\n\tstep: WorkflowCtx | WorkflowStepRunner,\n\tbinding: WorkflowBinding<Kind, Args, Result>,\n\tinput: WorkflowExecution<ContractInput<Args>>,\n\toptions: WorkflowStepOptions = {},\n): Promise<ContractInput<Result>> {\n\t// SAFETY: each binding has nonempty, checked generated args. Native ArgsAndOptions' empty-args overload is never selected.\n\tconst runner = step as WorkflowStepRunner\n\tconst execution = workflowExecution(input)\n\tconst versions = [binding, ...(binding.compatibleVersions ?? [])]\n\tif (\n\t\texecution.operation !== binding.operation ||\n\t\t!versions.some(\n\t\t\t(version) =>\n\t\t\t\tversion.operationVersion === execution.operationVersion &&\n\t\t\t\tversion.contractVersion === execution.contractVersion &&\n\t\t\t\tversion.bindingVersion === execution.bindingVersion,\n\t\t)\n\t)\n\t\tthrow new WorkflowBindingError('Incompatible workflow operation version')\n\tconst nativeOptions = {\n\t\t...options,\n\t\tname: options.name ?? `${execution.operation}:${execution.occurrence}`,\n\t}\n\tlet output: unknown\n\tswitch (binding.kind) {\n\t\tcase 'query':\n\t\t\tif (!runner.runQuery) throw new WorkflowBindingError('Native query runner missing')\n\t\t\t// SAFETY: the checked binding kind selects this exact native reference kind.\n\t\t\toutput = await runner.runQuery(\n\t\t\t\tbinding.reference as FunctionReference<'query', FunctionVisibility>,\n\t\t\t\t{ execution },\n\t\t\t\tnativeOptions,\n\t\t\t)\n\t\t\tbreak\n\t\tcase 'mutation':\n\t\t\tif (!runner.runMutation) throw new WorkflowBindingError('Native mutation runner missing')\n\t\t\t// SAFETY: the checked binding kind selects this exact native reference kind.\n\t\t\toutput = await runner.runMutation(\n\t\t\t\tbinding.reference as FunctionReference<'mutation', FunctionVisibility>,\n\t\t\t\t{ execution },\n\t\t\t\tnativeOptions,\n\t\t\t)\n\t\t\tbreak\n\t\tcase 'action':\n\t\t\tif (!runner.runAction) throw new WorkflowBindingError('Native action runner missing')\n\t\t\tif (options.inline) throw new WorkflowBindingError('Actions cannot execute inline')\n\t\t\t// SAFETY: the checked binding kind selects this exact native reference kind.\n\t\t\toutput = await runner.runAction(\n\t\t\t\tbinding.reference as FunctionReference<'action', FunctionVisibility>,\n\t\t\t\t{ execution },\n\t\t\t\t{ ...nativeOptions, retry: options.retry ?? false },\n\t\t\t)\n\t\t\tbreak\n\t}\n\t// Native validators own wire validation. Replaying workflow code must not rerun transforms.\n\t// SAFETY: the binding correlates the generated reference's result with this raw wire contract.\n\treturn output as ContractInput<Result>\n}\nexport async function workflowDecode<S extends NeutralSchema>(\n\tschema: S,\n\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- The schema parses retained or native transport values at this boundary.\n\tvalue: unknown,\n): Promise<ContractOutput<S>> {\n\tconst decoded = await decodeContract(schema, value)\n\tif (decoded.issues) throw new WorkflowBindingError('Workflow contract validation failed')\n\treturn decoded.value\n}\ntype Ordinary<A> = A | PromiseLike<A>\n/** This helper belongs inside a registered native function, never in the replaying workflow handler. */\nexport function workflowAttempt<Args, Authority, Result>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>\n\texecute: (execution: WorkflowExecution<Args>, authority: Authority) => Ordinary<Result>\n}) {\n\treturn async (input: WorkflowExecution<Args>): Promise<Result> => {\n\t\tconst execution = workflowExecution(input)\n\t\tconst authority = await configuration.authorize(execution)\n\t\treturn configuration.execute(execution, authority)\n\t}\n}\nexport type WorkflowOutcome<Result = unknown, Failure = unknown> =\n\t| { readonly version: 1; readonly kind: 'succeeded'; readonly value: Result }\n\t| { readonly version: 1; readonly kind: 'failed'; readonly error: Failure }\ndeclare const protectedMutation: unique symbol\nexport interface ReceiptProtectedWorkflowMutation<Args, Result> {\n\treadonly [protectedMutation]: { args: Args; result: Result }\n\treadonly handler: (execution: WorkflowExecution<Args>) => Promise<Result>\n}\nexport interface WorkflowReceiptAdapter<S extends NeutralSchema> {\n\treadonly replayResult: S\n\treadonly prepare: (\n\t\tinvocation: IdempotencyInvocation,\n\t) => Promise<IdempotencyPreparation<ContractOutput<S>>>\n}\n/** Host registers this handler as the inner native mutation. All callbacks share its transaction. */\nexport function receiptWorkflowMutation<\n\tArgs,\n\tAuthority,\n\tconst Replay extends NeutralSchema,\n>(configuration: {\n\tauthorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>\n\treceipt: (authority: Authority) => WorkflowReceiptAdapter<Replay>\n\tinvocation: (execution: WorkflowExecution<Args>, authority: Authority) => IdempotencyInvocation\n\texecute: (\n\t\texecution: WorkflowExecution<Args>,\n\t\tauthority: Authority,\n\t) => Ordinary<ContractOutput<Replay>>\n}): ReceiptProtectedWorkflowMutation<Args, ContractOutput<Replay>> {\n\tconst handler = workflowAttempt({\n\t\tauthorize: configuration.authorize,\n\t\texecute: async (execution: WorkflowExecution<Args>, authority: Authority) => {\n\t\t\tconst adapter = configuration.receipt(authority)\n\t\t\tconst preparation = await adapter.prepare(configuration.invocation(execution, authority))\n\t\t\tif (preparation.kind === 'replay')\n\t\t\t\treturn workflowDecode(adapter.replayResult, preparation.result)\n\t\t\tconst value = await configuration.execute(execution, authority)\n\t\t\tawait preparation.complete(value)\n\t\t\treturn value\n\t\t},\n\t})\n\t// SAFETY: the private type evidence can only be issued by this receipt-protected helper.\n\treturn { handler } as ReceiptProtectedWorkflowMutation<Args, ContractOutput<Replay>>\n}\nexport function workflowReceiptInvocation(\n\texecution: WorkflowExecution,\n\toptions: { scope: string; fingerprintPolicy: string; bounds: CanonicalConvexBounds },\n): IdempotencyInvocation {\n\tconst descriptor = workflowExecution(execution)\n\treturn captureIdempotencyInvocation({\n\t\tbinding: { kind: 'mutation', atomicity: 'same-mutation' },\n\t\tidentity: {\n\t\t\toperation: descriptor.operation,\n\t\t\tscope: options.scope,\n\t\t\tkey: JSON.stringify([descriptor.run, descriptor.occurrence]),\n\t\t},\n\t\tversions: {\n\t\t\toperation: descriptor.operationVersion,\n\t\t\tcontract: descriptor.contractVersion,\n\t\t\tbinding: descriptor.bindingVersion,\n\t\t\tfingerprintPolicy: options.fingerprintPolicy,\n\t\t},\n\t\trawInput: descriptor.args,\n\t\tcanonical: { bounds: options.bounds },\n\t})\n}\ntype TerminalMode<Args> =\n\t| {\n\t\t\tkind: 'mutation'\n\t\t\t/** Assertion supplied only after host native rollback/journaling acceptance. */ atomicJournalProof: 'host-verified'\n\t }\n\t| { kind: 'action'; protectedMutation: ReceiptProtectedWorkflowMutation<Args, unknown> }\n/** The native inner mutation rejection must cross its transaction boundary before terminal mapping. */\nexport function terminalWorkflowAttempt<\n\tArgs,\n\tAuthority,\n\tconst Result extends NeutralSchema,\n\tconst Failure extends NeutralSchema,\n>(\n\tconfiguration: TerminalMode<Args> & {\n\t\tauthorize: (execution: WorkflowExecution<Args>) => Ordinary<Authority>\n\t\tinvokeMutation: (\n\t\t\texecution: WorkflowExecution<Args>,\n\t\t\tauthority: Authority,\n\t\t) => Promise<ContractInput<Result>>\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Native thrown values are classified by the host before validating the terminal failure contract.\n\t\tterminal: (error: unknown) => Ordinary<ContractInput<Failure> | undefined>\n\t\tresult: Result\n\t\tfailure: Failure\n\t},\n) {\n\treturn workflowAttempt({\n\t\tauthorize: configuration.authorize,\n\t\texecute: async (\n\t\t\texecution: WorkflowExecution<Args>,\n\t\t\tauthority: Authority,\n\t\t): Promise<WorkflowOutcome<ContractInput<Result>, ContractOutput<Failure>>> => {\n\t\t\tlet value: ContractInput<Result>\n\t\t\ttry {\n\t\t\t\tvalue = await configuration.invokeMutation(execution, authority)\n\t\t\t} catch (error) {\n\t\t\t\tconst terminal = await configuration.terminal(error)\n\t\t\t\tif (terminal === undefined) throw error\n\t\t\t\tconst safeFailure = await workflowDecode(configuration.failure, terminal)\n\t\t\t\tcanonicalConvexBytes(safeFailure, descriptorBounds)\n\t\t\t\treturn { version: 1, kind: 'failed', error: safeFailure }\n\t\t\t}\n\t\t\tawait workflowDecode(configuration.result, value)\n\t\t\tcanonicalConvexBytes(value, descriptorBounds)\n\t\t\treturn { version: 1, kind: 'succeeded', value }\n\t\t},\n\t})\n}\nexport type WorkflowNativeStatus = 'running' | 'succeeded' | 'failed' | 'canceled'\nexport interface WorkflowHostState<Result = unknown, Failure = unknown> {\n\treadonly generation: number\n\treadonly status: WorkflowNativeStatus\n\treadonly nativeStatus: WorkflowNativeStatus\n\treadonly outcome?: WorkflowOutcome<Result, Failure>\n}\nexport interface WorkflowHostUpdate<Result = unknown, Failure = unknown> {\n\treadonly generation: number\n\treadonly nativeStatus: WorkflowNativeStatus\n\treadonly outcome?: WorkflowOutcome<Result, Failure>\n}\nexport type WorkflowTransition<Result = unknown, Failure = unknown> = {\n\treadonly kind: 'applied' | 'ignored'\n\treadonly state: WorkflowHostState<Result, Failure>\n}\n/** Call within a host transaction or compare-and-set. A late operation failure refines host success; cancellation and terminal native status stay fenced. */\nexport function workflowTransition<Result, Failure>(\n\tcurrent: WorkflowHostState<Result, Failure>,\n\tupdate: WorkflowHostUpdate<Result, Failure>,\n): WorkflowTransition<Result, Failure> {\n\tgeneration(current.generation)\n\tgeneration(update.generation)\n\tif (current.generation !== update.generation) return { kind: 'ignored', state: current }\n\tconst nativeStatus =\n\t\tcurrent.nativeStatus !== 'running' ? current.nativeStatus : update.nativeStatus\n\tconst outcome = current.outcome ?? update.outcome\n\tconst status =\n\t\t(current.status === 'running' || current.status === 'succeeded') &&\n\t\tnativeStatus === 'succeeded' &&\n\t\toutcome?.kind === 'failed'\n\t\t\t? 'failed'\n\t\t\t: current.status !== 'running'\n\t\t\t\t? current.status\n\t\t\t\t: nativeStatus\n\tconst state = { generation: current.generation, status, nativeStatus }\n\treturn { kind: 'applied', state: outcome === undefined ? state : { ...state, outcome } }\n}\nexport function workflowCancel<Result, Failure>(\n\tcurrent: WorkflowHostState<Result, Failure>,\n\texpectedGeneration: number,\n): WorkflowTransition<Result, Failure> {\n\tgeneration(expectedGeneration)\n\tif (current.generation !== expectedGeneration) return { kind: 'ignored', state: current }\n\treturn {\n\t\tkind: 'applied',\n\t\tstate: { ...current, status: current.status === 'running' ? 'canceled' : current.status },\n\t}\n}\n/** Host calls after an authorized native restart. Receipt identity remains run plus occurrence. */\nexport function workflowRestart<Result, Failure>(\n\tcurrent: WorkflowHostState<Result, Failure>,\n): WorkflowHostState<Result, Failure> {\n\tgeneration(current.generation)\n\tgeneration(current.generation + 1)\n\tconst state = {\n\t\tgeneration: current.generation + 1,\n\t\tstatus: 'running' as const,\n\t\tnativeStatus: 'running' as const,\n\t}\n\treturn current.outcome?.kind === 'succeeded' ? { ...state, outcome: current.outcome } : state\n}\n/** Host closures capture the trusted run, secured storage and manager. `write` must enforce expected generation atomically. */\nexport function workflowStatusBindings<Result, Failure>(configuration: {\n\tauthorize: () => Ordinary<void>\n\tread: () => Ordinary<WorkflowHostState<Result, Failure>>\n\twrite: (expectedGeneration: number, state: WorkflowHostState<Result, Failure>) => Ordinary<void>\n\tnativeStatus: () => Ordinary<WorkflowNativeStatus>\n\treceiptOutcome: () => Ordinary<WorkflowOutcome<Result, Failure> | undefined>\n\t/** Host calls the manager in the same transaction as its guarded state write. */\n\tcancelNative: () => Ordinary<void>\n\trestartNative: () => Ordinary<void>\n}) {\n\tasync function apply(\n\t\texpectedGeneration: number,\n\t\tnativeStatus: WorkflowNativeStatus,\n\t\toutcome?: WorkflowOutcome<Result, Failure>,\n\t) {\n\t\tconst update = { generation: expectedGeneration, nativeStatus }\n\t\tconst transition = workflowTransition(\n\t\t\tawait configuration.read(),\n\t\t\toutcome === undefined ? update : { ...update, outcome },\n\t\t)\n\t\tif (transition.kind === 'applied')\n\t\t\tawait configuration.write(expectedGeneration, transition.state)\n\t\treturn transition\n\t}\n\treturn {\n\t\tasync callback(\n\t\t\texpectedGeneration: number,\n\t\t\tnativeStatus: WorkflowNativeStatus,\n\t\t\toutcome?: WorkflowOutcome<Result, Failure>,\n\t\t) {\n\t\t\tawait configuration.authorize()\n\t\t\treturn apply(expectedGeneration, nativeStatus, outcome)\n\t\t},\n\t\tasync reconcile(expectedGeneration: number) {\n\t\t\tawait configuration.authorize()\n\t\t\treturn apply(\n\t\t\t\texpectedGeneration,\n\t\t\t\tawait configuration.nativeStatus(),\n\t\t\t\tawait configuration.receiptOutcome(),\n\t\t\t)\n\t\t},\n\t\tasync cancel(expectedGeneration: number) {\n\t\t\tawait configuration.authorize()\n\t\t\tconst current = await configuration.read()\n\t\t\tconst transition = workflowCancel(current, expectedGeneration)\n\t\t\tif (transition.kind === 'applied' && current.status === 'running') {\n\t\t\t\tawait configuration.cancelNative()\n\t\t\t\tawait configuration.write(expectedGeneration, transition.state)\n\t\t\t}\n\t\t\treturn transition\n\t\t},\n\t\tasync restart(expectedGeneration: number) {\n\t\t\tawait configuration.authorize()\n\t\t\tconst current = await configuration.read()\n\t\t\tif (current.generation !== expectedGeneration)\n\t\t\t\treturn { kind: 'ignored' as const, state: current }\n\t\t\tconst state = workflowRestart(current)\n\t\t\tawait configuration.restartNative()\n\t\t\tawait configuration.write(expectedGeneration, state)\n\t\t\treturn { kind: 'applied' as const, state }\n\t\t},\n\t}\n}\nfunction generation(value: number): void {\n\tif (!Number.isSafeInteger(value) || value < 0)\n\t\tthrow new WorkflowBindingError('Invalid host execution generation')\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { OperationExecutor, OperationPublicResult, OperationTool, OperationToolConverter, OperationToolDefinition, OperationToolJsonSchema, OperationToolOutcome, SelectedOperation, bindOperationExecutor, createOperationTools, operationToolDialect, selectOperation } from "../contracts/exposure.mjs";
2
+ export { type OperationExecutor, type OperationPublicResult, type OperationTool, type OperationToolConverter, type OperationToolDefinition, type OperationToolJsonSchema, type OperationToolOutcome, type SelectedOperation, bindOperationExecutor, createOperationTools, operationToolDialect, selectOperation };
@@ -0,0 +1 @@
1
+ import{bindOperationExecutor as e,createOperationTools as t,operationToolDialect as n,selectOperation as r}from"../contracts/exposure.mjs";export{e as bindOperationExecutor,t as createOperationTools,n as operationToolDialect,r as selectOperation};