@aithos/sdk 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (66) hide show
  1. package/README.md +159 -0
  2. package/dist/src/auth-api.d.ts +105 -0
  3. package/dist/src/auth-api.js +178 -0
  4. package/dist/src/auth.d.ts +359 -68
  5. package/dist/src/auth.js +1035 -69
  6. package/dist/src/compute.d.ts +221 -9
  7. package/dist/src/compute.js +293 -16
  8. package/dist/src/data-schema-contacts-v1.d.ts +14 -0
  9. package/dist/src/data-schema-contacts-v1.js +28 -0
  10. package/dist/src/data.d.ts +97 -0
  11. package/dist/src/data.js +634 -0
  12. package/dist/src/endpoints.d.ts +9 -0
  13. package/dist/src/endpoints.js +5 -0
  14. package/dist/src/ethos.d.ts +202 -1
  15. package/dist/src/ethos.js +821 -16
  16. package/dist/src/index.d.ts +15 -6
  17. package/dist/src/index.js +36 -9
  18. package/dist/src/internal/delegate-bundle.d.ts +18 -0
  19. package/dist/src/internal/delegate-bundle.js +94 -0
  20. package/dist/src/internal/delegate-state.d.ts +45 -0
  21. package/dist/src/internal/delegate-state.js +120 -0
  22. package/dist/src/internal/owner-signers.d.ts +78 -0
  23. package/dist/src/internal/owner-signers.js +179 -0
  24. package/dist/src/internal/protocol-client-bridge.d.ts +8 -0
  25. package/dist/src/internal/protocol-client-bridge.js +20 -0
  26. package/dist/src/internal/recovery-file.d.ts +29 -0
  27. package/dist/src/internal/recovery-file.js +98 -0
  28. package/dist/src/internal/signer.d.ts +59 -0
  29. package/dist/src/internal/signer.js +86 -0
  30. package/dist/src/key-store.d.ts +128 -0
  31. package/dist/src/key-store.js +244 -0
  32. package/dist/src/mandates.d.ts +163 -1
  33. package/dist/src/mandates.js +286 -8
  34. package/dist/src/sdk.d.ts +39 -3
  35. package/dist/src/sdk.js +36 -23
  36. package/dist/src/session-store.d.ts +58 -0
  37. package/dist/src/session-store.js +158 -0
  38. package/dist/src/wallet.d.ts +4 -6
  39. package/dist/src/wallet.js +18 -8
  40. package/dist/src/web.d.ts +279 -0
  41. package/dist/src/web.js +186 -0
  42. package/dist/test/auth-j3.test.d.ts +2 -0
  43. package/dist/test/auth-j3.test.js +391 -0
  44. package/dist/test/compute-delegate-path.test.d.ts +2 -0
  45. package/dist/test/compute-delegate-path.test.js +183 -0
  46. package/dist/test/compute.test.js +26 -11
  47. package/dist/test/endpoints.test.js +20 -1
  48. package/dist/test/ethos-first-edition.test.d.ts +2 -0
  49. package/dist/test/ethos-first-edition.test.js +248 -0
  50. package/dist/test/ethos.test.d.ts +2 -0
  51. package/dist/test/ethos.test.js +219 -0
  52. package/dist/test/key-store.test.d.ts +2 -0
  53. package/dist/test/key-store.test.js +161 -0
  54. package/dist/test/mandates-compute.test.d.ts +2 -0
  55. package/dist/test/mandates-compute.test.js +256 -0
  56. package/dist/test/mandates.test.d.ts +2 -0
  57. package/dist/test/mandates.test.js +93 -0
  58. package/dist/test/sdk.test.js +70 -30
  59. package/dist/test/signer.test.d.ts +2 -0
  60. package/dist/test/signer.test.js +117 -0
  61. package/dist/test/signup-bootstrap.test.d.ts +2 -0
  62. package/dist/test/signup-bootstrap.test.js +222 -0
  63. package/dist/test/wallet.test.js +20 -9
  64. package/dist/test/web.test.d.ts +2 -0
  65. package/dist/test/web.test.js +270 -0
  66. package/package.json +5 -4
@@ -1,16 +1,31 @@
1
- import { type BrowserIdentity } from "@aithos/protocol-client";
1
+ import type { AithosAuth } from "./auth.js";
2
2
  import { type AithosSdkEndpoints } from "./endpoints.js";
3
3
  export interface ComputeMessage {
4
4
  readonly role: "user" | "assistant";
5
5
  readonly content: string;
6
6
  }
