@tinycloud/sdk-services 3.1.0-beta.2 → 3.1.0-beta.7
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-C8zRy0ww.d.cts} +73 -1
- package/dist/{BaseService-CuV-ZVPs.d.ts → BaseService-DU-lE-Qx.d.ts} +73 -1
- package/dist/encryption/index.cjs +191 -100
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +1 -1
- package/dist/encryption/index.d.ts +1 -1
- package/dist/encryption/index.js +191 -100
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +446 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -39
- package/dist/index.d.ts +29 -39
- package/dist/index.js +426 -159
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +333 -35
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +26 -12
- package/dist/kv/index.d.ts +26 -12
- package/dist/kv/index.js +333 -35
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +139 -30
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +5 -2
- package/dist/sql/index.d.ts +5 -2
- package/dist/sql/index.js +130 -21
- package/dist/sql/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
import { I as IService, a as IServiceContext, S as ServiceSession, b as ServiceError, R as Result } from './types-qwMmB7qB.cjs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Base Service Types
|
|
5
|
+
*
|
|
6
|
+
* Types specific to the base service infrastructure.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Service constructor type for registration.
|
|
11
|
+
* Used by the SDK to instantiate services.
|
|
12
|
+
*/
|
|
13
|
+
interface ServiceConstructor<TConfig = Record<string, unknown>, TService extends IService = IService> {
|
|
14
|
+
/** Service identifier used for registration */
|
|
15
|
+
readonly serviceName: string;
|
|
16
|
+
/** Create a new instance of the service */
|
|
17
|
+
new (config?: TConfig): TService;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Service registration entry.
|
|
21
|
+
*/
|
|
22
|
+
interface ServiceRegistration {
|
|
23
|
+
/** The service class constructor */
|
|
24
|
+
constructor: ServiceConstructor;
|
|
25
|
+
/** Configuration for this service instance */
|
|
26
|
+
config?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for base service operations.
|
|
30
|
+
*/
|
|
31
|
+
interface BaseServiceOptions {
|
|
32
|
+
/** Override the default timeout for this operation */
|
|
33
|
+
timeout?: number;
|
|
34
|
+
/** Custom abort signal for this operation */
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A per-request abort signal and the cleanup that releases it.
|
|
39
|
+
* Created by `BaseService.createRequestSignal()`.
|
|
40
|
+
*/
|
|
41
|
+
interface RequestSignal {
|
|
42
|
+
/**
|
|
43
|
+
* Aborts on service sign-out, context abort, the caller's signal, or when
|
|
44
|
+
* the request timeout elapses (reason: a `TimeoutError`).
|
|
45
|
+
*/
|
|
46
|
+
readonly signal: AbortSignal;
|
|
47
|
+
/**
|
|
48
|
+
* Clear the timeout and detach from the parent signals. Call once the
|
|
49
|
+
* response has been consumed. Idempotent.
|
|
50
|
+
*/
|
|
51
|
+
dispose(): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
3
54
|
/**
|
|
4
55
|
* BaseService - Abstract base class for all TinyCloud services.
|
|
5
56
|
*
|
|
@@ -144,6 +195,27 @@ declare abstract class BaseService implements IService {
|
|
|
144
195
|
* @returns A combined abort signal
|
|
145
196
|
*/
|
|
146
197
|
protected combineSignals(...signals: (AbortSignal | undefined)[]): AbortSignal;
|
|
198
|
+
/**
|
|
199
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
200
|
+
*
|
|
201
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
202
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
203
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
204
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
205
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
206
|
+
*
|
|
207
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
208
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
209
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
210
|
+
*
|
|
211
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
212
|
+
* which clears the timer and removes the listeners this adds to the
|
|
213
|
+
* long-lived service and context signals.
|
|
214
|
+
*
|
|
215
|
+
* @param signal - The caller's abort signal for this request
|
|
216
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
217
|
+
*/
|
|
218
|
+
protected createRequestSignal(signal?: AbortSignal, timeoutMs?: number): RequestSignal;
|
|
147
219
|
/**
|
|
148
220
|
* Wrap an operation with error handling and telemetry.
|
|
149
221
|
*
|
|
@@ -155,4 +227,4 @@ declare abstract class BaseService implements IService {
|
|
|
155
227
|
protected withTelemetry<T>(action: string, key: string | undefined, operation: () => Promise<Result<T>>): Promise<Result<T>>;
|
|
156
228
|
}
|
|
157
229
|
|
|
158
|
-
export { BaseService as B };
|
|
230
|
+
export { BaseService as B, type RequestSignal as R, type ServiceConstructor as S, type BaseServiceOptions as a, type ServiceRegistration as b };
|
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
import { I as IService, a as IServiceContext, S as ServiceSession, b as ServiceError, R as Result } from './types-qwMmB7qB.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Base Service Types
|
|
5
|
+
*
|
|
6
|
+
* Types specific to the base service infrastructure.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Service constructor type for registration.
|
|
11
|
+
* Used by the SDK to instantiate services.
|
|
12
|
+
*/
|
|
13
|
+
interface ServiceConstructor<TConfig = Record<string, unknown>, TService extends IService = IService> {
|
|
14
|
+
/** Service identifier used for registration */
|
|
15
|
+
readonly serviceName: string;
|
|
16
|
+
/** Create a new instance of the service */
|
|
17
|
+
new (config?: TConfig): TService;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Service registration entry.
|
|
21
|
+
*/
|
|
22
|
+
interface ServiceRegistration {
|
|
23
|
+
/** The service class constructor */
|
|
24
|
+
constructor: ServiceConstructor;
|
|
25
|
+
/** Configuration for this service instance */
|
|
26
|
+
config?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for base service operations.
|
|
30
|
+
*/
|
|
31
|
+
interface BaseServiceOptions {
|
|
32
|
+
/** Override the default timeout for this operation */
|
|
33
|
+
timeout?: number;
|
|
34
|
+
/** Custom abort signal for this operation */
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A per-request abort signal and the cleanup that releases it.
|
|
39
|
+
* Created by `BaseService.createRequestSignal()`.
|
|
40
|
+
*/
|
|
41
|
+
interface RequestSignal {
|
|
42
|
+
/**
|
|
43
|
+
* Aborts on service sign-out, context abort, the caller's signal, or when
|
|
44
|
+
* the request timeout elapses (reason: a `TimeoutError`).
|
|
45
|
+
*/
|
|
46
|
+
readonly signal: AbortSignal;
|
|
47
|
+
/**
|
|
48
|
+
* Clear the timeout and detach from the parent signals. Call once the
|
|
49
|
+
* response has been consumed. Idempotent.
|
|
50
|
+
*/
|
|
51
|
+
dispose(): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
3
54
|
/**
|
|
4
55
|
* BaseService - Abstract base class for all TinyCloud services.
|
|
5
56
|
*
|
|
@@ -144,6 +195,27 @@ declare abstract class BaseService implements IService {
|
|
|
144
195
|
* @returns A combined abort signal
|
|
145
196
|
*/
|
|
146
197
|
protected combineSignals(...signals: (AbortSignal | undefined)[]): AbortSignal;
|
|
198
|
+
/**
|
|
199
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
200
|
+
*
|
|
201
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
202
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
203
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
204
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
205
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
206
|
+
*
|
|
207
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
208
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
209
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
210
|
+
*
|
|
211
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
212
|
+
* which clears the timer and removes the listeners this adds to the
|
|
213
|
+
* long-lived service and context signals.
|
|
214
|
+
*
|
|
215
|
+
* @param signal - The caller's abort signal for this request
|
|
216
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
217
|
+
*/
|
|
218
|
+
protected createRequestSignal(signal?: AbortSignal, timeoutMs?: number): RequestSignal;
|
|
147
219
|
/**
|
|
148
220
|
* Wrap an operation with error handling and telemetry.
|
|
149
221
|
*
|
|
@@ -155,4 +227,4 @@ declare abstract class BaseService implements IService {
|
|
|
155
227
|
protected withTelemetry<T>(action: string, key: string | undefined, operation: () => Promise<Result<T>>): Promise<Result<T>>;
|
|
156
228
|
}
|
|
157
229
|
|
|
158
|
-
export { BaseService as B };
|
|
230
|
+
export { BaseService as B, type RequestSignal as R, type ServiceConstructor as S, type BaseServiceOptions as a, type ServiceRegistration as b };
|
|
@@ -125,11 +125,131 @@ function err(error) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// src/errors.ts
|
|
128
|
-
|
|
128
|
+
var import_bootstrap = require("@tinycloud/bootstrap");
|
|
129
|
+
|
|
130
|
+
// src/encryption/networkId.ts
|
|
131
|
+
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
132
|
+
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
133
|
+
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
134
|
+
var NetworkIdError = class extends Error {
|
|
135
|
+
constructor(message) {
|
|
136
|
+
super(message);
|
|
137
|
+
this.name = "NetworkIdError";
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
function parseNetworkId(networkId) {
|
|
141
|
+
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
142
|
+
throw new NetworkIdError("networkId must be a non-empty string");
|
|
143
|
+
}
|
|
144
|
+
if (!networkId.startsWith(URN_PREFIX)) {
|
|
145
|
+
throw new NetworkIdError(
|
|
146
|
+
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
const body = networkId.slice(URN_PREFIX.length);
|
|
150
|
+
const lastColon = body.lastIndexOf(":");
|
|
151
|
+
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
152
|
+
throw new NetworkIdError(
|
|
153
|
+
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const ownerDid = body.slice(0, lastColon);
|
|
157
|
+
const name = body.slice(lastColon + 1);
|
|
158
|
+
if (!ownerDid.startsWith("did:")) {
|
|
159
|
+
throw new NetworkIdError(
|
|
160
|
+
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const didParts = ownerDid.split(":");
|
|
164
|
+
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
165
|
+
throw new NetworkIdError(
|
|
166
|
+
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
170
|
+
throw new NetworkIdError(
|
|
171
|
+
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
return { networkId, ownerDid, name };
|
|
175
|
+
}
|
|
176
|
+
function buildNetworkId(ownerDid, name) {
|
|
177
|
+
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
178
|
+
throw new NetworkIdError("ownerDid must be a DID");
|
|
179
|
+
}
|
|
180
|
+
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
181
|
+
throw new NetworkIdError(
|
|
182
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
186
|
+
parseNetworkId(networkId);
|
|
187
|
+
return networkId;
|
|
188
|
+
}
|
|
189
|
+
function isNetworkId(networkId) {
|
|
190
|
+
if (typeof networkId !== "string") {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
parseNetworkId(networkId);
|
|
195
|
+
return true;
|
|
196
|
+
} catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function parsePkhOwnerDid(ownerDid) {
|
|
201
|
+
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
202
|
+
if (!match) return null;
|
|
203
|
+
return {
|
|
204
|
+
chainId: match[1],
|
|
205
|
+
address: match[2].toLowerCase()
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function ownerDidMatches(a, b) {
|
|
209
|
+
const aPkh = parsePkhOwnerDid(a);
|
|
210
|
+
const bPkh = parsePkhOwnerDid(b);
|
|
211
|
+
if (aPkh && bPkh) {
|
|
212
|
+
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
213
|
+
}
|
|
214
|
+
return a === b;
|
|
215
|
+
}
|
|
216
|
+
function networkDiscoveryKey(name) {
|
|
217
|
+
if (!NETWORK_NAME_RE.test(name)) {
|
|
218
|
+
throw new NetworkIdError(
|
|
219
|
+
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
return `.well-known/encryption/network/${name}`;
|
|
223
|
+
}
|
|
224
|
+
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
225
|
+
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
226
|
+
|
|
227
|
+
// src/errors.ts
|
|
228
|
+
var RequestTimeoutError = class extends Error {
|
|
229
|
+
constructor(timeoutMs) {
|
|
230
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
231
|
+
this.name = "TimeoutError";
|
|
232
|
+
this.timeoutMs = timeoutMs;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
function isRequestTimeoutError(error) {
|
|
236
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
237
|
+
}
|
|
238
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
239
|
+
if (timeoutMs === void 0) {
|
|
240
|
+
return {
|
|
241
|
+
code: ErrorCodes.TIMEOUT,
|
|
242
|
+
message: "Request timed out.",
|
|
243
|
+
service,
|
|
244
|
+
...cause === void 0 ? {} : { cause }
|
|
245
|
+
};
|
|
246
|
+
}
|
|
129
247
|
return {
|
|
130
248
|
code: ErrorCodes.TIMEOUT,
|
|
131
|
-
message:
|
|
132
|
-
service
|
|
249
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
250
|
+
service,
|
|
251
|
+
...cause === void 0 ? {} : { cause },
|
|
252
|
+
meta: { timeoutMs }
|
|
133
253
|
};
|
|
134
254
|
}
|
|
135
255
|
function abortedError(service) {
|
|
@@ -139,8 +259,17 @@ function abortedError(service) {
|
|
|
139
259
|
service
|
|
140
260
|
};
|
|
141
261
|
}
|
|
262
|
+
var grantableActions = new Set(
|
|
263
|
+
import_bootstrap.CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
264
|
+
);
|
|
265
|
+
var capabilityServices = new Set(
|
|
266
|
+
import_bootstrap.CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
267
|
+
);
|
|
142
268
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
143
269
|
if (error instanceof Error) {
|
|
270
|
+
if (isRequestTimeoutError(error)) {
|
|
271
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
272
|
+
}
|
|
144
273
|
if (error.name === "AbortError") {
|
|
145
274
|
return abortedError(service);
|
|
146
275
|
}
|
|
@@ -162,6 +291,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
|
162
291
|
}
|
|
163
292
|
|
|
164
293
|
// src/base/BaseService.ts
|
|
294
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
165
295
|
var BaseService = class {
|
|
166
296
|
constructor() {
|
|
167
297
|
/**
|
|
@@ -342,6 +472,64 @@ var BaseService = class {
|
|
|
342
472
|
}
|
|
343
473
|
return controller.signal;
|
|
344
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
477
|
+
*
|
|
478
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
479
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
480
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
481
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
482
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
483
|
+
*
|
|
484
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
485
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
486
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
487
|
+
*
|
|
488
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
489
|
+
* which clears the timer and removes the listeners this adds to the
|
|
490
|
+
* long-lived service and context signals.
|
|
491
|
+
*
|
|
492
|
+
* @param signal - The caller's abort signal for this request
|
|
493
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
494
|
+
*/
|
|
495
|
+
createRequestSignal(signal, timeoutMs) {
|
|
496
|
+
const controller = new AbortController();
|
|
497
|
+
const detachers = [];
|
|
498
|
+
let timer;
|
|
499
|
+
const dispose = () => {
|
|
500
|
+
if (timer !== void 0) {
|
|
501
|
+
clearTimeout(timer);
|
|
502
|
+
timer = void 0;
|
|
503
|
+
}
|
|
504
|
+
for (const detach of detachers.splice(0)) {
|
|
505
|
+
detach();
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
const abort = (reason) => {
|
|
509
|
+
dispose();
|
|
510
|
+
controller.abort(reason);
|
|
511
|
+
};
|
|
512
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
513
|
+
const parents = [
|
|
514
|
+
this.abortController.signal,
|
|
515
|
+
this.context?.abortSignal,
|
|
516
|
+
signal
|
|
517
|
+
].filter((parent) => parent !== void 0);
|
|
518
|
+
for (const parent of parents) {
|
|
519
|
+
if (parent.aborted) {
|
|
520
|
+
abort(parent.reason);
|
|
521
|
+
return requestSignal;
|
|
522
|
+
}
|
|
523
|
+
const onAbort = () => abort(parent.reason);
|
|
524
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
525
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
526
|
+
}
|
|
527
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
528
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
529
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
530
|
+
}
|
|
531
|
+
return requestSignal;
|
|
532
|
+
}
|
|
345
533
|
/**
|
|
346
534
|
* Wrap an operation with error handling and telemetry.
|
|
347
535
|
*
|
|
@@ -481,103 +669,6 @@ function canonicalHashHex(sha256, value) {
|
|
|
481
669
|
return hexEncode(sha256(utf8Encode(canonical)));
|
|
482
670
|
}
|
|
483
671
|
|
|
484
|
-
// src/encryption/networkId.ts
|
|
485
|
-
var URN_PREFIX = "urn:tinycloud:encryption:";
|
|
486
|
-
var NETWORK_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
487
|
-
var PKH_EIP155_DID_RE = /^did:pkh:eip155:(\d+):(0x[a-fA-F0-9]{40})$/;
|
|
488
|
-
var NetworkIdError = class extends Error {
|
|
489
|
-
constructor(message) {
|
|
490
|
-
super(message);
|
|
491
|
-
this.name = "NetworkIdError";
|
|
492
|
-
}
|
|
493
|
-
};
|
|
494
|
-
function parseNetworkId(networkId) {
|
|
495
|
-
if (typeof networkId !== "string" || networkId.length === 0) {
|
|
496
|
-
throw new NetworkIdError("networkId must be a non-empty string");
|
|
497
|
-
}
|
|
498
|
-
if (!networkId.startsWith(URN_PREFIX)) {
|
|
499
|
-
throw new NetworkIdError(
|
|
500
|
-
`networkId must start with ${URN_PREFIX} (got ${JSON.stringify(networkId)})`
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
const body = networkId.slice(URN_PREFIX.length);
|
|
504
|
-
const lastColon = body.lastIndexOf(":");
|
|
505
|
-
if (lastColon <= 0 || lastColon === body.length - 1) {
|
|
506
|
-
throw new NetworkIdError(
|
|
507
|
-
`networkId missing ownerDid or name segment (got ${JSON.stringify(networkId)})`
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
const ownerDid = body.slice(0, lastColon);
|
|
511
|
-
const name = body.slice(lastColon + 1);
|
|
512
|
-
if (!ownerDid.startsWith("did:")) {
|
|
513
|
-
throw new NetworkIdError(
|
|
514
|
-
`networkId ownerDid must be a DID (got ${JSON.stringify(ownerDid)})`
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
const didParts = ownerDid.split(":");
|
|
518
|
-
if (didParts.length < 3 || didParts.some((p) => p.length === 0)) {
|
|
519
|
-
throw new NetworkIdError(
|
|
520
|
-
`networkId ownerDid is not a well-formed DID (got ${JSON.stringify(ownerDid)})`
|
|
521
|
-
);
|
|
522
|
-
}
|
|
523
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
524
|
-
throw new NetworkIdError(
|
|
525
|
-
`networkId name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
return { networkId, ownerDid, name };
|
|
529
|
-
}
|
|
530
|
-
function buildNetworkId(ownerDid, name) {
|
|
531
|
-
if (typeof ownerDid !== "string" || !ownerDid.startsWith("did:")) {
|
|
532
|
-
throw new NetworkIdError("ownerDid must be a DID");
|
|
533
|
-
}
|
|
534
|
-
if (typeof name !== "string" || !NETWORK_NAME_RE.test(name)) {
|
|
535
|
-
throw new NetworkIdError(
|
|
536
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
537
|
-
);
|
|
538
|
-
}
|
|
539
|
-
const networkId = `${URN_PREFIX}${ownerDid}:${name}`;
|
|
540
|
-
parseNetworkId(networkId);
|
|
541
|
-
return networkId;
|
|
542
|
-
}
|
|
543
|
-
function isNetworkId(networkId) {
|
|
544
|
-
if (typeof networkId !== "string") {
|
|
545
|
-
return false;
|
|
546
|
-
}
|
|
547
|
-
try {
|
|
548
|
-
parseNetworkId(networkId);
|
|
549
|
-
return true;
|
|
550
|
-
} catch {
|
|
551
|
-
return false;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
function parsePkhOwnerDid(ownerDid) {
|
|
555
|
-
const match = ownerDid.match(PKH_EIP155_DID_RE);
|
|
556
|
-
if (!match) return null;
|
|
557
|
-
return {
|
|
558
|
-
chainId: match[1],
|
|
559
|
-
address: match[2].toLowerCase()
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
function ownerDidMatches(a, b) {
|
|
563
|
-
const aPkh = parsePkhOwnerDid(a);
|
|
564
|
-
const bPkh = parsePkhOwnerDid(b);
|
|
565
|
-
if (aPkh && bPkh) {
|
|
566
|
-
return aPkh.chainId === bPkh.chainId && aPkh.address === bPkh.address;
|
|
567
|
-
}
|
|
568
|
-
return a === b;
|
|
569
|
-
}
|
|
570
|
-
function networkDiscoveryKey(name) {
|
|
571
|
-
if (!NETWORK_NAME_RE.test(name)) {
|
|
572
|
-
throw new NetworkIdError(
|
|
573
|
-
`network name ${JSON.stringify(name)} must match ${NETWORK_NAME_RE.source}`
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
return `.well-known/encryption/network/${name}`;
|
|
577
|
-
}
|
|
578
|
-
var ENCRYPTION_NETWORK_URN_PREFIX = URN_PREFIX;
|
|
579
|
-
var NETWORK_NAME_PATTERN = NETWORK_NAME_RE;
|
|
580
|
-
|
|
581
672
|
// src/encryption/types.ts
|
|
582
673
|
var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
|
|
583
674
|
var ENVELOPE_VERSION = 1;
|