salt-agent-sdk 0.1.0 → 0.18.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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +941 -30
  3. package/dist/actions.d.ts +21 -5
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/actions.js +673 -54
  6. package/dist/actions.js.map +1 -1
  7. package/dist/ask.d.ts +83 -0
  8. package/dist/ask.d.ts.map +1 -0
  9. package/dist/ask.js +215 -0
  10. package/dist/ask.js.map +1 -0
  11. package/dist/chatPrivacy.d.ts +34 -0
  12. package/dist/chatPrivacy.d.ts.map +1 -0
  13. package/dist/chatPrivacy.js +60 -0
  14. package/dist/chatPrivacy.js.map +1 -0
  15. package/dist/client.d.ts +2783 -35
  16. package/dist/client.d.ts.map +1 -1
  17. package/dist/client.js +1200 -143
  18. package/dist/client.js.map +1 -1
  19. package/dist/config.d.ts +16 -6
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +16 -5
  22. package/dist/config.js.map +1 -1
  23. package/dist/crypto.d.ts +62 -0
  24. package/dist/crypto.d.ts.map +1 -1
  25. package/dist/crypto.js +121 -0
  26. package/dist/crypto.js.map +1 -1
  27. package/dist/delegations.d.ts +25 -8
  28. package/dist/delegations.d.ts.map +1 -1
  29. package/dist/delegations.js +67 -11
  30. package/dist/delegations.js.map +1 -1
  31. package/dist/device/client.d.ts +161 -0
  32. package/dist/device/client.d.ts.map +1 -0
  33. package/dist/device/client.js +601 -0
  34. package/dist/device/client.js.map +1 -0
  35. package/dist/device/host.d.ts +222 -0
  36. package/dist/device/host.d.ts.map +1 -0
  37. package/dist/device/host.js +891 -0
  38. package/dist/device/host.js.map +1 -0
  39. package/dist/device/http.d.ts +12 -0
  40. package/dist/device/http.d.ts.map +1 -0
  41. package/dist/device/http.js +124 -0
  42. package/dist/device/http.js.map +1 -0
  43. package/dist/device/index.d.ts +5 -0
  44. package/dist/device/index.d.ts.map +1 -0
  45. package/dist/device/index.js +27 -0
  46. package/dist/device/index.js.map +1 -0
  47. package/dist/device/protocol.d.ts +312 -0
  48. package/dist/device/protocol.d.ts.map +1 -0
  49. package/dist/device/protocol.js +435 -0
  50. package/dist/device/protocol.js.map +1 -0
  51. package/dist/identities.d.ts +9 -2
  52. package/dist/identities.d.ts.map +1 -1
  53. package/dist/identities.js +33 -3
  54. package/dist/identities.js.map +1 -1
  55. package/dist/identity.d.ts +155 -0
  56. package/dist/identity.d.ts.map +1 -0
  57. package/dist/identity.js +196 -0
  58. package/dist/identity.js.map +1 -0
  59. package/dist/identityShare.d.ts +129 -0
  60. package/dist/identityShare.d.ts.map +1 -0
  61. package/dist/identityShare.js +308 -0
  62. package/dist/identityShare.js.map +1 -0
  63. package/dist/ids.d.ts +11 -0
  64. package/dist/ids.d.ts.map +1 -0
  65. package/dist/ids.js +17 -0
  66. package/dist/ids.js.map +1 -0
  67. package/dist/index.d.ts +13 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +13 -0
  70. package/dist/index.js.map +1 -1
  71. package/dist/reconcile.d.ts +25 -0
  72. package/dist/reconcile.d.ts.map +1 -0
  73. package/dist/reconcile.js +60 -0
  74. package/dist/reconcile.js.map +1 -0
  75. package/dist/recovery.d.ts +51 -0
  76. package/dist/recovery.d.ts.map +1 -0
  77. package/dist/recovery.js +59 -0
  78. package/dist/recovery.js.map +1 -0
  79. package/dist/register.d.ts +32 -0
  80. package/dist/register.d.ts.map +1 -0
  81. package/dist/register.js +65 -0
  82. package/dist/register.js.map +1 -0
  83. package/dist/scriptJob.d.ts +92 -0
  84. package/dist/scriptJob.d.ts.map +1 -0
  85. package/dist/scriptJob.js +270 -0
  86. package/dist/scriptJob.js.map +1 -0
  87. package/dist/sessions.d.ts +131 -0
  88. package/dist/sessions.d.ts.map +1 -0
  89. package/dist/sessions.js +240 -0
  90. package/dist/sessions.js.map +1 -0
  91. package/dist/socket.d.ts +115 -0
  92. package/dist/socket.d.ts.map +1 -0
  93. package/dist/socket.js +1038 -0
  94. package/dist/socket.js.map +1 -0
  95. package/dist/webhook.d.ts +613 -24
  96. package/dist/webhook.d.ts.map +1 -1
  97. package/dist/webhook.js +1384 -83
  98. package/dist/webhook.js.map +1 -1
  99. package/dist/work.d.ts +57 -0
  100. package/dist/work.d.ts.map +1 -0
  101. package/dist/work.js +213 -0
  102. package/dist/work.js.map +1 -0
  103. package/package.json +26 -4
