@the-ai-company/cbio-node-runtime 0.39.0 → 1.0.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 (113) hide show
  1. package/README.md +116 -54
  2. package/dist/clients/agent/client.d.ts +9 -0
  3. package/dist/clients/agent/client.js +72 -0
  4. package/dist/clients/agent/client.js.map +1 -0
  5. package/dist/clients/agent/contracts.d.ts +34 -0
  6. package/dist/clients/agent/contracts.js +2 -0
  7. package/dist/clients/agent/contracts.js.map +1 -0
  8. package/dist/clients/agent/index.d.ts +3 -0
  9. package/dist/clients/agent/index.js +2 -0
  10. package/dist/clients/agent/index.js.map +1 -0
  11. package/dist/clients/owner/client.d.ts +18 -0
  12. package/dist/clients/owner/client.js +169 -0
  13. package/dist/clients/owner/client.js.map +1 -0
  14. package/dist/clients/owner/contracts.d.ts +34 -0
  15. package/dist/clients/owner/contracts.js +2 -0
  16. package/dist/clients/owner/contracts.js.map +1 -0
  17. package/dist/clients/owner/index.d.ts +3 -0
  18. package/dist/clients/owner/index.js +2 -0
  19. package/dist/clients/owner/index.js.map +1 -0
  20. package/dist/runtime/index.d.ts +8 -10
  21. package/dist/runtime/index.js +8 -7
  22. package/dist/runtime/index.js.map +1 -1
  23. package/dist/storage/fs.d.ts +1 -0
  24. package/dist/storage/fs.js +28 -0
  25. package/dist/storage/fs.js.map +1 -1
  26. package/dist/storage/memory.d.ts +1 -0
  27. package/dist/storage/memory.js +20 -0
  28. package/dist/storage/memory.js.map +1 -1
  29. package/dist/storage/provider.d.ts +2 -0
  30. package/dist/vault-core/contracts.d.ts +230 -0
  31. package/dist/vault-core/contracts.js +2 -0
  32. package/dist/vault-core/contracts.js.map +1 -0
  33. package/dist/vault-core/core.d.ts +21 -0
  34. package/dist/vault-core/core.js +335 -0
  35. package/dist/vault-core/core.js.map +1 -0
  36. package/dist/vault-core/defaults.d.ts +141 -0
  37. package/dist/vault-core/defaults.js +602 -0
  38. package/dist/vault-core/defaults.js.map +1 -0
  39. package/dist/vault-core/errors.d.ts +4 -0
  40. package/dist/vault-core/errors.js +9 -0
  41. package/dist/vault-core/errors.js.map +1 -0
  42. package/dist/vault-core/index.d.ts +6 -0
  43. package/dist/vault-core/index.js +5 -0
  44. package/dist/vault-core/index.js.map +1 -0
  45. package/dist/vault-core/persistence.d.ts +87 -0
  46. package/dist/vault-core/persistence.js +309 -0
  47. package/dist/vault-core/persistence.js.map +1 -0
  48. package/dist/vault-core/ports.d.ts +101 -0
  49. package/dist/vault-core/ports.js +2 -0
  50. package/dist/vault-core/ports.js.map +1 -0
  51. package/dist/vault-ingress/defaults.d.ts +14 -0
  52. package/dist/vault-ingress/defaults.js +41 -0
  53. package/dist/vault-ingress/defaults.js.map +1 -0
  54. package/dist/vault-ingress/flow-factories.d.ts +24 -0
  55. package/dist/vault-ingress/flow-factories.js +48 -0
  56. package/dist/vault-ingress/flow-factories.js.map +1 -0
  57. package/dist/vault-ingress/index.d.ts +81 -0
  58. package/dist/vault-ingress/index.js +357 -0
  59. package/dist/vault-ingress/index.js.map +1 -0
  60. package/docs/ARCHITECTURE.md +44 -76
  61. package/docs/REFERENCE.md +217 -218
  62. package/docs/WORKS_WITH_CUSTOM_FETCH.md +16 -191
  63. package/docs/es/README.md +8 -24
  64. package/docs/fr/README.md +8 -24
  65. package/docs/ja/README.md +8 -24
  66. package/docs/ko/README.md +8 -24
  67. package/docs/pt/README.md +8 -24
  68. package/docs/zh/README.md +21 -7
  69. package/package.json +2 -10
  70. package/dist/agent/agent.d.ts +0 -267
  71. package/dist/agent/agent.js +0 -689
  72. package/dist/agent/agent.js.map +0 -1
  73. package/dist/audit/ActivityLog.d.ts +0 -25
  74. package/dist/audit/ActivityLog.js +0 -71
  75. package/dist/audit/ActivityLog.js.map +0 -1
  76. package/dist/http/authClient.d.ts +0 -26
  77. package/dist/http/authClient.js +0 -132
  78. package/dist/http/authClient.js.map +0 -1
  79. package/dist/http/genericSecretValidator.d.ts +0 -11
  80. package/dist/http/genericSecretValidator.js +0 -42
  81. package/dist/http/genericSecretValidator.js.map +0 -1
  82. package/dist/http/localAuthProxy.d.ts +0 -33
  83. package/dist/http/localAuthProxy.js +0 -93
  84. package/dist/http/localAuthProxy.js.map +0 -1
  85. package/dist/http/localSecretIngress.d.ts +0 -33
  86. package/dist/http/localSecretIngress.js +0 -162
  87. package/dist/http/localSecretIngress.js.map +0 -1
  88. package/dist/http/secretAcquisition.d.ts +0 -54
  89. package/dist/http/secretAcquisition.js +0 -177
  90. package/dist/http/secretAcquisition.js.map +0 -1
  91. package/dist/protocol/childSecretNaming.d.ts +0 -7
  92. package/dist/protocol/childSecretNaming.js +0 -12
  93. package/dist/protocol/childSecretNaming.js.map +0 -1
  94. package/dist/protocol/identity.d.ts +0 -8
  95. package/dist/protocol/identity.js +0 -16
  96. package/dist/protocol/identity.js.map +0 -1
  97. package/dist/sealed/index.d.ts +0 -6
  98. package/dist/sealed/index.js +0 -6
  99. package/dist/sealed/index.js.map +0 -1
  100. package/dist/vault/secretPolicy.d.ts +0 -3
  101. package/dist/vault/secretPolicy.js +0 -14
  102. package/dist/vault/secretPolicy.js.map +0 -1
  103. package/dist/vault/vault.d.ts +0 -100
  104. package/dist/vault/vault.js +0 -603
  105. package/dist/vault/vault.js.map +0 -1
  106. package/docs/TODO-multi-vault.md +0 -29
  107. package/docs/spec/runtime/README.md +0 -44
  108. package/docs/spec/runtime/activity-log.md +0 -71
  109. package/docs/spec/runtime/exposure-surfaces.md +0 -99
  110. package/docs/spec/runtime/managed-agent-record.md +0 -52
  111. package/docs/spec/runtime/merge-rules.md +0 -52
  112. package/docs/spec/runtime/secret-origin-policy.md +0 -46
  113. package/docs/spec/runtime/secret-validation.md +0 -113
