@ixo/flow-work 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/protocol.js CHANGED
@@ -1,23 +1,172 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { z } from 'zod';
2
- /**
3
- * The flow-work wire protocol — the Matrix events flow-manager and helper
4
- * oracles exchange. Mirror of flow-manager's oracle-delegation plugin
5
- * (apps/app/src/plugins/oracle-delegation/oracle-room.ts). If these shapes
6
- * change, both sides change together; until this lives in a shared package
7
- * the duplication is deliberate and must be kept in sync.
8
- */
3
+ /** Matrix event names for flow-work protocol v2. */
9
4
  export const FLOW_WORK_ASSIGN_EVENT = 'ixo.flow.work.assign';
5
+ export const FLOW_WORK_READY_EVENT = 'ixo.flow.work.ready';
10
6
  export const FLOW_WORK_INVOKE_EVENT = 'ixo.flow.work.invoke';
11
7
  export const FLOW_WORK_RECEIPT_EVENT = 'ixo.flow.work.receipt';
12
- export const flowWorkInvokeSchema = z.object({
13
- invocationId: z.string().trim().min(1),
14
- capability: z.string().trim().min(1),
15
- actionType: z.string().trim().min(1),
16
- nodeId: z.string().trim().min(1),
8
+ const nonEmpty = z.string().trim().min(1);
9
+ const reservedNbKeys = new Set([
10
+ 'protocolVersion',
11
+ 'invocationId',
12
+ 'managerDid',
13
+ 'audience',
14
+ 'actionType',
15
+ 'nodeId',
16
+ 'inputHash',
17
+ 'attempt',
18
+ 'deadline',
19
+ 'delegationDepth',
20
+ ]);
21
+ const contractCaveatsSchema = z
22
+ .record(z.string(), z.unknown())
23
+ .refine((value) => Object.keys(value).every((key) => !reservedNbKeys.has(key)), 'contractCaveats cannot override flow-work protocol bindings');
24
+ const bindingShape = {
25
+ protocolVersion: z.literal(2),
26
+ invocationId: nonEmpty,
27
+ managerDid: nonEmpty,
28
+ /** Entity DID of the oracle contracted for this invocation. */
29
+ audience: nonEmpty,
30
+ capability: nonEmpty,
31
+ actionType: nonEmpty,
32
+ nodeId: nonEmpty,
33
+ /** UCAN resource, and therefore the exact value of capability.with. */
34
+ resource: nonEmpty,
35
+ inputHash: z.string().regex(/^sha256:[0-9a-f]{64}$/),
36
+ attempt: z.number().int().safe().min(1),
37
+ /** Absolute Unix epoch deadline in milliseconds. */
38
+ deadline: z.number().int().safe().positive(),
39
+ /** Service-contract caveats copied exactly into the UCAN nb object. */
40
+ contractCaveats: contractCaveatsSchema,
41
+ };
42
+ /**
43
+ * Immutable routing and authorization binding shared by assign, ready, invoke,
44
+ * and receipt. Every hop repeats these fields so no event can be spliced into
45
+ * a different contract.
46
+ */
47
+ export const flowWorkBindingSchema = z.object(bindingShape).strict();
48
+ export const flowWorkAssignSchema = z
49
+ .object({
50
+ ...bindingShape,
51
+ /** Exact Matrix operator user id contracted for this entity DID. */
52
+ oracleMatrixId: nonEmpty,
53
+ assignedAt: z.string().datetime(),
54
+ status: z.literal('invited'),
55
+ })
56
+ .strict();
57
+ export const flowWorkReadySchema = z
58
+ .object({
59
+ ...bindingShape,
60
+ status: z.literal('ready'),
61
+ })
62
+ .strict();
63
+ export const flowWorkInvokeSchema = z
64
+ .object({
65
+ ...bindingShape,
17
66
  inputs: z.record(z.string(), z.unknown()),
18
67
  /** Serialized UCAN delegation (base64 CAR) authorizing this work. */
19
- delegation: z.string().trim().min(1),
20
- /** DID of the oracle this invocation is addressed to. */
21
- audience: z.string().trim().min(1),
22
- });
68
+ delegation: nonEmpty,
69
+ })
70
+ .strict();
71
+ export const flowWorkErrorCodeSchema = z.enum([
72
+ 'assignment_missing',
73
+ 'sender_untrusted',
74
+ 'binding_mismatch',
75
+ 'deadline_expired',
76
+ 'delegation_invalid',
77
+ 'delegation_expired',
78
+ 'capability_not_declared',
79
+ 'input_invalid',
80
+ 'output_invalid',
81
+ 'tool_error',
82
+ ]);
83
+ export const flowWorkReceiptSchema = z.discriminatedUnion('status', [
84
+ z
85
+ .object({
86
+ ...bindingShape,
87
+ status: z.literal('success'),
88
+ output: z.record(z.string(), z.unknown()).nullable(),
89
+ error: z.null(),
90
+ })
91
+ .strict(),
92
+ z
93
+ .object({
94
+ ...bindingShape,
95
+ status: z.literal('failure'),
96
+ output: z.null(),
97
+ error: z
98
+ .object({
99
+ code: flowWorkErrorCodeSchema,
100
+ message: z.string(),
101
+ })
102
+ .strict(),
103
+ })
104
+ .strict(),
105
+ ]);
106
+ export function flowWorkNbFor(binding) {
107
+ return {
108
+ protocolVersion: binding.protocolVersion,
109
+ invocationId: binding.invocationId,
110
+ managerDid: binding.managerDid,
111
+ audience: binding.audience,
112
+ actionType: binding.actionType,
113
+ nodeId: binding.nodeId,
114
+ inputHash: binding.inputHash,
115
+ attempt: binding.attempt,
116
+ deadline: binding.deadline,
117
+ delegationDepth: 0,
118
+ ...binding.contractCaveats,
119
+ };
120
+ }
121
+ export function sameFlowWorkNb(actual, binding) {
122
+ return (actual !== undefined &&
123
+ canonicalJson(actual) === canonicalJson(flowWorkNbFor(binding)));
124
+ }
125
+ export const FLOW_WORK_BINDING_FIELDS = [
126
+ 'protocolVersion',
127
+ 'invocationId',
128
+ 'managerDid',
129
+ 'audience',
130
+ 'capability',
131
+ 'actionType',
132
+ 'nodeId',
133
+ 'resource',
134
+ 'inputHash',
135
+ 'attempt',
136
+ 'deadline',
137
+ 'contractCaveats',
138
+ ];
139
+ export function sameFlowWorkBinding(left, right) {
140
+ return FLOW_WORK_BINDING_FIELDS.every((field) => field === 'contractCaveats'
141
+ ? canonicalJson(left[field]) === canonicalJson(right[field])
142
+ : left[field] === right[field]);
143
+ }
144
+ /** Stable JSON hash used by assignment to commit to later invoke inputs. */
145
+ export function computeFlowWorkInputHash(inputs) {
146
+ return `sha256:${createHash('sha256').update(canonicalJson(inputs)).digest('hex')}`;
147
+ }
148
+ export function canonicalJson(value) {
149
+ if (value === null)
150
+ return 'null';
151
+ if (typeof value === 'string' || typeof value === 'boolean') {
152
+ return JSON.stringify(value);
153
+ }
154
+ if (typeof value === 'number') {
155
+ return Number.isFinite(value) ? JSON.stringify(value) : 'null';
156
+ }
157
+ if (Array.isArray(value)) {
158
+ return `[${value.map((entry) => canonicalJson(entry ?? null)).join(',')}]`;
159
+ }
160
+ if (typeof value === 'object') {
161
+ const record = value;
162
+ return `{${Object.keys(record)
163
+ .sort()
164
+ .filter((key) => record[key] !== undefined)
165
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`)
166
+ .join(',')}}`;
167
+ }
168
+ if (value === undefined)
169
+ return 'null';
170
+ throw new TypeError(`Cannot hash non-JSON input value of type ${typeof value}`);
171
+ }
23
172
  //# sourceMappingURL=protocol.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAC7D,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAC7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAE/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IACzC,qEAAqE;IACrE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,yDAAyD;IACzD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACnC,CAAC,CAAC"}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ixo/flow-work",
3
- "version": "0.2.0",
3
+ "version": "0.4.1",
4
4
  "description": "Oracle-side flow-work plugin: accept UCAN-delegated ixo.flow.work invocations from the IXO flow-manager over Matrix and post receipts.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -10,6 +10,10 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./input": {
15
+ "types": "./dist/input.d.ts",
16
+ "import": "./dist/input.js"
13
17
  }
14
18
  },
15
19
  "files": [
@@ -38,7 +42,7 @@
38
42
  "devDependencies": {
39
43
  "@changesets/cli": "^2.31.0",
40
44
  "@ixo/oracle-runtime": "^1.3.4",
41
- "@ixo/ucan": "^2.0.0",
45
+ "@ixo/ucan": "^2.1.0",
42
46
  "@nestjs/common": "^11.1.19",
43
47
  "@types/node": "^22.10.7",
44
48
  "matrix-js-sdk": "^37.11.0",