7
7
  export interface InvokeBedrockArgs {
8
- /** Mandate ID granting this app the right to spend the user's wallet. */
9
- readonly mandateId: string;
8
+ /**
9
+ * Mandate ID under which this call should be attributed.
10
+ *
11
+ * - **Owner sessions**: optional. The SDK uses the owner's own DID
12
+ * as a sentinel "self" mandate id — the proxy skips all
13
+ * mandate-related checks (scope, allowed_models, caps) when the
14
+ * envelope is owner-signed, so the value is informational only.
15
+ * - **Delegate sessions**: required. Must reference the imported
16
+ * mandate bundle the SDK signs with (the proxy enforces
17
+ * `compute.invoke` scope and any `allowed_models` filter).
18
+ */
19
+ readonly mandateId?: string;
10
20
  /**
11
21
  * Model id. Today the proxy accepts the canonical Aithos identifiers:
12
- * `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-7`.
22
+ * `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-opus-4-6`.
13
23
  * The proxy maps these to Bedrock cross-region inference profiles.
24
+ *
25
+ * NOTE: `claude-opus-4-7` is also provisioned on the Bedrock account
26
+ * but commercial access is gated behind an AWS Sales unlock (as of
27
+ * May 2026) — InvokeModel returns AccessDeniedException pointing to
28
+ * AWS Sales. Stick with `claude-opus-4-6` until the unlock lands.
14
29
  */
15
30
  readonly model: string;
16
31
  /** Conversation messages (user / assistant turns). */
@@ -44,16 +59,150 @@ export interface InvokeBedrockResult {
44
59
  /** Audit log id for traceability. */
45
60
  readonly auditId: string;
46
61
  }
62
+ /**
63
+ * Stable cross-provider image model ids supported by the Aithos compute
64
+ * proxy. New models can be added on the server side without an SDK
65
+ * release — but tagging the namespaced literal here gives consumers
66
+ * autocomplete + type-checking.
67
+ *
68
+ * The `image:` prefix is part of the wire contract: the server uses it
69
+ * to disambiguate text and image dispatch when a mandate's
70
+ * `allowed_models` mixes both.
71
+ */
72
+ export type ImageModelId = "image:flux-schnell" | "image:flux-dev" | "image:flux-pro-1.1" | "image:flux-pro-1.1-ultra" | "image:imagen-3" | "image:imagen-4" | "image:nano-banana";
73
+ /** Aspect ratios accepted by `invokeImage`. */
74
+ export type ImageAspectRatio = "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "21:9";
75
+ export interface InvokeImageArgs {
76
+ /**
77
+ * Mandate ID under which this call should be attributed.
78
+ *
79
+ * - **Owner sessions**: optional. The SDK uses the owner's own DID
80
+ * as a sentinel "self" mandate id — the proxy skips all
81
+ * mandate-related checks when the envelope is owner-signed.
82
+ * - **Delegate sessions**: required. Must reference the imported
83
+ * mandate bundle the SDK signs with.
84
+ */
85
+ readonly mandateId?: string;
86
+ /**
87
+ * Image model id. Defaults to `"image:flux-pro-1.1"` on the SDK side
88
+ * if omitted — the server allowlist is the source of truth for which
89
+ * ones actually work.
90
+ */
91
+ readonly model?: ImageModelId;
92
+ /** What to draw. */
93
+ readonly prompt: string;
94
+ /** Optional comma-separated list of things to avoid (e.g. "blurry, watermark"). */
95
+ readonly negativePrompt?: string;
96
+ /** Default 1:1. */
97
+ readonly aspectRatio?: ImageAspectRatio;
98
+ /** Deterministic seed (re-rolls). Omit for random. */
99
+ readonly seed?: number;
100
+ /** Number of images to generate. Default 1, max 4. */
101
+ readonly numberOfImages?: number;
102
+ /** Idempotency key for retries (generated if omitted). */
103
+ readonly idempotencyKey?: string;
104
+ /** Abort signal to cancel the request (network + provider call). */
105
+ readonly signal?: AbortSignal;
106
+ }
107
+ export interface InvokeImageImage {
108
+ /** Base64-encoded image bytes (raw, no data: URI prefix). */
109
+ readonly base64: string;
110
+ /** "image/png" | "image/jpeg". */
111
+ readonly contentType: string;
112
+ readonly width: number;
113
+ readonly height: number;
114
+ }
115
+ export interface InvokeImageResult {
116
+ readonly images: readonly InvokeImageImage[];
117
+ /** Seed actually used by the provider (echoed back even when caller didn't set one). */
118
+ readonly seed: number;
119
+ /** Microcredits debited from the wallet (exact — no reconcile path for images). */
120
+ readonly creditsCharged: number;
121
+ /** Wallet balance after debit. */
122
+ readonly walletBalance: number;
123
+ /** Audit log id for traceability. */
124
+ readonly auditId: string;
125
+ }
126
+ export interface InvokeBedrockVisionArgs {
127
+ readonly mandateId?: string;
128
+ /**
129
+ * Model id. Sonnet 4.6 is the default — it's vision-capable and
130
+ * returns reliable structured JSON when prompted.
131
+ */
132
+ readonly model?: string;
133
+ /** Source image — Blob (recommended) or raw base64. */
134
+ readonly image: Blob | {
135
+ readonly base64: string;
136
+ readonly contentType: string;
137
+ };
138
+ /** Text prompt accompanying the image. */
139
+ readonly prompt: string;
140
+ /** Optional system prompt. */
141
+ readonly system?: string;
142
+ readonly maxTokens?: number;
143
+ readonly temperature?: number;
144
+ readonly idempotencyKey?: string;
145
+ readonly signal?: AbortSignal;
146
+ }
147
+ export interface InvokeBedrockVisionResult {
148
+ readonly content: string;
149
+ readonly stopReason: StopReason;
150
+ readonly usage: {
151
+ readonly inputTokens: number;
152
+ readonly outputTokens: number;
153
+ };
154
+ readonly creditsCharged: number;
155
+ readonly walletBalance: number;
156
+ readonly auditId: string;
157
+ }
158
+ export interface InvokeSegmentationArgs {
159
+ /** Mandate id (optional for owner sessions — see InvokeImageArgs). */
160
+ readonly mandateId?: string;
161
+ /** Source image. Blob (recommended) or raw base64. */
162
+ readonly image: Blob | {
163
+ readonly base64: string;
164
+ readonly contentType: string;
165
+ };
166
+ /**
167
+ * Text phrase describing what to segment. Florence-2 is robust with
168
+ * natural-language descriptions: "the torso of the robot", "the
169
+ * dog's head", "the chest of the character".
170
+ */
171
+ readonly textInput: string;
172
+ readonly idempotencyKey?: string;
173
+ readonly signal?: AbortSignal;
174
+ }
175
+ export interface SegmentPolygon {
176
+ readonly points: ReadonlyArray<{
177
+ readonly x: number;
178
+ readonly y: number;
179
+ }>;
180
+ }
181
+ export interface InvokeSegmentationResult {
182
+ /** All polygons Florence-2 returned (typically 1, sometimes a few when the prompt matches multiple regions). */
183
+ readonly polygons: readonly SegmentPolygon[];
184
+ /** Bbox of the first polygon for callers that only need a coarse target. */
185
+ readonly bbox: {
186
+ readonly left: number;
187
+ readonly top: number;
188
+ readonly right: number;
189
+ readonly bottom: number;
190
+ } | null;
191
+ readonly creditsCharged: number;
192
+ readonly walletBalance: number;
193
+ readonly auditId: string;
194
+ }
47
195
  export interface ComputeNamespaceDeps {
48
- readonly identity: BrowserIdentity;
196
+ readonly auth: AithosAuth;
49
197
  readonly appDid: string;
50
198
  readonly endpoints: AithosSdkEndpoints;
51
199
  readonly fetch: typeof fetch;
52
200
  }
53
201
  /**
54
202
  * `sdk.compute` namespace. Constructed once by the {@link AithosSDK}
55
- * constructor; all calls share the SDK's identity, app DID, and endpoint
56
- * configuration.
203
+ * constructor; reads the active owner from the supplied
204
+ * {@link AithosAuth} on every call so signing material follows the
205
+ * latest sign-in/sign-out state.
57
206
  */
58
207
  export declare class ComputeNamespace {
59
208
  #private;
@@ -62,10 +211,73 @@ export declare class ComputeNamespace {
62
211
  * Invoke a Bedrock model through the compute proxy. See
63
212
  * {@link InvokeBedrockArgs} and {@link InvokeBedrockResult}.
64
213
  *
214
+ * Two signer paths are supported:
215
+ *
216
+ * - **Owner**: when the caller is signed in as an owner, the
217
+ * envelope is signed with the owner's `#public` sphere key and
218
+ * no mandate is attached (the proxy resolves the mandate
219
+ * server-side from `params.mandate_id`).
220
+ * - **Delegate**: when the caller is delegate-only (mandate
221
+ * imported via `auth.importMandate`), the envelope is signed
222
+ * with the delegate's bound keypair and the full SignedMandate
223
+ * is attached so the proxy can verify both signature and
224
+ * authorisation in one pass. The mandate must carry the
225
+ * `compute.invoke` scope and the proxy enforces its constraints
226
+ * (caps, allowed models, …) at server-side.
227
+ *
228
+ * Owner takes precedence: if a session has BOTH an owner and a
229
+ * matching delegate session, we use the owner key (more flexible —
230
+ * the mandate is dereferenced via `mandate_id` and there's no
231
+ * lifetime cliff if the delegate seed has been wiped).
232
+ *
65
233
  * @throws {AithosSDKError} on protocol errors. The `code` field is one of
66
- * `network`, `http`, `empty`, or any code returned by the proxy
67
- * (`quota_exceeded`, `mandate_revoked`, `insufficient_credits`, …).
234
+ * `sdk_no_signer`, `sdk_no_delegate_for_mandate`, `network`, `http`,
235
+ * `empty`, or any code returned by the proxy (`quota_exceeded`,
236
+ * `mandate_revoked`, `insufficient_credits`, …).
68
237
  */
69
238
  invokeBedrock(args: InvokeBedrockArgs): Promise<InvokeBedrockResult>;
239
+ /**
240
+ * Multimodal Bedrock invoke — image + text → text response.
241
+ * Default model: `claude-sonnet-4-6` (vision-capable, reliable JSON).
242
+ *
243
+ * Use when you need a VLM to reason about an image: locating
244
+ * features, structured extraction, semantic Q&A. Prompt the model
245
+ * to return JSON if you need structured output (the API itself is
246
+ * unstructured).
247
+ */
248
+ invokeBedrockVision(args: InvokeBedrockVisionArgs): Promise<InvokeBedrockVisionResult>;
249
+ /**
250
+ * Generate one or more images through the Aithos compute proxy
251
+ * (currently powered by fal.ai FLUX models). Spec mirror of
252
+ * {@link invokeBedrock}: same envelope, same wallet path, same
253
+ * mandate-scope gate (`compute.invoke` + `allowed_models`). The
254
+ * separation at the JSON-RPC method level (`aithos.compute_invoke_image`
255
+ * vs `aithos.compute_invoke`) commits each envelope to a specific
256
+ * modality so a stolen text-invoke envelope cannot be replayed
257
+ * against the image endpoint.
258
+ *
259
+ * Default model: `"image:flux-pro-1.1"`. Default aspect ratio: 1:1.
260
+ * Default count: 1 image.
261
+ *
262
+ * Pricing is per image and deterministic (no token-based reconcile):
263
+ * - flux-schnell: 3 000 mc + fee per image
264
+ * - flux-dev: 25 000 mc + fee per image
265
+ * - flux-pro-1.1: 40 000 mc + fee per image
266
+ * - flux-pro-1.1-ultra: 60 000 mc + fee per image
267
+ */
268
+ invokeImage(args: InvokeImageArgs): Promise<InvokeImageResult>;
269
+ /**
270
+ * Run text-prompted segmentation (Florence-2 referring-expression)
271
+ * on a source image. Returns one or more polygons hugging the
272
+ * region matching the text prompt.
273
+ *
274
+ * Use cases: locate the chest/torso area of a generated mascot
275
+ * for logo compositing, find the face zone for a thumbnail crop,
276
+ * extract a product from a marketing shot — anything that needs
277
+ * a precise mask + bbox from natural-language description.
278
+ *
279
+ * Pricing: flat 5 000 mc per call (~$0.005 — Florence-2 is cheap).
280
+ */
281
+ invokeSegmentation(args: InvokeSegmentationArgs): Promise<InvokeSegmentationResult>;
70
282
  }
71
283
  //# sourceMappingURL=compute.d.ts.map
@@ -4,8 +4,8 @@
4
4
  //
5
5
  // Wraps the JSON-RPC + signed-envelope protocol of `compute.aithos.be`
6
6
  // behind an ergonomic method on the SDK. Internally builds a §11 envelope
7
- // signed with the user's public-sphere key and posts it to
8
- // `${compute}/v1/invoke`.
7
+ // signed with the user's public-sphere key (read from
8
+ // {@link AithosAuth} at call time) and posts it to `${compute}/v1/invoke`.
9
9
  //
10
10
  // Server-side guarantees (enforced by the proxy, not by this lib):
11
11
  // - Envelope signature verified against the user's `did.json`.
@@ -18,11 +18,13 @@
18
18
  // tool calling on the proxy) will land in a follow-up.
19
19
  import { buildSignedEnvelope, } from "@aithos/protocol-client";
20
20
  import { computeInvokeUrl, } from "./endpoints.js";
21
+ import { delegateKeyPair, ownerKeyPair, } from "./internal/protocol-client-bridge.js";
21
22
  import { AithosSDKError } from "./types.js";
22
23
  /**
23
24
  * `sdk.compute` namespace. Constructed once by the {@link AithosSDK}
24
- * constructor; all calls share the SDK's identity, app DID, and endpoint
25
- * configuration.
25
+ * constructor; reads the active owner from the supplied
26
+ * {@link AithosAuth} on every call so signing material follows the
27
+ * latest sign-in/sign-out state.
26
28
  */
27
29
  export class ComputeNamespace {
28
30
  #deps;
@@ -33,17 +35,38 @@ export class ComputeNamespace {
33
35
  * Invoke a Bedrock model through the compute proxy. See
34
36
  * {@link InvokeBedrockArgs} and {@link InvokeBedrockResult}.
35
37
  *
38
+ * Two signer paths are supported:
39
+ *
40
+ * - **Owner**: when the caller is signed in as an owner, the
41
+ * envelope is signed with the owner's `#public` sphere key and
42
+ * no mandate is attached (the proxy resolves the mandate
43
+ * server-side from `params.mandate_id`).
44
+ * - **Delegate**: when the caller is delegate-only (mandate
45
+ * imported via `auth.importMandate`), the envelope is signed
46
+ * with the delegate's bound keypair and the full SignedMandate
47
+ * is attached so the proxy can verify both signature and
48
+ * authorisation in one pass. The mandate must carry the
49
+ * `compute.invoke` scope and the proxy enforces its constraints
50
+ * (caps, allowed models, …) at server-side.
51
+ *
52
+ * Owner takes precedence: if a session has BOTH an owner and a
53
+ * matching delegate session, we use the owner key (more flexible —
54
+ * the mandate is dereferenced via `mandate_id` and there's no
55
+ * lifetime cliff if the delegate seed has been wiped).
56
+ *
36
57
  * @throws {AithosSDKError} on protocol errors. The `code` field is one of
37
- * `network`, `http`, `empty`, or any code returned by the proxy
38
- * (`quota_exceeded`, `mandate_revoked`, `insufficient_credits`, …).
58
+ * `sdk_no_signer`, `sdk_no_delegate_for_mandate`, `network`, `http`,
59
+ * `empty`, or any code returned by the proxy (`quota_exceeded`,
60
+ * `mandate_revoked`, `insufficient_credits`, …).
39
61
  */
40
62
  async invokeBedrock(args) {
41
- const { identity, appDid, endpoints, fetch: fetchImpl } = this.#deps;
63
+ const { endpoints, fetch: fetchImpl } = this.#deps;
64
+ const choice = this.#resolveSigner(args.mandateId);
42
65
  const url = computeInvokeUrl(endpoints);
43
66
  const idempotencyKey = args.idempotencyKey ?? generateIdempotencyKey();
44
67
  const params = {
45
- app_did: appDid,
46
- mandate_id: args.mandateId,
68
+ app_did: this.#deps.appDid,
69
+ mandate_id: this.#resolveMandateIdForWire(args.mandateId, choice),
47
70
  model: args.model,
48
71
  messages: args.messages,
49
72
  idempotency_key: idempotencyKey,
@@ -54,13 +77,252 @@ export class ComputeNamespace {
54
77
  params.max_tokens = args.maxTokens;
55
78
  if (args.temperature !== undefined)
56
79
  params.temperature = args.temperature;
80
+ return await this.#signAndPost({
81
+ url,
82
+ method: "aithos.compute_invoke",
83
+ params,
84
+ choice,
85
+ fetchImpl,
86
+ signal: args.signal,
87
+ });
88
+ }
89
+ /**
90
+ * Multimodal Bedrock invoke — image + text → text response.
91
+ * Default model: `claude-sonnet-4-6` (vision-capable, reliable JSON).
92
+ *
93
+ * Use when you need a VLM to reason about an image: locating
94
+ * features, structured extraction, semantic Q&A. Prompt the model
95
+ * to return JSON if you need structured output (the API itself is
96
+ * unstructured).
97
+ */
98
+ async invokeBedrockVision(args) {
99
+ const { endpoints, fetch: fetchImpl } = this.#deps;
100
+ const choice = this.#resolveSigner(args.mandateId);
101
+ let imageBase64;
102
+ let imageContentType;
103
+ if ("base64" in args.image) {
104
+ imageBase64 = args.image.base64;
105
+ imageContentType = args.image.contentType;
106
+ }
107
+ else {
108
+ const buf = await args.image.arrayBuffer();
109
+ imageBase64 = arrayBufferToBase64(buf);
110
+ imageContentType = args.image.type || "image/png";
111
+ }
112
+ const url = computeInvokeUrl(endpoints);
113
+ const idempotencyKey = args.idempotencyKey ?? generateIdempotencyKey();
114
+ const model = args.model ?? "claude-sonnet-4-6";
115
+ const params = {
116
+ app_did: this.#deps.appDid,
117
+ mandate_id: this.#resolveMandateIdForWire(args.mandateId, choice),
118
+ model,
119
+ image_base64: imageBase64,
120
+ image_content_type: imageContentType,
121
+ prompt: args.prompt,
122
+ idempotency_key: idempotencyKey,
123
+ };
124
+ if (args.system !== undefined)
125
+ params.system = args.system;
126
+ if (args.maxTokens !== undefined)
127
+ params.max_tokens = args.maxTokens;
128
+ if (args.temperature !== undefined)
129
+ params.temperature = args.temperature;
130
+ return await this.#signAndPost({
131
+ url,
132
+ method: "aithos.compute_invoke_bedrock_vision",
133
+ params,
134
+ choice,
135
+ fetchImpl,
136
+ signal: args.signal,
137
+ });
138
+ }
139
+ /**
140
+ * Generate one or more images through the Aithos compute proxy
141
+ * (currently powered by fal.ai FLUX models). Spec mirror of
142
+ * {@link invokeBedrock}: same envelope, same wallet path, same
143
+ * mandate-scope gate (`compute.invoke` + `allowed_models`). The
144
+ * separation at the JSON-RPC method level (`aithos.compute_invoke_image`
145
+ * vs `aithos.compute_invoke`) commits each envelope to a specific
146
+ * modality so a stolen text-invoke envelope cannot be replayed
147
+ * against the image endpoint.
148
+ *
149
+ * Default model: `"image:flux-pro-1.1"`. Default aspect ratio: 1:1.
150
+ * Default count: 1 image.
151
+ *
152
+ * Pricing is per image and deterministic (no token-based reconcile):
153
+ * - flux-schnell: 3 000 mc + fee per image
154
+ * - flux-dev: 25 000 mc + fee per image
155
+ * - flux-pro-1.1: 40 000 mc + fee per image
156
+ * - flux-pro-1.1-ultra: 60 000 mc + fee per image
157
+ */
158
+ async invokeImage(args) {
159
+ const { endpoints, fetch: fetchImpl } = this.#deps;
160
+ const choice = this.#resolveSigner(args.mandateId);
161
+ const url = computeInvokeUrl(endpoints);
162
+ const idempotencyKey = args.idempotencyKey ?? generateIdempotencyKey();
163
+ // Default is Imagen 4 since alpha.17 — flat-illustration style is
164
+ // the right match for brand-mascot use cases. FLUX Pro 1.1 remains
165
+ // available via explicit `model: "image:flux-pro-1.1"`.
166
+ const model = args.model ?? "image:imagen-4";
167
+ const params = {
168
+ app_did: this.#deps.appDid,
169
+ mandate_id: this.#resolveMandateIdForWire(args.mandateId, choice),
170
+ model,
171
+ prompt: args.prompt,
172
+ idempotency_key: idempotencyKey,
173
+ };
174
+ if (args.negativePrompt !== undefined)
175
+ params.negative_prompt = args.negativePrompt;
176
+ if (args.aspectRatio !== undefined)
177
+ params.aspect_ratio = args.aspectRatio;
178
+ if (args.seed !== undefined)
179
+ params.seed = args.seed;
180
+ if (args.numberOfImages !== undefined)
181
+ params.number_of_images = args.numberOfImages;
182
+ return await this.#signAndPost({
183
+ url,
184
+ method: "aithos.compute_invoke_image",
185
+ params,
186
+ choice,
187
+ fetchImpl,
188
+ signal: args.signal,
189
+ });
190
+ }
191
+ /**
192
+ * Run text-prompted segmentation (Florence-2 referring-expression)
193
+ * on a source image. Returns one or more polygons hugging the
194
+ * region matching the text prompt.
195
+ *
196
+ * Use cases: locate the chest/torso area of a generated mascot
197
+ * for logo compositing, find the face zone for a thumbnail crop,
198
+ * extract a product from a marketing shot — anything that needs
199
+ * a precise mask + bbox from natural-language description.
200
+ *
201
+ * Pricing: flat 5 000 mc per call (~$0.005 — Florence-2 is cheap).
202
+ */
203
+ async invokeSegmentation(args) {
204
+ const { endpoints, fetch: fetchImpl } = this.#deps;
205
+ const choice = this.#resolveSigner(args.mandateId);
206
+ // Normalize image input to base64 + content type.
207
+ let imageBase64;
208
+ let imageContentType;
209
+ if ("base64" in args.image) {
210
+ imageBase64 = args.image.base64;
211
+ imageContentType = args.image.contentType;
212
+ }
213
+ else {
214
+ const buf = await args.image.arrayBuffer();
215
+ imageBase64 = arrayBufferToBase64(buf);
216
+ imageContentType = args.image.type || "image/png";
217
+ }
218
+ const url = computeInvokeUrl(endpoints);
219
+ const idempotencyKey = args.idempotencyKey ?? generateIdempotencyKey();
220
+ const params = {
221
+ app_did: this.#deps.appDid,
222
+ mandate_id: this.#resolveMandateIdForWire(args.mandateId, choice),
223
+ image_base64: imageBase64,
224
+ image_content_type: imageContentType,
225
+ text_input: args.textInput,
226
+ idempotency_key: idempotencyKey,
227
+ };
228
+ return await this.#signAndPost({
229
+ url,
230
+ method: "aithos.compute_invoke_segmentation",
231
+ params,
232
+ choice,
233
+ fetchImpl,
234
+ signal: args.signal,
235
+ });
236
+ }
237
+ /**
238
+ * Resolve the active signer (owner takes precedence over delegate).
239
+ *
240
+ * - When an owner is signed in: returns the owner-signer regardless
241
+ * of `mandateId` (the proxy ignores params.mandate_id on
242
+ * owner-signed envelopes, so owners can omit it).
243
+ * - When delegate-only: requires `mandateId` to find the matching
244
+ * imported bundle. Throws `sdk_no_delegate_for_mandate` if absent
245
+ * or no match.
246
+ */
247
+ #resolveSigner(mandateId) {
248
+ const { auth } = this.#deps;
249
+ const owner = auth._getOwnerSigners();
250
+ const ownerLoaded = owner !== null && !owner.destroyed;
251
+ if (ownerLoaded) {
252
+ const publicKp = ownerKeyPair(owner, "public");
253
+ return {
254
+ kind: "owner",
255
+ iss: owner.did,
256
+ verificationMethod: `${owner.did}#public`,
257
+ signer: publicKp,
258
+ mandate: undefined,
259
+ };
260
+ }
261
+ if (mandateId === undefined || mandateId.length === 0) {
262
+ throw new AithosSDKError("sdk_no_signer", "no owner signed in and no mandateId provided — pass a mandateId for a delegate session, or sign in as an owner first.");
263
+ }
264
+ const actor = auth._getDelegateActor(mandateId);
265
+ if (!actor || actor.destroyed) {
266
+ throw new AithosSDKError("sdk_no_delegate_for_mandate", `no owner signed in and no imported delegate mandate matches '${mandateId}'. Sign in as an owner, or import a delegate bundle for that mandate via auth.importMandate.`);
267
+ }
268
+ const kp = delegateKeyPair(actor);
269
+ return {
270
+ kind: "delegate",
271
+ iss: actor.subjectDid,
272
+ verificationMethod: actor.granteePubkeyMultibase,
273
+ signer: kp,
274
+ // The DelegateActor stores the SignedMandate as a structurally
275
+ // opaque object so the SDK doesn't have to import the
276
+ // protocol-client type at the storage boundary. Round-trip
277
+ // through `unknown` for the TS cast — at runtime the bytes are
278
+ // the canonical SignedMandate the bundle parser already
279
+ // validated.
280
+ mandate: actor.mandate,
281
+ };
282
+ }
283
+ /**
284
+ * Resolve the `mandate_id` value the SDK writes into the JSON-RPC
285
+ * params for the wire. The proxy requires this field to be a
286
+ * non-empty string but only consults it for the delegate path —
287
+ * for owner-signed envelopes it's audit-log metadata, with no
288
+ * security implication.
289
+ *
290
+ * Strategy:
291
+ * - Caller-provided id always wins (owner who wants to attribute
292
+ * to a specific minted mandate can still pass it).
293
+ * - Delegate path: the choice carries the real mandate.id — use it
294
+ * so a delegate cannot accidentally lie about which mandate
295
+ * it claims to spend under.
296
+ * - Owner path with no explicit id: use the owner DID followed
297
+ * by `#self` — a stable sentinel that's unambiguously not a
298
+ * real mandate id (mandate ids are ULIDs).
299
+ */
300
+ #resolveMandateIdForWire(explicit, choice) {
301
+ if (explicit && explicit.length > 0)
302
+ return explicit;
303
+ if (choice.kind === "delegate")
304
+ return choice.mandate.id;
305
+ // Owner-direct sentinel. The proxy never inspects this value
306
+ // beyond non-empty-string validation when no mandate is attached.
307
+ return `${choice.iss}#self`;
308
+ }
309
+ /**
310
+ * Sign the params with the resolved signer and POST a JSON-RPC
311
+ * request. Shared between `invokeBedrock` and `invokeImage` — the
312
+ * only difference between those two is the method name and the
313
+ * params shape; the envelope construction + transport + error
314
+ * mapping is identical.
315
+ */
316
+ async #signAndPost(opts) {
317
+ const { url, method, params, choice, fetchImpl, signal } = opts;
57
318
  const envelope = buildSignedEnvelope({
58
- iss: identity.did,
319
+ iss: choice.iss,
59
320
  aud: url,
60
- method: "aithos.compute_invoke",
61
- verificationMethod: `${identity.did}#public`,
321
+ method,
322
+ verificationMethod: choice.verificationMethod,
62
323
  params,
63
- signer: identity.public,
324
+ signer: choice.signer,
325
+ ...(choice.kind === "delegate" ? { mandate: choice.mandate } : {}),
64
326
  });
