pi-radar 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/extension/baseline.js +333 -394
- package/dist/extension/radar-client.js +126 -11
- package/dist/extension/radar-communication.js +39 -0
- package/dist/extension/radar-execution.js +169 -382
- package/dist/extension/radar-launch.js +18 -13
- package/dist/extension/radar-publication.js +161 -298
- package/dist/extension/radar-runtime.js +1 -1
- package/dist/index.js +356 -407
- package/extension/baseline.ts +2 -0
- package/extension/generated-contracts.ts +1310 -10
- package/extension/radar-client.ts +191 -23
- package/extension/radar-communication.ts +66 -0
- package/extension/radar-execution.ts +11 -58
- package/extension/radar-launch.ts +29 -22
- package/extension/radar-publication.ts +211 -410
- package/extension/radar-runtime.ts +4 -1
- package/index.ts +1 -0
- package/package.json +9 -5
- package/schema/public/v1/handoff-inbox.deserialize.schema.json +18 -0
- package/schema/public/v1/handoff-inbox.serialize.schema.json +18 -0
- package/schema/public/v1/handoff-publish-params.deserialize.schema.json +33 -0
- package/schema/public/v1/handoff-publish-params.serialize.schema.json +33 -0
- package/schema/public/v1/handoff-receipt.deserialize.schema.json +66 -0
- package/schema/public/v1/handoff-receipt.serialize.schema.json +66 -0
- package/schema/public/v1/handoff.deserialize.schema.json +84 -0
- package/schema/public/v1/handoff.serialize.schema.json +84 -0
- package/schema/public/v1/observation-get-params.deserialize.schema.json +46 -0
- package/schema/public/v1/observation-get-params.serialize.schema.json +52 -0
- package/schema/public/v1/observation-get-response.deserialize.schema.json +2731 -0
- package/schema/public/v1/observation-get-response.serialize.schema.json +2862 -0
- package/schema/public/v1/observation-snapshot.deserialize.schema.json +2616 -0
- package/schema/public/v1/observation-snapshot.serialize.schema.json +2741 -0
- package/schema/public/v1/presence-answer.deserialize.schema.json +40 -0
- package/schema/public/v1/presence-answer.serialize.schema.json +40 -0
- package/schema/public/v1/presence-release.deserialize.schema.json +51 -0
- package/schema/public/v1/presence-release.serialize.schema.json +52 -0
- package/schema/public/v1/presence-report.deserialize.schema.json +149 -0
- package/schema/public/v1/presence-report.serialize.schema.json +157 -0
- package/extension/radar-session-marker.ts +0 -146
- package/schema/public/v1/launch-identity-marker.deserialize.schema.json +0 -32
- package/schema/public/v1/launch-identity-marker.serialize.schema.json +0 -32
|
@@ -15,6 +15,7 @@ var RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
|
15
15
|
var RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
16
16
|
var RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
17
17
|
var RADAR_EVENTS_CONTRACT = "events.v1";
|
|
18
|
+
var RADAR_COMMUNICATION_CONTRACT = "communication.handoff.v1";
|
|
18
19
|
var RADAR_REQUESTER = "pi-radar";
|
|
19
20
|
var RADAR_MAX_LINE_BYTES = 1024 * 1024;
|
|
20
21
|
var RADAR_CALL_TIMEOUT_MS = 2e3;
|
|
@@ -112,6 +113,25 @@ function recordAt(value, field) {
|
|
|
112
113
|
function isUuid(value) {
|
|
113
114
|
return typeof value === "string" && UUID.test(value);
|
|
114
115
|
}
|
|
116
|
+
function decodePresenceAnswer(value) {
|
|
117
|
+
const registrationId = recordAt(value, "registration_id");
|
|
118
|
+
const claimId = recordAt(value, "claim_id");
|
|
119
|
+
const standing = recordAt(value, "standing");
|
|
120
|
+
const subjectId = recordAt(value, "subject_id");
|
|
121
|
+
if (!isUuid(registrationId) || !isUuid(claimId) || !["pending", "granted", "duplicate", "released"].includes(String(standing)) || subjectId !== void 0 && !isUuid(subjectId) || standing === "granted" && !isUuid(subjectId))
|
|
122
|
+
return protocol("presence reply carries no valid claim standing");
|
|
123
|
+
return { ok: true, value };
|
|
124
|
+
}
|
|
125
|
+
function managementAt(value) {
|
|
126
|
+
const field = recordAt(value, "management");
|
|
127
|
+
const state = stringAt(field, "state");
|
|
128
|
+
if (state === "managed") {
|
|
129
|
+
const subjectId = stringAt(field, "subject_id");
|
|
130
|
+
return subjectId === void 0 ? void 0 : { state, subject_id: subjectId };
|
|
131
|
+
}
|
|
132
|
+
if (state === "duplicate" || state === "pending" || state === "unmanaged") return { state };
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
115
135
|
function stringAt(value, field) {
|
|
116
136
|
if (typeof value !== "object" || value === null) return void 0;
|
|
117
137
|
const found = value[field];
|
|
@@ -122,6 +142,28 @@ function numberAt(value, field) {
|
|
|
122
142
|
const found = value[field];
|
|
123
143
|
return typeof found === "number" && Number.isFinite(found) ? found : void 0;
|
|
124
144
|
}
|
|
145
|
+
function handoffAt(value) {
|
|
146
|
+
const version = numberAt(value, "version");
|
|
147
|
+
const id = stringAt(value, "id");
|
|
148
|
+
const sender = recordAt(value, "sender");
|
|
149
|
+
const senderGeneration = numberAt(sender, "execution_generation");
|
|
150
|
+
const target = stringAt(value, "recipient_subject_id");
|
|
151
|
+
const summary = stringAt(value, "summary");
|
|
152
|
+
const content = stringAt(value, "content");
|
|
153
|
+
const published = numberAt(value, "published_at_unix_ms");
|
|
154
|
+
const correlation = typeof value === "object" && value !== null ? value.correlation_id : void 0;
|
|
155
|
+
if (version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "registration_id")) || !isUuid(stringAt(sender, "session_id")) || !isUuid(stringAt(sender, "subject_id")) || !isUuid(stringAt(sender, "execution_id")) || !Number.isSafeInteger(senderGeneration) || (senderGeneration ?? 0) < 1 || !isUuid(target) || summary === void 0 || content === void 0 || published === void 0 || !Number.isSafeInteger(published) || published < 0 || correlation !== void 0 && correlation !== null && (typeof correlation !== "string" || correlation.length === 0 || Buffer.byteLength(correlation, "utf8") > 256 || new RegExp("\\p{Cc}", "u").test(correlation))) return void 0;
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
function handoffReceiptAt(value) {
|
|
159
|
+
const version = numberAt(value, "version");
|
|
160
|
+
const handoffId = stringAt(value, "handoff_id");
|
|
161
|
+
const recipient = recordAt(value, "recipient");
|
|
162
|
+
const generation = numberAt(recipient, "execution_generation");
|
|
163
|
+
const received = numberAt(value, "received_at_unix_ms");
|
|
164
|
+
if (version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "registration_id")) || !isUuid(stringAt(recipient, "session_id")) || !isUuid(stringAt(recipient, "subject_id")) || !isUuid(stringAt(recipient, "execution_id")) || !Number.isSafeInteger(generation) || (generation ?? 0) < 1 || received === void 0 || !Number.isSafeInteger(received) || received < 0) return void 0;
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
125
167
|
function writerBinding(value) {
|
|
126
168
|
const handle = stringAt(value, "handle");
|
|
127
169
|
const source = stringAt(value, "source");
|
|
@@ -227,7 +269,8 @@ var RADAR_SPAWN_TOKEN_ENV = "PI_RADAR_SPAWN_TOKEN";
|
|
|
227
269
|
var RADAR_MANAGED_IDENTITY_ENV = /* @__PURE__ */ new Set([
|
|
228
270
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
229
271
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
230
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
272
|
+
"PI_RADAR_MANAGED_EXECUTION_GENERATION",
|
|
273
|
+
"PI_RADAR_MANAGED_PARENT_SUBJECT_ID"
|
|
231
274
|
]);
|
|
232
275
|
function unresolvedSpawn(requestId, detail) {
|
|
233
276
|
return {
|
|
@@ -272,7 +315,7 @@ function spawnEdge(value) {
|
|
|
272
315
|
const bound = recordAt(value, "bound");
|
|
273
316
|
const source = stringAt(bound, "source");
|
|
274
317
|
const incarnation = stringAt(bound, "incarnation");
|
|
275
|
-
const agentId = stringAt(bound, "
|
|
318
|
+
const agentId = stringAt(bound, "registration_id");
|
|
276
319
|
const exit = exitAt(recordAt(value, "exit_observation"));
|
|
277
320
|
return {
|
|
278
321
|
ok: true,
|
|
@@ -286,7 +329,7 @@ function spawnEdge(value) {
|
|
|
286
329
|
bound: {
|
|
287
330
|
source,
|
|
288
331
|
incarnation,
|
|
289
|
-
...isUuid(agentId) ? {
|
|
332
|
+
...isUuid(agentId) ? { registration_id: agentId } : {}
|
|
290
333
|
}
|
|
291
334
|
} : {},
|
|
292
335
|
...exit !== void 0 ? { exit_observation: exit } : {}
|
|
@@ -626,6 +669,22 @@ function createRadarClient(options = {}) {
|
|
|
626
669
|
return {
|
|
627
670
|
socketPath,
|
|
628
671
|
ping,
|
|
672
|
+
async presence(request) {
|
|
673
|
+
return withRegistry(async () => {
|
|
674
|
+
const answer = await call("agent.presence", { ...request });
|
|
675
|
+
if (!answer.ok) return answer;
|
|
676
|
+
return decodePresenceAnswer(answer.value);
|
|
677
|
+
});
|
|
678
|
+
},
|
|
679
|
+
async releasePresence(request) {
|
|
680
|
+
return withRegistry(async () => {
|
|
681
|
+
const answer = await call("agent.release", { ...request });
|
|
682
|
+
if (!answer.ok) return answer;
|
|
683
|
+
const decoded = decodePresenceAnswer(answer.value);
|
|
684
|
+
if (!decoded.ok) return decoded;
|
|
685
|
+
return decoded.value.standing === "released" ? decoded : protocol("release reply did not confirm the claim release");
|
|
686
|
+
});
|
|
687
|
+
},
|
|
629
688
|
async register(registration) {
|
|
630
689
|
return withRegistry(async () => {
|
|
631
690
|
const answer = await call("agent.register", {
|
|
@@ -641,15 +700,15 @@ function createRadarClient(options = {}) {
|
|
|
641
700
|
});
|
|
642
701
|
if (answer.ok === false) return answer;
|
|
643
702
|
const record = answer.value.registration;
|
|
644
|
-
const agentId = stringAt(record, "
|
|
645
|
-
if (!isUuid(agentId)) return protocol("registration reply carries no
|
|
646
|
-
return { ok: true, value: {
|
|
703
|
+
const agentId = stringAt(record, "registration_id");
|
|
704
|
+
if (!isUuid(agentId)) return protocol("registration reply carries no registration_id");
|
|
705
|
+
return { ok: true, value: { registration_id: agentId } };
|
|
647
706
|
});
|
|
648
707
|
},
|
|
649
708
|
async acquire(request) {
|
|
650
709
|
return withRegistryChannel(request.channel, async () => {
|
|
651
710
|
const answer = await call("agent.acquire", {
|
|
652
|
-
|
|
711
|
+
registration_id: request.registration_id,
|
|
653
712
|
channel: request.channel,
|
|
654
713
|
publisher: request.publisher,
|
|
655
714
|
...request.replace !== void 0 ? { replace: request.replace } : {}
|
|
@@ -678,7 +737,7 @@ function createRadarClient(options = {}) {
|
|
|
678
737
|
}
|
|
679
738
|
return withRegistryChannel(request.channel, async () => {
|
|
680
739
|
const answer = await call("agent.publish", {
|
|
681
|
-
|
|
740
|
+
registration_id: request.registration_id,
|
|
682
741
|
channel: request.channel,
|
|
683
742
|
writer_handle: request.writer_handle,
|
|
684
743
|
sequence: request.sequence,
|
|
@@ -697,7 +756,7 @@ function createRadarClient(options = {}) {
|
|
|
697
756
|
async context(request) {
|
|
698
757
|
return withRegistry(async () => {
|
|
699
758
|
const answer = await call("agent.context", {
|
|
700
|
-
|
|
759
|
+
registration_id: request.registration_id,
|
|
701
760
|
publisher: request.publisher,
|
|
702
761
|
...request.writer_handle !== void 0 ? { writer_handle: request.writer_handle } : {},
|
|
703
762
|
...request.replace !== void 0 ? { replace: request.replace } : {},
|
|
@@ -713,9 +772,14 @@ function createRadarClient(options = {}) {
|
|
|
713
772
|
if (writer === void 0)
|
|
714
773
|
return protocol("context reply carries no writer binding");
|
|
715
774
|
const warning = stringAt(answer.value, "warning");
|
|
775
|
+
const management = managementAt(answer.value);
|
|
716
776
|
return {
|
|
717
777
|
ok: true,
|
|
718
|
-
value: {
|
|
778
|
+
value: {
|
|
779
|
+
writer,
|
|
780
|
+
...warning !== void 0 ? { warning } : {},
|
|
781
|
+
...management !== void 0 ? { management } : {}
|
|
782
|
+
}
|
|
719
783
|
};
|
|
720
784
|
});
|
|
721
785
|
},
|
|
@@ -792,7 +856,7 @@ function createRadarClient(options = {}) {
|
|
|
792
856
|
message: "agent.get requires a canonical agent UUID"
|
|
793
857
|
};
|
|
794
858
|
return withRegistry(async () => {
|
|
795
|
-
const answer = await call("agent.get", {
|
|
859
|
+
const answer = await call("agent.get", { registration_id: agentId });
|
|
796
860
|
if (answer.ok === false) return answer;
|
|
797
861
|
return agentProcessAt(recordAt(answer.value, "agent"));
|
|
798
862
|
});
|
|
@@ -843,6 +907,56 @@ function createRadarClient(options = {}) {
|
|
|
843
907
|
return protocol("spawn.close reply carries no close outcome");
|
|
844
908
|
});
|
|
845
909
|
},
|
|
910
|
+
async communicationPublish(request) {
|
|
911
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
912
|
+
const answer = await call("communication.publish", {
|
|
913
|
+
sender_registration_id: request.sender_registration_id,
|
|
914
|
+
recipient_subject_id: request.recipient_subject_id,
|
|
915
|
+
...request.correlation_id !== void 0 ? { correlation_id: request.correlation_id } : {},
|
|
916
|
+
summary: request.summary,
|
|
917
|
+
content: request.content
|
|
918
|
+
}, request.request_id);
|
|
919
|
+
if (answer.ok === false) return answer;
|
|
920
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
921
|
+
const created = recordAt(answer.value, "created");
|
|
922
|
+
if (handoff === void 0 || typeof created !== "boolean")
|
|
923
|
+
return protocol("communication.publish reply carries no handoff");
|
|
924
|
+
return { ok: true, value: { handoff, created } };
|
|
925
|
+
});
|
|
926
|
+
},
|
|
927
|
+
async communicationInbox(request) {
|
|
928
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
929
|
+
const answer = await call("communication.inbox", request);
|
|
930
|
+
if (answer.ok === false) return answer;
|
|
931
|
+
const handoffIds = recordAt(answer.value, "handoff_ids");
|
|
932
|
+
if (!Array.isArray(handoffIds) || handoffIds.some((id) => !isUuid(id)))
|
|
933
|
+
return protocol("communication.inbox reply carries malformed handoff IDs");
|
|
934
|
+
return { ok: true, value: answer.value };
|
|
935
|
+
});
|
|
936
|
+
},
|
|
937
|
+
async communicationGet(request) {
|
|
938
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
939
|
+
const answer = await call("communication.get", request);
|
|
940
|
+
if (answer.ok === false) return answer;
|
|
941
|
+
const handoff = handoffAt(recordAt(answer.value, "handoff"));
|
|
942
|
+
const receiptValue = recordAt(answer.value, "receipt");
|
|
943
|
+
const receipt = receiptValue === null ? null : handoffReceiptAt(receiptValue);
|
|
944
|
+
if (handoff === void 0 || receiptValue !== null && receipt === void 0)
|
|
945
|
+
return protocol("communication.get reply carries malformed content or receipt");
|
|
946
|
+
return { ok: true, value: { handoff, receipt: receipt ?? null } };
|
|
947
|
+
});
|
|
948
|
+
},
|
|
949
|
+
async communicationAck(request) {
|
|
950
|
+
return withContract(RADAR_COMMUNICATION_CONTRACT, async () => {
|
|
951
|
+
const answer = await call("communication.ack", request);
|
|
952
|
+
if (answer.ok === false) return answer;
|
|
953
|
+
const receipt = handoffReceiptAt(recordAt(answer.value, "receipt"));
|
|
954
|
+
const created = recordAt(answer.value, "created");
|
|
955
|
+
if (receipt === void 0 || typeof created !== "boolean")
|
|
956
|
+
return protocol("communication.ack reply carries no receipt");
|
|
957
|
+
return { ok: true, value: { receipt, created } };
|
|
958
|
+
});
|
|
959
|
+
},
|
|
846
960
|
async events(request) {
|
|
847
961
|
if (!Number.isSafeInteger(request.after) || request.after < 0 || !Number.isSafeInteger(request.wait_ms) || request.wait_ms < 0 || request.wait_ms > RADAR_EVENT_WAIT_MS)
|
|
848
962
|
return {
|
|
@@ -1063,6 +1177,43 @@ function boundedRadarSnapshot(snapshot) {
|
|
|
1063
1177
|
};
|
|
1064
1178
|
}
|
|
1065
1179
|
|
|
1180
|
+
// extension/radar-communication.ts
|
|
1181
|
+
function createRadarHandoffPort(client, publication, parentSubjectId = () => process.env.PI_RADAR_MANAGED_PARENT_SUBJECT_ID) {
|
|
1182
|
+
async function agentId() {
|
|
1183
|
+
const subject = await publication.subject();
|
|
1184
|
+
return subject === void 0 ? { ok: false, code: "absent", message: "this process has no current Radar registration" } : { ok: true, value: subject.registration_id };
|
|
1185
|
+
}
|
|
1186
|
+
return {
|
|
1187
|
+
async publish(request) {
|
|
1188
|
+
const identity = await agentId();
|
|
1189
|
+
if (identity.ok === false) return identity;
|
|
1190
|
+
const parent = parentSubjectId();
|
|
1191
|
+
if (parent === void 0)
|
|
1192
|
+
return { ok: false, code: "absent", message: "this managed execution has no Radar parent subject" };
|
|
1193
|
+
return client.communicationPublish({
|
|
1194
|
+
...request,
|
|
1195
|
+
sender_registration_id: identity.value,
|
|
1196
|
+
recipient_subject_id: parent
|
|
1197
|
+
});
|
|
1198
|
+
},
|
|
1199
|
+
async inbox() {
|
|
1200
|
+
const identity = await agentId();
|
|
1201
|
+
if (identity.ok === false) return identity;
|
|
1202
|
+
return client.communicationInbox({ registration_id: identity.value });
|
|
1203
|
+
},
|
|
1204
|
+
async get(handoff_id) {
|
|
1205
|
+
const identity = await agentId();
|
|
1206
|
+
if (identity.ok === false) return identity;
|
|
1207
|
+
return client.communicationGet({ registration_id: identity.value, handoff_id });
|
|
1208
|
+
},
|
|
1209
|
+
async ack(handoff_id) {
|
|
1210
|
+
const identity = await agentId();
|
|
1211
|
+
if (identity.ok === false) return identity;
|
|
1212
|
+
return client.communicationAck({ registration_id: identity.value, handoff_id });
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1066
1217
|
// extension/radar-publication.ts
|
|
1067
1218
|
import { createHash, randomUUID as randomUUID2 } from "node:crypto";
|
|
1068
1219
|
import {
|
|
@@ -1079,77 +1230,7 @@ import {
|
|
|
1079
1230
|
writeSync
|
|
1080
1231
|
} from "node:fs";
|
|
1081
1232
|
import { dirname as dirname2, join as join2, parse, resolve, sep } from "node:path";
|
|
1082
|
-
|
|
1083
|
-
// extension/radar-session-marker.ts
|
|
1084
|
-
var RADAR_LAUNCH_MARKER_TYPE = "pi-radar.launch-identity";
|
|
1085
|
-
var RADAR_LAUNCH_MARKER_VERSION = 1;
|
|
1086
|
-
var RADAR_MAX_EXECUTION_GENERATION = 4294967295;
|
|
1087
|
-
var RADAR_MANAGED_SUBJECT_ENV = "PI_RADAR_MANAGED_SUBJECT_ID";
|
|
1088
|
-
var RADAR_MANAGED_LAUNCH_ENV = "PI_RADAR_MANAGED_LAUNCH_ID";
|
|
1089
|
-
var RADAR_MANAGED_GENERATION_ENV = "PI_RADAR_MANAGED_EXECUTION_GENERATION";
|
|
1090
|
-
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
1091
|
-
function decodeRadarLaunchMarker(value) {
|
|
1092
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
1093
|
-
const record = value;
|
|
1094
|
-
if (Object.keys(record).sort().join(",") !== "execution_generation,launch_id,subject_id,version") {
|
|
1095
|
-
return void 0;
|
|
1096
|
-
}
|
|
1097
|
-
if (record.version !== RADAR_LAUNCH_MARKER_VERSION || typeof record.subject_id !== "string" || !UUID2.test(record.subject_id) || typeof record.launch_id !== "string" || !UUID2.test(record.launch_id) || !Number.isSafeInteger(record.execution_generation) || record.execution_generation < 1 || record.execution_generation > RADAR_MAX_EXECUTION_GENERATION) {
|
|
1098
|
-
return void 0;
|
|
1099
|
-
}
|
|
1100
|
-
return {
|
|
1101
|
-
version: RADAR_LAUNCH_MARKER_VERSION,
|
|
1102
|
-
subject_id: record.subject_id,
|
|
1103
|
-
launch_id: record.launch_id,
|
|
1104
|
-
execution_generation: record.execution_generation
|
|
1105
|
-
};
|
|
1106
|
-
}
|
|
1107
|
-
function appendRadarLaunchMarker(appendEntry, marker) {
|
|
1108
|
-
const validated = decodeRadarLaunchMarker(marker);
|
|
1109
|
-
if (!validated) throw new Error("invalid Radar launch identity marker");
|
|
1110
|
-
appendEntry(RADAR_LAUNCH_MARKER_TYPE, validated);
|
|
1111
|
-
}
|
|
1112
|
-
function latestRadarLaunchMarker(branch) {
|
|
1113
|
-
let latest;
|
|
1114
|
-
for (const entry of branch) {
|
|
1115
|
-
if (entry.type === "custom" && entry.customType === RADAR_LAUNCH_MARKER_TYPE) {
|
|
1116
|
-
latest = entry;
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
if (!latest) return { status: "absent" };
|
|
1120
|
-
const marker = decodeRadarLaunchMarker(latest.data);
|
|
1121
|
-
return marker ? { status: "valid", marker } : { status: "invalid" };
|
|
1122
|
-
}
|
|
1123
|
-
function radarLaunchMarkerFromEnvironment(env = process.env) {
|
|
1124
|
-
const rawGeneration = env[RADAR_MANAGED_GENERATION_ENV];
|
|
1125
|
-
if (env[RADAR_MANAGED_SUBJECT_ENV] === void 0 || env[RADAR_MANAGED_LAUNCH_ENV] === void 0 || rawGeneration === void 0 || !/^[1-9][0-9]*$/.test(rawGeneration)) {
|
|
1126
|
-
return void 0;
|
|
1127
|
-
}
|
|
1128
|
-
return decodeRadarLaunchMarker({
|
|
1129
|
-
version: RADAR_LAUNCH_MARKER_VERSION,
|
|
1130
|
-
subject_id: env[RADAR_MANAGED_SUBJECT_ENV],
|
|
1131
|
-
launch_id: env[RADAR_MANAGED_LAUNCH_ENV],
|
|
1132
|
-
execution_generation: Number(rawGeneration)
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
function activeRadarLaunchMarker(host) {
|
|
1136
|
-
if (!host.sessionManager) return { status: "absent" };
|
|
1137
|
-
return latestRadarLaunchMarker(host.sessionManager.getBranch());
|
|
1138
|
-
}
|
|
1139
|
-
function persistRadarLaunchMarker(host, env = process.env) {
|
|
1140
|
-
const marker = radarLaunchMarkerFromEnvironment(env);
|
|
1141
|
-
if (!marker) return "absent";
|
|
1142
|
-
if (!host.appendEntry || !host.sessionManager) return "unsupported";
|
|
1143
|
-
const current = latestRadarLaunchMarker(host.sessionManager.getBranch());
|
|
1144
|
-
if (current.status === "valid" && sameMarker(current.marker, marker)) return "unchanged";
|
|
1145
|
-
appendRadarLaunchMarker(host.appendEntry, marker);
|
|
1146
|
-
return "written";
|
|
1147
|
-
}
|
|
1148
|
-
function sameMarker(a, b) {
|
|
1149
|
-
return a.version === b.version && a.subject_id === b.subject_id && a.launch_id === b.launch_id && a.execution_generation === b.execution_generation;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
// extension/radar-publication.ts
|
|
1233
|
+
var DUPLICATE_SESSION_DIAGNOSTIC = "Radar rejected this session claim as a duplicate; reload or resume the session before retrying";
|
|
1153
1234
|
var RADAR_PUBLICATION_VERSION = 1;
|
|
1154
1235
|
var RADAR_LEASE_MS = 3e4;
|
|
1155
1236
|
var RADAR_HEARTBEAT_MS = 15e3;
|
|
@@ -1174,7 +1255,7 @@ function readProcessBirth() {
|
|
|
1174
1255
|
return void 0;
|
|
1175
1256
|
}
|
|
1176
1257
|
}
|
|
1177
|
-
var RECORD_NAME = /^(?:subjects|channels|context|bindings)\/[a-z0-9-]{1,64}\.json$/;
|
|
1258
|
+
var RECORD_NAME = /^(?:registrations|presence|subjects|channels|context|bindings)\/[a-z0-9-]{1,64}\.json$/;
|
|
1178
1259
|
var MAX_RECORD_BYTES = 64 * 1024;
|
|
1179
1260
|
var PRIVATE_MODE = 448;
|
|
1180
1261
|
var RECORD_MODE = 384;
|
|
@@ -1456,39 +1537,6 @@ function pendingAt(value, keys = PENDING_KEYS, codec = executionCodec) {
|
|
|
1456
1537
|
return void 0;
|
|
1457
1538
|
return { sequence, snapshot, lease_ms: lease, observed_at: observed };
|
|
1458
1539
|
}
|
|
1459
|
-
var CONTEXT_PENDING_KEYS = "lease_ms,observed_at,sequence,session";
|
|
1460
|
-
var CONTEXT_PENDING_MARKED_KEYS = "launch_identity,lease_ms,observed_at,sequence,session";
|
|
1461
|
-
var CONTEXT_ACCEPTED_KEYS = "lease_ms,observed_at,sent_at,sequence,session";
|
|
1462
|
-
var CONTEXT_ACCEPTED_MARKED_KEYS = "launch_identity,lease_ms,observed_at,sent_at,sequence,session";
|
|
1463
|
-
function sessionAt(value) {
|
|
1464
|
-
if (typeof value !== "object" || value === null) return void 0;
|
|
1465
|
-
const found = value.session;
|
|
1466
|
-
if (found === null) return null;
|
|
1467
|
-
return typeof found === "string" ? found : void 0;
|
|
1468
|
-
}
|
|
1469
|
-
function sameLaunchIdentity(a, b) {
|
|
1470
|
-
return a === b || a !== void 0 && b !== void 0 && a.version === b.version && a.subject_id === b.subject_id && a.launch_id === b.launch_id && a.execution_generation === b.execution_generation;
|
|
1471
|
-
}
|
|
1472
|
-
function contextReportAt(value, keys, markedKeys) {
|
|
1473
|
-
const marked = exactKeys(value, markedKeys);
|
|
1474
|
-
if (!exactKeys(value, keys) && !marked) return void 0;
|
|
1475
|
-
const sequence = numberAt2(value, "sequence");
|
|
1476
|
-
const lease = numberAt2(value, "lease_ms");
|
|
1477
|
-
const observed = textAt(value, "observed_at");
|
|
1478
|
-
const session = sessionAt(value);
|
|
1479
|
-
if (sequence === void 0 || sequence < 1) return void 0;
|
|
1480
|
-
if (lease === void 0 || observed === void 0 || session === void 0)
|
|
1481
|
-
return void 0;
|
|
1482
|
-
const marker = marked ? decodeRadarLaunchMarker(value.launch_identity) : void 0;
|
|
1483
|
-
if (marked && marker === void 0) return void 0;
|
|
1484
|
-
return {
|
|
1485
|
-
sequence,
|
|
1486
|
-
session,
|
|
1487
|
-
lease_ms: lease,
|
|
1488
|
-
observed_at: observed,
|
|
1489
|
-
...marker !== void 0 ? { launch_identity: marker } : {}
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
1540
|
function createChannelWriter(input) {
|
|
1493
1541
|
const { store, client, scheduler, recordName, channel, publisher } = input;
|
|
1494
1542
|
const codec = input.codec ?? executionCodec;
|
|
@@ -1504,7 +1552,7 @@ function createChannelWriter(input) {
|
|
|
1504
1552
|
function blank(agentId) {
|
|
1505
1553
|
return {
|
|
1506
1554
|
version: RADAR_PUBLICATION_VERSION,
|
|
1507
|
-
|
|
1555
|
+
registration_id: agentId,
|
|
1508
1556
|
channel,
|
|
1509
1557
|
publisher,
|
|
1510
1558
|
sequence: 0
|
|
@@ -1512,7 +1560,7 @@ function createChannelWriter(input) {
|
|
|
1512
1560
|
}
|
|
1513
1561
|
function loadRecord() {
|
|
1514
1562
|
const value = store.read(recordName);
|
|
1515
|
-
const agentId = textAt(value, "
|
|
1563
|
+
const agentId = textAt(value, "registration_id");
|
|
1516
1564
|
const storedPublisher = recordAt2(value, "publisher");
|
|
1517
1565
|
if (numberAt2(value, "version") !== RADAR_PUBLICATION_VERSION || agentId === void 0 || !isUuid(agentId) || textAt(value, "channel") !== channel || textAt(storedPublisher, "source") !== publisher.source || textAt(storedPublisher, "incarnation") !== publisher.incarnation || textAt(storedPublisher, "reporting_owner") !== publisher.reporting_owner)
|
|
1518
1566
|
return blank("");
|
|
@@ -1527,7 +1575,7 @@ function createChannelWriter(input) {
|
|
|
1527
1575
|
const sentAt = numberAt2(acceptedValue, "sent_at");
|
|
1528
1576
|
return {
|
|
1529
1577
|
version: RADAR_PUBLICATION_VERSION,
|
|
1530
|
-
|
|
1578
|
+
registration_id: agentId,
|
|
1531
1579
|
channel,
|
|
1532
1580
|
publisher,
|
|
1533
1581
|
...handle !== void 0 && generation !== void 0 ? { writer: { handle, generation } } : {},
|
|
@@ -1568,12 +1616,12 @@ function createChannelWriter(input) {
|
|
|
1568
1616
|
if (record.writer !== void 0) return true;
|
|
1569
1617
|
const agentId = await input.subject(recovering);
|
|
1570
1618
|
if (agentId === void 0) return false;
|
|
1571
|
-
if (record.
|
|
1619
|
+
if (record.registration_id !== agentId) {
|
|
1572
1620
|
record = blank(agentId);
|
|
1573
1621
|
save();
|
|
1574
1622
|
}
|
|
1575
1623
|
const answer = await client.acquire({
|
|
1576
|
-
|
|
1624
|
+
registration_id: agentId,
|
|
1577
1625
|
channel,
|
|
1578
1626
|
publisher
|
|
1579
1627
|
});
|
|
@@ -1603,7 +1651,7 @@ function createChannelWriter(input) {
|
|
|
1603
1651
|
const writer = record.writer;
|
|
1604
1652
|
if (writer === void 0) return;
|
|
1605
1653
|
const answer = await client.publish({
|
|
1606
|
-
|
|
1654
|
+
registration_id: record.registration_id,
|
|
1607
1655
|
channel,
|
|
1608
1656
|
writer_handle: writer.handle,
|
|
1609
1657
|
sequence: pending.sequence,
|
|
@@ -1697,9 +1745,9 @@ function createChannelWriter(input) {
|
|
|
1697
1745
|
stopPump();
|
|
1698
1746
|
const writer = record.writer;
|
|
1699
1747
|
if (writer === void 0) return;
|
|
1700
|
-
const agentId = record.
|
|
1748
|
+
const agentId = record.registration_id;
|
|
1701
1749
|
try {
|
|
1702
|
-
void client.retire({
|
|
1750
|
+
void client.retire({ registration_id: agentId, channel, writer_handle: writer.handle }).then((answer) => {
|
|
1703
1751
|
if (answer.ok === true) {
|
|
1704
1752
|
try {
|
|
1705
1753
|
record.retired_at = new Date(scheduler.now()).toISOString();
|
|
@@ -1722,214 +1770,127 @@ function createChannelWriter(input) {
|
|
|
1722
1770
|
diagnostic: () => record.diagnostic
|
|
1723
1771
|
};
|
|
1724
1772
|
}
|
|
1725
|
-
function
|
|
1726
|
-
const { store, client, scheduler, recordName
|
|
1727
|
-
let
|
|
1728
|
-
let
|
|
1729
|
-
let
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
function blank(agentId) {
|
|
1737
|
-
return {
|
|
1738
|
-
version: RADAR_PUBLICATION_VERSION,
|
|
1739
|
-
agent_id: agentId,
|
|
1740
|
-
publisher,
|
|
1741
|
-
sequence: 0
|
|
1742
|
-
};
|
|
1743
|
-
}
|
|
1744
|
-
function loadRecord() {
|
|
1745
|
-
const value = store.read(recordName);
|
|
1746
|
-
const agentId = textAt(value, "agent_id");
|
|
1747
|
-
const storedPublisher = recordAt2(value, "publisher");
|
|
1748
|
-
if (numberAt2(value, "version") !== RADAR_PUBLICATION_VERSION || agentId === void 0 || !isUuid(agentId) && agentId !== "" || textAt(storedPublisher, "source") !== publisher.source || textAt(storedPublisher, "incarnation") !== publisher.incarnation || textAt(storedPublisher, "reporting_owner") !== publisher.reporting_owner)
|
|
1749
|
-
return blank("");
|
|
1750
|
-
const writer = recordAt2(value, "writer");
|
|
1751
|
-
const handle = textAt(writer, "handle");
|
|
1752
|
-
const generation = numberAt2(writer, "generation");
|
|
1753
|
-
if (writer !== void 0 && (!exactKeys(writer, WRITER_KEYS) || !isUuid(handle) || generation === void 0))
|
|
1754
|
-
return blank(agentId);
|
|
1755
|
-
const pending = contextReportAt(
|
|
1756
|
-
recordAt2(value, "pending"),
|
|
1757
|
-
CONTEXT_PENDING_KEYS,
|
|
1758
|
-
CONTEXT_PENDING_MARKED_KEYS
|
|
1759
|
-
);
|
|
1760
|
-
const acceptedValue = recordAt2(value, "accepted");
|
|
1761
|
-
const accepted = contextReportAt(
|
|
1762
|
-
acceptedValue,
|
|
1763
|
-
CONTEXT_ACCEPTED_KEYS,
|
|
1764
|
-
CONTEXT_ACCEPTED_MARKED_KEYS
|
|
1765
|
-
);
|
|
1766
|
-
const sentAt = numberAt2(acceptedValue, "sent_at");
|
|
1767
|
-
return {
|
|
1768
|
-
version: RADAR_PUBLICATION_VERSION,
|
|
1769
|
-
agent_id: agentId,
|
|
1770
|
-
publisher,
|
|
1771
|
-
...handle !== void 0 && generation !== void 0 ? { writer: { handle, generation } } : {},
|
|
1772
|
-
sequence: numberAt2(value, "sequence") ?? 0,
|
|
1773
|
-
...pending !== void 0 ? { pending } : {},
|
|
1774
|
-
...accepted !== void 0 && sentAt !== void 0 ? { accepted: { ...accepted, sent_at: sentAt } } : {},
|
|
1775
|
-
...textAt(value, "diagnostic") !== void 0 ? { diagnostic: textAt(value, "diagnostic") } : {}
|
|
1776
|
-
};
|
|
1777
|
-
}
|
|
1778
|
-
function note(message) {
|
|
1779
|
-
if (record.diagnostic !== void 0) return;
|
|
1780
|
-
record.diagnostic = message.slice(0, 256);
|
|
1781
|
-
save();
|
|
1773
|
+
function createPresenceReporter(input) {
|
|
1774
|
+
const { store, client, scheduler, recordName } = input;
|
|
1775
|
+
let state;
|
|
1776
|
+
let standing;
|
|
1777
|
+
let diagnostic;
|
|
1778
|
+
try {
|
|
1779
|
+
const saved = store.read(recordName);
|
|
1780
|
+
if (saved?.version === 2 && isUuid(saved.claim_id) && isUuid(saved.session) && Array.isArray(saved.releases))
|
|
1781
|
+
state = saved;
|
|
1782
|
+
} catch (error) {
|
|
1783
|
+
diagnostic = `presence storage unavailable: ${String(error)}`;
|
|
1782
1784
|
}
|
|
1785
|
+
let timer;
|
|
1786
|
+
let stopped = false;
|
|
1787
|
+
let running;
|
|
1783
1788
|
function save() {
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
function startPump() {
|
|
1792
|
-
if (pump !== void 0 || stopped || fenced) return;
|
|
1793
|
-
pump = scheduler.setInterval(() => kick(), input.heartbeatMs);
|
|
1794
|
-
pump.unref?.();
|
|
1795
|
-
}
|
|
1796
|
-
function stopPump() {
|
|
1797
|
-
if (pump === void 0) return;
|
|
1798
|
-
scheduler.clearInterval(pump);
|
|
1799
|
-
pump = void 0;
|
|
1789
|
+
try {
|
|
1790
|
+
if (state) store.write(recordName, state);
|
|
1791
|
+
return true;
|
|
1792
|
+
} catch (error) {
|
|
1793
|
+
diagnostic = `presence storage unavailable: ${String(error)}`;
|
|
1794
|
+
return false;
|
|
1795
|
+
}
|
|
1800
1796
|
}
|
|
1801
|
-
async function
|
|
1802
|
-
if (
|
|
1803
|
-
const
|
|
1804
|
-
if (
|
|
1805
|
-
|
|
1806
|
-
|
|
1797
|
+
async function releasePending() {
|
|
1798
|
+
if (!state) return;
|
|
1799
|
+
const registration = await input.registration();
|
|
1800
|
+
if (!registration?.process) return;
|
|
1801
|
+
for (const release of [...state.releases]) {
|
|
1802
|
+
const answer = await client.releasePresence({ ...release, process: registration.process });
|
|
1803
|
+
if (!answer.ok) return;
|
|
1804
|
+
state.releases = state.releases.filter((r) => r.claim_id !== release.claim_id);
|
|
1807
1805
|
save();
|
|
1808
1806
|
}
|
|
1809
|
-
return true;
|
|
1810
1807
|
}
|
|
1811
|
-
function
|
|
1812
|
-
|
|
1808
|
+
function schedule() {
|
|
1809
|
+
if (stopped || timer) return;
|
|
1810
|
+
timer = scheduler.setTimeout(() => {
|
|
1811
|
+
timer = void 0;
|
|
1812
|
+
void ensure();
|
|
1813
|
+
}, input.heartbeatMs);
|
|
1814
|
+
timer.unref?.();
|
|
1813
1815
|
}
|
|
1814
|
-
async function
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1816
|
+
async function ensure() {
|
|
1817
|
+
if (running) return running;
|
|
1818
|
+
if (stopped || !state) return void 0;
|
|
1819
|
+
const claim = state;
|
|
1820
|
+
if (!save()) return void 0;
|
|
1821
|
+
running = (async () => {
|
|
1822
|
+
await releasePending();
|
|
1823
|
+
const registration = await input.registration();
|
|
1824
|
+
if (!registration?.process || state !== claim || stopped) return void 0;
|
|
1825
|
+
const answer = await client.presence({
|
|
1826
|
+
...registration,
|
|
1827
|
+
process: registration.process,
|
|
1828
|
+
session_id: claim.session,
|
|
1829
|
+
claim_id: claim.claim_id,
|
|
1830
|
+
...claim.registration_id ? { registration_id: claim.registration_id } : {},
|
|
1831
|
+
...claim.subject_id ? { subject_id: claim.subject_id } : {}
|
|
1832
|
+
});
|
|
1833
|
+
if (state !== claim) return void 0;
|
|
1834
|
+
if (!answer.ok) {
|
|
1835
|
+
if (!["absent", "timeout", "transport"].includes(answer.code)) diagnostic = answer.message;
|
|
1836
|
+
return void 0;
|
|
1828
1837
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
handle: answer.value.writer.handle,
|
|
1834
|
-
generation: answer.value.writer.generation
|
|
1835
|
-
};
|
|
1836
|
-
record.sequence = Math.max(record.sequence, answer.value.writer.sequence);
|
|
1837
|
-
record.accepted = {
|
|
1838
|
-
...pending,
|
|
1839
|
-
sent_at: answer.value.warning === void 0 ? scheduler.now() : record.accepted?.sent_at ?? scheduler.now()
|
|
1840
|
-
};
|
|
1841
|
-
record.pending = void 0;
|
|
1838
|
+
claim.registration_id = answer.value.registration_id;
|
|
1839
|
+
claim.subject_id = answer.value.standing === "granted" ? answer.value.subject_id ?? void 0 : void 0;
|
|
1840
|
+
standing = answer.value.standing === "granted" ? { state: "managed", subject_id: claim.subject_id } : answer.value.standing === "duplicate" ? { state: "duplicate" } : answer.value.standing === "pending" ? { state: "pending" } : { state: "unmanaged" };
|
|
1841
|
+
diagnostic = answer.value.standing === "duplicate" ? DUPLICATE_SESSION_DIAGNOSTIC : void 0;
|
|
1842
1842
|
save();
|
|
1843
|
-
return;
|
|
1844
|
-
}
|
|
1845
|
-
if (answer.code === "refused" || answer.code === "bad_params" || // A daemon that speaks the registry but does not serve this record would
|
|
1846
|
-
// refuse every retry the same way; one diagnostic beats a silent retry
|
|
1847
|
-
// loop once per heartbeat.
|
|
1848
|
-
answer.code === "unknown_method") {
|
|
1849
|
-
fence(answer.message);
|
|
1850
|
-
return;
|
|
1851
|
-
}
|
|
1852
|
-
if (answer.code === "not_found") {
|
|
1853
|
-
record = blank("");
|
|
1854
|
-
recovering = true;
|
|
1855
|
-
save();
|
|
1856
|
-
return;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
async function stage(session, launchIdentity) {
|
|
1860
|
-
const pending = {
|
|
1861
|
-
sequence: record.sequence + 1,
|
|
1862
|
-
session,
|
|
1863
|
-
lease_ms: input.leaseMs,
|
|
1864
|
-
observed_at: new Date(scheduler.now()).toISOString(),
|
|
1865
|
-
...launchIdentity !== void 0 ? { launch_identity: launchIdentity } : {}
|
|
1866
|
-
};
|
|
1867
|
-
record.pending = pending;
|
|
1868
|
-
save();
|
|
1869
|
-
await send(pending);
|
|
1870
|
-
}
|
|
1871
|
-
async function drainOnce() {
|
|
1872
|
-
if (fenced) return;
|
|
1873
|
-
if (record.pending !== void 0) {
|
|
1874
|
-
await send(record.pending);
|
|
1875
|
-
return;
|
|
1876
|
-
}
|
|
1877
|
-
if (desired === void 0) return;
|
|
1878
|
-
if (!await ensureSubject()) return;
|
|
1879
|
-
if (fenced) return;
|
|
1880
|
-
if (record.writer === void 0 || record.accepted === void 0 || record.accepted.session !== desired || !sameLaunchIdentity(record.accepted.launch_identity, desiredMarker)) {
|
|
1881
|
-
await stage(desired, desiredMarker);
|
|
1882
|
-
return;
|
|
1883
|
-
}
|
|
1884
|
-
if (heartbeatDue()) await stage(record.accepted.session, desiredMarker);
|
|
1885
|
-
}
|
|
1886
|
-
async function drain() {
|
|
1887
|
-
if (running || stopped || fenced) return;
|
|
1888
|
-
running = true;
|
|
1843
|
+
return claim.registration_id;
|
|
1844
|
+
})();
|
|
1889
1845
|
try {
|
|
1890
|
-
await
|
|
1846
|
+
return await running;
|
|
1891
1847
|
} catch (error) {
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
try {
|
|
1895
|
-
note(`context storage failure: ${String(error).slice(0, 180)}`);
|
|
1896
|
-
} catch {
|
|
1897
|
-
}
|
|
1848
|
+
diagnostic = `presence unavailable: ${String(error)}`;
|
|
1849
|
+
return void 0;
|
|
1898
1850
|
} finally {
|
|
1899
|
-
running =
|
|
1900
|
-
if (
|
|
1901
|
-
|
|
1902
|
-
kick();
|
|
1903
|
-
}
|
|
1851
|
+
running = void 0;
|
|
1852
|
+
if (!stopped && state !== claim) void ensure();
|
|
1853
|
+
else schedule();
|
|
1904
1854
|
}
|
|
1905
1855
|
}
|
|
1906
|
-
function kick() {
|
|
1907
|
-
if (stopped || fenced) return;
|
|
1908
|
-
startPump();
|
|
1909
|
-
if (running) {
|
|
1910
|
-
again = true;
|
|
1911
|
-
return;
|
|
1912
|
-
}
|
|
1913
|
-
void drain().catch(() => void 0);
|
|
1914
|
-
}
|
|
1915
1856
|
return {
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1857
|
+
report(session) {
|
|
1858
|
+
const releases = [...state?.releases ?? []];
|
|
1859
|
+
if (state?.registration_id && !releases.some((release) => release.claim_id === state.claim_id)) {
|
|
1860
|
+
releases.push({ registration_id: state.registration_id, claim_id: state.claim_id });
|
|
1861
|
+
}
|
|
1862
|
+
standing = void 0;
|
|
1863
|
+
state = { version: 2, session, claim_id: randomUUID2(), releases };
|
|
1864
|
+
save();
|
|
1865
|
+
stopped = false;
|
|
1866
|
+
void ensure();
|
|
1867
|
+
},
|
|
1868
|
+
ensure,
|
|
1869
|
+
async release() {
|
|
1870
|
+
const releasing = state;
|
|
1871
|
+
standing = void 0;
|
|
1872
|
+
stopped = true;
|
|
1873
|
+
if (timer) scheduler.clearTimeout(timer);
|
|
1874
|
+
timer = void 0;
|
|
1875
|
+
if (running) await running;
|
|
1876
|
+
if (state === releasing) standing = void 0;
|
|
1877
|
+
if (releasing?.registration_id && !releasing.releases.some((r) => r.claim_id === releasing.claim_id)) {
|
|
1878
|
+
releasing.releases.push({ registration_id: releasing.registration_id, claim_id: releasing.claim_id });
|
|
1879
|
+
if (!save()) return;
|
|
1880
|
+
}
|
|
1881
|
+
await releasePending();
|
|
1923
1882
|
},
|
|
1924
1883
|
stop() {
|
|
1925
1884
|
stopped = true;
|
|
1926
|
-
|
|
1885
|
+
if (timer) scheduler.clearTimeout(timer);
|
|
1886
|
+
timer = void 0;
|
|
1927
1887
|
},
|
|
1928
1888
|
reopen() {
|
|
1929
1889
|
stopped = false;
|
|
1930
|
-
|
|
1890
|
+
void ensure();
|
|
1931
1891
|
},
|
|
1932
|
-
|
|
1892
|
+
management: () => standing,
|
|
1893
|
+
diagnostic: () => diagnostic
|
|
1933
1894
|
};
|
|
1934
1895
|
}
|
|
1935
1896
|
var STORE_IDENTITY = /* @__PURE__ */ new WeakMap();
|
|
@@ -1958,10 +1919,13 @@ function unavailablePublication(error) {
|
|
|
1958
1919
|
};
|
|
1959
1920
|
return {
|
|
1960
1921
|
execution: writer,
|
|
1961
|
-
|
|
1962
|
-
|
|
1922
|
+
presence: {
|
|
1923
|
+
report: () => void 0,
|
|
1924
|
+
ensure: async () => void 0,
|
|
1925
|
+
release: async () => void 0,
|
|
1963
1926
|
stop: () => void 0,
|
|
1964
1927
|
reopen: () => void 0,
|
|
1928
|
+
management: () => void 0,
|
|
1965
1929
|
diagnostic: () => diagnostic
|
|
1966
1930
|
},
|
|
1967
1931
|
facts: { ...writer, update: () => void 0 },
|
|
@@ -1988,33 +1952,29 @@ function createRadarPublicationInner(options) {
|
|
|
1988
1952
|
cached.reopen();
|
|
1989
1953
|
return cached;
|
|
1990
1954
|
}
|
|
1991
|
-
const
|
|
1955
|
+
const registrationName = `registrations/${createHash("sha256").update(`${options.registration.source}\0${incarnation}`).digest("hex").slice(0, 32)}.json`;
|
|
1992
1956
|
const channelRecord = (channel, target) => `channels/${createHash("sha256").update(`${channel}\0${incarnation}\0${target ?? ""}`).digest("hex").slice(0, 32)}.json`;
|
|
1993
|
-
const
|
|
1994
|
-
function
|
|
1995
|
-
const value = store.read(
|
|
1957
|
+
const presenceRecord = `presence/${createHash("sha256").update(`presence\0${incarnation}`).digest("hex").slice(0, 32)}.json`;
|
|
1958
|
+
function readRegistration() {
|
|
1959
|
+
const value = store.read(registrationName);
|
|
1996
1960
|
const registration = recordAt2(value, "registration");
|
|
1997
1961
|
if (numberAt2(value, "version") !== RADAR_PUBLICATION_VERSION || textAt(registration, "source") !== options.registration.source || textAt(registration, "incarnation") !== incarnation)
|
|
1998
1962
|
return void 0;
|
|
1999
|
-
const storedAgentId = textAt(value, "
|
|
1963
|
+
const storedAgentId = textAt(value, "registration_id");
|
|
2000
1964
|
return {
|
|
2001
1965
|
version: RADAR_PUBLICATION_VERSION,
|
|
2002
1966
|
registration,
|
|
2003
|
-
...storedAgentId !== void 0 && isUuid(storedAgentId) ? {
|
|
1967
|
+
...storedAgentId !== void 0 && isUuid(storedAgentId) ? { registration_id: storedAgentId } : {}
|
|
2004
1968
|
};
|
|
2005
1969
|
}
|
|
2006
|
-
const stored =
|
|
2007
|
-
let
|
|
1970
|
+
const stored = readRegistration();
|
|
1971
|
+
let processRecord = stored;
|
|
2008
1972
|
let registrationDiagnostic;
|
|
2009
1973
|
let registrationRecord;
|
|
2010
1974
|
async function ensureRegistration() {
|
|
2011
|
-
if (
|
|
1975
|
+
if (processRecord !== void 0) return processRecord;
|
|
2012
1976
|
registrationRecord ??= (async () => {
|
|
2013
1977
|
const resolution = options.location ? await options.location() : { state: "absent", reason: "this process publishes no location" };
|
|
2014
|
-
if (resolution.state === "pending") {
|
|
2015
|
-
registrationDiagnostic = `location bootstrap pending: ${resolution.reason}`.slice(0, 256);
|
|
2016
|
-
return void 0;
|
|
2017
|
-
}
|
|
2018
1978
|
const built = {
|
|
2019
1979
|
version: RADAR_PUBLICATION_VERSION,
|
|
2020
1980
|
registration: {
|
|
@@ -2025,13 +1985,13 @@ function createRadarPublicationInner(options) {
|
|
|
2025
1985
|
}
|
|
2026
1986
|
};
|
|
2027
1987
|
try {
|
|
2028
|
-
store.write(
|
|
1988
|
+
store.write(registrationName, built);
|
|
2029
1989
|
} catch (error) {
|
|
2030
1990
|
registrationDiagnostic ??= `private storage unavailable: ${String(error)}`.slice(0, 256);
|
|
2031
1991
|
return void 0;
|
|
2032
1992
|
}
|
|
2033
1993
|
registrationDiagnostic = void 0;
|
|
2034
|
-
|
|
1994
|
+
processRecord = built;
|
|
2035
1995
|
return built;
|
|
2036
1996
|
})();
|
|
2037
1997
|
try {
|
|
@@ -2040,11 +2000,10 @@ function createRadarPublicationInner(options) {
|
|
|
2040
2000
|
registrationRecord = void 0;
|
|
2041
2001
|
}
|
|
2042
2002
|
}
|
|
2043
|
-
let agentId = stored?.
|
|
2003
|
+
let agentId = stored?.registration_id;
|
|
2044
2004
|
let subjectReady;
|
|
2045
2005
|
async function ensureSubject(recheck) {
|
|
2046
|
-
if (recheck
|
|
2047
|
-
if (agentId !== void 0) return agentId;
|
|
2006
|
+
if (!recheck && agentId !== void 0) return agentId;
|
|
2048
2007
|
subjectReady ??= (async () => {
|
|
2049
2008
|
const ready = await client.ping();
|
|
2050
2009
|
if (ready.ok === false) {
|
|
@@ -2054,18 +2013,11 @@ function createRadarPublicationInner(options) {
|
|
|
2054
2013
|
}
|
|
2055
2014
|
const record = await ensureRegistration();
|
|
2056
2015
|
if (record === void 0) return void 0;
|
|
2057
|
-
const
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
}
|
|
2061
|
-
|
|
2062
|
-
if (answer.code !== "absent" && answer.code !== "timeout" && answer.code !== "transport")
|
|
2063
|
-
registrationDiagnostic ??= `subject registration refused: ${answer.message}`.slice(0, 256);
|
|
2064
|
-
return void 0;
|
|
2065
|
-
}
|
|
2066
|
-
agentId = answer.value.agent_id;
|
|
2067
|
-
subject = { ...record, agent_id: agentId };
|
|
2068
|
-
store.write(subjectName, subject);
|
|
2016
|
+
const registered = await presence.ensure();
|
|
2017
|
+
if (registered === void 0) return void 0;
|
|
2018
|
+
agentId = registered;
|
|
2019
|
+
processRecord = { ...record, registration_id: agentId };
|
|
2020
|
+
store.write(registrationName, processRecord);
|
|
2069
2021
|
if (options.binding !== void 0) writeBinding(options.binding);
|
|
2070
2022
|
return agentId;
|
|
2071
2023
|
})();
|
|
@@ -2079,7 +2031,7 @@ function createRadarPublicationInner(options) {
|
|
|
2079
2031
|
if (agentId === void 0) return;
|
|
2080
2032
|
store.write(`bindings/${binding.key}.json`, {
|
|
2081
2033
|
version: RADAR_PUBLICATION_VERSION,
|
|
2082
|
-
|
|
2034
|
+
registration_id: agentId,
|
|
2083
2035
|
incarnation,
|
|
2084
2036
|
run: binding.run,
|
|
2085
2037
|
owner: binding.owner,
|
|
@@ -2103,14 +2055,22 @@ function createRadarPublicationInner(options) {
|
|
|
2103
2055
|
leaseMs: options.leaseMs ?? RADAR_LEASE_MS,
|
|
2104
2056
|
heartbeatMs: options.heartbeatMs ?? RADAR_HEARTBEAT_MS
|
|
2105
2057
|
});
|
|
2106
|
-
const
|
|
2058
|
+
const presence = createPresenceReporter({
|
|
2107
2059
|
store,
|
|
2108
2060
|
client,
|
|
2109
2061
|
scheduler,
|
|
2110
|
-
recordName:
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2062
|
+
recordName: presenceRecord,
|
|
2063
|
+
registration: async () => {
|
|
2064
|
+
const record = await ensureRegistration();
|
|
2065
|
+
if (!record) return void 0;
|
|
2066
|
+
const location = await options.location?.();
|
|
2067
|
+
const { location: _initialLocation, ...identity } = record.registration;
|
|
2068
|
+
return {
|
|
2069
|
+
...identity,
|
|
2070
|
+
...location?.state === "resolved" ? { location: location.location } : {},
|
|
2071
|
+
...spawnToken ? { spawn_token: spawnToken } : {}
|
|
2072
|
+
};
|
|
2073
|
+
},
|
|
2114
2074
|
heartbeatMs: options.heartbeatMs ?? RADAR_HEARTBEAT_MS
|
|
2115
2075
|
});
|
|
2116
2076
|
const facts = createChannelWriter({
|
|
@@ -2128,7 +2088,7 @@ function createRadarPublicationInner(options) {
|
|
|
2128
2088
|
const assignmentWriters = /* @__PURE__ */ new Map();
|
|
2129
2089
|
const publication = {
|
|
2130
2090
|
execution,
|
|
2131
|
-
|
|
2091
|
+
presence,
|
|
2132
2092
|
facts,
|
|
2133
2093
|
assignment(target, reportingOwner) {
|
|
2134
2094
|
const existing = assignmentWriters.get(target);
|
|
@@ -2143,7 +2103,7 @@ function createRadarPublicationInner(options) {
|
|
|
2143
2103
|
publisher: publisher("herdsman-owner", reportingOwner),
|
|
2144
2104
|
codec: assignmentCodec,
|
|
2145
2105
|
// The owner publishes about a subject it did not register: the exact
|
|
2146
|
-
//
|
|
2106
|
+
// registration_id from the child's sidecar is the whole correlation.
|
|
2147
2107
|
subject: async () => target,
|
|
2148
2108
|
leaseMs: options.leaseMs ?? RADAR_LEASE_MS,
|
|
2149
2109
|
heartbeatMs: options.heartbeatMs ?? RADAR_HEARTBEAT_MS
|
|
@@ -2163,7 +2123,7 @@ function createRadarPublicationInner(options) {
|
|
|
2163
2123
|
registrationDiagnostic ??= `Radar binding unavailable: ${String(error).slice(0, 180)}`;
|
|
2164
2124
|
return void 0;
|
|
2165
2125
|
}
|
|
2166
|
-
const bound = textAt(value, "
|
|
2126
|
+
const bound = textAt(value, "registration_id");
|
|
2167
2127
|
const boundIncarnation = textAt(value, "incarnation");
|
|
2168
2128
|
const run = textAt(value, "run");
|
|
2169
2129
|
const owner = textAt(value, "owner");
|
|
@@ -2173,7 +2133,7 @@ function createRadarPublicationInner(options) {
|
|
|
2173
2133
|
return void 0;
|
|
2174
2134
|
return {
|
|
2175
2135
|
version: RADAR_PUBLICATION_VERSION,
|
|
2176
|
-
|
|
2136
|
+
registration_id: bound,
|
|
2177
2137
|
incarnation: boundIncarnation,
|
|
2178
2138
|
run,
|
|
2179
2139
|
owner,
|
|
@@ -2189,23 +2149,27 @@ function createRadarPublicationInner(options) {
|
|
|
2189
2149
|
if (agentId2 === void 0) return void 0;
|
|
2190
2150
|
const record = await ensureRegistration();
|
|
2191
2151
|
if (record === void 0) return void 0;
|
|
2192
|
-
const
|
|
2152
|
+
const currentLocation = await options.location?.();
|
|
2153
|
+
const location = currentLocation?.state === "resolved" ? currentLocation.location : void 0;
|
|
2154
|
+
const standing = presence.management();
|
|
2155
|
+
const subjectId = standing?.state === "managed" ? standing.subject_id : void 0;
|
|
2193
2156
|
return {
|
|
2194
|
-
|
|
2157
|
+
registration_id: agentId2,
|
|
2158
|
+
...subjectId !== void 0 ? { subject_id: subjectId } : {},
|
|
2195
2159
|
...location !== void 0 ? { location } : {}
|
|
2196
2160
|
};
|
|
2197
2161
|
},
|
|
2198
|
-
diagnostic: () => registrationDiagnostic ?? execution.diagnostic() ??
|
|
2162
|
+
diagnostic: () => registrationDiagnostic ?? execution.diagnostic() ?? presence.diagnostic() ?? facts.diagnostic(),
|
|
2199
2163
|
stop() {
|
|
2200
2164
|
for (const writer of assignmentWriters.values()) writer.stop();
|
|
2201
2165
|
execution.stop();
|
|
2202
|
-
|
|
2166
|
+
presence.stop();
|
|
2203
2167
|
facts.stop();
|
|
2204
2168
|
},
|
|
2205
2169
|
reopen() {
|
|
2206
2170
|
for (const writer of assignmentWriters.values()) writer.reopen();
|
|
2207
2171
|
execution.reopen();
|
|
2208
|
-
|
|
2172
|
+
presence.reopen();
|
|
2209
2173
|
facts.reopen();
|
|
2210
2174
|
}
|
|
2211
2175
|
};
|
|
@@ -2237,10 +2201,13 @@ function unavailablePublication2() {
|
|
|
2237
2201
|
return {
|
|
2238
2202
|
execution: writer,
|
|
2239
2203
|
facts: { ...writer, update: () => void 0 },
|
|
2240
|
-
|
|
2241
|
-
|
|
2204
|
+
presence: {
|
|
2205
|
+
report: () => void 0,
|
|
2242
2206
|
stop: () => void 0,
|
|
2243
2207
|
reopen: () => void 0,
|
|
2208
|
+
management: () => void 0,
|
|
2209
|
+
ensure: async () => void 0,
|
|
2210
|
+
release: async () => void 0,
|
|
2244
2211
|
diagnostic: () => "Radar private storage is unavailable"
|
|
2245
2212
|
},
|
|
2246
2213
|
assignment: () => writer,
|
|
@@ -2323,11 +2290,11 @@ function createRadarExecutionAdapter(pi, options) {
|
|
|
2323
2290
|
...lastOutcome !== void 0 ? { last_outcome: lastOutcome } : {}
|
|
2324
2291
|
};
|
|
2325
2292
|
}
|
|
2326
|
-
function reportSession(context
|
|
2293
|
+
function reportSession(context) {
|
|
2327
2294
|
const session = context?.sessionManager?.getSessionId?.();
|
|
2328
2295
|
if (!isUuid(session)) return;
|
|
2329
2296
|
try {
|
|
2330
|
-
publication.
|
|
2297
|
+
publication.presence.report(session);
|
|
2331
2298
|
} catch {
|
|
2332
2299
|
}
|
|
2333
2300
|
}
|
|
@@ -2391,38 +2358,8 @@ function createRadarExecutionAdapter(pi, options) {
|
|
|
2391
2358
|
})
|
|
2392
2359
|
);
|
|
2393
2360
|
on("session_start", (_event, context) => {
|
|
2394
|
-
const sessionHost = {
|
|
2395
|
-
appendEntry: pi.appendEntry ? (customType, data) => pi.appendEntry?.(customType, data) : void 0,
|
|
2396
|
-
sessionManager: context?.sessionManager
|
|
2397
|
-
};
|
|
2398
|
-
let launchIdentity;
|
|
2399
|
-
try {
|
|
2400
|
-
const result = persistRadarLaunchMarker(
|
|
2401
|
-
sessionHost,
|
|
2402
|
-
options.markerEnvironment
|
|
2403
|
-
);
|
|
2404
|
-
if (result === "written" || result === "unchanged") {
|
|
2405
|
-
const expected = radarLaunchMarkerFromEnvironment(options.markerEnvironment);
|
|
2406
|
-
const activeMarker = activeRadarLaunchMarker(sessionHost);
|
|
2407
|
-
if (expected && activeMarker.status === "valid" && JSON.stringify(activeMarker.marker) === JSON.stringify(expected)) {
|
|
2408
|
-
launchIdentity = activeMarker.marker;
|
|
2409
|
-
} else {
|
|
2410
|
-
options.diagnostic?.("Radar launch marker was not visible on the active Pi session branch");
|
|
2411
|
-
}
|
|
2412
|
-
} else if (result === "unsupported") {
|
|
2413
|
-
options.diagnostic?.("Pi host does not support Radar launch identity session entries");
|
|
2414
|
-
} else if (options.markerEnvironment && [
|
|
2415
|
-
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
2416
|
-
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
2417
|
-
"PI_RADAR_MANAGED_EXECUTION_GENERATION"
|
|
2418
|
-
].some((key) => options.markerEnvironment?.[key] !== void 0)) {
|
|
2419
|
-
options.diagnostic?.("incomplete or invalid Radar launch identity environment");
|
|
2420
|
-
}
|
|
2421
|
-
} catch (error) {
|
|
2422
|
-
options.diagnostic?.(`could not persist Radar launch marker: ${String(error)}`);
|
|
2423
|
-
}
|
|
2424
2361
|
rootSession = true;
|
|
2425
|
-
reportSession(context
|
|
2362
|
+
reportSession(context);
|
|
2426
2363
|
publishFacts(context);
|
|
2427
2364
|
publication.reopen();
|
|
2428
2365
|
active = context?.isIdle?.() === false;
|
|
@@ -2453,8 +2390,9 @@ function createRadarExecutionAdapter(pi, options) {
|
|
|
2453
2390
|
}
|
|
2454
2391
|
emit();
|
|
2455
2392
|
});
|
|
2456
|
-
on("session_shutdown", () => {
|
|
2393
|
+
on("session_shutdown", async () => {
|
|
2457
2394
|
suspend();
|
|
2395
|
+
await publication.presence.release();
|
|
2458
2396
|
});
|
|
2459
2397
|
function suspend() {
|
|
2460
2398
|
if (stopped) return;
|
|
@@ -2589,7 +2527,7 @@ async function resolveRadarProcessLocation(client, env = process.env) {
|
|
|
2589
2527
|
|
|
2590
2528
|
// extension/radar-runtime.ts
|
|
2591
2529
|
var RADAR_RUNTIME_REQUEST = "pi-radar/runtime-request";
|
|
2592
|
-
var RADAR_RUNTIME_VERSION =
|
|
2530
|
+
var RADAR_RUNTIME_VERSION = 2;
|
|
2593
2531
|
function lazyRadarRuntime(start) {
|
|
2594
2532
|
let pending;
|
|
2595
2533
|
return {
|
|
@@ -2617,6 +2555,7 @@ function registerPiRadar(pi) {
|
|
|
2617
2555
|
});
|
|
2618
2556
|
const runtime = lazyRadarRuntime(async () => ({
|
|
2619
2557
|
publication: execution.publication,
|
|
2558
|
+
communication: createRadarHandoffPort(client, execution.publication),
|
|
2620
2559
|
execution
|
|
2621
2560
|
}));
|
|
2622
2561
|
provideRadarRuntime(pi.events, runtime);
|