@@ -0,0 +1,155 @@
1
+ /**
2
+ * The fixed set of CLAIM sections an agent may set about itself via
3
+ * `identity.set` in R1. Per the plan (section 2): "Claim sections (name,
4
+ * bio, link, avatar, category, price, funding disclosure) are editable by
5
+ * their subject." Keyed here the way salt-api's registry names them
6
+ * (snake_case, matching the agent's own existing field names where one
7
+ * already exists -- `display_name`, `message_price` -- rather than the
8
+ * plan's prose shorthand).
9
+ */
10
+ export declare const AGENT_CLAIM_SECTION_KEYS: readonly ["display_name", "bio", "link", "avatar", "category", "message_price", "funding_disclosure"];
11
+ export type AgentClaimSectionKey = (typeof AGENT_CLAIM_SECTION_KEYS)[number];
12
+ /** One line of an agent's "What I can do" list (salt-api 0.107.0): a title of at most 60 characters and an optional one-line detail of at most 120. */
13
+ export interface Capability {
14
+ title: string;
15
+ detail?: string;
16
+ }
17
+ /** At most this many capabilities; salt-api refuses more. */
18
+ export declare const MAX_CAPABILITIES = 5;
19
+ /**
20
+ * What `identity.set` accepts: any subset of the fixed claim vocabulary,
21
+ * each a plain string value, plus `capabilities` -- the agent's "What I can
22
+ * do" list, which is what visitors see on its card and what its A2A card's
23
+ * `skills` are generated from.
24
+ */
25
+ export type IdentityClaims = Partial<Record<AgentClaimSectionKey, string>> & {
26
+ capabilities?: Capability[];
27
+ };
28
+ /**
29
+ * The PROOF sections a card or an identity response can carry, for
30
+ * reference -- these are never written through this SDK. Kept here (not
31
+ * just in a comment) so a caller can check `PROOF_SECTION_KEYS.includes(key)`
32
+ * instead of hardcoding the list a second time.
33
+ */
34
+ export declare const PROOF_SECTION_KEYS: readonly ["pgp_fingerprint", "salt_did", "verified_did", "health", "trust_score", "rail_address"];
35
+ export type ProofSectionKey = (typeof PROOF_SECTION_KEYS)[number];
36
+ export type IdentitySectionKind = "claim" | "proof";
37
+ /**
38
+ * One row of the OWNER's own identity view (`GET /api/v1/identity` /
39
+ * `PATCH /api/v1/identity/sections`) -- richer than what a public card
40
+ * serves, since only the subject (or Salt, for a proof) ever sees `scope`,
41
+ * `editable_by`, `checked_by`.
42
+ */
43
+ export interface IdentitySection {
44
+ key: string;
45
+ label: string;
46
+ value: string | null;
47
+ /** "everyone" in R1 -- other scopes (`verified contacts`, `named`, `nobody`) ship in R2. */
48
+ scope: string;
49
+ kind: IdentitySectionKind;
50
+ /** Who may edit this section's value -- null/absent for a proof. */
51
+ editable_by?: string | null;
52
+ /** Who checked and signed this section -- null/absent for a claim. */
53
+ checked_by?: string | null;
54
+ }
55
+ export interface IdentitySections {
56
+ sections: IdentitySection[];
57
+ /** The public, signed card this identity is served as -- see `card()`. */
58
+ card_url: string;
59
+ }
60
+ export interface CardSaltIdentity {
61
+ did?: string;
62
+ pgpFingerprint?: string;
63
+ /** Present only once Salt has actually verified a DIFFERENT, externally-verified identity for the subject. */
64
+ verifiedDid?: string;
65
+ }
66
+ /**
67
+ * One section as it rides on a PUBLIC signed card: just `{key, value,
68
+ * proof}`. `proof` is `null` for a claim; any other value marks a proof
69
+ * section Salt itself checked and signed ("Checked by Salt.", plan section
70
+ * 6) -- this SDK never inspects what shape a non-null proof takes, since
71
+ * that is Salt's business, not the reader's.
72
+ */
73
+ export interface CardSection {
74
+ key: string;
75
+ value: string | null;
76
+ proof: unknown;
77
+ }
78
+ export interface CardSignatureEntry {
79
+ protected: string;
80
+ signature: string;
81
+ }
82
+ /**
83
+ * The shape `AgentCardSigner.sign` produces: an A2A AgentCard (or, once
84
+ * `GET /api/v1/users/:username/card.json` ships, the same shape for a
85
+ * person) plus `sections` and, when a signing key is configured,
86
+ * `signatures`. Left open (`[key: string]: unknown`) for every other A2A
87
+ * field (`name`, `description`, `supportedInterfaces`, `capabilities`,
88
+ * `skills`, ...) this module has no reason to type narrowly.
89
+ */
90
+ export interface SignedCard {
91
+ saltIdentity?: CardSaltIdentity;
92
+ sections?: CardSection[];
93
+ signatures?: CardSignatureEntry[];
94
+ [key: string]: unknown;
95
+ }
96
+ /** Thrown by `verifySignedCard` (and so by `client.card()`) for any card whose signature this SDK cannot confirm -- untrusted, tampered, unsigned, or signed by a key this deployment doesn't publish. Never returned as `verified: false`; a card either verifies or this throws. */
97
+ export declare class IdentityCardInvalidError extends Error {
98
+ constructor(message: string);
99
+ }
100
+ /** One entry of the Web Bot Auth key directory (`/.well-known/http-message-signatures-directory`) -- see salt-api's `SaltSigningKey#public_jwk`. */
101
+ export interface Ed25519Jwk {
102
+ kty: string;
103
+ crv: string;
104
+ kid?: string;
105
+ x: string;
106
+ }
107
+ export declare class JcsUnsupportedValueError extends Error {
108
+ }
109
+ /**
110
+ * Canonicalizes `value` exactly the way salt-api's `Jcs.canonicalize` does:
111
+ * object keys sorted by UTF-16 code unit (plain `Array#sort` on strings
112
+ * already does this in JS, matching Ruby's default `String#<=>` for the
113
+ * ASCII-only keys a card uses), no whitespace, integers as bare digits,
114
+ * strings via JSON string escaping, and a hard refusal on anything else
115
+ * (a non-integer number, undefined, a function) rather than guessing at a
116
+ * serialization another implementation wouldn't match.
117
+ */
118
+ export declare function canonicalizeJcs(value: unknown): string;
119
+ export declare function base64urlEncode(bytes: Buffer): string;
120
+ export declare function base64urlDecode(str: string): Buffer;
121
+ export interface CardSignatureHeader {
122
+ alg?: string;
123
+ kid?: string;
124
+ }
125
+ /**
126
+ * Parses (never verifies) `card`'s first signature's protected header --
127
+ * just enough to read `kid` without a network round trip. Used by
128
+ * `client.card()` to notice a kid its cached key set doesn't have (Salt
129
+ * rotated its signing key since the last directory fetch) and force one
130
+ * refetch BEFORE spending a verification attempt that would otherwise fail
131
+ * for a perfectly legitimate card. Returns undefined for a card with no
132
+ * signature at all or an unparseable header -- `verifySignedCard` raises
133
+ * the actual, specific error for those cases at verify time; this helper
134
+ * only ever informs a caching decision.
135
+ */
136
+ export declare function parseCardSignatureHeader(card: SignedCard): CardSignatureHeader | undefined;
137
+ /**
138
+ * Verifies `card`'s first signature against the Web Bot Auth key directory
139
+ * entries in `jwks`, reconstructing the signing input exactly the way
140
+ * `AgentCardSigner.verify` does server-side: `protected_b64` is reused
141
+ * verbatim from the card (never recomputed -- only the payload is), the
142
+ * payload is the JCS canonicalization of the card with `signatures`
143
+ * removed, and the whole thing is Ed25519-verified with no digest
144
+ * (RFC 8032 pure EdDSA, not Ed25519ph).
145
+ *
146
+ * Throws `IdentityCardInvalidError` for every failure mode -- no signature
147
+ * at all, an unparseable protected header, an unsupported algorithm, no
148
+ * matching published key, or a signature that doesn't match -- so a caller
149
+ * never has to remember to check a boolean before trusting the result. This
150
+ * function itself never refetches anything -- see `parseCardSignatureHeader`
151
+ * for the kid-rotation retry, which happens in client.ts BEFORE this is
152
+ * called a second time with a freshened `jwks`.
153
+ */
154
+ export declare function verifySignedCard(card: SignedCard, jwks: Ed25519Jwk[]): void;
155
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ // Identity on Salt (design-fleet/runs/2026-09-22-identity/plan.md): the
3
+ // signed card Salt already serves for agents (A2A AgentCard, 0.72.0) made
4
+ // editable, section by section. This is R1 only: `identity.set`/`identity.get`
5
+ // on the SDK surface (plan section 7) -- reading/writing an agent's own
6
+ // CLAIM sections, and fetching + verifying anyone's signed public card.
7
+ // `identity.share` (an E2E slice into a chat) and `onIdentityAsk` are later
8
+ // releases, and there is deliberately no `setScope` here at all: scope is
9
+ // owner-authenticated through the agent-management API only (an agent may
10
+ // state a claim, never decide who else gets to see it).
11
+ //
12
+ // The card vocabulary is fixed (plan section 9.5 -- "like the Cards block
13
+ // vocabulary; a new section is a release"), split into two kinds:
14
+ // - CLAIM sections: the subject's own word about themselves. An agent may
15
+ // set its own claim sections via `identity.set`. Never signed as true --
16
+ // only signed as "this is what they said".
17
+ // - PROOF sections (pgp fingerprint, Salt DID, verified DID, health, trust
18
+ // score, rail address): read-only, computed and signed by Salt itself.
19
+ // No client-side API sets these -- they exist here only so a reader of
20
+ // a fetched card can tell a proof row from a claim row and never launder
21
+ // one as the other (plan section 6: "A proof glyph on a claim row would
22
+ // launder the claim").
23
+ //
24
+ // Card signing (see salt-api's AgentCardSigner + Jcs + SaltSigningKey,
25
+ // read to get these bytes exactly right): a JWS-shaped (RFC 7515)
26
+ // signature over the card's own RFC 8785 canonical JSON (JCS), flattened
27
+ // without a `payload` field -- the payload IS the card itself, minus
28
+ // `signatures`. `canonicalizeJcs` below is a deliberately narrow port of
29
+ // salt-api's Jcs.rb: only what an identity card ever contains (nested
30
+ // objects/arrays, strings, booleans, null, integers), sorted by UTF-16
31
+ // code unit (JS's default string sort already does this for the plain
32
+ // ASCII keys a card uses). A float reaching it is a bug in the caller, so
33
+ // it throws rather than guessing at a serialization another implementation
34
+ // wouldn't match.
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.JcsUnsupportedValueError = exports.IdentityCardInvalidError = exports.PROOF_SECTION_KEYS = exports.MAX_CAPABILITIES = exports.AGENT_CLAIM_SECTION_KEYS = void 0;
37
+ exports.canonicalizeJcs = canonicalizeJcs;
38
+ exports.base64urlEncode = base64urlEncode;
39
+ exports.base64urlDecode = base64urlDecode;
40
+ exports.parseCardSignatureHeader = parseCardSignatureHeader;
41
+ exports.verifySignedCard = verifySignedCard;
42
+ const node_crypto_1 = require("node:crypto");
43
+ // --- Section vocabulary --------------------------------------------------
44
+ /**
45
+ * The fixed set of CLAIM sections an agent may set about itself via
46
+ * `identity.set` in R1. Per the plan (section 2): "Claim sections (name,
47
+ * bio, link, avatar, category, price, funding disclosure) are editable by
48
+ * their subject." Keyed here the way salt-api's registry names them
49
+ * (snake_case, matching the agent's own existing field names where one
50
+ * already exists -- `display_name`, `message_price` -- rather than the
51
+ * plan's prose shorthand).
52
+ */
53
+ exports.AGENT_CLAIM_SECTION_KEYS = [
54
+ "display_name",
55
+ "bio",
56
+ "link",
57
+ "avatar",
58
+ "category",
59
+ "message_price",
60
+ "funding_disclosure",
61
+ ];
62
+ /** At most this many capabilities; salt-api refuses more. */
63
+ exports.MAX_CAPABILITIES = 5;
64
+ /**
65
+ * The PROOF sections a card or an identity response can carry, for
66
+ * reference -- these are never written through this SDK. Kept here (not
67
+ * just in a comment) so a caller can check `PROOF_SECTION_KEYS.includes(key)`
68
+ * instead of hardcoding the list a second time.
69
+ */
70
+ exports.PROOF_SECTION_KEYS = [
71
+ "pgp_fingerprint",
72
+ "salt_did",
73
+ "verified_did",
74
+ "health",
75
+ "trust_score",
76
+ "rail_address",
77
+ ];
78
+ /** Thrown by `verifySignedCard` (and so by `client.card()`) for any card whose signature this SDK cannot confirm -- untrusted, tampered, unsigned, or signed by a key this deployment doesn't publish. Never returned as `verified: false`; a card either verifies or this throws. */
79
+ class IdentityCardInvalidError extends Error {
80
+ constructor(message) {
81
+ super(message);
82
+ this.name = "IdentityCardInvalid";
83
+ }
84
+ }
85
+ exports.IdentityCardInvalidError = IdentityCardInvalidError;
86
+ // --- RFC 8785 JCS (narrow port of salt-api's Jcs.rb) ---------------------
87
+ class JcsUnsupportedValueError extends Error {
88
+ }
89
+ exports.JcsUnsupportedValueError = JcsUnsupportedValueError;
90
+ /**
91
+ * Canonicalizes `value` exactly the way salt-api's `Jcs.canonicalize` does:
92
+ * object keys sorted by UTF-16 code unit (plain `Array#sort` on strings
93
+ * already does this in JS, matching Ruby's default `String#<=>` for the
94
+ * ASCII-only keys a card uses), no whitespace, integers as bare digits,
95
+ * strings via JSON string escaping, and a hard refusal on anything else
96
+ * (a non-integer number, undefined, a function) rather than guessing at a
97
+ * serialization another implementation wouldn't match.
98
+ */
99
+ function canonicalizeJcs(value) {
100
+ if (value === null)
101
+ return "null";
102
+ if (typeof value === "boolean")
103
+ return value ? "true" : "false";
104
+ if (typeof value === "string")
105
+ return JSON.stringify(value);
106
+ if (typeof value === "number") {
107
+ if (!Number.isInteger(value)) {
108
+ throw new JcsUnsupportedValueError(`canonicalizeJcs: unsupported non-integer number ${value}`);
109
+ }
110
+ return String(value);
111
+ }
112
+ if (Array.isArray(value)) {
113
+ return "[" + value.map((v) => canonicalizeJcs(v)).join(",") + "]";
114
+ }
115
+ if (typeof value === "object") {
116
+ const obj = value;
117
+ const keys = Object.keys(obj).sort();
118
+ return "{" + keys.map((k) => `${JSON.stringify(k)}:${canonicalizeJcs(obj[k])}`).join(",") + "}";
119
+ }
120
+ throw new JcsUnsupportedValueError(`canonicalizeJcs: unsupported value of type ${typeof value}`);
121
+ }
122
+ // --- base64url (no padding), matching SaltSigningKey.b64/unb64 ----------
123
+ function base64urlEncode(bytes) {
124
+ return bytes.toString("base64url");
125
+ }
126
+ function base64urlDecode(str) {
127
+ return Buffer.from(str, "base64url");
128
+ }
129
+ /**
130
+ * Parses (never verifies) `card`'s first signature's protected header --
131
+ * just enough to read `kid` without a network round trip. Used by
132
+ * `client.card()` to notice a kid its cached key set doesn't have (Salt
133
+ * rotated its signing key since the last directory fetch) and force one
134
+ * refetch BEFORE spending a verification attempt that would otherwise fail
135
+ * for a perfectly legitimate card. Returns undefined for a card with no
136
+ * signature at all or an unparseable header -- `verifySignedCard` raises
137
+ * the actual, specific error for those cases at verify time; this helper
138
+ * only ever informs a caching decision.
139
+ */
140
+ function parseCardSignatureHeader(card) {
141
+ const sigEntry = card.signatures?.[0];
142
+ if (!sigEntry?.protected)
143
+ return undefined;
144
+ try {
145
+ return JSON.parse(base64urlDecode(sigEntry.protected).toString("utf8"));
146
+ }
147
+ catch {
148
+ return undefined;
149
+ }
150
+ }
151
+ /**
152
+ * Verifies `card`'s first signature against the Web Bot Auth key directory
153
+ * entries in `jwks`, reconstructing the signing input exactly the way
154
+ * `AgentCardSigner.verify` does server-side: `protected_b64` is reused
155
+ * verbatim from the card (never recomputed -- only the payload is), the
156
+ * payload is the JCS canonicalization of the card with `signatures`
157
+ * removed, and the whole thing is Ed25519-verified with no digest
158
+ * (RFC 8032 pure EdDSA, not Ed25519ph).
159
+ *
160
+ * Throws `IdentityCardInvalidError` for every failure mode -- no signature
161
+ * at all, an unparseable protected header, an unsupported algorithm, no
162
+ * matching published key, or a signature that doesn't match -- so a caller
163
+ * never has to remember to check a boolean before trusting the result. This
164
+ * function itself never refetches anything -- see `parseCardSignatureHeader`
165
+ * for the kid-rotation retry, which happens in client.ts BEFORE this is
166
+ * called a second time with a freshened `jwks`.
167
+ */
168
+ function verifySignedCard(card, jwks) {
169
+ const sigEntry = card.signatures?.[0];
170
+ if (!sigEntry || !sigEntry.protected || !sigEntry.signature) {
171
+ throw new IdentityCardInvalidError("This card carries no signature -- Salt has not signed it (signing may be unconfigured on this deployment, or this isn't really a Salt identity card).");
172
+ }
173
+ const header = parseCardSignatureHeader(card);
174
+ if (!header) {
175
+ throw new IdentityCardInvalidError("This card's signature header could not be parsed.");
176
+ }
177
+ if (header.alg !== "EdDSA") {
178
+ throw new IdentityCardInvalidError(`This card is signed with an unsupported algorithm (${header.alg ?? "none"}); only EdDSA (Ed25519) is trusted.`);
179
+ }
180
+ const key = jwks.find((k) => k.kid === header.kid && k.kty === "OKP" && k.crv === "Ed25519");
181
+ if (!key) {
182
+ throw new IdentityCardInvalidError(`No published Salt key matches this card's signing key id (${header.kid ?? "unknown"}).`);
183
+ }
184
+ const { signatures: _signatures, ...unsigned } = card;
185
+ const payloadB64 = base64urlEncode(Buffer.from(canonicalizeJcs(unsigned), "utf8"));
186
+ const signingInput = Buffer.from(`${sigEntry.protected}.${payloadB64}`, "utf8");
187
+ const signatureBytes = base64urlDecode(sigEntry.signature);
188
+ const publicKey = (0, node_crypto_1.createPublicKey)({ key: { kty: "OKP", crv: "Ed25519", x: key.x }, format: "jwk" });
189
+ // No digest -- Ed25519 (pure EdDSA) signs the message directly, mirroring
190
+ // SaltSigningKey#sign/#verify server-side (`@pkey.sign(nil, message)`).
191
+ const ok = (0, node_crypto_1.verify)(null, signingInput, publicKey, signatureBytes);
192
+ if (!ok) {
193
+ throw new IdentityCardInvalidError("This card's signature does not match its contents -- it may have been tampered with.");
194
+ }
195
+ }
196
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import type { IdentityDisclosure, SaltClient } from "./client";
2
+ import { type CardSection } from "./identity.js";
3
+ import type { AgentIdentity } from "./identities";
4
+ import { type SaltId } from "./ids.js";
5
+ /** Every SALT-IDENTITY-* marker starts with this -- webhook.ts checks it before attempting the more specific parse, the same way it gates on delegations.FLOOR_REQUEST_MARKER. */
6
+ export declare const IDENTITY_MARKER_PREFIX = "[[SALT-IDENTITY-";
7
+ export interface IdentitySlicePayload {
8
+ sections: CardSection[];
9
+ signature: string;
10
+ }
11
+ export type ParsedIdentityMarker = {
12
+ kind: "ask";
13
+ id: string;
14
+ keys: string[];
15
+ text?: string;
16
+ } | {
17
+ kind: "slice";
18
+ id: string;
19
+ askId?: string;
20
+ payload: IdentitySlicePayload;
21
+ } | {
22
+ kind: "decline";
23
+ id: string;
24
+ askId?: string;
25
+ } | {
26
+ kind: "revoke";
27
+ id: string;
28
+ };
29
+ /**
30
+ * Parses one SALT-IDENTITY-* marker (plus, for SLICE, its JSON line) out of
31
+ * a decrypted plaintext. Returns null for anything that isn't one of these
32
+ * four markers, or that starts as one but is malformed (a bad id, an ASK
33
+ * with no keys, a SLICE whose JSON doesn't parse into {sections,
34
+ * signature}) -- webhook.ts treats either case as "starts with the prefix
35
+ * but nothing usable came out of it" and drops the message rather than
36
+ * guessing.
37
+ */
38
+ export declare function parseIdentityMarker(plaintext: string): ParsedIdentityMarker | null;
39
+ /** `[[SALT-IDENTITY-ASK id=… keys=k1,k2]]`, optionally followed by a text line. */
40
+ export declare function formatIdentityAsk(id: string, keys: string[], text?: string): string;
41
+ /** `[[SALT-IDENTITY-SLICE id=… [ask=…]]]` followed by the {sections, signature} JSON line. */
42
+ export declare function formatIdentitySlice(id: string, sections: CardSection[], signature: string, askId?: string): string;
43
+ /** `[[SALT-IDENTITY-DECLINE id=… [ask=…]]]`. */
44
+ export declare function formatIdentityDecline(id: string, askId?: string): string;
45
+ /** `[[SALT-IDENTITY-REVOKE id=…]]`. */
46
+ export declare function formatIdentityRevoke(id: string): string;
47
+ export interface IdentityAskInfo {
48
+ id: string;
49
+ keys: string[];
50
+ text?: string;
51
+ chatId: SaltId;
52
+ from: SaltId;
53
+ }
54
+ /**
55
+ * Handed to `onIdentityAsk`. Return the subset of `info.keys` to share
56
+ * (shares those, replying with a SLICE carrying `ask=info.id`) or
57
+ * `null`/`false` (sends a DECLINE carrying `ask=info.id`). Returning an
58
+ * empty array behaves like declining -- there is nothing to build a slice
59
+ * from. Leaving `onIdentityAsk` unset entirely means an incoming ask is
60
+ * never intercepted at all: it reaches `onMessage` as ordinary text with
61
+ * just the marker line stripped (see webhook.ts), unanswered.
62
+ */
63
+ export type IdentityAskHandler = (info: IdentityAskInfo) => Promise<string[] | null | false | undefined> | string[] | null | false | undefined;
64
+ export interface IdentitySliceEvent {
65
+ kind: "slice";
66
+ id: string;
67
+ askId?: string;
68
+ from: SaltId;
69
+ chatId: SaltId;
70
+ sections: CardSection[];
71
+ /** True only when the signature verified against the sender's own public key (fetched fresh from the chat's member list). False for a bad/missing signature, an unknown sender key, or a verification that itself failed -- never thrown. */
72
+ verified: boolean;
73
+ }
74
+ export interface IdentityDeclineEvent {
75
+ kind: "decline";
76
+ id: string;
77
+ askId?: string;
78
+ from: SaltId;
79
+ chatId: SaltId;
80
+ }
81
+ export interface IdentityRevokeEvent {
82
+ kind: "revoke";
83
+ id: string;
84
+ from: SaltId;
85
+ chatId: SaltId;
86
+ }
87
+ export type IdentitySharedEvent = IdentitySliceEvent | IdentityDeclineEvent | IdentityRevokeEvent;
88
+ /** Handed every incoming SLICE, DECLINE and REVOKE from someone else -- never called for this identity's own outgoing messages. None of the three ever reach `onMessage`. */
89
+ export type IdentitySharedHandler = (event: IdentitySharedEvent) => Promise<void> | void;
90
+ export interface ShareOptions {
91
+ /** Set when this share answers an incoming SALT-IDENTITY-ASK -- rides on the SLICE marker as `ask=`. */
92
+ ask?: string;
93
+ }
94
+ export interface ShareResult {
95
+ /** Names the whole share -- what rides on the wire SLICE's `id=`, what every ledger row was posted under, and what `revoke(id)` takes to pull it all back at once. */
96
+ id: string;
97
+ messageId: SaltId;
98
+ /** Every non-observer chat member other than the caller this was disclosed to, in the same order client.getChatMembers returned -- one ledger row was written per entry, all under `id`. */
99
+ recipients: SaltId[];
100
+ }
101
+ export interface IdentitySharer {
102
+ /**
103
+ * Shares `keys` from this agent's own identity into `chatId`: ONE fresh
104
+ * id for the whole share, one ledger row posted under it per
105
+ * non-observer member other than the caller (salt-api keys a row on
106
+ * subject + recipient + id, so this is the same id every time; aborts
107
+ * on the first refusal with nothing sent), then ONE signed, encrypted
108
+ * SLICE message carrying that id to the whole chat, then a single
109
+ * message_id PATCH (every row shares the id, so one PATCH reaches all
110
+ * of them).
111
+ */
112
+ share(caller: AgentIdentity, chatId: SaltId, keys: string[], opts?: ShareOptions): Promise<ShareResult>;
113
+ /** Sends an ASK for `keys` into a 1:1 chat and returns its id. Refuses (before sending anything) outside a 1:1. */
114
+ ask(caller: AgentIdentity, chatId: SaltId, keys: string[], text?: string): Promise<string>;
115
+ /** Sends a bare DECLINE (optionally answering `askId`) with no ledger row -- there is nothing to disclose. Returns the decline message's own id. */
116
+ decline(caller: AgentIdentity, chatId: SaltId, askId?: string): Promise<{
117
+ id: string;
118
+ }>;
119
+ /** This agent's own disclosure ledger, newest first. */
120
+ disclosures(caller: AgentIdentity, opts?: {
121
+ before?: string;
122
+ limit?: number;
123
+ }): Promise<IdentityDisclosure[]>;
124
+ /** Revokes every ledger row under `id` (the id `share()` returned) in one call, then sends a REVOKE marker into the chat it was disclosed in. */
125
+ revoke(caller: AgentIdentity, id: string): Promise<IdentityDisclosure[]>;
126
+ }
127
+ /** Builds the {share, ask, decline, disclosures, revoke} surface bound to one client. */
128
+ export declare function createIdentitySharer(client: SaltClient, pgpPassphrase: string): IdentitySharer;
129
+ //# sourceMappingURL=identityShare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identityShare.d.ts","sourceRoot":"","sources":["../src/identityShare.ts"],"names":[],"mappings":"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"}