65
327
  let res;
66
328
  try {
@@ -69,11 +331,11 @@ export class ComputeNamespace {
69
331
  headers: { "content-type": "application/json" },
70
332
  body: JSON.stringify({
71
333
  jsonrpc: "2.0",
72
- id: "aithos.compute_invoke",
73
- method: "aithos.compute_invoke",
334
+ id: method,
335
+ method,
74
336
  params: { ...params, _envelope: envelope },
75
337
  }),
76
- ...(args.signal ? { signal: args.signal } : {}),
338
+ ...(signal ? { signal } : {}),
77
339
  });
78
340
  }
79
341
  catch (e) {
@@ -101,4 +363,19 @@ function generateIdempotencyKey() {
101
363
  }
102
364
  return hex;
103
365
  }
366
+ /**
367
+ * Encode an ArrayBuffer as base64 in environments where `Buffer` is
368
+ * not available (browser). Uses btoa over a binary string — safe for
369
+ * the small payload sizes the SDK deals with (≤ a few MB).
370
+ */
371
+ function arrayBufferToBase64(buf) {
372
+ const bytes = new Uint8Array(buf);
373
+ let bin = "";
374
+ // Process in chunks to avoid stack overflow on String.fromCharCode.apply
375
+ const CHUNK = 0x8000;
376
+ for (let i = 0; i < bytes.length; i += CHUNK) {
377
+ bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));
378
+ }
379
+ return btoa(bin);
380
+ }
104
381
  //# sourceMappingURL=compute.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Bundled copy of the `aithos.contacts.v1` schema.
