@aria-cli/server 1.0.19
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/README.md +17 -0
- package/dist/.aria-build-stamp.json +4 -0
- package/dist/auth/api-key.d.ts +106 -0
- package/dist/config.d.ts +28 -0
- package/dist/daemon-launcher.d.ts +23 -0
- package/dist/daemon-launcher.js +3 -0
- package/dist/index-5tav2m70.js +3 -0
- package/dist/index-6extw9n6.js +2 -0
- package/dist/index-9n50yafd.js +3 -0
- package/dist/index-9xs3gn0p.js +2 -0
- package/dist/index-ghh3ag4c.js +548 -0
- package/dist/index-mnt9k223.js +15 -0
- package/dist/index-pe0pkp0v.js +2 -0
- package/dist/index-raeajnr7.js +2 -0
- package/dist/index-rr0sea4c.js +2 -0
- package/dist/index-zge0mhc0.js +3 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -0
- package/dist/peer-principal-auth.d.ts +37 -0
- package/dist/routes/arions.d.ts +34 -0
- package/dist/routes/council.d.ts +15 -0
- package/dist/routes/entrypoint-errors.d.ts +7 -0
- package/dist/routes/health.d.ts +6 -0
- package/dist/routes/invite-relay.d.ts +2 -0
- package/dist/routes/local-control.d.ts +3 -0
- package/dist/routes/message.d.ts +17 -0
- package/dist/routes/network.d.ts +14 -0
- package/dist/routes/pair.d.ts +57 -0
- package/dist/routes/pair.js +1 -0
- package/dist/routes/pipeline-mailbox.d.ts +10 -0
- package/dist/routes/relay.d.ts +29 -0
- package/dist/routes/resume.d.ts +2 -0
- package/dist/routes/run-control-surface.d.ts +24 -0
- package/dist/routes/run.d.ts +6 -0
- package/dist/routes/runtime-bootstrap.d.ts +3 -0
- package/dist/routes/runtime-node-advertisement.d.ts +3 -0
- package/dist/routes/runtime-run-room.d.ts +8 -0
- package/dist/routes/shared.d.ts +45 -0
- package/dist/routes/stream.d.ts +10 -0
- package/dist/routes/validation.d.ts +7 -0
- package/dist/routes/ws-revocation.d.ts +25 -0
- package/dist/runtime/attached-sender-inbox.d.ts +3 -0
- package/dist/runtime/authoritative-peer-endpoint.d.ts +27 -0
- package/dist/runtime/continuity-bind-suspicion.d.ts +39 -0
- package/dist/runtime/continuity-verification.d.ts +54 -0
- package/dist/runtime/decorate-runtime-surface.d.ts +2 -0
- package/dist/runtime/durable-network-store-surface.d.ts +51 -0
- package/dist/runtime/error-diagnostic.d.ts +12 -0
- package/dist/runtime/headless-dispatch-handler.d.ts +30 -0
- package/dist/runtime/host-supervisor.d.ts +109 -0
- package/dist/runtime/host-supervisor.js +1 -0
- package/dist/runtime/join-control.d.ts +3 -0
- package/dist/runtime/local-control-api.d.ts +63 -0
- package/dist/runtime/local-control-api.js +1 -0
- package/dist/runtime/local-control-pairing.d.ts +12 -0
- package/dist/runtime/local-control-socket.d.ts +48 -0
- package/dist/runtime/log-file-sink.d.ts +21 -0
- package/dist/runtime/network-read-control.d.ts +17 -0
- package/dist/runtime/network-state-stores.d.ts +2 -0
- package/dist/runtime/node-metadata.d.ts +22 -0
- package/dist/runtime/node-metadata.js +1 -0
- package/dist/runtime/node-runtime.d.ts +157 -0
- package/dist/runtime/node-store-revocation-store.d.ts +42 -0
- package/dist/runtime/node-store.d.ts +184 -0
- package/dist/runtime/node-store.js +1 -0
- package/dist/runtime/pinned-control-session.d.ts +41 -0
- package/dist/runtime/principal-binding-authority.d.ts +173 -0
- package/dist/runtime/reachable-control-host.d.ts +5 -0
- package/dist/runtime/runtime-admin-api.d.ts +16 -0
- package/dist/runtime/runtime-authority-registry.d.ts +55 -0
- package/dist/runtime/runtime-autonomous-loop.d.ts +40 -0
- package/dist/runtime/runtime-bootstrap-authority.d.ts +5 -0
- package/dist/runtime/runtime-bootstrap-record.d.ts +21 -0
- package/dist/runtime/runtime-event-journal.d.ts +21 -0
- package/dist/runtime/runtime-outbox.d.ts +35 -0
- package/dist/runtime/runtime-registry.d.ts +33 -0
- package/dist/runtime/runtime-registry.js +1 -0
- package/dist/runtime/runtime-run-control.d.ts +71 -0
- package/dist/runtime/stale-owner-error.d.ts +13 -0
- package/dist/runtime-run-control-0r21xdh5.js +2 -0
- package/dist/server.d.ts +84 -0
- package/dist/session-history-messages.d.ts +3 -0
- package/dist/session-history.d.ts +28 -0
- package/dist/shared-4jsvhy6g.js +1 -0
- package/dist/types.d.ts +299 -0
- package/dist/utils/rate-limiter.d.ts +25 -0
- package/dist/utils/sanitize-error.d.ts +10 -0
- package/package.json +82 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import{Aa as rr}from"./index-9xs3gn0p.js";import{randomUUID as V}from"node:crypto";import*as A from"node:fs";import*as $ from"node:path";import er from"better-sqlite3";import{canonicalizeAuthoritativeDirectEndpoint as R,canonicalizeOutboxReceiptStatus as tr,NodeIdSchema as G,NodeMetadataSchema as f,LoopbackTlsIdentitySchema as ar,PeerTransportIdSchema as g,PrincipalFingerprintSchema as hr,RevocationOperatorConfirmationSchema as wr,RuntimeBootstrapRecordSchema as i,RuntimeEventSchema as dr,RuntimeOwnerRecordSchema as p,RuntimeIdSchema as z,TlsCaFingerprintSchema as Er}from"@aria-cli/tools/network-runtime";class k extends Error{kind="StaleOwnerError";claimedGeneration;currentGeneration;constructor(r,e){super(`StaleOwnerError: runtime claims generation ${r} but store is at generation ${e}. This runtime has been superseded and must shut down immediately.`);this.name="StaleOwnerError",this.claimedGeneration=r,this.currentGeneration=e}}var X=1,C=["queued_for_route","dispatching","acked","expired"],j=C.map((r)=>`'${r}'`).join(", ");function Sr(r,e){return r.nodeId===e.nodeId&&r.principalFingerprint===e.principalFingerprint&&r.transportPublicKey===e.transportPublicKey&&r.continuityRevision===e.continuityRevision&&(r.endpointHost??void 0)===(e.endpointHost??void 0)&&(r.endpointPort??void 0)===(e.endpointPort??void 0)&&(r.endpointRevision??0)===(e.endpointRevision??0)&&(r.displayNameSnapshot??void 0)===(e.displayNameSnapshot??void 0)&&(r.controlEndpointHost??void 0)===(e.controlEndpointHost??void 0)&&(r.controlEndpointPort??void 0)===(e.controlEndpointPort??void 0)&&(r.controlTlsCaFingerprint??void 0)===(e.controlTlsCaFingerprint??void 0)}function Y(r){return G.parse(r)}function O(r){return r}function x(r){return hr.parse(r)}function F(r){let e=Er.safeParse(r);if(!e.success)throw Error(`[node-store] Invalid TLS CA fingerprint: ${r.slice(0,20)}`);return e.data}function T(r){return r}function br(r){return wr.parse(r)}function Or(r,e){return r.nodeId===e.nodeId&&(r.displayNameSnapshot??void 0)===(e.displayNameSnapshot??void 0)&&r.fingerprint===e.fingerprint&&r.revokedAt===e.revokedAt&&r.revokedBy===e.revokedBy&&r.operatorConfirmation===e.operatorConfirmation&&(r.reason??void 0)===(e.reason??void 0)&&r.revocationGeneration===e.revocationGeneration}function sr(r,e){return r.nodeId===e.nodeId&&r.runtimeId===e.runtimeId&&(r.arionName??void 0)===(e.arionName??void 0)&&r.ownerGeneration===e.ownerGeneration&&r.bootstrapRevision===e.bootstrapRevision&&r.phase===e.phase&&r.protocolVersion===e.protocolVersion&&r.controlEndpoint.host===e.controlEndpoint.host&&r.controlEndpoint.port===e.controlEndpoint.port&&r.tls.caFingerprint===e.tls.caFingerprint&&r.tls.caCertPem===e.tls.caCertPem&&r.tls.principalIdentity===e.tls.principalIdentity&&r.tls.loopbackIdentity===e.tls.loopbackIdentity&&(r.displayNameSnapshot??void 0)===(e.displayNameSnapshot??void 0)&&r.signingPublicKey===e.signingPublicKey&&r.transportPublicKey===e.transportPublicKey&&r.transportEndpoint.host===e.transportEndpoint.host&&r.transportEndpoint.port===e.transportEndpoint.port&&r.publishedAt===e.publishedAt&&(r.degradedReason??void 0)===(e.degradedReason??void 0)&&(r.failedPhase??void 0)===(e.failedPhase??void 0)}function D(r){let e=$.resolve(r);try{return A.realpathSync.native(e)}catch{return e}}function Gr(r){return $.join(D(r),"node","node-state.db")}function xr(r){return C.every((e)=>r.includes(`'${e}'`))}function Tr(r){A.mkdirSync($.dirname(r),{recursive:!0,mode:448})}function $r(r,e){if(!r)return null;let a=f.safeParse({nodeId:r.node_id,createdAt:r.created_at,schemaVersion:r.schema_version,migratedFromLegacy:r.migrated_from_legacy===1});if(!a.success)throw Error(`[node-store] Invalid node metadata in ${e}: ${a.error.issues.map((t)=>t.message).join(", ")}`);return a.data}function kr(r,e){if(!r)return null;let a=p.safeParse({schemaVersion:r.schema_version,nodeId:r.node_id,ariaHome:r.aria_home,runtimePid:r.runtime_pid,runtimeId:r.runtime_id,displayNameSnapshot:r.display_name_snapshot??void 0,runtimeSocket:r.runtime_socket,startedAt:r.started_at,lastHeartbeat:r.last_heartbeat,ownerGeneration:r.owner_generation});if(!a.success)throw Error(`[node-store] Invalid runtime owner record in ${e}: ${a.error.issues.map((t)=>t.message).join(", ")}`);return a.data}function Z(r){if(!r)return null;return{nodeId:Y(r.node_id),displayNameSnapshot:r.display_name_snapshot??void 0,fingerprint:x(r.fingerprint),revokedAt:r.revoked_at,revokedBy:Y(r.local_node_id),operatorConfirmation:br(r.operator_confirmation),reason:r.reason??void 0,revocationGeneration:r.revocation_generation}}function _(r,e){if(!r)return null;let a;try{a=JSON.parse(r.payload_json)}catch(w){throw Error(`[node-store] Invalid runtime event payload in ${e}: ${w instanceof Error?w.message:String(w)}`)}let t=dr.safeParse({eventId:r.event_id,nodeId:r.node_id,runtimeId:r.runtime_id,kind:r.kind,revision:r.revision,recordedAt:r.recorded_at,payload:a});if(!t.success)throw Error(`[node-store] Invalid runtime event in ${e}: ${t.error.issues.map((w)=>w.message).join(", ")}`);return t.data}function yr(r,e){if(!r)return null;if(!r.identity_json)return null;let a;try{a=JSON.parse(r.identity_json)}catch(w){throw Error(`[node-store] Invalid runtime bootstrap identity in ${e}: ${w instanceof Error?w.message:String(w)}`)}let t=i.safeParse({nodeId:r.node_id,runtimeId:r.runtime_id,ownerGeneration:r.owner_generation,bootstrapRevision:r.bootstrap_revision,phase:r.phase,protocolVersion:r.protocol_version,controlEndpoint:{host:r.control_endpoint_host,port:r.control_endpoint_port},tls:{caFingerprint:F(r.tls_ca_fingerprint),caCertPem:r.tls_ca_cert_pem,principalIdentity:x(r.tls_principal_identity),loopbackIdentity:ar.parse(r.tls_loopback_identity)},...a,publishedAt:r.published_at,degradedReason:r.degraded_reason??void 0,failedPhase:r.failed_phase??void 0});if(!t.success)throw Error(`[node-store] Invalid runtime bootstrap record in ${e}: ${t.error.issues.map((w)=>w.message).join(", ")}`);return t.data}function v(r){if(!r)return null;return{nodeId:G.parse(r.node_id),principalFingerprint:x(r.principal_fingerprint),transportPublicKey:g.parse(r.transport_public_key),continuityRevision:r.continuity_revision,endpointHost:r.endpoint_host??void 0,endpointPort:r.endpoint_port??void 0,endpointRevision:r.endpoint_revision,displayNameSnapshot:r.display_name_snapshot??void 0,controlEndpointHost:r.control_endpoint_host??void 0,controlEndpointPort:r.control_endpoint_port??void 0,controlTlsCaFingerprint:r.control_tls_ca_fingerprint?F(r.control_tls_ca_fingerprint):void 0,updatedAt:r.updated_at}}function I(r){let e=G.safeParse(r.nodeId);if(!e.success)throw Error("Peer binding requires a valid nodeId");let a=Object.prototype.hasOwnProperty.call(r,"endpointHost")||Object.prototype.hasOwnProperty.call(r,"endpointPort"),t=R({endpointHost:r.endpointHost,endpointPort:r.endpointPort});return{...r,nodeId:e.data,principalFingerprint:x(r.principalFingerprint),transportPublicKey:g.parse(r.transportPublicKey),endpointHost:t.endpointHost,endpointPort:t.endpointPort,endpointRevision:typeof r.endpointRevision==="number"&&Number.isInteger(r.endpointRevision)?r.endpointRevision:0,controlTlsCaFingerprint:r.controlTlsCaFingerprint?F(r.controlTlsCaFingerprint):void 0,updatedAt:r.updatedAt??new Date().toISOString(),endpointProjectionSpecified:a}}function K(r,e){let{endpointProjectionSpecified:a,endpointHost:t,endpointPort:w,endpointRevision:S,...d}=e;if(!r)return{...d,endpointHost:t,endpointPort:w,endpointRevision:t!==void 0||w!==void 0?S:0};if(a)return{...d,endpointHost:t,endpointPort:w,endpointRevision:t!==void 0||w!==void 0?S:0,displayNameSnapshot:d.displayNameSnapshot??r.displayNameSnapshot,controlEndpointHost:d.controlEndpointHost??r.controlEndpointHost,controlEndpointPort:d.controlEndpointPort??r.controlEndpointPort,controlTlsCaFingerprint:d.controlTlsCaFingerprint??r.controlTlsCaFingerprint};return{...d,endpointHost:t??r.endpointHost,endpointPort:w??r.endpointPort,endpointRevision:t!==void 0||w!==void 0?S:r.endpointRevision,displayNameSnapshot:d.displayNameSnapshot??r.displayNameSnapshot,controlEndpointHost:d.controlEndpointHost??r.controlEndpointHost,controlEndpointPort:d.controlEndpointPort??r.controlEndpointPort,controlTlsCaFingerprint:d.controlTlsCaFingerprint??r.controlTlsCaFingerprint}}function Ar(r,e){return r.nodeId===e.nodeId&&r.principalFingerprint===e.principalFingerprint&&r.transportPublicKey===e.transportPublicKey&&r.continuityRevision===e.continuityRevision}function P(r,e){if(!Ar(r,e))return"conflict";let a=r.endpointRevision??0,t=e.endpointRevision??0;if(t<a)return"stale";let w=(r.endpointHost??void 0)!==(e.endpointHost??void 0)||(r.endpointPort??void 0)!==(e.endpointPort??void 0),S=typeof r.endpointHost!=="string"||typeof r.endpointPort!=="number",d=(r.controlEndpointHost??void 0)!==(e.controlEndpointHost??void 0)||(r.controlEndpointPort??void 0)!==(e.controlEndpointPort??void 0)||(r.controlTlsCaFingerprint??void 0)!==(e.controlTlsCaFingerprint??void 0),E=typeof r.controlEndpointHost!=="string"||typeof r.controlEndpointPort!=="number"||typeof r.controlTlsCaFingerprint!=="string",b=(r.displayNameSnapshot??void 0)!==(e.displayNameSnapshot??void 0);if(t===a){if(b)return"conflict";if(w&&!S)return"conflict";if(d&&!E)return"conflict"}return Sr(r,e)?"idempotent":"refresh"}function y(r){return r instanceof Error&&(r.message.includes("idx_peer_binding_direct_endpoint")||r.message.includes("peer_binding.endpoint_host")&&r.message.includes("peer_binding.endpoint_port"))}function q(r,e,a){if(r.prepare(`DELETE FROM revocation_events
|
|
2
|
+
WHERE node_id = ?
|
|
3
|
+
AND revocation_generation = ?`).run(e,a).changes===1)return;throw Error(`Continuity proposal could not clear revoked principal binding for ${e}`)}function Mr(r){if(!r)return null;return{messageId:r.message_id,senderNodeId:G.parse(r.sender_node_id),senderFingerprint:x(r.sender_fingerprint),runtimeId:z.parse(r.runtime_id),receivedAt:r.received_at}}function Nr(r){if(!r)return null;let e=tr(r.status);return{messageId:r.message_id,senderNodeId:G.parse(r.sender_node_id),recipientNodeId:G.parse(r.recipient_node_id),transport:r.transport,status:e,deliveryLifecycleRevision:r.delivery_lifecycle_revision,updatedAt:r.updated_at}}function Ur(r){if(!r)return null;return{conflictId:r.conflict_id,nodeId:G.parse(r.node_id),previousFingerprint:r.previous_fingerprint?x(r.previous_fingerprint):void 0,conflictingFingerprint:x(r.conflicting_fingerprint),reason:r.reason,recordedAt:r.recorded_at}}class Vr{ariaHome;dbPath;db;ownerGeneration;constructor(r){this.ariaHome=D(r.ariaHome),this.dbPath=Gr(this.ariaHome),Tr(this.dbPath);try{this.db=new er(this.dbPath)}catch(e){throw Error(`[node-store] Failed to open NodeStore at ${this.dbPath}: ${e instanceof Error?e.message:String(e)}`)}try{this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.pragma("busy_timeout = 5000"),this.ensureSchema()}catch(e){throw this.db.close(),Error(`[node-store] Failed to initialize NodeStore at ${this.dbPath}: ${e instanceof Error?e.message:String(e)}`)}if(this.ownerGeneration=r.ownerGeneration,this.ownerGeneration!==void 0)this.claimEpoch(this.ownerGeneration)}claimEpoch(r){if(this.db.prepare(`INSERT INTO owner_epoch (scope, owner_generation) VALUES ('runtime', ?)
|
|
4
|
+
ON CONFLICT(scope) DO UPDATE SET owner_generation = excluded.owner_generation
|
|
5
|
+
WHERE excluded.owner_generation > owner_epoch.owner_generation`).run(r).changes===0){let t=this.db.prepare("SELECT owner_generation FROM owner_epoch WHERE scope = 'runtime'").get()?.owner_generation??0;if(t>r)throw new k(r,t)}}assertOwnership(){if(this.ownerGeneration===void 0)throw Error("[node-store] Cannot perform durable writes on an unfenced NodeStore. Provide ownerGeneration at construction time.");let e=this.db.prepare("SELECT owner_generation FROM owner_epoch WHERE scope = 'runtime'").get()?.owner_generation??0;if(e>this.ownerGeneration)throw new k(this.ownerGeneration,e)}close(){this.db.close()}readNodeMetadata(){let r=this.db.prepare(`SELECT node_id, created_at, schema_version, migrated_from_legacy
|
|
6
|
+
FROM node_metadata
|
|
7
|
+
WHERE singleton_key = 'node'
|
|
8
|
+
LIMIT 1`).get();return $r(r,this.dbPath)}writeNodeMetadata(r){let e=f.parse(r);return this.db.prepare(`INSERT INTO node_metadata
|
|
9
|
+
(singleton_key, node_id, created_at, schema_version, migrated_from_legacy)
|
|
10
|
+
VALUES ('node', ?, ?, ?, ?)
|
|
11
|
+
ON CONFLICT(singleton_key) DO UPDATE SET
|
|
12
|
+
node_id = excluded.node_id,
|
|
13
|
+
created_at = excluded.created_at,
|
|
14
|
+
schema_version = excluded.schema_version,
|
|
15
|
+
migrated_from_legacy = excluded.migrated_from_legacy`).run(e.nodeId,e.createdAt,e.schemaVersion,e.migratedFromLegacy?1:0),e}readRuntimeOwnerRecord(r){let e=this.db.prepare(`SELECT
|
|
16
|
+
schema_version,
|
|
17
|
+
node_id,
|
|
18
|
+
aria_home,
|
|
19
|
+
runtime_pid,
|
|
20
|
+
runtime_id,
|
|
21
|
+
display_name_snapshot,
|
|
22
|
+
runtime_socket,
|
|
23
|
+
started_at,
|
|
24
|
+
last_heartbeat,
|
|
25
|
+
owner_generation
|
|
26
|
+
FROM runtime_owner_records
|
|
27
|
+
WHERE node_id = ?
|
|
28
|
+
LIMIT 1`).get(r);return kr(e,this.dbPath)}readRuntimeBootstrapRecord(r){let e=this.db.prepare(`SELECT
|
|
29
|
+
node_id,
|
|
30
|
+
runtime_id,
|
|
31
|
+
owner_generation,
|
|
32
|
+
bootstrap_revision,
|
|
33
|
+
phase,
|
|
34
|
+
protocol_version,
|
|
35
|
+
control_endpoint_host,
|
|
36
|
+
control_endpoint_port,
|
|
37
|
+
tls_ca_fingerprint,
|
|
38
|
+
tls_ca_cert_pem,
|
|
39
|
+
tls_principal_identity,
|
|
40
|
+
tls_loopback_identity,
|
|
41
|
+
identity_json,
|
|
42
|
+
published_at,
|
|
43
|
+
degraded_reason,
|
|
44
|
+
failed_phase
|
|
45
|
+
FROM runtime_bootstrap_records
|
|
46
|
+
WHERE node_id = ?
|
|
47
|
+
LIMIT 1`).get(r);return yr(e,this.dbPath)}writeRuntimeOwnerRecord(r){this.assertOwnership();let e=p.parse({...r,ariaHome:D(r.ariaHome)}),a=this.readRuntimeOwnerRecord(e.nodeId);if(a){if(a.ownerGeneration>e.ownerGeneration)return a;if(a.ownerGeneration===e.ownerGeneration){if(!(a.runtimeId===e.runtimeId&&a.runtimePid===e.runtimePid&&a.runtimeSocket===e.runtimeSocket&&a.startedAt===e.startedAt&&a.ariaHome===e.ariaHome))return a;if(a.lastHeartbeat.localeCompare(e.lastHeartbeat)>0)return a}}return this.db.prepare(`INSERT INTO runtime_owner_records
|
|
48
|
+
(
|
|
49
|
+
node_id,
|
|
50
|
+
schema_version,
|
|
51
|
+
aria_home,
|
|
52
|
+
runtime_pid,
|
|
53
|
+
runtime_id,
|
|
54
|
+
display_name_snapshot,
|
|
55
|
+
runtime_socket,
|
|
56
|
+
started_at,
|
|
57
|
+
last_heartbeat,
|
|
58
|
+
owner_generation
|
|
59
|
+
)
|
|
60
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
61
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
62
|
+
schema_version = excluded.schema_version,
|
|
63
|
+
aria_home = excluded.aria_home,
|
|
64
|
+
runtime_pid = excluded.runtime_pid,
|
|
65
|
+
runtime_id = excluded.runtime_id,
|
|
66
|
+
display_name_snapshot = excluded.display_name_snapshot,
|
|
67
|
+
runtime_socket = excluded.runtime_socket,
|
|
68
|
+
started_at = excluded.started_at,
|
|
69
|
+
last_heartbeat = excluded.last_heartbeat,
|
|
70
|
+
owner_generation = excluded.owner_generation`).run(e.nodeId,e.schemaVersion,e.ariaHome,e.runtimePid,e.runtimeId,e.displayNameSnapshot??null,e.runtimeSocket,e.startedAt,e.lastHeartbeat,e.ownerGeneration),e}writeRuntimeBootstrapRecord(r){return this.commitRuntimeBootstrapRecord(r)}removeRuntimeOwnerRecord(r){this.assertOwnership(),this.db.prepare("DELETE FROM runtime_owner_records WHERE node_id = ?").run(r)}clearRuntimeOwnerRecords(){return this.assertOwnership(),this.db.prepare("DELETE FROM runtime_owner_records").run().changes}clearRuntimeBootstrapRecords(){return this.assertOwnership(),this.db.prepare("DELETE FROM runtime_bootstrap_records").run().changes}resolveOrCreateNode(){let r=this.readNodeMetadata();if(r)return r;let e={nodeId:G.parse(V()),createdAt:new Date().toISOString(),schemaVersion:X,migratedFromLegacy:!1};return this.writeNodeMetadata(e)}appendRuntimeEvent(r){this.assertOwnership();let e=r.eventId??`evt-${V()}`,a=r.recordedAt??new Date().toISOString(),t=r.payload??{};this.db.prepare(`INSERT INTO runtime_events
|
|
71
|
+
(event_id, node_id, runtime_id, kind, recorded_at, payload_json, owner_generation)
|
|
72
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(e,r.nodeId,r.runtimeId,r.kind,a,JSON.stringify(t),this.ownerGeneration??0);let w=this.db.prepare(`SELECT event_id, node_id, runtime_id, kind, revision, recorded_at, payload_json
|
|
73
|
+
FROM runtime_events
|
|
74
|
+
WHERE event_id = ?
|
|
75
|
+
LIMIT 1`).get(e),S=_(w,this.dbPath);if(!S)throw Error(`[node-store] Failed to read back runtime event ${e}`);return S}listRuntimeEvents(){return this.db.prepare(`SELECT event_id, node_id, runtime_id, kind, revision, recorded_at, payload_json
|
|
76
|
+
FROM runtime_events
|
|
77
|
+
ORDER BY revision ASC`).all().map((e)=>{let a=_(e,this.dbPath);if(!a)throw Error("[node-store] Runtime event list contained an empty row");return a})}clearRuntimeEvents(){return this.assertOwnership(),this.db.prepare("DELETE FROM runtime_events").run().changes}commitRuntimeBootstrapRecord(r){this.assertOwnership();let e=i.parse(r),a=this.readRuntimeBootstrapRecord(e.nodeId),t=e;if(a){if(a.ownerGeneration>t.ownerGeneration)return a;if(a.ownerGeneration===t.ownerGeneration){if(a.bootstrapRevision>t.bootstrapRevision)return a;if(a.bootstrapRevision===t.bootstrapRevision){if(!sr(a,t))throw Error(`Runtime bootstrap revision conflict for ${t.nodeId} at owner generation ${t.ownerGeneration}`);return a}}if(t.bootstrapRevision<=a.bootstrapRevision)t={...t,bootstrapRevision:a.bootstrapRevision+1}}return this.db.prepare(`INSERT INTO runtime_bootstrap_records (
|
|
78
|
+
node_id,
|
|
79
|
+
runtime_id,
|
|
80
|
+
owner_generation,
|
|
81
|
+
bootstrap_revision,
|
|
82
|
+
phase,
|
|
83
|
+
protocol_version,
|
|
84
|
+
control_endpoint_host,
|
|
85
|
+
control_endpoint_port,
|
|
86
|
+
tls_ca_fingerprint,
|
|
87
|
+
tls_ca_cert_pem,
|
|
88
|
+
tls_principal_identity,
|
|
89
|
+
tls_loopback_identity,
|
|
90
|
+
identity_json,
|
|
91
|
+
published_at,
|
|
92
|
+
degraded_reason,
|
|
93
|
+
failed_phase
|
|
94
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
95
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
96
|
+
runtime_id = excluded.runtime_id,
|
|
97
|
+
owner_generation = excluded.owner_generation,
|
|
98
|
+
bootstrap_revision = excluded.bootstrap_revision,
|
|
99
|
+
phase = excluded.phase,
|
|
100
|
+
protocol_version = excluded.protocol_version,
|
|
101
|
+
control_endpoint_host = excluded.control_endpoint_host,
|
|
102
|
+
control_endpoint_port = excluded.control_endpoint_port,
|
|
103
|
+
tls_ca_fingerprint = excluded.tls_ca_fingerprint,
|
|
104
|
+
tls_ca_cert_pem = excluded.tls_ca_cert_pem,
|
|
105
|
+
tls_principal_identity = excluded.tls_principal_identity,
|
|
106
|
+
tls_loopback_identity = excluded.tls_loopback_identity,
|
|
107
|
+
identity_json = excluded.identity_json,
|
|
108
|
+
published_at = excluded.published_at,
|
|
109
|
+
degraded_reason = excluded.degraded_reason,
|
|
110
|
+
failed_phase = excluded.failed_phase
|
|
111
|
+
WHERE excluded.owner_generation > runtime_bootstrap_records.owner_generation
|
|
112
|
+
OR (
|
|
113
|
+
excluded.owner_generation = runtime_bootstrap_records.owner_generation
|
|
114
|
+
AND excluded.bootstrap_revision > runtime_bootstrap_records.bootstrap_revision
|
|
115
|
+
)`).run(t.nodeId,t.runtimeId,t.ownerGeneration,t.bootstrapRevision,t.phase,t.protocolVersion,t.controlEndpoint.host,t.controlEndpoint.port,T(t.tls.caFingerprint),t.tls.caCertPem,t.tls.principalIdentity,t.tls.loopbackIdentity,JSON.stringify({...t.arionName?{arionName:t.arionName}:{},signingPublicKey:t.signingPublicKey,transportPublicKey:t.transportPublicKey,transportEndpoint:t.transportEndpoint,...t.displayNameSnapshot?{displayNameSnapshot:t.displayNameSnapshot}:{}}),t.publishedAt,t.degradedReason??null,t.failedPhase??null),this.readRuntimeBootstrapRecord(t.nodeId)}readPeerBinding(r){let e=this.db.prepare(`SELECT
|
|
116
|
+
node_id,
|
|
117
|
+
principal_fingerprint,
|
|
118
|
+
transport_public_key,
|
|
119
|
+
continuity_revision,
|
|
120
|
+
endpoint_host,
|
|
121
|
+
endpoint_port,
|
|
122
|
+
endpoint_revision,
|
|
123
|
+
display_name_snapshot,
|
|
124
|
+
control_endpoint_host,
|
|
125
|
+
control_endpoint_port,
|
|
126
|
+
control_tls_ca_fingerprint,
|
|
127
|
+
updated_at
|
|
128
|
+
FROM peer_binding
|
|
129
|
+
WHERE node_id = ?
|
|
130
|
+
LIMIT 1`).get(r);return v(e)}listPeerBindings(){return this.db.prepare(`SELECT
|
|
131
|
+
node_id,
|
|
132
|
+
principal_fingerprint,
|
|
133
|
+
transport_public_key,
|
|
134
|
+
continuity_revision,
|
|
135
|
+
endpoint_host,
|
|
136
|
+
endpoint_port,
|
|
137
|
+
endpoint_revision,
|
|
138
|
+
display_name_snapshot,
|
|
139
|
+
control_endpoint_host,
|
|
140
|
+
control_endpoint_port,
|
|
141
|
+
control_tls_ca_fingerprint,
|
|
142
|
+
updated_at
|
|
143
|
+
FROM peer_binding
|
|
144
|
+
ORDER BY node_id ASC`).all().map((e)=>v(e)).filter(Boolean)}getPeerTransportState(r){return this.db.prepare("SELECT transport_state FROM peer_binding WHERE node_id = ?").get(r)?.transport_state??"unknown"}setPeerTransportState(r,e){this.db.prepare("UPDATE peer_binding SET transport_state = ? WHERE node_id = ?").run(e,r)}commitPeerEndpointProjection(r){this.assertOwnership();let e=G.parse(r.nodeId);if(!Number.isInteger(r.endpointRevision)||r.endpointRevision<0)throw Error("Peer endpoint projection requires a non-negative endpoint revision");let a=this.readPeerBinding(e);if(!a)return{kind:"not_found"};let t=R({endpointHost:r.endpointHost,endpointPort:r.endpointPort}),w=t.endpointHost,S=t.endpointPort,d=r.updatedAt??new Date().toISOString(),E=a.endpointRevision??0;if(E>r.endpointRevision)return{kind:"stale",binding:a};if(E===r.endpointRevision){let s=a.endpointHost===r.endpointHost&&a.endpointPort===r.endpointPort,H=typeof a.endpointHost!=="string"||typeof a.endpointPort!=="number";if(!s){if(H)return this.db.prepare(`UPDATE peer_binding
|
|
145
|
+
SET endpoint_host = ?,
|
|
146
|
+
endpoint_port = ?,
|
|
147
|
+
endpoint_revision = ?,
|
|
148
|
+
updated_at = ?,
|
|
149
|
+
owner_generation = ?
|
|
150
|
+
WHERE node_id = ?`).run(r.endpointHost,r.endpointPort,r.endpointRevision,d,this.ownerGeneration??0,e),{kind:"applied",binding:this.readPeerBinding(e)};throw Error(`Peer binding endpoint revision conflict for ${O(e)}`)}return{kind:"idempotent",binding:a}}try{this.db.prepare(`UPDATE peer_binding
|
|
151
|
+
SET endpoint_host = ?,
|
|
152
|
+
endpoint_port = ?,
|
|
153
|
+
endpoint_revision = ?,
|
|
154
|
+
updated_at = ?,
|
|
155
|
+
owner_generation = ?
|
|
156
|
+
WHERE node_id = ?
|
|
157
|
+
AND owner_generation <= ?
|
|
158
|
+
AND endpoint_revision < ?`).run(w??null,S??null,r.endpointRevision,d,this.ownerGeneration??0,e,this.ownerGeneration??0,r.endpointRevision)}catch(s){if(y(s))throw Error(`Peer binding direct transport endpoint conflict for ${O(e)}`);throw s}let b=this.readPeerBinding(e);if(!b)throw Error(`Peer endpoint projection for ${O(e)} disappeared after commit`);return{kind:"applied",binding:b}}commitPairContinuity(r){this.assertOwnership();let e=I(r),a=this.readPeerBinding(e.nodeId),t=K(a,e);if(a&&a.continuityRevision>t.continuityRevision)return a;if(a&&a.continuityRevision===t.continuityRevision){let E=P(a,t);if(E==="idempotent")return a;if(E==="stale"||E==="conflict")throw Error(`Peer binding continuity revision conflict for ${t.nodeId}`);try{if(this.db.prepare(`UPDATE peer_binding
|
|
159
|
+
SET endpoint_host = ?,
|
|
160
|
+
endpoint_port = ?,
|
|
161
|
+
endpoint_revision = ?,
|
|
162
|
+
display_name_snapshot = ?,
|
|
163
|
+
control_endpoint_host = ?,
|
|
164
|
+
control_endpoint_port = ?,
|
|
165
|
+
control_tls_ca_fingerprint = ?,
|
|
166
|
+
updated_at = ?,
|
|
167
|
+
owner_generation = ?
|
|
168
|
+
WHERE node_id = ?
|
|
169
|
+
AND continuity_revision = ?
|
|
170
|
+
AND principal_fingerprint = ?
|
|
171
|
+
AND transport_public_key = ?
|
|
172
|
+
AND owner_generation <= ?
|
|
173
|
+
AND endpoint_revision <= ?`).run(t.endpointHost??null,t.endpointPort??null,t.endpointRevision,t.displayNameSnapshot??null,t.controlEndpointHost??null,t.controlEndpointPort??null,t.controlTlsCaFingerprint?T(t.controlTlsCaFingerprint):null,t.updatedAt,this.ownerGeneration??0,t.nodeId,t.continuityRevision,t.principalFingerprint,t.transportPublicKey,this.ownerGeneration??0,t.endpointRevision).changes!==1)throw Error(`Peer binding continuity revision conflict for ${t.nodeId}`)}catch(b){if(y(b))throw Error(`Peer binding direct transport endpoint conflict for ${O(t.nodeId)}`);throw b}return this.readPeerBinding(t.nodeId)}let w=a!==null&&a.transportPublicKey!==t.transportPublicKey,S=a?this.getPeerTransportState(t.nodeId):"unknown",d=w?"unknown":S;try{this.db.prepare(`INSERT INTO peer_binding (
|
|
174
|
+
node_id,
|
|
175
|
+
principal_fingerprint,
|
|
176
|
+
transport_public_key,
|
|
177
|
+
continuity_revision,
|
|
178
|
+
endpoint_host,
|
|
179
|
+
endpoint_port,
|
|
180
|
+
endpoint_revision,
|
|
181
|
+
display_name_snapshot,
|
|
182
|
+
control_endpoint_host,
|
|
183
|
+
control_endpoint_port,
|
|
184
|
+
control_tls_ca_fingerprint,
|
|
185
|
+
identity_state,
|
|
186
|
+
transport_state,
|
|
187
|
+
updated_at,
|
|
188
|
+
owner_generation
|
|
189
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
190
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
191
|
+
principal_fingerprint = excluded.principal_fingerprint,
|
|
192
|
+
transport_public_key = excluded.transport_public_key,
|
|
193
|
+
continuity_revision = excluded.continuity_revision,
|
|
194
|
+
endpoint_host = excluded.endpoint_host,
|
|
195
|
+
endpoint_port = excluded.endpoint_port,
|
|
196
|
+
endpoint_revision = excluded.endpoint_revision,
|
|
197
|
+
display_name_snapshot = excluded.display_name_snapshot,
|
|
198
|
+
control_endpoint_host = excluded.control_endpoint_host,
|
|
199
|
+
control_endpoint_port = excluded.control_endpoint_port,
|
|
200
|
+
control_tls_ca_fingerprint = excluded.control_tls_ca_fingerprint,
|
|
201
|
+
identity_state = excluded.identity_state,
|
|
202
|
+
transport_state = excluded.transport_state,
|
|
203
|
+
updated_at = excluded.updated_at,
|
|
204
|
+
owner_generation = excluded.owner_generation
|
|
205
|
+
WHERE excluded.continuity_revision > peer_binding.continuity_revision
|
|
206
|
+
AND excluded.owner_generation >= peer_binding.owner_generation`).run(t.nodeId,t.principalFingerprint,t.transportPublicKey,t.continuityRevision,t.endpointHost??null,t.endpointPort??null,t.endpointRevision,t.displayNameSnapshot??null,t.controlEndpointHost??null,t.controlEndpointPort??null,t.controlTlsCaFingerprint?T(t.controlTlsCaFingerprint):null,"paired_unverified",d,t.updatedAt,this.ownerGeneration??0)}catch(E){if(y(E))throw Error(`Peer binding direct transport endpoint conflict for ${O(t.nodeId)}`);throw E}try{this.appendRuntimeEvent({nodeId:t.nodeId,runtimeId:z.parse("node-store"),kind:"continuity_bound",payload:{nodeId:t.nodeId,transportKeyChanged:w,previousTransportState:S,newTransportState:d,continuityRevision:t.continuityRevision}})}catch{}return this.readPeerBinding(t.nodeId)}commitPairContinuityClearingRevocation(r){this.assertOwnership();let e=I(r);return this.db.transaction(()=>{let a=this.readPeerBinding(e.nodeId),t=K(a,e);if(a&&a.continuityRevision>t.continuityRevision)return a;if(a&&a.continuityRevision===t.continuityRevision){let E=P(a,t);if(E==="idempotent")return q(this.db,t.nodeId,r.expectedRevocationGeneration),a;if(E==="stale"||E==="conflict")throw Error(`Peer binding continuity revision conflict for ${t.nodeId}`);q(this.db,t.nodeId,r.expectedRevocationGeneration);try{if(this.db.prepare(`UPDATE peer_binding
|
|
207
|
+
SET endpoint_host = ?,
|
|
208
|
+
endpoint_port = ?,
|
|
209
|
+
endpoint_revision = ?,
|
|
210
|
+
display_name_snapshot = ?,
|
|
211
|
+
control_endpoint_host = ?,
|
|
212
|
+
control_endpoint_port = ?,
|
|
213
|
+
control_tls_ca_fingerprint = ?,
|
|
214
|
+
updated_at = ?,
|
|
215
|
+
owner_generation = ?
|
|
216
|
+
WHERE node_id = ?
|
|
217
|
+
AND continuity_revision = ?
|
|
218
|
+
AND principal_fingerprint = ?
|
|
219
|
+
AND transport_public_key = ?
|
|
220
|
+
AND owner_generation <= ?
|
|
221
|
+
AND endpoint_revision <= ?`).run(t.endpointHost??null,t.endpointPort??null,t.endpointRevision,t.displayNameSnapshot??null,t.controlEndpointHost??null,t.controlEndpointPort??null,t.controlTlsCaFingerprint?T(t.controlTlsCaFingerprint):null,t.updatedAt,this.ownerGeneration??0,t.nodeId,t.continuityRevision,t.principalFingerprint,t.transportPublicKey,this.ownerGeneration??0,t.endpointRevision).changes!==1)throw Error(`Peer binding continuity revision conflict for ${t.nodeId}`)}catch(b){if(y(b))throw Error(`Peer binding direct transport endpoint conflict for ${O(t.nodeId)}`);throw b}return this.readPeerBinding(t.nodeId)}q(this.db,t.nodeId,r.expectedRevocationGeneration);let w=a!==null&&a.transportPublicKey!==t.transportPublicKey,S=a?this.getPeerTransportState(t.nodeId):"unknown",d=w?"unknown":S;try{this.db.prepare(`INSERT INTO peer_binding (
|
|
222
|
+
node_id,
|
|
223
|
+
principal_fingerprint,
|
|
224
|
+
transport_public_key,
|
|
225
|
+
continuity_revision,
|
|
226
|
+
endpoint_host,
|
|
227
|
+
endpoint_port,
|
|
228
|
+
endpoint_revision,
|
|
229
|
+
display_name_snapshot,
|
|
230
|
+
control_endpoint_host,
|
|
231
|
+
control_endpoint_port,
|
|
232
|
+
control_tls_ca_fingerprint,
|
|
233
|
+
identity_state,
|
|
234
|
+
transport_state,
|
|
235
|
+
updated_at,
|
|
236
|
+
owner_generation
|
|
237
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
238
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
239
|
+
principal_fingerprint = excluded.principal_fingerprint,
|
|
240
|
+
transport_public_key = excluded.transport_public_key,
|
|
241
|
+
continuity_revision = excluded.continuity_revision,
|
|
242
|
+
endpoint_host = excluded.endpoint_host,
|
|
243
|
+
endpoint_port = excluded.endpoint_port,
|
|
244
|
+
endpoint_revision = excluded.endpoint_revision,
|
|
245
|
+
display_name_snapshot = excluded.display_name_snapshot,
|
|
246
|
+
control_endpoint_host = excluded.control_endpoint_host,
|
|
247
|
+
control_endpoint_port = excluded.control_endpoint_port,
|
|
248
|
+
control_tls_ca_fingerprint = excluded.control_tls_ca_fingerprint,
|
|
249
|
+
identity_state = excluded.identity_state,
|
|
250
|
+
transport_state = excluded.transport_state,
|
|
251
|
+
updated_at = excluded.updated_at,
|
|
252
|
+
owner_generation = excluded.owner_generation
|
|
253
|
+
WHERE excluded.continuity_revision > peer_binding.continuity_revision
|
|
254
|
+
AND excluded.owner_generation >= peer_binding.owner_generation`).run(t.nodeId,t.principalFingerprint,t.transportPublicKey,t.continuityRevision,t.endpointHost??null,t.endpointPort??null,t.endpointRevision,t.displayNameSnapshot??null,t.controlEndpointHost??null,t.controlEndpointPort??null,t.controlTlsCaFingerprint?T(t.controlTlsCaFingerprint):null,"paired_unverified",d,t.updatedAt,this.ownerGeneration??0)}catch(E){if(y(E))throw Error(`Peer binding direct transport endpoint conflict for ${O(t.nodeId)}`);throw E}try{this.appendRuntimeEvent({nodeId:t.nodeId,runtimeId:z.parse("node-store"),kind:"continuity_bound",payload:{nodeId:t.nodeId,transportKeyChanged:w,previousTransportState:S,newTransportState:d,continuityRevision:t.continuityRevision,clearedRevocationGeneration:r.expectedRevocationGeneration}})}catch{}return this.readPeerBinding(t.nodeId)})()}readPeerRevocation(r){let e=this.db.prepare(`SELECT
|
|
255
|
+
node_id,
|
|
256
|
+
display_name_snapshot,
|
|
257
|
+
fingerprint,
|
|
258
|
+
revoked_at,
|
|
259
|
+
local_node_id,
|
|
260
|
+
operator_confirmation,
|
|
261
|
+
reason,
|
|
262
|
+
revocation_generation
|
|
263
|
+
FROM revocation_events
|
|
264
|
+
WHERE node_id = ?
|
|
265
|
+
LIMIT 1`).get(O(r));return Z(e)}getPeerRevocationGeneration(r){return this.readPeerRevocation(r)?.revocationGeneration??null}revoke(r){this.commitPeerRevocation({nodeId:r.nodeId,displayNameSnapshot:r.displayNameSnapshot,fingerprint:r.fingerprint,revokedAt:r.revokedAt,revokedBy:r.localNodeId,operatorConfirmation:r.operatorConfirmation,reason:r.reason,revocationGeneration:r.revocationGeneration})}readRevocation(r){return this.readPeerRevocation(r)}listRevocations(){return this.db.prepare("SELECT * FROM revocation_events ORDER BY revoked_at DESC").all().map((e)=>Z(e)).filter(Boolean)}isPeerRevoked(r){return this.readPeerRevocation(r)!==null}clearRevocationForNodeId(r,e){return this.assertOwnership(),(typeof e==="number"?this.db.prepare("DELETE FROM revocation_events WHERE node_id = ? AND revocation_generation = ?").run(O(r),e):this.db.prepare("DELETE FROM revocation_events WHERE node_id = ?").run(O(r))).changes>0}commitPeerRevocation(r){let e=this.getPeerRevocationGeneration(r.nodeId)??0,a={nodeId:r.nodeId,displayNameSnapshot:r.displayNameSnapshot,fingerprint:r.fingerprint,revokedAt:r.revokedAt,revokedBy:r.revokedBy,operatorConfirmation:r.operatorConfirmation??"local_operator_confirmed",reason:r.reason,revocationGeneration:typeof r.revocationGeneration==="number"&&r.revocationGeneration>0?r.revocationGeneration:e+1},t=this.readPeerRevocation(a.nodeId);if(t&&t.revocationGeneration>a.revocationGeneration)return t;if(t&&t.revocationGeneration===a.revocationGeneration){if(!Or(t,a))throw Error(`Peer revocation generation conflict for ${O(a.nodeId)}`);return t}return this.db.prepare(`INSERT INTO revocation_events (
|
|
266
|
+
node_id,
|
|
267
|
+
display_name_snapshot,
|
|
268
|
+
fingerprint,
|
|
269
|
+
revoked_at,
|
|
270
|
+
local_node_id,
|
|
271
|
+
operator_confirmation,
|
|
272
|
+
reason,
|
|
273
|
+
revocation_generation
|
|
274
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
275
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
276
|
+
display_name_snapshot = excluded.display_name_snapshot,
|
|
277
|
+
fingerprint = excluded.fingerprint,
|
|
278
|
+
revoked_at = excluded.revoked_at,
|
|
279
|
+
local_node_id = excluded.local_node_id,
|
|
280
|
+
operator_confirmation = excluded.operator_confirmation,
|
|
281
|
+
reason = excluded.reason,
|
|
282
|
+
revocation_generation = excluded.revocation_generation
|
|
283
|
+
WHERE excluded.revocation_generation > revocation_events.revocation_generation`).run(O(a.nodeId),a.displayNameSnapshot??null,a.fingerprint,a.revokedAt,O(a.revokedBy),a.operatorConfirmation,a.reason??null,a.revocationGeneration),this.readPeerRevocation(a.nodeId)??a}deletePeerBinding(r){return this.assertOwnership(),this.db.prepare("DELETE FROM peer_binding WHERE node_id = ? AND owner_generation <= ?").run(r,this.ownerGeneration??0).changes>0}restorePeerBinding(r,e){if(this.assertOwnership(),!e){this.db.prepare("DELETE FROM peer_binding WHERE node_id = ?").run(r);return}this.db.prepare(`INSERT INTO peer_binding (
|
|
284
|
+
node_id,
|
|
285
|
+
principal_fingerprint,
|
|
286
|
+
transport_public_key,
|
|
287
|
+
continuity_revision,
|
|
288
|
+
endpoint_host,
|
|
289
|
+
endpoint_port,
|
|
290
|
+
endpoint_revision,
|
|
291
|
+
display_name_snapshot,
|
|
292
|
+
control_endpoint_host,
|
|
293
|
+
control_endpoint_port,
|
|
294
|
+
control_tls_ca_fingerprint,
|
|
295
|
+
updated_at,
|
|
296
|
+
owner_generation
|
|
297
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
298
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
299
|
+
principal_fingerprint = excluded.principal_fingerprint,
|
|
300
|
+
transport_public_key = excluded.transport_public_key,
|
|
301
|
+
continuity_revision = excluded.continuity_revision,
|
|
302
|
+
endpoint_host = excluded.endpoint_host,
|
|
303
|
+
endpoint_port = excluded.endpoint_port,
|
|
304
|
+
endpoint_revision = excluded.endpoint_revision,
|
|
305
|
+
display_name_snapshot = excluded.display_name_snapshot,
|
|
306
|
+
control_endpoint_host = excluded.control_endpoint_host,
|
|
307
|
+
control_endpoint_port = excluded.control_endpoint_port,
|
|
308
|
+
control_tls_ca_fingerprint = excluded.control_tls_ca_fingerprint,
|
|
309
|
+
updated_at = excluded.updated_at,
|
|
310
|
+
owner_generation = excluded.owner_generation
|
|
311
|
+
WHERE excluded.owner_generation >= peer_binding.owner_generation`).run(e.nodeId,e.principalFingerprint,e.transportPublicKey,e.continuityRevision,e.endpointHost??null,e.endpointPort??null,e.endpointRevision,e.displayNameSnapshot??null,e.controlEndpointHost??null,e.controlEndpointPort??null,e.controlTlsCaFingerprint?T(e.controlTlsCaFingerprint):null,e.updatedAt,this.ownerGeneration??0)}readIngressReceipt(r){let e=this.db.prepare(`SELECT
|
|
312
|
+
message_id,
|
|
313
|
+
sender_node_id,
|
|
314
|
+
sender_fingerprint,
|
|
315
|
+
runtime_id,
|
|
316
|
+
received_at
|
|
317
|
+
FROM replay_guard
|
|
318
|
+
WHERE message_id = ?
|
|
319
|
+
LIMIT 1`).get(r);return Mr(e)}commitIngressReceipt(r){this.assertOwnership();let e={...r,receivedAt:r.receivedAt??new Date().toISOString()},a=this.db.prepare(`INSERT OR IGNORE INTO replay_guard (
|
|
320
|
+
message_id,
|
|
321
|
+
sender_node_id,
|
|
322
|
+
sender_fingerprint,
|
|
323
|
+
runtime_id,
|
|
324
|
+
received_at,
|
|
325
|
+
owner_generation
|
|
326
|
+
) VALUES (?, ?, ?, ?, ?, ?)`).run(e.messageId,e.senderNodeId,e.senderFingerprint,e.runtimeId,e.receivedAt,this.ownerGeneration??0);return{...this.readIngressReceipt(e.messageId)??e,duplicate:a.changes===0}}readOutboxReceipt(r){let e=this.db.prepare(`SELECT
|
|
327
|
+
message_id,
|
|
328
|
+
sender_node_id,
|
|
329
|
+
recipient_node_id,
|
|
330
|
+
transport,
|
|
331
|
+
status,
|
|
332
|
+
delivery_lifecycle_revision,
|
|
333
|
+
updated_at
|
|
334
|
+
FROM outbox_receipt
|
|
335
|
+
WHERE message_id = ?
|
|
336
|
+
LIMIT 1`).get(r);return Nr(e)}commitOutboxReceipt(r){this.assertOwnership();let e=this.readOutboxReceipt(r.messageId),a={...r,deliveryLifecycleRevision:r.deliveryLifecycleRevision??(e?.deliveryLifecycleRevision??0)+1,updatedAt:r.updatedAt??new Date().toISOString()};if(e){if(!(e.senderNodeId===a.senderNodeId&&e.recipientNodeId===a.recipientNodeId&&e.transport===a.transport))return e;if(a.deliveryLifecycleRevision<e.deliveryLifecycleRevision)return e;if(a.deliveryLifecycleRevision===e.deliveryLifecycleRevision)return e;let w={queued_for_route:0,dispatching:0,expired:1,acked:2},S=w[a.status],d=w[e.status];if(S<d)return e;if(a.updatedAt.localeCompare(e.updatedAt)<0)return e}return this.db.prepare(`INSERT INTO outbox_receipt (
|
|
337
|
+
message_id,
|
|
338
|
+
sender_node_id,
|
|
339
|
+
recipient_node_id,
|
|
340
|
+
transport,
|
|
341
|
+
status,
|
|
342
|
+
delivery_lifecycle_revision,
|
|
343
|
+
updated_at,
|
|
344
|
+
owner_generation
|
|
345
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
346
|
+
ON CONFLICT(message_id) DO UPDATE SET
|
|
347
|
+
sender_node_id = excluded.sender_node_id,
|
|
348
|
+
recipient_node_id = excluded.recipient_node_id,
|
|
349
|
+
transport = excluded.transport,
|
|
350
|
+
status = excluded.status,
|
|
351
|
+
delivery_lifecycle_revision = excluded.delivery_lifecycle_revision,
|
|
352
|
+
updated_at = excluded.updated_at,
|
|
353
|
+
owner_generation = excluded.owner_generation`).run(a.messageId,a.senderNodeId,a.recipientNodeId,a.transport,a.status,a.deliveryLifecycleRevision,a.updatedAt,this.ownerGeneration??0),this.readOutboxReceipt(a.messageId)}listRevocationConflicts(){return this.db.prepare(`SELECT
|
|
354
|
+
conflict_id,
|
|
355
|
+
node_id,
|
|
356
|
+
previous_fingerprint,
|
|
357
|
+
conflicting_fingerprint,
|
|
358
|
+
reason,
|
|
359
|
+
recorded_at
|
|
360
|
+
FROM revocation_conflict
|
|
361
|
+
ORDER BY recorded_at ASC`).all().map((e)=>Ur(e)).filter(Boolean)}commitRevocationConflict(r){this.assertOwnership();let e={...r,conflictId:r.conflictId??`revconf-${V()}`,recordedAt:r.recordedAt??new Date().toISOString()};return this.db.prepare(`INSERT INTO revocation_conflict (
|
|
362
|
+
conflict_id,
|
|
363
|
+
node_id,
|
|
364
|
+
previous_fingerprint,
|
|
365
|
+
conflicting_fingerprint,
|
|
366
|
+
reason,
|
|
367
|
+
recorded_at,
|
|
368
|
+
owner_generation
|
|
369
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)`).run(e.conflictId,e.nodeId,e.previousFingerprint??null,e.conflictingFingerprint,e.reason,e.recordedAt,this.ownerGeneration??0),this.listRevocationConflicts().find((a)=>a.conflictId===e.conflictId)??e}ensureSchema(){let r=this.db.prepare("PRAGMA table_info(revocation_events)").all(),e=r.find((h)=>h.pk===1)?.name;if(r.length>0&&(e!=="node_id"||!r.some((h)=>h.name==="node_id")||!r.some((h)=>h.name==="display_name_snapshot")||!r.some((h)=>h.name==="local_node_id")||!r.some((h)=>h.name==="operator_confirmation")||r.some((h)=>h.name==="revoked_by")))this.db.exec(`
|
|
370
|
+
DROP TABLE IF EXISTS revocation_events;
|
|
371
|
+
`);this.db.exec(`
|
|
372
|
+
CREATE TABLE IF NOT EXISTS owner_epoch (
|
|
373
|
+
scope TEXT PRIMARY KEY DEFAULT 'runtime',
|
|
374
|
+
owner_generation INTEGER NOT NULL
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
CREATE TABLE IF NOT EXISTS node_store_schema_version (
|
|
378
|
+
singleton_key TEXT PRIMARY KEY CHECK (singleton_key = 'node_store'),
|
|
379
|
+
schema_version INTEGER NOT NULL
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
INSERT INTO node_store_schema_version (singleton_key, schema_version)
|
|
383
|
+
VALUES ('node_store', ${X})
|
|
384
|
+
ON CONFLICT(singleton_key) DO NOTHING;
|
|
385
|
+
|
|
386
|
+
CREATE TABLE IF NOT EXISTS node_metadata (
|
|
387
|
+
singleton_key TEXT PRIMARY KEY CHECK (singleton_key = 'node'),
|
|
388
|
+
node_id TEXT NOT NULL,
|
|
389
|
+
created_at TEXT NOT NULL,
|
|
390
|
+
schema_version INTEGER NOT NULL,
|
|
391
|
+
migrated_from_legacy INTEGER NOT NULL CHECK (migrated_from_legacy IN (0, 1))
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
CREATE TABLE IF NOT EXISTS runtime_owner_records (
|
|
395
|
+
node_id TEXT PRIMARY KEY,
|
|
396
|
+
schema_version INTEGER NOT NULL,
|
|
397
|
+
aria_home TEXT NOT NULL,
|
|
398
|
+
runtime_pid INTEGER NOT NULL,
|
|
399
|
+
runtime_id TEXT NOT NULL,
|
|
400
|
+
display_name_snapshot TEXT,
|
|
401
|
+
runtime_socket TEXT NOT NULL,
|
|
402
|
+
started_at TEXT NOT NULL,
|
|
403
|
+
last_heartbeat TEXT NOT NULL,
|
|
404
|
+
owner_generation INTEGER NOT NULL
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
CREATE TABLE IF NOT EXISTS runtime_events (
|
|
408
|
+
revision INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
409
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
410
|
+
node_id TEXT NOT NULL,
|
|
411
|
+
runtime_id TEXT NOT NULL,
|
|
412
|
+
kind TEXT NOT NULL,
|
|
413
|
+
recorded_at TEXT NOT NULL,
|
|
414
|
+
payload_json TEXT NOT NULL,
|
|
415
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
CREATE TABLE IF NOT EXISTS runtime_bootstrap_records (
|
|
419
|
+
node_id TEXT PRIMARY KEY,
|
|
420
|
+
runtime_id TEXT NOT NULL,
|
|
421
|
+
owner_generation INTEGER NOT NULL,
|
|
422
|
+
bootstrap_revision INTEGER NOT NULL,
|
|
423
|
+
phase TEXT NOT NULL,
|
|
424
|
+
protocol_version INTEGER NOT NULL,
|
|
425
|
+
control_endpoint_host TEXT NOT NULL,
|
|
426
|
+
control_endpoint_port INTEGER NOT NULL,
|
|
427
|
+
tls_ca_fingerprint TEXT NOT NULL,
|
|
428
|
+
tls_ca_cert_pem TEXT NOT NULL,
|
|
429
|
+
tls_principal_identity TEXT NOT NULL,
|
|
430
|
+
tls_loopback_identity TEXT NOT NULL,
|
|
431
|
+
identity_json TEXT,
|
|
432
|
+
published_at TEXT NOT NULL,
|
|
433
|
+
degraded_reason TEXT,
|
|
434
|
+
failed_phase TEXT
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
CREATE TABLE IF NOT EXISTS peer_binding (
|
|
438
|
+
node_id TEXT PRIMARY KEY,
|
|
439
|
+
principal_fingerprint TEXT NOT NULL,
|
|
440
|
+
transport_public_key TEXT NOT NULL,
|
|
441
|
+
continuity_revision INTEGER NOT NULL,
|
|
442
|
+
endpoint_host TEXT,
|
|
443
|
+
endpoint_port INTEGER,
|
|
444
|
+
endpoint_revision INTEGER NOT NULL DEFAULT 0,
|
|
445
|
+
display_name_snapshot TEXT,
|
|
446
|
+
control_endpoint_host TEXT,
|
|
447
|
+
control_endpoint_port INTEGER,
|
|
448
|
+
control_tls_ca_fingerprint TEXT,
|
|
449
|
+
identity_state TEXT NOT NULL DEFAULT 'paired_unverified',
|
|
450
|
+
transport_state TEXT NOT NULL DEFAULT 'unknown',
|
|
451
|
+
updated_at TEXT NOT NULL,
|
|
452
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
CREATE TABLE IF NOT EXISTS outbox_receipt (
|
|
456
|
+
message_id TEXT PRIMARY KEY,
|
|
457
|
+
sender_node_id TEXT NOT NULL,
|
|
458
|
+
recipient_node_id TEXT NOT NULL,
|
|
459
|
+
transport TEXT NOT NULL,
|
|
460
|
+
status TEXT NOT NULL CHECK (status IN (${j})),
|
|
461
|
+
delivery_lifecycle_revision INTEGER NOT NULL DEFAULT 1,
|
|
462
|
+
updated_at TEXT NOT NULL,
|
|
463
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
CREATE TABLE IF NOT EXISTS replay_guard (
|
|
467
|
+
message_id TEXT PRIMARY KEY,
|
|
468
|
+
sender_node_id TEXT NOT NULL,
|
|
469
|
+
sender_fingerprint TEXT NOT NULL,
|
|
470
|
+
runtime_id TEXT NOT NULL,
|
|
471
|
+
received_at TEXT NOT NULL,
|
|
472
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
CREATE TABLE IF NOT EXISTS revocation_events (
|
|
476
|
+
node_id TEXT PRIMARY KEY,
|
|
477
|
+
display_name_snapshot TEXT,
|
|
478
|
+
fingerprint TEXT NOT NULL,
|
|
479
|
+
revoked_at INTEGER NOT NULL,
|
|
480
|
+
local_node_id TEXT NOT NULL,
|
|
481
|
+
operator_confirmation TEXT NOT NULL,
|
|
482
|
+
reason TEXT,
|
|
483
|
+
revocation_generation INTEGER NOT NULL DEFAULT 1
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
CREATE INDEX IF NOT EXISTS idx_revocation_fingerprint
|
|
487
|
+
ON revocation_events(fingerprint);
|
|
488
|
+
|
|
489
|
+
CREATE INDEX IF NOT EXISTS idx_revocation_time
|
|
490
|
+
ON revocation_events(revoked_at);
|
|
491
|
+
|
|
492
|
+
CREATE TABLE IF NOT EXISTS revocation_conflict (
|
|
493
|
+
conflict_id TEXT PRIMARY KEY,
|
|
494
|
+
node_id TEXT NOT NULL,
|
|
495
|
+
previous_fingerprint TEXT,
|
|
496
|
+
conflicting_fingerprint TEXT NOT NULL,
|
|
497
|
+
reason TEXT NOT NULL,
|
|
498
|
+
recorded_at TEXT NOT NULL,
|
|
499
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
500
|
+
);
|
|
501
|
+
`);let t=new Set(this.db.prepare("PRAGMA table_info(runtime_owner_records)").all().map((h)=>h.name)),w=["display_name_snapshot"].filter((h)=>!t.has(h));if(w.length>0)throw Error(`[node-store] Legacy runtime_owner_records schema requires hard reset: missing columns: ${w.join(", ")}`);let S=new Set(this.db.prepare("PRAGMA table_info(runtime_bootstrap_records)").all().map((h)=>h.name)),d=["node_id","runtime_id","owner_generation","bootstrap_revision","phase","protocol_version","control_endpoint_host","control_endpoint_port","tls_ca_fingerprint","tls_ca_cert_pem","tls_principal_identity","tls_loopback_identity","identity_json","published_at","degraded_reason","failed_phase"].filter((h)=>!S.has(h));if(d.length>0)throw Error(`[node-store] Legacy runtime_bootstrap_records schema requires hard reset: missing columns: ${d.join(", ")}`);let E=this.db.prepare("PRAGMA table_info(peer_binding)").all(),b=E.find((h)=>h.pk===1)?.name,s=new Set(E.map((h)=>h.name)),M=["node_id","principal_fingerprint","transport_public_key","continuity_revision","endpoint_host","endpoint_port","endpoint_revision","display_name_snapshot","control_endpoint_host","control_endpoint_port","control_tls_ca_fingerprint","updated_at"].filter((h)=>!s.has(h)).filter((h)=>h!=="endpoint_host"&&h!=="endpoint_port"&&h!=="endpoint_revision");if(b!=="node_id"||M.length>0){let h=[...b!=="node_id"?[`primary key is ${b??"missing"}`]:[],...M.length>0?[`missing columns: ${M.join(", ")}`]:[]];throw Error(`[node-store] Legacy peer_binding schema requires hard reset: ${h.join("; ")}`)}if(!s.has("identity_state"))this.db.exec("ALTER TABLE peer_binding ADD COLUMN identity_state TEXT NOT NULL DEFAULT 'paired_unverified'");if(!s.has("transport_state"))this.db.exec("ALTER TABLE peer_binding ADD COLUMN transport_state TEXT NOT NULL DEFAULT 'unknown'");if(!s.has("endpoint_host"))this.db.exec("ALTER TABLE peer_binding ADD COLUMN endpoint_host TEXT");if(!s.has("endpoint_port"))this.db.exec("ALTER TABLE peer_binding ADD COLUMN endpoint_port INTEGER");if(!s.has("endpoint_revision"))this.db.exec("ALTER TABLE peer_binding ADD COLUMN endpoint_revision INTEGER NOT NULL DEFAULT 0");this.db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_peer_binding_direct_endpoint
|
|
502
|
+
ON peer_binding(endpoint_host, endpoint_port)
|
|
503
|
+
WHERE endpoint_host IS NOT NULL AND endpoint_port IS NOT NULL`);let N=new Set(this.db.prepare("PRAGMA table_info(outbox_receipt)").all().map((h)=>h.name)),J=["sender_node_id","recipient_node_id","delivery_lifecycle_revision"].filter((h)=>!N.has(h));if(J.length>0)throw Error(`[node-store] Legacy outbox_receipt schema requires hard reset: missing columns: ${J.join(", ")}`);if(!N.has("owner_generation"))this.db.exec("ALTER TABLE outbox_receipt ADD COLUMN owner_generation INTEGER NOT NULL DEFAULT 0"),N.add("owner_generation");let B=this.db.prepare(`SELECT sql
|
|
504
|
+
FROM sqlite_master
|
|
505
|
+
WHERE type = 'table'
|
|
506
|
+
AND name = 'outbox_receipt'`).get(),U=String(B?.sql??""),u=this.db.prepare(`SELECT COUNT(*) AS count
|
|
507
|
+
FROM outbox_receipt
|
|
508
|
+
WHERE status = 'queued'
|
|
509
|
+
OR status NOT IN (${j})`).get();if(U.length===0||!xr(U)||U.includes("'queued'")||Number(u?.count??0)>0)this.db.exec(`
|
|
510
|
+
BEGIN;
|
|
511
|
+
ALTER TABLE outbox_receipt RENAME TO outbox_receipt_legacy_status;
|
|
512
|
+
CREATE TABLE outbox_receipt (
|
|
513
|
+
message_id TEXT PRIMARY KEY,
|
|
514
|
+
sender_node_id TEXT NOT NULL,
|
|
515
|
+
recipient_node_id TEXT NOT NULL,
|
|
516
|
+
transport TEXT NOT NULL,
|
|
517
|
+
status TEXT NOT NULL CHECK (status IN (${j})),
|
|
518
|
+
delivery_lifecycle_revision INTEGER NOT NULL DEFAULT 1,
|
|
519
|
+
updated_at TEXT NOT NULL,
|
|
520
|
+
owner_generation INTEGER NOT NULL DEFAULT 0
|
|
521
|
+
);
|
|
522
|
+
INSERT INTO outbox_receipt (
|
|
523
|
+
message_id,
|
|
524
|
+
sender_node_id,
|
|
525
|
+
recipient_node_id,
|
|
526
|
+
transport,
|
|
527
|
+
status,
|
|
528
|
+
delivery_lifecycle_revision,
|
|
529
|
+
updated_at,
|
|
530
|
+
owner_generation
|
|
531
|
+
)
|
|
532
|
+
SELECT
|
|
533
|
+
message_id,
|
|
534
|
+
sender_node_id,
|
|
535
|
+
recipient_node_id,
|
|
536
|
+
transport,
|
|
537
|
+
CASE status
|
|
538
|
+
WHEN 'queued' THEN 'queued_for_route'
|
|
539
|
+
ELSE status
|
|
540
|
+
END,
|
|
541
|
+
delivery_lifecycle_revision,
|
|
542
|
+
updated_at,
|
|
543
|
+
owner_generation
|
|
544
|
+
FROM outbox_receipt_legacy_status;
|
|
545
|
+
DROP TABLE outbox_receipt_legacy_status;
|
|
546
|
+
COMMIT;
|
|
547
|
+
`);let c=new Set(this.db.prepare("PRAGMA table_info(replay_guard)").all().map((h)=>h.name)),L=["message_id","sender_node_id","sender_fingerprint","runtime_id","received_at"].filter((h)=>!c.has(h));if(L.length>0)throw Error(`[node-store] Legacy replay_guard schema requires hard reset: missing columns: ${L.join(", ")}`);let l=new Set(this.db.prepare("PRAGMA table_info(revocation_events)").all().map((h)=>h.name)),Q=["node_id","display_name_snapshot","fingerprint","revoked_at","local_node_id","operator_confirmation","reason","revocation_generation"].filter((h)=>!l.has(h));if(Q.length>0)throw Error(`[node-store] Legacy revocation_events schema requires hard reset: missing columns: ${Q.join(", ")}`);let n=new Set(this.db.prepare("PRAGMA table_info(revocation_conflict)").all().map((h)=>h.name)),W=["conflict_id","node_id","previous_fingerprint","conflicting_fingerprint","reason","recorded_at"].filter((h)=>!n.has(h));if(W.length>0)throw Error(`[node-store] Legacy revocation_conflict schema requires hard reset: missing columns: ${W.join(", ")}`);let o=["peer_binding","runtime_events","outbox_receipt","replay_guard","revocation_conflict"];for(let h of o)if(!new Set(this.db.prepare(`PRAGMA table_info(${h})`).all().map((m)=>m.name)).has("owner_generation"))this.db.exec(`ALTER TABLE ${h} ADD COLUMN owner_generation INTEGER NOT NULL DEFAULT 0`)}}async function Lr(r){return(await import("./runtime/node-metadata.js")).resolveOrCreateNode(r)}
|
|
548
|
+
export{k as ua,X as va,Sr as wa,Gr as xa,Vr as ya,Lr as za};
|