@tinycloud/cli 1.1.0-beta.19 → 1.1.0-beta.20
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/legacy-entry.js +501 -168
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +4 -4
package/dist/legacy-entry.js
CHANGED
|
@@ -591,8 +591,8 @@ function canonicalizeAddress(address) {
|
|
|
591
591
|
const trimmed = address.trim();
|
|
592
592
|
return trimmed.startsWith("0x") ? `0x${trimmed.slice(2).toLowerCase()}` : trimmed.toLowerCase();
|
|
593
593
|
}
|
|
594
|
-
function normalizePkhIdentifier(
|
|
595
|
-
return
|
|
594
|
+
function normalizePkhIdentifier(identifier2) {
|
|
595
|
+
return identifier2.replace(
|
|
596
596
|
/(eip155:\d+:)(0x[0-9a-fA-F]{40})(?=[:#]|$)/,
|
|
597
597
|
(_match, prefix, address) => prefix + address.toLowerCase()
|
|
598
598
|
);
|
|
@@ -10000,7 +10000,7 @@ var AsyncQueue = class {
|
|
|
10000
10000
|
}
|
|
10001
10001
|
const waiter = this.waiters.shift();
|
|
10002
10002
|
if (waiter) {
|
|
10003
|
-
waiter({ value, done: false });
|
|
10003
|
+
waiter.resolve({ value, done: false });
|
|
10004
10004
|
return;
|
|
10005
10005
|
}
|
|
10006
10006
|
this.values.push(value);
|
|
@@ -10012,7 +10012,22 @@ var AsyncQueue = class {
|
|
|
10012
10012
|
this.closed = true;
|
|
10013
10013
|
while (this.waiters.length > 0) {
|
|
10014
10014
|
const waiter = this.waiters.shift();
|
|
10015
|
-
waiter?.({ value: void 0, done: true });
|
|
10015
|
+
waiter?.resolve({ value: void 0, done: true });
|
|
10016
|
+
}
|
|
10017
|
+
}
|
|
10018
|
+
/**
|
|
10019
|
+
* Fail the queue: pending and future `next()` calls reject with `error`,
|
|
10020
|
+
* so a `for await` consumer sees the iterator throw.
|
|
10021
|
+
*/
|
|
10022
|
+
fail(error) {
|
|
10023
|
+
if (this.closed) {
|
|
10024
|
+
return;
|
|
10025
|
+
}
|
|
10026
|
+
this.closed = true;
|
|
10027
|
+
this.failure = error;
|
|
10028
|
+
while (this.waiters.length > 0) {
|
|
10029
|
+
const waiter = this.waiters.shift();
|
|
10030
|
+
waiter?.reject(error);
|
|
10016
10031
|
}
|
|
10017
10032
|
}
|
|
10018
10033
|
next() {
|
|
@@ -10020,20 +10035,26 @@ var AsyncQueue = class {
|
|
|
10020
10035
|
const value = this.values.shift();
|
|
10021
10036
|
return Promise.resolve({ value, done: false });
|
|
10022
10037
|
}
|
|
10038
|
+
if (this.failure !== void 0) {
|
|
10039
|
+
return Promise.reject(this.failure);
|
|
10040
|
+
}
|
|
10023
10041
|
if (this.closed) {
|
|
10024
10042
|
return Promise.resolve({ value: void 0, done: true });
|
|
10025
10043
|
}
|
|
10026
|
-
return new Promise((resolve5) => {
|
|
10027
|
-
this.waiters.push(resolve5);
|
|
10044
|
+
return new Promise((resolve5, reject) => {
|
|
10045
|
+
this.waiters.push({ resolve: resolve5, reject });
|
|
10028
10046
|
});
|
|
10029
10047
|
}
|
|
10030
10048
|
};
|
|
10049
|
+
var HOOK_STREAM_RETRY_BASE_DELAY_MS = 250;
|
|
10050
|
+
var HOOK_STREAM_RETRY_MAX_DELAY_MS = 3e4;
|
|
10051
|
+
var HOOK_STREAM_HEALTHY_MS = 5e3;
|
|
10031
10052
|
var HooksService = class extends BaseService {
|
|
10032
10053
|
constructor(config = {}) {
|
|
10033
10054
|
super();
|
|
10034
10055
|
this._subscribers = /* @__PURE__ */ new Set();
|
|
10035
|
-
this.
|
|
10036
|
-
this.
|
|
10056
|
+
this._supervising = false;
|
|
10057
|
+
this._sessionGeneration = 0;
|
|
10037
10058
|
this._config = config;
|
|
10038
10059
|
}
|
|
10039
10060
|
get config() {
|
|
@@ -10049,35 +10070,32 @@ var HooksService = class extends BaseService {
|
|
|
10049
10070
|
if (subscriptions.length === 0) {
|
|
10050
10071
|
throw new Error("At least one hook subscription is required");
|
|
10051
10072
|
}
|
|
10052
|
-
const
|
|
10073
|
+
const requested = subscriptions.map(normalizeSubscription);
|
|
10053
10074
|
const subscriber = {
|
|
10054
|
-
requested
|
|
10075
|
+
requested,
|
|
10076
|
+
signatures: requested.map(subscriptionSignature),
|
|
10055
10077
|
ttlSeconds: options.ttlSeconds,
|
|
10056
10078
|
queue: new AsyncQueue()
|
|
10057
10079
|
};
|
|
10058
|
-
|
|
10059
|
-
const abortHandler = () => {
|
|
10080
|
+
const leave = () => {
|
|
10060
10081
|
this._subscribers.delete(subscriber);
|
|
10061
10082
|
subscriber.queue.close();
|
|
10062
|
-
|
|
10083
|
+
this.wake();
|
|
10063
10084
|
};
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
} else {
|
|
10068
|
-
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
10069
|
-
}
|
|
10085
|
+
const { signal } = options;
|
|
10086
|
+
if (signal?.aborted) {
|
|
10087
|
+
return;
|
|
10070
10088
|
}
|
|
10071
|
-
|
|
10089
|
+
signal?.addEventListener("abort", leave, { once: true });
|
|
10090
|
+
this._subscribers.add(subscriber);
|
|
10091
|
+
this.wake();
|
|
10072
10092
|
try {
|
|
10073
10093
|
for await (const event of subscriber.queue) {
|
|
10074
10094
|
yield event;
|
|
10075
10095
|
}
|
|
10076
10096
|
} finally {
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
}
|
|
10080
|
-
abortHandler();
|
|
10097
|
+
signal?.removeEventListener("abort", leave);
|
|
10098
|
+
leave();
|
|
10081
10099
|
}
|
|
10082
10100
|
}
|
|
10083
10101
|
async register(webhook) {
|
|
@@ -10218,146 +10236,292 @@ var HooksService = class extends BaseService {
|
|
|
10218
10236
|
return err(wrapError2("hooks", error));
|
|
10219
10237
|
}
|
|
10220
10238
|
}
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
if (state.signature !== this._activeSignature) {
|
|
10233
|
-
this._activeSignature = state.signature;
|
|
10234
|
-
this.abortSharedStream();
|
|
10239
|
+
/**
|
|
10240
|
+
* Called after anything that may change what the supervisor should do:
|
|
10241
|
+
* subscribe, unsubscribe, session change, sign-out. Interrupts the running
|
|
10242
|
+
* step if the plan moved away from it, and starts the supervisor if none
|
|
10243
|
+
* runs. Touches only SDK-owned state, so it never throws into callers such
|
|
10244
|
+
* as `ServiceContext.setSession`.
|
|
10245
|
+
*/
|
|
10246
|
+
wake() {
|
|
10247
|
+
const phase = this._phase;
|
|
10248
|
+
if (phase && phase.key !== this.plan()?.key) {
|
|
10249
|
+
phase.interrupt.abort();
|
|
10235
10250
|
}
|
|
10236
|
-
if (
|
|
10237
|
-
|
|
10238
|
-
if (!isAbortError(error)) {
|
|
10239
|
-
throw error;
|
|
10240
|
-
}
|
|
10241
|
-
}).finally(() => {
|
|
10242
|
-
this._sharedStreamTask = void 0;
|
|
10243
|
-
this._sharedStreamAbort = void 0;
|
|
10244
|
-
if (this._subscribers.size > 0) {
|
|
10245
|
-
void this.scheduleSharedStreamRefresh();
|
|
10246
|
-
}
|
|
10247
|
-
});
|
|
10251
|
+
if (this._supervising || this._subscribers.size === 0) {
|
|
10252
|
+
return;
|
|
10248
10253
|
}
|
|
10254
|
+
this._supervising = true;
|
|
10255
|
+
this.supervise().catch(() => this.collapse());
|
|
10249
10256
|
}
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10257
|
+
/**
|
|
10258
|
+
* The only owner of the shared stream. Each iteration is one attempt
|
|
10259
|
+
* (mint → open → drain), then a classification and, unless the attempt was
|
|
10260
|
+
* superseded or released its subscribers, a backoff. Every await is a
|
|
10261
|
+
* `phase` that wake() can interrupt; an interrupted phase yields
|
|
10262
|
+
* `undefined`, so a superseded mint can never act. Outside `attempt` and
|
|
10263
|
+
* `pause`, which each own one catch, the loop touches only SDK state.
|
|
10264
|
+
*/
|
|
10265
|
+
async supervise() {
|
|
10266
|
+
let streak = 0;
|
|
10267
|
+
for (; ; ) {
|
|
10268
|
+
const plan = this.plan();
|
|
10269
|
+
if (!plan) {
|
|
10270
|
+
this._supervising = false;
|
|
10271
|
+
return;
|
|
10272
|
+
}
|
|
10273
|
+
const health = { openedAt: 0, delivered: false };
|
|
10274
|
+
const outcome = await this.phase(
|
|
10275
|
+
plan.key,
|
|
10276
|
+
(signal) => this.attempt(plan, signal, health)
|
|
10277
|
+
);
|
|
10278
|
+
if (health.delivered || health.openedAt > 0 && performance.now() - health.openedAt >= HOOK_STREAM_HEALTHY_MS) {
|
|
10279
|
+
streak = 0;
|
|
10256
10280
|
}
|
|
10257
|
-
|
|
10258
|
-
|
|
10281
|
+
if (!outcome) {
|
|
10282
|
+
continue;
|
|
10259
10283
|
}
|
|
10284
|
+
if (this.plan()?.key !== plan.key) {
|
|
10285
|
+
continue;
|
|
10286
|
+
}
|
|
10287
|
+
if (outcome.kind === "stopped") {
|
|
10288
|
+
this.release();
|
|
10289
|
+
continue;
|
|
10290
|
+
}
|
|
10291
|
+
if (outcome.kind === "refused" && outcome.terminal) {
|
|
10292
|
+
this.release(outcome.error);
|
|
10293
|
+
this.report(outcome.error);
|
|
10294
|
+
continue;
|
|
10295
|
+
}
|
|
10296
|
+
if (outcome.kind !== "ended") {
|
|
10297
|
+
this.report(outcome.error);
|
|
10298
|
+
}
|
|
10299
|
+
streak += 1;
|
|
10300
|
+
await this.phase(
|
|
10301
|
+
plan.key,
|
|
10302
|
+
(signal) => this.pause(streak, signal)
|
|
10303
|
+
);
|
|
10260
10304
|
}
|
|
10261
|
-
const subscriptions = [...merged.values()].sort(
|
|
10262
|
-
(left, right) => subscriptionSignature(left).localeCompare(subscriptionSignature(right))
|
|
10263
|
-
);
|
|
10264
|
-
const ttlSeconds = ttlCandidates.length > 0 ? Math.min(...ttlCandidates) : void 0;
|
|
10265
|
-
const signature = JSON.stringify({
|
|
10266
|
-
subscriptions: subscriptions.map(subscriptionSignature),
|
|
10267
|
-
ttlSeconds
|
|
10268
|
-
});
|
|
10269
|
-
return {
|
|
10270
|
-
subscriptions,
|
|
10271
|
-
ttlSeconds,
|
|
10272
|
-
signature
|
|
10273
|
-
};
|
|
10274
10305
|
}
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10306
|
+
/**
|
|
10307
|
+
* Run one step under an interrupt that wake() fires when the plan key moves
|
|
10308
|
+
* on. An interrupted step's result is discarded. The interrupt is also
|
|
10309
|
+
* fired when the step returns, which releases whatever it left open: the
|
|
10310
|
+
* request signal and its listeners, an unread response body, a timer.
|
|
10311
|
+
*/
|
|
10312
|
+
async phase(key, step) {
|
|
10313
|
+
const interrupt = new AbortController();
|
|
10314
|
+
this._phase = { key, interrupt };
|
|
10278
10315
|
try {
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10316
|
+
if (this.plan()?.key !== key) {
|
|
10317
|
+
interrupt.abort();
|
|
10318
|
+
}
|
|
10319
|
+
const result = await step(interrupt.signal);
|
|
10320
|
+
return interrupt.signal.aborted ? void 0 : result;
|
|
10321
|
+
} finally {
|
|
10322
|
+
this._phase = void 0;
|
|
10323
|
+
interrupt.abort();
|
|
10324
|
+
}
|
|
10325
|
+
}
|
|
10326
|
+
/**
|
|
10327
|
+
* One mint → open → drain. The single catch site for everything the
|
|
10328
|
+
* attempt touches that the SDK does not own: context accessors, invoke,
|
|
10329
|
+
* fetch, response bodies, the SSE parser. Never rejects.
|
|
10330
|
+
*/
|
|
10331
|
+
async attempt(plan, signal, health) {
|
|
10332
|
+
let phase = "mint";
|
|
10333
|
+
let request;
|
|
10334
|
+
const owns = () => !signal.aborted && !request?.signal.aborted && this.plan()?.key === plan.key;
|
|
10335
|
+
try {
|
|
10336
|
+
const context = this.context;
|
|
10337
|
+
const contextSignal = context.abortSignal;
|
|
10338
|
+
this._lastContextSignal = contextSignal;
|
|
10339
|
+
if (!context.isAuthenticated || contextSignal?.aborted) {
|
|
10340
|
+
return { kind: "stopped" };
|
|
10341
|
+
}
|
|
10342
|
+
request = this.createRequestSignal(signal, 0);
|
|
10343
|
+
const host = this.host;
|
|
10344
|
+
const minted = await awaitOwned(
|
|
10345
|
+
request.signal,
|
|
10346
|
+
() => context.fetch(`${host}/hooks/tickets`, {
|
|
10347
|
+
method: "POST",
|
|
10348
|
+
headers: {
|
|
10349
|
+
...serviceHeadersToRecord(this.createInvokeHeaders(plan.subscriptions)),
|
|
10350
|
+
"content-type": "application/json"
|
|
10351
|
+
},
|
|
10352
|
+
body: JSON.stringify({
|
|
10353
|
+
subscriptions: plan.subscriptions,
|
|
10354
|
+
ttlSeconds: plan.ttlSeconds
|
|
10355
|
+
}),
|
|
10356
|
+
signal: request.signal
|
|
10357
|
+
})
|
|
10284
10358
|
);
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10359
|
+
if (!owns()) return { kind: "stopped" };
|
|
10360
|
+
if (!minted.ok) {
|
|
10361
|
+
const status = minted.status;
|
|
10362
|
+
const error = await awaitOwned(
|
|
10363
|
+
request.signal,
|
|
10364
|
+
() => responseError("hooks", "failed to mint hook ticket", minted)
|
|
10365
|
+
);
|
|
10366
|
+
if (!owns()) return { kind: "stopped" };
|
|
10367
|
+
return { kind: "refused", terminal: isTerminalMintRefusal(status), error };
|
|
10368
|
+
}
|
|
10369
|
+
const body = await awaitOwned(request.signal, () => minted.json());
|
|
10370
|
+
if (!owns()) return { kind: "stopped" };
|
|
10371
|
+
const ticket = body !== null && typeof body === "object" && "ticket" in body ? body.ticket : void 0;
|
|
10372
|
+
if (typeof ticket !== "string" || ticket.length === 0) {
|
|
10373
|
+
throw new Error("Hook ticket response did not include a ticket");
|
|
10374
|
+
}
|
|
10375
|
+
phase = "open";
|
|
10376
|
+
if (!owns()) return { kind: "stopped" };
|
|
10377
|
+
const stream = await awaitOwned(
|
|
10378
|
+
request.signal,
|
|
10379
|
+
() => context.fetch(`${host}/hooks/events?ticket=${encodeURIComponent(ticket)}`, {
|
|
10380
|
+
method: "GET",
|
|
10381
|
+
headers: { accept: "text/event-stream" },
|
|
10382
|
+
signal: request.signal
|
|
10383
|
+
})
|
|
10289
10384
|
);
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
if (
|
|
10300
|
-
|
|
10301
|
-
|
|
10385
|
+
if (!owns()) return { kind: "stopped" };
|
|
10386
|
+
if (!stream.ok) {
|
|
10387
|
+
return { kind: "refused", terminal: false, error: hookStreamRefusal(stream.status) };
|
|
10388
|
+
}
|
|
10389
|
+
health.openedAt = performance.now();
|
|
10390
|
+
const iterator = parseSseStream(stream.body, request.signal)[Symbol.asyncIterator]();
|
|
10391
|
+
try {
|
|
10392
|
+
for (; ; ) {
|
|
10393
|
+
const next = await awaitOwned(request.signal, () => iterator.next());
|
|
10394
|
+
if (!owns()) return { kind: "stopped" };
|
|
10395
|
+
if (next.done) break;
|
|
10396
|
+
const message = next.value;
|
|
10397
|
+
if (!message.data) continue;
|
|
10398
|
+
const event = parseHookEvent(message);
|
|
10399
|
+
if (!owns()) return { kind: "stopped" };
|
|
10400
|
+
this.dispatch(event);
|
|
10401
|
+
health.delivered = true;
|
|
10302
10402
|
}
|
|
10403
|
+
} finally {
|
|
10404
|
+
const closing = iterator.return?.();
|
|
10405
|
+
if (closing) void Promise.resolve(closing).then(() => void 0, () => void 0);
|
|
10303
10406
|
}
|
|
10407
|
+
return owns() ? { kind: "ended" } : { kind: "stopped" };
|
|
10408
|
+
} catch (thrown) {
|
|
10409
|
+
return request?.signal.aborted || thrown === SUPERSEDED ? { kind: "stopped" } : { kind: "failed", error: hookStreamFailure(phase, thrown) };
|
|
10410
|
+
}
|
|
10411
|
+
}
|
|
10412
|
+
/**
|
|
10413
|
+
* Back off before the next attempt. `config.streamRetry` overrides the
|
|
10414
|
+
* delay and the clock; whatever they do, the pause ends by the delay or the
|
|
10415
|
+
* interrupt, then yields one timer turn so an instant clock cannot starve
|
|
10416
|
+
* due timers or the process.
|
|
10417
|
+
*/
|
|
10418
|
+
async pause(attempt, signal) {
|
|
10419
|
+
try {
|
|
10420
|
+
this._lastContextSignal = this.context.abortSignal;
|
|
10421
|
+
} catch {
|
|
10422
|
+
}
|
|
10423
|
+
const contextSignal = this._lastContextSignal;
|
|
10424
|
+
const waits = [];
|
|
10425
|
+
const aborts = [];
|
|
10426
|
+
try {
|
|
10427
|
+
const retry = this._config.streamRetry;
|
|
10428
|
+
const delayMs = retry?.delay?.(attempt) ?? hookStreamRetryDelay(attempt);
|
|
10429
|
+
waits.push((retry?.wait ?? sleep)(delayMs, attempt, signal));
|
|
10430
|
+
} catch {
|
|
10431
|
+
waits.push(Promise.resolve());
|
|
10432
|
+
}
|
|
10433
|
+
aborts.push(abortPromise(signal));
|
|
10434
|
+
if (contextSignal) aborts.push(abortPromise(contextSignal));
|
|
10435
|
+
try {
|
|
10436
|
+
await Promise.race([...waits, ...aborts.map(({ promise }) => promise)]);
|
|
10437
|
+
} catch {
|
|
10304
10438
|
} finally {
|
|
10305
|
-
|
|
10306
|
-
|
|
10439
|
+
for (const abort of aborts) abort.dispose();
|
|
10440
|
+
}
|
|
10441
|
+
await new Promise((resolve5) => setTimeout(resolve5, 0));
|
|
10442
|
+
}
|
|
10443
|
+
/** The stream the current subscribers need, or undefined when none remain. */
|
|
10444
|
+
plan() {
|
|
10445
|
+
if (this._subscribers.size === 0) {
|
|
10446
|
+
return void 0;
|
|
10447
|
+
}
|
|
10448
|
+
const merged = /* @__PURE__ */ new Map();
|
|
10449
|
+
let ttlSeconds;
|
|
10450
|
+
for (const subscriber of this._subscribers) {
|
|
10451
|
+
subscriber.requested.forEach(
|
|
10452
|
+
(subscription, index) => merged.set(subscriber.signatures[index], subscription)
|
|
10453
|
+
);
|
|
10454
|
+
if (typeof subscriber.ttlSeconds === "number") {
|
|
10455
|
+
ttlSeconds = Math.min(subscriber.ttlSeconds, ttlSeconds ?? Infinity);
|
|
10307
10456
|
}
|
|
10308
10457
|
}
|
|
10458
|
+
const signatures = [...merged.keys()].sort();
|
|
10459
|
+
return {
|
|
10460
|
+
key: JSON.stringify([this._sessionGeneration, signatures, ttlSeconds ?? null]),
|
|
10461
|
+
subscriptions: signatures.map((signature) => merged.get(signature)),
|
|
10462
|
+
ttlSeconds
|
|
10463
|
+
};
|
|
10309
10464
|
}
|
|
10310
|
-
|
|
10311
|
-
this.
|
|
10465
|
+
dispatch(event) {
|
|
10466
|
+
for (const subscriber of this._subscribers) {
|
|
10467
|
+
if (matchesAnySubscription(event, subscriber.requested)) {
|
|
10468
|
+
subscriber.queue.push(event);
|
|
10469
|
+
}
|
|
10470
|
+
}
|
|
10312
10471
|
}
|
|
10313
|
-
|
|
10314
|
-
|
|
10472
|
+
/**
|
|
10473
|
+
* Detach every subscriber. With `error`, their iterators throw it after
|
|
10474
|
+
* draining buffered events; without, they complete.
|
|
10475
|
+
*/
|
|
10476
|
+
release(error) {
|
|
10477
|
+
const subscribers = [...this._subscribers];
|
|
10478
|
+
this._subscribers.clear();
|
|
10479
|
+
for (const { queue } of subscribers) {
|
|
10480
|
+
if (error) {
|
|
10481
|
+
queue.fail(error);
|
|
10482
|
+
} else {
|
|
10483
|
+
queue.close();
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10315
10486
|
}
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
const ticketResponse = await this.context.fetch(`${host}/hooks/tickets`, {
|
|
10320
|
-
method: "POST",
|
|
10321
|
-
headers: {
|
|
10322
|
-
...serviceHeadersToRecord(headers),
|
|
10323
|
-
"content-type": "application/json"
|
|
10324
|
-
},
|
|
10325
|
-
body: JSON.stringify({
|
|
10326
|
-
subscriptions,
|
|
10327
|
-
ttlSeconds
|
|
10328
|
-
}),
|
|
10329
|
-
signal
|
|
10330
|
-
});
|
|
10331
|
-
if (!ticketResponse.ok) {
|
|
10332
|
-
throw await responseError(
|
|
10333
|
-
"hooks",
|
|
10334
|
-
"failed to mint hook ticket",
|
|
10335
|
-
ticketResponse
|
|
10336
|
-
);
|
|
10487
|
+
report(error) {
|
|
10488
|
+
if (error.meta && typeof error.meta === "object") {
|
|
10489
|
+
Object.freeze(error.meta);
|
|
10337
10490
|
}
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10491
|
+
Object.freeze(error);
|
|
10492
|
+
try {
|
|
10493
|
+
this.emitError(error, "stream");
|
|
10494
|
+
} catch {
|
|
10341
10495
|
}
|
|
10342
|
-
return ticketJson;
|
|
10343
10496
|
}
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10497
|
+
/**
|
|
10498
|
+
* Unreachable by construction. If the loop ever rejects anyway, fail its
|
|
10499
|
+
* subscribers visibly instead of stranding them or crashing the process.
|
|
10500
|
+
*/
|
|
10501
|
+
collapse() {
|
|
10502
|
+
this._supervising = false;
|
|
10503
|
+
this._phase?.interrupt.abort();
|
|
10504
|
+
this._phase = void 0;
|
|
10505
|
+
const error = serviceError(
|
|
10506
|
+
ErrorCodes.NETWORK_ERROR,
|
|
10507
|
+
"hook stream supervisor stopped unexpectedly",
|
|
10508
|
+
"hooks"
|
|
10352
10509
|
);
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10510
|
+
this.report(error);
|
|
10511
|
+
this.release(error);
|
|
10512
|
+
}
|
|
10513
|
+
onSessionChange(session) {
|
|
10514
|
+
super.onSessionChange(session);
|
|
10515
|
+
this._sessionGeneration += 1;
|
|
10516
|
+
this.wake();
|
|
10517
|
+
}
|
|
10518
|
+
onSignOut() {
|
|
10519
|
+
super.onSignOut();
|
|
10520
|
+
this.release();
|
|
10521
|
+
this.wake();
|
|
10522
|
+
}
|
|
10523
|
+
createHookHeaders(action, path) {
|
|
10524
|
+
return this.context.invoke(this.session, "hooks", path, action);
|
|
10361
10525
|
}
|
|
10362
10526
|
createInvokeHeaders(subscriptions) {
|
|
10363
10527
|
const entries = subscriptions.map((subscription) => ({
|
|
@@ -10388,11 +10552,168 @@ function buildScopePath(service, pathPrefix) {
|
|
|
10388
10552
|
const normalized = normalizePathPrefix(pathPrefix);
|
|
10389
10553
|
return normalized ? `${service}/${normalized}` : service;
|
|
10390
10554
|
}
|
|
10555
|
+
function hookStreamRetryDelay(attempt) {
|
|
10556
|
+
const cap = Math.min(
|
|
10557
|
+
HOOK_STREAM_RETRY_BASE_DELAY_MS * 2 ** Math.max(0, attempt - 1),
|
|
10558
|
+
HOOK_STREAM_RETRY_MAX_DELAY_MS
|
|
10559
|
+
);
|
|
10560
|
+
return cap / 2 + Math.random() * (cap / 2);
|
|
10561
|
+
}
|
|
10562
|
+
function isTerminalMintRefusal(status) {
|
|
10563
|
+
return typeof status === "number" && status >= 400 && status < 500 && status !== 408 && status !== 429;
|
|
10564
|
+
}
|
|
10565
|
+
var SUPERSEDED = /* @__PURE__ */ Symbol("hooks attempt superseded");
|
|
10566
|
+
async function awaitOwned(signal, operation) {
|
|
10567
|
+
if (signal.aborted) {
|
|
10568
|
+
if (typeof operation !== "function") {
|
|
10569
|
+
void operation.then(cancelLateResponse, () => void 0);
|
|
10570
|
+
}
|
|
10571
|
+
throw SUPERSEDED;
|
|
10572
|
+
}
|
|
10573
|
+
const promise = typeof operation === "function" ? operation() : operation;
|
|
10574
|
+
return new Promise((resolve5, reject) => {
|
|
10575
|
+
let settled = false;
|
|
10576
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
10577
|
+
const onAbort = () => {
|
|
10578
|
+
if (settled) return;
|
|
10579
|
+
settled = true;
|
|
10580
|
+
cleanup();
|
|
10581
|
+
reject(SUPERSEDED);
|
|
10582
|
+
};
|
|
10583
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
10584
|
+
promise.then(
|
|
10585
|
+
(value) => {
|
|
10586
|
+
if (settled) {
|
|
10587
|
+
cancelLateResponse(value);
|
|
10588
|
+
return;
|
|
10589
|
+
}
|
|
10590
|
+
settled = true;
|
|
10591
|
+
cleanup();
|
|
10592
|
+
resolve5(value);
|
|
10593
|
+
},
|
|
10594
|
+
(error) => {
|
|
10595
|
+
if (settled) return;
|
|
10596
|
+
settled = true;
|
|
10597
|
+
cleanup();
|
|
10598
|
+
reject(error);
|
|
10599
|
+
}
|
|
10600
|
+
);
|
|
10601
|
+
});
|
|
10602
|
+
}
|
|
10603
|
+
function cancelLateResponse(value) {
|
|
10604
|
+
if (!(value instanceof Response) || !value.body) return;
|
|
10605
|
+
try {
|
|
10606
|
+
const cancellation = value.body.cancel();
|
|
10607
|
+
void cancellation.then(() => void 0, () => void 0);
|
|
10608
|
+
} catch {
|
|
10609
|
+
}
|
|
10610
|
+
}
|
|
10611
|
+
function hookStreamRefusal(status) {
|
|
10612
|
+
const code3 = typeof status === "number" ? status : void 0;
|
|
10613
|
+
return serviceError(
|
|
10614
|
+
ErrorCodes.NETWORK_ERROR,
|
|
10615
|
+
`hook stream open refused: ${code3 ?? "unknown status"}`,
|
|
10616
|
+
"hooks",
|
|
10617
|
+
{ meta: { phase: "open", status: code3 } }
|
|
10618
|
+
);
|
|
10619
|
+
}
|
|
10620
|
+
var STREAM_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
10621
|
+
"Error",
|
|
10622
|
+
"TypeError",
|
|
10623
|
+
"AbortError",
|
|
10624
|
+
"TimeoutError",
|
|
10625
|
+
"SyntaxError",
|
|
10626
|
+
"RangeError",
|
|
10627
|
+
"NetworkError"
|
|
10628
|
+
]);
|
|
10629
|
+
function hookStreamFailure(phase, thrown) {
|
|
10630
|
+
const candidateName = readProperty(thrown, "name");
|
|
10631
|
+
const name = typeof candidateName === "string" && STREAM_ERROR_NAMES.has(candidateName) ? candidateName : "Error";
|
|
10632
|
+
const code3 = identifier(readProperty(thrown, "code")) ?? identifier(readProperty(readProperty(thrown, "cause"), "code"));
|
|
10633
|
+
return serviceError(
|
|
10634
|
+
ErrorCodes.NETWORK_ERROR,
|
|
10635
|
+
`hook stream ${phase} failed: ${name}${code3 ? ` (${code3})` : ""}`,
|
|
10636
|
+
"hooks",
|
|
10637
|
+
{ meta: { phase, errorName: name, ...code3 ? { errorCode: code3 } : {} } }
|
|
10638
|
+
);
|
|
10639
|
+
}
|
|
10640
|
+
var STREAM_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
10641
|
+
"ECONNREFUSED",
|
|
10642
|
+
"ECONNRESET",
|
|
10643
|
+
"ECONNABORTED",
|
|
10644
|
+
"ETIMEDOUT",
|
|
10645
|
+
"EPIPE",
|
|
10646
|
+
"ENOTFOUND",
|
|
10647
|
+
"EAI_AGAIN",
|
|
10648
|
+
"EHOSTUNREACH",
|
|
10649
|
+
"ENETUNREACH",
|
|
10650
|
+
"ENETDOWN",
|
|
10651
|
+
"EADDRNOTAVAIL",
|
|
10652
|
+
"UND_ERR_SOCKET",
|
|
10653
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
10654
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
10655
|
+
"UND_ERR_BODY_TIMEOUT",
|
|
10656
|
+
"UND_ERR_CLOSED",
|
|
10657
|
+
"UND_ERR_ABORTED",
|
|
10658
|
+
"UND_ERR_RESPONSE_STATUS_CODE",
|
|
10659
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
10660
|
+
"CERT_HAS_EXPIRED",
|
|
10661
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
10662
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
10663
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
10664
|
+
"ERR_SSL_WRONG_VERSION_NUMBER"
|
|
10665
|
+
]);
|
|
10666
|
+
function identifier(value) {
|
|
10667
|
+
return typeof value === "string" && STREAM_ERROR_CODES.has(value) ? value : void 0;
|
|
10668
|
+
}
|
|
10669
|
+
function readProperty(value, key) {
|
|
10670
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
10671
|
+
return void 0;
|
|
10672
|
+
}
|
|
10673
|
+
try {
|
|
10674
|
+
return Reflect.get(value, key);
|
|
10675
|
+
} catch {
|
|
10676
|
+
return void 0;
|
|
10677
|
+
}
|
|
10678
|
+
}
|
|
10679
|
+
function sleep(delayMs, _attempt, signal) {
|
|
10680
|
+
return new Promise((resolve5) => {
|
|
10681
|
+
const finish = () => {
|
|
10682
|
+
clearTimeout(timer);
|
|
10683
|
+
signal.removeEventListener("abort", stop);
|
|
10684
|
+
resolve5();
|
|
10685
|
+
};
|
|
10686
|
+
const timer = setTimeout(finish, delayMs);
|
|
10687
|
+
timer.unref?.();
|
|
10688
|
+
const stop = () => finish();
|
|
10689
|
+
if (signal.aborted) {
|
|
10690
|
+
finish();
|
|
10691
|
+
} else {
|
|
10692
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
10693
|
+
}
|
|
10694
|
+
});
|
|
10695
|
+
}
|
|
10696
|
+
function abortPromise(signal) {
|
|
10697
|
+
let resolve5;
|
|
10698
|
+
const promise = new Promise((done) => {
|
|
10699
|
+
resolve5 = done;
|
|
10700
|
+
});
|
|
10701
|
+
const onAbort = () => resolve5();
|
|
10702
|
+
if (signal.aborted) {
|
|
10703
|
+
resolve5();
|
|
10704
|
+
} else {
|
|
10705
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
10706
|
+
}
|
|
10707
|
+
return {
|
|
10708
|
+
promise,
|
|
10709
|
+
dispose: () => signal.removeEventListener("abort", onAbort)
|
|
10710
|
+
};
|
|
10711
|
+
}
|
|
10391
10712
|
function normalizeSubscription(subscription) {
|
|
10392
10713
|
return {
|
|
10393
10714
|
...subscription,
|
|
10394
10715
|
pathPrefix: normalizePathPrefix(subscription.pathPrefix),
|
|
10395
|
-
abilities: subscription.abilities
|
|
10716
|
+
abilities: subscription.abilities ? [...subscription.abilities] : []
|
|
10396
10717
|
};
|
|
10397
10718
|
}
|
|
10398
10719
|
function subscriptionSignature(subscription) {
|
|
@@ -10458,9 +10779,6 @@ async function responseError(service, message, response) {
|
|
|
10458
10779
|
meta: { ...error.meta, status: response.status, statusText: response.statusText }
|
|
10459
10780
|
};
|
|
10460
10781
|
}
|
|
10461
|
-
function isAbortError(error) {
|
|
10462
|
-
return error instanceof DOMException && error.name === "AbortError";
|
|
10463
|
-
}
|
|
10464
10782
|
async function* parseSseStream(body, signal) {
|
|
10465
10783
|
if (!body) {
|
|
10466
10784
|
throw new Error("Hook stream response does not expose a readable body");
|
|
@@ -10489,11 +10807,24 @@ async function* parseSseStream(body, signal) {
|
|
|
10489
10807
|
async function* readBodyChunks(body, signal) {
|
|
10490
10808
|
const asyncIterable = body;
|
|
10491
10809
|
if (typeof asyncIterable?.[Symbol.asyncIterator] === "function") {
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10810
|
+
const iterator = asyncIterable[Symbol.asyncIterator]();
|
|
10811
|
+
const cancel = () => {
|
|
10812
|
+
try {
|
|
10813
|
+
const closing = iterator.return?.();
|
|
10814
|
+
if (closing) void Promise.resolve(closing).then(() => void 0, () => void 0);
|
|
10815
|
+
} catch {
|
|
10495
10816
|
}
|
|
10496
|
-
|
|
10817
|
+
};
|
|
10818
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
10819
|
+
try {
|
|
10820
|
+
while (!signal?.aborted) {
|
|
10821
|
+
const next = await iterator.next();
|
|
10822
|
+
if (next.done) break;
|
|
10823
|
+
yield next.value;
|
|
10824
|
+
}
|
|
10825
|
+
} finally {
|
|
10826
|
+
signal?.removeEventListener("abort", cancel);
|
|
10827
|
+
cancel();
|
|
10497
10828
|
}
|
|
10498
10829
|
return;
|
|
10499
10830
|
}
|
|
@@ -10502,21 +10833,23 @@ async function* readBodyChunks(body, signal) {
|
|
|
10502
10833
|
throw new Error("Unsupported hook stream body type");
|
|
10503
10834
|
}
|
|
10504
10835
|
const reader = stream.getReader();
|
|
10836
|
+
const cancelReader = () => {
|
|
10837
|
+
try {
|
|
10838
|
+
const cancellation = reader.cancel?.();
|
|
10839
|
+
if (cancellation) void cancellation.then(() => void 0, () => void 0);
|
|
10840
|
+
} catch {
|
|
10841
|
+
}
|
|
10842
|
+
};
|
|
10843
|
+
signal?.addEventListener("abort", cancelReader, { once: true });
|
|
10505
10844
|
try {
|
|
10506
10845
|
while (!signal?.aborted) {
|
|
10507
10846
|
const { done, value } = await reader.read();
|
|
10508
|
-
if (done)
|
|
10509
|
-
|
|
10510
|
-
}
|
|
10511
|
-
if (value) {
|
|
10512
|
-
yield value;
|
|
10513
|
-
}
|
|
10847
|
+
if (done) break;
|
|
10848
|
+
if (value) yield value;
|
|
10514
10849
|
}
|
|
10515
10850
|
} finally {
|
|
10516
|
-
|
|
10517
|
-
|
|
10518
|
-
} catch {
|
|
10519
|
-
}
|
|
10851
|
+
signal?.removeEventListener("abort", cancelReader);
|
|
10852
|
+
cancelReader();
|
|
10520
10853
|
reader.releaseLock?.();
|
|
10521
10854
|
}
|
|
10522
10855
|
}
|
|
@@ -12897,10 +13230,10 @@ var EncryptionService = class extends BaseService {
|
|
|
12897
13230
|
get crypto() {
|
|
12898
13231
|
return this._config.crypto;
|
|
12899
13232
|
}
|
|
12900
|
-
async discoverNetwork(
|
|
13233
|
+
async discoverNetwork(identifier2, ownerDid) {
|
|
12901
13234
|
this.assertActive();
|
|
12902
13235
|
const result = await discoverNetwork({
|
|
12903
|
-
identifier,
|
|
13236
|
+
identifier: identifier2,
|
|
12904
13237
|
...ownerDid !== void 0 ? { ownerDid } : {},
|
|
12905
13238
|
...this._config.node !== void 0 ? { node: this._config.node } : {},
|
|
12906
13239
|
...this._config.wellKnown !== void 0 ? { wellKnown: this._config.wellKnown } : {}
|
|
@@ -30222,17 +30555,17 @@ function validRecipientDid(value) {
|
|
|
30222
30555
|
if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
|
|
30223
30556
|
const parts = value.split(":");
|
|
30224
30557
|
if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
|
|
30225
|
-
const
|
|
30226
|
-
if (
|
|
30558
|
+
const identifier2 = parts.slice(2);
|
|
30559
|
+
if (identifier2.some((part) => part.length === 0)) return false;
|
|
30227
30560
|
if (parts[1] === "web") {
|
|
30228
|
-
const host =
|
|
30561
|
+
const host = identifier2[0] ?? "";
|
|
30229
30562
|
if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
|
|
30230
|
-
return
|
|
30563
|
+
return identifier2.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
30231
30564
|
}
|
|
30232
|
-
if (parts[1] === "pkh") return
|
|
30565
|
+
if (parts[1] === "pkh") return identifier2.length >= 3 && identifier2.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
30233
30566
|
if (parts[1] === "key") {
|
|
30234
30567
|
try {
|
|
30235
|
-
const bytes3 = base58btc2.decode(
|
|
30568
|
+
const bytes3 = base58btc2.decode(identifier2.join(":"));
|
|
30236
30569
|
return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
|
|
30237
30570
|
} catch {
|
|
30238
30571
|
return false;
|