@agentidentity/sdk 0.1.0 → 0.2.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 CHANGED
@@ -31,13 +31,53 @@ await client.mail.send({
31
31
  });
32
32
  ```
33
33
 
34
- Don't have an org yet? Bootstrap one — these run before you have a key, so they're plain
35
- functions rather than client methods:
34
+ ## Signing up as an agent
35
+
36
+ You don't need a human to create the account. An agent can register itself, and the human only
37
+ has to read a code out of their inbox.
38
+
39
+ ```ts
40
+ import { createOrganization, verifyOwner, AgentClient } from "@agentidentity/sdk";
41
+
42
+ const BASE = "https://api.agent-identity.dev";
43
+
44
+ // 1. Register. Unauthenticated — no form, no card. Naming an owner emails them a 6-digit code.
45
+ const org = await createOrganization(BASE, {
46
+ name: "Acme Support",
47
+ slug: "acme-support",
48
+ ownerEmail: "you@acme.com",
49
+ });
50
+
51
+ org.adminApiKey; // returned exactly once — store it now
52
+ org.verificationRequired; // true: a code is waiting in that inbox
53
+ org.nextStep; // what to do, in words you can show a human
54
+
55
+ // 2. Ask the human for the code, then return it.
56
+ await verifyOwner(BASE, org.adminApiKey, "481923");
57
+
58
+ // 3. Give yourself an identity with a real mailbox.
59
+ const admin = new AgentClient({ baseUrl: BASE, apiKey: org.adminApiKey });
60
+ const me = await admin.identities.create({ handle: "support", displayName: "Support Agent" });
61
+ me.mailboxAddress; // support@…
62
+
63
+ // 4. Mint a key that acts as *you* rather than as the whole organization.
64
+ const key = await admin.apiKeys.create({ name: "self", identityId: me.id });
65
+ const self = new AgentClient({ baseUrl: BASE, apiKey: key.key });
66
+ ```
67
+
68
+ **Before verification** the organization may only email its own owner, a few messages a day.
69
+ Sending anywhere else fails with `AidApiError`, code `mail.unverified_recipient`. That's what
70
+ makes open signup safe: an unverified organization cannot reach a stranger at all.
71
+
72
+ The code expires in 15 minutes and allows 5 wrong guesses. Verifying an already-verified
73
+ organization is a no-op rather than an error, so retrying is safe.
74
+
75
+ Signing up as a human instead — with an email and password, already verified:
36
76
 
37
77
  ```ts
38
- import { signUp, logIn, createOrganization } from "@agentidentity/sdk";
78
+ import { signUp, logIn } from "@agentidentity/sdk";
39
79
 