package/docs/REFERENCE.md CHANGED
@@ -1,291 +1,290 @@
1
- # CBIO SDK Deep Reference
1
+ # CBIO Vault Runtime Reference
2
2
 
3
- This document provides a comprehensive technical reference for the CBIO SDK, covering advanced API usage, custom storage implementation, and structured error handling.
3
+ This document describes the current implemented runtime surface.
4
4
 
5
- For high-level concepts and quick start, see [README.md](../README.md). For module structure and naming rules, see [ARCHITECTURE.md](./ARCHITECTURE.md). For cross-language runtime contracts, see [spec/runtime/README.md](./spec/runtime/README.md).
5
+ This file is intentionally narrower: it documents what the shipped API does today.
6
6
 
7
- ---
7
+ ## Public Surface
8
8
 
9
- ## 1. Advanced Identity APIs
9
+ The current top-level modules are:
10
10
 
11
- These methods are available under `identity.admin` and its sub-facets, and are intended for administrative or high-privilege bootstrap logic.
11
+ - `vault-core`
12
+ - `vault-ingress`
13
+ - `clients/owner`
14
+ - `clients/agent`
12
15
 
13
- ### 1.1 Vault Synchronization & Merging
14
- - **`identity.admin.vault.mergeFrom(otherIdentity, options?)`**: Atomically merges secrets from another vault.
15
- - `onConflict`: `'abort'` (default), `'skip'`, or `'overwrite'`.
16
- - Throws `MERGE_IDENTITY_MISMATCH` if root identities differ.
16
+ The main constructors are:
17
17
 
