@aithos/sdk 0.1.0-alpha.1 → 0.1.0-alpha.10

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 (55) hide show
  1. package/README.md +45 -0
  2. package/dist/src/auth-api.d.ts +41 -0
  3. package/dist/src/auth-api.js +82 -0
  4. package/dist/src/auth.d.ts +166 -0
  5. package/dist/src/auth.js +730 -0
  6. package/dist/src/compute.d.ts +27 -6
  7. package/dist/src/compute.js +67 -10
  8. package/dist/src/ethos.d.ts +117 -1
  9. package/dist/src/ethos.js +646 -16
  10. package/dist/src/index.d.ts +11 -4
  11. package/dist/src/index.js +31 -5
  12. package/dist/src/internal/delegate-bundle.d.ts +18 -0
  13. package/dist/src/internal/delegate-bundle.js +94 -0
  14. package/dist/src/internal/delegate-state.d.ts +45 -0
  15. package/dist/src/internal/delegate-state.js +120 -0
  16. package/dist/src/internal/owner-signers.d.ts +78 -0
  17. package/dist/src/internal/owner-signers.js +179 -0
  18. package/dist/src/internal/protocol-client-bridge.d.ts +8 -0
  19. package/dist/src/internal/protocol-client-bridge.js +20 -0
  20. package/dist/src/internal/recovery-file.d.ts +29 -0
  21. package/dist/src/internal/recovery-file.js +98 -0
  22. package/dist/src/internal/signer.d.ts +59 -0
  23. package/dist/src/internal/signer.js +86 -0
  24. package/dist/src/key-store.d.ts +128 -0
  25. package/dist/src/key-store.js +244 -0
  26. package/dist/src/mandates.d.ts +163 -1
  27. package/dist/src/mandates.js +286 -8
  28. package/dist/src/sdk.d.ts +36 -3
  29. package/dist/src/sdk.js +28 -22
  30. package/dist/src/session-store.d.ts +58 -0
  31. package/dist/src/session-store.js +158 -0
  32. package/dist/src/wallet.d.ts +42 -2
  33. package/dist/src/wallet.js +89 -14
  34. package/dist/test/auth-j3.test.d.ts +2 -0
  35. package/dist/test/auth-j3.test.js +391 -0
  36. package/dist/test/auth.test.d.ts +2 -0
  37. package/dist/test/auth.test.js +175 -0
  38. package/dist/test/compute-delegate-path.test.d.ts +2 -0
  39. package/dist/test/compute-delegate-path.test.js +183 -0
  40. package/dist/test/compute.test.js +22 -11
  41. package/dist/test/ethos-first-edition.test.d.ts +2 -0
  42. package/dist/test/ethos-first-edition.test.js +248 -0
  43. package/dist/test/ethos.test.d.ts +2 -0
  44. package/dist/test/ethos.test.js +219 -0
  45. package/dist/test/key-store.test.d.ts +2 -0
  46. package/dist/test/key-store.test.js +161 -0
  47. package/dist/test/mandates-compute.test.d.ts +2 -0
  48. package/dist/test/mandates-compute.test.js +256 -0
  49. package/dist/test/mandates.test.d.ts +2 -0
  50. package/dist/test/mandates.test.js +93 -0
  51. package/dist/test/sdk.test.js +70 -30
  52. package/dist/test/signer.test.d.ts +2 -0
  53. package/dist/test/signer.test.js +117 -0
  54. package/dist/test/wallet.test.js +20 -9
  55. package/package.json +4 -3
@@ -1,4 +1,4 @@
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";
@@ -45,15 +45,16 @@ export interface InvokeBedrockResult {
45
45
  readonly auditId: string;
46
46
  }
47
47
  export interface ComputeNamespaceDeps {
48
- readonly identity: BrowserIdentity;
48
+ readonly auth: AithosAuth;
49
49
  readonly appDid: string;
50
50
  readonly endpoints: AithosSdkEndpoints;
51
51
  readonly fetch: typeof fetch;
52
52
  }
53
53
  /**
54
54
  * `sdk.compute` namespace. Constructed once by the {@link AithosSDK}
55
- * constructor; all calls share the SDK's identity, app DID, and endpoint
56
- * configuration.
55
+ * constructor; reads the active owner from the supplied
56
+ * {@link AithosAuth} on every call so signing material follows the
57
+ * latest sign-in/sign-out state.
57
58
  */