40
- const session = await signUp("https://api.agent-identity.dev", {
80
+ const session = await signUp(BASE, {
41
81
  orgName: "Acme",
42
82
  orgSlug: "acme",
43
83
  email: "you@acme.com",
package/dist/client.d.ts CHANGED
@@ -223,12 +223,26 @@ export interface SubscribeInput<T extends AidEventType | string = string> extend
223
223
  export interface CreateOrganizationInput {
224
224
  name: string;
225
225
  slug: string;
226
+ /**
227
+ * The human who owns this organization. Naming one emails them a six-digit code; returning it
228
+ * through {@link verifyOwner} lifts the restrictions an unverified organization runs under.
229
+ *
230
+ * Without it the organization stays unverified: a few messages a day, and no way to prove a
231
+ * human is behind it.
232
+ */
233
+ ownerEmail?: string;
226
234
  }
227
235
  export interface OrganizationBootstrap {
228
236
  id: string;
229
237
  slug: string;
230
238
  name: string;
239
+ /** Returned exactly once. There is no endpoint that will show it again. */
231
240
  adminApiKey: string;
241
+ ownerEmail: string | null;
242
+ /** True when a code has been emailed and the organization is waiting for it. */
243
+ verificationRequired: boolean;
244
+ /** What to do next, in words you can act on or show to a human. */
245
+ nextStep: string;
232
246
  }
233
247
  export interface WhoAmI {
234
248
  actorType: string;
@@ -562,6 +576,23 @@ export interface CreateTunnelInput {
562
576
  hostname?: string;
563
577
  }
564
578
  export declare function createOrganization(baseUrl: string, input: CreateOrganizationInput, fetchImpl?: typeof fetch): Promise<OrganizationBootstrap>;
579
+ /**
580
+ * Completes signup by returning the six-digit code emailed to the organization's owner.
581
+ *
582
+ * Until this succeeds the organization may only email that owner, and only a few times a day.
583
+ * Any key belonging to the organization can call it — the secret is the code, which reaches the
584
+ * human's inbox, so the agent that started the flow can also finish it.
585
+ *
586
+ * ```ts
587
+ * const org = await createOrganization(baseUrl, { name, slug, ownerEmail: "you@example.com" });
588
+ * // ask the human for the code that just arrived, then:
589
+ * await verifyOwner(baseUrl, org.adminApiKey, code);
590
+ * ```
591
+ */
592
+ export declare function verifyOwner(baseUrl: string, apiKey: string, code: string, fetchImpl?: typeof fetch): Promise<{
593
+ verified: true;
594
+ orgId: string;
595
+ }>;
565
596
  export interface SignUpInput {
566
597
  orgName: string;
567
598
  orgSlug: string;
package/dist/client.js CHANGED
@@ -3,10 +3,43 @@ import { AidApiError, AidConnectionError } from "./errors.js";
3
3
  export { AidApiError, AidConnectionError } from "./errors.js";
4
4
  export async function createOrganization(baseUrl, input, fetchImpl = fetch) {
5
5
  const body = await sendRequest(fetchImpl, baseUrl, "POST", "/v1/organizations", {
6
- body: { name: input.name, slug: input.slug },
6
+ body: {
7
+ name: input.name,
8
+ slug: input.slug,
9
+ ...(input.ownerEmail !== undefined ? { owner_email: input.ownerEmail } : {}),
10
+ },
11
+ });
12
+ const b = body;
13
+ return {
14
+ id: b.id,
15
+ slug: b.slug,
16
+ name: b.name,
17
+ adminApiKey: b.admin_api_key,
18
+ ownerEmail: b.owner_email ?? null,
19
+ verificationRequired: Boolean(b.verification_required),
20
+ nextStep: b.next_step ?? "",
21
+ };
22
+ }
23
+ /**
24
+ * Completes signup by returning the six-digit code emailed to the organization's owner.
25
+ *
26
+ * Until this succeeds the organization may only email that owner, and only a few times a day.
27
+ * Any key belonging to the organization can call it — the secret is the code, which reaches the
28
+ * human's inbox, so the agent that started the flow can also finish it.
29
+ *
30
+ * ```ts
31
+ * const org = await createOrganization(baseUrl, { name, slug, ownerEmail: "you@example.com" });
32
+ * // ask the human for the code that just arrived, then:
33
+ * await verifyOwner(baseUrl, org.adminApiKey, code);
34
+ * ```
35
+ */
36
+ export async function verifyOwner(baseUrl, apiKey, code, fetchImpl = fetch) {
37
+ const body = await sendRequest(fetchImpl, baseUrl, "POST", "/v1/auth/verify", {
38
+ headers: { authorization: `Bearer ${apiKey}` },
39
+ body: { code },
7
40
  });
8
41
  const b = body;
9
- return { id: b.id, slug: b.slug, name: b.name, adminApiKey: b.admin_api_key };
42
+ return { verified: true, orgId: b.org_id };
10
43
  }
11
44
  function toAuthSession(body) {
12
45
  const b = body;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentidentity/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TypeScript client for Agent Identity \u2014 give an agent its own email address, durable event stream, and encrypted secret vault.",
5
5
  "license": "MIT",
6
6
  "keywords": [