18
- ### 1.2 Backups & Sealing
19
- - **`identity.admin.vault.seal(kdk: string): string`**: Exports the entire vault as an encrypted blob.
20
- - **`identity.admin.vault.loadFromSealedBlob(kdk: string, blob: string)`**: Restores a vault from a sealed backup.
21
- - **`identity.admin.vault.saveVault()`**: Persists the current vault back to its bound storage.
22
- - **`identity.admin.vault.saveVaultAs(storageKey)`**: One-time save of the vault to an explicit key/path. Does NOT change the bound storage for subsequent `saveVault()` or autosave.
18
+ - `createVaultCore(...)`
19
+ - `createVaultService(...)`
20
+ - `createOwnerClient(...)`
21
+ - `createAgentClient(...)`
22
+ - `LocalVaultTransport`
23
23
 
24
- Lower-level sealed blob primitives are also exported from the package subpath:
24
+ ## Secret-Flow Model
25
25
 
26
- ```ts
27
- import { sealBlob, unsealBlob } from '@the-ai-company/cbio-node-runtime/sealed';
28
- ```
26
+ The current HTTP-facing API supports two explicit secret-flow classes:
29
27
 
30
- ### 1.3 Audit & Lifecycle
31
- - **`identity.admin.vault.getActivityLog()`**: Returns a read-only list of all vault-authenticated actions.
32
- - **`identity.admin.managedAgents.revokeManagedAgent(publicKey, reason?)`**: Permanently revokes a child identity.
33
- - **`identity.admin.managedAgents.getManagedAgentCapabilities(publicKey)`**: Returns `{ status, capabilities }` for a managed agent, so callers can distinguish active, revoked, missing, and invalid records.
28
+ - `acquire_secret`
29
+ No secret leaves the vault. A response-derived secret is stored into the vault. Agent-visible output is limited to protocol metadata and a redacted response shape.
34
30
 
35
- ### 1.4 Agent Handles
36
- - **`getAgent()`**: Returns a minimally privileged handle with `vault:fetch` and `vault:list`.
37
- - **`getAgent({ permissions })`**: Returns a handle with explicitly provided runtime permissions.
38
- - **`getAgent({ deriveFromIssuedIdentity: true })`**: Derives runtime permissions from the issued identity's protocol capabilities.
31
+ - `send_secret`
32
+ A stored secret is sent to an owner-approved target. The remote response is treated as normal business output and may be returned to the agent.
39
33
 
40
- `permissions` and `deriveFromIssuedIdentity` are mutually exclusive; do not pass both.
34
+ This is a deliberate protocol boundary:
41
35
 
42
- Secret-use operations on a `CbioAgent` require:
43
- - `vault:fetch` for remote authenticated use such as `fetchWithAuth(...)`
44
- - `vault:acquire` for acquisition, ingress, compare, proof, and validation operations
36
+ - acquisition responses are assumed sensitive and are therefore redacted on the way back to the agent
37
+ - dispatch responses are treated as ordinary HTTP results once the owner has authorized sending the secret to that target
45
38
 
