@githolon/runtime 0.112.7 → 0.112.11
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/RUNTIME-SOURCES.sha256 +22 -19
- package/dist/nomos-native-runtime.js +330 -106
- package/dist/nomos-runner-web.js +145 -0
- package/dist/nomos-runner-worker.js +36411 -0
- package/dist/nomos-runner.js +547 -230
- package/package.json +4 -2
- package/runner/README.md +2 -1
- package/runner/build.ts +36 -3
- package/runner/node-entry.mjs +437 -187
package/runner/node-entry.mjs
CHANGED
|
@@ -6873,10 +6873,10 @@ function nodeCustodyFilesystem(directory2) {
|
|
|
6873
6873
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
6874
6874
|
import { TextDecoder as TextDecoder2 } from "node:util";
|
|
6875
6875
|
function kernelWasiStdio(memory, stderr, writeFile2, stderrPartial) {
|
|
6876
|
-
const
|
|
6876
|
+
const decoder5 = new TextDecoder2();
|
|
6877
6877
|
let pending = "";
|
|
6878
6878
|
const accept = (bytes) => {
|
|
6879
|
-
pending +=
|
|
6879
|
+
pending += decoder5.decode(bytes, { stream: true });
|
|
6880
6880
|
for (; ; ) {
|
|
6881
6881
|
const newline = pending.indexOf("\n");
|
|
6882
6882
|
if (newline >= 0 && newline < 16384) {
|
|
@@ -10307,13 +10307,13 @@ var Expression = class {
|
|
|
10307
10307
|
}
|
|
10308
10308
|
}
|
|
10309
10309
|
}
|
|
10310
|
-
let
|
|
10310
|
+
let namespace2 = void 0;
|
|
10311
10311
|
let tagAndPosition = withoutBrackets;
|
|
10312
10312
|
if (withoutBrackets.includes("::")) {
|
|
10313
10313
|
const nsIndex = withoutBrackets.indexOf("::");
|
|
10314
|
-
|
|
10314
|
+
namespace2 = withoutBrackets.substring(0, nsIndex).trim();
|
|
10315
10315
|
tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim();
|
|
10316
|
-
if (!
|
|
10316
|
+
if (!namespace2) {
|
|
10317
10317
|
throw new Error(`Invalid namespace in pattern: ${part}`);
|
|
10318
10318
|
}
|
|
10319
10319
|
}
|
|
@@ -10337,8 +10337,8 @@ var Expression = class {
|
|
|
10337
10337
|
throw new Error(`Invalid segment pattern: ${part}`);
|
|
10338
10338
|
}
|
|
10339
10339
|
segment.tag = tag;
|
|
10340
|
-
if (
|
|
10341
|
-
segment.namespace =
|
|
10340
|
+
if (namespace2) {
|
|
10341
|
+
segment.namespace = namespace2;
|
|
10342
10342
|
}
|
|
10343
10343
|
if (bracketContent) {
|
|
10344
10344
|
if (bracketContent.includes("=")) {
|
|
@@ -10728,7 +10728,7 @@ var Matcher = class {
|
|
|
10728
10728
|
* @param {Object|null} [options=null]
|
|
10729
10729
|
* @param {string[]} [options.keep] - Names of attributes (from attrValues)
|
|
10730
10730
|
*/
|
|
10731
|
-
push(tagName, attrValues = null,
|
|
10731
|
+
push(tagName, attrValues = null, namespace2 = null, options = null) {
|
|
10732
10732
|
this._pathStringCache = null;
|
|
10733
10733
|
if (this.path.length > 0) {
|
|
10734
10734
|
this.path[this.path.length - 1].values = void 0;
|
|
@@ -10739,7 +10739,7 @@ var Matcher = class {
|
|
|
10739
10739
|
level = { counts: /* @__PURE__ */ new Map(), total: 0 };
|
|
10740
10740
|
this.siblingStacks[currentLevel] = level;
|
|
10741
10741
|
}
|
|
10742
|
-
const siblingKey =
|
|
10742
|
+
const siblingKey = namespace2 ? `${namespace2}:${tagName}` : tagName;
|
|
10743
10743
|
const counter = level.counts.get(siblingKey) || 0;
|
|
10744
10744
|
const position = level.total;
|
|
10745
10745
|
level.counts.set(siblingKey, counter + 1);
|
|
@@ -10749,8 +10749,8 @@ var Matcher = class {
|
|
|
10749
10749
|
position,
|
|
10750
10750
|
counter
|
|
10751
10751
|
};
|
|
10752
|
-
if (
|
|
10753
|
-
node.namespace =
|
|
10752
|
+
if (namespace2 !== null && namespace2 !== void 0) {
|
|
10753
|
+
node.namespace = namespace2;
|
|
10754
10754
|
}
|
|
10755
10755
|
if (attrValues !== null && attrValues !== void 0) {
|
|
10756
10756
|
node.values = attrValues;
|
|
@@ -12133,10 +12133,10 @@ var parseXml = function(xmlData) {
|
|
|
12133
12133
|
}
|
|
12134
12134
|
let prefixedAttrs = null;
|
|
12135
12135
|
let rawAttrs = {};
|
|
12136
|
-
let
|
|
12137
|
-
|
|
12136
|
+
let namespace2 = void 0;
|
|
12137
|
+
namespace2 = extractNamespace(rawTagName);
|
|
12138
12138
|
if (tagName !== xmlObj.tagname) {
|
|
12139
|
-
this.matcher.push(tagName, {},
|
|
12139
|
+
this.matcher.push(tagName, {}, namespace2);
|
|
12140
12140
|
}
|
|
12141
12141
|
if (tagName !== tagExp && attrExpPresent) {
|
|
12142
12142
|
prefixedAttrs = this.buildAttributesMap(tagExp, this.matcher, tagName);
|
|
@@ -13361,17 +13361,17 @@ function attributes(capability) {
|
|
|
13361
13361
|
}
|
|
13362
13362
|
return result;
|
|
13363
13363
|
}
|
|
13364
|
-
function capabilityByNamespace(capabilities,
|
|
13365
|
-
const matches = capabilities.filter((capability) => capability.namespace ===
|
|
13364
|
+
function capabilityByNamespace(capabilities, namespace2) {
|
|
13365
|
+
const matches = capabilities.filter((capability) => capability.namespace === namespace2);
|
|
13366
13366
|
if (matches.length !== 1) {
|
|
13367
|
-
throw new Error(`OSGi resource needs exactly one ${
|
|
13367
|
+
throw new Error(`OSGi resource needs exactly one ${namespace2} capability`);
|
|
13368
13368
|
}
|
|
13369
13369
|
return matches[0];
|
|
13370
13370
|
}
|
|
13371
|
-
function optionalCapabilityByNamespace(capabilities,
|
|
13372
|
-
const matches = capabilities.filter((capability) => capability.namespace ===
|
|
13371
|
+
function optionalCapabilityByNamespace(capabilities, namespace2) {
|
|
13372
|
+
const matches = capabilities.filter((capability) => capability.namespace === namespace2);
|
|
13373
13373
|
if (matches.length > 1) {
|
|
13374
|
-
throw new Error(`OSGi resource needs at most one ${
|
|
13374
|
+
throw new Error(`OSGi resource needs at most one ${namespace2} capability`);
|
|
13375
13375
|
}
|
|
13376
13376
|
return matches[0];
|
|
13377
13377
|
}
|
|
@@ -14154,7 +14154,8 @@ var KernelPort = class {
|
|
|
14154
14154
|
}
|
|
14155
14155
|
}));
|
|
14156
14156
|
if (response.outcome.case === "failure") {
|
|
14157
|
-
|
|
14157
|
+
throwUnnamedHistoryRequirement(response.outcome.value, mount.workspace);
|
|
14158
|
+
throwKernelFailure(response.outcome.value);
|
|
14158
14159
|
}
|
|
14159
14160
|
if (response.outcome.case !== "outbox") {
|
|
14160
14161
|
throw new Error(`kernel returned '${response.outcome.case || "empty"}' while reading correspondence`);
|
|
@@ -14183,7 +14184,8 @@ var KernelPort = class {
|
|
|
14183
14184
|
}
|
|
14184
14185
|
}));
|
|
14185
14186
|
if (response.outcome.case === "failure") {
|
|
14186
|
-
|
|
14187
|
+
throwUnnamedHistoryRequirement(response.outcome.value, mount.workspace);
|
|
14188
|
+
throwKernelFailure(response.outcome.value);
|
|
14187
14189
|
}
|
|
14188
14190
|
if (response.outcome.case !== "outbox") {
|
|
14189
14191
|
throw new Error(
|
|
@@ -17222,19 +17224,19 @@ function base64(bytes) {
|
|
|
17222
17224
|
// ../src/runtime/workspace_naming.ts
|
|
17223
17225
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
17224
17226
|
var WORKSPACE_NAME_SEP = "";
|
|
17225
|
-
var keyedBirthNameOf = (
|
|
17227
|
+
var keyedBirthNameOf = (namespace2, key) => `${namespace2}-${sha256Hex(new TextEncoder().encode(namespace2 + WORKSPACE_NAME_SEP + key)).slice(0, 40)}`;
|
|
17226
17228
|
var RECEIVING_GROUP_NAME_PREFIX = "nomos-rg-";
|
|
17227
17229
|
var receivingGroupNameOf = (principal) => `${RECEIVING_GROUP_NAME_PREFIX}${sha256Hex(new TextEncoder().encode(principal)).slice(0, 40)}`;
|
|
17228
|
-
var isKeyedBirthOf = (
|
|
17230
|
+
var isKeyedBirthOf = (namespace2, workspace) => workspace.startsWith(`${namespace2}-`);
|
|
17229
17231
|
var WORKSPACE_NAME_REQUEST_INVALID = "nomos.runtime.workspace_name_request_invalid";
|
|
17230
17232
|
function resolveWorkspaceName(command) {
|
|
17231
17233
|
switch (command.birth.case) {
|
|
17232
17234
|
case "keyed": {
|
|
17233
|
-
const { namespace, key } = command.birth.value;
|
|
17234
|
-
if (
|
|
17235
|
+
const { namespace: namespace2, key } = command.birth.value;
|
|
17236
|
+
if (namespace2.length === 0 || key.length === 0) {
|
|
17235
17237
|
throw new Error(`${WORKSPACE_NAME_REQUEST_INVALID}: a keyed birth name needs both its namespace and its key`);
|
|
17236
17238
|
}
|
|
17237
|
-
return create(ResolvedWorkspaceNameSchema, { workspace: keyedBirthNameOf(
|
|
17239
|
+
return create(ResolvedWorkspaceNameSchema, { workspace: keyedBirthNameOf(namespace2, key) });
|
|
17238
17240
|
}
|
|
17239
17241
|
case "receivingGroup": {
|
|
17240
17242
|
const { principal } = command.birth.value;
|
|
@@ -19285,6 +19287,136 @@ var ModelAdoptionDesk = class {
|
|
|
19285
19287
|
}
|
|
19286
19288
|
};
|
|
19287
19289
|
|
|
19290
|
+
// ../src/runtime/custody_receipts.ts
|
|
19291
|
+
init_define_NOMOS_KERNEL_RELEASE();
|
|
19292
|
+
|
|
19293
|
+
// ../src/runtime/peer_desk_store.ts
|
|
19294
|
+
init_define_NOMOS_KERNEL_RELEASE();
|
|
19295
|
+
var recordId = (namespace2, key) => `${namespace2.length}:${namespace2}${key}`;
|
|
19296
|
+
var copy2 = (record) => ({
|
|
19297
|
+
...record,
|
|
19298
|
+
value: record.value.slice()
|
|
19299
|
+
});
|
|
19300
|
+
var MemoryPeerDeskStore = class {
|
|
19301
|
+
#records = /* @__PURE__ */ new Map();
|
|
19302
|
+
list(namespace2) {
|
|
19303
|
+
return [...this.#records.values()].filter((record) => record.namespace === namespace2).sort((left, right) => left.key.localeCompare(right.key)).map(copy2);
|
|
19304
|
+
}
|
|
19305
|
+
compareExchange(namespace2, key, expectedRevision, value) {
|
|
19306
|
+
const id = recordId(namespace2, key);
|
|
19307
|
+
const current = this.#records.get(id);
|
|
19308
|
+
if (current?.revision !== expectedRevision) {
|
|
19309
|
+
throw new Error(
|
|
19310
|
+
`peer desk record '${namespace2}/${key}' changed at revision ${current?.revision ?? "absent"}`
|
|
19311
|
+
);
|
|
19312
|
+
}
|
|
19313
|
+
if (value === void 0) {
|
|
19314
|
+
this.#records.delete(id);
|
|
19315
|
+
return void 0;
|
|
19316
|
+
}
|
|
19317
|
+
const next = Object.freeze({
|
|
19318
|
+
namespace: namespace2,
|
|
19319
|
+
key,
|
|
19320
|
+
revision: (current?.revision ?? 0n) + 1n,
|
|
19321
|
+
value: value.slice()
|
|
19322
|
+
});
|
|
19323
|
+
this.#records.set(id, next);
|
|
19324
|
+
return copy2(next);
|
|
19325
|
+
}
|
|
19326
|
+
};
|
|
19327
|
+
|
|
19328
|
+
// ../src/runtime/custody_receipts.ts
|
|
19329
|
+
var namespace = "nomos.peer-desk.custody-receipts/v1";
|
|
19330
|
+
var encoder = new TextEncoder();
|
|
19331
|
+
var decoder = new TextDecoder();
|
|
19332
|
+
var MAX_BASES = 256;
|
|
19333
|
+
var MAX_RECEIPTS = 4096;
|
|
19334
|
+
var CustodyReceipts = class {
|
|
19335
|
+
#store;
|
|
19336
|
+
#records = /* @__PURE__ */ new Map();
|
|
19337
|
+
#journals = /* @__PURE__ */ new Map();
|
|
19338
|
+
#receipts = /* @__PURE__ */ new Map();
|
|
19339
|
+
constructor(store = new MemoryPeerDeskStore()) {
|
|
19340
|
+
this.#store = store;
|
|
19341
|
+
for (const record of store.list(namespace)) {
|
|
19342
|
+
this.#records.set(record.key, record);
|
|
19343
|
+
try {
|
|
19344
|
+
if (record.key.startsWith("receipt:")) {
|
|
19345
|
+
const newline = record.value.indexOf(10);
|
|
19346
|
+
if (newline < 0) continue;
|
|
19347
|
+
const receipt = fromBinary(CustodyIntentAdmissionSchema, record.value.subarray(newline + 1));
|
|
19348
|
+
const header2 = JSON.parse(decoder.decode(record.value.subarray(0, newline)));
|
|
19349
|
+
if (receipt.outcome.case === "admitted" && typeof header2.generation === "string" && typeof header2.head === "string") this.#receipts.set(record.key, { ...header2, receipt });
|
|
19350
|
+
continue;
|
|
19351
|
+
}
|
|
19352
|
+
if (!record.key.startsWith("head:")) continue;
|
|
19353
|
+
const value = JSON.parse(decoder.decode(record.value));
|
|
19354
|
+
if (typeof value.head !== "string" || typeof value.generation !== "string" || !Array.isArray(value.bases) || !Array.isArray(value.keys) || value.bases.length > MAX_BASES || value.keys.length > MAX_RECEIPTS) continue;
|
|
19355
|
+
if (!value.bases.every((base) => typeof base === "string") || !value.keys.every((key) => typeof key === "string")) continue;
|
|
19356
|
+
this.#journals.set(record.key.slice(5), value);
|
|
19357
|
+
} catch {
|
|
19358
|
+
}
|
|
19359
|
+
}
|
|
19360
|
+
}
|
|
19361
|
+
covers(workspace, current, base) {
|
|
19362
|
+
const value = this.#journals.get(workspace);
|
|
19363
|
+
return value?.head === current && value.bases.includes(base);
|
|
19364
|
+
}
|
|
19365
|
+
receipt(workspace, current, change) {
|
|
19366
|
+
const value = this.#journals.get(workspace);
|
|
19367
|
+
if (value?.head !== current) return void 0;
|
|
19368
|
+
const stored = this.#receipts.get(`receipt:${workspace}:${sha256Hex(change)}`);
|
|
19369
|
+
if (stored?.generation !== value.generation) return void 0;
|
|
19370
|
+
if (stored.head !== value.head && !value.bases.includes(stored.head)) return void 0;
|
|
19371
|
+
return fromBinary(CustodyIntentAdmissionSchema, toBinary(CustodyIntentAdmissionSchema, stored.receipt));
|
|
19372
|
+
}
|
|
19373
|
+
record(workspace, before, after, receipts) {
|
|
19374
|
+
const old = this.#journals.get(workspace);
|
|
19375
|
+
const journalKey = `head:${workspace}`;
|
|
19376
|
+
const value = old?.head === before ? { ...old, head: after, bases: [...old.bases], keys: [...old.keys] } : { head: after, bases: [], keys: [], generation: String((this.#records.get(journalKey)?.revision ?? 0n) + 1n) };
|
|
19377
|
+
if (before && before !== after) value.bases.push(before);
|
|
19378
|
+
value.bases = [...new Set(value.bases)].slice(-MAX_BASES);
|
|
19379
|
+
const keys = new Set(value.keys);
|
|
19380
|
+
const discarded = new Set(old?.generation !== value.generation ? old?.keys : []);
|
|
19381
|
+
for (const { change, receipt } of receipts) {
|
|
19382
|
+
if (receipt.outcome.case !== "admitted") continue;
|
|
19383
|
+
const key = `receipt:${workspace}:${sha256Hex(change)}`;
|
|
19384
|
+
keys.delete(key);
|
|
19385
|
+
keys.add(key);
|
|
19386
|
+
discarded.delete(key);
|
|
19387
|
+
const header2 = encoder.encode(`${JSON.stringify({ generation: value.generation, head: after })}
|
|
19388
|
+
`);
|
|
19389
|
+
const body = toBinary(CustodyIntentAdmissionSchema, receipt);
|
|
19390
|
+
const bytes = new Uint8Array(header2.length + body.length);
|
|
19391
|
+
bytes.set(header2);
|
|
19392
|
+
bytes.set(body, header2.length);
|
|
19393
|
+
const record2 = this.#store.compareExchange(namespace, key, this.#records.get(key)?.revision, bytes);
|
|
19394
|
+
if (record2) this.#records.set(key, record2);
|
|
19395
|
+
this.#receipts.set(key, {
|
|
19396
|
+
generation: value.generation,
|
|
19397
|
+
head: after,
|
|
19398
|
+
receipt: fromBinary(CustodyIntentAdmissionSchema, body)
|
|
19399
|
+
});
|
|
19400
|
+
}
|
|
19401
|
+
const ordered = [...keys];
|
|
19402
|
+
for (const key of ordered.slice(0, -MAX_RECEIPTS)) discarded.add(key);
|
|
19403
|
+
value.keys = ordered.slice(-MAX_RECEIPTS);
|
|
19404
|
+
for (const key of discarded) {
|
|
19405
|
+
this.#store.compareExchange(namespace, key, this.#records.get(key)?.revision, void 0);
|
|
19406
|
+
this.#records.delete(key);
|
|
19407
|
+
this.#receipts.delete(key);
|
|
19408
|
+
}
|
|
19409
|
+
const record = this.#store.compareExchange(
|
|
19410
|
+
namespace,
|
|
19411
|
+
journalKey,
|
|
19412
|
+
this.#records.get(journalKey)?.revision,
|
|
19413
|
+
encoder.encode(JSON.stringify(value))
|
|
19414
|
+
);
|
|
19415
|
+
if (record) this.#records.set(journalKey, record);
|
|
19416
|
+
this.#journals.set(workspace, value);
|
|
19417
|
+
}
|
|
19418
|
+
};
|
|
19419
|
+
|
|
19288
19420
|
// ../src/runtime/custodian_placement.ts
|
|
19289
19421
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
19290
19422
|
var CustodianPlacement = class {
|
|
@@ -19390,14 +19522,16 @@ var CandidateCustodyRequiredError = class extends Error {
|
|
|
19390
19522
|
var CustodyAdmissionDesk = class {
|
|
19391
19523
|
#kernel;
|
|
19392
19524
|
#custody;
|
|
19393
|
-
|
|
19525
|
+
#receipts;
|
|
19526
|
+
constructor(kernel, custody, receipts = new CustodyReceipts()) {
|
|
19394
19527
|
this.#kernel = kernel;
|
|
19395
19528
|
this.#custody = custody;
|
|
19529
|
+
this.#receipts = receipts;
|
|
19396
19530
|
}
|
|
19397
19531
|
admit(request, command) {
|
|
19398
|
-
const
|
|
19399
|
-
if (!
|
|
19400
|
-
const mount = this.#custody.
|
|
19532
|
+
const workspace = request.target?.workspace;
|
|
19533
|
+
if (!workspace) throw new Error("custody admission requires an addressed workspace");
|
|
19534
|
+
const mount = this.#custody.mountForWorkspace(workspace);
|
|
19401
19535
|
if (command.evidencePack.byteLength > 0) {
|
|
19402
19536
|
this.#kernel.applyPack(mount, request.requestId, command.evidencePack);
|
|
19403
19537
|
}
|
|
@@ -19408,21 +19542,42 @@ var CustodyAdmissionDesk = class {
|
|
|
19408
19542
|
const births = [];
|
|
19409
19543
|
const admittedBase = this.#kernel.head(mount, request.requestId) ?? "";
|
|
19410
19544
|
if (command.fastForwardOnly && offers.length > 0 && (command.baseHead ?? "") !== admittedBase) {
|
|
19545
|
+
for (const offer of offers) {
|
|
19546
|
+
const receipt = this.#receipts.receipt(mount.workspace, admittedBase, offer.changeUsda);
|
|
19547
|
+
if (!receipt) continue;
|
|
19548
|
+
receipt.commitOid = offer.commitOid;
|
|
19549
|
+
const records = sessions.get(offer.session) ?? [];
|
|
19550
|
+
records.push(receipt);
|
|
19551
|
+
sessions.set(offer.session, records);
|
|
19552
|
+
}
|
|
19553
|
+
let delta = custodyReturnDelta(
|
|
19554
|
+
this.#kernel,
|
|
19555
|
+
mount,
|
|
19556
|
+
request.requestId,
|
|
19557
|
+
command.baseHead,
|
|
19558
|
+
admittedBase,
|
|
19559
|
+
admittedBase,
|
|
19560
|
+
command.observedHead
|
|
19561
|
+
);
|
|
19562
|
+
if (command.baseHead && command.observedHead !== admittedBase && this.#receipts.covers(mount.workspace, admittedBase, command.baseHead)) {
|
|
19563
|
+
try {
|
|
19564
|
+
delta = {
|
|
19565
|
+
resultBase: command.baseHead,
|
|
19566
|
+
resultPack: this.#kernel.packDelta(mount, request.requestId, admittedBase, command.baseHead),
|
|
19567
|
+
recoveryRequired: false
|
|
19568
|
+
};
|
|
19569
|
+
} catch {
|
|
19570
|
+
}
|
|
19571
|
+
}
|
|
19411
19572
|
return create(CustodyAdmissionSchema, {
|
|
19412
19573
|
main: admittedBase,
|
|
19413
|
-
...
|
|
19414
|
-
|
|
19415
|
-
mount,
|
|
19416
|
-
request.requestId,
|
|
19417
|
-
command.baseHead,
|
|
19418
|
-
admittedBase,
|
|
19419
|
-
admittedBase,
|
|
19420
|
-
command.observedHead
|
|
19421
|
-
)
|
|
19574
|
+
sessions: [...sessions].map(([session, intents]) => create(CustodySessionAdmissionSchema, { session, intents })),
|
|
19575
|
+
...delta
|
|
19422
19576
|
});
|
|
19423
19577
|
}
|
|
19424
19578
|
let main = admittedBase;
|
|
19425
19579
|
const heldSessions = /* @__PURE__ */ new Map();
|
|
19580
|
+
const receipts = [];
|
|
19426
19581
|
for (const offer of offers) {
|
|
19427
19582
|
const heldBehind = heldSessions.get(offer.session);
|
|
19428
19583
|
const verdict = heldBehind === void 0 ? this.#offer(request, mount, offer) : create(OfferResponseSchema, { outcome: { case: "blockedOnDependency", value: {
|
|
@@ -19432,7 +19587,9 @@ var CustodyAdmissionDesk = class {
|
|
|
19432
19587
|
heldSessions.set(offer.session, verdict.outcome.value.offerId || offer.commitOid);
|
|
19433
19588
|
}
|
|
19434
19589
|
const records = sessions.get(offer.session) ?? [];
|
|
19435
|
-
|
|
19590
|
+
const receipt = this.#record(offer, verdict);
|
|
19591
|
+
records.push(receipt);
|
|
19592
|
+
receipts.push({ change: offer.changeUsda, receipt });
|
|
19436
19593
|
sessions.set(offer.session, records);
|
|
19437
19594
|
if (verdict.outcome.case === "admitted") {
|
|
19438
19595
|
main = verdict.outcome.value.head;
|
|
@@ -19448,6 +19605,9 @@ var CustodyAdmissionDesk = class {
|
|
|
19448
19605
|
}
|
|
19449
19606
|
}
|
|
19450
19607
|
}
|
|
19608
|
+
if (receipts.some((entry) => entry.receipt.outcome.case === "admitted")) {
|
|
19609
|
+
this.#receipts.record(mount.workspace, admittedBase, main, receipts);
|
|
19610
|
+
}
|
|
19451
19611
|
return create(CustodyAdmissionSchema, {
|
|
19452
19612
|
main,
|
|
19453
19613
|
sessions: [...sessions].map(
|
|
@@ -22419,8 +22579,8 @@ var short = (oid) => oid.slice(0, 12);
|
|
|
22419
22579
|
// ../src/runtime/preserved_copies_desk.ts
|
|
22420
22580
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
22421
22581
|
var PRESERVED_COPIES_NAMESPACE = "nomos.peer-desk.preserved-local-copies/v1";
|
|
22422
|
-
var
|
|
22423
|
-
var
|
|
22582
|
+
var encoder2 = new TextEncoder();
|
|
22583
|
+
var decoder2 = new TextDecoder();
|
|
22424
22584
|
var PreservedCopiesDesk = class {
|
|
22425
22585
|
#store;
|
|
22426
22586
|
constructor(store) {
|
|
@@ -22429,7 +22589,7 @@ var PreservedCopiesDesk = class {
|
|
|
22429
22589
|
list(workspace) {
|
|
22430
22590
|
const record = this.#store.list(PRESERVED_COPIES_NAMESPACE).find((entry) => entry.key === workspace);
|
|
22431
22591
|
if (!record) return [];
|
|
22432
|
-
const values = JSON.parse(
|
|
22592
|
+
const values = JSON.parse(decoder2.decode(record.value));
|
|
22433
22593
|
if (!Array.isArray(values)) {
|
|
22434
22594
|
throw new Error(`corrupt preserved-copy record for '${workspace}' at revision ${record.revision}`);
|
|
22435
22595
|
}
|
|
@@ -22443,7 +22603,7 @@ var PreservedCopiesDesk = class {
|
|
|
22443
22603
|
PRESERVED_COPIES_NAMESPACE,
|
|
22444
22604
|
copy3.workspace,
|
|
22445
22605
|
current?.revision,
|
|
22446
|
-
|
|
22606
|
+
encoder2.encode(`[${next.map((entry) => toJsonString(PreservedLocalCopySchema, entry)).join(",")}]`)
|
|
22447
22607
|
);
|
|
22448
22608
|
if (!stored) throw new Error(`preserved copy of '${copy3.workspace}' was not recorded`);
|
|
22449
22609
|
}
|
|
@@ -22486,9 +22646,9 @@ var LOCAL_ONLY_NAMESPACES = /* @__PURE__ */ new Set([
|
|
|
22486
22646
|
]);
|
|
22487
22647
|
var SEAT_PREFIX = "nomos-office-seat/v1:";
|
|
22488
22648
|
var SEAT_DIGEST_HEX = 64;
|
|
22489
|
-
var
|
|
22490
|
-
var
|
|
22491
|
-
var header = (digest) =>
|
|
22649
|
+
var encoder3 = new TextEncoder();
|
|
22650
|
+
var decoder3 = new TextDecoder();
|
|
22651
|
+
var header = (digest) => encoder3.encode(`${SEAT_PREFIX}${digest}
|
|
22492
22652
|
`);
|
|
22493
22653
|
var QuarantineReason = Object.freeze({
|
|
22494
22654
|
/** Another office's seat: a copied state directory, or a store lifted from another peer. */
|
|
@@ -22499,7 +22659,7 @@ var QuarantineReason = Object.freeze({
|
|
|
22499
22659
|
function readSeal(value) {
|
|
22500
22660
|
const headerLength = SEAT_PREFIX.length + SEAT_DIGEST_HEX + 1;
|
|
22501
22661
|
if (value.byteLength < headerLength) return void 0;
|
|
22502
|
-
const text =
|
|
22662
|
+
const text = decoder3.decode(value.subarray(0, headerLength));
|
|
22503
22663
|
if (!text.startsWith(SEAT_PREFIX) || !text.endsWith("\n")) return void 0;
|
|
22504
22664
|
const seat = text.slice(SEAT_PREFIX.length, headerLength - 1);
|
|
22505
22665
|
if (!/^[0-9a-f]{64}$/.test(seat)) return void 0;
|
|
@@ -22523,44 +22683,44 @@ var SeatedPeerDeskStore = class {
|
|
|
22523
22683
|
this.#seat = seat;
|
|
22524
22684
|
this.#report = report;
|
|
22525
22685
|
}
|
|
22526
|
-
list(
|
|
22527
|
-
if (LOCAL_ONLY_NAMESPACES.has(
|
|
22686
|
+
list(namespace2) {
|
|
22687
|
+
if (LOCAL_ONLY_NAMESPACES.has(namespace2)) return this.#inner.list(namespace2);
|
|
22528
22688
|
const kept = [];
|
|
22529
|
-
for (const record of this.#inner.list(
|
|
22689
|
+
for (const record of this.#inner.list(namespace2)) {
|
|
22530
22690
|
const sealed = readSeal(record.value);
|
|
22531
22691
|
if (sealed?.seat === this.#seat.digest) {
|
|
22532
22692
|
kept.push({ ...record, value: sealed.value.slice() });
|
|
22533
22693
|
continue;
|
|
22534
22694
|
}
|
|
22535
|
-
this.#quarantine(
|
|
22695
|
+
this.#quarantine(namespace2, record, sealed?.seat);
|
|
22536
22696
|
}
|
|
22537
22697
|
return kept;
|
|
22538
22698
|
}
|
|
22539
|
-
compareExchange(
|
|
22540
|
-
if (LOCAL_ONLY_NAMESPACES.has(
|
|
22541
|
-
return this.#inner.compareExchange(
|
|
22699
|
+
compareExchange(namespace2, key, expectedRevision, value) {
|
|
22700
|
+
if (LOCAL_ONLY_NAMESPACES.has(namespace2)) {
|
|
22701
|
+
return this.#inner.compareExchange(namespace2, key, expectedRevision, value);
|
|
22542
22702
|
}
|
|
22543
22703
|
const stored = this.#inner.compareExchange(
|
|
22544
|
-
|
|
22704
|
+
namespace2,
|
|
22545
22705
|
key,
|
|
22546
22706
|
expectedRevision,
|
|
22547
22707
|
value === void 0 ? void 0 : seal(this.#seat.digest, value)
|
|
22548
22708
|
);
|
|
22549
22709
|
if (stored === void 0) return void 0;
|
|
22550
22710
|
const sealed = readSeal(stored.value);
|
|
22551
|
-
if (!sealed) throw new Error(`peer desk record '${
|
|
22711
|
+
if (!sealed) throw new Error(`peer desk record '${namespace2}/${key}' lost its office seat`);
|
|
22552
22712
|
return { ...stored, value: sealed.value.slice() };
|
|
22553
22713
|
}
|
|
22554
22714
|
/** Preserve the foreign record under the quarantine namespace, then free the slot. */
|
|
22555
|
-
#quarantine(
|
|
22556
|
-
const key = `${
|
|
22715
|
+
#quarantine(namespace2, record, recordedSeat) {
|
|
22716
|
+
const key = `${namespace2}\0${record.key}\0${record.revision}`;
|
|
22557
22717
|
try {
|
|
22558
22718
|
this.#inner.compareExchange(QUARANTINED_BINDINGS_NAMESPACE, key, void 0, record.value);
|
|
22559
22719
|
} catch {
|
|
22560
22720
|
}
|
|
22561
|
-
this.#inner.compareExchange(
|
|
22721
|
+
this.#inner.compareExchange(namespace2, record.key, record.revision, void 0);
|
|
22562
22722
|
this.#report(create(QuarantinedBindingSchema, {
|
|
22563
|
-
namespace,
|
|
22723
|
+
namespace: namespace2,
|
|
22564
22724
|
key: record.key,
|
|
22565
22725
|
reason: recordedSeat === void 0 ? QuarantineReason.Unseated : QuarantineReason.ForeignSeat,
|
|
22566
22726
|
recordedSeat: recordedSeat ?? "",
|
|
@@ -22611,6 +22771,7 @@ var ReplicaInventoryDesk = class _ReplicaInventoryDesk {
|
|
|
22611
22771
|
const undiscovered = /* @__PURE__ */ new Set();
|
|
22612
22772
|
for (const restored of this.#follows.recover()) {
|
|
22613
22773
|
following.set(restored.workspace, restored.delayMillis);
|
|
22774
|
+
followed.add(restored.workspace);
|
|
22614
22775
|
}
|
|
22615
22776
|
if (!this.#bootstrapped) {
|
|
22616
22777
|
this.#bootstrapped = true;
|
|
@@ -22648,6 +22809,7 @@ var ReplicaInventoryDesk = class _ReplicaInventoryDesk {
|
|
|
22648
22809
|
stopped.delete(workspace);
|
|
22649
22810
|
} else if (reconciliation.changed) {
|
|
22650
22811
|
following.delete(workspace);
|
|
22812
|
+
followed.delete(workspace);
|
|
22651
22813
|
stopped.add(workspace);
|
|
22652
22814
|
}
|
|
22653
22815
|
} catch (error) {
|
|
@@ -22981,7 +23143,7 @@ var LiveCorrespondenceDesk = class {
|
|
|
22981
23143
|
wasResident: this.kernel.isResident(binding.workspace) !== false
|
|
22982
23144
|
};
|
|
22983
23145
|
this.#links.set(binding.workspace, link);
|
|
22984
|
-
if (link.wasResident) this.#open(link);
|
|
23146
|
+
if (!link.publisher || link.wasResident) this.#open(link);
|
|
22985
23147
|
}
|
|
22986
23148
|
changed(workspace) {
|
|
22987
23149
|
const link = this.#links.get(workspace);
|
|
@@ -23008,6 +23170,9 @@ var LiveCorrespondenceDesk = class {
|
|
|
23008
23170
|
this.#effect(link, { case: "send", value: bytes });
|
|
23009
23171
|
}
|
|
23010
23172
|
export(binding, base, requestId) {
|
|
23173
|
+
if (this.kernel.isResident(binding.workspace) === false) {
|
|
23174
|
+
return create(CustodyOfferBatchRequestSchema, { protocolVersion: 2 });
|
|
23175
|
+
}
|
|
23011
23176
|
const mount = workspaceMount(binding.workspace);
|
|
23012
23177
|
const head = this.kernel.head(mount, requestId);
|
|
23013
23178
|
if (!base || !head || base === head) return create(CustodyOfferBatchRequestSchema, { protocolVersion: 2 });
|
|
@@ -23068,6 +23233,7 @@ var LiveCorrespondenceDesk = class {
|
|
|
23068
23233
|
}
|
|
23069
23234
|
if (frame.message.case === "frontier") {
|
|
23070
23235
|
this.#announced(link, frame.message.value.head);
|
|
23236
|
+
if (this.kernel.isResident(link.binding.workspace) === false) return;
|
|
23071
23237
|
if (!frame.message.value.response) {
|
|
23072
23238
|
this.#send(link, { case: "frontier", value: {
|
|
23073
23239
|
head: this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId) ?? "",
|
|
@@ -23084,6 +23250,10 @@ var LiveCorrespondenceDesk = class {
|
|
|
23084
23250
|
if (frame.message.case !== "offers") return;
|
|
23085
23251
|
const batch = frame.message.value;
|
|
23086
23252
|
if (batch.protocolVersion !== 2 || !batch.requestId || batch.source.case !== "inline" || !batch.source.value.offers.length) return;
|
|
23253
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
23254
|
+
this.remoteAdvanced?.(link.binding.workspace);
|
|
23255
|
+
return;
|
|
23256
|
+
}
|
|
23087
23257
|
if ([...this.#pending.values()].some((pending) => pending.link === link && pending.bytes.length === bytes.length && pending.bytes.every((byte, index) => byte === bytes[index]))) return;
|
|
23088
23258
|
if (this.#pending.size >= 32) return;
|
|
23089
23259
|
this.#pending.set(request.requestId, { link, bytes });
|
|
@@ -23091,7 +23261,16 @@ var LiveCorrespondenceDesk = class {
|
|
|
23091
23261
|
protocolVersion: 2,
|
|
23092
23262
|
requestId: request.requestId,
|
|
23093
23263
|
target: { workspace: link.binding.workspace, session: link.binding.replicaId },
|
|
23094
|
-
|
|
23264
|
+
// HTTP sender reconciliation controls are not part of a live proposal.
|
|
23265
|
+
// Keeping fastForwardOnly while removing baseHead silently skips every
|
|
23266
|
+
// offer against a nonempty local head. The Kernel judges sealed causality;
|
|
23267
|
+
// live receivers neither ask for a return archive nor confirm the sender.
|
|
23268
|
+
command: { case: "admitCustodyOffers", value: create(CustodyOfferBatchRequestSchema, {
|
|
23269
|
+
...batch,
|
|
23270
|
+
baseHead: void 0,
|
|
23271
|
+
observedHead: void 0,
|
|
23272
|
+
fastForwardOnly: false
|
|
23273
|
+
}) }
|
|
23095
23274
|
});
|
|
23096
23275
|
}
|
|
23097
23276
|
/** Upstream news is a frontier this replica has NEVER seen: neither its own head nor the
|
|
@@ -23100,6 +23279,10 @@ var LiveCorrespondenceDesk = class {
|
|
|
23100
23279
|
#announced(link, head) {
|
|
23101
23280
|
if (!head || link.lastAnnounced === head) return;
|
|
23102
23281
|
link.lastAnnounced = head;
|
|
23282
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
23283
|
+
this.remoteAdvanced?.(link.binding.workspace);
|
|
23284
|
+
return;
|
|
23285
|
+
}
|
|
23103
23286
|
const mount = workspaceMount(link.binding.workspace);
|
|
23104
23287
|
if (head === this.kernel.head(mount, ++this.#requestId) || head === this.kernel.resolveRef(mount, ++this.#requestId, "refs/remotes/nomos/main")) return;
|
|
23105
23288
|
this.remoteAdvanced?.(link.binding.workspace);
|
|
@@ -23109,6 +23292,10 @@ var LiveCorrespondenceDesk = class {
|
|
|
23109
23292
|
#placementAnnounced(link, frontier) {
|
|
23110
23293
|
if (!frontier || link.lastPlacementAnnounced === frontier) return;
|
|
23111
23294
|
link.lastPlacementAnnounced = frontier;
|
|
23295
|
+
if (this.kernel.isResident(link.binding.workspace) === false) {
|
|
23296
|
+
this.placementAdvanced?.(link.binding.workspace);
|
|
23297
|
+
return;
|
|
23298
|
+
}
|
|
23112
23299
|
const mount = workspaceMount(link.binding.workspace);
|
|
23113
23300
|
if (frontier === this.kernel.resolveRef(mount, ++this.#requestId, PLACEMENT_REF2)) return;
|
|
23114
23301
|
this.placementAdvanced?.(link.binding.workspace);
|
|
@@ -23125,11 +23312,13 @@ var LiveCorrespondenceDesk = class {
|
|
|
23125
23312
|
disconnect(workspace) {
|
|
23126
23313
|
const link = this.#links.get(workspace);
|
|
23127
23314
|
if (!link) return;
|
|
23315
|
+
if (link.state === "open") this.linkClosed?.(workspace);
|
|
23128
23316
|
this.#effect(link, { case: "close", value: true });
|
|
23129
23317
|
this.#links.delete(workspace);
|
|
23130
23318
|
for (const [id, pending] of this.#pending) if (pending.link === link) this.#pending.delete(id);
|
|
23131
23319
|
}
|
|
23132
23320
|
#hello(link) {
|
|
23321
|
+
if (this.kernel.isResident(link.binding.workspace) === false) return;
|
|
23133
23322
|
const head = this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId);
|
|
23134
23323
|
this.#send(link, { case: "frontier", value: { head: head ?? "" } });
|
|
23135
23324
|
}
|
|
@@ -23137,19 +23326,20 @@ var LiveCorrespondenceDesk = class {
|
|
|
23137
23326
|
const now = this.clock.monotonicNanoseconds();
|
|
23138
23327
|
let wake;
|
|
23139
23328
|
for (const link of this.#links.values()) {
|
|
23140
|
-
|
|
23329
|
+
const resident = this.kernel.isResident(link.binding.workspace) !== false;
|
|
23330
|
+
if (link.publisher && !resident) {
|
|
23141
23331
|
if (link.wasResident) this.disconnect(link.binding.workspace);
|
|
23142
23332
|
else wake = wake === void 0 || wake > 250n ? 250n : wake;
|
|
23143
23333
|
continue;
|
|
23144
23334
|
}
|
|
23145
|
-
link.wasResident = true;
|
|
23335
|
+
if (resident) link.wasResident = true;
|
|
23146
23336
|
if (link.state === "opening" && now >= link.due) {
|
|
23147
23337
|
this.#effect(link, { case: "close", value: true });
|
|
23148
23338
|
link.state = "closed";
|
|
23149
23339
|
}
|
|
23150
23340
|
if (link.state === "closed" && now >= link.due) this.#open(link);
|
|
23151
23341
|
if (link.state === "open") {
|
|
23152
|
-
if (link.dirty) {
|
|
23342
|
+
if (link.dirty && resident) {
|
|
23153
23343
|
link.dirty = false;
|
|
23154
23344
|
try {
|
|
23155
23345
|
link.published ??= link.publisher ? this.kernel.head(workspaceMount(link.binding.workspace), ++this.#requestId) : this.kernel.resolveRef(workspaceMount(link.binding.workspace), ++this.#requestId, "refs/remotes/nomos/main");
|
|
@@ -23168,8 +23358,7 @@ var LiveCorrespondenceDesk = class {
|
|
|
23168
23358
|
return wake;
|
|
23169
23359
|
}
|
|
23170
23360
|
close() {
|
|
23171
|
-
for (const
|
|
23172
|
-
this.#links.clear();
|
|
23361
|
+
for (const workspace of [...this.#links.keys()]) this.disconnect(workspace);
|
|
23173
23362
|
this.#pending.clear();
|
|
23174
23363
|
}
|
|
23175
23364
|
};
|
|
@@ -23300,9 +23489,9 @@ var RecordsDesk = class {
|
|
|
23300
23489
|
command.namespace === void 0 ? {} : { "custody.children_namespace": command.namespace },
|
|
23301
23490
|
() => this.#kernel.childWorkspaces(mount, request.requestId)
|
|
23302
23491
|
);
|
|
23303
|
-
const
|
|
23304
|
-
const selected =
|
|
23305
|
-
(child) => child.status === ChildWorkspaceLifecycleStatus.ACTIVE && isKeyedBirthOf(
|
|
23492
|
+
const namespace2 = command.namespace;
|
|
23493
|
+
const selected = namespace2 === void 0 ? result.children : result.children.filter(
|
|
23494
|
+
(child) => child.status === ChildWorkspaceLifecycleStatus.ACTIVE && isKeyedBirthOf(namespace2, child.workspace)
|
|
23306
23495
|
);
|
|
23307
23496
|
return create(ChildWorkspaceListSchema, {
|
|
23308
23497
|
children: selected.map((child) => create(ChildWorkspaceSchema, {
|
|
@@ -23670,41 +23859,6 @@ var RecoveryDesk = class {
|
|
|
23670
23859
|
// ../src/runtime/correspondence_desk.ts
|
|
23671
23860
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
23672
23861
|
|
|
23673
|
-
// ../src/runtime/peer_desk_store.ts
|
|
23674
|
-
init_define_NOMOS_KERNEL_RELEASE();
|
|
23675
|
-
var recordId = (namespace, key) => `${namespace.length}:${namespace}${key}`;
|
|
23676
|
-
var copy2 = (record) => ({
|
|
23677
|
-
...record,
|
|
23678
|
-
value: record.value.slice()
|
|
23679
|
-
});
|
|
23680
|
-
var MemoryPeerDeskStore = class {
|
|
23681
|
-
#records = /* @__PURE__ */ new Map();
|
|
23682
|
-
list(namespace) {
|
|
23683
|
-
return [...this.#records.values()].filter((record) => record.namespace === namespace).sort((left, right) => left.key.localeCompare(right.key)).map(copy2);
|
|
23684
|
-
}
|
|
23685
|
-
compareExchange(namespace, key, expectedRevision, value) {
|
|
23686
|
-
const id = recordId(namespace, key);
|
|
23687
|
-
const current = this.#records.get(id);
|
|
23688
|
-
if (current?.revision !== expectedRevision) {
|
|
23689
|
-
throw new Error(
|
|
23690
|
-
`peer desk record '${namespace}/${key}' changed at revision ${current?.revision ?? "absent"}`
|
|
23691
|
-
);
|
|
23692
|
-
}
|
|
23693
|
-
if (value === void 0) {
|
|
23694
|
-
this.#records.delete(id);
|
|
23695
|
-
return void 0;
|
|
23696
|
-
}
|
|
23697
|
-
const next = Object.freeze({
|
|
23698
|
-
namespace,
|
|
23699
|
-
key,
|
|
23700
|
-
revision: (current?.revision ?? 0n) + 1n,
|
|
23701
|
-
value: value.slice()
|
|
23702
|
-
});
|
|
23703
|
-
this.#records.set(id, next);
|
|
23704
|
-
return copy2(next);
|
|
23705
|
-
}
|
|
23706
|
-
};
|
|
23707
|
-
|
|
23708
23862
|
// ../src/runtime/correspondence_recovery.ts
|
|
23709
23863
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
23710
23864
|
var CorrespondenceRecoveryWork = class {
|
|
@@ -24090,6 +24244,7 @@ var WorkspaceSyncWork = class {
|
|
|
24090
24244
|
#offerSequence = 0;
|
|
24091
24245
|
#lastStep;
|
|
24092
24246
|
#probeOnly;
|
|
24247
|
+
#liveConnected;
|
|
24093
24248
|
/** Set when this round adopted the upstream's own head as its base (see #establishBase). */
|
|
24094
24249
|
#establishedBase;
|
|
24095
24250
|
#receiveState;
|
|
@@ -24122,6 +24277,7 @@ var WorkspaceSyncWork = class {
|
|
|
24122
24277
|
this.#directoryAnswered = args.directoryAnswered;
|
|
24123
24278
|
this.#placementFetched = args.placementFetched;
|
|
24124
24279
|
this.#probeOnly = args.probeOnly ?? false;
|
|
24280
|
+
this.#liveConnected = args.liveConnected === true;
|
|
24125
24281
|
this.#receiveState = args.receiveState;
|
|
24126
24282
|
this.#completeHistory = args.completeHistory === true;
|
|
24127
24283
|
this.#repairMissingCommit = args.repairMissingCommit === true;
|
|
@@ -24192,6 +24348,9 @@ var WorkspaceSyncWork = class {
|
|
|
24192
24348
|
#openRound() {
|
|
24193
24349
|
if (this.#receiveState || this.#replaceLocalHead !== void 0) return this.#leaseEffect();
|
|
24194
24350
|
if (!this.#localHead) return this.#leaseEffect();
|
|
24351
|
+
if (this.#liveConnected && !this.#probeOnly && this.#holdsLocalWork() && this.#previousHead) {
|
|
24352
|
+
return this.#offerOrReconcile();
|
|
24353
|
+
}
|
|
24195
24354
|
const requestId = `${this.#binding.replicaId}:${this.#requestId}:${this.workId}:frontier`;
|
|
24196
24355
|
return this.#beginOffer(encodeInlineCustodyOffer({
|
|
24197
24356
|
session: this.#binding.replicaId,
|
|
@@ -24423,6 +24582,18 @@ var WorkspaceSyncWork = class {
|
|
|
24423
24582
|
return this.#finishOfferOutcome(false);
|
|
24424
24583
|
}
|
|
24425
24584
|
const admission = outcome.value;
|
|
24585
|
+
globalThis.__nomosSyncDiagnostic?.("sync.admission", {
|
|
24586
|
+
workspace: this.#mount.workspace,
|
|
24587
|
+
phase: state.phase,
|
|
24588
|
+
local: this.#localHead,
|
|
24589
|
+
tracked: this.#previousHead,
|
|
24590
|
+
remote: admission.main,
|
|
24591
|
+
sealed: admission.sealedMain,
|
|
24592
|
+
resultBase: admission.resultBase,
|
|
24593
|
+
resultBytes: admission.resultPack.byteLength,
|
|
24594
|
+
recoveryRequired: admission.recoveryRequired,
|
|
24595
|
+
summary: summarizeCustodyAdmission(admission)
|
|
24596
|
+
});
|
|
24426
24597
|
this.#desiredHead = admission.main || void 0;
|
|
24427
24598
|
if (!this.#desiredHead) return this.#transportFailure("resident peer returned no admitted frontier", false);
|
|
24428
24599
|
this.#candidateDurable = admission.sealedMain === this.#desiredHead;
|
|
@@ -25039,6 +25210,19 @@ var WorkspaceSyncWork = class {
|
|
|
25039
25210
|
return step;
|
|
25040
25211
|
}
|
|
25041
25212
|
#finish(value) {
|
|
25213
|
+
globalThis.__nomosSyncDiagnostic?.("sync.finished", {
|
|
25214
|
+
workspace: value.workspace,
|
|
25215
|
+
previous: value.previousHead,
|
|
25216
|
+
current: value.currentHead,
|
|
25217
|
+
stillAhead: value.stillAhead,
|
|
25218
|
+
deferred: String(value.deferred),
|
|
25219
|
+
admitted: String(value.admitted),
|
|
25220
|
+
reconnect: value.reconnectRequired,
|
|
25221
|
+
directOfferDeferred: value.directOfferDeferred,
|
|
25222
|
+
pushFailed: value.pushFailed,
|
|
25223
|
+
failure: value.pushError?.message,
|
|
25224
|
+
wallMs: elapsedMillis(this.#clock, this.#started)
|
|
25225
|
+
});
|
|
25042
25226
|
this.#state = { phase: WorkspaceSyncPhase.Done };
|
|
25043
25227
|
this.#current = void 0;
|
|
25044
25228
|
return this.#remember({ case: "synced", value });
|
|
@@ -25095,6 +25279,10 @@ var WorkspaceDependencySyncWork = class {
|
|
|
25095
25279
|
this.#plan = [this.#args.root];
|
|
25096
25280
|
return this.#advance();
|
|
25097
25281
|
}
|
|
25282
|
+
if (this.#args.liveConnected && this.#args.kernel.resolveRef(this.#args.root.mount, this.#args.requestId, trackedMain2)) {
|
|
25283
|
+
this.#plan = this.#planDependencies();
|
|
25284
|
+
return this.#advance();
|
|
25285
|
+
}
|
|
25098
25286
|
this.#current = this.#work(this.#args.root, `${this.workId}:frontier`, true);
|
|
25099
25287
|
return this.#accept(this.#current.start());
|
|
25100
25288
|
}
|
|
@@ -26288,6 +26476,7 @@ var CorrespondenceDesk = class {
|
|
|
26288
26476
|
#onSyncCompleted;
|
|
26289
26477
|
#onPlacementFetched;
|
|
26290
26478
|
#onShallowMount;
|
|
26479
|
+
#onOutboxHistoryRequired;
|
|
26291
26480
|
#remoteOffers = new CorrespondenceWorkRegistry();
|
|
26292
26481
|
#recoveries = new CorrespondenceWorkRegistry();
|
|
26293
26482
|
#deliveries = new CorrespondenceWorkRegistry();
|
|
@@ -26334,6 +26523,7 @@ var CorrespondenceDesk = class {
|
|
|
26334
26523
|
this.#onSyncCompleted = args.onSyncCompleted;
|
|
26335
26524
|
this.#onPlacementFetched = args.onPlacementFetched;
|
|
26336
26525
|
this.#onShallowMount = args.onShallowMount;
|
|
26526
|
+
this.#onOutboxHistoryRequired = args.onOutboxHistoryRequired;
|
|
26337
26527
|
this.#clock = args.clock;
|
|
26338
26528
|
this.#outboxClock = new OutboxObservationClock(args.clock, args.peerIdentity);
|
|
26339
26529
|
this.#executesCustodianObligations = args.executesCustodianObligations ?? false;
|
|
@@ -26497,6 +26687,15 @@ var CorrespondenceDesk = class {
|
|
|
26497
26687
|
this.#followLane.dependencyAdvanced(workspace);
|
|
26498
26688
|
this.reportFollows();
|
|
26499
26689
|
}
|
|
26690
|
+
/** Received custody can release correspondence and foreign-read dependencies,
|
|
26691
|
+
* but is not newly authored work to send back to its upstream. Recovery is
|
|
26692
|
+
* driven separately by missing history, reconnects and provider announcements.
|
|
26693
|
+
* In particular an optimistic relay is not a durable upstream receipt. */
|
|
26694
|
+
receivedFrontierChanged(workspace) {
|
|
26695
|
+
this.wakeOutbox(workspace);
|
|
26696
|
+
this.#followLane.dependencyAdvanced(workspace);
|
|
26697
|
+
this.reportFollows();
|
|
26698
|
+
}
|
|
26500
26699
|
/**
|
|
26501
26700
|
* Tell a workspace's sessions what its durable follow ALREADY knows.
|
|
26502
26701
|
*
|
|
@@ -26733,8 +26932,16 @@ var CorrespondenceDesk = class {
|
|
|
26733
26932
|
)
|
|
26734
26933
|
);
|
|
26735
26934
|
} catch (error) {
|
|
26935
|
+
if (error instanceof KernelHistoryRequired && this.#onOutboxHistoryRequired) {
|
|
26936
|
+
const retry = this.#onOutboxHistoryRequired(workspace, binding.credentialCapability);
|
|
26937
|
+
this.#outboxDueAt.set(workspace, now + Math.max(250, retry));
|
|
26938
|
+
return { nextAfterMillis: 0 };
|
|
26939
|
+
}
|
|
26736
26940
|
const format = localCopyFormatRefusal(error);
|
|
26737
|
-
if (format === void 0)
|
|
26941
|
+
if (format === void 0) {
|
|
26942
|
+
this.#outboxDueAt.set(workspace, now + 3e4);
|
|
26943
|
+
return { nextAfterMillis: 0 };
|
|
26944
|
+
}
|
|
26738
26945
|
this.#readability.mark(workspace, void 0, format);
|
|
26739
26946
|
this.#outboxDueAt.delete(workspace);
|
|
26740
26947
|
return { nextAfterMillis: 0 };
|
|
@@ -27014,6 +27221,7 @@ var CorrespondenceDesk = class {
|
|
|
27014
27221
|
requestId: request.requestId,
|
|
27015
27222
|
workId: id,
|
|
27016
27223
|
probeOnly,
|
|
27224
|
+
liveConnected: this.#openLinks.has(target3.mount.workspace),
|
|
27017
27225
|
...beforeConverge === void 0 ? {} : { beforeConverge },
|
|
27018
27226
|
...target3.receiveState === void 0 ? {} : { receiveState: target3.receiveState },
|
|
27019
27227
|
...target3.offerHead === void 0 ? {} : { offerHead: target3.offerHead },
|
|
@@ -27041,6 +27249,7 @@ var CorrespondenceDesk = class {
|
|
|
27041
27249
|
root,
|
|
27042
27250
|
work,
|
|
27043
27251
|
outbound: command.admit,
|
|
27252
|
+
liveConnected: this.#openLinks.has(mount.workspace),
|
|
27044
27253
|
dependency: (workspace, source, acquire2 = false) => {
|
|
27045
27254
|
if (this.#roundInFlight(workspace, workId2)) return void 0;
|
|
27046
27255
|
const existing = this.#follows.bindingForWorkspace(workspace);
|
|
@@ -28580,15 +28789,15 @@ function reduceHistoryAcquisition(state, event) {
|
|
|
28580
28789
|
var HISTORY_ACQUISITION_NAMESPACE = "nomos.peer-desk.history-acquisition/v1";
|
|
28581
28790
|
var HISTORY_BACKGROUND_START_MILLIS = 1e4;
|
|
28582
28791
|
var SLICE_ANSWER_MILLIS = 5 * 6e4;
|
|
28583
|
-
var
|
|
28584
|
-
var
|
|
28792
|
+
var encoder4 = new TextEncoder();
|
|
28793
|
+
var decoder4 = new TextDecoder();
|
|
28585
28794
|
var workId = (workspace) => `history-acquisition:${workspace}`;
|
|
28586
28795
|
var effectId = (workspace, attempt) => `history-acquisition:${workspace}:${HistoryAcquisitionPhase.Acquiring}:${attempt}`;
|
|
28587
28796
|
var encode2 = (work) => {
|
|
28588
28797
|
if (!work.credentialCapability) {
|
|
28589
28798
|
throw new Error(`history acquisition for '${work.workspace}' has not restored its credential capability`);
|
|
28590
28799
|
}
|
|
28591
|
-
return
|
|
28800
|
+
return encoder4.encode(JSON.stringify({
|
|
28592
28801
|
version: 2,
|
|
28593
28802
|
workspace: work.workspace,
|
|
28594
28803
|
credentialCapability: work.credentialCapability,
|
|
@@ -28597,7 +28806,7 @@ var encode2 = (work) => {
|
|
|
28597
28806
|
};
|
|
28598
28807
|
var upgraded = (state) => state.case === "backoff" ? { case: HistoryAcquisitionPhase.Paced, attempt: state.attempt, delayMillis: state.delayMillis, failed: true } : state;
|
|
28599
28808
|
var decode2 = (record) => {
|
|
28600
|
-
const value = JSON.parse(
|
|
28809
|
+
const value = JSON.parse(decoder4.decode(record.value));
|
|
28601
28810
|
if (!value || typeof value !== "object") throw corrupt2(record, "not an object");
|
|
28602
28811
|
const candidate = value;
|
|
28603
28812
|
if (candidate.version !== 1 && candidate.version !== 2 || candidate.workspace !== record.key || !candidate.state) {
|
|
@@ -28660,6 +28869,21 @@ var HistoryAcquisitionDesk = class {
|
|
|
28660
28869
|
this.#ensure(workspace, credentialCapability);
|
|
28661
28870
|
this.#dueAt.set(workspace, this.#now() + HISTORY_BACKGROUND_START_MILLIS);
|
|
28662
28871
|
}
|
|
28872
|
+
/** A background kernel read needs an omitted ancestor now. Queue one bounded
|
|
28873
|
+
* slice on the existing history lane; a failed slice keeps its retry pace. */
|
|
28874
|
+
requestFromBackground(workspace, credentialCapability) {
|
|
28875
|
+
if (!workspace) throw new Error("kernel history requirement names no workspace");
|
|
28876
|
+
this.#ensure(workspace, credentialCapability);
|
|
28877
|
+
const work = this.#get(workspace);
|
|
28878
|
+
const now = this.#now();
|
|
28879
|
+
if (work.state.case === HistoryAcquisitionPhase.Paced && work.state.failed) {
|
|
28880
|
+
const due2 = this.#dueAt.get(workspace) ?? now + work.state.delayMillis;
|
|
28881
|
+
this.#dueAt.set(workspace, due2);
|
|
28882
|
+
if (due2 > now) return due2 - now;
|
|
28883
|
+
}
|
|
28884
|
+
this.#dueAt.set(workspace, now);
|
|
28885
|
+
return 250;
|
|
28886
|
+
}
|
|
28663
28887
|
/** An operation needs history this custody lacks: its next slice now, joining one in flight. */
|
|
28664
28888
|
begin(workspace, credentialCapability) {
|
|
28665
28889
|
if (!workspace) throw new Error("kernel history requirement names no workspace");
|
|
@@ -28968,7 +29192,7 @@ var PeerOffice = class {
|
|
|
28968
29192
|
this.#trace,
|
|
28969
29193
|
this.#readability
|
|
28970
29194
|
);
|
|
28971
|
-
this.#custodyAdmission = new CustodyAdmissionDesk(this.#kernel, this.#custody);
|
|
29195
|
+
this.#custodyAdmission = new CustodyAdmissionDesk(this.#kernel, this.#custody, new CustodyReceipts(seatedStore));
|
|
28972
29196
|
this.#queries = new KernelQueries(this.#kernel, this.#credentials);
|
|
28973
29197
|
this.#follows = new ReplicaFollowController(
|
|
28974
29198
|
new ReplicaFollowDesk(seatedStore),
|
|
@@ -29130,6 +29354,7 @@ var PeerOffice = class {
|
|
|
29130
29354
|
// Lazy history: a head-only mount materialises its history in the background, never on
|
|
29131
29355
|
// the path of an operation (architecture/lazy_history.md).
|
|
29132
29356
|
onShallowMount: (workspace, credentialCapability) => this.#historyAcquisition.materialise(workspace, credentialCapability),
|
|
29357
|
+
onOutboxHistoryRequired: (workspace, credentialCapability) => this.#historyAcquisition.requestFromBackground(workspace, credentialCapability),
|
|
29133
29358
|
onSyncCompleted: (session, event) => {
|
|
29134
29359
|
if (event.result?.workspace) {
|
|
29135
29360
|
this.#replicaInventory.placementMayHaveChanged(event.result.workspace);
|
|
@@ -29596,8 +29821,8 @@ var PeerOffice = class {
|
|
|
29596
29821
|
this.#replicaInventory.placementMayHaveChanged(workspace);
|
|
29597
29822
|
}
|
|
29598
29823
|
}
|
|
29599
|
-
/** Execute a typed paper after the access desk
|
|
29600
|
-
*
|
|
29824
|
+
/** Execute a typed paper after the access desk. Custody admission addresses a
|
|
29825
|
+
* workspace by replica identity; application calls retain session binding. */
|
|
29601
29826
|
#dispatchRequest(request) {
|
|
29602
29827
|
validateRuntimeV2Request(request);
|
|
29603
29828
|
try {
|
|
@@ -29611,18 +29836,20 @@ var PeerOffice = class {
|
|
|
29611
29836
|
if (!request.target.workspace || !request.target.session) {
|
|
29612
29837
|
throw new Error("addressed runtime request requires workspace and session");
|
|
29613
29838
|
}
|
|
29614
|
-
|
|
29615
|
-
|
|
29616
|
-
if (binding
|
|
29617
|
-
|
|
29618
|
-
|
|
29619
|
-
|
|
29839
|
+
if (request.command.case !== "admitCustodyOffers") {
|
|
29840
|
+
const binding = this.#sessions.bindingIfPresent(request.target.session);
|
|
29841
|
+
if (binding !== void 0) {
|
|
29842
|
+
if (binding.workspace !== request.target.workspace) {
|
|
29843
|
+
throw new Error(
|
|
29844
|
+
`session '${request.target.session}' is bound to workspace '${binding.workspace}', not '${request.target.workspace}'`
|
|
29845
|
+
);
|
|
29846
|
+
}
|
|
29847
|
+
} else {
|
|
29848
|
+
this.#bindInteraction(create(BindSessionRequestSchema, {
|
|
29849
|
+
session: request.target.session,
|
|
29850
|
+
workspace: request.target.workspace
|
|
29851
|
+
}));
|
|
29620
29852
|
}
|
|
29621
|
-
} else {
|
|
29622
|
-
this.#bindInteraction(create(BindSessionRequestSchema, {
|
|
29623
|
-
session: request.target.session,
|
|
29624
|
-
workspace: request.target.workspace
|
|
29625
|
-
}));
|
|
29626
29853
|
}
|
|
29627
29854
|
}
|
|
29628
29855
|
switch (request.command.case) {
|
|
@@ -29819,7 +30046,7 @@ var PeerOffice = class {
|
|
|
29819
30046
|
ReadMaintenanceCause.ADMITTED_OFFER
|
|
29820
30047
|
);
|
|
29821
30048
|
this.#subscriptions.refreshWorkspace(request.target.workspace);
|
|
29822
|
-
this.#correspondence.
|
|
30049
|
+
this.#correspondence.receivedFrontierChanged(request.target.workspace);
|
|
29823
30050
|
}
|
|
29824
30051
|
return this.#birthCustodyResponse(
|
|
29825
30052
|
request,
|
|
@@ -30403,6 +30630,15 @@ function createBackgroundLanes(options) {
|
|
|
30403
30630
|
const correspondenceNotBefore = /* @__PURE__ */ new Map();
|
|
30404
30631
|
let retention = 0;
|
|
30405
30632
|
let closed = false;
|
|
30633
|
+
let selectionFailures = 0;
|
|
30634
|
+
const selectionFault = (error) => {
|
|
30635
|
+
try {
|
|
30636
|
+
options.onSelectionError?.(error);
|
|
30637
|
+
} catch {
|
|
30638
|
+
}
|
|
30639
|
+
selectionFailures += 1;
|
|
30640
|
+
wake(Math.min(3e4, 250 * 2 ** Math.min(selectionFailures - 1, 7)));
|
|
30641
|
+
};
|
|
30406
30642
|
const wake = (delayMillis = 0) => {
|
|
30407
30643
|
if (closed) return;
|
|
30408
30644
|
const delay = Math.max(0, Math.ceil(delayMillis));
|
|
@@ -30413,53 +30649,58 @@ function createBackgroundLanes(options) {
|
|
|
30413
30649
|
}
|
|
30414
30650
|
wakeAt = at;
|
|
30415
30651
|
timer = setTimer(() => {
|
|
30416
|
-
|
|
30417
|
-
|
|
30418
|
-
|
|
30419
|
-
|
|
30420
|
-
|
|
30421
|
-
|
|
30422
|
-
|
|
30423
|
-
|
|
30424
|
-
|
|
30425
|
-
|
|
30426
|
-
|
|
30427
|
-
|
|
30428
|
-
if (
|
|
30429
|
-
|
|
30430
|
-
|
|
30431
|
-
|
|
30432
|
-
|
|
30652
|
+
try {
|
|
30653
|
+
timer = void 0;
|
|
30654
|
+
wakeAt = void 0;
|
|
30655
|
+
if (closed) return;
|
|
30656
|
+
const now = options.monotonicNanoseconds();
|
|
30657
|
+
for (const [workspace2, at2] of correspondenceNotBefore) {
|
|
30658
|
+
if (at2 <= now) correspondenceNotBefore.delete(workspace2);
|
|
30659
|
+
}
|
|
30660
|
+
const backoffMillis = correspondenceNotBefore.size ? Math.min(...[...correspondenceNotBefore.values()].map((at2) => Number((at2 - now + 999999n) / 1000000n))) : void 0;
|
|
30661
|
+
const retentionOnly = correspondenceInFlight;
|
|
30662
|
+
const next = options.nextPaper(retentionOnly, new Set(correspondenceNotBefore.keys()));
|
|
30663
|
+
selectionFailures = 0;
|
|
30664
|
+
if (next.frame === void 0) {
|
|
30665
|
+
const delays = [next.nextAfterMillis, backoffMillis].filter((delay2) => delay2 !== void 0);
|
|
30666
|
+
if (delays.length) wake(Math.min(...delays));
|
|
30667
|
+
return;
|
|
30668
|
+
}
|
|
30669
|
+
if (options.isRetention(next.frame)) {
|
|
30670
|
+
retention += 1;
|
|
30671
|
+
void options.drive(next.frame).then(
|
|
30672
|
+
() => {
|
|
30673
|
+
retention -= 1;
|
|
30674
|
+
wake(0);
|
|
30675
|
+
},
|
|
30676
|
+
() => {
|
|
30677
|
+
retention -= 1;
|
|
30678
|
+
wake(0);
|
|
30679
|
+
}
|
|
30680
|
+
);
|
|
30681
|
+
wake(next.nextAfterMillis ?? 0);
|
|
30682
|
+
return;
|
|
30683
|
+
}
|
|
30684
|
+
if (retentionOnly) throw new Error("background desk reserved correspondence while its lane was unavailable");
|
|
30685
|
+
const workspace = next.workspace;
|
|
30686
|
+
if (!workspace) throw new Error("background correspondence has no source workspace");
|
|
30687
|
+
if (correspondenceNotBefore.has(workspace)) throw new Error("background desk bypassed a workspace's physical backoff");
|
|
30688
|
+
correspondenceInFlight = true;
|
|
30433
30689
|
void options.drive(next.frame).then(
|
|
30434
30690
|
() => {
|
|
30435
|
-
|
|
30436
|
-
wake(0);
|
|
30691
|
+
correspondenceInFlight = false;
|
|
30692
|
+
wake(next.nextAfterMillis ?? 0);
|
|
30437
30693
|
},
|
|
30438
30694
|
() => {
|
|
30439
|
-
|
|
30695
|
+
correspondenceInFlight = false;
|
|
30696
|
+
correspondenceNotBefore.set(workspace, options.monotonicNanoseconds() + BigInt(failureBackoffMillis) * 1000000n);
|
|
30440
30697
|
wake(0);
|
|
30441
30698
|
}
|
|
30442
30699
|
);
|
|
30443
|
-
wake(
|
|
30444
|
-
|
|
30700
|
+
wake(0);
|
|
30701
|
+
} catch (error) {
|
|
30702
|
+
selectionFault(error);
|
|
30445
30703
|
}
|
|
30446
|
-
if (retentionOnly) throw new Error("background desk reserved correspondence while its lane was unavailable");
|
|
30447
|
-
const workspace = next.workspace;
|
|
30448
|
-
if (!workspace) throw new Error("background correspondence has no source workspace");
|
|
30449
|
-
if (correspondenceNotBefore.has(workspace)) throw new Error("background desk bypassed a workspace's physical backoff");
|
|
30450
|
-
correspondenceInFlight = true;
|
|
30451
|
-
void options.drive(next.frame).then(
|
|
30452
|
-
() => {
|
|
30453
|
-
correspondenceInFlight = false;
|
|
30454
|
-
wake(next.nextAfterMillis ?? 0);
|
|
30455
|
-
},
|
|
30456
|
-
() => {
|
|
30457
|
-
correspondenceInFlight = false;
|
|
30458
|
-
correspondenceNotBefore.set(workspace, options.monotonicNanoseconds() + BigInt(failureBackoffMillis) * 1000000n);
|
|
30459
|
-
wake(0);
|
|
30460
|
-
}
|
|
30461
|
-
);
|
|
30462
|
-
wake(0);
|
|
30463
30704
|
}, delay);
|
|
30464
30705
|
};
|
|
30465
30706
|
return {
|
|
@@ -30534,7 +30775,8 @@ function createPeerOfficeFrameRunner(kernel, credentials, profile, observations,
|
|
|
30534
30775
|
throw error;
|
|
30535
30776
|
}),
|
|
30536
30777
|
isRetention: (frame) => fromBinary(RuntimeRequestSchema, frame).command.case === "retainFrontier",
|
|
30537
|
-
monotonicNanoseconds: () => observations.monotonicNanoseconds()
|
|
30778
|
+
monotonicNanoseconds: () => observations.monotonicNanoseconds(),
|
|
30779
|
+
onSelectionError: (error) => console.error("Nomos background paper selection failed", error)
|
|
30538
30780
|
});
|
|
30539
30781
|
const scheduleCorrespondence = (delayMillis = 0) => {
|
|
30540
30782
|
lanes?.wake(delayMillis);
|
|
@@ -30765,13 +31007,19 @@ var candidateSessionReference = async (identity) => {
|
|
|
30765
31007
|
};
|
|
30766
31008
|
var executeGitFetchWithAlongside = async (effect, fetchImpl) => {
|
|
30767
31009
|
if (!effect.alongside) return executeGitFetchEffect(effect, fetchImpl);
|
|
30768
|
-
const
|
|
30769
|
-
|
|
30770
|
-
|
|
30771
|
-
|
|
30772
|
-
|
|
31010
|
+
const cancelAlongside = new AbortController();
|
|
31011
|
+
let alongside;
|
|
31012
|
+
void executeHttpEffect(effect.alongside, (input, init) => fetchImpl(input, {
|
|
31013
|
+
...init,
|
|
31014
|
+
signal: init?.signal ? AbortSignal.any([init.signal, cancelAlongside.signal]) : cancelAlongside.signal
|
|
31015
|
+
})).then((receipt) => {
|
|
31016
|
+
alongside = receipt;
|
|
31017
|
+
});
|
|
31018
|
+
const fetched = await executeGitFetchEffect(effect, fetchImpl);
|
|
31019
|
+
if (fetched.outcome.case === "gitFetch" && alongside?.outcome.case === "response") {
|
|
30773
31020
|
fetched.outcome.value.alongside = alongside.outcome.value;
|
|
30774
31021
|
}
|
|
31022
|
+
cancelAlongside.abort();
|
|
30775
31023
|
return fetched;
|
|
30776
31024
|
};
|
|
30777
31025
|
var executeGitPushEffect = async (effect, fetchImpl) => {
|
|
@@ -31139,7 +31387,8 @@ function socketEffects(invoke2, permits = () => true) {
|
|
|
31139
31387
|
requestId: ++sequence,
|
|
31140
31388
|
command: { case: "socketReceipt", value: create(PeerSocketReceiptSchema, { connectionId, observation }) }
|
|
31141
31389
|
}));
|
|
31142
|
-
void Promise.resolve().then(() => invoke2(frame)).catch(() => {
|
|
31390
|
+
void Promise.resolve().then(() => invoke2(frame)).catch((error) => {
|
|
31391
|
+
console.warn("[nomos-socket] receipt failed", { connectionId, error });
|
|
31143
31392
|
sockets.get(connectionId)?.close();
|
|
31144
31393
|
});
|
|
31145
31394
|
};
|
|
@@ -31161,6 +31410,7 @@ function socketEffects(invoke2, permits = () => true) {
|
|
|
31161
31410
|
socket.onopen = () => receipt(id, { case: "opened", value: true });
|
|
31162
31411
|
socket.onmessage = (message) => {
|
|
31163
31412
|
if (message.data instanceof ArrayBuffer) receipt(id, { case: "received", value: new Uint8Array(message.data) });
|
|
31413
|
+
else if (typeof message.data === "string") receipt(id, { case: "received", value: new TextEncoder().encode(message.data) });
|
|
31164
31414
|
};
|
|
31165
31415
|
socket.onclose = () => {
|
|
31166
31416
|
if (sockets.get(id) === socket) sockets.delete(id);
|
|
@@ -31374,21 +31624,21 @@ var SqlitePeerDeskStore = class {
|
|
|
31374
31624
|
}
|
|
31375
31625
|
return this.#opened = database;
|
|
31376
31626
|
}
|
|
31377
|
-
list(
|
|
31627
|
+
list(namespace2) {
|
|
31378
31628
|
const rows = this.#database().prepare(`
|
|
31379
31629
|
SELECT record_key AS key, revision, value
|
|
31380
31630
|
FROM peer_desk_record
|
|
31381
31631
|
WHERE namespace = ?
|
|
31382
31632
|
ORDER BY record_key
|
|
31383
|
-
`).all(
|
|
31633
|
+
`).all(namespace2);
|
|
31384
31634
|
return rows.map((row) => ({
|
|
31385
|
-
namespace,
|
|
31635
|
+
namespace: namespace2,
|
|
31386
31636
|
key: row.key,
|
|
31387
31637
|
revision: BigInt(row.revision),
|
|
31388
31638
|
value: Uint8Array.from(row.value)
|
|
31389
31639
|
}));
|
|
31390
31640
|
}
|
|
31391
|
-
compareExchange(
|
|
31641
|
+
compareExchange(namespace2, key, expectedRevision, value) {
|
|
31392
31642
|
const expected = expectedRevision === void 0 ? void 0 : Number(expectedRevision);
|
|
31393
31643
|
if (expected !== void 0 && (!Number.isSafeInteger(expected) || expected <= 0)) {
|
|
31394
31644
|
throw new Error(`peer desk revision ${expectedRevision} cannot be represented by SQLite`);
|
|
@@ -31401,8 +31651,8 @@ var SqlitePeerDeskStore = class {
|
|
|
31401
31651
|
const removed = database.prepare(`
|
|
31402
31652
|
DELETE FROM peer_desk_record
|
|
31403
31653
|
WHERE namespace = ? AND record_key = ? AND revision = ?
|
|
31404
|
-
`).run(
|
|
31405
|
-
if (removed.changes !== 1) this.#conflict(
|
|
31654
|
+
`).run(namespace2, key, expected);
|
|
31655
|
+
if (removed.changes !== 1) this.#conflict(namespace2, key);
|
|
31406
31656
|
return this.#commit(void 0);
|
|
31407
31657
|
}
|
|
31408
31658
|
const bytes = Buffer.from(value.buffer, value.byteOffset, value.byteLength);
|
|
@@ -31414,14 +31664,14 @@ var SqlitePeerDeskStore = class {
|
|
|
31414
31664
|
INSERT INTO peer_desk_record(namespace, record_key, revision, value)
|
|
31415
31665
|
VALUES (?, ?, 1, ?)
|
|
31416
31666
|
ON CONFLICT(namespace, record_key) DO NOTHING
|
|
31417
|
-
`).run(
|
|
31667
|
+
`).run(namespace2, key, bytes) : database.prepare(`
|
|
31418
31668
|
UPDATE peer_desk_record
|
|
31419
31669
|
SET revision = ?, value = ?
|
|
31420
31670
|
WHERE namespace = ? AND record_key = ? AND revision = ?
|
|
31421
|
-
`).run(nextRevision, bytes,
|
|
31422
|
-
if (changed.changes !== 1) this.#conflict(
|
|
31671
|
+
`).run(nextRevision, bytes, namespace2, key, expected);
|
|
31672
|
+
if (changed.changes !== 1) this.#conflict(namespace2, key);
|
|
31423
31673
|
return this.#commit({
|
|
31424
|
-
namespace,
|
|
31674
|
+
namespace: namespace2,
|
|
31425
31675
|
key,
|
|
31426
31676
|
revision: BigInt(nextRevision),
|
|
31427
31677
|
value: value.slice()
|
|
@@ -31439,12 +31689,12 @@ var SqlitePeerDeskStore = class {
|
|
|
31439
31689
|
this.#database().exec("COMMIT");
|
|
31440
31690
|
return value;
|
|
31441
31691
|
}
|
|
31442
|
-
#conflict(
|
|
31692
|
+
#conflict(namespace2, key) {
|
|
31443
31693
|
const current = this.#database().prepare(`
|
|
31444
31694
|
SELECT revision FROM peer_desk_record WHERE namespace = ? AND record_key = ?
|
|
31445
|
-
`).get(
|
|
31695
|
+
`).get(namespace2, key);
|
|
31446
31696
|
throw new Error(
|
|
31447
|
-
`peer desk record '${
|
|
31697
|
+
`peer desk record '${namespace2}/${key}' changed at revision ${current?.revision ?? "absent"}`
|
|
31448
31698
|
);
|
|
31449
31699
|
}
|
|
31450
31700
|
};
|
|
@@ -31757,7 +32007,7 @@ var okBytes = async (fetchImpl, url) => {
|
|
|
31757
32007
|
async function selectReleaseKernel(args) {
|
|
31758
32008
|
const fetchImpl = args.fetchImpl ?? ((input, init) => globalThis.fetch(input, init));
|
|
31759
32009
|
const base = args.base.replace(/\/+$/, "");
|
|
31760
|
-
const repositoryUrl = `${base}/v1/runtime/repository.xml`;
|
|
32010
|
+
const repositoryUrl = args.repositoryUrl ?? `${base}/v1/runtime/repository.xml`;
|
|
31761
32011
|
const repositoryResponse = await fetchImpl(repositoryUrl);
|
|
31762
32012
|
if (!repositoryResponse.ok) {
|
|
31763
32013
|
throw new Error(`custodian kernel repository ${repositoryUrl}: HTTP ${repositoryResponse.status}`);
|