3
+ *
4
+ * Mirrors `spec/data/schemas/aithos.contacts.v1.json` of the
5
+ * Aithos-protocol repo. The SDK uses this to split a record into its
6
+ * indexable (metadata) and encrypted (payload) parts on insert and to
7
+ * recombine them on read.
8
+ *
9
+ * In a later iteration the SDK will fetch / resolve schemas dynamically
10
+ * from a registry; for v0.1 we bundle the core schemas.
11
+ */
12
+ import type { AithosSchemaLite } from "./data.js";
13
+ export declare const contactsV1: AithosSchemaLite;
14
+ //# sourceMappingURL=data-schema-contacts-v1.d.ts.map
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 Mathieu Colla
3
+ export const contactsV1 = {
4
+ schema: "aithos.contacts.v1",
5
+ indexable: new Set([
6
+ "name",
7
+ "email",
8
+ "phone_hash",
9
+ "status",
10
+ "tags",
11
+ "source",
12
+ "created_at",
13
+ "modified_at",
14
+ "last_contacted_at",
15
+ ]),
16
+ encrypted: new Set([
17
+ "phone",
18
+ "notes",
19
+ "conversation_log",
20
+ "form_responses",
21
+ "custom_fields",
22
+ ]),
23
+ auto: new Set(["created_at", "modified_at"]),
24
+ defaults: {
25
+ status: "lead",
26
+ },
27
+ };
28
+ //# sourceMappingURL=data-schema-contacts-v1.js.map