46
- ### 1.5 Recursive Child Identity Management
47
- When a child is registered via `registerChildIdentity(keys)`, its key material is stored in the parent vault. The method returns `{ publicKey }` (domain-level identifier). Treat the persisted child record as runtime-managed state rather than application-readable plaintext.
48
- ```ts
49
- const { publicKey: childPublicKey } = await identity.registerChildIdentity(keys);
50
- console.log(childPublicKey);
51
- ```
39
+ The runtime does not try to reinterpret every remote protocol. If an approved target returns sensitive values during a normal dispatch call, that is part of the target contract and owner authorization scope rather than a vault-side parsing obligation.
52
40
 
53
- ---
41
+ The runtime does not claim to understand arbitrary network protocols. The API communicates only the currently supported boundary:
54
42
 
55
- ## 2. Storage Customization
43
+ - supported: explicit acquisition into vault through built-in standard flows
44
+ - supported: explicit secret-backed outbound dispatch
45
+ - supported: owner-defined `custom_http` flows for explicit exception cases
46
+ - unsupported: mixed bidirectional-secret flows as a first-class surface
47
+ - unsupported: no-secret operations as a first-class vault primitive
56
48
 
57
- The SDK can run on any backend by implementing the `IStorageProvider` interface.
49
+ ## Vault Service
58
50
 
59
- ### 2.1 Interface Definition
60
- ```ts
61
- export interface IStorageProvider {
62
- read(key: string): Promise<Buffer | null>;
63
- write(key: string, data: Buffer): Promise<void>;
64
- delete(key: string): Promise<void>;
65
- has(key: string): Promise<boolean>;
66
- rename?(fromKey: string, toKey: string): Promise<void>; // Improves atomic writes
67
- }
68
- ```
51
+ `vault-ingress` is the request-shaped boundary around the vault kernel.
69
52
 
70
- ### 2.2 Pre-built Providers
71
- - **`MemoryStorageProvider`**: Ephemeral storage for testing or in-memory caches.
72
- - **Filesystem (Default)**: Persists to `~/.c-bio/`. Use `C_BIO_VAULT_DIR` environment variable to override.
53
+ Important methods:
73
54
 
74
- When loading an identity, use `storageKey` to choose the persisted vault location or provider key. Activity log behavior is configured explicitly with `activityLog`, for example `activityLog: { key: 'my-vault.activity.jsonl' }` or `activityLog: { enabled: false }`.
55
+ - `bootstrapOwnerIdentity(...)`
56
+ - `registerAgentIdentity(...)`
57
+ - `registerOwnerIdentity(...)`
58
+ - `writeSecret(...)`
59
+ - `acquireSecret(...)`
60
+ - `dispatch(...)`
61
+ - `handleAgentDispatch(...)`
62
+ - `readAudit(...)`
75
63
 
76
- ---
64
+ ### Owner Bootstrap
77
65
 
78
- ## 3. Advanced Request Patterns
66
+ The very first owner is bootstrapped explicitly:
79
67
 
80
- ### 3.1 Custom Fetch for SDKs (OpenAI/Anthropic)
81
- If a third-party SDK supports a custom `fetch` implementation, use `createFetchWithAuth`. This keeps the vault boundary while using the official client.
82
68
  ```ts
83
- const openai = new OpenAI({
84
- fetch: agent.createFetchWithAuth('openai'),
69
+ await vault.bootstrapOwnerIdentity({
70
+ vaultId: vault.vaultId,
71
+ ownerId: 'owner-1',
72
+ publicKey: ownerPublicKey,
85
73
  });
86
74
  ```
87
75
 
