@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 +44 -4
- package/dist/client.d.ts +31 -0
- package/dist/client.js +35 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,13 +31,53 @@ await client.mail.send({
|
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
78
|
+
import { signUp, logIn } from "@agentidentity/sdk";
|
|
39
79
|
|
|
40
|
-
const session = await signUp(
|
|
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: {
|
|
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 {
|
|
42
|
+
return { verified: true, orgId: b.org_id };
|
|
10
43
|
}
|
|
11
44
|
function toAuthSession(body) {
|
|
12
45
|
const b = body;
|
package/package.json
CHANGED