@multiagency/sdk 0.3.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.
Files changed (78) hide show
  1. package/CHANGES.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -0
  4. package/THIRD-PARTY-NOTICES +127 -0
  5. package/bin/release-server.d.mts +29 -0
  6. package/bin/release-server.mjs +143 -0
  7. package/dist/compensation-contract.d.ts +370 -0
  8. package/dist/compensation-contract.js +51 -0
  9. package/dist/contract/agent-connection.d.ts +86 -0
  10. package/dist/contract/agent-connection.js +36 -0
  11. package/dist/contract/app-access.d.ts +141 -0
  12. package/dist/contract/app-access.js +57 -0
  13. package/dist/contract/app-client.d.ts +140 -0
  14. package/dist/contract/app-client.js +61 -0
  15. package/dist/contract/app-consent.d.ts +68 -0
  16. package/dist/contract/app-consent.js +91 -0
  17. package/dist/contract/assets.d.ts +6 -0
  18. package/dist/contract/assets.js +6 -0
  19. package/dist/contract/client.d.ts +347 -0
  20. package/dist/contract/client.js +81 -0
  21. package/dist/contract/gateway.d.ts +74 -0
  22. package/dist/contract/gateway.js +47 -0
  23. package/dist/contract/index.d.ts +26 -0
  24. package/dist/contract/index.js +25 -0
  25. package/dist/contract/inputs.d.ts +230 -0
  26. package/dist/contract/inputs.js +99 -0
  27. package/dist/contract/intents-account.d.ts +5 -0
  28. package/dist/contract/intents-account.js +8 -0
  29. package/dist/contract/orpc-client.js +2037 -0
  30. package/dist/contract/owner-capabilities.d.ts +81 -0
  31. package/dist/contract/owner-capabilities.js +33 -0
  32. package/dist/contract/owner-client.d.ts +99 -0
  33. package/dist/contract/owner-client.js +146 -0
  34. package/dist/contract/owner-contract.d.ts +1156 -0
  35. package/dist/contract/owner-contract.js +37 -0
  36. package/dist/contract/owner-inputs.d.ts +166 -0
  37. package/dist/contract/owner-inputs.js +1 -0
  38. package/dist/contract/owner-outputs.d.ts +5749 -0
  39. package/dist/contract/owner-outputs.js +751 -0
  40. package/dist/contract/package-version.d.ts +5 -0
  41. package/dist/contract/package-version.js +2 -0
  42. package/dist/contract/payee-entry.d.ts +10 -0
  43. package/dist/contract/payee-entry.js +10 -0
  44. package/dist/contract/payee.d.ts +326 -0
  45. package/dist/contract/payee.js +32 -0
  46. package/dist/contract/permissions.d.ts +20 -0
  47. package/dist/contract/permissions.js +64 -0
  48. package/dist/contract/proposals.d.ts +178 -0
  49. package/dist/contract/proposals.js +27 -0
  50. package/dist/contract/run-log-schema.d.ts +888 -0
  51. package/dist/contract/run-log-schema.js +150 -0
  52. package/dist/contract/run-progress-schema.d.ts +104 -0
  53. package/dist/contract/run-progress-schema.js +20 -0
  54. package/dist/payee-contract.d.ts +9 -0
  55. package/dist/payee-contract.js +15 -0
  56. package/package.json +58 -0
  57. package/provenance.json +61 -0
  58. package/schemas/agentConnection.json +76 -0
  59. package/schemas/agentConnectionIssue.json +22 -0
  60. package/schemas/agentConnectionList.json +88 -0
  61. package/schemas/agentConnectionStarted.json +90 -0
  62. package/schemas/compensationSend.json +40 -0
  63. package/schemas/errorBody.json +16 -0
  64. package/schemas/fileResult.json +67 -0
  65. package/schemas/invoicesView.json +130 -0
  66. package/schemas/ownerCompensationView.json +556 -0
  67. package/schemas/payeeCompensationView.json +546 -0
  68. package/schemas/payeeWorkOrderRequest.json +31 -0
  69. package/schemas/publicWorkOrder.json +94 -0
  70. package/schemas/reportCommand.json +82 -0
  71. package/schemas/requestRecord.json +149 -0
  72. package/schemas/session.json +20 -0
  73. package/schemas/workOrderList.json +43 -0
  74. package/schemas/workOrderRequestResult.json +20 -0
  75. package/skills/app-server/SKILL.md +190 -0
  76. package/skills/getting-started/SKILL.md +90 -0
  77. package/skills/owner-workflows/SKILL.md +157 -0
  78. package/skills/payee-workflows/SKILL.md +200 -0
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import { AppScope } from "./app-consent.js";
3
+ /**
4
+ * What an app deployment may do through `/apps/v1`: the gateway enforces with these same definitions, and
5
+ * the app client is typed by them. Presenting never authorizes.
6
+ */
7
+ /** Reads the app may make with `read` consent. Workflow records (agreements, invoices, work orders) stay out. */
8
+ export const APP_READS = ["instance", "overview", "policyHistory", "activity", "unresolved", "held", "ledger", "ledgerCsv",
9
+ "owner/actions", "owner/pending", "owner/status", "paymentHistory", "paymentStatus"];
10
+ /** Owner actions with `owner` consent: prepared here, completed only by the owner's own wallet signature at submit. */
11
+ export const APP_OWNER = ["owner/prepare", "owner/submit", "owner/status", "owner/pending", "owner/actions"];
12
+ /**
13
+ * Payout requests with `payout` consent: each sent at most once under the app's `requestId`, within the owner-signed
14
+ * policy, and held for the owner's vote when the policy says so. `held` shows what waits for that vote. `deposit` gives a
15
+ * one-time address that credits USDC, or wNEAR, to the agent's confidential balance, so the app can fund it; it moves
16
+ * nothing out.
17
+ */
18
+ export const APP_PAYOUT = ["payouts/request", "payouts/status", "held", "deposit"];
19
+ const READS = new Set(APP_READS), OWNER = new Set(APP_OWNER), PAYOUT = new Set(APP_PAYOUT);
20
+ /** Whether consent scopes cover a procedure (the gateway also requires the owner's own access to it). */
21
+ export const appScopesCover = (scopes, path) => (scopes.includes("read") && READS.has(path)) || (scopes.includes("owner") && OWNER.has(path)) || (scopes.includes("payout") && PAYOUT.has(path));
22
+ /**
23
+ * What the app may ask an owner to sign. The app chooses what it asks for, but never what the owner reads: a prepared
24
+ * intent reaches the app only when it is NEP-413, whose text the owner's wallet shows. A NEP-366 intent (creation,
25
+ * freeze, unfreeze, on-chain policy edits) is held on the platform, and the app gets a confirm page instead, where the
26
+ * platform shows the owner its own record of the action and the owner signs; the app gets those bytes only with the
27
+ * owner's signature over the link's text, which tells the owner in the wallet to sign it only on the platform. Payees are added after creation, not at it. A
28
+ * vote on a held payout is bound by the agent to that payout's provider evidence and re-authorized under the current
29
+ * policy, so it can release only a transfer to an agreed payee within the caps; its prepared answer carries the proven
30
+ * terms for the app to show.
31
+ */
32
+ const APP_OWNER_ACTIONS = new Set(["agent_create", "agent_freeze", "agent_unfreeze", "grant_issue", "grant_revoke", "policy_update", "approval_vote"]);
33
+ /** Whether a parsed owner action is one the app may prepare (signer `wallet` is checked separately). */
34
+ export function appMayAsk(action) {
35
+ if (action.type === "agent_create" && action.payees?.length)
36
+ return false;
37
+ return APP_OWNER_ACTIONS.has(action.type);
38
+ }
39
+ /**
40
+ * A NEP-366 owner action the platform holds for the owner to sign on its confirm page (`/confirm/<token>`). The link
41
+ * shows the action's terms to whoever holds it; the bytes to sign go only to whoever presents the owner's signature over
42
+ * the link's text, which the page asks the owner's wallet for. Open it for the owner right away: the intent expires in minutes. Follow the outcome with
43
+ * `owner/status`; the app can't submit it.
44
+ */
45
+ export const appConfirm = z.looseObject({ url: z.string(), expiresAt: z.string() });
46
+ /** `GET /apps/v1/agents/<agent>`: what the owner's consent must name. */
47
+ export const appAgent = z.looseObject({ agent: z.string(), owner: z.string(), agentId: z.string().nullable(), created: z.boolean(),
48
+ host: z.string(), deployment: z.string() });
49
+ /** A stored consent as the platform shows it: never its message, nonce or signature. Times are epoch milliseconds. */
50
+ export const appConsentView = z.looseObject({ id: z.string(), deployment: z.string(), host: z.string(), organization: z.string(),
51
+ owner: z.string(), agent: z.string(), agentId: z.string(), scopes: z.array(AppScope), expiresAt: z.number(), createdAt: z.number(),
52
+ publicKey: z.string(), revoked: z.boolean(), revokedAt: z.number().nullable() });
53
+ export const appConsentList = z.looseObject({ consents: z.array(appConsentView) });
54
+ export const appConsentStored = z.looseObject({ consent: appConsentView });
55
+ /** `POST /apps/v1/setup`: the hosted agent's name and its setup consent (agent ID `unborn`). */
56
+ export const appSetupStored = z.looseObject({ agent: z.string(), consent: appConsentView });
57
+ export const appRevoked = z.looseObject({ revoked: z.literal(true) });
@@ -0,0 +1,140 @@
1
+ import type { z } from "zod";
2
+ import { type AppOwnerAction, type AppProcedure } from "./app-access.js";
3
+ import type { appConsentSubmission } from "./app-consent.js";
4
+ import { type OwnerCallOptions, type OwnerOutput, type OwnerResult } from "./owner-client.js";
5
+ import type { OwnerInputs } from "./owner-inputs.js";
6
+ type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
7
+ export type AppBase = `https://${string}` | `http://${string}`;
8
+ export type AppConsentSubmission = z.input<typeof appConsentSubmission>;
9
+ /**
10
+ * An answer from the app routes (identity, setup, consents). Decided by status, never by message text.
11
+ * - `session` (401): the service credential is invalid, expired or revoked.
12
+ * - `forbidden` (403): refused for this caller (for example setup unavailable on this host, or a signer that doesn't own
13
+ * the agent). Resending the same request won't change it.
14
+ * - `refused`: the platform refused the request as made (400 invalid or revoked text, 404, 409 conflict, 429 limit).
15
+ * - `unavailable`: no answer, 5xx (503: an ownership or key check went unanswered, nothing stored or forwarded), or an
16
+ * unreadable one. Setup, consent submission and revocation are idempotent for the same signed body, so resending it is safe.
17
+ */
18
+ export type AppRouteResult<T> = {
19
+ ok: true;
20
+ value: T;
21
+ } | {
22
+ ok: false;
23
+ kind: "session";
24
+ status: 401;
25
+ error: string;
26
+ } | {
27
+ ok: false;
28
+ kind: "forbidden";
29
+ status: 403;
30
+ error: string;
31
+ } | {
32
+ ok: false;
33
+ kind: "refused";
34
+ status: number;
35
+ error: string;
36
+ } | {
37
+ ok: false;
38
+ kind: "unavailable";
39
+ httpStatus?: number;
40
+ };
41
+ /** Procedure inputs as an app may send them: `owner/prepare` takes only actions an app may ask an owner to sign. */
42
+ export type AppInputs = {
43
+ [P in AppProcedure]: P extends "owner/prepare" ? {
44
+ action: AppOwnerAction;
45
+ signer: "wallet";
46
+ } : OwnerInputs[P];
47
+ };
48
+ /**
49
+ * A server-side client for an app deployment's routes under `/apps/v1` on the platform host. It adds the deployment's
50
+ * service credential (a server secret: never give it to a browser). Agent calls go through `ownerClient`, with its result
51
+ * kinds; they are typed to what app consents can reach, and the gateway enforces the same lists.
52
+ */
53
+ export declare function appClient({ base, credential, fetch: send }: {
54
+ base: AppBase;
55
+ credential: string;
56
+ fetch?: Fetch;
57
+ }): {
58
+ /** The agent's owner and current provider ID (`agentId`, null until created): what a consent must name. */
59
+ identity: (agent: string) => Promise<AppRouteResult<{
60
+ [x: string]: unknown;
61
+ agent: string;
62
+ owner: string;
63
+ agentId: string | null;
64
+ created: boolean;
65
+ host: string;
66
+ deployment: string;
67
+ }>>;
68
+ /** A wallet owner's signed setup text: reserves the hosted agent and returns its setup consent. */
69
+ setup: (submission: AppConsentSubmission) => Promise<AppRouteResult<{
70
+ [x: string]: unknown;
71
+ agent: string;
72
+ consent: {
73
+ [x: string]: unknown;
74
+ id: string;
75
+ deployment: string;
76
+ host: string;
77
+ organization: string;
78
+ owner: string;
79
+ agent: string;
80
+ agentId: string;
81
+ scopes: ("owner" | "payout" | "read")[];
82
+ expiresAt: number;
83
+ createdAt: number;
84
+ publicKey: string;
85
+ revoked: boolean;
86
+ revokedAt: number | null;
87
+ };
88
+ }>>;
89
+ consents: {
90
+ list: (organization?: string) => Promise<AppRouteResult<{
91
+ [x: string]: unknown;
92
+ consents: {
93
+ [x: string]: unknown;
94
+ id: string;
95
+ deployment: string;
96
+ host: string;
97
+ organization: string;
98
+ owner: string;
99
+ agent: string;
100
+ agentId: string;
101
+ scopes: ("owner" | "payout" | "read")[];
102
+ expiresAt: number;
103
+ createdAt: number;
104
+ publicKey: string;
105
+ revoked: boolean;
106
+ revokedAt: number | null;
107
+ }[];
108
+ }>>;
109
+ submit: (submission: AppConsentSubmission) => Promise<AppRouteResult<{
110
+ [x: string]: unknown;
111
+ consent: {
112
+ [x: string]: unknown;
113
+ id: string;
114
+ deployment: string;
115
+ host: string;
116
+ organization: string;
117
+ owner: string;
118
+ agent: string;
119
+ agentId: string;
120
+ scopes: ("owner" | "payout" | "read")[];
121
+ expiresAt: number;
122
+ createdAt: number;
123
+ publicKey: string;
124
+ revoked: boolean;
125
+ revokedAt: number | null;
126
+ };
127
+ }>>;
128
+ /** Permanent: the owner signs a new consent to restore access. */
129
+ revoke: (id: string) => Promise<AppRouteResult<{
130
+ [x: string]: unknown;
131
+ revoked: true;
132
+ }>>;
133
+ };
134
+ /** One Organization's agent: reads and owner actions its live consents cover. */
135
+ agent(organization: string, agent: string): {
136
+ call<P extends AppProcedure>(path: P, ...[input, options]: undefined extends AppInputs[P] ? [input?: AppInputs[P], options?: OwnerCallOptions] : [input: AppInputs[P], options?: OwnerCallOptions]): Promise<OwnerResult<OwnerOutput<P>>>;
137
+ };
138
+ };
139
+ export type AppClient = ReturnType<typeof appClient>;
140
+ export {};
@@ -0,0 +1,61 @@
1
+ import { appAgent, appConsentList, appConsentStored, appRevoked, appSetupStored } from "./app-access.js";
2
+ import { ownerClient } from "./owner-client.js";
3
+ const covered = true;
4
+ void covered;
5
+ /**
6
+ * A server-side client for an app deployment's routes under `/apps/v1` on the platform host. It adds the deployment's
7
+ * service credential (a server secret: never give it to a browser). Agent calls go through `ownerClient`, with its result
8
+ * kinds; they are typed to what app consents can reach, and the gateway enforces the same lists.
9
+ */
10
+ export function appClient({ base, credential, fetch: send = globalThis.fetch }) {
11
+ const root = base.replace(/\/+$/, "");
12
+ const authorized = (input, init) => {
13
+ const headers = new Headers(init?.headers);
14
+ headers.set("authorization", `Bearer ${credential}`);
15
+ return send(input, { ...init, headers });
16
+ };
17
+ async function route(path, schema, init = {}) {
18
+ let response;
19
+ try {
20
+ response = await authorized(`${root}/apps/v1${path}`, init);
21
+ }
22
+ catch {
23
+ return { ok: false, kind: "unavailable" };
24
+ }
25
+ const body = await response.json().catch(() => undefined);
26
+ if (response.ok) {
27
+ const parsed = schema.safeParse(body);
28
+ return parsed.success ? { ok: true, value: parsed.data } : { ok: false, kind: "unavailable", httpStatus: response.status };
29
+ }
30
+ const error = typeof body?.error === "string" ? body.error : `HTTP ${response.status}`;
31
+ if (response.status === 401)
32
+ return { ok: false, kind: "session", status: 401, error };
33
+ if (response.status === 403)
34
+ return { ok: false, kind: "forbidden", status: 403, error };
35
+ if (response.status >= 400 && response.status < 500)
36
+ return { ok: false, kind: "refused", status: response.status, error };
37
+ return { ok: false, kind: "unavailable", httpStatus: response.status };
38
+ }
39
+ const post = (body) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
40
+ return {
41
+ /** The agent's owner and current provider ID (`agentId`, null until created): what a consent must name. */
42
+ identity: (agent) => route(`/agents/${encodeURIComponent(agent)}`, appAgent),
43
+ /** A wallet owner's signed setup text: reserves the hosted agent and returns its setup consent. */
44
+ setup: (submission) => route("/setup", appSetupStored, post(submission)),
45
+ consents: {
46
+ list: (organization) => route(`/consents${organization ? `?organization=${encodeURIComponent(organization)}` : ""}`, appConsentList),
47
+ submit: (submission) => route("/consents", appConsentStored, post(submission)),
48
+ /** Permanent: the owner signs a new consent to restore access. */
49
+ revoke: (id) => route(`/consents/${encodeURIComponent(id)}`, appRevoked, { method: "DELETE" }),
50
+ },
51
+ /** One Organization's agent: reads and owner actions its live consents cover. */
52
+ agent(organization, agent) {
53
+ const owner = ownerClient({ base: `${root}/apps/v1/o/${encodeURIComponent(organization)}/a/${encodeURIComponent(agent)}`, fetch: authorized });
54
+ return {
55
+ call(path, ...[input, options]) {
56
+ return owner.call(path, input, options);
57
+ },
58
+ };
59
+ },
60
+ };
61
+ }
@@ -0,0 +1,68 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * An agent owner's consent for one app deployment to act for one Organization on one agent: `read` for the listed
4
+ * reads, `owner` to prepare and submit owner actions that only the owner's own wallet signature completes.
5
+ * The owner signs `consentMessage(...)` with NEP-413, recipient the platform host. The platform accepts only the exact
6
+ * canonical text, so what was signed and what is stored are the same bytes.
7
+ */
8
+ export declare const APP_CONSENT_TYPE = "multiagency.app-consent";
9
+ export declare const AppScope: z.ZodEnum<{
10
+ owner: "owner";
11
+ payout: "payout";
12
+ read: "read";
13
+ }>;
14
+ export type AppScope = z.infer<typeof AppScope>;
15
+ /** Stands for an agent its server reports not created yet; only the platform's setup consent carries it, never a signed text. */
16
+ export declare const UNBORN_AGENT = "unborn";
17
+ export declare const appConsent: z.ZodObject<{
18
+ type: z.ZodLiteral<"multiagency.app-consent">;
19
+ version: z.ZodLiteral<1>;
20
+ host: z.ZodString;
21
+ deployment: z.ZodString;
22
+ organization: z.ZodString;
23
+ owner: z.ZodString;
24
+ agent: z.ZodString;
25
+ agentId: z.ZodString;
26
+ scopes: z.ZodArray<z.ZodEnum<{
27
+ owner: "owner";
28
+ payout: "payout";
29
+ read: "read";
30
+ }>>;
31
+ expiresAt: z.ZodISODateTime;
32
+ }, z.core.$strict>;
33
+ export type AppConsent = z.output<typeof appConsent>;
34
+ /** The canonical text to sign: fixed key order, sorted scopes, no whitespace. */
35
+ export declare function consentMessage(consent: Omit<AppConsent, "type" | "version">): string;
36
+ /** The consent a signed text states, or null unless the text is exactly its canonical form. */
37
+ export declare function parseConsentMessage(message: string): AppConsent | null;
38
+ /** What the app submits after the owner signs: the text, the NEP-413 nonce (32 bytes, base64) and the signature. */
39
+ export declare const appConsentSubmission: z.ZodObject<{
40
+ message: z.ZodString;
41
+ nonce: z.ZodString;
42
+ publicKey: z.ZodString;
43
+ signature: z.ZodString;
44
+ }, z.core.$strict>;
45
+ /**
46
+ * An agent owner's request, signed with NEP-413 like a consent, that the platform set up a hosted agent for this owner
47
+ * and area and let the app prepare its creation. It lasts at most an hour: it authorizes a setup, not ongoing
48
+ * access. Once the agent exists, the app asks for a consent naming its provider ID.
49
+ */
50
+ export declare const APP_SETUP_TYPE = "multiagency.app-setup";
51
+ export declare const appSetup: z.ZodObject<{
52
+ type: z.ZodLiteral<"multiagency.app-setup">;
53
+ version: z.ZodLiteral<1>;
54
+ host: z.ZodString;
55
+ deployment: z.ZodString;
56
+ organization: z.ZodString;
57
+ owner: z.ZodString;
58
+ area: z.ZodEnum<{
59
+ payables: "payables";
60
+ treasury: "treasury";
61
+ }>;
62
+ expiresAt: z.ZodISODateTime;
63
+ }, z.core.$strict>;
64
+ export type AppSetup = z.output<typeof appSetup>;
65
+ /** The canonical setup text to sign: fixed key order, no whitespace. */
66
+ export declare function setupMessage(setup: Omit<AppSetup, "type" | "version">): string;
67
+ /** The setup a signed text states, or null unless the text is exactly its canonical form. */
68
+ export declare function parseSetupMessage(message: string): AppSetup | null;
@@ -0,0 +1,91 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * An agent owner's consent for one app deployment to act for one Organization on one agent: `read` for the listed
4
+ * reads, `owner` to prepare and submit owner actions that only the owner's own wallet signature completes.
5
+ * The owner signs `consentMessage(...)` with NEP-413, recipient the platform host. The platform accepts only the exact
6
+ * canonical text, so what was signed and what is stored are the same bytes.
7
+ */
8
+ export const APP_CONSENT_TYPE = "multiagency.app-consent";
9
+ export const AppScope = z.enum(["owner", "payout", "read"]);
10
+ const name = z.string().regex(/^[a-z0-9-]{1,32}$/);
11
+ /** Stands for an agent its server reports not created yet; only the platform's setup consent carries it, never a signed text. */
12
+ export const UNBORN_AGENT = "unborn";
13
+ const account = z.string().min(2).max(64).regex(/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/);
14
+ export const appConsent = z.strictObject({
15
+ type: z.literal(APP_CONSENT_TYPE),
16
+ version: z.literal(1),
17
+ host: z.string().min(1).max(253).regex(/^[a-z0-9.-]+(?::\d{1,5})?$/),
18
+ deployment: name,
19
+ organization: z.string().regex(/^[A-Za-z0-9_-]{1,128}$/),
20
+ owner: account,
21
+ agent: name,
22
+ /** The agent's provider ID when the owner signs: a replacement agent under the same name isn't covered. */
23
+ agentId: z.string().min(1).max(128).refine(id => id !== UNBORN_AGENT, "Not an agent ID"),
24
+ scopes: z.array(AppScope).min(1).refine(values => new Set(values).size === values.length, "Scopes must be distinct"),
25
+ expiresAt: z.iso.datetime(),
26
+ });
27
+ /** The canonical text to sign: fixed key order, sorted scopes, no whitespace. */
28
+ export function consentMessage(consent) {
29
+ const value = appConsent.parse({ type: APP_CONSENT_TYPE, version: 1, ...consent });
30
+ return JSON.stringify({ type: value.type, version: value.version, host: value.host, deployment: value.deployment,
31
+ organization: value.organization, owner: value.owner, agent: value.agent, agentId: value.agentId, scopes: [...value.scopes].sort(), expiresAt: value.expiresAt });
32
+ }
33
+ /** The consent a signed text states, or null unless the text is exactly its canonical form. */
34
+ export function parseConsentMessage(message) {
35
+ let value;
36
+ try {
37
+ value = JSON.parse(message);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ const parsed = appConsent.safeParse(value);
43
+ if (!parsed.success)
44
+ return null;
45
+ const { type: _type, version: _version, ...fields } = parsed.data;
46
+ return consentMessage(fields) === message ? parsed.data : null;
47
+ }
48
+ /** What the app submits after the owner signs: the text, the NEP-413 nonce (32 bytes, base64) and the signature. */
49
+ export const appConsentSubmission = z.strictObject({
50
+ message: z.string().min(1).max(2_048),
51
+ nonce: z.string().min(1).max(64),
52
+ publicKey: z.string().regex(/^ed25519:[1-9A-HJ-NP-Za-km-z]{32,64}$/),
53
+ signature: z.string().min(1).max(200),
54
+ });
55
+ /**
56
+ * An agent owner's request, signed with NEP-413 like a consent, that the platform set up a hosted agent for this owner
57
+ * and area and let the app prepare its creation. It lasts at most an hour: it authorizes a setup, not ongoing
58
+ * access. Once the agent exists, the app asks for a consent naming its provider ID.
59
+ */
60
+ export const APP_SETUP_TYPE = "multiagency.app-setup";
61
+ export const appSetup = z.strictObject({
62
+ type: z.literal(APP_SETUP_TYPE),
63
+ version: z.literal(1),
64
+ host: appConsent.shape.host,
65
+ deployment: name,
66
+ organization: appConsent.shape.organization,
67
+ owner: account,
68
+ area: z.enum(["treasury", "payables"]),
69
+ expiresAt: z.iso.datetime(),
70
+ });
71
+ /** The canonical setup text to sign: fixed key order, no whitespace. */
72
+ export function setupMessage(setup) {
73
+ const value = appSetup.parse({ type: APP_SETUP_TYPE, version: 1, ...setup });
74
+ return JSON.stringify({ type: value.type, version: value.version, host: value.host, deployment: value.deployment,
75
+ organization: value.organization, owner: value.owner, area: value.area, expiresAt: value.expiresAt });
76
+ }
77
+ /** The setup a signed text states, or null unless the text is exactly its canonical form. */
78
+ export function parseSetupMessage(message) {
79
+ let value;
80
+ try {
81
+ value = JSON.parse(message);
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ const parsed = appSetup.safeParse(value);
87
+ if (!parsed.success)
88
+ return null;
89
+ const { type: _type, version: _version, ...fields } = parsed.data;
90
+ return setupMessage(fields) === message ? parsed.data : null;
91
+ }
@@ -0,0 +1,6 @@
1
+ /** Platform asset ids. Single source: the server's policy (src/policy.ts) re-exports these. */
2
+ export declare const ASSETS: {
3
+ readonly wNEAR: "nep141:wrap.near";
4
+ readonly USDC: "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1";
5
+ readonly ETH: "nep141:eth.omft.near";
6
+ };
@@ -0,0 +1,6 @@
1
+ /** Platform asset ids. Single source: the server's policy (src/policy.ts) re-exports these. */
2
+ export const ASSETS = {
3
+ wNEAR: "nep141:wrap.near",
4
+ USDC: "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
5
+ ETH: "nep141:eth.omft.near",
6
+ };