88
- ### 3.2 Complex HTTP Calls
89
- Use full request options for `fetchWithAuth`:
76
+ After that, additional owner and agent identities should be registered through owner-signed commands rather than direct raw records.
77
+
78
+ ## Owner Client
79
+
80
+ `clients/owner` is the owner-facing caller surface.
81
+
82
+ Current owner operations:
83
+
84
+ - `writeSecret(...)`
85
+ - `getAudit(...)`
86
+ - `registerAgentIdentity(...)`
87
+ - `registerOwnerIdentity(...)`
88
+ - `registerCustomFlow(...)`
89
+
90
+ Example:
91
+
90
92
  ```ts
91
- const response = await agent.fetchWithAuth('my-secret', 'https://api.example.com', {
92
- method: 'POST',
93
- headers: { 'Content-Type': 'application/json' },
94
- body: JSON.stringify({ key: 'value' }),
95
- authPrefix: 'Token ', // Optional: default is 'Bearer '
96
- withSignature: true, // Optional: adds X-CBIO-Signature
93
+ const owner = createOwnerClient(ownerIdentity, vault, ownerSigner, clock);
94
+
95
+ await owner.registerAgentIdentity({
96
+ agentId: 'agent-1',
97
+ publicKey: agentPublicKey,
97
98
  });
98
- ```
99
99
 
100
- ### 3.3 JSON Secret Acquisition
101
- Use `fetchJsonAndAddSecret(...)` and `fetchJsonAndUpdateSecret(...)` when the upstream returns a JSON payload that contains a secret value to store or rotate.
100
+ await owner.registerCustomFlow({
101
+ flowId: 'custom-status-read',
102
+ mode: 'send_secret',
103
+ targetUrl: 'https://api.example.com/custom-status',
104
+ method: 'POST',
105
+ responseVisibility: 'shape_only',
106
+ });
102
107
 
103
- ```ts
104
- const acquired = await agent.fetchJsonAndAddSecret({
105
- secretName: 'service-token',
106
- url: 'https://issuer.example.com/token',
107
- body: { scope: 'read' },
108
- extractKey: (response: { api_key?: string }) => response.api_key ?? '',
108
+ await owner.writeSecret({
109
+ alias: 'api-token',
110
+ plaintext: 'secret-value',
111
+ targetBindings: [
112
+ {
113
+ kind: 'site',
114
+ targetId: 'api.example.com',
115
+ targetUrl: 'https://api.example.com/endpoint',
116
+ methods: ['POST'],
117
+ },
118
+ ],
109
119
  });
110
120
  ```
111
121
 
112
- These methods are intentionally JSON-specific:
113
- - request bodies are JSON-stringified
114
- - responses are parsed with `response.json()`
115
- - `extractKey(...)` receives the parsed JSON body
122
+ ## Agent Client
116
123
 
117
- ### 3.4 Local Auth Proxy
118
- Use `startLocalAuthProxy(...)` when a local process should forward requests to an upstream API while vault-backed auth is injected automatically.
124
+ `clients/agent` creates signed dispatch requests. It never receives plaintext secrets.
119
125
 
120
- Required fields:
121
- - `authHandle`: any object with `fetchWithAuth(...)`
122
- - `secretName`: vault secret to inject
123
- - `upstreamBaseUrl`: upstream API base URL
126
+ Current dispatch capabilities use `dispatch_http` as the explicit secret-send operation.
127
+ It is intended for standard secret-backed resource access, not for token mint / refresh / exchange / registration-finalize style acquisition flows.
124
128
 
125
- Optional fields:
126
- - `authHeaderName`: defaults to `Authorization`
127
- - `authPrefix`: defaults to `Bearer `
128
- - `host`: defaults to `127.0.0.1`
129
- - `port`: defaults to an ephemeral port
129
+ The runtime also supports `custom_http` as an owner-defined exception path. A `custom_http` capability must reference a registered `customFlowId`.
130
+ Owner-defined HTTP boundaries share one factory layer:
130
131
 
131
- OpenAI example:
132
- ```ts
133
- const proxy = await startLocalAuthProxy({
134
- authHandle: agent,
135
- secretName: 'openai',
136
- upstreamBaseUrl: 'https://api.openai.com',
137
- });
138
- ```
132
+ - `createOwnerHttpFlowBoundary(...)`
133
+ - `createStandardAcquireBoundary(...)`
134
+ - `createStandardDispatchBoundary(...)`
135
+
136
+ The owner-defined flow may use one of three modes:
137
+
138
+ - `acquire_secret`
139
+ - `send_secret`
140
+ - `bidirectional_secret`
141
+
142
+ Example:
139
143
 
