@ixo/flow-work 0.1.0

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/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @ixo/flow-work
2
+
3
+ Oracle-side flow-work plugin: accept UCAN-delegated `ixo.flow.work` invocations
4
+ from the IXO flow-manager over Matrix and post receipts.
5
+
6
+ It is the oracle half of the flow-work contract. Flow-manager discovers a
7
+ capable oracle, mints a UCAN delegation scoped to a flow node, and sends an
8
+ `ixo.flow.work.invoke` event carrying the work brief by value. `FlowWorkListener`
9
+ validates the delegation (audience, expiry, signature chain, nb caveats),
10
+ runs the matching capability handler, and posts an `ixo.flow.work.receipt`.
11
+ The oracle never gains read authority over anything — inputs arrive in the
12
+ invocation, the result leaves in the receipt.
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ pnpm add @ixo/flow-work
18
+ ```
19
+
20
+ Peer dependencies: `@ixo/oracle-runtime`, `@ixo/ucan`, `@nestjs/common`,
21
+ `matrix-js-sdk`.
22
+
23
+ ## Releasing
24
+
25
+ This package versions independently of the flow-manager app via
26
+ [Changesets](https://github.com/changesets/changesets). It lives outside the
27
+ pnpm workspace with its own lockfile, so its Changesets setup is self-contained
28
+ in this directory.
29
+
30
+ 1. Make your change, then record it:
31
+
32
+ ```sh
33
+ cd packages/flow-work
34
+ pnpm changeset # pick patch / minor / major, write a summary
35
+ ```
36
+
37
+ Commit the generated `.changeset/*.md` file with your PR.
38
+
39
+ 2. On merge to `main`, the **Release @ixo/flow-work** workflow opens a
40
+ `release/flow-work` PR that bumps `package.json` + `CHANGELOG.md`.
41
+
42
+ 3. Merging that PR publishes the new version to npm via OIDC trusted publishing.
43
+
44
+ A change with no changeset never releases this package, and a change to the
45
+ flow-manager app never releases this package — the two version independently.
46
+
47
+ > The initial `0.1.0` publish is a one-time manual bootstrap
48
+ > (`publish-flow-work.yml`, run from the Actions tab). Configure the npm trusted
49
+ > publisher after that first release; the Changesets workflow needs no token.
@@ -0,0 +1,26 @@
1
+ import type { z } from 'zod';
2
+ /**
3
+ * A contractable capability: the unit of work this oracle accepts from
4
+ * flow-manager. `can` is what flow-manager discovers and delegates
5
+ * (`cap:<can>` keyword on the domain card); `actionType` narrows which
6
+ * handler runs; the handler is a plain async function — no coupling to the
7
+ * runtime's tool registry.
8
+ */
9
+ export interface FlowWorkCapability<Schema extends z.ZodType = z.ZodType> {
10
+ /** Capability ability, e.g. 'flow/diagnose'. Must match the UCAN grant. */
11
+ can: string;
12
+ /** Work discriminator within the capability, e.g. 'diagnose_http_request'. */
13
+ actionType: string;
14
+ description: string;
15
+ /**
16
+ * Claim schema constraints published on the domain card — the structured
17
+ * list flow-manager filters on. An empty array means no schema restriction
18
+ * (matches any). Omit entirely for capabilities that don't touch claims.
19
+ */
20
+ claimSchemas?: string[];
21
+ /** Validates the invocation's `inputs` before the handler runs. */
22
+ inputSchema: Schema;
23
+ handler: (inputs: z.infer<Schema>) => Promise<unknown>;
24
+ }
25
+ export declare function findCapability(capabilities: readonly FlowWorkCapability[], can: string, actionType: string): FlowWorkCapability | undefined;
26
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB,CAAC,MAAM,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IACtE,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD;AAED,wBAAgB,cAAc,CAC5B,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,kBAAkB,GAAG,SAAS,CAIhC"}
@@ -0,0 +1,4 @@
1
+ export function findCapability(capabilities, can, actionType) {
2
+ return capabilities.find((entry) => entry.can === can && entry.actionType === actionType);
3
+ }
4
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,cAAc,CAC5B,YAA2C,EAC3C,GAAW,EACX,UAAkB;IAElB,OAAO,YAAY,CAAC,IAAI,CACtB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,KAAK,UAAU,CAChE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { OraclePlugin, z, type PluginContext, type PluginManifest } from '@ixo/oracle-runtime';
2
+ import { type DynamicModule } from '@nestjs/common';
3
+ import type * as sdk from 'matrix-js-sdk';
4
+ import type { FlowWorkCapability } from './capability.js';
5
+ export interface FlowWorkPluginOptions {
6
+ matrixClient: sdk.MatrixClient;
7
+ capabilities: FlowWorkCapability[];
8
+ }
9
+ export declare class FlowWorkPlugin extends OraclePlugin {
10
+ private readonly options;
11
+ readonly name = "flow-work";
12
+ readonly version = "0.1.0";
13
+ readonly manifest: PluginManifest;
14
+ readonly configSchema: z.ZodObject<{
15
+ FLOW_WORK_TRUSTED_HOMESERVERS: z.ZodString;
16
+ ORACLE_ENTITY_DID: z.ZodString;
17
+ BLOCKSYNC_GRAPHQL_URL: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$strip>;
19
+ readonly autoDetectHint = "FLOW_WORK_TRUSTED_HOMESERVERS";
20
+ constructor(options: FlowWorkPluginOptions);
21
+ autoDetect(env: NodeJS.ProcessEnv): boolean;
22
+ getNestModules(ctx?: PluginContext): DynamicModule[];
23
+ }
24
+ //# sourceMappingURL=flow-work.plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-work.plugin.d.ts","sourceRoot":"","sources":["../src/flow-work.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,CAAC,EACD,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,aAAa,EAGnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,KAAK,GAAG,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AA4B1D,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC;IAC/B,YAAY,EAAE,kBAAkB,EAAE,CAAC;CACpC;AAED,qBAAa,cAAe,SAAQ,YAAY;IAWlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAVpC,QAAQ,CAAC,IAAI,eAAe;IAE5B,QAAQ,CAAC,OAAO,WAAW;IAE3B,QAAQ,CAAC,QAAQ,iBAAY;IAE7B,SAAkB,YAAY;;;;sBAAgB;IAE9C,SAAkB,cAAc,mCAAmC;gBAEtC,OAAO,EAAE,qBAAqB;IAIlD,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO;IAI3C,cAAc,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE;CAiD9D"}
@@ -0,0 +1,92 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { OraclePlugin, z, } from '@ixo/oracle-runtime';
8
+ import { Module, } from '@nestjs/common';
9
+ import { FlowWorkListener } from './listener.js';
10
+ import { adaptMatrixClient } from './matrix-port.js';
11
+ import { buildDelegationValidator } from './ucan.js';
12
+ const configSchema = z.object({
13
+ /** Comma-separated homeserver domains whose room invites are accepted. */
14
+ FLOW_WORK_TRUSTED_HOMESERVERS: z.string().trim().min(1),
15
+ /** This oracle's DID — the expected UCAN delegation audience. */
16
+ ORACLE_ENTITY_DID: z.string().trim().min(1),
17
+ /** Blocksync GraphQL endpoint for did:ixo key resolution. */
18
+ BLOCKSYNC_GRAPHQL_URL: z.string().url().optional(),
19
+ });
20
+ const manifest = {
21
+ title: 'Flow Work',
22
+ summary: 'Accepts contracted work from flow-manager: joins trusted rooms, validates UCAN-delegated ' +
23
+ 'ixo.flow.work.invoke events, runs the declared capability handler, and posts receipts.',
24
+ whenToUse: [],
25
+ whenNotToUse: [],
26
+ examples: [],
27
+ tags: ['flow', 'delegation', 'ucan', 'matrix'],
28
+ category: 'automation',
29
+ visibility: 'silent',
30
+ stability: 'experimental',
31
+ };
32
+ export class FlowWorkPlugin extends OraclePlugin {
33
+ options;
34
+ name = 'flow-work';
35
+ version = '0.1.0';
36
+ manifest = manifest;
37
+ configSchema = configSchema;
38
+ autoDetectHint = 'FLOW_WORK_TRUSTED_HOMESERVERS';
39
+ constructor(options) {
40
+ super();
41
+ this.options = options;
42
+ }
43
+ autoDetect(env) {
44
+ return Boolean(env.FLOW_WORK_TRUSTED_HOMESERVERS?.trim());
45
+ }
46
+ getNestModules(ctx) {
47
+ if (!ctx)
48
+ throw new Error('FlowWorkPlugin requires a PluginContext');
49
+ const config = configSchema.parse(ctx.config);
50
+ const trustedHomeservers = config.FLOW_WORK_TRUSTED_HOMESERVERS.split(',')
51
+ .map((value) => value.trim())
52
+ .filter((value) => value.length > 0);
53
+ const logger = ctx.logger;
54
+ const listener = new FlowWorkListener({
55
+ port: adaptMatrixClient(this.options.matrixClient),
56
+ oracleDid: config.ORACLE_ENTITY_DID,
57
+ trustedHomeservers,
58
+ capabilities: this.options.capabilities,
59
+ validateDelegation: buildDelegationValidator({
60
+ oracleDid: config.ORACLE_ENTITY_DID,
61
+ blocksyncUrl: config.BLOCKSYNC_GRAPHQL_URL,
62
+ }),
63
+ logger,
64
+ });
65
+ const matrixClient = this.options.matrixClient;
66
+ class FlowWorkLifecycle {
67
+ onModuleInit() {
68
+ // The shared client is also used by EditorPlugin; only start it if
69
+ // nothing else has.
70
+ if (!matrixClient.clientRunning) {
71
+ void matrixClient.startClient();
72
+ }
73
+ listener.start();
74
+ }
75
+ onModuleDestroy() {
76
+ listener.stop();
77
+ }
78
+ }
79
+ let FlowWorkModule = class FlowWorkModule {
80
+ };
81
+ FlowWorkModule = __decorate([
82
+ Module({ providers: [FlowWorkLifecycle] })
83
+ ], FlowWorkModule);
84
+ return [
85
+ {
86
+ module: FlowWorkModule,
87
+ providers: [FlowWorkLifecycle],
88
+ },
89
+ ];
90
+ }
91
+ }
92
+ //# sourceMappingURL=flow-work.plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-work.plugin.js","sourceRoot":"","sources":["../src/flow-work.plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { FlowWorkPlugin, type FlowWorkPluginOptions, } from './flow-work.plugin.js';
2
+ export { findCapability, type FlowWorkCapability } from './capability.js';
3
+ export { FlowWorkListener, homeserverOf } from './listener.js';
4
+ export { adaptMatrixClient, type FlowWorkMatrixPort } from './matrix-port.js';
5
+ export { FLOW_WORK_ASSIGN_EVENT, FLOW_WORK_INVOKE_EVENT, FLOW_WORK_RECEIPT_EVENT, flowWorkInvokeSchema, type FlowWorkErrorCode, type FlowWorkInvoke, type FlowWorkReceipt, } from './protocol.js';
6
+ export { buildDelegationValidator, type DelegationValidator } from './ucan.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,wBAAwB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { FlowWorkPlugin, } from './flow-work.plugin.js';
2
+ export { findCapability } from './capability.js';
3
+ export { FlowWorkListener, homeserverOf } from './listener.js';
4
+ export { adaptMatrixClient } from './matrix-port.js';
5
+ export { FLOW_WORK_ASSIGN_EVENT, FLOW_WORK_INVOKE_EVENT, FLOW_WORK_RECEIPT_EVENT, flowWorkInvokeSchema, } from './protocol.js';
6
+ export { buildDelegationValidator } from './ucan.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAA2B,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAA2B,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,GAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,wBAAwB,EAA4B,MAAM,WAAW,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { type FlowWorkCapability } from './capability.js';
2
+ import type { FlowWorkMatrixPort } from './matrix-port.js';
3
+ import type { DelegationValidator } from './ucan.js';
4
+ export interface FlowWorkLogger {
5
+ log(message: string): void;
6
+ warn(message: string): void;
7
+ error(message: string): void;
8
+ }
9
+ export interface FlowWorkListenerOptions {
10
+ port: FlowWorkMatrixPort;
11
+ /** This oracle's DID — invocations addressed elsewhere are ignored. */
12
+ oracleDid: string;
13
+ /** Homeserver domains whose room invites are accepted. */
14
+ trustedHomeservers: readonly string[];
15
+ capabilities: readonly FlowWorkCapability[];
16
+ validateDelegation: DelegationValidator;
17
+ logger: FlowWorkLogger;
18
+ /** How many recent room events to scan for an existing receipt. */
19
+ receiptScanLimit?: number;
20
+ }
21
+ /** Hostname of '@user:server.tld' or a bare/prefixed server name. */
22
+ export declare function homeserverOf(value: string): string | null;
23
+ /**
24
+ * The oracle side of the flow-work contract: accepts invites from trusted
25
+ * homeservers, executes UCAN-authorized `ixo.flow.work.invoke` events via
26
+ * the declared capability handlers, and posts `ixo.flow.work.receipt`s.
27
+ */
28
+ export declare class FlowWorkListener {
29
+ private readonly options;
30
+ private readonly trusted;
31
+ private readonly active;
32
+ private readonly completed;
33
+ private unsubscribe;
34
+ constructor(options: FlowWorkListenerOptions);
35
+ start(): void;
36
+ stop(): void;
37
+ private handleInvite;
38
+ private handleRoomEvent;
39
+ /**
40
+ * Bind nb caveats to the invocation before executing. A delegation minted
41
+ * for one claim schema must not be reusable with unrelated claim data:
42
+ * `nb.claimSchema` requires the invocation's `inputs.claimSchemaId` to be
43
+ * present and equal.
44
+ */
45
+ private enforceCaveats;
46
+ private execute;
47
+ private hasExistingReceipt;
48
+ private postFailure;
49
+ private postReceipt;
50
+ }
51
+ //# sourceMappingURL=listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAS1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,CAAC;IACzB,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC5C,kBAAkB,EAAE,mBAAmB,CAAC;IACxC,MAAM,EAAE,cAAc,CAAC;IACvB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAYD,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBzD;AAMD;;;;GAIG;AACH,qBAAa,gBAAgB;IAMf,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,WAAW,CAAyB;gBAEf,OAAO,EAAE,uBAAuB;IAa7D,KAAK,IAAI,IAAI;IAuBb,IAAI,IAAI,IAAI;YAKE,YAAY;YAcZ,eAAe;IAgE7B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;YAiBR,OAAO;IAqDrB,OAAO,CAAC,kBAAkB;YAYZ,WAAW;YAcX,WAAW;CAQ1B"}
@@ -0,0 +1,226 @@
1
+ import { findCapability } from './capability.js';
2
+ import { FLOW_WORK_INVOKE_EVENT, FLOW_WORK_RECEIPT_EVENT, flowWorkInvokeSchema, } from './protocol.js';
3
+ class FlowWorkFailure extends Error {
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.code = code;
8
+ this.name = 'FlowWorkFailure';
9
+ }
10
+ }
11
+ /** Hostname of '@user:server.tld' or a bare/prefixed server name. */
12
+ export function homeserverOf(value) {
13
+ let candidate = value.trim().toLowerCase();
14
+ if (candidate.startsWith('@')) {
15
+ const separator = candidate.indexOf(':');
16
+ if (separator < 0)
17
+ return null;
18
+ candidate = candidate.slice(separator + 1);
19
+ }
20
+ if (candidate === '')
21
+ return null;
22
+ try {
23
+ return new URL(candidate.includes('://') ? candidate : `matrix://${candidate}`).hostname
24
+ .replace(/\.$/, '')
25
+ .toLowerCase();
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function isRecord(value) {
32
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
33
+ }
34
+ /**
35
+ * The oracle side of the flow-work contract: accepts invites from trusted
36
+ * homeservers, executes UCAN-authorized `ixo.flow.work.invoke` events via
37
+ * the declared capability handlers, and posts `ixo.flow.work.receipt`s.
38
+ */
39
+ export class FlowWorkListener {
40
+ options;
41
+ trusted;
42
+ active = new Set();
43
+ completed = new Set();
44
+ unsubscribe = [];
45
+ constructor(options) {
46
+ this.options = options;
47
+ const trusted = options.trustedHomeservers
48
+ .map(homeserverOf)
49
+ .filter((value) => value !== null);
50
+ this.trusted = new Set(trusted);
51
+ if (this.trusted.size === 0) {
52
+ throw new Error('flow-work has no valid trusted homeserver domains');
53
+ }
54
+ if (options.capabilities.length === 0) {
55
+ throw new Error('flow-work has no declared capabilities');
56
+ }
57
+ }
58
+ start() {
59
+ const { port, logger } = this.options;
60
+ this.unsubscribe = [
61
+ port.onInvite((invite) => {
62
+ void this.handleInvite(invite).catch((error) => {
63
+ logger.error(`[flow-work] invite handling failed: ${message(error)}`);
64
+ });
65
+ }),
66
+ port.onRoomEvent((event) => {
67
+ void this.handleRoomEvent(event).catch((error) => {
68
+ logger.error(`[flow-work] event handling failed in ${event.roomId}: ${message(error)}`);
69
+ });
70
+ }),
71
+ ];
72
+ logger.log(`[flow-work] listening — capabilities: ${this.options.capabilities
73
+ .map((entry) => `${entry.can}#${entry.actionType}`)
74
+ .join(', ')}`);
75
+ }
76
+ stop() {
77
+ for (const off of this.unsubscribe)
78
+ off();
79
+ this.unsubscribe = [];
80
+ }
81
+ async handleInvite(invite) {
82
+ const host = homeserverOf(invite.inviterUserId);
83
+ if (!host || !this.trusted.has(host)) {
84
+ this.options.logger.warn(`[flow-work] rejected invite to ${invite.roomId} from untrusted sender ${invite.inviterUserId}`);
85
+ return;
86
+ }
87
+ await this.options.port.joinRoom(invite.roomId);
88
+ this.options.logger.log(`[flow-work] joined ${invite.roomId} (invited by ${invite.inviterUserId})`);
89
+ }
90
+ async handleRoomEvent(event) {
91
+ if (event.type !== FLOW_WORK_INVOKE_EVENT || !isRecord(event.content)) {
92
+ return;
93
+ }
94
+ if (event.content.audience !== this.options.oracleDid)
95
+ return;
96
+ const rawId = event.content.invocationId;
97
+ if (typeof rawId !== 'string' || rawId.trim() === '')
98
+ return;
99
+ const invocationId = rawId.trim();
100
+ const key = `${event.roomId}:${invocationId}`;
101
+ if (this.active.has(key) || this.completed.has(key))
102
+ return;
103
+ this.active.add(key);
104
+ let receiptPosted = false;
105
+ try {
106
+ if (this.hasExistingReceipt(event.roomId, invocationId)) {
107
+ this.completed.add(key);
108
+ return;
109
+ }
110
+ const parsed = flowWorkInvokeSchema.safeParse(event.content);
111
+ if (!parsed.success) {
112
+ await this.postFailure(event.roomId, invocationId, 'input_invalid', parsed.error.issues
113
+ .map((issue) => `${issue.path.join('.')}: ${issue.message}`)
114
+ .join('; '));
115
+ receiptPosted = true;
116
+ this.completed.add(key);
117
+ return;
118
+ }
119
+ const receipt = await this.execute(parsed.data);
120
+ await this.postReceipt(event.roomId, receipt);
121
+ receiptPosted = true;
122
+ this.completed.add(key);
123
+ }
124
+ catch (error) {
125
+ const failure = error instanceof FlowWorkFailure
126
+ ? error
127
+ : new FlowWorkFailure('tool_error', message(error));
128
+ try {
129
+ await this.postFailure(event.roomId, invocationId, failure.code, failure.message);
130
+ receiptPosted = true;
131
+ this.completed.add(key);
132
+ }
133
+ catch (postError) {
134
+ this.options.logger.error(`[flow-work] failed to post receipt for ${invocationId}: ${message(postError)}`);
135
+ }
136
+ }
137
+ finally {
138
+ this.active.delete(key);
139
+ if (!receiptPosted)
140
+ this.completed.delete(key);
141
+ }
142
+ }
143
+ /**
144
+ * Bind nb caveats to the invocation before executing. A delegation minted
145
+ * for one claim schema must not be reusable with unrelated claim data:
146
+ * `nb.claimSchema` requires the invocation's `inputs.claimSchemaId` to be
147
+ * present and equal.
148
+ */
149
+ enforceCaveats(nb, invoke) {
150
+ const claimSchema = nb?.claimSchema;
151
+ if (typeof claimSchema !== 'string' || claimSchema === '')
152
+ return;
153
+ const provided = invoke.inputs.claimSchemaId;
154
+ if (provided !== claimSchema) {
155
+ throw new FlowWorkFailure('delegation_invalid', `Delegation is caveated to claim schema '${claimSchema}' but the invocation carries '${typeof provided === 'string' ? provided : 'none'}'.`);
156
+ }
157
+ }
158
+ async execute(invoke) {
159
+ const capability = findCapability(this.options.capabilities, invoke.capability, invoke.actionType);
160
+ if (!capability) {
161
+ throw new FlowWorkFailure('capability_not_declared', `Capability '${invoke.capability}' with actionType '${invoke.actionType}' is not declared by this oracle.`);
162
+ }
163
+ const validation = await this.options.validateDelegation(invoke.delegation);
164
+ if (!validation.ok) {
165
+ throw new FlowWorkFailure(validation.code, validation.message);
166
+ }
167
+ if (validation.capability &&
168
+ validation.capability.can !== invoke.capability) {
169
+ throw new FlowWorkFailure('delegation_invalid', `Delegation grants '${validation.capability.can}', not '${invoke.capability}'.`);
170
+ }
171
+ this.enforceCaveats(validation.capability?.nb, invoke);
172
+ const inputs = capability.inputSchema.safeParse(invoke.inputs);
173
+ if (!inputs.success) {
174
+ throw new FlowWorkFailure('input_invalid', inputs.error.issues
175
+ .map((issue) => `${issue.path.join('.')}: ${issue.message}`)
176
+ .join('; '));
177
+ }
178
+ let output;
179
+ try {
180
+ output = await capability.handler(inputs.data);
181
+ }
182
+ catch (error) {
183
+ throw new FlowWorkFailure('tool_error', message(error));
184
+ }
185
+ return {
186
+ invocationId: invoke.invocationId,
187
+ status: 'success',
188
+ output: toReceiptOutput(output),
189
+ error: null,
190
+ };
191
+ }
192
+ hasExistingReceipt(roomId, invocationId) {
193
+ const limit = this.options.receiptScanLimit ?? 100;
194
+ return this.options.port
195
+ .recentEvents(roomId, limit)
196
+ .some((event) => event.type === FLOW_WORK_RECEIPT_EVENT &&
197
+ isRecord(event.content) &&
198
+ event.content.invocationId === invocationId);
199
+ }
200
+ async postFailure(roomId, invocationId, code, errorMessage) {
201
+ await this.postReceipt(roomId, {
202
+ invocationId,
203
+ status: 'failure',
204
+ output: null,
205
+ error: { code, message: errorMessage },
206
+ });
207
+ }
208
+ async postReceipt(roomId, receipt) {
209
+ await this.options.port.sendEvent(roomId, FLOW_WORK_RECEIPT_EVENT, {
210
+ ...receipt,
211
+ });
212
+ }
213
+ }
214
+ function toReceiptOutput(value) {
215
+ if (value === null || value === undefined)
216
+ return null;
217
+ const json = JSON.stringify(value);
218
+ if (json === undefined)
219
+ return { value: null };
220
+ const serializable = JSON.parse(json);
221
+ return isRecord(serializable) ? serializable : { value: serializable };
222
+ }
223
+ function message(error) {
224
+ return error instanceof Error ? error.message : String(error);
225
+ }
226
+ //# sourceMappingURL=listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener.js","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type * as sdk from 'matrix-js-sdk';
2
+ /**
3
+ * The narrow slice of Matrix the flow-work listener needs. The listener
4
+ * depends on this port, not on matrix-js-sdk — production wraps the real
5
+ * client (adaptMatrixClient), tests provide an in-memory implementation.
6
+ */
7
+ declare module 'matrix-js-sdk' {
8
+ interface TimelineEvents {
9
+ [key: `ixo.flow.work.${string}`]: Record<string, unknown>;
10
+ }
11
+ }
12
+ export interface FlowWorkRoomEvent {
13
+ roomId: string;
14
+ type: string;
15
+ content: unknown;
16
+ sender?: string;
17
+ }
18
+ export interface FlowWorkInvite {
19
+ roomId: string;
20
+ inviterUserId: string;
21
+ }
22
+ export interface FlowWorkMatrixPort {
23
+ /** Register an invite handler. Returns an unsubscribe function. */
24
+ onInvite(handler: (invite: FlowWorkInvite) => void): () => void;
25
+ /** Register a room-event handler (decrypted where applicable). Returns unsubscribe. */
26
+ onRoomEvent(handler: (event: FlowWorkRoomEvent) => void): () => void;
27
+ joinRoom(roomId: string): Promise<void>;
28
+ sendEvent(roomId: string, type: `ixo.flow.work.${string}`, content: Record<string, unknown>): Promise<void>;
29
+ /** Most recent events in a room, newest first — used for receipt replay checks. */
30
+ recentEvents(roomId: string, limit: number): FlowWorkRoomEvent[];
31
+ }
32
+ /** Wrap a live matrix-js-sdk client in the port interface. */
33
+ export declare function adaptMatrixClient(client: sdk.MatrixClient): FlowWorkMatrixPort;
34
+ //# sourceMappingURL=matrix-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix-port.d.ts","sourceRoot":"","sources":["../src/matrix-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,eAAe,CAAC;AAE1C;;;;GAIG;AAIH,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,cAAc;QACtB,CAAC,GAAG,EAAE,iBAAiB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC3D;CACF;AAID,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAChE,uFAAuF;IACvF,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CACP,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,iBAAiB,MAAM,EAAE,EAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,mFAAmF;IACnF,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAC;CAClE;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,GAAG,CAAC,YAAY,GACvB,kBAAkB,CAmFpB"}
@@ -0,0 +1,63 @@
1
+ /** Wrap a live matrix-js-sdk client in the port interface. */
2
+ export function adaptMatrixClient(client) {
3
+ return {
4
+ onInvite(handler) {
5
+ const membershipHandler = (event, member) => {
6
+ if (member.membership === 'invite' &&
7
+ member.userId === client.getUserId()) {
8
+ handler({
9
+ roomId: member.roomId,
10
+ inviterUserId: event.getSender() ?? '',
11
+ });
12
+ }
13
+ };
14
+ client.on('RoomMember.membership', membershipHandler);
15
+ return () => client.removeListener('RoomMember.membership', membershipHandler);
16
+ },
17
+ onRoomEvent(handler) {
18
+ const emit = (event) => {
19
+ const roomId = event.getRoomId();
20
+ if (!roomId || event.isEncrypted())
21
+ return;
22
+ handler({
23
+ roomId,
24
+ type: event.getType(),
25
+ content: event.getContent(),
26
+ sender: event.getSender(),
27
+ });
28
+ };
29
+ const timelineHandler = (event) => emit(event);
30
+ // Encrypted rooms surface events again once decrypted.
31
+ const decryptedHandler = (event) => emit(event);
32
+ client.on('Room.timeline', timelineHandler);
33
+ client.on('Event.decrypted', decryptedHandler);
34
+ return () => {
35
+ client.removeListener('Room.timeline', timelineHandler);
36
+ client.removeListener('Event.decrypted', decryptedHandler);
37
+ };
38
+ },
39
+ async joinRoom(roomId) {
40
+ await client.joinRoom(roomId);
41
+ },
42
+ async sendEvent(roomId, type, content) {
43
+ await client.sendEvent(roomId, type, content);
44
+ },
45
+ recentEvents(roomId, limit) {
46
+ const room = client.getRoom(roomId);
47
+ if (!room)
48
+ return [];
49
+ return room
50
+ .getLiveTimeline()
51
+ .getEvents()
52
+ .slice(-limit)
53
+ .reverse()
54
+ .map((event) => ({
55
+ roomId,
56
+ type: event.getType(),
57
+ content: event.getContent(),
58
+ sender: event.getSender(),
59
+ }));
60
+ },
61
+ };
62
+ }
63
+ //# sourceMappingURL=matrix-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix-port.js","sourceRoot":"","sources":["../src/matrix-port.ts"],"names":[],"mappings":"AA6CA,8DAA8D;AAC9D,MAAM,UAAU,iBAAiB,CAC/B,MAAwB;IAExB,OAAO;QACL,QAAQ,CAAC,OAAO;YACd,MAAM,iBAAiB,GAAG,CACxB,KAAsB,EACtB,MAAsB,EAChB,EAAE;gBACR,IACE,MAAM,CAAC,UAAU,KAAK,QAAQ;oBAC9B,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,SAAS,EAAE,EACpC,CAAC;oBACD,OAAO,CAAC;wBACN,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,aAAa,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE;qBACvC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC;YACF,MAAM,CAAC,EAAE,CACP,uBAAyD,EACzD,iBAAiB,CAClB,CAAC;YACF,OAAO,GAAG,EAAE,CACV,MAAM,CAAC,cAAc,CACnB,uBAAyD,EACzD,iBAAiB,CAClB,CAAC;QACN,CAAC;QAED,WAAW,CAAC,OAAO;YACjB,MAAM,IAAI,GAAG,CAAC,KAAsB,EAAQ,EAAE;gBAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE;oBAAE,OAAO;gBAC3C,OAAO,CAAC;oBACN,MAAM;oBACN,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE;oBACrB,OAAO,EAAE,KAAK,CAAC,UAAU,EAAE;oBAC3B,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE;iBAC1B,CAAC,CAAC;YACL,CAAC,CAAC;YACF,MAAM,eAAe,GAAG,CAAC,KAAsB,EAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtE,uDAAuD;YACvD,MAAM,gBAAgB,GAAG,CAAC,KAAsB,EAAQ,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,CAAC,EAAE,CAAC,eAAyC,EAAE,eAAe,CAAC,CAAC;YACtE,MAAM,CAAC,EAAE,CACP,iBAAmD,EACnD,gBAAgB,CACjB,CAAC;YACF,OAAO,GAAG,EAAE;gBACV,MAAM,CAAC,cAAc,CACnB,eAAyC,EACzC,eAAe,CAChB,CAAC;gBACF,MAAM,CAAC,cAAc,CACnB,iBAAmD,EACnD,gBAAgB,CACjB,CAAC;YACJ,CAAC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,MAAM;YACnB,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,IAAuB,EAAE,OAAO;YACtD,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QAED,YAAY,CAAC,MAAM,EAAE,KAAK;YACxB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI;gBAAE,OAAO,EAAE,CAAC;YACrB,OAAO,IAAI;iBACR,eAAe,EAAE;iBACjB,SAAS,EAAE;iBACX,KAAK,CAAC,CAAC,KAAK,CAAC;iBACb,OAAO,EAAE;iBACT,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACf,MAAM;gBACN,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE;gBACrB,OAAO,EAAE,KAAK,CAAC,UAAU,EAAE;gBAC3B,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE;aAC1B,CAAC,CAAC,CAAC;QACR,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ 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
+ */
9
+ export declare const FLOW_WORK_ASSIGN_EVENT = "ixo.flow.work.assign";
10
+ export declare const FLOW_WORK_INVOKE_EVENT = "ixo.flow.work.invoke";
11
+ export declare const FLOW_WORK_RECEIPT_EVENT = "ixo.flow.work.receipt";
12
+ export declare const flowWorkInvokeSchema: z.ZodObject<{
13
+ invocationId: z.ZodString;
14
+ capability: z.ZodString;
15
+ actionType: z.ZodString;
16
+ nodeId: z.ZodString;
17
+ inputs: z.ZodRecord<z.ZodString, z.ZodUnknown>;
18
+ delegation: z.ZodString;
19
+ audience: z.ZodString;
20
+ }, z.core.$strip>;
21
+ export type FlowWorkInvoke = z.infer<typeof flowWorkInvokeSchema>;
22
+ export type FlowWorkErrorCode = 'delegation_invalid' | 'delegation_expired' | 'capability_not_declared' | 'input_invalid' | 'tool_error';
23
+ export interface FlowWorkReceipt {
24
+ invocationId: string;
25
+ status: 'success' | 'failure';
26
+ output: Record<string, unknown> | null;
27
+ error: {
28
+ code: FlowWorkErrorCode;
29
+ message: string;
30
+ } | null;
31
+ }
32
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AAEH,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAC7D,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAC7D,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,eAAO,MAAM,oBAAoB;;;;;;;;iBAU/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,MAAM,MAAM,iBAAiB,GACzB,oBAAoB,GACpB,oBAAoB,GACpB,yBAAyB,GACzB,eAAe,GACf,YAAY,CAAC;AAEjB,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACvC,KAAK,EAAE;QAAE,IAAI,EAAE,iBAAiB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC5D"}
@@ -0,0 +1,23 @@
1
+ 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
+ */
9
+ export const FLOW_WORK_ASSIGN_EVENT = 'ixo.flow.work.assign';
10
+ export const FLOW_WORK_INVOKE_EVENT = 'ixo.flow.work.invoke';
11
+ 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),
17
+ inputs: z.record(z.string(), z.unknown()),
18
+ /** 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
+ });
23
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +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"}
package/dist/ucan.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * UCAN delegation validation for contracted work — same checks the runtime
3
+ * applies to HTTP requests (audience match, chain expiry, signature chain),
4
+ * built from the published @ixo/ucan package.
5
+ */
6
+ export type DelegationOutcome = {
7
+ ok: true;
8
+ invokerDid: string;
9
+ /**
10
+ * The capability carried by the delegation, including its nb caveats
11
+ * (e.g. the claimSchema a service contract is pinned to). Note:
12
+ * @ixo/ucan's ValidateResult surfaces a single capability — delegations
13
+ * carrying additional capabilities (e.g. supplementary read grants)
14
+ * need upstream validator support before they can be enumerated here.
15
+ */
16
+ capability?: {
17
+ can: string;
18
+ with: string;
19
+ nb?: Record<string, unknown>;
20
+ };
21
+ expiration?: number;
22
+ } | {
23
+ ok: false;
24
+ code: 'delegation_expired' | 'delegation_invalid';
25
+ message: string;
26
+ };
27
+ export type DelegationValidator = (serializedDelegation: string) => Promise<DelegationOutcome>;
28
+ export declare function buildDelegationValidator(options: {
29
+ /** This oracle's DID — the expected delegation audience. */
30
+ oracleDid: string;
31
+ /** Blocksync GraphQL endpoint for did:ixo key resolution. Optional: did:key verifies locally. */
32
+ blocksyncUrl?: string;
33
+ }): DelegationValidator;
34
+ //# sourceMappingURL=ucan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ucan.d.ts","sourceRoot":"","sources":["../src/ucan.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,MAAM,iBAAiB,GACzB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,oBAAoB,GAAG,oBAAoB,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAAG,CAChC,oBAAoB,EAAE,MAAM,KACzB,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEhC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,mBAAmB,CA8CtB"}
package/dist/ucan.js ADDED
@@ -0,0 +1,43 @@
1
+ import { createIxoDIDResolver, createUCANValidator } from '@ixo/ucan';
2
+ export function buildDelegationValidator(options) {
3
+ const validatorPromise = createUCANValidator({
4
+ serverDid: options.oracleDid,
5
+ rootIssuers: [],
6
+ ...(options.blocksyncUrl
7
+ ? {
8
+ didResolver: createIxoDIDResolver({
9
+ indexerUrl: options.blocksyncUrl,
10
+ }),
11
+ }
12
+ : {}),
13
+ });
14
+ return async (serializedDelegation) => {
15
+ const validator = await validatorPromise;
16
+ const result = await validator.validateDelegation(serializedDelegation);
17
+ if (!result.ok) {
18
+ const code = result.error?.code === 'EXPIRED'
19
+ ? 'delegation_expired'
20
+ : 'delegation_invalid';
21
+ return {
22
+ ok: false,
23
+ code,
24
+ message: `[${result.error?.code ?? 'UNKNOWN'}] ${result.error?.message ?? 'delegation validation failed'}`,
25
+ };
26
+ }
27
+ if (!result.invoker) {
28
+ return {
29
+ ok: false,
30
+ code: 'delegation_invalid',
31
+ message: 'Delegation validated without an invoker DID',
32
+ };
33
+ }
34
+ const capability = result.capability;
35
+ return {
36
+ ok: true,
37
+ invokerDid: result.invoker,
38
+ capability,
39
+ expiration: result.expiration,
40
+ };
41
+ };
42
+ }
43
+ //# sourceMappingURL=ucan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ucan.js","sourceRoot":"","sources":["../src/ucan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAgCtE,MAAM,UAAU,wBAAwB,CAAC,OAKxC;IACC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;QAC3C,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,WAAW,EAAE,EAAE;QACf,GAAG,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC;gBACE,WAAW,EAAE,oBAAoB,CAAC;oBAChC,UAAU,EAAE,OAAO,CAAC,YAAY;iBACjC,CAAC;aACH;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;IAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,EAAE;QACpC,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;QAExE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,GACR,MAAM,CAAC,KAAK,EAAE,IAAI,KAAK,SAAS;gBAC9B,CAAC,CAAC,oBAAoB;gBACtB,CAAC,CAAC,oBAAoB,CAAC;YAC3B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI;gBACJ,OAAO,EAAE,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,8BAA8B,EAAE;aAC3G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,oBAAoB;gBAC1B,OAAO,EAAE,6CAA6C;aACvD,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAEb,CAAC;QACd,OAAO;YACL,EAAE,EAAE,IAAI;YACR,UAAU,EAAE,MAAM,CAAC,OAAO;YAC1B,UAAU;YACV,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@ixo/flow-work",
3
+ "version": "0.1.0",
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
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/ixoworld/flow-manager-oracle.git",
24
+ "directory": "packages/flow-work"
25
+ },
26
+ "engines": {
27
+ "node": ">=22"
28
+ },
29
+ "dependencies": {
30
+ "zod": "^4.4.3"
31
+ },
32
+ "peerDependencies": {
33
+ "@ixo/oracle-runtime": ">=1.3.4",
34
+ "@ixo/ucan": ">=2.0.0",
35
+ "@nestjs/common": ">=11.0.0",
36
+ "matrix-js-sdk": ">=37.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@changesets/cli": "^2.31.0",
40
+ "@ixo/oracle-runtime": "^1.3.4",
41
+ "@ixo/ucan": "^2.0.0",
42
+ "@nestjs/common": "^11.1.19",
43
+ "@types/node": "^22.10.7",
44
+ "matrix-js-sdk": "^37.11.0",
45
+ "typescript": "^5.7.3",
46
+ "vitest": "^3.2.4"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc -p tsconfig.build.json",
50
+ "typecheck": "tsc -p tsconfig.build.json --noEmit",
51
+ "test": "vitest run",
52
+ "changeset": "changeset",
53
+ "version": "changeset version",
54
+ "release": "changeset publish"
55
+ }
56
+ }