58
59
  export declare class ComputeNamespace {
59
60
  #private;
@@ -62,9 +63,29 @@ export declare class ComputeNamespace {
62
63
  * Invoke a Bedrock model through the compute proxy. See
63
64
  * {@link InvokeBedrockArgs} and {@link InvokeBedrockResult}.
64
65
  *
66
+ * Two signer paths are supported:
67
+ *
68
+ * - **Owner**: when the caller is signed in as an owner, the
69
+ * envelope is signed with the owner's `#public` sphere key and
70
+ * no mandate is attached (the proxy resolves the mandate
71
+ * server-side from `params.mandate_id`).
72
+ * - **Delegate**: when the caller is delegate-only (mandate
73
+ * imported via `auth.importMandate`), the envelope is signed
74
+ * with the delegate's bound keypair and the full SignedMandate
75
+ * is attached so the proxy can verify both signature and
76
+ * authorisation in one pass. The mandate must carry the
77
+ * `compute.invoke` scope and the proxy enforces its constraints
78
+ * (caps, allowed models, …) at server-side.
79
+ *
80
+ * Owner takes precedence: if a session has BOTH an owner and a
81
+ * matching delegate session, we use the owner key (more flexible —
82
+ * the mandate is dereferenced via `mandate_id` and there's no
83
+ * lifetime cliff if the delegate seed has been wiped).
84
+ *
65
85
  * @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`, …).
86
+ * `sdk_no_signer`, `sdk_no_delegate_for_mandate`, `network`, `http`,
87
+ * `empty`, or any code returned by the proxy (`quota_exceeded`,
88
+ * `mandate_revoked`, `insufficient_credits`, …).
68
89
  */
69
90
  invokeBedrock(args: InvokeBedrockArgs): Promise<InvokeBedrockResult>;
70
91
  }
@@ -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,12 +35,66 @@ 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 { auth, appDid, endpoints, fetch: fetchImpl } = this.#deps;
64
+ const owner = auth._getOwnerSigners();
65
+ const ownerLoaded = owner !== null && !owner.destroyed;
66
+ let choice;
67
+ if (ownerLoaded) {
68
+ const publicKp = ownerKeyPair(owner, "public");
69
+ choice = {
70
+ kind: "owner",
71
+ iss: owner.did,
72
+ verificationMethod: `${owner.did}#public`,
73
+ signer: publicKp,
74
+ mandate: undefined,
75
+ };
76
+ }
77
+ else {
78
+ // Delegate-only path. Find a session whose mandate id matches.
79
+ const actor = auth._getDelegateActor(args.mandateId);
80
+ if (!actor || actor.destroyed) {
81
+ throw new AithosSDKError("sdk_no_delegate_for_mandate", `no owner signed in and no imported delegate mandate matches '${args.mandateId}'. Sign in as an owner, or import a delegate bundle for that mandate via auth.importMandate.`);
82
+ }
83
+ const kp = delegateKeyPair(actor);
84
+ choice = {
85
+ kind: "delegate",
86
+ iss: actor.subjectDid,
87
+ verificationMethod: actor.granteePubkeyMultibase,
88
+ signer: kp,
89
+ // The DelegateActor stores the SignedMandate as a structurally
90
+ // opaque object so the SDK doesn't have to import the
91
+ // protocol-client type at the storage boundary. Round-trip
92
+ // through `unknown` for the TS cast — at runtime the bytes are
93
+ // the canonical SignedMandate the bundle parser already
94
+ // validated.
95
+ mandate: actor.mandate,
96
+ };
97
+ }
42
98
  const url = computeInvokeUrl(endpoints);
43
99
  const idempotencyKey = args.idempotencyKey ?? generateIdempotencyKey();