140
- Anthropic example:
141
144
  ```ts
142
- const proxy = await startLocalAuthProxy({
143
- authHandle: agent,
144
- secretName: 'anthropic',
145
- upstreamBaseUrl: 'https://api.anthropic.com',
146
- authHeaderName: 'x-api-key',
147
- authPrefix: '',
148
- });
145
+ const capability = {
146
+ vaultId: vault.vaultId,
147
+ capabilityId: 'cap-1',
148
+ agentId: 'agent-1',
149
+ secretAliases: ['api-token'],
150
+ operation: 'dispatch_http',
151
+ allowedTargets: ['https://api.example.com/endpoint'],
152
+ allowedMethods: ['POST'],
153
+ issuedAt: new Date().toISOString(),
154
+ };
149
155
  ```
150
156
 
151
- Resend example:
157
+ Custom capability example:
158
+
152
159
  ```ts
153
- const proxy = await startLocalAuthProxy({
154
- authHandle: agent,
155
- secretName: 'resend',
156
- upstreamBaseUrl: 'https://api.resend.com',
157
- });
160
+ const customCapability = {
161
+ vaultId: vault.vaultId,
162
+ capabilityId: 'cap-custom',
163
+ agentId: 'agent-1',
164
+ customFlowId: 'custom-status-read',
165
+ secretAliases: ['api-token'],
166
+ operation: 'custom_http',
167
+ allowedTargets: ['https://api.example.com/custom-status'],
168
+ allowedMethods: ['POST'],
169
+ issuedAt: new Date().toISOString(),
170
+ };
158
171
  ```
159
172
 
160
- ### 3.5 Local Secret Ingress
161
- Use `startLocalSecretIngress(...)` when a trusted local process already has a newly issued secret and should hand it directly into CBIO without printing it to terminal output first.
173
+ ## Acquisition Result Shape
174
+
175
+ `acquireSecret(...)` is the explicit acquisition operation.
176
+
177
+ It no longer accepts an open-ended extractor callback. The current surface only supports built-in protocol flows:
178
+
179
+ - `oauth_token_response.access_token`
180
+ - `oauth_token_response.refresh_token`
181
+ - `openid_token_response.id_token`
182
+
183
+ Input:
162
184
 
163
185
  ```ts
164
- const ingress = await identity.startLocalSecretIngress({
165
- secretName: 'service-token',
186
+ const acquireBoundary = createStandardAcquireBoundary({
187
+ targetUrl: 'https://issuer.example.com/token',
188
+ responseField: 'access_token',
189
+ storeAlias: 'issuer-token',
166
190
  });
167
191
 
168
- await fetch(ingress.url, {
169
- method: 'POST',
170
- headers: {
171
- Authorization: `Bearer ${ingress.authToken}`,
172
- 'Content-Type': 'text/plain',
173
- },
174
- body: 'new-secret-value',
192
+ const acquired = await vault.acquireSecret({
193
+ alias: acquireBoundary.responseSecret.storeAlias,
194
+ issuerId: 'issuer-1',
195
+ url: acquireBoundary.targetUrl,
196
+ flow: 'oauth_token_response.access_token',
197
+ method: acquireBoundary.method,
175
198
  });
176
199
  ```
177
200
 
178
- Optional fields:
179
- - `allowedOrigins`
180
- - `overwrite`
181
- - `host`
182
- - `port`
183
- - `path`
184
- - `authToken`
185
- - `once`
186
- - `maxBodyBytes`
187
-
188
- ### 3.6 Local Compare / Proof
189
- Use `compareSecret(...)` and `proveSecret(...)` when the application needs a local KMS-like operation without exporting the stored secret.
201
+ Output:
190
202
 
191
203
  ```ts
192
- const same = await identity.compareSecret('service-token', 'candidate-value');
193
- const proof = await identity.proveSecret('service-token', 'challenge-123');
204
+ type VaultAcquireSecretResult = {
205
+ vaultId: VaultId;
206
+ alias: string;
207
+ status: 'stored';
208
+ responseStatus: number;
209
+ contentType: string | null;
210
+ responseShape: RedactedResponseShape;
211
+ };
194
212
  ```
