githolon 0.113.2 → 0.113.3

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.
@@ -7050,6 +7050,37 @@ var init_kernel_port = __esm({
7050
7050
  }
7051
7051
  });
7052
7052
 
7053
+ // ../peer-office/src/runtime/http_origin.ts
7054
+ function httpOrigin(url) {
7055
+ const match = AUTHORITY.exec(url.trim());
7056
+ if (!match) return void 0;
7057
+ const scheme = match[1].toLowerCase();
7058
+ if (scheme !== "http" && scheme !== "https") return void 0;
7059
+ const authority = match[2];
7060
+ const hostAndPort = authority.slice(authority.lastIndexOf("@") + 1);
7061
+ const ipv6 = /^(\[[0-9a-f:.]+\])(?::(\d*))?$/i.exec(hostAndPort);
7062
+ const named = /^([^:[\]\s]+)(?::(\d*))?$/.exec(hostAndPort);
7063
+ const parts = ipv6 ?? named;
7064
+ if (!parts) return void 0;
7065
+ const host = parts[1].toLowerCase();
7066
+ if (host.length === 0 || /[\s<>^`{|}%\\]/.test(host)) return void 0;
7067
+ let port = parts[2] ?? "";
7068
+ if (port !== "") {
7069
+ const value = Number(port);
7070
+ if (!Number.isInteger(value) || value > 65535) return void 0;
7071
+ port = String(value);
7072
+ }
7073
+ return port === "" || port === DEFAULT_PORTS[scheme] ? `${scheme}://${host}` : `${scheme}://${host}:${port}`;
7074
+ }
7075
+ var AUTHORITY, DEFAULT_PORTS;
7076
+ var init_http_origin = __esm({
7077
+ "../peer-office/src/runtime/http_origin.ts"() {
7078
+ "use strict";
7079
+ AUTHORITY = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)/i;
7080
+ DEFAULT_PORTS = { http: "80", https: "443" };
7081
+ }
7082
+ });
7083
+
7053
7084
  // ../peer-office/src/git_read_lease.ts
7054
7085
  import { fromBinary as fromBinary5 } from "@bufbuild/protobuf";
7055
7086
  function decodeGitReadLease(bytes, workspace, nowUnixSeconds = BigInt(Math.floor(Date.now() / 1e3))) {
@@ -7401,6 +7432,7 @@ var stableIdentifier, normalizeProfile, originOf2, ReplicaPlacementDirectiveKind
7401
7432
  var init_placement_desk = __esm({
7402
7433
  "../peer-office/src/runtime/placement_desk.ts"() {
7403
7434
  "use strict";
7435
+ init_http_origin();
7404
7436
  init_provider_origins();
7405
7437
  init_kernel_pb();
7406
7438
  init_placement_desk_pb();
@@ -7425,14 +7457,7 @@ var init_placement_desk = __esm({
7425
7457
  ...servedOrigin === void 0 ? {} : { servedOrigin }
7426
7458
  });
7427
7459
  };
7428
- originOf2 = (url) => {
7429
- try {
7430
- const parsed = new URL(url);
7431
- return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.origin : void 0;
7432
- } catch {
7433
- return void 0;
7434
- }
7435
- };
7460
+ originOf2 = httpOrigin;
7436
7461
  ReplicaPlacementDirectiveKind = Object.freeze({
7437
7462
  None: "none",
7438
7463
  Cache: "cache",
@@ -13599,7 +13624,10 @@ var init_read_maintenance_desk = __esm({
13599
13624
  ...background ? { background } : {},
13600
13625
  ...awaited || existing?.awaited ? { awaited: true } : {},
13601
13626
  failures: existing?.failures ?? 0,
13602
- retryNotBeforeNanoseconds: 0n
13627
+ // A foreground read may retry at once. Upkeep owed by a write or a sync keeps any back-off
13628
+ // it is already serving: otherwise every write retried a failing upkeep immediately, and a
13629
+ // workspace whose upkeep could not succeed retried on every write (CAP-693).
13630
+ retryNotBeforeNanoseconds: isReadDemand ? 0n : existing?.retryNotBeforeNanoseconds ?? 0n
13603
13631
  });
13604
13632
  if (isReadDemand && (!existing?.read || existing.read.owedByAdvance)) {
13605
13633
  const entries = [...this.#pending.entries()];
@@ -14248,18 +14276,17 @@ var init_subscription_manager = __esm({
14248
14276
  #requestReadMaintenance;
14249
14277
  #clock;
14250
14278
  #subscriptions = /* @__PURE__ */ new Map();
14251
- /** Watches owed a re-read, drained one query group per turn when a turn scheduler is given. */
14279
+ /** Watches owed a re-read, drained one query group per office turn (see [drainOwedTurn]). */
14252
14280
  #owed = /* @__PURE__ */ new Set();
14253
- #nextTurn;
14254
- #draining = false;
14281
+ #deferRefreshes;
14255
14282
  #sequence = 0n;
14256
- constructor(queries, sessions, events, requestReadMaintenance, clock, nextTurn) {
14283
+ constructor(queries, sessions, events, requestReadMaintenance, clock, deferRefreshes = false) {
14257
14284
  this.#queries = queries;
14258
14285
  this.#sessions = sessions;
14259
14286
  this.#events = events;
14260
14287
  this.#requestReadMaintenance = requestReadMaintenance;
14261
14288
  this.#clock = clock;
14262
- this.#nextTurn = nextTurn;
14289
+ this.#deferRefreshes = deferRefreshes;
14263
14290
  }
14264
14291
  start(request, command) {
14265
14292
  if (!command.subscriptionId) throw new Error("watch requires a subscription identity");
@@ -14365,34 +14392,33 @@ var init_subscription_manager = __esm({
14365
14392
  * or replace current authorization. Each watch still owns its delivery state.
14366
14393
  */
14367
14394
  #refreshMatching(matches, cause) {
14368
- if (this.#nextTurn && !cause) {
14395
+ if (this.#deferRefreshes && !cause) {
14369
14396
  for (const [id, subscription] of this.#subscriptions) {
14370
14397
  if (subscription.request.query && matches(subscription)) this.#owed.add(id);
14371
14398
  }
14372
- this.#drain();
14373
14399
  return;
14374
14400
  }
14375
14401
  this.#refreshGroups(this.#groups(matches), cause);
14376
14402
  }
14377
- #drain() {
14378
- if (this.#draining || this.#owed.size === 0) return;
14379
- this.#draining = true;
14380
- this.#nextTurn(() => {
14381
- this.#draining = false;
14382
- if (this.#owed.size === 0) return;
14383
- const first = this.#owed.values().next().value;
14384
- const lead = this.#subscriptions.get(first);
14385
- if (!lead?.request.query) {
14386
- this.#owed.delete(first);
14387
- } else {
14388
- const declaration = toBinary15(QueryRequestSchema, lead.request.query);
14389
- const session = lead.request.session;
14390
- const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary15(QueryRequestSchema, subscription.request.query), declaration));
14391
- for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
14392
- this.#refreshGroups(group);
14393
- }
14394
- this.#drain();
14395
- });
14403
+ /** Whether any watch is owed a re-read: the office's next drive() is due at once. */
14404
+ get owesRefresh() {
14405
+ return this.#owed.size > 0;
14406
+ }
14407
+ /** One office turn of owed re-reads: the first owed watch's query group. False when none was owed. */
14408
+ drainOwedTurn() {
14409
+ if (this.#owed.size === 0) return false;
14410
+ const first = this.#owed.values().next().value;
14411
+ const lead = this.#subscriptions.get(first);
14412
+ if (!lead?.request.query) {
14413
+ this.#owed.delete(first);
14414
+ return true;
14415
+ }
14416
+ const declaration = toBinary15(QueryRequestSchema, lead.request.query);
14417
+ const session = lead.request.session;
14418
+ const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary15(QueryRequestSchema, subscription.request.query), declaration));
14419
+ for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
14420
+ this.#refreshGroups(group);
14421
+ return true;
14396
14422
  }
14397
14423
  #groups(matches) {
14398
14424
  const groups = [];
@@ -14512,6 +14538,44 @@ var init_subscription_manager = __esm({
14512
14538
  }
14513
14539
  });
14514
14540
 
14541
+ // ../peer-office/src/runtime/shell_contract.ts
14542
+ function declaredShellContract(scope = globalThis) {
14543
+ const declared = scope.__nomosShellContract;
14544
+ return declared === void 0 ? 1 : Number(declared);
14545
+ }
14546
+ function assertShellContract(scope = globalThis) {
14547
+ const declared = declaredShellContract(scope);
14548
+ if (!Number.isInteger(declared) || declared < SHELL_CONTRACT_MINIMUM) {
14549
+ throw new Error(`nomos.runtime.shell_contract_unsupported: this runtime needs shell contract ${SHELL_CONTRACT_MINIMUM} or later; the shell declares ${String(declared)}`);
14550
+ }
14551
+ }
14552
+ var SHELL_CONTRACT_V1, SHELL_CONTRACT_V2, SHELL_CONTRACT_MINIMUM;
14553
+ var init_shell_contract = __esm({
14554
+ "../peer-office/src/runtime/shell_contract.ts"() {
14555
+ "use strict";
14556
+ SHELL_CONTRACT_V1 = Object.freeze({
14557
+ version: 1,
14558
+ /** Host globals beyond ECMAScript 2022, which every shell supplies. */
14559
+ host: Object.freeze(["TextEncoder", "TextDecoder", "queueMicrotask", "console"]),
14560
+ /** Nomos bridges a native bootstrap installs for the ports it hands to peerOffice.open. */
14561
+ bridges: Object.freeze([
14562
+ "__nomosKernel",
14563
+ "__nomosCredentialVault",
14564
+ "__nomosProfile",
14565
+ "__nomosObservations",
14566
+ "__nomosCustodyStorage",
14567
+ "__nomosPeerDeskStore",
14568
+ "__nomosSyncDiagnostic",
14569
+ "__nomosShellContract"
14570
+ ]),
14571
+ /** Globals the runtime may only probe: used behind their own `typeof` test, never bare. */
14572
+ probed: Object.freeze(["process", "Deno", "Bun", "define"])
14573
+ });
14574
+ SHELL_CONTRACT_V2 = Object.freeze({ ...SHELL_CONTRACT_V1, version: 2 });
14575
+ SHELL_CONTRACT_MINIMUM = 1;
14576
+ }
14577
+ });
14578
+
14515
14579
  // ../peer-office/src/runtime/replica_follow_state.ts
14516
14580
  function reduceReplicaFollow(state, event, policy) {
14517
14581
  switch (event.case) {
@@ -22741,6 +22805,7 @@ var init_peer_office = __esm({
22741
22805
  init_residency_pins();
22742
22806
  init_maintenance_desk_pb();
22743
22807
  init_subscription_manager();
22808
+ init_shell_contract();
22744
22809
  init_replica_follow_controller();
22745
22810
  init_replica_follow_desk();
22746
22811
  init_local_copy_drop();
@@ -22937,10 +23002,9 @@ var init_peer_office = __esm({
22937
23002
  this.#trace,
22938
23003
  (session) => this.#readMaintenance.schedule(session, ReadMaintenanceCause.READ_DEBT),
22939
23004
  observations,
22940
- // An interactive peer keeps its thread responsive while watches catch up.
22941
- this.#interactivePeer ? (run2) => {
22942
- setTimeout(run2, 0);
22943
- } : void 0
23005
+ // An interactive peer keeps its thread responsive while watches catch up: owed re-reads
23006
+ // wait for its drive() turns.
23007
+ this.#interactivePeer
22944
23008
  );
22945
23009
  this.#application = new ApplicationDesk({
22946
23010
  onAdmitted: (session) => {
@@ -23347,7 +23411,9 @@ var init_peer_office = __esm({
23347
23411
  * mirrors queue/backoff state.
23348
23412
  */
23349
23413
  drive() {
23350
- return this.#maintenance.drive();
23414
+ if (this.#subscriptions.drainOwedTurn()) return 0n;
23415
+ const wake = this.#maintenance.drive();
23416
+ return this.#subscriptions.owesRefresh ? 0n : wake;
23351
23417
  }
23352
23418
  /**
23353
23419
  * Carry one exact maintenance demand through a durable host continuation.
@@ -24308,6 +24374,7 @@ var init_peer_office = __esm({
24308
24374
  };
24309
24375
  peerOffice = {
24310
24376
  open(kernel, credentials, profile, observations, custodyStorage, peerDeskStore) {
24377
+ assertShellContract();
24311
24378
  return new PeerOffice(kernel, credentials, profile, observations, custodyStorage, peerDeskStore);
24312
24379
  },
24313
24380
  Peer: PeerOffice
@@ -4954,6 +4954,31 @@ var KernelPort = class {
4954
4954
  // ../peer-office/src/runtime/placement_desk.ts
4955
4955
  import { create as create14 } from "@bufbuild/protobuf";
4956
4956
 
4957
+ // ../peer-office/src/runtime/http_origin.ts
4958
+ var AUTHORITY = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)/i;
4959
+ var DEFAULT_PORTS = { http: "80", https: "443" };
4960
+ function httpOrigin(url) {
4961
+ const match = AUTHORITY.exec(url.trim());
4962
+ if (!match) return void 0;
4963
+ const scheme = match[1].toLowerCase();
4964
+ if (scheme !== "http" && scheme !== "https") return void 0;
4965
+ const authority = match[2];
4966
+ const hostAndPort = authority.slice(authority.lastIndexOf("@") + 1);
4967
+ const ipv6 = /^(\[[0-9a-f:.]+\])(?::(\d*))?$/i.exec(hostAndPort);
4968
+ const named = /^([^:[\]\s]+)(?::(\d*))?$/.exec(hostAndPort);
4969
+ const parts = ipv6 ?? named;
4970
+ if (!parts) return void 0;
4971
+ const host = parts[1].toLowerCase();
4972
+ if (host.length === 0 || /[\s<>^`{|}%\\]/.test(host)) return void 0;
4973
+ let port = parts[2] ?? "";
4974
+ if (port !== "") {
4975
+ const value = Number(port);
4976
+ if (!Number.isInteger(value) || value > 65535) return void 0;
4977
+ port = String(value);
4978
+ }
4979
+ return port === "" || port === DEFAULT_PORTS[scheme] ? `${scheme}://${host}` : `${scheme}://${host}:${port}`;
4980
+ }
4981
+
4957
4982
  // ../peer-office/src/runtime/provider_origins.ts
4958
4983
  import { create as create13 } from "@bufbuild/protobuf";
4959
4984
  import { fromBinary as fromBinary10 } from "@bufbuild/protobuf";
@@ -5292,14 +5317,7 @@ var normalizeProfile = (profile) => {
5292
5317
  ...servedOrigin === void 0 ? {} : { servedOrigin }
5293
5318
  });
5294
5319
  };
5295
- var originOf2 = (url) => {
5296
- try {
5297
- const parsed = new URL(url);
5298
- return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.origin : void 0;
5299
- } catch {
5300
- return void 0;
5301
- }
5302
- };
5320
+ var originOf2 = httpOrigin;
5303
5321
  var ReplicaPlacementDirectiveKind = Object.freeze({
5304
5322
  None: "none",
5305
5323
  Cache: "cache",
@@ -11138,7 +11156,10 @@ var ReadMaintenanceDesk = class {
11138
11156
  ...background ? { background } : {},
11139
11157
  ...awaited || existing?.awaited ? { awaited: true } : {},
11140
11158
  failures: existing?.failures ?? 0,
11141
- retryNotBeforeNanoseconds: 0n
11159
+ // A foreground read may retry at once. Upkeep owed by a write or a sync keeps any back-off
11160
+ // it is already serving: otherwise every write retried a failing upkeep immediately, and a
11161
+ // workspace whose upkeep could not succeed retried on every write (CAP-693).
11162
+ retryNotBeforeNanoseconds: isReadDemand ? 0n : existing?.retryNotBeforeNanoseconds ?? 0n
11142
11163
  });
11143
11164
  if (isReadDemand && (!existing?.read || existing.read.owedByAdvance)) {
11144
11165
  const entries = [...this.#pending.entries()];
@@ -11746,18 +11767,17 @@ var SubscriptionManager = class {
11746
11767
  #requestReadMaintenance;
11747
11768
  #clock;
11748
11769
  #subscriptions = /* @__PURE__ */ new Map();
11749
- /** Watches owed a re-read, drained one query group per turn when a turn scheduler is given. */
11770
+ /** Watches owed a re-read, drained one query group per office turn (see [drainOwedTurn]). */
11750
11771
  #owed = /* @__PURE__ */ new Set();
11751
- #nextTurn;
11752
- #draining = false;
11772
+ #deferRefreshes;
11753
11773
  #sequence = 0n;
11754
- constructor(queries, sessions, events, requestReadMaintenance, clock, nextTurn) {
11774
+ constructor(queries, sessions, events, requestReadMaintenance, clock, deferRefreshes = false) {
11755
11775
  this.#queries = queries;
11756
11776
  this.#sessions = sessions;
11757
11777
  this.#events = events;
11758
11778
  this.#requestReadMaintenance = requestReadMaintenance;
11759
11779
  this.#clock = clock;
11760
- this.#nextTurn = nextTurn;
11780
+ this.#deferRefreshes = deferRefreshes;
11761
11781
  }
11762
11782
  start(request, command) {
11763
11783
  if (!command.subscriptionId) throw new Error("watch requires a subscription identity");
@@ -11863,34 +11883,33 @@ var SubscriptionManager = class {
11863
11883
  * or replace current authorization. Each watch still owns its delivery state.
11864
11884
  */
11865
11885
  #refreshMatching(matches, cause) {
11866
- if (this.#nextTurn && !cause) {
11886
+ if (this.#deferRefreshes && !cause) {
11867
11887
  for (const [id, subscription] of this.#subscriptions) {
11868
11888
  if (subscription.request.query && matches(subscription)) this.#owed.add(id);
11869
11889
  }
11870
- this.#drain();
11871
11890
  return;
11872
11891
  }
11873
11892
  this.#refreshGroups(this.#groups(matches), cause);
11874
11893
  }
11875
- #drain() {
11876
- if (this.#draining || this.#owed.size === 0) return;
11877
- this.#draining = true;
11878
- this.#nextTurn(() => {
11879
- this.#draining = false;
11880
- if (this.#owed.size === 0) return;
11881
- const first = this.#owed.values().next().value;
11882
- const lead = this.#subscriptions.get(first);
11883
- if (!lead?.request.query) {
11884
- this.#owed.delete(first);
11885
- } else {
11886
- const declaration = toBinary20(QueryRequestSchema, lead.request.query);
11887
- const session = lead.request.session;
11888
- const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary20(QueryRequestSchema, subscription.request.query), declaration));
11889
- for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
11890
- this.#refreshGroups(group);
11891
- }
11892
- this.#drain();
11893
- });
11894
+ /** Whether any watch is owed a re-read: the office's next drive() is due at once. */
11895
+ get owesRefresh() {
11896
+ return this.#owed.size > 0;
11897
+ }
11898
+ /** One office turn of owed re-reads: the first owed watch's query group. False when none was owed. */
11899
+ drainOwedTurn() {
11900
+ if (this.#owed.size === 0) return false;
11901
+ const first = this.#owed.values().next().value;
11902
+ const lead = this.#subscriptions.get(first);
11903
+ if (!lead?.request.query) {
11904
+ this.#owed.delete(first);
11905
+ return true;
11906
+ }
11907
+ const declaration = toBinary20(QueryRequestSchema, lead.request.query);
11908
+ const session = lead.request.session;
11909
+ const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary20(QueryRequestSchema, subscription.request.query), declaration));
11910
+ for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
11911
+ this.#refreshGroups(group);
11912
+ return true;
11894
11913
  }
11895
11914
  #groups(matches) {
11896
11915
  const groups = [];
@@ -12014,6 +12033,38 @@ function createSyntheticRequest(requestId) {
12014
12033
  });
12015
12034
  }
12016
12035
 
12036
+ // ../peer-office/src/runtime/shell_contract.ts
12037
+ var SHELL_CONTRACT_V1 = Object.freeze({
12038
+ version: 1,
12039
+ /** Host globals beyond ECMAScript 2022, which every shell supplies. */
12040
+ host: Object.freeze(["TextEncoder", "TextDecoder", "queueMicrotask", "console"]),
12041
+ /** Nomos bridges a native bootstrap installs for the ports it hands to peerOffice.open. */
12042
+ bridges: Object.freeze([
12043
+ "__nomosKernel",
12044
+ "__nomosCredentialVault",
12045
+ "__nomosProfile",
12046
+ "__nomosObservations",
12047
+ "__nomosCustodyStorage",
12048
+ "__nomosPeerDeskStore",
12049
+ "__nomosSyncDiagnostic",
12050
+ "__nomosShellContract"
12051
+ ]),
12052
+ /** Globals the runtime may only probe: used behind their own `typeof` test, never bare. */
12053
+ probed: Object.freeze(["process", "Deno", "Bun", "define"])
12054
+ });
12055
+ var SHELL_CONTRACT_V2 = Object.freeze({ ...SHELL_CONTRACT_V1, version: 2 });
12056
+ var SHELL_CONTRACT_MINIMUM = 1;
12057
+ function declaredShellContract(scope = globalThis) {
12058
+ const declared = scope.__nomosShellContract;
12059
+ return declared === void 0 ? 1 : Number(declared);
12060
+ }
12061
+ function assertShellContract(scope = globalThis) {
12062
+ const declared = declaredShellContract(scope);
12063
+ if (!Number.isInteger(declared) || declared < SHELL_CONTRACT_MINIMUM) {
12064
+ throw new Error(`nomos.runtime.shell_contract_unsupported: this runtime needs shell contract ${SHELL_CONTRACT_MINIMUM} or later; the shell declares ${String(declared)}`);
12065
+ }
12066
+ }
12067
+
12017
12068
  // ../peer-office/src/runtime/replica_follow_state.ts
12018
12069
  var ReplicaFollowPhase = Object.freeze({
12019
12070
  Desired: "desired",
@@ -19990,10 +20041,9 @@ var PeerOffice = class {
19990
20041
  this.#trace,
19991
20042
  (session) => this.#readMaintenance.schedule(session, ReadMaintenanceCause.READ_DEBT),
19992
20043
  observations,
19993
- // An interactive peer keeps its thread responsive while watches catch up.
19994
- this.#interactivePeer ? (run2) => {
19995
- setTimeout(run2, 0);
19996
- } : void 0
20044
+ // An interactive peer keeps its thread responsive while watches catch up: owed re-reads
20045
+ // wait for its drive() turns.
20046
+ this.#interactivePeer
19997
20047
  );
19998
20048
  this.#application = new ApplicationDesk({
19999
20049
  onAdmitted: (session) => {
@@ -20400,7 +20450,9 @@ var PeerOffice = class {
20400
20450
  * mirrors queue/backoff state.
20401
20451
  */
20402
20452
  drive() {
20403
- return this.#maintenance.drive();
20453
+ if (this.#subscriptions.drainOwedTurn()) return 0n;
20454
+ const wake = this.#maintenance.drive();
20455
+ return this.#subscriptions.owesRefresh ? 0n : wake;
20404
20456
  }
20405
20457
  /**
20406
20458
  * Carry one exact maintenance demand through a durable host continuation.
@@ -21361,6 +21413,7 @@ var PeerOffice = class {
21361
21413
  };
21362
21414
  var peerOffice = {
21363
21415
  open(kernel, credentials, profile, observations, custodyStorage, peerDeskStore) {
21416
+ assertShellContract();
21364
21417
  return new PeerOffice(kernel, credentials, profile, observations, custodyStorage, peerDeskStore);
21365
21418
  },
21366
21419
  Peer: PeerOffice
package/dist/full-cli.mjs CHANGED
@@ -12985,6 +12985,37 @@ var init_kernel_port = __esm({
12985
12985
  }
12986
12986
  });
12987
12987
 
12988
+ // ../peer-office/src/runtime/http_origin.ts
12989
+ function httpOrigin(url) {
12990
+ const match = AUTHORITY.exec(url.trim());
12991
+ if (!match) return void 0;
12992
+ const scheme = match[1].toLowerCase();
12993
+ if (scheme !== "http" && scheme !== "https") return void 0;
12994
+ const authority = match[2];
12995
+ const hostAndPort = authority.slice(authority.lastIndexOf("@") + 1);
12996
+ const ipv6 = /^(\[[0-9a-f:.]+\])(?::(\d*))?$/i.exec(hostAndPort);
12997
+ const named = /^([^:[\]\s]+)(?::(\d*))?$/.exec(hostAndPort);
12998
+ const parts = ipv6 ?? named;
12999
+ if (!parts) return void 0;
13000
+ const host2 = parts[1].toLowerCase();
13001
+ if (host2.length === 0 || /[\s<>^`{|}%\\]/.test(host2)) return void 0;
13002
+ let port = parts[2] ?? "";
13003
+ if (port !== "") {
13004
+ const value = Number(port);
13005
+ if (!Number.isInteger(value) || value > 65535) return void 0;
13006
+ port = String(value);
13007
+ }
13008
+ return port === "" || port === DEFAULT_PORTS[scheme] ? `${scheme}://${host2}` : `${scheme}://${host2}:${port}`;
13009
+ }
13010
+ var AUTHORITY, DEFAULT_PORTS;
13011
+ var init_http_origin = __esm({
13012
+ "../peer-office/src/runtime/http_origin.ts"() {
13013
+ "use strict";
13014
+ AUTHORITY = /^([a-z][a-z0-9+.-]*):\/\/([^/?#]*)/i;
13015
+ DEFAULT_PORTS = { http: "80", https: "443" };
13016
+ }
13017
+ });
13018
+
12988
13019
  // ../peer-office/src/git_read_lease.ts
12989
13020
  import { fromBinary as fromBinary5 } from "@bufbuild/protobuf";
12990
13021
  function decodeGitReadLease(bytes, workspace, nowUnixSeconds = BigInt(Math.floor(Date.now() / 1e3))) {
@@ -13336,6 +13367,7 @@ var stableIdentifier, normalizeProfile, originOf2, ReplicaPlacementDirectiveKind
13336
13367
  var init_placement_desk = __esm({
13337
13368
  "../peer-office/src/runtime/placement_desk.ts"() {
13338
13369
  "use strict";
13370
+ init_http_origin();
13339
13371
  init_provider_origins();
13340
13372
  init_kernel_pb();
13341
13373
  init_placement_desk_pb();
@@ -13360,14 +13392,7 @@ var init_placement_desk = __esm({
13360
13392
  ...servedOrigin === void 0 ? {} : { servedOrigin }
13361
13393
  });
13362
13394
  };
13363
- originOf2 = (url) => {
13364
- try {
13365
- const parsed = new URL(url);
13366
- return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.origin : void 0;
13367
- } catch {
13368
- return void 0;
13369
- }
13370
- };
13395
+ originOf2 = httpOrigin;
13371
13396
  ReplicaPlacementDirectiveKind = Object.freeze({
13372
13397
  None: "none",
13373
13398
  Cache: "cache",
@@ -19534,7 +19559,10 @@ var init_read_maintenance_desk = __esm({
19534
19559
  ...background ? { background } : {},
19535
19560
  ...awaited || existing?.awaited ? { awaited: true } : {},
19536
19561
  failures: existing?.failures ?? 0,
19537
- retryNotBeforeNanoseconds: 0n
19562
+ // A foreground read may retry at once. Upkeep owed by a write or a sync keeps any back-off
19563
+ // it is already serving: otherwise every write retried a failing upkeep immediately, and a
19564
+ // workspace whose upkeep could not succeed retried on every write (CAP-693).
19565
+ retryNotBeforeNanoseconds: isReadDemand ? 0n : existing?.retryNotBeforeNanoseconds ?? 0n
19538
19566
  });
19539
19567
  if (isReadDemand && (!existing?.read || existing.read.owedByAdvance)) {
19540
19568
  const entries = [...this.#pending.entries()];
@@ -20183,18 +20211,17 @@ var init_subscription_manager = __esm({
20183
20211
  #requestReadMaintenance;
20184
20212
  #clock;
20185
20213
  #subscriptions = /* @__PURE__ */ new Map();
20186
- /** Watches owed a re-read, drained one query group per turn when a turn scheduler is given. */
20214
+ /** Watches owed a re-read, drained one query group per office turn (see [drainOwedTurn]). */
20187
20215
  #owed = /* @__PURE__ */ new Set();
20188
- #nextTurn;
20189
- #draining = false;
20216
+ #deferRefreshes;
20190
20217
  #sequence = 0n;
20191
- constructor(queries, sessions, events, requestReadMaintenance, clock, nextTurn) {
20218
+ constructor(queries, sessions, events, requestReadMaintenance, clock, deferRefreshes = false) {
20192
20219
  this.#queries = queries;
20193
20220
  this.#sessions = sessions;
20194
20221
  this.#events = events;
20195
20222
  this.#requestReadMaintenance = requestReadMaintenance;
20196
20223
  this.#clock = clock;
20197
- this.#nextTurn = nextTurn;
20224
+ this.#deferRefreshes = deferRefreshes;
20198
20225
  }
20199
20226
  start(request, command) {
20200
20227
  if (!command.subscriptionId) throw new Error("watch requires a subscription identity");
@@ -20300,34 +20327,33 @@ var init_subscription_manager = __esm({
20300
20327
  * or replace current authorization. Each watch still owns its delivery state.
20301
20328
  */
20302
20329
  #refreshMatching(matches, cause) {
20303
- if (this.#nextTurn && !cause) {
20330
+ if (this.#deferRefreshes && !cause) {
20304
20331
  for (const [id, subscription] of this.#subscriptions) {
20305
20332
  if (subscription.request.query && matches(subscription)) this.#owed.add(id);
20306
20333
  }
20307
- this.#drain();
20308
20334
  return;
20309
20335
  }
20310
20336
  this.#refreshGroups(this.#groups(matches), cause);
20311
20337
  }
20312
- #drain() {
20313
- if (this.#draining || this.#owed.size === 0) return;
20314
- this.#draining = true;
20315
- this.#nextTurn(() => {
20316
- this.#draining = false;
20317
- if (this.#owed.size === 0) return;
20318
- const first = this.#owed.values().next().value;
20319
- const lead = this.#subscriptions.get(first);
20320
- if (!lead?.request.query) {
20321
- this.#owed.delete(first);
20322
- } else {
20323
- const declaration = toBinary15(QueryRequestSchema, lead.request.query);
20324
- const session = lead.request.session;
20325
- const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary15(QueryRequestSchema, subscription.request.query), declaration));
20326
- for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
20327
- this.#refreshGroups(group);
20328
- }
20329
- this.#drain();
20330
- });
20338
+ /** Whether any watch is owed a re-read: the office's next drive() is due at once. */
20339
+ get owesRefresh() {
20340
+ return this.#owed.size > 0;
20341
+ }
20342
+ /** One office turn of owed re-reads: the first owed watch's query group. False when none was owed. */
20343
+ drainOwedTurn() {
20344
+ if (this.#owed.size === 0) return false;
20345
+ const first = this.#owed.values().next().value;
20346
+ const lead = this.#subscriptions.get(first);
20347
+ if (!lead?.request.query) {
20348
+ this.#owed.delete(first);
20349
+ return true;
20350
+ }
20351
+ const declaration = toBinary15(QueryRequestSchema, lead.request.query);
20352
+ const session = lead.request.session;
20353
+ const group = this.#groups((subscription) => subscription.request.session === session && this.#owed.has(subscription.request.subscriptionId) && sameBytes(toBinary15(QueryRequestSchema, subscription.request.query), declaration));
20354
+ for (const each of group) for (const watch of each.watches) this.#owed.delete(watch.request.subscriptionId);
20355
+ this.#refreshGroups(group);
20356
+ return true;
20331
20357
  }
20332
20358
  #groups(matches) {
20333
20359
  const groups = [];
@@ -20447,6 +20473,44 @@ var init_subscription_manager = __esm({
20447
20473
  }
20448
20474
  });
20449
20475
 
20476
+ // ../peer-office/src/runtime/shell_contract.ts
20477
+ function declaredShellContract(scope = globalThis) {
20478
+ const declared = scope.__nomosShellContract;
20479
+ return declared === void 0 ? 1 : Number(declared);
20480
+ }
20481
+ function assertShellContract(scope = globalThis) {
20482
+ const declared = declaredShellContract(scope);
20483
+ if (!Number.isInteger(declared) || declared < SHELL_CONTRACT_MINIMUM) {
20484
+ throw new Error(`nomos.runtime.shell_contract_unsupported: this runtime needs shell contract ${SHELL_CONTRACT_MINIMUM} or later; the shell declares ${String(declared)}`);
20485
+ }
20486
+ }
20487
+ var SHELL_CONTRACT_V1, SHELL_CONTRACT_V2, SHELL_CONTRACT_MINIMUM;
20488
+ var init_shell_contract = __esm({
20489
+ "../peer-office/src/runtime/shell_contract.ts"() {
20490
+ "use strict";
20491
+ SHELL_CONTRACT_V1 = Object.freeze({
20492
+ version: 1,
20493
+ /** Host globals beyond ECMAScript 2022, which every shell supplies. */
20494
+ host: Object.freeze(["TextEncoder", "TextDecoder", "queueMicrotask", "console"]),
20495
+ /** Nomos bridges a native bootstrap installs for the ports it hands to peerOffice.open. */
20496
+ bridges: Object.freeze([
20497
+ "__nomosKernel",
20498
+ "__nomosCredentialVault",
20499
+ "__nomosProfile",
20500
+ "__nomosObservations",
20501
+ "__nomosCustodyStorage",
20502
+ "__nomosPeerDeskStore",
20503
+ "__nomosSyncDiagnostic",
20504
+ "__nomosShellContract"
20505
+ ]),
20506
+ /** Globals the runtime may only probe: used behind their own `typeof` test, never bare. */
20507
+ probed: Object.freeze(["process", "Deno", "Bun", "define"])
20508
+ });
20509
+ SHELL_CONTRACT_V2 = Object.freeze({ ...SHELL_CONTRACT_V1, version: 2 });
20510
+ SHELL_CONTRACT_MINIMUM = 1;
20511
+ }
20512
+ });
20513
+
20450
20514
  // ../peer-office/src/runtime/replica_follow_state.ts
20451
20515
  function reduceReplicaFollow(state, event, policy) {
20452
20516
  switch (event.case) {
@@ -28676,6 +28740,7 @@ var init_peer_office = __esm({
28676
28740
  init_residency_pins();
28677
28741
  init_maintenance_desk_pb();
28678
28742
  init_subscription_manager();
28743
+ init_shell_contract();
28679
28744
  init_replica_follow_controller();
28680
28745
  init_replica_follow_desk();
28681
28746
  init_local_copy_drop();
@@ -28872,10 +28937,9 @@ var init_peer_office = __esm({
28872
28937
  this.#trace,
28873
28938
  (session) => this.#readMaintenance.schedule(session, ReadMaintenanceCause.READ_DEBT),
28874
28939
  observations,
28875
- // An interactive peer keeps its thread responsive while watches catch up.
28876
- this.#interactivePeer ? (run2) => {
28877
- setTimeout(run2, 0);
28878
- } : void 0
28940
+ // An interactive peer keeps its thread responsive while watches catch up: owed re-reads
28941
+ // wait for its drive() turns.
28942
+ this.#interactivePeer
28879
28943
  );
28880
28944
  this.#application = new ApplicationDesk({
28881
28945
  onAdmitted: (session) => {
@@ -29282,7 +29346,9 @@ var init_peer_office = __esm({
29282
29346
  * mirrors queue/backoff state.
29283
29347
  */
29284
29348
  drive() {
29285
- return this.#maintenance.drive();
29349
+ if (this.#subscriptions.drainOwedTurn()) return 0n;
29350
+ const wake = this.#maintenance.drive();
29351
+ return this.#subscriptions.owesRefresh ? 0n : wake;
29286
29352
  }
29287
29353
  /**
29288
29354
  * Carry one exact maintenance demand through a durable host continuation.
@@ -30243,6 +30309,7 @@ var init_peer_office = __esm({
30243
30309
  };
30244
30310
  peerOffice = {
30245
30311
  open(kernel, credentials, profile, observations, custodyStorage, peerDeskStore) {
30312
+ assertShellContract();
30246
30313
  return new PeerOffice(kernel, credentials, profile, observations, custodyStorage, peerDeskStore);
30247
30314
  },
30248
30315
  Peer: PeerOffice
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.113.2",
3
+ "version": "0.113.3",
4
4
  "type": "module",
5
5
  "description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -30,7 +30,7 @@
30
30
  "dependencies": {
31
31
  "@bjorn3/browser_wasi_shim": "0.4.2",
32
32
  "@bufbuild/protobuf": "^2.13.0",
33
- "@githolon/dsl": "^0.113.2",
33
+ "@githolon/dsl": "^0.113.3",
34
34
  "fast-xml-parser": "5.10.1",
35
35
  "isomorphic-git": "^1.38.4",
36
36
  "tsx": "^4.19.2",