44
100
  const params = {
@@ -55,12 +111,13 @@ export class ComputeNamespace {
55
111
  if (args.temperature !== undefined)
56
112
  params.temperature = args.temperature;
57
113
  const envelope = buildSignedEnvelope({
58
- iss: identity.did,
114
+ iss: choice.iss,
59
115
  aud: url,
60
116
  method: "aithos.compute_invoke",
61
- verificationMethod: `${identity.did}#public`,
117
+ verificationMethod: choice.verificationMethod,
62
118
  params,
63
- signer: identity.public,
119
+ signer: choice.signer,
120
+ ...(choice.kind === "delegate" ? { mandate: choice.mandate } : {}),
64
121
  });
65
122
  let res;
66
123
  try {
@@ -1,2 +1,118 @@
1
- export { parsePublicZone, type ParsedZone, loadEditSnapshot, publishZoneEdit, publishPublicZoneAsDelegate, publishPrivateZoneAsDelegate, type EditSnapshot, type AddSectionInput, type ModifySectionInput, type PublishEditArgs, type PublishEditResult, addSectionToList, modifySectionInList, deleteSectionFromList, buildSignedFirstEdition, buildSignedNextEdition, type ZoneDoc, type ZoneManifest, type Section, SPHERES, type Sphere, } from "@aithos/protocol-client";
1
+ import { type Section } from "@aithos/protocol-client";
2
+ import type { AithosAuth } from "./auth.js";
3
+ import type { AithosSdkEndpoints } from "./endpoints.js";
4
+ import type { DelegateActor } from "./internal/delegate-state.js";
5
+ import type { OwnerSigners } from "./internal/owner-signers.js";
6
+ export type ZoneName = "public" | "circle" | "self";
7
+ export declare const ZONE_NAMES: readonly ZoneName[];
8
+ export interface AddSectionInput {
9
+ readonly title: string;
10
+ readonly body: string;
11
+ readonly tags?: readonly string[];
12
+ }
13
+ export interface UpdateSectionPatch {
14
+ readonly title?: string;
15
+ readonly body?: string;
16
+ readonly tags?: readonly string[];
17
+ }
18
+ export type StagedChange = {
19
+ readonly kind: "add";
20
+ readonly zone: ZoneName;
21
+ readonly section: Section;
22
+ } | {
23
+ readonly kind: "update";
24
+ readonly zone: ZoneName;
25
+ readonly sectionId: string;
26
+ readonly patch: UpdateSectionPatch;
27
+ } | {
28
+ readonly kind: "delete";
29
+ readonly zone: ZoneName;
30
+ readonly sectionId: string;
31
+ };
32
+ export interface PublishResult {
33
+ /** New manifest height after publish. */
34
+ readonly editionHeight: number;
35
+ /** SHA-256 hex of the canonical manifest. */
36
+ readonly manifestHash: string;
37
+ /** DID of the subject we published for. */
38
+ readonly subjectDid: string;
39
+ /** Zones whose contents changed in this edition. */
40
+ readonly zonesPublished: readonly ZoneName[];
41
+ }
42
+ type ActorOwner = {
43
+ readonly kind: "owner";
44
+ readonly subjectDid: string;
45
+ readonly signers: OwnerSigners;
46
+ };
47
+ type ActorDelegate = {
48
+ readonly kind: "delegate";
49
+ readonly subjectDid: string;
50
+ readonly actor: DelegateActor;
51
+ };
52
+ type ActorAnonymous = {
53
+ readonly kind: "anonymous";
54
+ readonly subjectDid: string;
55
+ };
56
+ type Actor = ActorOwner | ActorDelegate | ActorAnonymous;
57
+ export declare class EthosClient {
58
+ #private;
59
+ readonly subjectDid: string;
60
+ readonly mode: Actor["kind"];
61
+ constructor(actor: Actor);
62
+ /** Return the per-zone proxy. */
63
+ zone(name: ZoneName): EthosZone;
64
+ hasPendingChanges(): boolean;
65
+ pendingChanges(): readonly StagedChange[];
66
+ discard(): void;
67
+ /**
68
+ * Build and publish a new edition with all staged mutations applied.
69
+ * Throws if there's nothing staged. After a successful publish, the
70
+ * mutation buffer is cleared and any cached snapshot is invalidated
71
+ * so the next read picks up the fresh edition.
72
+ */
73
+ publish(): Promise<PublishResult>;
74
+ _readZone(zone: ZoneName): Promise<readonly Section[]>;
75
+ _stageAdd(zone: ZoneName, input: AddSectionInput): void;
76
+ _stageUpdate(zone: ZoneName, sectionId: string, patch: UpdateSectionPatch): void;
77
+ _stageDelete(zone: ZoneName, sectionId: string): void;
78
+ }
79
+ export declare class EthosZone {
80
+ #private;
81
+ constructor(parent: EthosClient, name: ZoneName);
82
+ get name(): ZoneName;
83
+ /** Effective sections (persisted + staged mutations applied). */
84
+ sections(): Promise<readonly Section[]>;
85
+ addSection(input: AddSectionInput): void;
86
+ updateSection(sectionId: string, patch: UpdateSectionPatch): void;
87
+ deleteSection(sectionId: string): void;
88
+ }
89
+ export interface EthosNamespaceDeps {
90
+ readonly auth: AithosAuth;
91
+ readonly endpoints: AithosSdkEndpoints;
92
+ readonly fetch: typeof fetch;
93
+ }
94
+ export declare class EthosNamespace {
95
+ #private;
96
+ constructor(deps: EthosNamespaceDeps);
97
+ /**
98
+ * EthosClient for the currently signed-in owner. Throws if there is
99
+ * no owner — callers should check `auth.canSignAsOwner()` first or
100
+ * surface the error to the user as "please sign in".
101
+ */
102
+ me(): EthosClient;
103
+ /**
104
+ * EthosClient for an arbitrary subject DID. The mode is resolved at
105
+ * construction time:
106
+ * - if `did` matches the currently signed-in owner → owner mode
107
+ * - else if a mandate held by `auth` covers this subject → delegate mode
108
+ * - else → anonymous read-only mode
109
+ *
110
+ * Async signature so future implementations may do an eager manifest
111
+ * fetch (e.g. to fail fast on unknown DIDs); today resolution is sync
112
+ * and the actual fetch happens on the first `sections()` / `publish()`
113
+ * call.
114
+ */
115
+ of(did: string): Promise<EthosClient>;
116
+ }
117
+ export {};
2
118
  //# sourceMappingURL=ethos.d.ts.map