195
213
 
196
- Current proof algorithms:
197
- - `sha256`
198
- - `sha512`
199
-
200
- `proveSecret(...)` returns a base64url-encoded HMAC proof for the active secret value and the provided challenge.
214
+ `responseShape` is flow-specific. It preserves only the protocol-defined non-sensitive fields that the runtime explicitly allows for that built-in flow.
201
215
 
202
- ### 3.7 Secret Validation
203
- Use `validateSecret(...)` when the application wants a structured validity result rather than exporting a secret and probing manually.
216
+ Example:
204
217
 
205
- `validateSecret(...)` accepts a `SecretValidator`, whose `validate(handle)` method receives a restricted handle with:
206
- - `fetchWithAuth(url, options?)`
207
- - `compare(candidate)`
208
- - `prove(challenge, options?)`
218
+ ```ts
219
+ {
220
+ token_type: 'Bearer',
221
+ expires_in: 3600,
222
+ scope: 'read write',
223
+ }
224
+ ```
209
225
 
210
- The validator never receives the plaintext secret value.
226
+ ## Dispatch Result Shape
211
227
 
212
- Result shape:
228
+ `dispatch_http` returns normal remote output:
213
229
 
214
230
  ```ts
215
- type SecretValidationResult = {
216
- valid: boolean;
217
- status: 'valid' | 'invalid' | 'indeterminate';
218
- reason?: string;
219
- providerSubject?: string;
220
- expiresAt?: string;
221
- scopes?: readonly string[];
222
- metadata?: Record<string, unknown>;
231
+ type DispatchResult = {
232
+ vaultId: VaultId;
233
+ requestId: string;
234
+ status: 'succeeded' | 'denied' | 'failed';
235
+ targetUrl: string;
236
+ method: string;
237
+ responseStatus?: number;
238
+ responseBody?: string;
239
+ error?: string;
223
240
  };
224
241
  ```
225
242
 
226
- Minimal example:
243
+ This is an intentional current-surface choice: `dispatch_http` is treated as secret-out / non-secret-in.
244
+
245
+ In other words, the vault respects the standard HTTP response surface for normal dispatch. It does not attempt to retroactively sanitize every downstream response body, because doing so would shift responsibility away from the target protocol and the owner's authorization decision.
246
+
247
+ For `custom_http`, response visibility is chosen by the owner at flow registration time:
248
+
249
+ - `passthrough`: return the remote body
250
+ - `shape_only`: return a redacted shape-only body
251
+
252
+ If the custom flow mode includes secret acquisition, the owner also defines a response secret rule. The current built-in rule shape is:
227
253
 
228
254
  ```ts
229
- const result = await identity.validateSecret('service-token', {
230
- async validate(handle) {
231
- const response = await handle.fetchWithAuth('https://api.example.com/me');
232
- return {
233
- valid: response.ok,
234
- status: response.ok ? 'valid' : 'invalid',
235
- };
236
- },
237
- });
255
+ {
256
+ kind: 'json_field',
257
+ field: 'access_token',
258
+ storeAlias: 'new-token',
259
+ }
238
260
  ```
239
261
 
240
- ### 3.8 Generic HTTP Validator
241
- Use `genericHttpValidator(...)` when a remote service can be probed by a normal authenticated HTTP request and you want a reusable validator without writing custom validator boilerplate.
262
+ ## Persistent Dependencies
242
263
 
