@tinycloud/sdk-services 3.7.0-beta.3 → 3.7.0-beta.4

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.
@@ -0,0 +1,220 @@
1
+ import { E as EncryptionCrypto, I as InlineEncryptedEnvelope, J as Json } from '../types-BGRzS1ob.js';
2
+ import { ParsedKeyResource } from './resource.js';
3
+ import '../types-DAOyIbXu.js';
4
+
5
+ /**
6
+ * Named-key client: key admin, descriptor reads, `ensureKey` and key-scoped
7
+ * encrypt / decrypt.
8
+ *
9
+ * Rules enforced here:
10
+ * - Everything is dark unless the node's `/info` `features` contains
11
+ * `encryption-named-keys-v1`. Without it no key ability, key URN or `keyPath`
12
+ * is sent to the node; the call throws `NAMED_KEYS_UNSUPPORTED` first.
13
+ * - Every invocation carries exactly ONE capability whose `with` is the EXACT
14
+ * key URN (a parsed `kind: "key"`; a prefix or bare network is never a
15
+ * target) and whose `can` is the one ability the call needs.
16
+ * - Admin bodies are hashed and serialized with the same canonical JSON used
17
+ * by the network-admin invocation (`canonicalHashHex` / `canonicalize`).
18
+ * - Envelope v2 carries `keyPath` and is wrapped to the KEY's public key. It is
19
+ * decrypted only through `POST /invoke` with a single decrypt capability on
20
+ * that key. v1 envelopes (no `keyPath`) go to the root-key path unchanged.
21
+ * A key and the root, or two keys, are never mixed in one invocation.
22
+ * - `key.delete` is not offered. The create body carries `deletable`, which is
23
+ * `true` exactly when the path starts with `apps/`; the node refuses it with
24
+ * `deletable_unavailable` while app-key deletion is not enabled there.
25
+ */
26
+
27
+ declare const KEY_ADMIN_FACT_TYPE: "tinycloud.encryption.key-admin/v1";
28
+ declare const KEY_DESCRIBE_FACT_TYPE: "tinycloud.encryption.key-describe/v1";
29
+ declare const NAMED_KEY_ENVELOPE_VERSION: 2;
30
+ type NamedKeyErrorCode = "NAMED_KEYS_UNSUPPORTED" | "INVALID_KEY_TARGET" | "INVALID_ENVELOPE" | "INVALID_RESPONSE" | "KEY_BLOCKED" | "KEY_NOT_FOUND" | "KEY_EXISTS" | "NETWORK_NOT_FOUND" | "NETWORK_NOT_ACTIVE" | "KEY_LIMIT_EXCEEDED" | "DELETABLE_UNAVAILABLE"
31
+ /** The key is not deletable (a deterministic key answers 409 `key_not_deletable`). */
32
+ | "KEY_NOT_DELETABLE" | "KEY_PATH_INVALID" | "KEY_UNWRAP_FAILED"
33
+ /** Key is in a state other than active/blocked; `rawState` holds the node's string. */
34
+ | "KEY_UNAVAILABLE"
35
+ /** `ensureKey` found a key that is not deterministic. */
36
+ | "KEY_KIND_MISMATCH" | "DECRYPT_FAILED" | "NODE_ERROR"
37
+ /** The node rejected `receiverPublicKey` (400, invocation not consumed). */
38
+ | "RECEIVER_KEY_INVALID"
39
+ /** The node object lacks an invocation hook the node-sdk wiring needs. */
40
+ | "NODE_HOOK_MISSING";
41
+ /**
42
+ * Render an untrusted value (resource, path, node-supplied state, parser or
43
+ * signer text) for an error message: capped at 120 characters, then every
44
+ * character outside printable ASCII escaped, so bidi, zero-width and other
45
+ * format or control characters can never reach a terminal or log through a
46
+ * message. Raw values live only in non-message fields (`input`, `rawState`,
47
+ * `kind`, `detail`, `cause`).
48
+ */
49
+ declare function safeEcho(value: unknown): string;
50
+ interface NamedKeyErrorInit {
51
+ status?: number;
52
+ /** The node's `<code>` prefix, when it sent one. */
53
+ nodeCode?: string;
54
+ /** The node's `<detail>` text. Raw: never in `message`. */
55
+ detail?: string;
56
+ /** Raw state string (KEY_UNAVAILABLE). Raw: never in `message`. */
57
+ rawState?: string;
58
+ kind?: string;
59
+ /** The rejected caller input (resource or path), unescaped. Raw: never in `message`. */
60
+ input?: string;
61
+ cause?: unknown;
62
+ }
63
+ declare class NamedKeyError extends Error {
64
+ readonly code: NamedKeyErrorCode;
65
+ readonly status?: number;
66
+ readonly nodeCode?: string;
67
+ readonly detail?: string;
68
+ readonly rawState?: string;
69
+ readonly kind?: string;
70
+ readonly input?: string;
71
+ constructor(code: NamedKeyErrorCode, message: string, init?: NamedKeyErrorInit);
72
+ }
73
+ /** Map a node plain-text `<code>: <detail>` error response to a typed error. */
74
+ declare function mapNodeKeyError(status: number, text: string, context: string): NamedKeyError;
75
+ interface PublicKeyDescriptor {
76
+ networkId: string;
77
+ keyPath: string;
78
+ alg: string;
79
+ keyVersion: number;
80
+ publicEncryptionKey: string;
81
+ }
82
+ interface KeyDescriptor extends PublicKeyDescriptor {
83
+ /** Raw node state string (`active`, `blocked`, ...). */
84
+ state: string;
85
+ /** `deterministic` outside `apps/`, `deletable` under it; kept as a string so unknown kinds surface. */
86
+ kind: string;
87
+ createdAt?: string;
88
+ updatedAt?: string;
89
+ }
90
+ /** v2 inline envelope: v1 fields plus `keyPath`, wrapped to the key's public key. */
91
+ interface NamedKeyEnvelope extends Omit<InlineEncryptedEnvelope, "v"> {
92
+ v: typeof NAMED_KEY_ENVELOPE_VERSION;
93
+ keyPath: string;
94
+ }
95
+ interface NamedKeyInvocationInput {
96
+ targetNode: string;
97
+ /** The EXACT key URN. This is the single capability's `with`. */
98
+ resource: string;
99
+ /** The single capability's `can`. */
100
+ action: string;
101
+ facts: Record<string, unknown>;
102
+ }
103
+ interface NamedKeyClientConfig {
104
+ host: string;
105
+ crypto: EncryptionCrypto;
106
+ fetch: typeof fetch;
107
+ /** Network used when a call does not name one. */
108
+ defaultNetworkId: () => string;
109
+ /** Mint one single-capability invocation and return the Authorization header value. */
110
+ signInvocation: (input: NamedKeyInvocationInput) => Promise<{
111
+ authorization: string;
112
+ invocationCid: string;
113
+ }>;
114
+ /**
115
+ * Decrypt a v1 (root key, bare network capability) envelope exactly as the
116
+ * existing network decrypt path does.
117
+ */
118
+ decryptRoot?: (envelope: InlineEncryptedEnvelope) => Promise<{
119
+ ok: true;
120
+ data: Uint8Array;
121
+ } | {
122
+ ok: false;
123
+ error: {
124
+ message: string;
125
+ };
126
+ }>;
127
+ }
128
+ interface KeyCallOptions {
129
+ /** Full network id URN. Defaults to the client's default network. */
130
+ networkId?: string;
131
+ }
132
+ interface KeyEncryptOptions extends KeyCallOptions {
133
+ aad?: Uint8Array;
134
+ metadata?: Record<string, string>;
135
+ }
136
+ type DecryptManyResult = {
137
+ ok: true;
138
+ data: Uint8Array;
139
+ } | {
140
+ ok: false;
141
+ error: NamedKeyError;
142
+ };
143
+ /** Accept only a parsed `kind: "key"`; a prefix or bare network is never a target. */
144
+ declare function requireKeyTarget(resource: string): ParsedKeyResource;
145
+ /** `{type, targetNode, networkId, keyPath, action, bodyHash}` for key admin routes. */
146
+ declare function buildKeyAdminFacts(input: {
147
+ crypto: EncryptionCrypto;
148
+ targetNode: string;
149
+ keyResource: string;
150
+ action: string;
151
+ body: Json;
152
+ }): Record<string, unknown>;
153
+ /** `{type, targetNode, networkId, keyPath}`; no body hash. */
154
+ declare function buildKeyDescribeFacts(input: {
155
+ targetNode: string;
156
+ keyResource: string;
157
+ }): Record<string, unknown>;
158
+ declare class NamedKeyClient {
159
+ private readonly config;
160
+ /** One `/info` read per client: the node DID once the feature is confirmed. */
161
+ private nodeId?;
162
+ constructor(config: NamedKeyClientConfig);
163
+ private networkFor;
164
+ private keyUrn;
165
+ /**
166
+ * Require the named-keys feature and return the node DID. The first call
167
+ * reads `/info`; a positive answer is cached for the life of this client, so
168
+ * later calls make no `/info` request. A node without the feature is NOT
169
+ * cached: the typed `NAMED_KEYS_UNSUPPORTED` error is thrown and the next
170
+ * call re-reads (so a retry sees an upgraded node). No key request is made
171
+ * before the gate passes.
172
+ */
173
+ private requireNode;
174
+ /** Clear the cached `/info` answer; the next call reads it again. */
175
+ refreshNodeInfo(): void;
176
+ private readNodeInfo;
177
+ private keysUrl;
178
+ /** Public GET: the key's public key. Derive-only (no 404) outside `apps/`; under `apps/` the node answers 404. */
179
+ getPublicKey(path: string, options?: KeyCallOptions): Promise<PublicKeyDescriptor>;
180
+ /**
181
+ * Authenticated GET: the full descriptor, or `null` on `key_not_found`.
182
+ * `ability` is the one capability the invocation carries (default decrypt).
183
+ */
184
+ describeKey(path: string, options?: KeyCallOptions & {
185
+ ability?: string;
186
+ }): Promise<KeyDescriptor | null>;
187
+ /** Public fields of an authenticated describe (decrypt ability); `key_not_found` throws. */
188
+ private describePublic;
189
+ /** The authenticated GET response body, or `null` on `key_not_found`. */
190
+ private describeBody;
191
+ private admin;
192
+ /** `key.create`: `deletable` is `true` exactly under `apps/`, else a deterministic key. */
193
+ createKey(path: string, options?: KeyCallOptions): Promise<KeyDescriptor>;
194
+ blockKey(path: string, options?: KeyCallOptions): Promise<KeyDescriptor>;
195
+ unblockKey(path: string, options?: KeyCallOptions): Promise<KeyDescriptor>;
196
+ /**
197
+ * Make sure a key exists and is usable: authenticated GET; on
198
+ * `key_not_found` create it; on 409 `key_exists` read it again. Succeeds only
199
+ * for `state: "active"` and the kind the path implies: `deletable` under
200
+ * `apps/`, `deterministic` elsewhere.
201
+ */
202
+ ensureKey(path: string, options?: KeyCallOptions): Promise<KeyDescriptor>;
203
+ /** Encrypt to a named key: envelope v2, symmetric key wrapped to the key's public key. */
204
+ encrypt(path: string, plaintext: Uint8Array, options?: KeyEncryptOptions): Promise<NamedKeyEnvelope>;
205
+ /**
206
+ * Decrypt one envelope. v1 (no `keyPath`) uses the root-key path exactly as
207
+ * before; v2 uses one decrypt capability on the exact key via `/invoke`.
208
+ */
209
+ decrypt(envelope: InlineEncryptedEnvelope | NamedKeyEnvelope): Promise<Uint8Array>;
210
+ /**
211
+ * Decrypt a batch. Each envelope is its own invocation with its own single
212
+ * capability, so v1 and v2 (or two different keys) are never combined.
213
+ */
214
+ decryptMany(envelopes: ReadonlyArray<InlineEncryptedEnvelope | NamedKeyEnvelope>): Promise<DecryptManyResult[]>;
215
+ private decryptRoot;
216
+ private validateKeyEnvelope;
217
+ private decryptKey;
218
+ }
219
+
220
+ export { type DecryptManyResult, KEY_ADMIN_FACT_TYPE, KEY_DESCRIBE_FACT_TYPE, type KeyCallOptions, type KeyDescriptor, type KeyEncryptOptions, NAMED_KEY_ENVELOPE_VERSION, NamedKeyClient, type NamedKeyClientConfig, type NamedKeyEnvelope, NamedKeyError, type NamedKeyErrorCode, type NamedKeyErrorInit, type NamedKeyInvocationInput, type PublicKeyDescriptor, buildKeyAdminFacts, buildKeyDescribeFacts, mapNodeKeyError, requireKeyTarget, safeEcho };