@tinycloud/sdk-services 3.1.0-beta.9 → 3.1.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.
- package/dist/index.cjs +551 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -12
- package/dist/index.d.ts +103 -12
- package/dist/index.js +551 -171
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +56 -11
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +12 -2
- package/dist/kv/index.d.ts +12 -2
- package/dist/kv/index.js +56 -11
- package/dist/kv/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1863,6 +1863,24 @@ var MAX_KV_BATCH_READ_ITEMS = 100;
|
|
|
1863
1863
|
function isJsonObject(value) {
|
|
1864
1864
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1865
1865
|
}
|
|
1866
|
+
var pathByteEncoder = new TextEncoder();
|
|
1867
|
+
function comparePathsByBytes(a, b) {
|
|
1868
|
+
const left = pathByteEncoder.encode(a);
|
|
1869
|
+
const right = pathByteEncoder.encode(b);
|
|
1870
|
+
const length = Math.min(left.length, right.length);
|
|
1871
|
+
for (let index = 0; index < length; index++) {
|
|
1872
|
+
if (left[index] !== right[index]) {
|
|
1873
|
+
return left[index] - right[index];
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
return left.length - right.length;
|
|
1877
|
+
}
|
|
1878
|
+
var REVOKED_BODY = /^(?:Invalid invocation: )?delegation-(?:(revoked): [A-Za-z0-9]+|(ancestor-revoked): ancestor=[A-Za-z0-9]+ invoked=[A-Za-z0-9]+)$/;
|
|
1879
|
+
function revocationCodeOf(body) {
|
|
1880
|
+
const match = REVOKED_BODY.exec(body.trim());
|
|
1881
|
+
if (match === null) return void 0;
|
|
1882
|
+
return match[1] !== void 0 ? ErrorCodes.AUTH_DELEGATION_REVOKED : ErrorCodes.AUTH_DELEGATION_ANCESTOR_REVOKED;
|
|
1883
|
+
}
|
|
1866
1884
|
function encodeKvBatchPartName(path) {
|
|
1867
1885
|
return encodeURIComponent(path).replace(
|
|
1868
1886
|
/[!'()*]/g,
|
|
@@ -2090,15 +2108,25 @@ var KVService = class extends BaseService {
|
|
|
2090
2108
|
)?.[1];
|
|
2091
2109
|
return contentType?.includes("application/json") ? JSON.parse(text) : text;
|
|
2092
2110
|
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Validate a batch read response and return its items in the caller's
|
|
2113
|
+
* request order. The node flattens invocation abilities from a `BTreeMap`,
|
|
2114
|
+
* so results arrive sorted by UTF-8 byte order of the path, not in request
|
|
2115
|
+
* order. Items that carry their path in `key` are matched by path; if no
|
|
2116
|
+
* item carries a key, items are assumed to be in the node's byte-sorted
|
|
2117
|
+
* order and the request is aligned the same way. Any mix of keyed and
|
|
2118
|
+
* keyless items, a missing requested path, an unrequested path, or a
|
|
2119
|
+
* malformed item fails closed (returns undefined).
|
|
2120
|
+
*/
|
|
2093
2121
|
normalizeBatchReadResponse(data, paths, requireData) {
|
|
2094
2122
|
if (!data || typeof data !== "object") return void 0;
|
|
2095
2123
|
const response = data;
|
|
2096
|
-
|
|
2124
|
+
const items = response.results;
|
|
2125
|
+
if (!Array.isArray(items) || items.length !== paths.length) {
|
|
2097
2126
|
return void 0;
|
|
2098
2127
|
}
|
|
2099
|
-
for (
|
|
2100
|
-
|
|
2101
|
-
if (!item || typeof item !== "object" || item.key !== paths[index] || typeof item.ok !== "boolean") {
|
|
2128
|
+
for (const item of items) {
|
|
2129
|
+
if (!item || typeof item !== "object" || typeof item.ok !== "boolean") {
|
|
2102
2130
|
return void 0;
|
|
2103
2131
|
}
|
|
2104
2132
|
if (item.ok && (!item.headers || typeof item.headers !== "object" || Object.values(item.headers).some((value) => typeof value !== "string") || requireData && typeof item.dataBase64 !== "string")) {
|
|
@@ -2108,7 +2136,24 @@ var KVService = class extends BaseService {
|
|
|
2108
2136
|
return void 0;
|
|
2109
2137
|
}
|
|
2110
2138
|
}
|
|
2111
|
-
|
|
2139
|
+
if (items.every((item) => typeof item.key === "string")) {
|
|
2140
|
+
const byPath = new Map(items.map((item) => [item.key, item]));
|
|
2141
|
+
if (byPath.size !== items.length) return void 0;
|
|
2142
|
+
const aligned2 = [];
|
|
2143
|
+
for (const path of paths) {
|
|
2144
|
+
const item = byPath.get(path);
|
|
2145
|
+
if (!item) return void 0;
|
|
2146
|
+
aligned2.push(item);
|
|
2147
|
+
}
|
|
2148
|
+
return aligned2;
|
|
2149
|
+
}
|
|
2150
|
+
if (items.some((item) => item.key !== void 0)) return void 0;
|
|
2151
|
+
const requestOrder = paths.map((_, index) => index).sort((a, b) => comparePathsByBytes(paths[a], paths[b]));
|
|
2152
|
+
const aligned = new Array(items.length);
|
|
2153
|
+
for (let position = 0; position < requestOrder.length; position++) {
|
|
2154
|
+
aligned[requestOrder[position]] = items[position];
|
|
2155
|
+
}
|
|
2156
|
+
return aligned;
|
|
2112
2157
|
}
|
|
2113
2158
|
async batchRead(keys, action, options) {
|
|
2114
2159
|
if (!this.requireAuth()) return err(authRequiredError("kv"));
|
|
@@ -2201,19 +2246,19 @@ var KVService = class extends BaseService {
|
|
|
2201
2246
|
{ meta: { status: response.status, statusText: response.statusText } }
|
|
2202
2247
|
));
|
|
2203
2248
|
}
|
|
2204
|
-
const
|
|
2249
|
+
const items = this.normalizeBatchReadResponse(
|
|
2205
2250
|
await response.json(),
|
|
2206
2251
|
paths,
|
|
2207
2252
|
action === KVAction.GET
|
|
2208
2253
|
);
|
|
2209
|
-
if (!
|
|
2254
|
+
if (!items) {
|
|
2210
2255
|
return err(serviceError(
|
|
2211
2256
|
ErrorCodes.NETWORK_ERROR,
|
|
2212
2257
|
"KV batch read response did not match the requested keys",
|
|
2213
2258
|
"kv"
|
|
2214
2259
|
));
|
|
2215
2260
|
}
|
|
2216
|
-
const results =
|
|
2261
|
+
const results = items.map((item, index) => {
|
|
2217
2262
|
if (!item.ok) {
|
|
2218
2263
|
return {
|
|
2219
2264
|
key: keys[index],
|
|
@@ -2847,8 +2892,8 @@ var KVService = class extends BaseService {
|
|
|
2847
2892
|
}
|
|
2848
2893
|
/**
|
|
2849
2894
|
* Map a failed `kv/sync` response. 410 and the retention 403 carry
|
|
2850
|
-
* `{"error":{"code","reason"}}`; a revoked grant is a 401 whose
|
|
2851
|
-
*
|
|
2895
|
+
* `{"error":{"code","reason"}}`; a revoked grant is a 401 whose whole body
|
|
2896
|
+
* is the node's revocation error (see REVOKED_BODY). A body read that
|
|
2852
2897
|
* fails because the request was cancelled or timed out rethrows, so the
|
|
2853
2898
|
* caller sees `ABORTED`/`TIMEOUT` rather than a mapped status.
|
|
2854
2899
|
*/
|
|
@@ -2893,7 +2938,7 @@ var KVService = class extends BaseService {
|
|
|
2893
2938
|
));
|
|
2894
2939
|
}
|
|
2895
2940
|
if (response.status === 401) {
|
|
2896
|
-
const revoked =
|
|
2941
|
+
const revoked = revocationCodeOf(errorText);
|
|
2897
2942
|
if (revoked !== void 0) {
|
|
2898
2943
|
return err(serviceError(revoked, `${context}: 401 - ${errorText}`, "kv", { meta }));
|
|
2899
2944
|
}
|
|
@@ -4140,7 +4185,7 @@ var AsyncQueue = class {
|
|
|
4140
4185
|
}
|
|
4141
4186
|
const waiter = this.waiters.shift();
|
|
4142
4187
|
if (waiter) {
|
|
4143
|
-
waiter({ value, done: false });
|
|
4188
|
+
waiter.resolve({ value, done: false });
|
|
4144
4189
|
return;
|
|
4145
4190
|
}
|
|
4146
4191
|
this.values.push(value);
|
|
@@ -4152,7 +4197,22 @@ var AsyncQueue = class {
|
|
|
4152
4197
|
this.closed = true;
|
|
4153
4198
|
while (this.waiters.length > 0) {
|
|
4154
4199
|
const waiter = this.waiters.shift();
|
|
4155
|
-
waiter?.({ value: void 0, done: true });
|
|
4200
|
+
waiter?.resolve({ value: void 0, done: true });
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
/**
|
|
4204
|
+
* Fail the queue: pending and future `next()` calls reject with `error`,
|
|
4205
|
+
* so a `for await` consumer sees the iterator throw.
|
|
4206
|
+
*/
|
|
4207
|
+
fail(error) {
|
|
4208
|
+
if (this.closed) {
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
this.closed = true;
|
|
4212
|
+
this.failure = error;
|
|
4213
|
+
while (this.waiters.length > 0) {
|
|
4214
|
+
const waiter = this.waiters.shift();
|
|
4215
|
+
waiter?.reject(error);
|
|
4156
4216
|
}
|
|
4157
4217
|
}
|
|
4158
4218
|
next() {
|
|
@@ -4160,20 +4220,28 @@ var AsyncQueue = class {
|
|
|
4160
4220
|
const value = this.values.shift();
|
|
4161
4221
|
return Promise.resolve({ value, done: false });
|
|
4162
4222
|
}
|
|
4223
|
+
if (this.failure !== void 0) {
|
|
4224
|
+
return Promise.reject(this.failure);
|
|
4225
|
+
}
|
|
4163
4226
|
if (this.closed) {
|
|
4164
4227
|
return Promise.resolve({ value: void 0, done: true });
|
|
4165
4228
|
}
|
|
4166
|
-
return new Promise((resolve) => {
|
|
4167
|
-
this.waiters.push(resolve);
|
|
4229
|
+
return new Promise((resolve, reject) => {
|
|
4230
|
+
this.waiters.push({ resolve, reject });
|
|
4168
4231
|
});
|
|
4169
4232
|
}
|
|
4170
4233
|
};
|
|
4234
|
+
var HOOK_STREAM_RETRY_BASE_DELAY_MS = 250;
|
|
4235
|
+
var HOOK_STREAM_RETRY_MAX_DELAY_MS = 3e4;
|
|
4236
|
+
var HOOK_STREAM_HEALTHY_MS = 5e3;
|
|
4171
4237
|
var HooksService = class extends BaseService {
|
|
4172
4238
|
constructor(config = {}) {
|
|
4173
4239
|
super();
|
|
4174
4240
|
this._subscribers = /* @__PURE__ */ new Set();
|
|
4175
|
-
|
|
4176
|
-
this.
|
|
4241
|
+
/** True while the one supervisor loop runs. Set only by wake(), cleared only at loop exit. */
|
|
4242
|
+
this._supervising = false;
|
|
4243
|
+
/** Bumped on every session change; part of the plan key. */
|
|
4244
|
+
this._sessionGeneration = 0;
|
|
4177
4245
|
this._config = config;
|
|
4178
4246
|
}
|
|
4179
4247
|
get config() {
|
|
@@ -4189,35 +4257,32 @@ var HooksService = class extends BaseService {
|
|
|
4189
4257
|
if (subscriptions.length === 0) {
|
|
4190
4258
|
throw new Error("At least one hook subscription is required");
|
|
4191
4259
|
}
|
|
4192
|
-
const
|
|
4260
|
+
const requested = subscriptions.map(normalizeSubscription);
|
|
4193
4261
|
const subscriber = {
|
|
4194
|
-
requested
|
|
4262
|
+
requested,
|
|
4263
|
+
signatures: requested.map(subscriptionSignature),
|
|
4195
4264
|
ttlSeconds: options.ttlSeconds,
|
|
4196
4265
|
queue: new AsyncQueue()
|
|
4197
4266
|
};
|
|
4198
|
-
|
|
4199
|
-
const abortHandler = () => {
|
|
4267
|
+
const leave = () => {
|
|
4200
4268
|
this._subscribers.delete(subscriber);
|
|
4201
4269
|
subscriber.queue.close();
|
|
4202
|
-
|
|
4270
|
+
this.wake();
|
|
4203
4271
|
};
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
} else {
|
|
4208
|
-
options.signal.addEventListener("abort", abortHandler, { once: true });
|
|
4209
|
-
}
|
|
4272
|
+
const { signal } = options;
|
|
4273
|
+
if (signal?.aborted) {
|
|
4274
|
+
return;
|
|
4210
4275
|
}
|
|
4211
|
-
|
|
4276
|
+
signal?.addEventListener("abort", leave, { once: true });
|
|
4277
|
+
this._subscribers.add(subscriber);
|
|
4278
|
+
this.wake();
|
|
4212
4279
|
try {
|
|
4213
4280
|
for await (const event of subscriber.queue) {
|
|
4214
4281
|
yield event;
|
|
4215
4282
|
}
|
|
4216
4283
|
} finally {
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
}
|
|
4220
|
-
abortHandler();
|
|
4284
|
+
signal?.removeEventListener("abort", leave);
|
|
4285
|
+
leave();
|
|
4221
4286
|
}
|
|
4222
4287
|
}
|
|
4223
4288
|
async register(webhook) {
|
|
@@ -4358,146 +4423,292 @@ var HooksService = class extends BaseService {
|
|
|
4358
4423
|
return err(wrapError("hooks", error));
|
|
4359
4424
|
}
|
|
4360
4425
|
}
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
if (state.signature !== this._activeSignature) {
|
|
4373
|
-
this._activeSignature = state.signature;
|
|
4374
|
-
this.abortSharedStream();
|
|
4426
|
+
/**
|
|
4427
|
+
* Called after anything that may change what the supervisor should do:
|
|
4428
|
+
* subscribe, unsubscribe, session change, sign-out. Interrupts the running
|
|
4429
|
+
* step if the plan moved away from it, and starts the supervisor if none
|
|
4430
|
+
* runs. Touches only SDK-owned state, so it never throws into callers such
|
|
4431
|
+
* as `ServiceContext.setSession`.
|
|
4432
|
+
*/
|
|
4433
|
+
wake() {
|
|
4434
|
+
const phase = this._phase;
|
|
4435
|
+
if (phase && phase.key !== this.plan()?.key) {
|
|
4436
|
+
phase.interrupt.abort();
|
|
4375
4437
|
}
|
|
4376
|
-
if (
|
|
4377
|
-
|
|
4378
|
-
if (!isAbortError(error)) {
|
|
4379
|
-
throw error;
|
|
4380
|
-
}
|
|
4381
|
-
}).finally(() => {
|
|
4382
|
-
this._sharedStreamTask = void 0;
|
|
4383
|
-
this._sharedStreamAbort = void 0;
|
|
4384
|
-
if (this._subscribers.size > 0) {
|
|
4385
|
-
void this.scheduleSharedStreamRefresh();
|
|
4386
|
-
}
|
|
4387
|
-
});
|
|
4438
|
+
if (this._supervising || this._subscribers.size === 0) {
|
|
4439
|
+
return;
|
|
4388
4440
|
}
|
|
4441
|
+
this._supervising = true;
|
|
4442
|
+
this.supervise().catch(() => this.collapse());
|
|
4389
4443
|
}
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4444
|
+
/**
|
|
4445
|
+
* The only owner of the shared stream. Each iteration is one attempt
|
|
4446
|
+
* (mint → open → drain), then a classification and, unless the attempt was
|
|
4447
|
+
* superseded or released its subscribers, a backoff. Every await is a
|
|
4448
|
+
* `phase` that wake() can interrupt; an interrupted phase yields
|
|
4449
|
+
* `undefined`, so a superseded mint can never act. Outside `attempt` and
|
|
4450
|
+
* `pause`, which each own one catch, the loop touches only SDK state.
|
|
4451
|
+
*/
|
|
4452
|
+
async supervise() {
|
|
4453
|
+
let streak = 0;
|
|
4454
|
+
for (; ; ) {
|
|
4455
|
+
const plan = this.plan();
|
|
4456
|
+
if (!plan) {
|
|
4457
|
+
this._supervising = false;
|
|
4458
|
+
return;
|
|
4459
|
+
}
|
|
4460
|
+
const health = { openedAt: 0, delivered: false };
|
|
4461
|
+
const outcome = await this.phase(
|
|
4462
|
+
plan.key,
|
|
4463
|
+
(signal) => this.attempt(plan, signal, health)
|
|
4464
|
+
);
|
|
4465
|
+
if (health.delivered || health.openedAt > 0 && performance.now() - health.openedAt >= HOOK_STREAM_HEALTHY_MS) {
|
|
4466
|
+
streak = 0;
|
|
4467
|
+
}
|
|
4468
|
+
if (!outcome) {
|
|
4469
|
+
continue;
|
|
4470
|
+
}
|
|
4471
|
+
if (this.plan()?.key !== plan.key) {
|
|
4472
|
+
continue;
|
|
4396
4473
|
}
|
|
4397
|
-
|
|
4398
|
-
|
|
4474
|
+
if (outcome.kind === "stopped") {
|
|
4475
|
+
this.release();
|
|
4476
|
+
continue;
|
|
4477
|
+
}
|
|
4478
|
+
if (outcome.kind === "refused" && outcome.terminal) {
|
|
4479
|
+
this.release(outcome.error);
|
|
4480
|
+
this.report(outcome.error);
|
|
4481
|
+
continue;
|
|
4399
4482
|
}
|
|
4483
|
+
if (outcome.kind !== "ended") {
|
|
4484
|
+
this.report(outcome.error);
|
|
4485
|
+
}
|
|
4486
|
+
streak += 1;
|
|
4487
|
+
await this.phase(
|
|
4488
|
+
plan.key,
|
|
4489
|
+
(signal) => this.pause(streak, signal)
|
|
4490
|
+
);
|
|
4491
|
+
}
|
|
4492
|
+
}
|
|
4493
|
+
/**
|
|
4494
|
+
* Run one step under an interrupt that wake() fires when the plan key moves
|
|
4495
|
+
* on. An interrupted step's result is discarded. The interrupt is also
|
|
4496
|
+
* fired when the step returns, which releases whatever it left open: the
|
|
4497
|
+
* request signal and its listeners, an unread response body, a timer.
|
|
4498
|
+
*/
|
|
4499
|
+
async phase(key, step) {
|
|
4500
|
+
const interrupt = new AbortController();
|
|
4501
|
+
this._phase = { key, interrupt };
|
|
4502
|
+
try {
|
|
4503
|
+
if (this.plan()?.key !== key) {
|
|
4504
|
+
interrupt.abort();
|
|
4505
|
+
}
|
|
4506
|
+
const result = await step(interrupt.signal);
|
|
4507
|
+
return interrupt.signal.aborted ? void 0 : result;
|
|
4508
|
+
} finally {
|
|
4509
|
+
this._phase = void 0;
|
|
4510
|
+
interrupt.abort();
|
|
4400
4511
|
}
|
|
4401
|
-
const subscriptions = [...merged.values()].sort(
|
|
4402
|
-
(left, right) => subscriptionSignature(left).localeCompare(subscriptionSignature(right))
|
|
4403
|
-
);
|
|
4404
|
-
const ttlSeconds = ttlCandidates.length > 0 ? Math.min(...ttlCandidates) : void 0;
|
|
4405
|
-
const signature = JSON.stringify({
|
|
4406
|
-
subscriptions: subscriptions.map(subscriptionSignature),
|
|
4407
|
-
ttlSeconds
|
|
4408
|
-
});
|
|
4409
|
-
return {
|
|
4410
|
-
subscriptions,
|
|
4411
|
-
ttlSeconds,
|
|
4412
|
-
signature
|
|
4413
|
-
};
|
|
4414
4512
|
}
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4513
|
+
/**
|
|
4514
|
+
* One mint → open → drain. The single catch site for everything the
|
|
4515
|
+
* attempt touches that the SDK does not own: context accessors, invoke,
|
|
4516
|
+
* fetch, response bodies, the SSE parser. Never rejects.
|
|
4517
|
+
*/
|
|
4518
|
+
async attempt(plan, signal, health) {
|
|
4519
|
+
let phase = "mint";
|
|
4520
|
+
let request;
|
|
4521
|
+
const owns = () => !signal.aborted && !request?.signal.aborted && this.plan()?.key === plan.key;
|
|
4418
4522
|
try {
|
|
4419
|
-
const
|
|
4420
|
-
const
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4523
|
+
const context = this.context;
|
|
4524
|
+
const contextSignal = context.abortSignal;
|
|
4525
|
+
this._lastContextSignal = contextSignal;
|
|
4526
|
+
if (!context.isAuthenticated || contextSignal?.aborted) {
|
|
4527
|
+
return { kind: "stopped" };
|
|
4528
|
+
}
|
|
4529
|
+
request = this.createRequestSignal(signal, 0);
|
|
4530
|
+
const host = this.host;
|
|
4531
|
+
const minted = await awaitOwned(
|
|
4532
|
+
request.signal,
|
|
4533
|
+
() => context.fetch(`${host}/hooks/tickets`, {
|
|
4534
|
+
method: "POST",
|
|
4535
|
+
headers: {
|
|
4536
|
+
...serviceHeadersToRecord(this.createInvokeHeaders(plan.subscriptions)),
|
|
4537
|
+
"content-type": "application/json"
|
|
4538
|
+
},
|
|
4539
|
+
body: JSON.stringify({
|
|
4540
|
+
subscriptions: plan.subscriptions,
|
|
4541
|
+
ttlSeconds: plan.ttlSeconds
|
|
4542
|
+
}),
|
|
4543
|
+
signal: request.signal
|
|
4544
|
+
})
|
|
4424
4545
|
);
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4546
|
+
if (!owns()) return { kind: "stopped" };
|
|
4547
|
+
if (!minted.ok) {
|
|
4548
|
+
const status = minted.status;
|
|
4549
|
+
const error = await awaitOwned(
|
|
4550
|
+
request.signal,
|
|
4551
|
+
() => responseError("hooks", "failed to mint hook ticket", minted)
|
|
4552
|
+
);
|
|
4553
|
+
if (!owns()) return { kind: "stopped" };
|
|
4554
|
+
return { kind: "refused", terminal: isTerminalMintRefusal(status), error };
|
|
4555
|
+
}
|
|
4556
|
+
const body = await awaitOwned(request.signal, () => minted.json());
|
|
4557
|
+
if (!owns()) return { kind: "stopped" };
|
|
4558
|
+
const ticket = body !== null && typeof body === "object" && "ticket" in body ? body.ticket : void 0;
|
|
4559
|
+
if (typeof ticket !== "string" || ticket.length === 0) {
|
|
4560
|
+
throw new Error("Hook ticket response did not include a ticket");
|
|
4561
|
+
}
|
|
4562
|
+
phase = "open";
|
|
4563
|
+
if (!owns()) return { kind: "stopped" };
|
|
4564
|
+
const stream = await awaitOwned(
|
|
4565
|
+
request.signal,
|
|
4566
|
+
() => context.fetch(`${host}/hooks/events?ticket=${encodeURIComponent(ticket)}`, {
|
|
4567
|
+
method: "GET",
|
|
4568
|
+
headers: { accept: "text/event-stream" },
|
|
4569
|
+
signal: request.signal
|
|
4570
|
+
})
|
|
4429
4571
|
);
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
if (
|
|
4440
|
-
|
|
4441
|
-
|
|
4572
|
+
if (!owns()) return { kind: "stopped" };
|
|
4573
|
+
if (!stream.ok) {
|
|
4574
|
+
return { kind: "refused", terminal: false, error: hookStreamRefusal(stream.status) };
|
|
4575
|
+
}
|
|
4576
|
+
health.openedAt = performance.now();
|
|
4577
|
+
const iterator = parseSseStream(stream.body, request.signal)[Symbol.asyncIterator]();
|
|
4578
|
+
try {
|
|
4579
|
+
for (; ; ) {
|
|
4580
|
+
const next = await awaitOwned(request.signal, () => iterator.next());
|
|
4581
|
+
if (!owns()) return { kind: "stopped" };
|
|
4582
|
+
if (next.done) break;
|
|
4583
|
+
const message = next.value;
|
|
4584
|
+
if (!message.data) continue;
|
|
4585
|
+
const event = parseHookEvent(message);
|
|
4586
|
+
if (!owns()) return { kind: "stopped" };
|
|
4587
|
+
this.dispatch(event);
|
|
4588
|
+
health.delivered = true;
|
|
4442
4589
|
}
|
|
4590
|
+
} finally {
|
|
4591
|
+
const closing = iterator.return?.();
|
|
4592
|
+
if (closing) void Promise.resolve(closing).then(() => void 0, () => void 0);
|
|
4443
4593
|
}
|
|
4594
|
+
return owns() ? { kind: "ended" } : { kind: "stopped" };
|
|
4595
|
+
} catch (thrown) {
|
|
4596
|
+
return request?.signal.aborted || thrown === SUPERSEDED ? { kind: "stopped" } : { kind: "failed", error: hookStreamFailure(phase, thrown) };
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
/**
|
|
4600
|
+
* Back off before the next attempt. `config.streamRetry` overrides the
|
|
4601
|
+
* delay and the clock; whatever they do, the pause ends by the delay or the
|
|
4602
|
+
* interrupt, then yields one timer turn so an instant clock cannot starve
|
|
4603
|
+
* due timers or the process.
|
|
4604
|
+
*/
|
|
4605
|
+
async pause(attempt, signal) {
|
|
4606
|
+
try {
|
|
4607
|
+
this._lastContextSignal = this.context.abortSignal;
|
|
4608
|
+
} catch {
|
|
4609
|
+
}
|
|
4610
|
+
const contextSignal = this._lastContextSignal;
|
|
4611
|
+
const waits = [];
|
|
4612
|
+
const aborts = [];
|
|
4613
|
+
try {
|
|
4614
|
+
const retry = this._config.streamRetry;
|
|
4615
|
+
const delayMs = retry?.delay?.(attempt) ?? hookStreamRetryDelay(attempt);
|
|
4616
|
+
waits.push((retry?.wait ?? sleep)(delayMs, attempt, signal));
|
|
4617
|
+
} catch {
|
|
4618
|
+
waits.push(Promise.resolve());
|
|
4619
|
+
}
|
|
4620
|
+
aborts.push(abortPromise(signal));
|
|
4621
|
+
if (contextSignal) aborts.push(abortPromise(contextSignal));
|
|
4622
|
+
try {
|
|
4623
|
+
await Promise.race([...waits, ...aborts.map(({ promise }) => promise)]);
|
|
4624
|
+
} catch {
|
|
4444
4625
|
} finally {
|
|
4445
|
-
|
|
4446
|
-
|
|
4626
|
+
for (const abort of aborts) abort.dispose();
|
|
4627
|
+
}
|
|
4628
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
4629
|
+
}
|
|
4630
|
+
/** The stream the current subscribers need, or undefined when none remain. */
|
|
4631
|
+
plan() {
|
|
4632
|
+
if (this._subscribers.size === 0) {
|
|
4633
|
+
return void 0;
|
|
4634
|
+
}
|
|
4635
|
+
const merged = /* @__PURE__ */ new Map();
|
|
4636
|
+
let ttlSeconds;
|
|
4637
|
+
for (const subscriber of this._subscribers) {
|
|
4638
|
+
subscriber.requested.forEach(
|
|
4639
|
+
(subscription, index) => merged.set(subscriber.signatures[index], subscription)
|
|
4640
|
+
);
|
|
4641
|
+
if (typeof subscriber.ttlSeconds === "number") {
|
|
4642
|
+
ttlSeconds = Math.min(subscriber.ttlSeconds, ttlSeconds ?? Infinity);
|
|
4447
4643
|
}
|
|
4448
4644
|
}
|
|
4645
|
+
const signatures = [...merged.keys()].sort();
|
|
4646
|
+
return {
|
|
4647
|
+
key: JSON.stringify([this._sessionGeneration, signatures, ttlSeconds ?? null]),
|
|
4648
|
+
subscriptions: signatures.map((signature) => merged.get(signature)),
|
|
4649
|
+
ttlSeconds
|
|
4650
|
+
};
|
|
4449
4651
|
}
|
|
4450
|
-
|
|
4451
|
-
this.
|
|
4652
|
+
dispatch(event) {
|
|
4653
|
+
for (const subscriber of this._subscribers) {
|
|
4654
|
+
if (matchesAnySubscription(event, subscriber.requested)) {
|
|
4655
|
+
subscriber.queue.push(event);
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4452
4658
|
}
|
|
4453
|
-
|
|
4454
|
-
|
|
4659
|
+
/**
|
|
4660
|
+
* Detach every subscriber. With `error`, their iterators throw it after
|
|
4661
|
+
* draining buffered events; without, they complete.
|
|
4662
|
+
*/
|
|
4663
|
+
release(error) {
|
|
4664
|
+
const subscribers = [...this._subscribers];
|
|
4665
|
+
this._subscribers.clear();
|
|
4666
|
+
for (const { queue } of subscribers) {
|
|
4667
|
+
if (error) {
|
|
4668
|
+
queue.fail(error);
|
|
4669
|
+
} else {
|
|
4670
|
+
queue.close();
|
|
4671
|
+
}
|
|
4672
|
+
}
|
|
4455
4673
|
}
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
const ticketResponse = await this.context.fetch(`${host}/hooks/tickets`, {
|
|
4460
|
-
method: "POST",
|
|
4461
|
-
headers: {
|
|
4462
|
-
...serviceHeadersToRecord(headers),
|
|
4463
|
-
"content-type": "application/json"
|
|
4464
|
-
},
|
|
4465
|
-
body: JSON.stringify({
|
|
4466
|
-
subscriptions,
|
|
4467
|
-
ttlSeconds
|
|
4468
|
-
}),
|
|
4469
|
-
signal
|
|
4470
|
-
});
|
|
4471
|
-
if (!ticketResponse.ok) {
|
|
4472
|
-
throw await responseError(
|
|
4473
|
-
"hooks",
|
|
4474
|
-
"failed to mint hook ticket",
|
|
4475
|
-
ticketResponse
|
|
4476
|
-
);
|
|
4674
|
+
report(error) {
|
|
4675
|
+
if (error.meta && typeof error.meta === "object") {
|
|
4676
|
+
Object.freeze(error.meta);
|
|
4477
4677
|
}
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4678
|
+
Object.freeze(error);
|
|
4679
|
+
try {
|
|
4680
|
+
this.emitError(error, "stream");
|
|
4681
|
+
} catch {
|
|
4481
4682
|
}
|
|
4482
|
-
return ticketJson;
|
|
4483
4683
|
}
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4684
|
+
/**
|
|
4685
|
+
* Unreachable by construction. If the loop ever rejects anyway, fail its
|
|
4686
|
+
* subscribers visibly instead of stranding them or crashing the process.
|
|
4687
|
+
*/
|
|
4688
|
+
collapse() {
|
|
4689
|
+
this._supervising = false;
|
|
4690
|
+
this._phase?.interrupt.abort();
|
|
4691
|
+
this._phase = void 0;
|
|
4692
|
+
const error = serviceError(
|
|
4693
|
+
ErrorCodes.NETWORK_ERROR,
|
|
4694
|
+
"hook stream supervisor stopped unexpectedly",
|
|
4695
|
+
"hooks"
|
|
4492
4696
|
);
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4697
|
+
this.report(error);
|
|
4698
|
+
this.release(error);
|
|
4699
|
+
}
|
|
4700
|
+
onSessionChange(session) {
|
|
4701
|
+
super.onSessionChange(session);
|
|
4702
|
+
this._sessionGeneration += 1;
|
|
4703
|
+
this.wake();
|
|
4704
|
+
}
|
|
4705
|
+
onSignOut() {
|
|
4706
|
+
super.onSignOut();
|
|
4707
|
+
this.release();
|
|
4708
|
+
this.wake();
|
|
4709
|
+
}
|
|
4710
|
+
createHookHeaders(action, path) {
|
|
4711
|
+
return this.context.invoke(this.session, "hooks", path, action);
|
|
4501
4712
|
}
|
|
4502
4713
|
createInvokeHeaders(subscriptions) {
|
|
4503
4714
|
const entries = subscriptions.map((subscription) => ({
|
|
@@ -4528,11 +4739,168 @@ function buildScopePath(service, pathPrefix) {
|
|
|
4528
4739
|
const normalized = normalizePathPrefix(pathPrefix);
|
|
4529
4740
|
return normalized ? `${service}/${normalized}` : service;
|
|
4530
4741
|
}
|
|
4742
|
+
function hookStreamRetryDelay(attempt) {
|
|
4743
|
+
const cap = Math.min(
|
|
4744
|
+
HOOK_STREAM_RETRY_BASE_DELAY_MS * 2 ** Math.max(0, attempt - 1),
|
|
4745
|
+
HOOK_STREAM_RETRY_MAX_DELAY_MS
|
|
4746
|
+
);
|
|
4747
|
+
return cap / 2 + Math.random() * (cap / 2);
|
|
4748
|
+
}
|
|
4749
|
+
function isTerminalMintRefusal(status) {
|
|
4750
|
+
return typeof status === "number" && status >= 400 && status < 500 && status !== 408 && status !== 429;
|
|
4751
|
+
}
|
|
4752
|
+
var SUPERSEDED = /* @__PURE__ */ Symbol("hooks attempt superseded");
|
|
4753
|
+
async function awaitOwned(signal, operation) {
|
|
4754
|
+
if (signal.aborted) {
|
|
4755
|
+
if (typeof operation !== "function") {
|
|
4756
|
+
void operation.then(cancelLateResponse, () => void 0);
|
|
4757
|
+
}
|
|
4758
|
+
throw SUPERSEDED;
|
|
4759
|
+
}
|
|
4760
|
+
const promise = typeof operation === "function" ? operation() : operation;
|
|
4761
|
+
return new Promise((resolve, reject) => {
|
|
4762
|
+
let settled = false;
|
|
4763
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
4764
|
+
const onAbort = () => {
|
|
4765
|
+
if (settled) return;
|
|
4766
|
+
settled = true;
|
|
4767
|
+
cleanup();
|
|
4768
|
+
reject(SUPERSEDED);
|
|
4769
|
+
};
|
|
4770
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4771
|
+
promise.then(
|
|
4772
|
+
(value) => {
|
|
4773
|
+
if (settled) {
|
|
4774
|
+
cancelLateResponse(value);
|
|
4775
|
+
return;
|
|
4776
|
+
}
|
|
4777
|
+
settled = true;
|
|
4778
|
+
cleanup();
|
|
4779
|
+
resolve(value);
|
|
4780
|
+
},
|
|
4781
|
+
(error) => {
|
|
4782
|
+
if (settled) return;
|
|
4783
|
+
settled = true;
|
|
4784
|
+
cleanup();
|
|
4785
|
+
reject(error);
|
|
4786
|
+
}
|
|
4787
|
+
);
|
|
4788
|
+
});
|
|
4789
|
+
}
|
|
4790
|
+
function cancelLateResponse(value) {
|
|
4791
|
+
if (!(value instanceof Response) || !value.body) return;
|
|
4792
|
+
try {
|
|
4793
|
+
const cancellation = value.body.cancel();
|
|
4794
|
+
void cancellation.then(() => void 0, () => void 0);
|
|
4795
|
+
} catch {
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
function hookStreamRefusal(status) {
|
|
4799
|
+
const code = typeof status === "number" ? status : void 0;
|
|
4800
|
+
return serviceError(
|
|
4801
|
+
ErrorCodes.NETWORK_ERROR,
|
|
4802
|
+
`hook stream open refused: ${code ?? "unknown status"}`,
|
|
4803
|
+
"hooks",
|
|
4804
|
+
{ meta: { phase: "open", status: code } }
|
|
4805
|
+
);
|
|
4806
|
+
}
|
|
4807
|
+
var STREAM_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
4808
|
+
"Error",
|
|
4809
|
+
"TypeError",
|
|
4810
|
+
"AbortError",
|
|
4811
|
+
"TimeoutError",
|
|
4812
|
+
"SyntaxError",
|
|
4813
|
+
"RangeError",
|
|
4814
|
+
"NetworkError"
|
|
4815
|
+
]);
|
|
4816
|
+
function hookStreamFailure(phase, thrown) {
|
|
4817
|
+
const candidateName = readProperty(thrown, "name");
|
|
4818
|
+
const name = typeof candidateName === "string" && STREAM_ERROR_NAMES.has(candidateName) ? candidateName : "Error";
|
|
4819
|
+
const code = identifier(readProperty(thrown, "code")) ?? identifier(readProperty(readProperty(thrown, "cause"), "code"));
|
|
4820
|
+
return serviceError(
|
|
4821
|
+
ErrorCodes.NETWORK_ERROR,
|
|
4822
|
+
`hook stream ${phase} failed: ${name}${code ? ` (${code})` : ""}`,
|
|
4823
|
+
"hooks",
|
|
4824
|
+
{ meta: { phase, errorName: name, ...code ? { errorCode: code } : {} } }
|
|
4825
|
+
);
|
|
4826
|
+
}
|
|
4827
|
+
var STREAM_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
4828
|
+
"ECONNREFUSED",
|
|
4829
|
+
"ECONNRESET",
|
|
4830
|
+
"ECONNABORTED",
|
|
4831
|
+
"ETIMEDOUT",
|
|
4832
|
+
"EPIPE",
|
|
4833
|
+
"ENOTFOUND",
|
|
4834
|
+
"EAI_AGAIN",
|
|
4835
|
+
"EHOSTUNREACH",
|
|
4836
|
+
"ENETUNREACH",
|
|
4837
|
+
"ENETDOWN",
|
|
4838
|
+
"EADDRNOTAVAIL",
|
|
4839
|
+
"UND_ERR_SOCKET",
|
|
4840
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
4841
|
+
"UND_ERR_HEADERS_TIMEOUT",
|
|
4842
|
+
"UND_ERR_BODY_TIMEOUT",
|
|
4843
|
+
"UND_ERR_CLOSED",
|
|
4844
|
+
"UND_ERR_ABORTED",
|
|
4845
|
+
"UND_ERR_RESPONSE_STATUS_CODE",
|
|
4846
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
4847
|
+
"CERT_HAS_EXPIRED",
|
|
4848
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
4849
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE",
|
|
4850
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
4851
|
+
"ERR_SSL_WRONG_VERSION_NUMBER"
|
|
4852
|
+
]);
|
|
4853
|
+
function identifier(value) {
|
|
4854
|
+
return typeof value === "string" && STREAM_ERROR_CODES.has(value) ? value : void 0;
|
|
4855
|
+
}
|
|
4856
|
+
function readProperty(value, key) {
|
|
4857
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") {
|
|
4858
|
+
return void 0;
|
|
4859
|
+
}
|
|
4860
|
+
try {
|
|
4861
|
+
return Reflect.get(value, key);
|
|
4862
|
+
} catch {
|
|
4863
|
+
return void 0;
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4866
|
+
function sleep(delayMs, _attempt, signal) {
|
|
4867
|
+
return new Promise((resolve) => {
|
|
4868
|
+
const finish = () => {
|
|
4869
|
+
clearTimeout(timer);
|
|
4870
|
+
signal.removeEventListener("abort", stop);
|
|
4871
|
+
resolve();
|
|
4872
|
+
};
|
|
4873
|
+
const timer = setTimeout(finish, delayMs);
|
|
4874
|
+
timer.unref?.();
|
|
4875
|
+
const stop = () => finish();
|
|
4876
|
+
if (signal.aborted) {
|
|
4877
|
+
finish();
|
|
4878
|
+
} else {
|
|
4879
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
4880
|
+
}
|
|
4881
|
+
});
|
|
4882
|
+
}
|
|
4883
|
+
function abortPromise(signal) {
|
|
4884
|
+
let resolve;
|
|
4885
|
+
const promise = new Promise((done) => {
|
|
4886
|
+
resolve = done;
|
|
4887
|
+
});
|
|
4888
|
+
const onAbort = () => resolve();
|
|
4889
|
+
if (signal.aborted) {
|
|
4890
|
+
resolve();
|
|
4891
|
+
} else {
|
|
4892
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4893
|
+
}
|
|
4894
|
+
return {
|
|
4895
|
+
promise,
|
|
4896
|
+
dispose: () => signal.removeEventListener("abort", onAbort)
|
|
4897
|
+
};
|
|
4898
|
+
}
|
|
4531
4899
|
function normalizeSubscription(subscription) {
|
|
4532
4900
|
return {
|
|
4533
4901
|
...subscription,
|
|
4534
4902
|
pathPrefix: normalizePathPrefix(subscription.pathPrefix),
|
|
4535
|
-
abilities: subscription.abilities
|
|
4903
|
+
abilities: subscription.abilities ? [...subscription.abilities] : []
|
|
4536
4904
|
};
|
|
4537
4905
|
}
|
|
4538
4906
|
function subscriptionSignature(subscription) {
|
|
@@ -4598,9 +4966,6 @@ async function responseError(service, message, response) {
|
|
|
4598
4966
|
meta: { ...error.meta, status: response.status, statusText: response.statusText }
|
|
4599
4967
|
};
|
|
4600
4968
|
}
|
|
4601
|
-
function isAbortError(error) {
|
|
4602
|
-
return error instanceof DOMException && error.name === "AbortError";
|
|
4603
|
-
}
|
|
4604
4969
|
async function* parseSseStream(body, signal) {
|
|
4605
4970
|
if (!body) {
|
|
4606
4971
|
throw new Error("Hook stream response does not expose a readable body");
|
|
@@ -4629,11 +4994,24 @@ async function* parseSseStream(body, signal) {
|
|
|
4629
4994
|
async function* readBodyChunks(body, signal) {
|
|
4630
4995
|
const asyncIterable = body;
|
|
4631
4996
|
if (typeof asyncIterable?.[Symbol.asyncIterator] === "function") {
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4997
|
+
const iterator = asyncIterable[Symbol.asyncIterator]();
|
|
4998
|
+
const cancel = () => {
|
|
4999
|
+
try {
|
|
5000
|
+
const closing = iterator.return?.();
|
|
5001
|
+
if (closing) void Promise.resolve(closing).then(() => void 0, () => void 0);
|
|
5002
|
+
} catch {
|
|
5003
|
+
}
|
|
5004
|
+
};
|
|
5005
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
5006
|
+
try {
|
|
5007
|
+
while (!signal?.aborted) {
|
|
5008
|
+
const next = await iterator.next();
|
|
5009
|
+
if (next.done) break;
|
|
5010
|
+
yield next.value;
|
|
4635
5011
|
}
|
|
4636
|
-
|
|
5012
|
+
} finally {
|
|
5013
|
+
signal?.removeEventListener("abort", cancel);
|
|
5014
|
+
cancel();
|
|
4637
5015
|
}
|
|
4638
5016
|
return;
|
|
4639
5017
|
}
|
|
@@ -4642,21 +5020,23 @@ async function* readBodyChunks(body, signal) {
|
|
|
4642
5020
|
throw new Error("Unsupported hook stream body type");
|
|
4643
5021
|
}
|
|
4644
5022
|
const reader = stream.getReader();
|
|
5023
|
+
const cancelReader = () => {
|
|
5024
|
+
try {
|
|
5025
|
+
const cancellation = reader.cancel?.();
|
|
5026
|
+
if (cancellation) void cancellation.then(() => void 0, () => void 0);
|
|
5027
|
+
} catch {
|
|
5028
|
+
}
|
|
5029
|
+
};
|
|
5030
|
+
signal?.addEventListener("abort", cancelReader, { once: true });
|
|
4645
5031
|
try {
|
|
4646
5032
|
while (!signal?.aborted) {
|
|
4647
5033
|
const { done, value } = await reader.read();
|
|
4648
|
-
if (done)
|
|
4649
|
-
|
|
4650
|
-
}
|
|
4651
|
-
if (value) {
|
|
4652
|
-
yield value;
|
|
4653
|
-
}
|
|
5034
|
+
if (done) break;
|
|
5035
|
+
if (value) yield value;
|
|
4654
5036
|
}
|
|
4655
5037
|
} finally {
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
} catch {
|
|
4659
|
-
}
|
|
5038
|
+
signal?.removeEventListener("abort", cancelReader);
|
|
5039
|
+
cancelReader();
|
|
4660
5040
|
reader.releaseLock?.();
|
|
4661
5041
|
}
|
|
4662
5042
|
}
|
|
@@ -7300,10 +7680,10 @@ var EncryptionService = class extends BaseService {
|
|
|
7300
7680
|
get crypto() {
|
|
7301
7681
|
return this._config.crypto;
|
|
7302
7682
|
}
|
|
7303
|
-
async discoverNetwork(
|
|
7683
|
+
async discoverNetwork(identifier2, ownerDid) {
|
|
7304
7684
|
this.assertActive();
|
|
7305
7685
|
const result = await discoverNetwork({
|
|
7306
|
-
identifier,
|
|
7686
|
+
identifier: identifier2,
|
|
7307
7687
|
...ownerDid !== void 0 ? { ownerDid } : {},
|
|
7308
7688
|
...this._config.node !== void 0 ? { node: this._config.node } : {},
|
|
7309
7689
|
...this._config.wellKnown !== void 0 ? { wellKnown: this._config.wellKnown } : {}
|