243
- ```ts
244
- const validator = genericHttpValidator({
245
- url: 'https://api.example.com/me',
246
- extractResult: (_response, data: { subject?: string; scopes?: string[] } | undefined) => ({
247
- providerSubject: data?.subject,
248
- scopes: data?.scopes,
249
- }),
250
- });
264
+ `createPersistentVaultCoreDependencies(...)` builds a file-backed single-node profile with:
265
+
266
+ - persistent secret metadata
267
+ - sealed secret custody blobs
268
+ - append-only tamper-evident audit
269
+ - persistent replay guard
270
+ - persistent rate-limit state
271
+ - persistent capability revocation state
272
+
273
+ It still expects caller-provided identity registries unless you supply your own persistent registry adapters.
274
+
275
+ ## Storage Provider
251
276
 
252
- const result = await identity.validateSecret('service-token', validator);
277
+ Any backend can be used by implementing `IStorageProvider`:
278
+
279
+ ```ts
280
+ export interface IStorageProvider {
281
+ read(key: string): Promise<Buffer | null>;
282
+ write(key: string, data: Buffer): Promise<void>;
283
+ delete(key: string): Promise<void>;
284
+ has(key: string): Promise<boolean>;
285
+ rename?(fromKey: string, toKey: string): Promise<void>;
286
+ withLock?<T>(key: string, task: () => Promise<T>): Promise<T>;
287
+ }
253
288
  ```
254
289
 
255
- Supported config fields:
256
- - `url`
257
- - `method`
258
- - `headers`
259
- - `body`
260
- - `isValid(response, data)`
261
- - `classifyStatus(response, data)`
262
- - `extractResult(response, data)`
263
-
264
- Default behavior:
265
- - `2xx` -> `{ valid: true, status: 'valid' }`
266
- - `401/403` -> `{ valid: false, status: 'invalid', reason: 'http_<status>' }`
267
- - other non-`2xx` -> `{ valid: false, status: 'indeterminate', reason: 'http_<status>' }`
268
-
269
- ---
270
-
271
- ## 4. Error Code Dictionary
272
-
273
- The SDK uses structured `IdentityError` objects with the following codes:
274
-
275
- | Code | Meaning | Typical Fix / Recovery |
276
- | :--- | :--- | :--- |
277
- | `PERMISSION_DENIED` | Handle lacks the required runtime capability. | Check `agent.can()` before calling. |
278
- | `SECRET_NOT_FOUND` | Secret name does not exist in the vault. | Add it first or check the naming. |
279
- | `ISSUED_IDENTITY_INVALID` | Bound or persisted issued identity failed protocol or authority/subject validation. | Re-issue the managed identity or load with the correct authority context. |
280
- | `SECRET_ALREADY_EXISTS` | `addSecret` used on an existing name. | Use a new name or `update`. |
281
- | `SECRET_POLICY_REQUIRED` | Agent rotation attempted without allowed origins. | Set origins in identity code. |
282
- | `SECRET_SOURCE_ORIGIN_MISMATCH` | Rotation came from a disallowed origin. | Check secret policy and rotation URL. |
283
- | `SECRET_OPERATION_RATE_LIMITED` | Local compare/proof/validate operation exceeded the runtime limit window. | Back off, reduce probe frequency, or avoid low-entropy repeated guesses. |
284
- | `VAULT_PERSISTENCE_FAILED` | Storage is not writable. | Fix permissions or check storage path. |
285
- | `VAULT_FILE_NOT_FOUND` | Expected vault file does not exist. | Initialize identity or check storage key. |
286
- | `VAULT_WRITE_INTEGRITY_FAILED` | Save verification failed. | Check disk space/integrity. |
287
- | `VAULT_CORRUPTED` | Vault file is truncated or unreadable. | Restore from backup; do not overwrite. |
288
- | `VAULT_DECRYPT_FAILED` | Decryption failed (wrong key or tampered). | Verify the correct Private Key was used. |
289
- | `MERGE_IDENTITY_MISMATCH` | Tried to merge vaults of different identities. | Only merge vaults of the same identity. |
290
- | `CHILD_IDENTITY_REQUIRES_PRIVATE_KEY` | Child keys were incomplete on registration. | Ensure child keys include Private Key. |
291
- | `SIGNER_REQUIRES_PRIVATE_KEY` | Administrative action requires a full signer. | Load identity from a full private key. |
290
+ `withLock(...)` is used when present to serialize read-modify-write persistence sequences.