@tinycloud/sdk-services 3.0.0 → 3.1.0-beta.10
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/dist/{BaseService-BhpVpA9b.d.cts → BaseService-B_UKhVht.d.ts} +74 -2
- package/dist/{BaseService-CuV-ZVPs.d.ts → BaseService-DWbPbov7.d.cts} +74 -2
- package/dist/encryption/index.cjs +199 -100
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +199 -100
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +832 -310
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -42
- package/dist/index.d.ts +84 -42
- package/dist/index.js +806 -292
- package/dist/index.js.map +1 -1
- package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
- package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
- package/dist/kv/index.cjs +623 -125
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +204 -14
- package/dist/kv/index.d.ts +204 -14
- package/dist/kv/index.js +623 -125
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +191 -35
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +6 -3
- package/dist/sql/index.d.ts +6 -3
- package/dist/sql/index.js +182 -26
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-qwMmB7qB.d.cts → types-CVwwxqXF.d.cts} +8 -0
- package/dist/{types-qwMmB7qB.d.ts → types-CVwwxqXF.d.ts} +8 -0
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BaseService } from '../BaseService-
|
|
2
|
-
import { P as PermissionHint, I as IService, R as Result } from '../types-
|
|
1
|
+
import { B as BaseService } from '../BaseService-DWbPbov7.cjs';
|
|
2
|
+
import { P as PermissionHint, I as IService, R as Result } from '../types-CVwwxqXF.cjs';
|
|
3
3
|
export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BaseService } from '../BaseService-
|
|
2
|
-
import { P as PermissionHint, I as IService, R as Result } from '../types-
|
|
1
|
+
import { B as BaseService } from '../BaseService-B_UKhVht.js';
|
|
2
|
+
import { P as PermissionHint, I as IService, R as Result } from '../types-CVwwxqXF.js';
|
|
3
3
|
export { DecryptTransportResponseError } from '@tinycloud/sdk-services/internal/decrypt-transport-response-error';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/encryption/index.js
CHANGED
|
@@ -5,6 +5,10 @@ var ErrorCodes = {
|
|
|
5
5
|
AUTH_EXPIRED: "AUTH_EXPIRED",
|
|
6
6
|
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
7
7
|
AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
|
|
8
|
+
/** HTTP 401: the delegation the invocation cites was revoked. */
|
|
9
|
+
AUTH_DELEGATION_REVOKED: "AUTH_DELEGATION_REVOKED",
|
|
10
|
+
/** HTTP 401: a delegation the cited one rests on was revoked. */
|
|
11
|
+
AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
|
|
8
12
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
9
13
|
TIMEOUT: "TIMEOUT",
|
|
10
14
|
ABORTED: "ABORTED",
|
|
@@ -16,6 +20,10 @@ var ErrorCodes = {
|
|
|
16
20
|
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
17
21
|
KV_CONFLICT: "KV_CONFLICT",
|
|
18
22
|
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
23
|
+
/** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */
|
|
24
|
+
KV_SYNC_RESET_REQUIRED: "KV_SYNC_RESET_REQUIRED",
|
|
25
|
+
/** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */
|
|
26
|
+
KV_RETENTION_GRANT_REFUSED: "KV_RETENTION_GRANT_REFUSED",
|
|
19
27
|
// SQL-specific errors
|
|
20
28
|
SQL_ERROR: "SQL_ERROR",
|
|
21
29
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -59,11 +67,131 @@ function err(error) {
|
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
// src/errors.ts
|
|
62
|
-
|
|
70
|
+
import { CAPABILITY_REGISTRY } from "@tinycloud/bootstrap";
|
|
71
|
+
|
|
72
|
+
// src/encryption/networkId.ts
|
|
73
|
+
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
74
|
+
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
75
|
+
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
76
|
+
var NetworkIdError = class extends Error {
|
|
77
|
+
constructor(message) {
|
|
78
|
+
super(message);
|
|
79
|
+
this.name = "NetworkIdError";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
function parseNetworkId(networkId) {
|
|
83
|
+
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
84
|
+
throw new NetworkIdError("networkId must be a non-empty string");
|
|
85
|
+
}
|
|
86
|
+
if (!networkId.startsWith(URN_PREFIX)) {
|
|
87
|
+
throw new NetworkIdError(
|
|
88
|
+
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const body = networkId.slice(URN_PREFIX.length);
|
|
92
|
+
const lastColon = body.lastIndexOf(":");
|
|
93
|
+
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
94
|
+
throw new NetworkIdError(
|
|
95
|
+
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const ownerDid = body.slice(0, lastColon);
|
|
99
|
+
const name = body.slice(lastColon + 1);
|
|
100
|
+
if (!ownerDid.startsWith("did:")) {
|
|
101
|
+
throw new NetworkIdError(
|
|
102
|
+
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const didParts = ownerDid.split(":");
|
|
106
|
+
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
107
|
+
throw new NetworkIdError(
|
|
108
|
+
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
112
|
+
throw new NetworkIdError(
|
|
113
|
+
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return { networkId, ownerDid, name };
|
|
117
|
+
}
|
|
118
|
+
function buildNetworkId(ownerDid, name) {
|
|
119
|
+
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
120
|
+
throw new NetworkIdError("ownerDid must be a DID");
|
|
121
|
+
}
|
|
122
|
+
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
123
|
+
throw new NetworkIdError(
|
|
124
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
128
|
+
parseNetworkId(networkId);
|
|
129
|
+
return networkId;
|
|
130
|
+
}
|
|
131
|
+
function isNetworkId(networkId) {
|
|
132
|
+
if (typeof networkId !== "string") {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
parseNetworkId(networkId);
|
|
137
|
+
return true;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function parsePkhOwnerDid(ownerDid) {
|
|
143
|
+
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
144
|
+
if (!match) return null;
|
|
145
|
+
return {
|
|
146
|
+
chainId: match[1],
|
|
147
|
+
address: match[2].toLowerCase()
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function ownerDidMatches(a, b) {
|
|
151
|
+
const aPkh = parsePkhOwnerDid(a);
|
|
152
|
+
const bPkh = parsePkhOwnerDid(b);
|
|
153
|
+
if (aPkh && bPkh) {
|
|
154
|
+
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
155
|
+
}
|
|
156
|
+
return a === b;
|
|
157
|
+
}
|
|
158
|
+
function networkDiscoveryKey(name) {
|
|
159
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
160
|
+
throw new NetworkIdError(
|
|
161
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return `.well-known/encryption/network/${name}`;
|
|
165
|
+
}
|
|
166
|
+
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
167
|
+
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
168
|
+
|
|
169
|
+
// src/errors.ts
|
|
170
|
+
var RequestTimeoutError = class extends Error {
|
|
171
|
+
constructor(timeoutMs) {
|
|
172
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
173
|
+
this.name = "TimeoutError";
|
|
174
|
+
this.timeoutMs = timeoutMs;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
function isRequestTimeoutError(error) {
|
|
178
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
179
|
+
}
|
|
180
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
181
|
+
if (timeoutMs === void 0) {
|
|
182
|
+
return {
|
|
183
|
+
code: ErrorCodes.TIMEOUT,
|
|
184
|
+
message: "Request timed out.",
|
|
185
|
+
service,
|
|
186
|
+
...cause === void 0 ? {} : { cause }
|
|
187
|
+
};
|
|
188
|
+
}
|
|
63
189
|
return {
|
|
64
190
|
code: ErrorCodes.TIMEOUT,
|
|
65
|
-
message:
|
|
66
|
-
service
|
|
191
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
192
|
+
service,
|
|
193
|
+
...cause === void 0 ? {} : { cause },
|
|
194
|
+
meta: { timeoutMs }
|
|
67
195
|
};
|
|
68
196
|
}
|
|
69
197
|
function abortedError(service) {
|
|
@@ -73,8 +201,17 @@ function abortedError(service) {
|
|
|
73
201
|
service
|
|
74
202
|
};
|
|
75
203
|
}
|
|
204
|
+
var grantableActions = new Set(
|
|
205
|
+
CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
206
|
+
);
|
|
207
|
+
var capabilityServices = new Set(
|
|
208
|
+
CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
209
|
+
);
|
|
76
210
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
77
211
|
if (error instanceof Error) {
|
|
212
|
+
if (isRequestTimeoutError(error)) {
|
|
213
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
214
|
+
}
|
|
78
215
|
if (error.name === "AbortError") {
|
|
79
216
|
return abortedError(service);
|
|
80
217
|
}
|
|
@@ -96,6 +233,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
|
96
233
|
}
|
|
97
234
|
|
|
98
235
|
// src/base/BaseService.ts
|
|
236
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
99
237
|
var BaseService = class {
|
|
100
238
|
constructor() {
|
|
101
239
|
/**
|
|
@@ -276,6 +414,64 @@ var BaseService = class {
|
|
|
276
414
|
}
|
|
277
415
|
return controller.signal;
|
|
278
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
419
|
+
*
|
|
420
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
421
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
422
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
423
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
424
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
425
|
+
*
|
|
426
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
427
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
428
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
429
|
+
*
|
|
430
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
431
|
+
* which clears the timer and removes the listeners this adds to the
|
|
432
|
+
* long-lived service and context signals.
|
|
433
|
+
*
|
|
434
|
+
* @param signal - The caller's abort signal for this request
|
|
435
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
436
|
+
*/
|
|
437
|
+
createRequestSignal(signal, timeoutMs) {
|
|
438
|
+
const controller = new AbortController();
|
|
439
|
+
const detachers = [];
|
|
440
|
+
let timer;
|
|
441
|
+
const dispose = () => {
|
|
442
|
+
if (timer !== void 0) {
|
|
443
|
+
clearTimeout(timer);
|
|
444
|
+
timer = void 0;
|
|
445
|
+
}
|
|
446
|
+
for (const detach of detachers.splice(0)) {
|
|
447
|
+
detach();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const abort = (reason) => {
|
|
451
|
+
dispose();
|
|
452
|
+
controller.abort(reason);
|
|
453
|
+
};
|
|
454
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
455
|
+
const parents = [
|
|
456
|
+
this.abortController.signal,
|
|
457
|
+
this.context?.abortSignal,
|
|
458
|
+
signal
|
|
459
|
+
].filter((parent) => parent !== void 0);
|
|
460
|
+
for (const parent of parents) {
|
|
461
|
+
if (parent.aborted) {
|
|
462
|
+
abort(parent.reason);
|
|
463
|
+
return requestSignal;
|
|
464
|
+
}
|
|
465
|
+
const onAbort = () => abort(parent.reason);
|
|
466
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
467
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
468
|
+
}
|
|
469
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
470
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
471
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
472
|
+
}
|
|
473
|
+
return requestSignal;
|
|
474
|
+
}
|
|
279
475
|
/**
|
|
280
476
|
* Wrap an operation with error handling and telemetry.
|
|
281
477
|
*
|
|
@@ -415,103 +611,6 @@ function canonicalHashHex(sha256, value) {
|
|
|
415
611
|
return hexEncode(sha256(utf8Encode(canonical)));
|
|
416
612
|
}
|
|
417
613
|
|
|
418
|
-
// src/encryption/networkId.ts
|
|
419
|
-
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
420
|
-
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
421
|
-
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
422
|
-
var NetworkIdError = class extends Error {
|
|
423
|
-
constructor(message) {
|
|
424
|
-
super(message);
|
|
425
|
-
this.name = "NetworkIdError";
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
function parseNetworkId(networkId) {
|
|
429
|
-
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
430
|
-
throw new NetworkIdError("networkId must be a non-empty string");
|
|
431
|
-
}
|
|
432
|
-
if (!networkId.startsWith(URN_PREFIX)) {
|
|
433
|
-
throw new NetworkIdError(
|
|
434
|
-
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
const body = networkId.slice(URN_PREFIX.length);
|
|
438
|
-
const lastColon = body.lastIndexOf(":");
|
|
439
|
-
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
440
|
-
throw new NetworkIdError(
|
|
441
|
-
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
const ownerDid = body.slice(0, lastColon);
|
|
445
|
-
const name = body.slice(lastColon + 1);
|
|
446
|
-
if (!ownerDid.startsWith("did:")) {
|
|
447
|
-
throw new NetworkIdError(
|
|
448
|
-
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
const didParts = ownerDid.split(":");
|
|
452
|
-
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
453
|
-
throw new NetworkIdError(
|
|
454
|
-
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
455
|
-
);
|
|
456
|
-
}
|
|
457
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
458
|
-
throw new NetworkIdError(
|
|
459
|
-
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
return { networkId, ownerDid, name };
|
|
463
|
-
}
|
|
464
|
-
function buildNetworkId(ownerDid, name) {
|
|
465
|
-
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
466
|
-
throw new NetworkIdError("ownerDid must be a DID");
|
|
467
|
-
}
|
|
468
|
-
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
469
|
-
throw new NetworkIdError(
|
|
470
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
474
|
-
parseNetworkId(networkId);
|
|
475
|
-
return networkId;
|
|
476
|
-
}
|
|
477
|
-
function isNetworkId(networkId) {
|
|
478
|
-
if (typeof networkId !== "string") {
|
|
479
|
-
return false;
|
|
480
|
-
}
|
|
481
|
-
try {
|
|
482
|
-
parseNetworkId(networkId);
|
|
483
|
-
return true;
|
|
484
|
-
} catch {
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
function parsePkhOwnerDid(ownerDid) {
|
|
489
|
-
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
490
|
-
if (!match) return null;
|
|
491
|
-
return {
|
|
492
|
-
chainId: match[1],
|
|
493
|
-
address: match[2].toLowerCase()
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
function ownerDidMatches(a, b) {
|
|
497
|
-
const aPkh = parsePkhOwnerDid(a);
|
|
498
|
-
const bPkh = parsePkhOwnerDid(b);
|
|
499
|
-
if (aPkh && bPkh) {
|
|
500
|
-
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
501
|
-
}
|
|
502
|
-
return a === b;
|
|
503
|
-
}
|
|
504
|
-
function networkDiscoveryKey(name) {
|
|
505
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
506
|
-
throw new NetworkIdError(
|
|
507
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
return `.well-known/encryption/network/${name}`;
|
|
511
|
-
}
|
|
512
|
-
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
513
|
-
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
514
|
-
|
|
515
614
|
// src/encryption/types.ts
|
|
516
615
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
517
616
|
var ENVELOPE_VERSION = 1;
|