camstack 1.2.47 → 1.2.48
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.
|
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
|
|
|
23633
23633
|
}
|
|
23634
23634
|
});
|
|
23635
23635
|
|
|
23636
|
-
// ../system/dist/dist-
|
|
23637
|
-
var
|
|
23638
|
-
"../system/dist/dist-
|
|
23636
|
+
// ../system/dist/dist-D3lqzV40.js
|
|
23637
|
+
var require_dist_D3lqzV40 = __commonJS({
|
|
23638
|
+
"../system/dist/dist-D3lqzV40.js"(exports) {
|
|
23639
23639
|
"use strict";
|
|
23640
23640
|
var zod = require_zod();
|
|
23641
23641
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
@@ -47109,17 +47109,39 @@ var require_dist_CQs1b7uh = __commonJS({
|
|
|
47109
47109
|
latitude: zod.z.number().min(-90).max(90),
|
|
47110
47110
|
longitude: zod.z.number().min(-180).max(180)
|
|
47111
47111
|
}).nullable();
|
|
47112
|
+
var TransportPlaneSchema = zod.z.enum([
|
|
47113
|
+
"http",
|
|
47114
|
+
"ws",
|
|
47115
|
+
"mesh",
|
|
47116
|
+
"unknown"
|
|
47117
|
+
]);
|
|
47118
|
+
var TransportPlaneCountsSchema = zod.z.object({
|
|
47119
|
+
http: zod.z.number(),
|
|
47120
|
+
ws: zod.z.number(),
|
|
47121
|
+
mesh: zod.z.number(),
|
|
47122
|
+
unknown: zod.z.number()
|
|
47123
|
+
});
|
|
47112
47124
|
var RequestCensusGroupSchema = zod.z.object({
|
|
47125
|
+
plane: TransportPlaneSchema,
|
|
47113
47126
|
procedure: zod.z.string(),
|
|
47114
47127
|
userAgent: zod.z.string(),
|
|
47115
47128
|
ip: zod.z.string(),
|
|
47116
47129
|
principal: zod.z.string(),
|
|
47117
47130
|
calls: zod.z.number(),
|
|
47131
|
+
subscriptions: zod.z.number(),
|
|
47118
47132
|
perMin: zod.z.number()
|
|
47119
47133
|
});
|
|
47120
47134
|
var RequestCensusProcedureSchema = zod.z.object({
|
|
47121
47135
|
procedure: zod.z.string(),
|
|
47122
47136
|
calls: zod.z.number(),
|
|
47137
|
+
/**
|
|
47138
|
+
* The same total, split by transport. THIS is the row that answers the
|
|
47139
|
+
* question the census exists for: one look at `deviceManager.listAll` says
|
|
47140
|
+
* which plane carried the 4 960, without joining two log lines by eye.
|
|
47141
|
+
*/
|
|
47142
|
+
planes: TransportPlaneCountsSchema,
|
|
47143
|
+
/** Subscription STARTS on this procedure. Never folded into `calls`. */
|
|
47144
|
+
subscriptions: zod.z.number(),
|
|
47123
47145
|
perMin: zod.z.number()
|
|
47124
47146
|
});
|
|
47125
47147
|
var RequestCensusStatusSchema = zod.z.object({
|
|
@@ -47139,14 +47161,45 @@ var require_dist_CQs1b7uh = __commonJS({
|
|
|
47139
47161
|
*/
|
|
47140
47162
|
procedureCalls: zod.z.number(),
|
|
47141
47163
|
/**
|
|
47164
|
+
* `procedureCalls` split by transport. The four keys sum to
|
|
47165
|
+
* `procedureCalls` by construction - {@link RequestCensusSnapshotSchema}'s
|
|
47166
|
+
* `planesExplainTotal` is that identity, checked rather than assumed.
|
|
47167
|
+
*/
|
|
47168
|
+
planes: TransportPlaneCountsSchema,
|
|
47169
|
+
/**
|
|
47170
|
+
* True iff `planes` sums to `procedureCalls`. False means a call was counted
|
|
47171
|
+
* on no plane at all - which is a RESULT (a plane is missing from the
|
|
47172
|
+
* instrument), not a failure, and it has to be visible to be read as one.
|
|
47173
|
+
*/
|
|
47174
|
+
planesExplainTotal: zod.z.boolean(),
|
|
47175
|
+
/**
|
|
47142
47176
|
* tRPC WebSocket connections opened during the window. NOT calls - the WS
|
|
47143
|
-
*
|
|
47144
|
-
*
|
|
47177
|
+
* adapter resolves one context per connection - kept because a plane's call
|
|
47178
|
+
* count of zero against 37 open connections says something different from a
|
|
47179
|
+
* plane with no connections at all.
|
|
47145
47180
|
*/
|
|
47146
47181
|
wsConnections: zod.z.number(),
|
|
47182
|
+
/**
|
|
47183
|
+
* Client frames the WS plane looked at. `wsMessages` far above
|
|
47184
|
+
* `planes.ws + subscriptions` means most traffic is not operations
|
|
47185
|
+
* (keepalives, connection params) - which is itself an answer.
|
|
47186
|
+
*/
|
|
47187
|
+
wsMessages: zod.z.number(),
|
|
47188
|
+
/**
|
|
47189
|
+
* Subscription STARTS across every plane, excluded from `procedureCalls` on
|
|
47190
|
+
* purpose: one live-events stream opened at boot and held for six hours is
|
|
47191
|
+
* one subscription, and counting it as a call would let a quiet plane
|
|
47192
|
+
* masquerade as the storm.
|
|
47193
|
+
*/
|
|
47194
|
+
subscriptions: zod.z.number(),
|
|
47195
|
+
/** `subscription.stop` frames. Starts minus stops is what is still open. */
|
|
47196
|
+
subscriptionStops: zod.z.number(),
|
|
47147
47197
|
distinctGroups: zod.z.number(),
|
|
47148
|
-
/**
|
|
47149
|
-
*
|
|
47198
|
+
/**
|
|
47199
|
+
* Operations counted in the totals whose CALLER attribution was shed at the
|
|
47200
|
+
* cardinality bound. Unrelated to the `unknown` PLANE: these calls know
|
|
47201
|
+
* which transport they arrived on, they just lost their group row.
|
|
47202
|
+
*/
|
|
47150
47203
|
unattributedCalls: zod.z.number(),
|
|
47151
47204
|
procedures: zod.z.array(RequestCensusProcedureSchema).readonly(),
|
|
47152
47205
|
groups: zod.z.array(RequestCensusGroupSchema).readonly()
|
|
@@ -57677,7 +57730,7 @@ var require_alerts_addon = __commonJS({
|
|
|
57677
57730
|
[Symbol.toStringTag]: { value: "Module" }
|
|
57678
57731
|
});
|
|
57679
57732
|
require_chunk_Cek0wNdY();
|
|
57680
|
-
var require_dist10 =
|
|
57733
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
57681
57734
|
function selectExpired(alerts, cutoffMs) {
|
|
57682
57735
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
57683
57736
|
}
|
|
@@ -58496,7 +58549,7 @@ var require_console_logging = __commonJS({
|
|
|
58496
58549
|
[Symbol.toStringTag]: { value: "Module" }
|
|
58497
58550
|
});
|
|
58498
58551
|
require_chunk_Cek0wNdY();
|
|
58499
|
-
var require_dist10 =
|
|
58552
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
58500
58553
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
58501
58554
|
var LEVEL_RANK = {
|
|
58502
58555
|
debug: 0,
|
|
@@ -58590,7 +58643,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
58590
58643
|
"use strict";
|
|
58591
58644
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
58592
58645
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
58593
|
-
var require_dist10 =
|
|
58646
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
58594
58647
|
var node_crypto = __require("crypto");
|
|
58595
58648
|
var node_fs_promises = __require("fs/promises");
|
|
58596
58649
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -59487,11 +59540,11 @@ var require_core_blocks = __commonJS({
|
|
|
59487
59540
|
}
|
|
59488
59541
|
});
|
|
59489
59542
|
|
|
59490
|
-
// ../system/dist/retired-settings-keys-
|
|
59491
|
-
var
|
|
59492
|
-
"../system/dist/retired-settings-keys-
|
|
59543
|
+
// ../system/dist/retired-settings-keys-OtUQtEbq.js
|
|
59544
|
+
var require_retired_settings_keys_OtUQtEbq = __commonJS({
|
|
59545
|
+
"../system/dist/retired-settings-keys-OtUQtEbq.js"(exports) {
|
|
59493
59546
|
"use strict";
|
|
59494
|
-
var require_dist10 =
|
|
59547
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
59495
59548
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
59496
59549
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
59497
59550
|
return raw === "" || raw === "hub";
|
|
@@ -61534,8 +61587,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
61534
61587
|
[Symbol.toStringTag]: { value: "Module" }
|
|
61535
61588
|
});
|
|
61536
61589
|
require_chunk_Cek0wNdY();
|
|
61537
|
-
var require_dist10 =
|
|
61538
|
-
var require_retired_settings_keys =
|
|
61590
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
61591
|
+
var require_retired_settings_keys = require_retired_settings_keys_OtUQtEbq();
|
|
61539
61592
|
var node_crypto = __require("crypto");
|
|
61540
61593
|
var _camstack_types_node = require_node();
|
|
61541
61594
|
var JOB_HISTORY = 20;
|
|
@@ -66204,7 +66257,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
66204
66257
|
[Symbol.toStringTag]: { value: "Module" }
|
|
66205
66258
|
});
|
|
66206
66259
|
require_chunk_Cek0wNdY();
|
|
66207
|
-
var require_dist10 =
|
|
66260
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
66208
66261
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
66209
66262
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
66210
66263
|
var HubForwarderDestination = class {
|
|
@@ -66341,7 +66394,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
66341
66394
|
"use strict";
|
|
66342
66395
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
66343
66396
|
require_chunk_Cek0wNdY();
|
|
66344
|
-
var require_dist10 =
|
|
66397
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
66345
66398
|
var NO_DEVICES = "liveness:no-devices";
|
|
66346
66399
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
66347
66400
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -66531,7 +66584,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
66531
66584
|
[Symbol.toStringTag]: { value: "Module" }
|
|
66532
66585
|
});
|
|
66533
66586
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
66534
|
-
var require_dist10 =
|
|
66587
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
66535
66588
|
var node_crypto = __require("crypto");
|
|
66536
66589
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
66537
66590
|
var crypto$1 = __require("crypto");
|
|
@@ -74215,7 +74268,7 @@ var require_loki_logging = __commonJS({
|
|
|
74215
74268
|
[Symbol.toStringTag]: { value: "Module" }
|
|
74216
74269
|
});
|
|
74217
74270
|
require_chunk_Cek0wNdY();
|
|
74218
|
-
var require_dist10 =
|
|
74271
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
74219
74272
|
function sanitizeLabelName(raw) {
|
|
74220
74273
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
74221
74274
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -74780,7 +74833,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
74780
74833
|
[Symbol.toStringTag]: { value: "Module" }
|
|
74781
74834
|
});
|
|
74782
74835
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
74783
|
-
var require_dist10 =
|
|
74836
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
74784
74837
|
var node_child_process = __require("child_process");
|
|
74785
74838
|
var node_util = __require("util");
|
|
74786
74839
|
var node_os = __require("os");
|
|
@@ -75722,7 +75775,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
75722
75775
|
[Symbol.toStringTag]: { value: "Module" }
|
|
75723
75776
|
});
|
|
75724
75777
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
75725
|
-
var require_dist10 =
|
|
75778
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
75726
75779
|
var node_crypto = __require("crypto");
|
|
75727
75780
|
var node_fs_promises = __require("fs/promises");
|
|
75728
75781
|
var node_path = __require("path");
|
|
@@ -76838,8 +76891,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
76838
76891
|
[Symbol.toStringTag]: { value: "Module" }
|
|
76839
76892
|
});
|
|
76840
76893
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
76841
|
-
var require_dist10 =
|
|
76842
|
-
var require_retired_settings_keys =
|
|
76894
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
76895
|
+
var require_retired_settings_keys = require_retired_settings_keys_OtUQtEbq();
|
|
76843
76896
|
var node_crypto = __require("crypto");
|
|
76844
76897
|
var node_fs = __require("fs");
|
|
76845
76898
|
var node_module = __require("module");
|
|
@@ -79033,7 +79086,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
79033
79086
|
[Symbol.toStringTag]: { value: "Module" }
|
|
79034
79087
|
});
|
|
79035
79088
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
79036
|
-
var require_dist10 =
|
|
79089
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
79037
79090
|
var node_crypto = __require("crypto");
|
|
79038
79091
|
var node_fs_promises = __require("fs/promises");
|
|
79039
79092
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -80912,7 +80965,7 @@ var require_system_config_addon = __commonJS({
|
|
|
80912
80965
|
[Symbol.toStringTag]: { value: "Module" }
|
|
80913
80966
|
});
|
|
80914
80967
|
require_chunk_Cek0wNdY();
|
|
80915
|
-
var require_dist10 =
|
|
80968
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
80916
80969
|
var SECTION_TITLES = {
|
|
80917
80970
|
server: "Server",
|
|
80918
80971
|
auth: "Authentication"
|
|
@@ -98973,7 +99026,7 @@ var require_winston_logging = __commonJS({
|
|
|
98973
99026
|
[Symbol.toStringTag]: { value: "Module" }
|
|
98974
99027
|
});
|
|
98975
99028
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
98976
|
-
var require_dist10 =
|
|
99029
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
98977
99030
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
98978
99031
|
var node_path = __require("path");
|
|
98979
99032
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -122221,7 +122274,7 @@ var require_dist3 = __commonJS({
|
|
|
122221
122274
|
"use strict";
|
|
122222
122275
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
122223
122276
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
122224
|
-
var require_dist10 =
|
|
122277
|
+
var require_dist10 = require_dist_D3lqzV40();
|
|
122225
122278
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
122226
122279
|
require_alerts();
|
|
122227
122280
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -201048,13 +201101,22 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
201048
201101
|
const actions = {};
|
|
201049
201102
|
for (const { actionName, invoke } of options.actions) actions[actionName] = { handler: async (ctx) => {
|
|
201050
201103
|
const raw = require_manifest_python_deps.deserializeTypedArrays(ctx.params);
|
|
201051
|
-
return invoke(raw !== null && typeof raw === "object" && Object.keys(raw).length === 0 ? void 0 : raw);
|
|
201104
|
+
return invoke(raw !== null && typeof raw === "object" && Object.keys(raw).length === 0 ? void 0 : raw, readOrigin(ctx));
|
|
201052
201105
|
} };
|
|
201053
201106
|
return {
|
|
201054
201107
|
name: options.serviceName ?? "$core-caps",
|
|
201055
201108
|
actions
|
|
201056
201109
|
};
|
|
201057
201110
|
}
|
|
201111
|
+
function readOrigin(ctx) {
|
|
201112
|
+
return {
|
|
201113
|
+
nodeId: asName(ctx.nodeID),
|
|
201114
|
+
caller: asName(ctx.caller)
|
|
201115
|
+
};
|
|
201116
|
+
}
|
|
201117
|
+
function asName(value) {
|
|
201118
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
201119
|
+
}
|
|
201058
201120
|
var HubLogForwarder = class {
|
|
201059
201121
|
broker;
|
|
201060
201122
|
connected = false;
|
|
@@ -227086,17 +227148,39 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
227086
227148
|
latitude: zod.z.number().min(-90).max(90),
|
|
227087
227149
|
longitude: zod.z.number().min(-180).max(180)
|
|
227088
227150
|
}).nullable();
|
|
227151
|
+
var TransportPlaneSchema = zod.z.enum([
|
|
227152
|
+
"http",
|
|
227153
|
+
"ws",
|
|
227154
|
+
"mesh",
|
|
227155
|
+
"unknown"
|
|
227156
|
+
]);
|
|
227157
|
+
var TransportPlaneCountsSchema = zod.z.object({
|
|
227158
|
+
http: zod.z.number(),
|
|
227159
|
+
ws: zod.z.number(),
|
|
227160
|
+
mesh: zod.z.number(),
|
|
227161
|
+
unknown: zod.z.number()
|
|
227162
|
+
});
|
|
227089
227163
|
var RequestCensusGroupSchema = zod.z.object({
|
|
227164
|
+
plane: TransportPlaneSchema,
|
|
227090
227165
|
procedure: zod.z.string(),
|
|
227091
227166
|
userAgent: zod.z.string(),
|
|
227092
227167
|
ip: zod.z.string(),
|
|
227093
227168
|
principal: zod.z.string(),
|
|
227094
227169
|
calls: zod.z.number(),
|
|
227170
|
+
subscriptions: zod.z.number(),
|
|
227095
227171
|
perMin: zod.z.number()
|
|
227096
227172
|
});
|
|
227097
227173
|
var RequestCensusProcedureSchema = zod.z.object({
|
|
227098
227174
|
procedure: zod.z.string(),
|
|
227099
227175
|
calls: zod.z.number(),
|
|
227176
|
+
/**
|
|
227177
|
+
* The same total, split by transport. THIS is the row that answers the
|
|
227178
|
+
* question the census exists for: one look at `deviceManager.listAll` says
|
|
227179
|
+
* which plane carried the 4 960, without joining two log lines by eye.
|
|
227180
|
+
*/
|
|
227181
|
+
planes: TransportPlaneCountsSchema,
|
|
227182
|
+
/** Subscription STARTS on this procedure. Never folded into `calls`. */
|
|
227183
|
+
subscriptions: zod.z.number(),
|
|
227100
227184
|
perMin: zod.z.number()
|
|
227101
227185
|
});
|
|
227102
227186
|
var RequestCensusSnapshotSchema = zod.z.object({
|
|
@@ -227116,14 +227200,45 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
227116
227200
|
*/
|
|
227117
227201
|
procedureCalls: zod.z.number(),
|
|
227118
227202
|
/**
|
|
227203
|
+
* `procedureCalls` split by transport. The four keys sum to
|
|
227204
|
+
* `procedureCalls` by construction - {@link RequestCensusSnapshotSchema}'s
|
|
227205
|
+
* `planesExplainTotal` is that identity, checked rather than assumed.
|
|
227206
|
+
*/
|
|
227207
|
+
planes: TransportPlaneCountsSchema,
|
|
227208
|
+
/**
|
|
227209
|
+
* True iff `planes` sums to `procedureCalls`. False means a call was counted
|
|
227210
|
+
* on no plane at all - which is a RESULT (a plane is missing from the
|
|
227211
|
+
* instrument), not a failure, and it has to be visible to be read as one.
|
|
227212
|
+
*/
|
|
227213
|
+
planesExplainTotal: zod.z.boolean(),
|
|
227214
|
+
/**
|
|
227119
227215
|
* tRPC WebSocket connections opened during the window. NOT calls - the WS
|
|
227120
|
-
*
|
|
227121
|
-
*
|
|
227216
|
+
* adapter resolves one context per connection - kept because a plane's call
|
|
227217
|
+
* count of zero against 37 open connections says something different from a
|
|
227218
|
+
* plane with no connections at all.
|
|
227122
227219
|
*/
|
|
227123
227220
|
wsConnections: zod.z.number(),
|
|
227221
|
+
/**
|
|
227222
|
+
* Client frames the WS plane looked at. `wsMessages` far above
|
|
227223
|
+
* `planes.ws + subscriptions` means most traffic is not operations
|
|
227224
|
+
* (keepalives, connection params) - which is itself an answer.
|
|
227225
|
+
*/
|
|
227226
|
+
wsMessages: zod.z.number(),
|
|
227227
|
+
/**
|
|
227228
|
+
* Subscription STARTS across every plane, excluded from `procedureCalls` on
|
|
227229
|
+
* purpose: one live-events stream opened at boot and held for six hours is
|
|
227230
|
+
* one subscription, and counting it as a call would let a quiet plane
|
|
227231
|
+
* masquerade as the storm.
|
|
227232
|
+
*/
|
|
227233
|
+
subscriptions: zod.z.number(),
|
|
227234
|
+
/** `subscription.stop` frames. Starts minus stops is what is still open. */
|
|
227235
|
+
subscriptionStops: zod.z.number(),
|
|
227124
227236
|
distinctGroups: zod.z.number(),
|
|
227125
|
-
/**
|
|
227126
|
-
*
|
|
227237
|
+
/**
|
|
227238
|
+
* Operations counted in the totals whose CALLER attribution was shed at the
|
|
227239
|
+
* cardinality bound. Unrelated to the `unknown` PLANE: these calls know
|
|
227240
|
+
* which transport they arrived on, they just lost their group row.
|
|
227241
|
+
*/
|
|
227127
227242
|
unattributedCalls: zod.z.number(),
|
|
227128
227243
|
procedures: zod.z.array(RequestCensusProcedureSchema).readonly(),
|
|
227129
227244
|
groups: zod.z.array(RequestCensusGroupSchema).readonly()
|
|
@@ -244160,6 +244275,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
244160
244275
|
exports.TrackedDetectionSchema = TrackedDetectionSchema;
|
|
244161
244276
|
exports.TrainingExportDeviceTotalsSchema = TrainingExportDeviceTotalsSchema;
|
|
244162
244277
|
exports.TrainingExportSummarySchema = TrainingExportSummarySchema;
|
|
244278
|
+
exports.TransportPlaneCountsSchema = TransportPlaneCountsSchema;
|
|
244279
|
+
exports.TransportPlaneSchema = TransportPlaneSchema;
|
|
244163
244280
|
exports.TurnServerSchema = TurnServerSchema;
|
|
244164
244281
|
exports.UNIT_TABLE = UNIT_TABLE;
|
|
244165
244282
|
exports.UnifiedBrokerInfoSchema = BrokerInfoSchema$1;
|
|
@@ -277297,6 +277414,90 @@ var require_agent_http_auth = __commonJS({
|
|
|
277297
277414
|
}
|
|
277298
277415
|
});
|
|
277299
277416
|
|
|
277417
|
+
// ../../server/backend/dist/agent/agent-update-routes.js
|
|
277418
|
+
var require_agent_update_routes = __commonJS({
|
|
277419
|
+
"../../server/backend/dist/agent/agent-update-routes.js"(exports) {
|
|
277420
|
+
"use strict";
|
|
277421
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277422
|
+
exports.ADDON_UPDATE_UNAVAILABLE_REASON = exports.SERVER_UPDATE_UNAVAILABLE_REASON = exports.APPLY_ALREADY_RUNNING_MESSAGE = void 0;
|
|
277423
|
+
exports.createAgentServerUpdateControls = createAgentServerUpdateControls;
|
|
277424
|
+
exports.registerAgentUpdateRoutes = registerAgentUpdateRoutes;
|
|
277425
|
+
exports.APPLY_ALREADY_RUNNING_MESSAGE = "Refused: an update is already in flight on this node.";
|
|
277426
|
+
function createAgentServerUpdateControls(engine, onError) {
|
|
277427
|
+
let lastCheckError = null;
|
|
277428
|
+
let lastApply = null;
|
|
277429
|
+
let applyInFlight = false;
|
|
277430
|
+
return {
|
|
277431
|
+
getView: async () => ({
|
|
277432
|
+
status: await engine.getServerPackageStatus(),
|
|
277433
|
+
lastCheckError,
|
|
277434
|
+
lastApply,
|
|
277435
|
+
applyInFlight
|
|
277436
|
+
}),
|
|
277437
|
+
check: async () => {
|
|
277438
|
+
const result = await engine.checkServerUpdate();
|
|
277439
|
+
lastCheckError = result.error;
|
|
277440
|
+
return result;
|
|
277441
|
+
},
|
|
277442
|
+
applyLatest: () => {
|
|
277443
|
+
if (applyInFlight) {
|
|
277444
|
+
return { started: false, message: exports.APPLY_ALREADY_RUNNING_MESSAGE };
|
|
277445
|
+
}
|
|
277446
|
+
applyInFlight = true;
|
|
277447
|
+
lastApply = null;
|
|
277448
|
+
void engine.applyServerUpdate({}).then((result) => {
|
|
277449
|
+
lastApply = result;
|
|
277450
|
+
if (!result.accepted)
|
|
277451
|
+
onError?.(result.message);
|
|
277452
|
+
}).catch((err) => {
|
|
277453
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
277454
|
+
lastApply = {
|
|
277455
|
+
accepted: false,
|
|
277456
|
+
targetVersion: null,
|
|
277457
|
+
restarting: false,
|
|
277458
|
+
message: `Update failed: ${message}`
|
|
277459
|
+
};
|
|
277460
|
+
onError?.(message);
|
|
277461
|
+
}).finally(() => {
|
|
277462
|
+
applyInFlight = false;
|
|
277463
|
+
});
|
|
277464
|
+
return { started: true, message: null };
|
|
277465
|
+
}
|
|
277466
|
+
};
|
|
277467
|
+
}
|
|
277468
|
+
exports.SERVER_UPDATE_UNAVAILABLE_REASON = "Framework updates are not available on this agent build.";
|
|
277469
|
+
exports.ADDON_UPDATE_UNAVAILABLE_REASON = "The addon roster is not available on this agent build.";
|
|
277470
|
+
function registerAgentUpdateRoutes(app, controls) {
|
|
277471
|
+
const server = controls.server;
|
|
277472
|
+
const addons = controls.addons;
|
|
277473
|
+
app.get("/api/agent/server-update", async () => {
|
|
277474
|
+
if (server === void 0) {
|
|
277475
|
+
return { available: false, reason: exports.SERVER_UPDATE_UNAVAILABLE_REASON };
|
|
277476
|
+
}
|
|
277477
|
+
return { available: true, ...await server.getView() };
|
|
277478
|
+
});
|
|
277479
|
+
app.post("/api/agent/server-update/check", async (_req, reply) => {
|
|
277480
|
+
if (server === void 0) {
|
|
277481
|
+
return reply.status(503).send({ error: exports.SERVER_UPDATE_UNAVAILABLE_REASON });
|
|
277482
|
+
}
|
|
277483
|
+
return server.check();
|
|
277484
|
+
});
|
|
277485
|
+
app.post("/api/agent/server-update/apply", async (_req, reply) => {
|
|
277486
|
+
if (server === void 0) {
|
|
277487
|
+
return reply.status(503).send({ error: exports.SERVER_UPDATE_UNAVAILABLE_REASON });
|
|
277488
|
+
}
|
|
277489
|
+
return server.applyLatest();
|
|
277490
|
+
});
|
|
277491
|
+
app.get("/api/agent/addon-updates", async () => {
|
|
277492
|
+
if (addons === void 0) {
|
|
277493
|
+
return { available: false, reason: exports.ADDON_UPDATE_UNAVAILABLE_REASON };
|
|
277494
|
+
}
|
|
277495
|
+
return { available: true, ...await addons.getReport() };
|
|
277496
|
+
});
|
|
277497
|
+
}
|
|
277498
|
+
}
|
|
277499
|
+
});
|
|
277500
|
+
|
|
277300
277501
|
// ../../server/backend/dist/agent/derive-hub-url.js
|
|
277301
277502
|
var require_derive_hub_url = __commonJS({
|
|
277302
277503
|
"../../server/backend/dist/agent/derive-hub-url.js"(exports) {
|
|
@@ -283473,6 +283674,7 @@ var require_agent_http = __commonJS({
|
|
|
283473
283674
|
var path = __importStar(__require("path"));
|
|
283474
283675
|
var fastify_1 = __importDefault(require_fastify());
|
|
283475
283676
|
var agent_http_auth_js_1 = require_agent_http_auth();
|
|
283677
|
+
var agent_update_routes_js_1 = require_agent_update_routes();
|
|
283476
283678
|
var derive_hub_url_js_1 = require_derive_hub_url();
|
|
283477
283679
|
Object.defineProperty(exports, "pickIpv4", { enumerable: true, get: function() {
|
|
283478
283680
|
return derive_hub_url_js_1.pickIpv4;
|
|
@@ -283720,6 +283922,7 @@ var require_agent_http = __commonJS({
|
|
|
283720
283922
|
});
|
|
283721
283923
|
return { success: true, message: "Agent reconnecting..." };
|
|
283722
283924
|
});
|
|
283925
|
+
(0, agent_update_routes_js_1.registerAgentUpdateRoutes)(app, config.updateControls ?? {});
|
|
283723
283926
|
app.get("/api/agent/discovered-nodes", async () => {
|
|
283724
283927
|
const b = getBroker();
|
|
283725
283928
|
const nodes = getRegistryNodes(b);
|
|
@@ -375651,312 +375854,6 @@ var require_agent_service = __commonJS({
|
|
|
375651
375854
|
}
|
|
375652
375855
|
});
|
|
375653
375856
|
|
|
375654
|
-
// ../../server/backend/dist/core/server-update/system-ensure-prebuilds.js
|
|
375655
|
-
var require_system_ensure_prebuilds = __commonJS({
|
|
375656
|
-
"../../server/backend/dist/core/server-update/system-ensure-prebuilds.js"(exports) {
|
|
375657
|
-
"use strict";
|
|
375658
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
375659
|
-
exports.buildSystemEnsureNativePrebuilds = buildSystemEnsureNativePrebuilds;
|
|
375660
|
-
var system_1 = require_dist3();
|
|
375661
|
-
function buildSystemEnsureNativePrebuilds(logger) {
|
|
375662
|
-
return async (closureDir) => {
|
|
375663
|
-
await (0, system_1.ensureNativePrebuilds)(closureDir, { logger });
|
|
375664
|
-
};
|
|
375665
|
-
}
|
|
375666
|
-
}
|
|
375667
|
-
});
|
|
375668
|
-
|
|
375669
|
-
// ../../server/backend/dist/core/server-update/system-exec-npm.js
|
|
375670
|
-
var require_system_exec_npm = __commonJS({
|
|
375671
|
-
"../../server/backend/dist/core/server-update/system-exec-npm.js"(exports) {
|
|
375672
|
-
"use strict";
|
|
375673
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
375674
|
-
exports.buildSystemExecNpm = buildSystemExecNpm;
|
|
375675
|
-
var system_1 = require_dist3();
|
|
375676
|
-
function buildSystemExecNpm(options, runNpmFn = system_1.runNpm) {
|
|
375677
|
-
return async (args, opts) => {
|
|
375678
|
-
const { stdout } = await runNpmFn(args, {
|
|
375679
|
-
cacheDir: options.cacheDir,
|
|
375680
|
-
registry: options.registry,
|
|
375681
|
-
logger: options.logger,
|
|
375682
|
-
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {},
|
|
375683
|
-
timeout: opts.timeoutMs
|
|
375684
|
-
});
|
|
375685
|
-
return { stdout };
|
|
375686
|
-
};
|
|
375687
|
-
}
|
|
375688
|
-
}
|
|
375689
|
-
});
|
|
375690
|
-
|
|
375691
|
-
// ../../server/backend/dist/core/update-availability-emitter.js
|
|
375692
|
-
var require_update_availability_emitter = __commonJS({
|
|
375693
|
-
"../../server/backend/dist/core/update-availability-emitter.js"(exports) {
|
|
375694
|
-
"use strict";
|
|
375695
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
375696
|
-
exports.UpdateAvailabilityEmitter = void 0;
|
|
375697
|
-
var types_1 = require_dist4();
|
|
375698
|
-
var UpdateAvailabilityEmitter = class {
|
|
375699
|
-
eventBus;
|
|
375700
|
-
source;
|
|
375701
|
-
store;
|
|
375702
|
-
latestByKey = /* @__PURE__ */ new Map();
|
|
375703
|
-
held = /* @__PURE__ */ new Map();
|
|
375704
|
-
/** Set when in-memory state diverged from what the store last saw. */
|
|
375705
|
-
dirty = false;
|
|
375706
|
-
constructor(eventBus, source, store) {
|
|
375707
|
-
this.eventBus = eventBus;
|
|
375708
|
-
this.source = source;
|
|
375709
|
-
this.store = store;
|
|
375710
|
-
const persisted = store?.load() ?? null;
|
|
375711
|
-
if (persisted === null)
|
|
375712
|
-
return;
|
|
375713
|
-
for (const [key, version] of Object.entries(persisted.latestByKey)) {
|
|
375714
|
-
this.latestByKey.set(key, version);
|
|
375715
|
-
}
|
|
375716
|
-
for (const [key, candidate] of Object.entries(persisted.held)) {
|
|
375717
|
-
this.held.set(key, candidate);
|
|
375718
|
-
}
|
|
375719
|
-
}
|
|
375720
|
-
publishSnapshot(target, candidates, nodeId) {
|
|
375721
|
-
const scope = nodeId ?? "hub";
|
|
375722
|
-
const present = /* @__PURE__ */ new Set();
|
|
375723
|
-
let latestChanged = false;
|
|
375724
|
-
for (const candidate of candidates) {
|
|
375725
|
-
if (candidate.target !== target)
|
|
375726
|
-
continue;
|
|
375727
|
-
const stamped = stampNode(candidate, nodeId);
|
|
375728
|
-
const key = this.key(stamped);
|
|
375729
|
-
present.add(key);
|
|
375730
|
-
if (this.note(stamped))
|
|
375731
|
-
latestChanged = true;
|
|
375732
|
-
}
|
|
375733
|
-
for (const key of [...this.held.keys()]) {
|
|
375734
|
-
if (!key.startsWith(`${target}:${scope}:`))
|
|
375735
|
-
continue;
|
|
375736
|
-
if (present.has(key))
|
|
375737
|
-
continue;
|
|
375738
|
-
this.held.delete(key);
|
|
375739
|
-
this.latestByKey.delete(key);
|
|
375740
|
-
this.dirty = true;
|
|
375741
|
-
}
|
|
375742
|
-
this.persistIfDirty();
|
|
375743
|
-
if (!latestChanged)
|
|
375744
|
-
return;
|
|
375745
|
-
this.emitList(target, scope);
|
|
375746
|
-
}
|
|
375747
|
-
/** Publish a partial candidate set without treating omissions as up-to-date. */
|
|
375748
|
-
publishCandidates(candidates) {
|
|
375749
|
-
const changed = /* @__PURE__ */ new Map();
|
|
375750
|
-
for (const candidate of candidates) {
|
|
375751
|
-
if (!this.note(candidate))
|
|
375752
|
-
continue;
|
|
375753
|
-
const scope = scopeOf(candidate);
|
|
375754
|
-
changed.set(`${candidate.target}:${scope}`, { target: candidate.target, scope });
|
|
375755
|
-
}
|
|
375756
|
-
this.persistIfDirty();
|
|
375757
|
-
for (const { target, scope } of changed.values())
|
|
375758
|
-
this.emitList(target, scope);
|
|
375759
|
-
}
|
|
375760
|
-
note(candidate) {
|
|
375761
|
-
const key = this.key(candidate);
|
|
375762
|
-
const previous = this.latestByKey.get(key);
|
|
375763
|
-
const previousHeld = this.held.get(key);
|
|
375764
|
-
if (previousHeld === void 0 || previousHeld.currentVersion !== candidate.currentVersion || previousHeld.latestVersion !== candidate.latestVersion || previousHeld.nodeId !== candidate.nodeId) {
|
|
375765
|
-
this.dirty = true;
|
|
375766
|
-
}
|
|
375767
|
-
this.held.set(key, candidate);
|
|
375768
|
-
this.latestByKey.set(key, candidate.latestVersion);
|
|
375769
|
-
return previous !== candidate.latestVersion;
|
|
375770
|
-
}
|
|
375771
|
-
/**
|
|
375772
|
-
* Flush to the durable store. Called BEFORE the emit so a crash between the
|
|
375773
|
-
* two costs a duplicate announcement, never a silent one.
|
|
375774
|
-
*/
|
|
375775
|
-
persistIfDirty() {
|
|
375776
|
-
if (!this.dirty)
|
|
375777
|
-
return;
|
|
375778
|
-
this.dirty = false;
|
|
375779
|
-
this.store?.save({
|
|
375780
|
-
latestByKey: Object.fromEntries(this.latestByKey),
|
|
375781
|
-
held: Object.fromEntries(this.held)
|
|
375782
|
-
});
|
|
375783
|
-
}
|
|
375784
|
-
/** Announce ONE scope's full list. `scope` is the node id, `hub` for the hub. */
|
|
375785
|
-
emitList(target, scope) {
|
|
375786
|
-
const list = [...this.held.values()].filter((candidate) => candidate.target === target && scopeOf(candidate) === scope);
|
|
375787
|
-
if (list.length === 0)
|
|
375788
|
-
return;
|
|
375789
|
-
const packages = list.map((candidate) => ({
|
|
375790
|
-
packageName: candidate.packageName,
|
|
375791
|
-
currentVersion: candidate.currentVersion,
|
|
375792
|
-
latestVersion: candidate.latestVersion,
|
|
375793
|
-
nodeId: scope
|
|
375794
|
-
}));
|
|
375795
|
-
const head = list[0];
|
|
375796
|
-
this.eventBus.emit({
|
|
375797
|
-
id: `update.available:${target}:${scope}:${packages.map((pkg) => `${pkg.packageName}@${pkg.latestVersion}`).toSorted().join(",")}`,
|
|
375798
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
375799
|
-
source: this.source,
|
|
375800
|
-
category: types_1.EventCategory.UpdateAvailable,
|
|
375801
|
-
data: {
|
|
375802
|
-
target,
|
|
375803
|
-
packageName: head.packageName,
|
|
375804
|
-
currentVersion: head.currentVersion,
|
|
375805
|
-
latestVersion: head.latestVersion,
|
|
375806
|
-
packages,
|
|
375807
|
-
nodeId: scope,
|
|
375808
|
-
nodeIds: [scope]
|
|
375809
|
-
}
|
|
375810
|
-
});
|
|
375811
|
-
}
|
|
375812
|
-
key(candidate) {
|
|
375813
|
-
return `${candidate.target}:${scopeOf(candidate)}:${candidate.packageName}`;
|
|
375814
|
-
}
|
|
375815
|
-
};
|
|
375816
|
-
exports.UpdateAvailabilityEmitter = UpdateAvailabilityEmitter;
|
|
375817
|
-
function scopeOf(candidate) {
|
|
375818
|
-
return candidate.nodeId ?? "hub";
|
|
375819
|
-
}
|
|
375820
|
-
function stampNode(candidate, nodeId) {
|
|
375821
|
-
if (nodeId === void 0 || candidate.nodeId !== void 0)
|
|
375822
|
-
return candidate;
|
|
375823
|
-
return { ...candidate, nodeId };
|
|
375824
|
-
}
|
|
375825
|
-
}
|
|
375826
|
-
});
|
|
375827
|
-
|
|
375828
|
-
// ../../server/backend/dist/core/update-availability-store.js
|
|
375829
|
-
var require_update_availability_store = __commonJS({
|
|
375830
|
-
"../../server/backend/dist/core/update-availability-store.js"(exports) {
|
|
375831
|
-
"use strict";
|
|
375832
|
-
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
375833
|
-
if (k2 === void 0) k2 = k;
|
|
375834
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
375835
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
375836
|
-
desc = { enumerable: true, get: function() {
|
|
375837
|
-
return m[k];
|
|
375838
|
-
} };
|
|
375839
|
-
}
|
|
375840
|
-
Object.defineProperty(o, k2, desc);
|
|
375841
|
-
}) : (function(o, m, k, k2) {
|
|
375842
|
-
if (k2 === void 0) k2 = k;
|
|
375843
|
-
o[k2] = m[k];
|
|
375844
|
-
}));
|
|
375845
|
-
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
375846
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
375847
|
-
}) : function(o, v) {
|
|
375848
|
-
o["default"] = v;
|
|
375849
|
-
});
|
|
375850
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
375851
|
-
var ownKeys = function(o) {
|
|
375852
|
-
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
375853
|
-
var ar = [];
|
|
375854
|
-
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
375855
|
-
return ar;
|
|
375856
|
-
};
|
|
375857
|
-
return ownKeys(o);
|
|
375858
|
-
};
|
|
375859
|
-
return function(mod) {
|
|
375860
|
-
if (mod && mod.__esModule) return mod;
|
|
375861
|
-
var result = {};
|
|
375862
|
-
if (mod != null) {
|
|
375863
|
-
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
375864
|
-
}
|
|
375865
|
-
__setModuleDefault(result, mod);
|
|
375866
|
-
return result;
|
|
375867
|
-
};
|
|
375868
|
-
})();
|
|
375869
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
375870
|
-
exports.FileUpdateAvailabilityStore = exports.UPDATE_AVAILABILITY_DIR = void 0;
|
|
375871
|
-
var fs = __importStar(__require("fs"));
|
|
375872
|
-
var path = __importStar(__require("path"));
|
|
375873
|
-
var types_1 = require_dist4();
|
|
375874
|
-
exports.UPDATE_AVAILABILITY_DIR = "update-availability";
|
|
375875
|
-
var FileUpdateAvailabilityStore = class {
|
|
375876
|
-
scopeId;
|
|
375877
|
-
logger;
|
|
375878
|
-
filePath;
|
|
375879
|
-
constructor(dataDir, scopeId, logger) {
|
|
375880
|
-
this.scopeId = scopeId;
|
|
375881
|
-
this.logger = logger;
|
|
375882
|
-
this.filePath = path.join(dataDir, exports.UPDATE_AVAILABILITY_DIR, `${scopeId}.json`);
|
|
375883
|
-
}
|
|
375884
|
-
load() {
|
|
375885
|
-
try {
|
|
375886
|
-
if (!fs.existsSync(this.filePath))
|
|
375887
|
-
return null;
|
|
375888
|
-
const parsed = JSON.parse(fs.readFileSync(this.filePath, "utf-8"));
|
|
375889
|
-
return parseState(parsed);
|
|
375890
|
-
} catch (error) {
|
|
375891
|
-
this.logger.warn("Update-availability state unreadable; starting from empty", {
|
|
375892
|
-
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
375893
|
-
});
|
|
375894
|
-
return null;
|
|
375895
|
-
}
|
|
375896
|
-
}
|
|
375897
|
-
save(state) {
|
|
375898
|
-
try {
|
|
375899
|
-
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
375900
|
-
const tmp = `${this.filePath}.tmp`;
|
|
375901
|
-
fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
375902
|
-
fs.renameSync(tmp, this.filePath);
|
|
375903
|
-
} catch (error) {
|
|
375904
|
-
this.logger.warn("Failed to persist update-availability state", {
|
|
375905
|
-
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
375906
|
-
});
|
|
375907
|
-
}
|
|
375908
|
-
}
|
|
375909
|
-
};
|
|
375910
|
-
exports.FileUpdateAvailabilityStore = FileUpdateAvailabilityStore;
|
|
375911
|
-
function parseState(raw) {
|
|
375912
|
-
if (raw === null || typeof raw !== "object")
|
|
375913
|
-
return null;
|
|
375914
|
-
const latestRaw = Reflect.get(raw, "latestByKey");
|
|
375915
|
-
const heldRaw = Reflect.get(raw, "held");
|
|
375916
|
-
if (latestRaw === null || typeof latestRaw !== "object")
|
|
375917
|
-
return null;
|
|
375918
|
-
if (heldRaw === null || typeof heldRaw !== "object")
|
|
375919
|
-
return null;
|
|
375920
|
-
const latestByKey = {};
|
|
375921
|
-
for (const [key, value] of Object.entries(latestRaw)) {
|
|
375922
|
-
if (typeof value === "string")
|
|
375923
|
-
latestByKey[key] = value;
|
|
375924
|
-
}
|
|
375925
|
-
const held = {};
|
|
375926
|
-
for (const [key, value] of Object.entries(heldRaw)) {
|
|
375927
|
-
const candidate = parseCandidate(value);
|
|
375928
|
-
if (candidate !== null)
|
|
375929
|
-
held[key] = candidate;
|
|
375930
|
-
}
|
|
375931
|
-
return { latestByKey, held };
|
|
375932
|
-
}
|
|
375933
|
-
function parseCandidate(raw) {
|
|
375934
|
-
if (raw === null || typeof raw !== "object")
|
|
375935
|
-
return null;
|
|
375936
|
-
const target = Reflect.get(raw, "target");
|
|
375937
|
-
const packageName = Reflect.get(raw, "packageName");
|
|
375938
|
-
const currentVersion = Reflect.get(raw, "currentVersion");
|
|
375939
|
-
const latestVersion = Reflect.get(raw, "latestVersion");
|
|
375940
|
-
const nodeId = Reflect.get(raw, "nodeId");
|
|
375941
|
-
if (target !== "addon" && target !== "server")
|
|
375942
|
-
return null;
|
|
375943
|
-
if (typeof packageName !== "string")
|
|
375944
|
-
return null;
|
|
375945
|
-
if (typeof currentVersion !== "string")
|
|
375946
|
-
return null;
|
|
375947
|
-
if (typeof latestVersion !== "string")
|
|
375948
|
-
return null;
|
|
375949
|
-
return {
|
|
375950
|
-
target,
|
|
375951
|
-
packageName,
|
|
375952
|
-
currentVersion,
|
|
375953
|
-
latestVersion,
|
|
375954
|
-
...typeof nodeId === "string" ? { nodeId } : {}
|
|
375955
|
-
};
|
|
375956
|
-
}
|
|
375957
|
-
}
|
|
375958
|
-
});
|
|
375959
|
-
|
|
375960
375857
|
// ../../server/backend/dist/server-root/index.js
|
|
375961
375858
|
var require_server_root = __commonJS({
|
|
375962
375859
|
"../../server/backend/dist/server-root/index.js"(exports, module) {
|
|
@@ -377467,6 +377364,441 @@ var require_server_root = __commonJS({
|
|
|
377467
377364
|
}
|
|
377468
377365
|
});
|
|
377469
377366
|
|
|
377367
|
+
// ../../server/backend/dist/agent/agent-addon-updates.js
|
|
377368
|
+
var require_agent_addon_updates = __commonJS({
|
|
377369
|
+
"../../server/backend/dist/agent/agent-addon-updates.js"(exports) {
|
|
377370
|
+
"use strict";
|
|
377371
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
377372
|
+
if (k2 === void 0) k2 = k;
|
|
377373
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
377374
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
377375
|
+
desc = { enumerable: true, get: function() {
|
|
377376
|
+
return m[k];
|
|
377377
|
+
} };
|
|
377378
|
+
}
|
|
377379
|
+
Object.defineProperty(o, k2, desc);
|
|
377380
|
+
}) : (function(o, m, k, k2) {
|
|
377381
|
+
if (k2 === void 0) k2 = k;
|
|
377382
|
+
o[k2] = m[k];
|
|
377383
|
+
}));
|
|
377384
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
377385
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
377386
|
+
}) : function(o, v) {
|
|
377387
|
+
o["default"] = v;
|
|
377388
|
+
});
|
|
377389
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
377390
|
+
var ownKeys = function(o) {
|
|
377391
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
377392
|
+
var ar = [];
|
|
377393
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
377394
|
+
return ar;
|
|
377395
|
+
};
|
|
377396
|
+
return ownKeys(o);
|
|
377397
|
+
};
|
|
377398
|
+
return function(mod) {
|
|
377399
|
+
if (mod && mod.__esModule) return mod;
|
|
377400
|
+
var result = {};
|
|
377401
|
+
if (mod != null) {
|
|
377402
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
377403
|
+
}
|
|
377404
|
+
__setModuleDefault(result, mod);
|
|
377405
|
+
return result;
|
|
377406
|
+
};
|
|
377407
|
+
})();
|
|
377408
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
377409
|
+
exports.DEFAULT_NPM_REGISTRY = void 0;
|
|
377410
|
+
exports.readInstalledAddonPackages = readInstalledAddonPackages;
|
|
377411
|
+
exports.buildAddonUpdateEntries = buildAddonUpdateEntries;
|
|
377412
|
+
exports.resolvePublishedVersion = resolvePublishedVersion;
|
|
377413
|
+
exports.buildAgentAddonUpdateReport = buildAgentAddonUpdateReport;
|
|
377414
|
+
var fs = __importStar(__require("fs"));
|
|
377415
|
+
var path = __importStar(__require("path"));
|
|
377416
|
+
var index_js_1 = require_server_root();
|
|
377417
|
+
var addon_scan_js_1 = require_addon_scan();
|
|
377418
|
+
exports.DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
377419
|
+
function readPackageIdentity(dir) {
|
|
377420
|
+
try {
|
|
377421
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf-8"));
|
|
377422
|
+
if (typeof parsed.name !== "string" || parsed.name.length === 0)
|
|
377423
|
+
return null;
|
|
377424
|
+
return {
|
|
377425
|
+
packageName: parsed.name,
|
|
377426
|
+
installedVersion: typeof parsed.version === "string" ? parsed.version : null
|
|
377427
|
+
};
|
|
377428
|
+
} catch {
|
|
377429
|
+
return null;
|
|
377430
|
+
}
|
|
377431
|
+
}
|
|
377432
|
+
function readInstalledAddonPackages(addonsDir) {
|
|
377433
|
+
const found = [];
|
|
377434
|
+
for (const dir of (0, addon_scan_js_1.resolveAddonPackageDirs)(addonsDir)) {
|
|
377435
|
+
const identity = readPackageIdentity(dir);
|
|
377436
|
+
if (identity !== null)
|
|
377437
|
+
found.push(identity);
|
|
377438
|
+
}
|
|
377439
|
+
return found.sort((a, b) => a.packageName.localeCompare(b.packageName));
|
|
377440
|
+
}
|
|
377441
|
+
function buildAddonUpdateEntries(installed, published) {
|
|
377442
|
+
return installed.map((pkg) => {
|
|
377443
|
+
const latest = published.get(pkg.packageName);
|
|
377444
|
+
const latestVersion = latest?.latestVersion ?? null;
|
|
377445
|
+
const updateAvailable = latestVersion !== null && pkg.installedVersion !== null && (0, index_js_1.compareSemver)(latestVersion, pkg.installedVersion) > 0;
|
|
377446
|
+
return {
|
|
377447
|
+
packageName: pkg.packageName,
|
|
377448
|
+
installedVersion: pkg.installedVersion,
|
|
377449
|
+
latestVersion,
|
|
377450
|
+
updateAvailable,
|
|
377451
|
+
error: latest?.error ?? null
|
|
377452
|
+
};
|
|
377453
|
+
});
|
|
377454
|
+
}
|
|
377455
|
+
async function resolvePublishedVersion(packageName, registryUrl, fetchFn) {
|
|
377456
|
+
const base = registryUrl.replace(/\/+$/, "");
|
|
377457
|
+
const url = `${base}/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
|
|
377458
|
+
try {
|
|
377459
|
+
const res = await fetchFn(url);
|
|
377460
|
+
if (!res.ok)
|
|
377461
|
+
return { latestVersion: null, error: `registry GET \u2192 ${res.status}` };
|
|
377462
|
+
const body = await res.json();
|
|
377463
|
+
const latest = body["dist-tags"]?.["latest"];
|
|
377464
|
+
if (typeof latest !== "string" || latest.length === 0) {
|
|
377465
|
+
return { latestVersion: null, error: "registry returned no dist-tags.latest" };
|
|
377466
|
+
}
|
|
377467
|
+
return { latestVersion: latest, error: null };
|
|
377468
|
+
} catch (err) {
|
|
377469
|
+
return { latestVersion: null, error: err instanceof Error ? err.message : String(err) };
|
|
377470
|
+
}
|
|
377471
|
+
}
|
|
377472
|
+
async function buildAgentAddonUpdateReport(input) {
|
|
377473
|
+
const now = input.now ?? Date.now;
|
|
377474
|
+
const registryUrl = input.registryUrl ?? exports.DEFAULT_NPM_REGISTRY;
|
|
377475
|
+
const installed = readInstalledAddonPackages(input.addonsDir);
|
|
377476
|
+
const published = /* @__PURE__ */ new Map();
|
|
377477
|
+
const resolved = await Promise.all(installed.map(async (pkg) => ({
|
|
377478
|
+
packageName: pkg.packageName,
|
|
377479
|
+
result: await resolvePublishedVersion(pkg.packageName, registryUrl, input.fetchFn)
|
|
377480
|
+
})));
|
|
377481
|
+
for (const r of resolved)
|
|
377482
|
+
published.set(r.packageName, r.result);
|
|
377483
|
+
const entries = buildAddonUpdateEntries(installed, published);
|
|
377484
|
+
const allFailed = entries.length > 0 && entries.every((e) => e.latestVersion === null);
|
|
377485
|
+
const firstError = entries.find((e) => e.error !== null)?.error ?? "registry unreachable";
|
|
377486
|
+
return {
|
|
377487
|
+
entries,
|
|
377488
|
+
checkedAtMs: now(),
|
|
377489
|
+
error: allFailed ? `Could not reach ${registryUrl}: ${firstError}` : null,
|
|
377490
|
+
hubReachable: input.isHubReachable()
|
|
377491
|
+
};
|
|
377492
|
+
}
|
|
377493
|
+
}
|
|
377494
|
+
});
|
|
377495
|
+
|
|
377496
|
+
// ../../server/backend/dist/core/server-update/system-ensure-prebuilds.js
|
|
377497
|
+
var require_system_ensure_prebuilds = __commonJS({
|
|
377498
|
+
"../../server/backend/dist/core/server-update/system-ensure-prebuilds.js"(exports) {
|
|
377499
|
+
"use strict";
|
|
377500
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
377501
|
+
exports.buildSystemEnsureNativePrebuilds = buildSystemEnsureNativePrebuilds;
|
|
377502
|
+
var system_1 = require_dist3();
|
|
377503
|
+
function buildSystemEnsureNativePrebuilds(logger) {
|
|
377504
|
+
return async (closureDir) => {
|
|
377505
|
+
await (0, system_1.ensureNativePrebuilds)(closureDir, { logger });
|
|
377506
|
+
};
|
|
377507
|
+
}
|
|
377508
|
+
}
|
|
377509
|
+
});
|
|
377510
|
+
|
|
377511
|
+
// ../../server/backend/dist/core/server-update/system-exec-npm.js
|
|
377512
|
+
var require_system_exec_npm = __commonJS({
|
|
377513
|
+
"../../server/backend/dist/core/server-update/system-exec-npm.js"(exports) {
|
|
377514
|
+
"use strict";
|
|
377515
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
377516
|
+
exports.buildSystemExecNpm = buildSystemExecNpm;
|
|
377517
|
+
var system_1 = require_dist3();
|
|
377518
|
+
function buildSystemExecNpm(options, runNpmFn = system_1.runNpm) {
|
|
377519
|
+
return async (args, opts) => {
|
|
377520
|
+
const { stdout } = await runNpmFn(args, {
|
|
377521
|
+
cacheDir: options.cacheDir,
|
|
377522
|
+
registry: options.registry,
|
|
377523
|
+
logger: options.logger,
|
|
377524
|
+
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {},
|
|
377525
|
+
timeout: opts.timeoutMs
|
|
377526
|
+
});
|
|
377527
|
+
return { stdout };
|
|
377528
|
+
};
|
|
377529
|
+
}
|
|
377530
|
+
}
|
|
377531
|
+
});
|
|
377532
|
+
|
|
377533
|
+
// ../../server/backend/dist/core/update-availability-emitter.js
|
|
377534
|
+
var require_update_availability_emitter = __commonJS({
|
|
377535
|
+
"../../server/backend/dist/core/update-availability-emitter.js"(exports) {
|
|
377536
|
+
"use strict";
|
|
377537
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
377538
|
+
exports.UpdateAvailabilityEmitter = void 0;
|
|
377539
|
+
var types_1 = require_dist4();
|
|
377540
|
+
var UpdateAvailabilityEmitter = class {
|
|
377541
|
+
eventBus;
|
|
377542
|
+
source;
|
|
377543
|
+
store;
|
|
377544
|
+
latestByKey = /* @__PURE__ */ new Map();
|
|
377545
|
+
held = /* @__PURE__ */ new Map();
|
|
377546
|
+
/** Set when in-memory state diverged from what the store last saw. */
|
|
377547
|
+
dirty = false;
|
|
377548
|
+
constructor(eventBus, source, store) {
|
|
377549
|
+
this.eventBus = eventBus;
|
|
377550
|
+
this.source = source;
|
|
377551
|
+
this.store = store;
|
|
377552
|
+
const persisted = store?.load() ?? null;
|
|
377553
|
+
if (persisted === null)
|
|
377554
|
+
return;
|
|
377555
|
+
for (const [key, version] of Object.entries(persisted.latestByKey)) {
|
|
377556
|
+
this.latestByKey.set(key, version);
|
|
377557
|
+
}
|
|
377558
|
+
for (const [key, candidate] of Object.entries(persisted.held)) {
|
|
377559
|
+
this.held.set(key, candidate);
|
|
377560
|
+
}
|
|
377561
|
+
}
|
|
377562
|
+
publishSnapshot(target, candidates, nodeId) {
|
|
377563
|
+
const scope = nodeId ?? "hub";
|
|
377564
|
+
const present = /* @__PURE__ */ new Set();
|
|
377565
|
+
let latestChanged = false;
|
|
377566
|
+
for (const candidate of candidates) {
|
|
377567
|
+
if (candidate.target !== target)
|
|
377568
|
+
continue;
|
|
377569
|
+
const stamped = stampNode(candidate, nodeId);
|
|
377570
|
+
const key = this.key(stamped);
|
|
377571
|
+
present.add(key);
|
|
377572
|
+
if (this.note(stamped))
|
|
377573
|
+
latestChanged = true;
|
|
377574
|
+
}
|
|
377575
|
+
for (const key of [...this.held.keys()]) {
|
|
377576
|
+
if (!key.startsWith(`${target}:${scope}:`))
|
|
377577
|
+
continue;
|
|
377578
|
+
if (present.has(key))
|
|
377579
|
+
continue;
|
|
377580
|
+
this.held.delete(key);
|
|
377581
|
+
this.latestByKey.delete(key);
|
|
377582
|
+
this.dirty = true;
|
|
377583
|
+
}
|
|
377584
|
+
this.persistIfDirty();
|
|
377585
|
+
if (!latestChanged)
|
|
377586
|
+
return;
|
|
377587
|
+
this.emitList(target, scope);
|
|
377588
|
+
}
|
|
377589
|
+
/** Publish a partial candidate set without treating omissions as up-to-date. */
|
|
377590
|
+
publishCandidates(candidates) {
|
|
377591
|
+
const changed = /* @__PURE__ */ new Map();
|
|
377592
|
+
for (const candidate of candidates) {
|
|
377593
|
+
if (!this.note(candidate))
|
|
377594
|
+
continue;
|
|
377595
|
+
const scope = scopeOf(candidate);
|
|
377596
|
+
changed.set(`${candidate.target}:${scope}`, { target: candidate.target, scope });
|
|
377597
|
+
}
|
|
377598
|
+
this.persistIfDirty();
|
|
377599
|
+
for (const { target, scope } of changed.values())
|
|
377600
|
+
this.emitList(target, scope);
|
|
377601
|
+
}
|
|
377602
|
+
note(candidate) {
|
|
377603
|
+
const key = this.key(candidate);
|
|
377604
|
+
const previous = this.latestByKey.get(key);
|
|
377605
|
+
const previousHeld = this.held.get(key);
|
|
377606
|
+
if (previousHeld === void 0 || previousHeld.currentVersion !== candidate.currentVersion || previousHeld.latestVersion !== candidate.latestVersion || previousHeld.nodeId !== candidate.nodeId) {
|
|
377607
|
+
this.dirty = true;
|
|
377608
|
+
}
|
|
377609
|
+
this.held.set(key, candidate);
|
|
377610
|
+
this.latestByKey.set(key, candidate.latestVersion);
|
|
377611
|
+
return previous !== candidate.latestVersion;
|
|
377612
|
+
}
|
|
377613
|
+
/**
|
|
377614
|
+
* Flush to the durable store. Called BEFORE the emit so a crash between the
|
|
377615
|
+
* two costs a duplicate announcement, never a silent one.
|
|
377616
|
+
*/
|
|
377617
|
+
persistIfDirty() {
|
|
377618
|
+
if (!this.dirty)
|
|
377619
|
+
return;
|
|
377620
|
+
this.dirty = false;
|
|
377621
|
+
this.store?.save({
|
|
377622
|
+
latestByKey: Object.fromEntries(this.latestByKey),
|
|
377623
|
+
held: Object.fromEntries(this.held)
|
|
377624
|
+
});
|
|
377625
|
+
}
|
|
377626
|
+
/** Announce ONE scope's full list. `scope` is the node id, `hub` for the hub. */
|
|
377627
|
+
emitList(target, scope) {
|
|
377628
|
+
const list = [...this.held.values()].filter((candidate) => candidate.target === target && scopeOf(candidate) === scope);
|
|
377629
|
+
if (list.length === 0)
|
|
377630
|
+
return;
|
|
377631
|
+
const packages = list.map((candidate) => ({
|
|
377632
|
+
packageName: candidate.packageName,
|
|
377633
|
+
currentVersion: candidate.currentVersion,
|
|
377634
|
+
latestVersion: candidate.latestVersion,
|
|
377635
|
+
nodeId: scope
|
|
377636
|
+
}));
|
|
377637
|
+
const head = list[0];
|
|
377638
|
+
this.eventBus.emit({
|
|
377639
|
+
id: `update.available:${target}:${scope}:${packages.map((pkg) => `${pkg.packageName}@${pkg.latestVersion}`).toSorted().join(",")}`,
|
|
377640
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
377641
|
+
source: this.source,
|
|
377642
|
+
category: types_1.EventCategory.UpdateAvailable,
|
|
377643
|
+
data: {
|
|
377644
|
+
target,
|
|
377645
|
+
packageName: head.packageName,
|
|
377646
|
+
currentVersion: head.currentVersion,
|
|
377647
|
+
latestVersion: head.latestVersion,
|
|
377648
|
+
packages,
|
|
377649
|
+
nodeId: scope,
|
|
377650
|
+
nodeIds: [scope]
|
|
377651
|
+
}
|
|
377652
|
+
});
|
|
377653
|
+
}
|
|
377654
|
+
key(candidate) {
|
|
377655
|
+
return `${candidate.target}:${scopeOf(candidate)}:${candidate.packageName}`;
|
|
377656
|
+
}
|
|
377657
|
+
};
|
|
377658
|
+
exports.UpdateAvailabilityEmitter = UpdateAvailabilityEmitter;
|
|
377659
|
+
function scopeOf(candidate) {
|
|
377660
|
+
return candidate.nodeId ?? "hub";
|
|
377661
|
+
}
|
|
377662
|
+
function stampNode(candidate, nodeId) {
|
|
377663
|
+
if (nodeId === void 0 || candidate.nodeId !== void 0)
|
|
377664
|
+
return candidate;
|
|
377665
|
+
return { ...candidate, nodeId };
|
|
377666
|
+
}
|
|
377667
|
+
}
|
|
377668
|
+
});
|
|
377669
|
+
|
|
377670
|
+
// ../../server/backend/dist/core/update-availability-store.js
|
|
377671
|
+
var require_update_availability_store = __commonJS({
|
|
377672
|
+
"../../server/backend/dist/core/update-availability-store.js"(exports) {
|
|
377673
|
+
"use strict";
|
|
377674
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
377675
|
+
if (k2 === void 0) k2 = k;
|
|
377676
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
377677
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
377678
|
+
desc = { enumerable: true, get: function() {
|
|
377679
|
+
return m[k];
|
|
377680
|
+
} };
|
|
377681
|
+
}
|
|
377682
|
+
Object.defineProperty(o, k2, desc);
|
|
377683
|
+
}) : (function(o, m, k, k2) {
|
|
377684
|
+
if (k2 === void 0) k2 = k;
|
|
377685
|
+
o[k2] = m[k];
|
|
377686
|
+
}));
|
|
377687
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
377688
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
377689
|
+
}) : function(o, v) {
|
|
377690
|
+
o["default"] = v;
|
|
377691
|
+
});
|
|
377692
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
377693
|
+
var ownKeys = function(o) {
|
|
377694
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
377695
|
+
var ar = [];
|
|
377696
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
377697
|
+
return ar;
|
|
377698
|
+
};
|
|
377699
|
+
return ownKeys(o);
|
|
377700
|
+
};
|
|
377701
|
+
return function(mod) {
|
|
377702
|
+
if (mod && mod.__esModule) return mod;
|
|
377703
|
+
var result = {};
|
|
377704
|
+
if (mod != null) {
|
|
377705
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
377706
|
+
}
|
|
377707
|
+
__setModuleDefault(result, mod);
|
|
377708
|
+
return result;
|
|
377709
|
+
};
|
|
377710
|
+
})();
|
|
377711
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
377712
|
+
exports.FileUpdateAvailabilityStore = exports.UPDATE_AVAILABILITY_DIR = void 0;
|
|
377713
|
+
var fs = __importStar(__require("fs"));
|
|
377714
|
+
var path = __importStar(__require("path"));
|
|
377715
|
+
var types_1 = require_dist4();
|
|
377716
|
+
exports.UPDATE_AVAILABILITY_DIR = "update-availability";
|
|
377717
|
+
var FileUpdateAvailabilityStore = class {
|
|
377718
|
+
scopeId;
|
|
377719
|
+
logger;
|
|
377720
|
+
filePath;
|
|
377721
|
+
constructor(dataDir, scopeId, logger) {
|
|
377722
|
+
this.scopeId = scopeId;
|
|
377723
|
+
this.logger = logger;
|
|
377724
|
+
this.filePath = path.join(dataDir, exports.UPDATE_AVAILABILITY_DIR, `${scopeId}.json`);
|
|
377725
|
+
}
|
|
377726
|
+
load() {
|
|
377727
|
+
try {
|
|
377728
|
+
if (!fs.existsSync(this.filePath))
|
|
377729
|
+
return null;
|
|
377730
|
+
const parsed = JSON.parse(fs.readFileSync(this.filePath, "utf-8"));
|
|
377731
|
+
return parseState(parsed);
|
|
377732
|
+
} catch (error) {
|
|
377733
|
+
this.logger.warn("Update-availability state unreadable; starting from empty", {
|
|
377734
|
+
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
377735
|
+
});
|
|
377736
|
+
return null;
|
|
377737
|
+
}
|
|
377738
|
+
}
|
|
377739
|
+
save(state) {
|
|
377740
|
+
try {
|
|
377741
|
+
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
377742
|
+
const tmp = `${this.filePath}.tmp`;
|
|
377743
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
377744
|
+
fs.renameSync(tmp, this.filePath);
|
|
377745
|
+
} catch (error) {
|
|
377746
|
+
this.logger.warn("Failed to persist update-availability state", {
|
|
377747
|
+
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
377748
|
+
});
|
|
377749
|
+
}
|
|
377750
|
+
}
|
|
377751
|
+
};
|
|
377752
|
+
exports.FileUpdateAvailabilityStore = FileUpdateAvailabilityStore;
|
|
377753
|
+
function parseState(raw) {
|
|
377754
|
+
if (raw === null || typeof raw !== "object")
|
|
377755
|
+
return null;
|
|
377756
|
+
const latestRaw = Reflect.get(raw, "latestByKey");
|
|
377757
|
+
const heldRaw = Reflect.get(raw, "held");
|
|
377758
|
+
if (latestRaw === null || typeof latestRaw !== "object")
|
|
377759
|
+
return null;
|
|
377760
|
+
if (heldRaw === null || typeof heldRaw !== "object")
|
|
377761
|
+
return null;
|
|
377762
|
+
const latestByKey = {};
|
|
377763
|
+
for (const [key, value] of Object.entries(latestRaw)) {
|
|
377764
|
+
if (typeof value === "string")
|
|
377765
|
+
latestByKey[key] = value;
|
|
377766
|
+
}
|
|
377767
|
+
const held = {};
|
|
377768
|
+
for (const [key, value] of Object.entries(heldRaw)) {
|
|
377769
|
+
const candidate = parseCandidate(value);
|
|
377770
|
+
if (candidate !== null)
|
|
377771
|
+
held[key] = candidate;
|
|
377772
|
+
}
|
|
377773
|
+
return { latestByKey, held };
|
|
377774
|
+
}
|
|
377775
|
+
function parseCandidate(raw) {
|
|
377776
|
+
if (raw === null || typeof raw !== "object")
|
|
377777
|
+
return null;
|
|
377778
|
+
const target = Reflect.get(raw, "target");
|
|
377779
|
+
const packageName = Reflect.get(raw, "packageName");
|
|
377780
|
+
const currentVersion = Reflect.get(raw, "currentVersion");
|
|
377781
|
+
const latestVersion = Reflect.get(raw, "latestVersion");
|
|
377782
|
+
const nodeId = Reflect.get(raw, "nodeId");
|
|
377783
|
+
if (target !== "addon" && target !== "server")
|
|
377784
|
+
return null;
|
|
377785
|
+
if (typeof packageName !== "string")
|
|
377786
|
+
return null;
|
|
377787
|
+
if (typeof currentVersion !== "string")
|
|
377788
|
+
return null;
|
|
377789
|
+
if (typeof latestVersion !== "string")
|
|
377790
|
+
return null;
|
|
377791
|
+
return {
|
|
377792
|
+
target,
|
|
377793
|
+
packageName,
|
|
377794
|
+
currentVersion,
|
|
377795
|
+
latestVersion,
|
|
377796
|
+
...typeof nodeId === "string" ? { nodeId } : {}
|
|
377797
|
+
};
|
|
377798
|
+
}
|
|
377799
|
+
}
|
|
377800
|
+
});
|
|
377801
|
+
|
|
377470
377802
|
// ../../server/backend/dist/core/updates/restart-marker.js
|
|
377471
377803
|
var require_restart_marker = __commonJS({
|
|
377472
377804
|
"../../server/backend/dist/core/updates/restart-marker.js"(exports) {
|
|
@@ -377921,6 +378253,8 @@ var require_main2 = __commonJS({
|
|
|
377921
378253
|
var agent_group_runner_js_1 = require_agent_group_runner();
|
|
377922
378254
|
var agent_http_js_1 = require_agent_http();
|
|
377923
378255
|
var agent_service_js_1 = require_agent_service();
|
|
378256
|
+
var agent_addon_updates_js_1 = require_agent_addon_updates();
|
|
378257
|
+
var agent_update_routes_js_1 = require_agent_update_routes();
|
|
377924
378258
|
var agent_update_service_js_1 = require_agent_update_service();
|
|
377925
378259
|
var derive_hub_url_js_1 = require_derive_hub_url();
|
|
377926
378260
|
var infra_boot_guard_js_1 = require_infra_boot_guard();
|
|
@@ -378329,13 +378663,29 @@ var require_main2 = __commonJS({
|
|
|
378329
378663
|
broker.createService((0, system_1.createReadinessServiceForRegistry)(agentReadinessRegistry, system_1.AGENT_READINESS_SERVICE_NAME));
|
|
378330
378664
|
}
|
|
378331
378665
|
const getBrokerFn = (() => broker);
|
|
378666
|
+
const updateControls = {
|
|
378667
|
+
server: (0, agent_update_routes_js_1.createAgentServerUpdateControls)(agentUpdateService, (message) => {
|
|
378668
|
+
consoleLogger.warn(`framework update not applied: ${message}`, {
|
|
378669
|
+
tags: { nodeId: config.nodeId }
|
|
378670
|
+
});
|
|
378671
|
+
}),
|
|
378672
|
+
addons: {
|
|
378673
|
+
getReport: () => (0, agent_addon_updates_js_1.buildAgentAddonUpdateReport)({
|
|
378674
|
+
addonsDir: config.addonsDir,
|
|
378675
|
+
...process.env["CAMSTACK_NPM_REGISTRY"] !== void 0 ? { registryUrl: process.env["CAMSTACK_NPM_REGISTRY"] } : {},
|
|
378676
|
+
fetchFn: (url) => fetch(url),
|
|
378677
|
+
isHubReachable: () => getHubConnectionState() === "connected"
|
|
378678
|
+
})
|
|
378679
|
+
}
|
|
378680
|
+
};
|
|
378332
378681
|
void (0, agent_http_js_1.startAgentHttpServer)(getBrokerFn, {
|
|
378333
378682
|
port: config.statusPort ?? 4444,
|
|
378334
378683
|
nodeId: config.nodeId,
|
|
378335
378684
|
dataDir: config.dataDir,
|
|
378336
378685
|
configPath: config.configPath,
|
|
378337
378686
|
onReconnect: reconnect,
|
|
378338
|
-
getHubConnectionState
|
|
378687
|
+
getHubConnectionState,
|
|
378688
|
+
updateControls
|
|
378339
378689
|
});
|
|
378340
378690
|
await bootCoreAddons(broker, config, capabilityRegistry, loadedAddons, loggerFactory);
|
|
378341
378691
|
for (const dest of capabilityRegistry.getCollection("log-destination")) {
|
|
@@ -401027,6 +401377,7 @@ var require_http_request_census = __commonJS({
|
|
|
401027
401377
|
"use strict";
|
|
401028
401378
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
401029
401379
|
exports.HttpRequestCensus = exports.UNKNOWN = exports.PROCEDURE_OVERFLOW = exports.BATCH_OVERFLOW_PROCEDURE = exports.MAX_BATCH_PROCEDURES = exports.USER_AGENT_MAX_CHARS = exports.MAX_PROCEDURES = exports.MAX_GROUPS = exports.MIN_REPORT_EVERY_MS = exports.DEFAULT_REPORT_EVERY_MS = exports.MIN_WINDOW_MS = exports.MAX_WINDOW_MS = exports.TRPC_URL_PREFIX = void 0;
|
|
401380
|
+
exports.zeroPlaneCounts = zeroPlaneCounts;
|
|
401030
401381
|
exports.shortenUserAgent = shortenUserAgent;
|
|
401031
401382
|
exports.parseTrpcProcedures = parseTrpcProcedures;
|
|
401032
401383
|
exports.TRPC_URL_PREFIX = "/trpc/";
|
|
@@ -401042,6 +401393,15 @@ var require_http_request_census = __commonJS({
|
|
|
401042
401393
|
exports.PROCEDURE_OVERFLOW = "(procedure-overflow)";
|
|
401043
401394
|
exports.UNKNOWN = "unknown";
|
|
401044
401395
|
var KEY_SEPARATOR = " | ";
|
|
401396
|
+
function zeroPlaneCounts() {
|
|
401397
|
+
return { http: 0, ws: 0, mesh: 0, unknown: 0 };
|
|
401398
|
+
}
|
|
401399
|
+
function freezePlaneCounts(counts) {
|
|
401400
|
+
return { http: counts.http, ws: counts.ws, mesh: counts.mesh, unknown: counts.unknown };
|
|
401401
|
+
}
|
|
401402
|
+
function sumPlaneCounts(counts) {
|
|
401403
|
+
return counts.http + counts.ws + counts.mesh + counts.unknown;
|
|
401404
|
+
}
|
|
401045
401405
|
function defaultSchedule(fn, ms) {
|
|
401046
401406
|
setTimeout(fn, ms).unref();
|
|
401047
401407
|
}
|
|
@@ -401131,7 +401491,11 @@ var require_http_request_census = __commonJS({
|
|
|
401131
401491
|
batchedRequests = 0;
|
|
401132
401492
|
procedureCalls = 0;
|
|
401133
401493
|
wsConnections = 0;
|
|
401494
|
+
wsMessages = 0;
|
|
401495
|
+
subscriptions = 0;
|
|
401496
|
+
subscriptionStops = 0;
|
|
401134
401497
|
unattributedCalls = 0;
|
|
401498
|
+
planeCalls = zeroPlaneCounts();
|
|
401135
401499
|
byProcedure = /* @__PURE__ */ new Map();
|
|
401136
401500
|
byGroup = /* @__PURE__ */ new Map();
|
|
401137
401501
|
logger = null;
|
|
@@ -401199,38 +401563,85 @@ var require_http_request_census = __commonJS({
|
|
|
401199
401563
|
this.httpRequests += 1;
|
|
401200
401564
|
if (observation.procedures.length > 1)
|
|
401201
401565
|
this.batchedRequests += 1;
|
|
401566
|
+
this.observe({ ...observation, plane: "http", kind: "call" });
|
|
401567
|
+
}
|
|
401568
|
+
/**
|
|
401569
|
+
* Count operations on ANY plane.
|
|
401570
|
+
*
|
|
401571
|
+
* The plane is data rather than a method name so that a plane added later
|
|
401572
|
+
* cannot quietly reuse the HTTP bookkeeping (`httpRequests`,
|
|
401573
|
+
* `batchedRequests`), which counts REQUESTS and means nothing off HTTP.
|
|
401574
|
+
*/
|
|
401575
|
+
observe(observation) {
|
|
401576
|
+
if (!this.isArmed)
|
|
401577
|
+
return;
|
|
401578
|
+
if (observation.procedures.length === 0)
|
|
401579
|
+
return;
|
|
401202
401580
|
const userAgent = shortenUserAgent(observation.userAgent);
|
|
401203
401581
|
const ip = observation.ip ?? exports.UNKNOWN;
|
|
401204
|
-
const principal = observation
|
|
401582
|
+
const { plane, kind, principal } = observation;
|
|
401205
401583
|
for (const procedure of observation.procedures) {
|
|
401206
|
-
|
|
401207
|
-
|
|
401208
|
-
|
|
401584
|
+
if (kind === "subscription")
|
|
401585
|
+
this.subscriptions += 1;
|
|
401586
|
+
else {
|
|
401587
|
+
this.procedureCalls += 1;
|
|
401588
|
+
this.planeCalls[plane] += 1;
|
|
401589
|
+
}
|
|
401590
|
+
this.countProcedure(procedure, plane, kind);
|
|
401591
|
+
const key = [plane, procedure, userAgent, ip, principal].join(KEY_SEPARATOR);
|
|
401209
401592
|
const group = this.byGroup.get(key);
|
|
401210
401593
|
if (group !== void 0) {
|
|
401211
|
-
|
|
401594
|
+
if (kind === "subscription")
|
|
401595
|
+
group.subscriptions += 1;
|
|
401596
|
+
else
|
|
401597
|
+
group.calls += 1;
|
|
401212
401598
|
continue;
|
|
401213
401599
|
}
|
|
401214
401600
|
if (this.byGroup.size >= exports.MAX_GROUPS) {
|
|
401215
401601
|
this.unattributedCalls += 1;
|
|
401216
401602
|
continue;
|
|
401217
401603
|
}
|
|
401218
|
-
this.byGroup.set(key, {
|
|
401604
|
+
this.byGroup.set(key, {
|
|
401605
|
+
plane,
|
|
401606
|
+
procedure,
|
|
401607
|
+
userAgent,
|
|
401608
|
+
ip,
|
|
401609
|
+
principal,
|
|
401610
|
+
calls: kind === "subscription" ? 0 : 1,
|
|
401611
|
+
subscriptions: kind === "subscription" ? 1 : 0
|
|
401612
|
+
});
|
|
401219
401613
|
}
|
|
401220
401614
|
}
|
|
401221
401615
|
/**
|
|
401222
401616
|
* Count one tRPC WebSocket connection opening.
|
|
401223
401617
|
*
|
|
401224
|
-
*
|
|
401225
|
-
*
|
|
401226
|
-
*
|
|
401227
|
-
* else" rather than as "the instrument was off".
|
|
401618
|
+
* NOT a call count - the WS adapter resolves one context per connection.
|
|
401619
|
+
* Kept alongside the per-operation `ws` plane because "37 connections, 0
|
|
401620
|
+
* calls" and "0 connections, 0 calls" are different answers.
|
|
401228
401621
|
*/
|
|
401229
401622
|
observeWsConnection() {
|
|
401230
401623
|
if (!this.isArmed)
|
|
401231
401624
|
return;
|
|
401232
401625
|
this.wsConnections += 1;
|
|
401233
401626
|
}
|
|
401627
|
+
/** Count one client frame the WS plane inspected, operation or not. */
|
|
401628
|
+
observeWsMessage() {
|
|
401629
|
+
if (!this.isArmed)
|
|
401630
|
+
return;
|
|
401631
|
+
this.wsMessages += 1;
|
|
401632
|
+
}
|
|
401633
|
+
/**
|
|
401634
|
+
* Count `subscription.stop` frames.
|
|
401635
|
+
*
|
|
401636
|
+
* Stops carry no procedure path on the wire (tRPC's stop message is `{ id }`
|
|
401637
|
+
* and nothing else), so they are a scalar rather than a group row - inventing
|
|
401638
|
+
* a path for them would put a name on the line that the client never sent.
|
|
401639
|
+
*/
|
|
401640
|
+
observeSubscriptionStop(count = 1) {
|
|
401641
|
+
if (!this.isArmed)
|
|
401642
|
+
return;
|
|
401643
|
+
this.subscriptionStops += count;
|
|
401644
|
+
}
|
|
401234
401645
|
/** Everything the window measured, busiest first. */
|
|
401235
401646
|
snapshot(limit = exports.MAX_GROUPS) {
|
|
401236
401647
|
const elapsedMs = this.elapsedMs();
|
|
@@ -401238,16 +401649,20 @@ var require_http_request_census = __commonJS({
|
|
|
401238
401649
|
const procedures = [...this.byProcedure.entries()].map(([procedure, count]) => ({
|
|
401239
401650
|
procedure,
|
|
401240
401651
|
calls: count.calls,
|
|
401652
|
+
planes: freezePlaneCounts(count.planes),
|
|
401653
|
+
subscriptions: count.subscriptions,
|
|
401241
401654
|
perMin: perMin(count.calls)
|
|
401242
401655
|
})).toSorted((a, b) => b.calls - a.calls);
|
|
401243
401656
|
const groups = [...this.byGroup.values()].map((group) => ({
|
|
401657
|
+
plane: group.plane,
|
|
401244
401658
|
procedure: group.procedure,
|
|
401245
401659
|
userAgent: group.userAgent,
|
|
401246
401660
|
ip: group.ip,
|
|
401247
401661
|
principal: group.principal,
|
|
401248
401662
|
calls: group.calls,
|
|
401663
|
+
subscriptions: group.subscriptions,
|
|
401249
401664
|
perMin: perMin(group.calls)
|
|
401250
|
-
})).toSorted((a, b) => b.calls - a.calls);
|
|
401665
|
+
})).toSorted((a, b) => b.calls + b.subscriptions - (a.calls + a.subscriptions));
|
|
401251
401666
|
return {
|
|
401252
401667
|
armed: this.isArmed,
|
|
401253
401668
|
elapsedMs,
|
|
@@ -401256,7 +401671,12 @@ var require_http_request_census = __commonJS({
|
|
|
401256
401671
|
httpRequests: this.httpRequests,
|
|
401257
401672
|
batchedRequests: this.batchedRequests,
|
|
401258
401673
|
procedureCalls: this.procedureCalls,
|
|
401674
|
+
planes: freezePlaneCounts(this.planeCalls),
|
|
401675
|
+
planesExplainTotal: sumPlaneCounts(this.planeCalls) === this.procedureCalls,
|
|
401259
401676
|
wsConnections: this.wsConnections,
|
|
401677
|
+
wsMessages: this.wsMessages,
|
|
401678
|
+
subscriptions: this.subscriptions,
|
|
401679
|
+
subscriptionStops: this.subscriptionStops,
|
|
401260
401680
|
distinctGroups: this.byGroup.size,
|
|
401261
401681
|
unattributedCalls: this.unattributedCalls,
|
|
401262
401682
|
procedures: procedures.slice(0, limit),
|
|
@@ -401264,55 +401684,71 @@ var require_http_request_census = __commonJS({
|
|
|
401264
401684
|
};
|
|
401265
401685
|
}
|
|
401266
401686
|
/**
|
|
401267
|
-
* Emit ONE aggregated line.
|
|
401687
|
+
* Emit ONE aggregated line - the line that answers the question.
|
|
401268
401688
|
*
|
|
401269
|
-
*
|
|
401270
|
-
*
|
|
401689
|
+
* Field order is the reading order: `planes` first (which transport), then
|
|
401690
|
+
* `planesExplainTotal` (is any call unaccounted for), then `procedures`
|
|
401691
|
+
* (which procedure, split by plane), then `top` (which caller). `top` is the
|
|
401692
|
+
* part that may be cut; the first three never are.
|
|
401693
|
+
*
|
|
401694
|
+
* The message is `transport census` rather than `http request census`
|
|
401695
|
+
* because the line now carries three planes. Grepping Loki for the old text
|
|
401696
|
+
* would find only pre-2026-08-27 windows, which is the honest outcome: those
|
|
401697
|
+
* windows really did measure one plane.
|
|
401271
401698
|
*/
|
|
401272
401699
|
report(phase) {
|
|
401273
401700
|
const logger = this.logger;
|
|
401274
401701
|
if (logger === null)
|
|
401275
401702
|
return;
|
|
401276
401703
|
const snap = this.snapshot();
|
|
401277
|
-
logger.info("
|
|
401704
|
+
logger.info("transport census", {
|
|
401278
401705
|
meta: {
|
|
401279
401706
|
phase,
|
|
401280
401707
|
armed: snap.armed,
|
|
401281
401708
|
elapsedMs: snap.elapsedMs,
|
|
401282
401709
|
windowMs: snap.windowMs,
|
|
401710
|
+
planes: snap.planes,
|
|
401711
|
+
procedureCalls: snap.procedureCalls,
|
|
401712
|
+
// The acceptance criterion, ON the line: false means a call was
|
|
401713
|
+
// counted on no plane, i.e. this instrument is missing one.
|
|
401714
|
+
planesExplainTotal: snap.planesExplainTotal,
|
|
401715
|
+
subscriptions: snap.subscriptions,
|
|
401716
|
+
subscriptionStops: snap.subscriptionStops,
|
|
401283
401717
|
httpRequests: snap.httpRequests,
|
|
401284
401718
|
batchedRequests: snap.batchedRequests,
|
|
401285
|
-
procedureCalls: snap.procedureCalls,
|
|
401286
401719
|
wsConnections: snap.wsConnections,
|
|
401720
|
+
wsMessages: snap.wsMessages,
|
|
401287
401721
|
distinctGroups: snap.distinctGroups,
|
|
401288
401722
|
unattributedCalls: snap.unattributedCalls,
|
|
401289
401723
|
procedures: snap.procedures.slice(0, REPORTED_PROCEDURES),
|
|
401290
401724
|
top: snap.groups.slice(0, REPORTED_GROUPS).map((group) => ({
|
|
401725
|
+
plane: group.plane,
|
|
401291
401726
|
procedure: group.procedure,
|
|
401292
401727
|
ua: group.userAgent,
|
|
401293
401728
|
ip: group.ip,
|
|
401294
401729
|
principal: group.principal,
|
|
401295
401730
|
calls: group.calls,
|
|
401731
|
+
subscriptions: group.subscriptions,
|
|
401296
401732
|
perMin: group.perMin
|
|
401297
401733
|
}))
|
|
401298
401734
|
}
|
|
401299
401735
|
});
|
|
401300
401736
|
}
|
|
401301
|
-
countProcedure(procedure) {
|
|
401737
|
+
countProcedure(procedure, plane, kind) {
|
|
401302
401738
|
const existing = this.byProcedure.get(procedure);
|
|
401303
401739
|
if (existing !== void 0) {
|
|
401304
|
-
existing
|
|
401740
|
+
bumpCount(existing, plane, kind);
|
|
401305
401741
|
return;
|
|
401306
401742
|
}
|
|
401307
401743
|
if (this.byProcedure.size >= exports.MAX_PROCEDURES) {
|
|
401308
|
-
const overflow = this.byProcedure.get(exports.PROCEDURE_OVERFLOW);
|
|
401309
|
-
|
|
401310
|
-
|
|
401311
|
-
else
|
|
401312
|
-
overflow.calls += 1;
|
|
401744
|
+
const overflow = this.byProcedure.get(exports.PROCEDURE_OVERFLOW) ?? newCount();
|
|
401745
|
+
bumpCount(overflow, plane, kind);
|
|
401746
|
+
this.byProcedure.set(exports.PROCEDURE_OVERFLOW, overflow);
|
|
401313
401747
|
return;
|
|
401314
401748
|
}
|
|
401315
|
-
|
|
401749
|
+
const fresh = newCount();
|
|
401750
|
+
bumpCount(fresh, plane, kind);
|
|
401751
|
+
this.byProcedure.set(procedure, fresh);
|
|
401316
401752
|
}
|
|
401317
401753
|
elapsedMs() {
|
|
401318
401754
|
if (this.armedAt === 0)
|
|
@@ -401327,7 +401763,11 @@ var require_http_request_census = __commonJS({
|
|
|
401327
401763
|
this.batchedRequests = 0;
|
|
401328
401764
|
this.procedureCalls = 0;
|
|
401329
401765
|
this.wsConnections = 0;
|
|
401766
|
+
this.wsMessages = 0;
|
|
401767
|
+
this.subscriptions = 0;
|
|
401768
|
+
this.subscriptionStops = 0;
|
|
401330
401769
|
this.unattributedCalls = 0;
|
|
401770
|
+
this.planeCalls = zeroPlaneCounts();
|
|
401331
401771
|
}
|
|
401332
401772
|
scheduleTick(generation) {
|
|
401333
401773
|
this.schedule(() => {
|
|
@@ -401345,6 +401785,17 @@ var require_http_request_census = __commonJS({
|
|
|
401345
401785
|
exports.HttpRequestCensus = HttpRequestCensus;
|
|
401346
401786
|
var REPORTED_PROCEDURES = 40;
|
|
401347
401787
|
var REPORTED_GROUPS = 25;
|
|
401788
|
+
function newCount() {
|
|
401789
|
+
return { calls: 0, subscriptions: 0, planes: zeroPlaneCounts() };
|
|
401790
|
+
}
|
|
401791
|
+
function bumpCount(count, plane, kind) {
|
|
401792
|
+
if (kind === "subscription") {
|
|
401793
|
+
count.subscriptions += 1;
|
|
401794
|
+
return;
|
|
401795
|
+
}
|
|
401796
|
+
count.calls += 1;
|
|
401797
|
+
count.planes[plane] += 1;
|
|
401798
|
+
}
|
|
401348
401799
|
function clamp(value, min, max) {
|
|
401349
401800
|
if (!Number.isFinite(value))
|
|
401350
401801
|
return min;
|
|
@@ -401673,7 +402124,7 @@ var require_request_census_settings = __commonJS({
|
|
|
401673
402124
|
updatedAt: this.now()
|
|
401674
402125
|
};
|
|
401675
402126
|
const persisted = await this.write(record);
|
|
401676
|
-
this.logger?.info("
|
|
402127
|
+
this.logger?.info("transport census switched", {
|
|
401677
402128
|
meta: {
|
|
401678
402129
|
armed: this.census.armed,
|
|
401679
402130
|
armedUntilMs: this.census.armedUntilMs,
|
|
@@ -401698,13 +402149,13 @@ var require_request_census_settings = __commonJS({
|
|
|
401698
402149
|
return false;
|
|
401699
402150
|
const remainingMs = until - this.now();
|
|
401700
402151
|
if (remainingMs <= 0) {
|
|
401701
|
-
this.logger?.info("
|
|
402152
|
+
this.logger?.info("transport census not restored - window already expired", {
|
|
401702
402153
|
meta: { armedUntilMs: until }
|
|
401703
402154
|
});
|
|
401704
402155
|
return false;
|
|
401705
402156
|
}
|
|
401706
402157
|
this.census.arm(remainingMs, record?.reportEveryMs ?? http_request_census_js_1.DEFAULT_REPORT_EVERY_MS);
|
|
401707
|
-
this.logger?.info("
|
|
402158
|
+
this.logger?.info("transport census restored from system-settings", {
|
|
401708
402159
|
meta: { remainingMs, armedUntilMs: this.census.armedUntilMs }
|
|
401709
402160
|
});
|
|
401710
402161
|
return true;
|
|
@@ -401722,7 +402173,7 @@ var require_request_census_settings = __commonJS({
|
|
|
401722
402173
|
});
|
|
401723
402174
|
return toRecord(raw);
|
|
401724
402175
|
} catch (err) {
|
|
401725
|
-
this.logger?.warn("
|
|
402176
|
+
this.logger?.warn("transport census settings read failed", {
|
|
401726
402177
|
meta: { error: (0, types_1.errMsg)(err) }
|
|
401727
402178
|
});
|
|
401728
402179
|
return null;
|
|
@@ -401737,7 +402188,7 @@ var require_request_census_settings = __commonJS({
|
|
|
401737
402188
|
});
|
|
401738
402189
|
return true;
|
|
401739
402190
|
} catch (err) {
|
|
401740
|
-
this.logger?.warn("
|
|
402191
|
+
this.logger?.warn("transport census armed in memory but NOT persisted - it will not survive a restart", { meta: { error: (0, types_1.errMsg)(err) } });
|
|
401741
402192
|
return false;
|
|
401742
402193
|
}
|
|
401743
402194
|
}
|
|
@@ -403305,6 +403756,499 @@ var require_cap_providers = __commonJS({
|
|
|
403305
403756
|
}
|
|
403306
403757
|
});
|
|
403307
403758
|
|
|
403759
|
+
// ../../server/backend/dist/core/auth/share-token.service.js
|
|
403760
|
+
var require_share_token_service = __commonJS({
|
|
403761
|
+
"../../server/backend/dist/core/auth/share-token.service.js"(exports) {
|
|
403762
|
+
"use strict";
|
|
403763
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
403764
|
+
if (k2 === void 0) k2 = k;
|
|
403765
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
403766
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
403767
|
+
desc = { enumerable: true, get: function() {
|
|
403768
|
+
return m[k];
|
|
403769
|
+
} };
|
|
403770
|
+
}
|
|
403771
|
+
Object.defineProperty(o, k2, desc);
|
|
403772
|
+
}) : (function(o, m, k, k2) {
|
|
403773
|
+
if (k2 === void 0) k2 = k;
|
|
403774
|
+
o[k2] = m[k];
|
|
403775
|
+
}));
|
|
403776
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
403777
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
403778
|
+
}) : function(o, v) {
|
|
403779
|
+
o["default"] = v;
|
|
403780
|
+
});
|
|
403781
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
403782
|
+
var ownKeys = function(o) {
|
|
403783
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
403784
|
+
var ar = [];
|
|
403785
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
403786
|
+
return ar;
|
|
403787
|
+
};
|
|
403788
|
+
return ownKeys(o);
|
|
403789
|
+
};
|
|
403790
|
+
return function(mod) {
|
|
403791
|
+
if (mod && mod.__esModule) return mod;
|
|
403792
|
+
var result = {};
|
|
403793
|
+
if (mod != null) {
|
|
403794
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
403795
|
+
}
|
|
403796
|
+
__setModuleDefault(result, mod);
|
|
403797
|
+
return result;
|
|
403798
|
+
};
|
|
403799
|
+
})();
|
|
403800
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
403801
|
+
exports.ShareTokenService = exports.ShareTokenRecordSchema = exports.ShareTokenScopeSchema = exports.SHARE_TOKEN_MAX_DEVICES = exports.SHARE_TOKEN_TTL_DEFAULT_SEC = exports.SHARE_TOKEN_TTL_MAX_SEC = exports.SHARE_TOKEN_TTL_MIN_SEC = exports.SHARE_TOKEN_PREFIX = void 0;
|
|
403802
|
+
var crypto2 = __importStar(__require("crypto"));
|
|
403803
|
+
var zod_1 = require_zod();
|
|
403804
|
+
var SHARE_TOKENS_COLLECTION = "share_view_tokens";
|
|
403805
|
+
var SHARE_TOKENS_INDEXES = [
|
|
403806
|
+
{ name: "idx_share_view_tokens_hash", columns: ["tokenHash"] },
|
|
403807
|
+
{ name: "idx_share_view_tokens_user", columns: ["userId"] }
|
|
403808
|
+
];
|
|
403809
|
+
exports.SHARE_TOKEN_PREFIX = "csv_";
|
|
403810
|
+
exports.SHARE_TOKEN_TTL_MIN_SEC = 60;
|
|
403811
|
+
exports.SHARE_TOKEN_TTL_MAX_SEC = 30 * 24 * 60 * 60;
|
|
403812
|
+
exports.SHARE_TOKEN_TTL_DEFAULT_SEC = 7 * 24 * 60 * 60;
|
|
403813
|
+
exports.SHARE_TOKEN_MAX_DEVICES = 64;
|
|
403814
|
+
exports.ShareTokenScopeSchema = zod_1.z.object({
|
|
403815
|
+
kind: zod_1.z.enum(["grid-view", "events-view"]),
|
|
403816
|
+
deviceIds: zod_1.z.array(zod_1.z.number().int().nonnegative()).min(1).max(exports.SHARE_TOKEN_MAX_DEVICES)
|
|
403817
|
+
});
|
|
403818
|
+
exports.ShareTokenRecordSchema = zod_1.z.object({
|
|
403819
|
+
id: zod_1.z.string(),
|
|
403820
|
+
/** The user that minted the share link (owner — may revoke it). */
|
|
403821
|
+
userId: zod_1.z.string(),
|
|
403822
|
+
tokenHash: zod_1.z.string(),
|
|
403823
|
+
/** First 12 chars of the raw token — display/audit label only. */
|
|
403824
|
+
tokenPrefix: zod_1.z.string(),
|
|
403825
|
+
scope: exports.ShareTokenScopeSchema,
|
|
403826
|
+
createdAt: zod_1.z.number(),
|
|
403827
|
+
/** Epoch ms — or `null` for a never-expiring token (explicit choice at mint). */
|
|
403828
|
+
expiresAt: zod_1.z.number().nullable(),
|
|
403829
|
+
lastUsedAt: zod_1.z.number().optional()
|
|
403830
|
+
});
|
|
403831
|
+
function parseShareToken(data) {
|
|
403832
|
+
const parsed = exports.ShareTokenRecordSchema.safeParse(data);
|
|
403833
|
+
return parsed.success ? parsed.data : null;
|
|
403834
|
+
}
|
|
403835
|
+
var ShareTokenService = class {
|
|
403836
|
+
getStore;
|
|
403837
|
+
logger;
|
|
403838
|
+
/**
|
|
403839
|
+
* Declaration is one-time per process; reset only if the backend itself
|
|
403840
|
+
* is swapped (it never is at runtime — the getter is lazy solely because
|
|
403841
|
+
* the sqlite builtin registers after this service is constructed).
|
|
403842
|
+
*/
|
|
403843
|
+
collectionDeclared = false;
|
|
403844
|
+
constructor(getStore, logger = null) {
|
|
403845
|
+
this.getStore = getStore;
|
|
403846
|
+
this.logger = logger;
|
|
403847
|
+
}
|
|
403848
|
+
/**
|
|
403849
|
+
* Resolve the backend AND ensure `share_view_tokens` is declared before
|
|
403850
|
+
* the first operation. The structured settings backend fail-closes on
|
|
403851
|
+
* undeclared collections; this KV shape (`id` PK + `data` TEXT) is
|
|
403852
|
+
* byte-identical to what the legacy on-demand path created, so existing
|
|
403853
|
+
* rows keep working with no migration.
|
|
403854
|
+
*/
|
|
403855
|
+
async store() {
|
|
403856
|
+
const store = this.getStore();
|
|
403857
|
+
if (!store) {
|
|
403858
|
+
throw new Error("Share tokens unavailable \u2014 settings backend not ready");
|
|
403859
|
+
}
|
|
403860
|
+
if (!this.collectionDeclared) {
|
|
403861
|
+
await store.declareCollection({
|
|
403862
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403863
|
+
columns: [
|
|
403864
|
+
{ name: "id", type: "TEXT", primaryKey: true, notNull: true },
|
|
403865
|
+
{ name: "data", type: "TEXT", notNull: true }
|
|
403866
|
+
],
|
|
403867
|
+
indexes: SHARE_TOKENS_INDEXES
|
|
403868
|
+
});
|
|
403869
|
+
this.collectionDeclared = true;
|
|
403870
|
+
}
|
|
403871
|
+
return store;
|
|
403872
|
+
}
|
|
403873
|
+
/**
|
|
403874
|
+
* Mint a new share token. Throws on invalid scope or out-of-bounds TTL
|
|
403875
|
+
* (fail fast — the router's Zod input schema should have caught both).
|
|
403876
|
+
* `ttlSec: 'never'` is the explicit opt-in to a never-expiring token
|
|
403877
|
+
* (`expiresAt: null`); omitted falls back to the 7-day default.
|
|
403878
|
+
* Returns the RAW token exactly once; only its hash is persisted.
|
|
403879
|
+
*/
|
|
403880
|
+
async create(input) {
|
|
403881
|
+
const scope = exports.ShareTokenScopeSchema.parse(input.scope);
|
|
403882
|
+
const ttlSec = input.ttlSec ?? exports.SHARE_TOKEN_TTL_DEFAULT_SEC;
|
|
403883
|
+
if (ttlSec !== "never" && (!Number.isInteger(ttlSec) || ttlSec < exports.SHARE_TOKEN_TTL_MIN_SEC || ttlSec > exports.SHARE_TOKEN_TTL_MAX_SEC)) {
|
|
403884
|
+
throw new Error(`Share token TTL out of bounds \u2014 got ${ttlSec}s, allowed [${exports.SHARE_TOKEN_TTL_MIN_SEC}s, ${exports.SHARE_TOKEN_TTL_MAX_SEC}s] or 'never'`);
|
|
403885
|
+
}
|
|
403886
|
+
const rawToken = `${exports.SHARE_TOKEN_PREFIX}${crypto2.randomBytes(32).toString("hex")}`;
|
|
403887
|
+
const now = Date.now();
|
|
403888
|
+
const record = {
|
|
403889
|
+
id: crypto2.randomUUID(),
|
|
403890
|
+
userId: input.userId,
|
|
403891
|
+
tokenHash: crypto2.createHash("sha256").update(rawToken).digest("hex"),
|
|
403892
|
+
tokenPrefix: rawToken.slice(0, 12),
|
|
403893
|
+
scope,
|
|
403894
|
+
createdAt: now,
|
|
403895
|
+
expiresAt: ttlSec === "never" ? null : now + ttlSec * 1e3
|
|
403896
|
+
};
|
|
403897
|
+
await (await this.store()).insert({
|
|
403898
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403899
|
+
record: { id: record.id, data: { ...record } }
|
|
403900
|
+
});
|
|
403901
|
+
this.logger?.info("Share token minted", {
|
|
403902
|
+
meta: {
|
|
403903
|
+
id: record.id,
|
|
403904
|
+
userId: record.userId,
|
|
403905
|
+
kind: scope.kind,
|
|
403906
|
+
deviceIds: scope.deviceIds,
|
|
403907
|
+
expiresAt: record.expiresAt
|
|
403908
|
+
}
|
|
403909
|
+
});
|
|
403910
|
+
return { token: rawToken, record };
|
|
403911
|
+
}
|
|
403912
|
+
/**
|
|
403913
|
+
* Resolve a raw `csv_*` token to its record. Returns `null` for:
|
|
403914
|
+
* wrong prefix, unknown token, corrupt record, or expired token.
|
|
403915
|
+
* Never throws on bad input — the auth boundary treats `null` as 401.
|
|
403916
|
+
*/
|
|
403917
|
+
async validate(rawToken) {
|
|
403918
|
+
if (!rawToken.startsWith(exports.SHARE_TOKEN_PREFIX))
|
|
403919
|
+
return null;
|
|
403920
|
+
const tokenHash = crypto2.createHash("sha256").update(rawToken).digest("hex");
|
|
403921
|
+
const results = await (await this.store()).query({
|
|
403922
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403923
|
+
filter: { where: { tokenHash } }
|
|
403924
|
+
});
|
|
403925
|
+
const first = results[0];
|
|
403926
|
+
if (!first)
|
|
403927
|
+
return null;
|
|
403928
|
+
const record = parseShareToken(first.data);
|
|
403929
|
+
if (!record)
|
|
403930
|
+
return null;
|
|
403931
|
+
if (record.expiresAt !== null && Date.now() > record.expiresAt)
|
|
403932
|
+
return null;
|
|
403933
|
+
this.touchLastUsed(record).catch(() => {
|
|
403934
|
+
});
|
|
403935
|
+
return record;
|
|
403936
|
+
}
|
|
403937
|
+
/**
|
|
403938
|
+
* Revoke (delete) a share token. Only the minting user or an admin may
|
|
403939
|
+
* revoke. Returns `false` when the token doesn't exist; throws on a
|
|
403940
|
+
* permission mismatch so the router surfaces a FORBIDDEN.
|
|
403941
|
+
*/
|
|
403942
|
+
async revoke(input) {
|
|
403943
|
+
const results = await (await this.store()).query({
|
|
403944
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403945
|
+
filter: { where: { id: input.id } }
|
|
403946
|
+
});
|
|
403947
|
+
const first = results[0];
|
|
403948
|
+
if (!first)
|
|
403949
|
+
return false;
|
|
403950
|
+
const record = parseShareToken(first.data);
|
|
403951
|
+
if (!record) {
|
|
403952
|
+
await (await this.store()).delete({ collection: SHARE_TOKENS_COLLECTION, key: input.id });
|
|
403953
|
+
return true;
|
|
403954
|
+
}
|
|
403955
|
+
if (!input.callerIsAdmin && record.userId !== input.callerUserId) {
|
|
403956
|
+
throw new Error("Only the token owner or an admin can revoke a share token");
|
|
403957
|
+
}
|
|
403958
|
+
await (await this.store()).delete({ collection: SHARE_TOKENS_COLLECTION, key: input.id });
|
|
403959
|
+
this.logger?.info("Share token revoked", {
|
|
403960
|
+
meta: { id: record.id, byUserId: input.callerUserId }
|
|
403961
|
+
});
|
|
403962
|
+
return true;
|
|
403963
|
+
}
|
|
403964
|
+
/** Every share token minted by `userId`, expired ones included. */
|
|
403965
|
+
async listForUser(userId) {
|
|
403966
|
+
const results = await (await this.store()).query({
|
|
403967
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403968
|
+
filter: { where: { userId } }
|
|
403969
|
+
});
|
|
403970
|
+
return results.map((r) => parseShareToken(r.data)).filter((r) => r !== null);
|
|
403971
|
+
}
|
|
403972
|
+
/** All share tokens (admin listing). */
|
|
403973
|
+
async listAll() {
|
|
403974
|
+
const results = await (await this.store()).query({
|
|
403975
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403976
|
+
filter: {}
|
|
403977
|
+
});
|
|
403978
|
+
return results.map((r) => parseShareToken(r.data)).filter((r) => r !== null);
|
|
403979
|
+
}
|
|
403980
|
+
async touchLastUsed(record) {
|
|
403981
|
+
await (await this.store()).update({
|
|
403982
|
+
collection: SHARE_TOKENS_COLLECTION,
|
|
403983
|
+
id: record.id,
|
|
403984
|
+
data: { ...record, lastUsedAt: Date.now() }
|
|
403985
|
+
});
|
|
403986
|
+
}
|
|
403987
|
+
};
|
|
403988
|
+
exports.ShareTokenService = ShareTokenService;
|
|
403989
|
+
}
|
|
403990
|
+
});
|
|
403991
|
+
|
|
403992
|
+
// ../../server/backend/dist/api/trpc/trpc-error-principal.js
|
|
403993
|
+
var require_trpc_error_principal = __commonJS({
|
|
403994
|
+
"../../server/backend/dist/api/trpc/trpc-error-principal.js"(exports) {
|
|
403995
|
+
"use strict";
|
|
403996
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
403997
|
+
exports.readCredentialIdentity = readCredentialIdentity;
|
|
403998
|
+
exports.describeTrpcPrincipal = describeTrpcPrincipal;
|
|
403999
|
+
function readCredentialIdentity(claims) {
|
|
404000
|
+
const kind = Reflect.get(claims, "kind");
|
|
404001
|
+
if (kind !== "sso-bridge")
|
|
404002
|
+
return {};
|
|
404003
|
+
const provider = Reflect.get(claims, "provider");
|
|
404004
|
+
const sessionId = Reflect.get(claims, "sessionId");
|
|
404005
|
+
return {
|
|
404006
|
+
...typeof provider === "string" && provider !== "" ? { credential: provider } : {},
|
|
404007
|
+
...typeof sessionId === "string" && sessionId !== "" ? { sessionId } : {}
|
|
404008
|
+
};
|
|
404009
|
+
}
|
|
404010
|
+
function describeTrpcPrincipal(user) {
|
|
404011
|
+
if (!user)
|
|
404012
|
+
return "anonymous";
|
|
404013
|
+
const name = user.username || user.id || "unknown";
|
|
404014
|
+
if (user.shareView)
|
|
404015
|
+
return `${name} (share-view)`;
|
|
404016
|
+
if (user.isAdmin)
|
|
404017
|
+
return `${name} (admin)`;
|
|
404018
|
+
if (user.credential) {
|
|
404019
|
+
const session = user.oauthSessionId ? ` session=${user.oauthSessionId}` : "";
|
|
404020
|
+
return `${name} (${user.credential}${session})`;
|
|
404021
|
+
}
|
|
404022
|
+
if (user.isScoped)
|
|
404023
|
+
return `${name} (scoped-token)`;
|
|
404024
|
+
return `${name} (session)`;
|
|
404025
|
+
}
|
|
404026
|
+
}
|
|
404027
|
+
});
|
|
404028
|
+
|
|
404029
|
+
// ../../server/backend/dist/api/trpc/trpc.context.js
|
|
404030
|
+
var require_trpc_context = __commonJS({
|
|
404031
|
+
"../../server/backend/dist/api/trpc/trpc.context.js"(exports) {
|
|
404032
|
+
"use strict";
|
|
404033
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
404034
|
+
exports.createMeshTrpcContext = createMeshTrpcContext;
|
|
404035
|
+
exports.createTrpcContext = createTrpcContext;
|
|
404036
|
+
exports.createWsTrpcContext = createWsTrpcContext;
|
|
404037
|
+
var types_1 = require_dist4();
|
|
404038
|
+
var share_token_service_js_1 = require_share_token_service();
|
|
404039
|
+
var trpc_error_principal_js_1 = require_trpc_error_principal();
|
|
404040
|
+
var SCOPE_REFRESH_TTL_MS = 3e4;
|
|
404041
|
+
var SCOPE_REFRESH_MISS_TTL_MS = 5e3;
|
|
404042
|
+
var liveScopeMemo = /* @__PURE__ */ new Map();
|
|
404043
|
+
async function refreshScopesFromStore(userId, addonRegistry) {
|
|
404044
|
+
const cached = liveScopeMemo.get(userId);
|
|
404045
|
+
const now = Date.now();
|
|
404046
|
+
if (cached && now - cached.at < (cached.scopes === null ? SCOPE_REFRESH_MISS_TTL_MS : SCOPE_REFRESH_TTL_MS)) {
|
|
404047
|
+
return cached.scopes;
|
|
404048
|
+
}
|
|
404049
|
+
let scopes = null;
|
|
404050
|
+
try {
|
|
404051
|
+
const userMgmt = addonRegistry.getCapabilityRegistry().getSingleton("user-management");
|
|
404052
|
+
const fresh = typeof userMgmt?.listUsers === "function" ? (await userMgmt.listUsers()).find((u) => u.id === userId) : null;
|
|
404053
|
+
if (fresh)
|
|
404054
|
+
scopes = (0, types_1.normalizeTokenScopes)(fresh.scopes ?? []);
|
|
404055
|
+
} catch {
|
|
404056
|
+
scopes = null;
|
|
404057
|
+
}
|
|
404058
|
+
liveScopeMemo.set(userId, { at: now, scopes });
|
|
404059
|
+
if (liveScopeMemo.size > 512) {
|
|
404060
|
+
for (const [key, entry] of liveScopeMemo) {
|
|
404061
|
+
if (now - entry.at > SCOPE_REFRESH_TTL_MS * 4)
|
|
404062
|
+
liveScopeMemo.delete(key);
|
|
404063
|
+
}
|
|
404064
|
+
}
|
|
404065
|
+
return scopes;
|
|
404066
|
+
}
|
|
404067
|
+
function readQuery(req) {
|
|
404068
|
+
if (!("query" in req))
|
|
404069
|
+
return null;
|
|
404070
|
+
const q = Reflect.get(req, "query");
|
|
404071
|
+
if (q === null || typeof q !== "object" || Array.isArray(q))
|
|
404072
|
+
return null;
|
|
404073
|
+
return { ...q };
|
|
404074
|
+
}
|
|
404075
|
+
function extractTokenFromRequest(req) {
|
|
404076
|
+
const authHeader = req.headers.authorization;
|
|
404077
|
+
if (authHeader && typeof authHeader === "string") {
|
|
404078
|
+
const [scheme, token2] = authHeader.split(" ");
|
|
404079
|
+
if (scheme === "Bearer" && token2)
|
|
404080
|
+
return token2;
|
|
404081
|
+
}
|
|
404082
|
+
const q = readQuery(req);
|
|
404083
|
+
if (q && typeof q.token === "string") {
|
|
404084
|
+
return q.token;
|
|
404085
|
+
}
|
|
404086
|
+
const url = req.url;
|
|
404087
|
+
if (url) {
|
|
404088
|
+
const qIdx = url.indexOf("?");
|
|
404089
|
+
if (qIdx !== -1) {
|
|
404090
|
+
const t = new URLSearchParams(url.slice(qIdx + 1)).get("token");
|
|
404091
|
+
if (t)
|
|
404092
|
+
return t;
|
|
404093
|
+
}
|
|
404094
|
+
}
|
|
404095
|
+
return null;
|
|
404096
|
+
}
|
|
404097
|
+
async function resolveUser(token2, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
404098
|
+
if (!token2)
|
|
404099
|
+
return null;
|
|
404100
|
+
if (token2.startsWith(share_token_service_js_1.SHARE_TOKEN_PREFIX)) {
|
|
404101
|
+
if (!shareTokens)
|
|
404102
|
+
return null;
|
|
404103
|
+
try {
|
|
404104
|
+
const record = await shareTokens.validate(token2);
|
|
404105
|
+
if (!record)
|
|
404106
|
+
return null;
|
|
404107
|
+
return {
|
|
404108
|
+
id: record.userId,
|
|
404109
|
+
// Display label — `share:<prefix>` keeps audit logs readable
|
|
404110
|
+
// without exposing the token hash.
|
|
404111
|
+
username: `share:${record.tokenPrefix}`,
|
|
404112
|
+
isAdmin: false,
|
|
404113
|
+
permissions: {
|
|
404114
|
+
isAdmin: false,
|
|
404115
|
+
allowedProviders: "*",
|
|
404116
|
+
allowedDevices: {}
|
|
404117
|
+
},
|
|
404118
|
+
isApiKey: true,
|
|
404119
|
+
shareView: { tokenId: record.id, scope: record.scope }
|
|
404120
|
+
};
|
|
404121
|
+
} catch {
|
|
404122
|
+
return null;
|
|
404123
|
+
}
|
|
404124
|
+
}
|
|
404125
|
+
if (token2.startsWith("cst_")) {
|
|
404126
|
+
try {
|
|
404127
|
+
const userMgmt = addonRegistry.getCapabilityRegistry().getSingleton("user-management");
|
|
404128
|
+
if (!userMgmt)
|
|
404129
|
+
return null;
|
|
404130
|
+
const record = await userMgmt.validateScopedToken({ token: token2 });
|
|
404131
|
+
if (!record)
|
|
404132
|
+
return null;
|
|
404133
|
+
return {
|
|
404134
|
+
id: record.userId,
|
|
404135
|
+
// Display label — `scoped:<prefix>` makes audit logs read
|
|
404136
|
+
// naturally without exposing the token hash.
|
|
404137
|
+
username: `scoped:${record.tokenPrefix}`,
|
|
404138
|
+
isAdmin: false,
|
|
404139
|
+
permissions: {
|
|
404140
|
+
isAdmin: false,
|
|
404141
|
+
allowedProviders: "*",
|
|
404142
|
+
allowedDevices: {}
|
|
404143
|
+
},
|
|
404144
|
+
isApiKey: true,
|
|
404145
|
+
isScoped: true,
|
|
404146
|
+
// Migrate any v2 `device:targets` grant to a v3 selector at the
|
|
404147
|
+
// boundary so the enforcement matcher only ever sees v3.
|
|
404148
|
+
scopes: (0, types_1.normalizeTokenScopes)(record.scopes)
|
|
404149
|
+
};
|
|
404150
|
+
} catch {
|
|
404151
|
+
return null;
|
|
404152
|
+
}
|
|
404153
|
+
}
|
|
404154
|
+
try {
|
|
404155
|
+
const payload = authService.verifyToken(token2);
|
|
404156
|
+
if (typeof payload.isAdmin !== "boolean") {
|
|
404157
|
+
return null;
|
|
404158
|
+
}
|
|
404159
|
+
const principal = (0, types_1.classifyBearerPrincipal)(payload);
|
|
404160
|
+
if (principal.kind === "not-a-credential") {
|
|
404161
|
+
logger?.warn("trpc: refused a bearer that is not an API credential", {
|
|
404162
|
+
meta: { reason: principal.reason, userId: payload.userId ?? payload.keyId ?? "unknown" }
|
|
404163
|
+
});
|
|
404164
|
+
return null;
|
|
404165
|
+
}
|
|
404166
|
+
const credential = (0, trpc_error_principal_js_1.readCredentialIdentity)(payload);
|
|
404167
|
+
return {
|
|
404168
|
+
id: payload.userId ?? payload.keyId ?? "unknown",
|
|
404169
|
+
username: payload.username ?? "unknown",
|
|
404170
|
+
isAdmin: payload.isAdmin,
|
|
404171
|
+
permissions: {
|
|
404172
|
+
isAdmin: payload.isAdmin,
|
|
404173
|
+
allowedProviders: payload.allowedProviders,
|
|
404174
|
+
allowedDevices: payload.allowedDevices
|
|
404175
|
+
},
|
|
404176
|
+
isApiKey: payload.type === "api_key",
|
|
404177
|
+
agentId: payload.agentId,
|
|
404178
|
+
// Scopes are baked into the JWT at login; the middleware uses
|
|
404179
|
+
// them to gate every call until the user re-logs. Normalised at the
|
|
404180
|
+
// boundary — a v2 `device:targets` JWT (issued before the v3 model)
|
|
404181
|
+
// migrates to a selector here, so a pre-v3 token keeps working.
|
|
404182
|
+
//
|
|
404183
|
+
// …but a login-time snapshot is exactly the bug: an admin editing a
|
|
404184
|
+
// user's scopes expects the change to APPLY, and the live session
|
|
404185
|
+
// kept gating on the old set until re-login (2026-08-15: a user
|
|
404186
|
+
// granted the whole fleet kept seeing zero cameras). For non-admin
|
|
404187
|
+
// SESSION principals the store's current scopes win when readable
|
|
404188
|
+
// (memoized — see above); the JWT's copy is the fallback when the
|
|
404189
|
+
// user-management cap is unreachable, so a store hiccup never
|
|
404190
|
+
// locks anybody out mid-request.
|
|
404191
|
+
//
|
|
404192
|
+
// `session` ONLY, and that word is the whole fix. An ACCOUNT-LINK token
|
|
404193
|
+
// is governed by the grant the operator consented to, not by the linking
|
|
404194
|
+
// user's record: it always carries `isAdmin: false` (`oauth-grants.ts`
|
|
404195
|
+
// → `baseClaims`) and its owner is normally an admin, whose record is
|
|
404196
|
+
// deliberately unscoped — so the refresh replaced a six-scope Home
|
|
404197
|
+
// Assistant grant with `[]` and the hub refused the component's first
|
|
404198
|
+
// call with `Have: (none)` (2026-08-19). The user store knows nothing
|
|
404199
|
+
// about a link and must not get a vote on one.
|
|
404200
|
+
...payload.scopes !== void 0 ? { scopes: (0, types_1.normalizeTokenScopes)(payload.scopes) } : {},
|
|
404201
|
+
...!payload.isAdmin && principal.kind === "session" ? await (async () => {
|
|
404202
|
+
const fresh = await refreshScopesFromStore(payload.userId ?? payload.keyId ?? "unknown", addonRegistry);
|
|
404203
|
+
return fresh !== null ? { scopes: fresh } : {};
|
|
404204
|
+
})() : {},
|
|
404205
|
+
...credential.credential !== void 0 ? { credential: credential.credential } : {},
|
|
404206
|
+
...credential.sessionId !== void 0 ? { oauthSessionId: credential.sessionId } : {}
|
|
404207
|
+
};
|
|
404208
|
+
} catch {
|
|
404209
|
+
return null;
|
|
404210
|
+
}
|
|
404211
|
+
}
|
|
404212
|
+
function makeDeviceScopeLookup(addonRegistry) {
|
|
404213
|
+
return {
|
|
404214
|
+
getAncestors: (deviceId) => addonRegistry.getPersistedAncestors(deviceId),
|
|
404215
|
+
getType: (deviceId) => addonRegistry.getPersistedType(deviceId),
|
|
404216
|
+
getLocation: (deviceId) => addonRegistry.getPersistedLocation(deviceId)
|
|
404217
|
+
};
|
|
404218
|
+
}
|
|
404219
|
+
function createMeshTrpcContext() {
|
|
404220
|
+
const user = {
|
|
404221
|
+
id: "mesh",
|
|
404222
|
+
username: "mesh",
|
|
404223
|
+
isAdmin: true,
|
|
404224
|
+
permissions: { isAdmin: true, allowedProviders: "*", allowedDevices: {} },
|
|
404225
|
+
isApiKey: true
|
|
404226
|
+
};
|
|
404227
|
+
return { user };
|
|
404228
|
+
}
|
|
404229
|
+
async function createTrpcContext(req, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
404230
|
+
const token2 = extractTokenFromRequest(req);
|
|
404231
|
+
return {
|
|
404232
|
+
user: await resolveUser(token2, authService, addonRegistry, shareTokens, logger),
|
|
404233
|
+
req,
|
|
404234
|
+
deviceScopeLookup: makeDeviceScopeLookup(addonRegistry),
|
|
404235
|
+
deviceFleet: () => addonRegistry.getPersistedDeviceList()
|
|
404236
|
+
};
|
|
404237
|
+
}
|
|
404238
|
+
async function createWsTrpcContext(opts, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
404239
|
+
const paramToken = opts.info.connectionParams?.["token"];
|
|
404240
|
+
const token2 = (typeof paramToken === "string" ? paramToken : null) ?? extractTokenFromRequest(opts.req);
|
|
404241
|
+
const user = await resolveUser(token2, authService, addonRegistry, shareTokens, logger);
|
|
404242
|
+
return {
|
|
404243
|
+
user,
|
|
404244
|
+
req: opts.req,
|
|
404245
|
+
deviceScopeLookup: makeDeviceScopeLookup(addonRegistry),
|
|
404246
|
+
deviceFleet: () => addonRegistry.getPersistedDeviceList()
|
|
404247
|
+
};
|
|
404248
|
+
}
|
|
404249
|
+
}
|
|
404250
|
+
});
|
|
404251
|
+
|
|
403308
404252
|
// ../../node_modules/superjson/dist/double-indexed-kv.js
|
|
403309
404253
|
var DoubleIndexedKV;
|
|
403310
404254
|
var init_double_indexed_kv = __esm({
|
|
@@ -404812,509 +405756,18 @@ var require_trpc_middleware = __commonJS({
|
|
|
404812
405756
|
}
|
|
404813
405757
|
});
|
|
404814
405758
|
|
|
404815
|
-
// ../../server/backend/dist/core/auth/share-token.service.js
|
|
404816
|
-
var require_share_token_service = __commonJS({
|
|
404817
|
-
"../../server/backend/dist/core/auth/share-token.service.js"(exports) {
|
|
404818
|
-
"use strict";
|
|
404819
|
-
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
404820
|
-
if (k2 === void 0) k2 = k;
|
|
404821
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
404822
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
404823
|
-
desc = { enumerable: true, get: function() {
|
|
404824
|
-
return m[k];
|
|
404825
|
-
} };
|
|
404826
|
-
}
|
|
404827
|
-
Object.defineProperty(o, k2, desc);
|
|
404828
|
-
}) : (function(o, m, k, k2) {
|
|
404829
|
-
if (k2 === void 0) k2 = k;
|
|
404830
|
-
o[k2] = m[k];
|
|
404831
|
-
}));
|
|
404832
|
-
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
404833
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
404834
|
-
}) : function(o, v) {
|
|
404835
|
-
o["default"] = v;
|
|
404836
|
-
});
|
|
404837
|
-
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
404838
|
-
var ownKeys = function(o) {
|
|
404839
|
-
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
404840
|
-
var ar = [];
|
|
404841
|
-
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
404842
|
-
return ar;
|
|
404843
|
-
};
|
|
404844
|
-
return ownKeys(o);
|
|
404845
|
-
};
|
|
404846
|
-
return function(mod) {
|
|
404847
|
-
if (mod && mod.__esModule) return mod;
|
|
404848
|
-
var result = {};
|
|
404849
|
-
if (mod != null) {
|
|
404850
|
-
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
404851
|
-
}
|
|
404852
|
-
__setModuleDefault(result, mod);
|
|
404853
|
-
return result;
|
|
404854
|
-
};
|
|
404855
|
-
})();
|
|
404856
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
404857
|
-
exports.ShareTokenService = exports.ShareTokenRecordSchema = exports.ShareTokenScopeSchema = exports.SHARE_TOKEN_MAX_DEVICES = exports.SHARE_TOKEN_TTL_DEFAULT_SEC = exports.SHARE_TOKEN_TTL_MAX_SEC = exports.SHARE_TOKEN_TTL_MIN_SEC = exports.SHARE_TOKEN_PREFIX = void 0;
|
|
404858
|
-
var crypto2 = __importStar(__require("crypto"));
|
|
404859
|
-
var zod_1 = require_zod();
|
|
404860
|
-
var SHARE_TOKENS_COLLECTION = "share_view_tokens";
|
|
404861
|
-
var SHARE_TOKENS_INDEXES = [
|
|
404862
|
-
{ name: "idx_share_view_tokens_hash", columns: ["tokenHash"] },
|
|
404863
|
-
{ name: "idx_share_view_tokens_user", columns: ["userId"] }
|
|
404864
|
-
];
|
|
404865
|
-
exports.SHARE_TOKEN_PREFIX = "csv_";
|
|
404866
|
-
exports.SHARE_TOKEN_TTL_MIN_SEC = 60;
|
|
404867
|
-
exports.SHARE_TOKEN_TTL_MAX_SEC = 30 * 24 * 60 * 60;
|
|
404868
|
-
exports.SHARE_TOKEN_TTL_DEFAULT_SEC = 7 * 24 * 60 * 60;
|
|
404869
|
-
exports.SHARE_TOKEN_MAX_DEVICES = 64;
|
|
404870
|
-
exports.ShareTokenScopeSchema = zod_1.z.object({
|
|
404871
|
-
kind: zod_1.z.enum(["grid-view", "events-view"]),
|
|
404872
|
-
deviceIds: zod_1.z.array(zod_1.z.number().int().nonnegative()).min(1).max(exports.SHARE_TOKEN_MAX_DEVICES)
|
|
404873
|
-
});
|
|
404874
|
-
exports.ShareTokenRecordSchema = zod_1.z.object({
|
|
404875
|
-
id: zod_1.z.string(),
|
|
404876
|
-
/** The user that minted the share link (owner — may revoke it). */
|
|
404877
|
-
userId: zod_1.z.string(),
|
|
404878
|
-
tokenHash: zod_1.z.string(),
|
|
404879
|
-
/** First 12 chars of the raw token — display/audit label only. */
|
|
404880
|
-
tokenPrefix: zod_1.z.string(),
|
|
404881
|
-
scope: exports.ShareTokenScopeSchema,
|
|
404882
|
-
createdAt: zod_1.z.number(),
|
|
404883
|
-
/** Epoch ms — or `null` for a never-expiring token (explicit choice at mint). */
|
|
404884
|
-
expiresAt: zod_1.z.number().nullable(),
|
|
404885
|
-
lastUsedAt: zod_1.z.number().optional()
|
|
404886
|
-
});
|
|
404887
|
-
function parseShareToken(data) {
|
|
404888
|
-
const parsed = exports.ShareTokenRecordSchema.safeParse(data);
|
|
404889
|
-
return parsed.success ? parsed.data : null;
|
|
404890
|
-
}
|
|
404891
|
-
var ShareTokenService = class {
|
|
404892
|
-
getStore;
|
|
404893
|
-
logger;
|
|
404894
|
-
/**
|
|
404895
|
-
* Declaration is one-time per process; reset only if the backend itself
|
|
404896
|
-
* is swapped (it never is at runtime — the getter is lazy solely because
|
|
404897
|
-
* the sqlite builtin registers after this service is constructed).
|
|
404898
|
-
*/
|
|
404899
|
-
collectionDeclared = false;
|
|
404900
|
-
constructor(getStore, logger = null) {
|
|
404901
|
-
this.getStore = getStore;
|
|
404902
|
-
this.logger = logger;
|
|
404903
|
-
}
|
|
404904
|
-
/**
|
|
404905
|
-
* Resolve the backend AND ensure `share_view_tokens` is declared before
|
|
404906
|
-
* the first operation. The structured settings backend fail-closes on
|
|
404907
|
-
* undeclared collections; this KV shape (`id` PK + `data` TEXT) is
|
|
404908
|
-
* byte-identical to what the legacy on-demand path created, so existing
|
|
404909
|
-
* rows keep working with no migration.
|
|
404910
|
-
*/
|
|
404911
|
-
async store() {
|
|
404912
|
-
const store = this.getStore();
|
|
404913
|
-
if (!store) {
|
|
404914
|
-
throw new Error("Share tokens unavailable \u2014 settings backend not ready");
|
|
404915
|
-
}
|
|
404916
|
-
if (!this.collectionDeclared) {
|
|
404917
|
-
await store.declareCollection({
|
|
404918
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
404919
|
-
columns: [
|
|
404920
|
-
{ name: "id", type: "TEXT", primaryKey: true, notNull: true },
|
|
404921
|
-
{ name: "data", type: "TEXT", notNull: true }
|
|
404922
|
-
],
|
|
404923
|
-
indexes: SHARE_TOKENS_INDEXES
|
|
404924
|
-
});
|
|
404925
|
-
this.collectionDeclared = true;
|
|
404926
|
-
}
|
|
404927
|
-
return store;
|
|
404928
|
-
}
|
|
404929
|
-
/**
|
|
404930
|
-
* Mint a new share token. Throws on invalid scope or out-of-bounds TTL
|
|
404931
|
-
* (fail fast — the router's Zod input schema should have caught both).
|
|
404932
|
-
* `ttlSec: 'never'` is the explicit opt-in to a never-expiring token
|
|
404933
|
-
* (`expiresAt: null`); omitted falls back to the 7-day default.
|
|
404934
|
-
* Returns the RAW token exactly once; only its hash is persisted.
|
|
404935
|
-
*/
|
|
404936
|
-
async create(input) {
|
|
404937
|
-
const scope = exports.ShareTokenScopeSchema.parse(input.scope);
|
|
404938
|
-
const ttlSec = input.ttlSec ?? exports.SHARE_TOKEN_TTL_DEFAULT_SEC;
|
|
404939
|
-
if (ttlSec !== "never" && (!Number.isInteger(ttlSec) || ttlSec < exports.SHARE_TOKEN_TTL_MIN_SEC || ttlSec > exports.SHARE_TOKEN_TTL_MAX_SEC)) {
|
|
404940
|
-
throw new Error(`Share token TTL out of bounds \u2014 got ${ttlSec}s, allowed [${exports.SHARE_TOKEN_TTL_MIN_SEC}s, ${exports.SHARE_TOKEN_TTL_MAX_SEC}s] or 'never'`);
|
|
404941
|
-
}
|
|
404942
|
-
const rawToken = `${exports.SHARE_TOKEN_PREFIX}${crypto2.randomBytes(32).toString("hex")}`;
|
|
404943
|
-
const now = Date.now();
|
|
404944
|
-
const record = {
|
|
404945
|
-
id: crypto2.randomUUID(),
|
|
404946
|
-
userId: input.userId,
|
|
404947
|
-
tokenHash: crypto2.createHash("sha256").update(rawToken).digest("hex"),
|
|
404948
|
-
tokenPrefix: rawToken.slice(0, 12),
|
|
404949
|
-
scope,
|
|
404950
|
-
createdAt: now,
|
|
404951
|
-
expiresAt: ttlSec === "never" ? null : now + ttlSec * 1e3
|
|
404952
|
-
};
|
|
404953
|
-
await (await this.store()).insert({
|
|
404954
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
404955
|
-
record: { id: record.id, data: { ...record } }
|
|
404956
|
-
});
|
|
404957
|
-
this.logger?.info("Share token minted", {
|
|
404958
|
-
meta: {
|
|
404959
|
-
id: record.id,
|
|
404960
|
-
userId: record.userId,
|
|
404961
|
-
kind: scope.kind,
|
|
404962
|
-
deviceIds: scope.deviceIds,
|
|
404963
|
-
expiresAt: record.expiresAt
|
|
404964
|
-
}
|
|
404965
|
-
});
|
|
404966
|
-
return { token: rawToken, record };
|
|
404967
|
-
}
|
|
404968
|
-
/**
|
|
404969
|
-
* Resolve a raw `csv_*` token to its record. Returns `null` for:
|
|
404970
|
-
* wrong prefix, unknown token, corrupt record, or expired token.
|
|
404971
|
-
* Never throws on bad input — the auth boundary treats `null` as 401.
|
|
404972
|
-
*/
|
|
404973
|
-
async validate(rawToken) {
|
|
404974
|
-
if (!rawToken.startsWith(exports.SHARE_TOKEN_PREFIX))
|
|
404975
|
-
return null;
|
|
404976
|
-
const tokenHash = crypto2.createHash("sha256").update(rawToken).digest("hex");
|
|
404977
|
-
const results = await (await this.store()).query({
|
|
404978
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
404979
|
-
filter: { where: { tokenHash } }
|
|
404980
|
-
});
|
|
404981
|
-
const first = results[0];
|
|
404982
|
-
if (!first)
|
|
404983
|
-
return null;
|
|
404984
|
-
const record = parseShareToken(first.data);
|
|
404985
|
-
if (!record)
|
|
404986
|
-
return null;
|
|
404987
|
-
if (record.expiresAt !== null && Date.now() > record.expiresAt)
|
|
404988
|
-
return null;
|
|
404989
|
-
this.touchLastUsed(record).catch(() => {
|
|
404990
|
-
});
|
|
404991
|
-
return record;
|
|
404992
|
-
}
|
|
404993
|
-
/**
|
|
404994
|
-
* Revoke (delete) a share token. Only the minting user or an admin may
|
|
404995
|
-
* revoke. Returns `false` when the token doesn't exist; throws on a
|
|
404996
|
-
* permission mismatch so the router surfaces a FORBIDDEN.
|
|
404997
|
-
*/
|
|
404998
|
-
async revoke(input) {
|
|
404999
|
-
const results = await (await this.store()).query({
|
|
405000
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
405001
|
-
filter: { where: { id: input.id } }
|
|
405002
|
-
});
|
|
405003
|
-
const first = results[0];
|
|
405004
|
-
if (!first)
|
|
405005
|
-
return false;
|
|
405006
|
-
const record = parseShareToken(first.data);
|
|
405007
|
-
if (!record) {
|
|
405008
|
-
await (await this.store()).delete({ collection: SHARE_TOKENS_COLLECTION, key: input.id });
|
|
405009
|
-
return true;
|
|
405010
|
-
}
|
|
405011
|
-
if (!input.callerIsAdmin && record.userId !== input.callerUserId) {
|
|
405012
|
-
throw new Error("Only the token owner or an admin can revoke a share token");
|
|
405013
|
-
}
|
|
405014
|
-
await (await this.store()).delete({ collection: SHARE_TOKENS_COLLECTION, key: input.id });
|
|
405015
|
-
this.logger?.info("Share token revoked", {
|
|
405016
|
-
meta: { id: record.id, byUserId: input.callerUserId }
|
|
405017
|
-
});
|
|
405018
|
-
return true;
|
|
405019
|
-
}
|
|
405020
|
-
/** Every share token minted by `userId`, expired ones included. */
|
|
405021
|
-
async listForUser(userId) {
|
|
405022
|
-
const results = await (await this.store()).query({
|
|
405023
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
405024
|
-
filter: { where: { userId } }
|
|
405025
|
-
});
|
|
405026
|
-
return results.map((r) => parseShareToken(r.data)).filter((r) => r !== null);
|
|
405027
|
-
}
|
|
405028
|
-
/** All share tokens (admin listing). */
|
|
405029
|
-
async listAll() {
|
|
405030
|
-
const results = await (await this.store()).query({
|
|
405031
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
405032
|
-
filter: {}
|
|
405033
|
-
});
|
|
405034
|
-
return results.map((r) => parseShareToken(r.data)).filter((r) => r !== null);
|
|
405035
|
-
}
|
|
405036
|
-
async touchLastUsed(record) {
|
|
405037
|
-
await (await this.store()).update({
|
|
405038
|
-
collection: SHARE_TOKENS_COLLECTION,
|
|
405039
|
-
id: record.id,
|
|
405040
|
-
data: { ...record, lastUsedAt: Date.now() }
|
|
405041
|
-
});
|
|
405042
|
-
}
|
|
405043
|
-
};
|
|
405044
|
-
exports.ShareTokenService = ShareTokenService;
|
|
405045
|
-
}
|
|
405046
|
-
});
|
|
405047
|
-
|
|
405048
|
-
// ../../server/backend/dist/api/trpc/trpc-error-principal.js
|
|
405049
|
-
var require_trpc_error_principal = __commonJS({
|
|
405050
|
-
"../../server/backend/dist/api/trpc/trpc-error-principal.js"(exports) {
|
|
405051
|
-
"use strict";
|
|
405052
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
405053
|
-
exports.readCredentialIdentity = readCredentialIdentity;
|
|
405054
|
-
exports.describeTrpcPrincipal = describeTrpcPrincipal;
|
|
405055
|
-
function readCredentialIdentity(claims) {
|
|
405056
|
-
const kind = Reflect.get(claims, "kind");
|
|
405057
|
-
if (kind !== "sso-bridge")
|
|
405058
|
-
return {};
|
|
405059
|
-
const provider = Reflect.get(claims, "provider");
|
|
405060
|
-
const sessionId = Reflect.get(claims, "sessionId");
|
|
405061
|
-
return {
|
|
405062
|
-
...typeof provider === "string" && provider !== "" ? { credential: provider } : {},
|
|
405063
|
-
...typeof sessionId === "string" && sessionId !== "" ? { sessionId } : {}
|
|
405064
|
-
};
|
|
405065
|
-
}
|
|
405066
|
-
function describeTrpcPrincipal(user) {
|
|
405067
|
-
if (!user)
|
|
405068
|
-
return "anonymous";
|
|
405069
|
-
const name = user.username || user.id || "unknown";
|
|
405070
|
-
if (user.shareView)
|
|
405071
|
-
return `${name} (share-view)`;
|
|
405072
|
-
if (user.isAdmin)
|
|
405073
|
-
return `${name} (admin)`;
|
|
405074
|
-
if (user.credential) {
|
|
405075
|
-
const session = user.oauthSessionId ? ` session=${user.oauthSessionId}` : "";
|
|
405076
|
-
return `${name} (${user.credential}${session})`;
|
|
405077
|
-
}
|
|
405078
|
-
if (user.isScoped)
|
|
405079
|
-
return `${name} (scoped-token)`;
|
|
405080
|
-
return `${name} (session)`;
|
|
405081
|
-
}
|
|
405082
|
-
}
|
|
405083
|
-
});
|
|
405084
|
-
|
|
405085
|
-
// ../../server/backend/dist/api/trpc/trpc.context.js
|
|
405086
|
-
var require_trpc_context = __commonJS({
|
|
405087
|
-
"../../server/backend/dist/api/trpc/trpc.context.js"(exports) {
|
|
405088
|
-
"use strict";
|
|
405089
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
405090
|
-
exports.createMeshTrpcContext = createMeshTrpcContext;
|
|
405091
|
-
exports.createTrpcContext = createTrpcContext;
|
|
405092
|
-
exports.createWsTrpcContext = createWsTrpcContext;
|
|
405093
|
-
var types_1 = require_dist4();
|
|
405094
|
-
var share_token_service_js_1 = require_share_token_service();
|
|
405095
|
-
var trpc_error_principal_js_1 = require_trpc_error_principal();
|
|
405096
|
-
var SCOPE_REFRESH_TTL_MS = 3e4;
|
|
405097
|
-
var SCOPE_REFRESH_MISS_TTL_MS = 5e3;
|
|
405098
|
-
var liveScopeMemo = /* @__PURE__ */ new Map();
|
|
405099
|
-
async function refreshScopesFromStore(userId, addonRegistry) {
|
|
405100
|
-
const cached = liveScopeMemo.get(userId);
|
|
405101
|
-
const now = Date.now();
|
|
405102
|
-
if (cached && now - cached.at < (cached.scopes === null ? SCOPE_REFRESH_MISS_TTL_MS : SCOPE_REFRESH_TTL_MS)) {
|
|
405103
|
-
return cached.scopes;
|
|
405104
|
-
}
|
|
405105
|
-
let scopes = null;
|
|
405106
|
-
try {
|
|
405107
|
-
const userMgmt = addonRegistry.getCapabilityRegistry().getSingleton("user-management");
|
|
405108
|
-
const fresh = typeof userMgmt?.listUsers === "function" ? (await userMgmt.listUsers()).find((u) => u.id === userId) : null;
|
|
405109
|
-
if (fresh)
|
|
405110
|
-
scopes = (0, types_1.normalizeTokenScopes)(fresh.scopes ?? []);
|
|
405111
|
-
} catch {
|
|
405112
|
-
scopes = null;
|
|
405113
|
-
}
|
|
405114
|
-
liveScopeMemo.set(userId, { at: now, scopes });
|
|
405115
|
-
if (liveScopeMemo.size > 512) {
|
|
405116
|
-
for (const [key, entry] of liveScopeMemo) {
|
|
405117
|
-
if (now - entry.at > SCOPE_REFRESH_TTL_MS * 4)
|
|
405118
|
-
liveScopeMemo.delete(key);
|
|
405119
|
-
}
|
|
405120
|
-
}
|
|
405121
|
-
return scopes;
|
|
405122
|
-
}
|
|
405123
|
-
function readQuery(req) {
|
|
405124
|
-
if (!("query" in req))
|
|
405125
|
-
return null;
|
|
405126
|
-
const q = Reflect.get(req, "query");
|
|
405127
|
-
if (q === null || typeof q !== "object" || Array.isArray(q))
|
|
405128
|
-
return null;
|
|
405129
|
-
return { ...q };
|
|
405130
|
-
}
|
|
405131
|
-
function extractTokenFromRequest(req) {
|
|
405132
|
-
const authHeader = req.headers.authorization;
|
|
405133
|
-
if (authHeader && typeof authHeader === "string") {
|
|
405134
|
-
const [scheme, token2] = authHeader.split(" ");
|
|
405135
|
-
if (scheme === "Bearer" && token2)
|
|
405136
|
-
return token2;
|
|
405137
|
-
}
|
|
405138
|
-
const q = readQuery(req);
|
|
405139
|
-
if (q && typeof q.token === "string") {
|
|
405140
|
-
return q.token;
|
|
405141
|
-
}
|
|
405142
|
-
const url = req.url;
|
|
405143
|
-
if (url) {
|
|
405144
|
-
const qIdx = url.indexOf("?");
|
|
405145
|
-
if (qIdx !== -1) {
|
|
405146
|
-
const t = new URLSearchParams(url.slice(qIdx + 1)).get("token");
|
|
405147
|
-
if (t)
|
|
405148
|
-
return t;
|
|
405149
|
-
}
|
|
405150
|
-
}
|
|
405151
|
-
return null;
|
|
405152
|
-
}
|
|
405153
|
-
async function resolveUser(token2, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
405154
|
-
if (!token2)
|
|
405155
|
-
return null;
|
|
405156
|
-
if (token2.startsWith(share_token_service_js_1.SHARE_TOKEN_PREFIX)) {
|
|
405157
|
-
if (!shareTokens)
|
|
405158
|
-
return null;
|
|
405159
|
-
try {
|
|
405160
|
-
const record = await shareTokens.validate(token2);
|
|
405161
|
-
if (!record)
|
|
405162
|
-
return null;
|
|
405163
|
-
return {
|
|
405164
|
-
id: record.userId,
|
|
405165
|
-
// Display label — `share:<prefix>` keeps audit logs readable
|
|
405166
|
-
// without exposing the token hash.
|
|
405167
|
-
username: `share:${record.tokenPrefix}`,
|
|
405168
|
-
isAdmin: false,
|
|
405169
|
-
permissions: {
|
|
405170
|
-
isAdmin: false,
|
|
405171
|
-
allowedProviders: "*",
|
|
405172
|
-
allowedDevices: {}
|
|
405173
|
-
},
|
|
405174
|
-
isApiKey: true,
|
|
405175
|
-
shareView: { tokenId: record.id, scope: record.scope }
|
|
405176
|
-
};
|
|
405177
|
-
} catch {
|
|
405178
|
-
return null;
|
|
405179
|
-
}
|
|
405180
|
-
}
|
|
405181
|
-
if (token2.startsWith("cst_")) {
|
|
405182
|
-
try {
|
|
405183
|
-
const userMgmt = addonRegistry.getCapabilityRegistry().getSingleton("user-management");
|
|
405184
|
-
if (!userMgmt)
|
|
405185
|
-
return null;
|
|
405186
|
-
const record = await userMgmt.validateScopedToken({ token: token2 });
|
|
405187
|
-
if (!record)
|
|
405188
|
-
return null;
|
|
405189
|
-
return {
|
|
405190
|
-
id: record.userId,
|
|
405191
|
-
// Display label — `scoped:<prefix>` makes audit logs read
|
|
405192
|
-
// naturally without exposing the token hash.
|
|
405193
|
-
username: `scoped:${record.tokenPrefix}`,
|
|
405194
|
-
isAdmin: false,
|
|
405195
|
-
permissions: {
|
|
405196
|
-
isAdmin: false,
|
|
405197
|
-
allowedProviders: "*",
|
|
405198
|
-
allowedDevices: {}
|
|
405199
|
-
},
|
|
405200
|
-
isApiKey: true,
|
|
405201
|
-
isScoped: true,
|
|
405202
|
-
// Migrate any v2 `device:targets` grant to a v3 selector at the
|
|
405203
|
-
// boundary so the enforcement matcher only ever sees v3.
|
|
405204
|
-
scopes: (0, types_1.normalizeTokenScopes)(record.scopes)
|
|
405205
|
-
};
|
|
405206
|
-
} catch {
|
|
405207
|
-
return null;
|
|
405208
|
-
}
|
|
405209
|
-
}
|
|
405210
|
-
try {
|
|
405211
|
-
const payload = authService.verifyToken(token2);
|
|
405212
|
-
if (typeof payload.isAdmin !== "boolean") {
|
|
405213
|
-
return null;
|
|
405214
|
-
}
|
|
405215
|
-
const principal = (0, types_1.classifyBearerPrincipal)(payload);
|
|
405216
|
-
if (principal.kind === "not-a-credential") {
|
|
405217
|
-
logger?.warn("trpc: refused a bearer that is not an API credential", {
|
|
405218
|
-
meta: { reason: principal.reason, userId: payload.userId ?? payload.keyId ?? "unknown" }
|
|
405219
|
-
});
|
|
405220
|
-
return null;
|
|
405221
|
-
}
|
|
405222
|
-
const credential = (0, trpc_error_principal_js_1.readCredentialIdentity)(payload);
|
|
405223
|
-
return {
|
|
405224
|
-
id: payload.userId ?? payload.keyId ?? "unknown",
|
|
405225
|
-
username: payload.username ?? "unknown",
|
|
405226
|
-
isAdmin: payload.isAdmin,
|
|
405227
|
-
permissions: {
|
|
405228
|
-
isAdmin: payload.isAdmin,
|
|
405229
|
-
allowedProviders: payload.allowedProviders,
|
|
405230
|
-
allowedDevices: payload.allowedDevices
|
|
405231
|
-
},
|
|
405232
|
-
isApiKey: payload.type === "api_key",
|
|
405233
|
-
agentId: payload.agentId,
|
|
405234
|
-
// Scopes are baked into the JWT at login; the middleware uses
|
|
405235
|
-
// them to gate every call until the user re-logs. Normalised at the
|
|
405236
|
-
// boundary — a v2 `device:targets` JWT (issued before the v3 model)
|
|
405237
|
-
// migrates to a selector here, so a pre-v3 token keeps working.
|
|
405238
|
-
//
|
|
405239
|
-
// …but a login-time snapshot is exactly the bug: an admin editing a
|
|
405240
|
-
// user's scopes expects the change to APPLY, and the live session
|
|
405241
|
-
// kept gating on the old set until re-login (2026-08-15: a user
|
|
405242
|
-
// granted the whole fleet kept seeing zero cameras). For non-admin
|
|
405243
|
-
// SESSION principals the store's current scopes win when readable
|
|
405244
|
-
// (memoized — see above); the JWT's copy is the fallback when the
|
|
405245
|
-
// user-management cap is unreachable, so a store hiccup never
|
|
405246
|
-
// locks anybody out mid-request.
|
|
405247
|
-
//
|
|
405248
|
-
// `session` ONLY, and that word is the whole fix. An ACCOUNT-LINK token
|
|
405249
|
-
// is governed by the grant the operator consented to, not by the linking
|
|
405250
|
-
// user's record: it always carries `isAdmin: false` (`oauth-grants.ts`
|
|
405251
|
-
// → `baseClaims`) and its owner is normally an admin, whose record is
|
|
405252
|
-
// deliberately unscoped — so the refresh replaced a six-scope Home
|
|
405253
|
-
// Assistant grant with `[]` and the hub refused the component's first
|
|
405254
|
-
// call with `Have: (none)` (2026-08-19). The user store knows nothing
|
|
405255
|
-
// about a link and must not get a vote on one.
|
|
405256
|
-
...payload.scopes !== void 0 ? { scopes: (0, types_1.normalizeTokenScopes)(payload.scopes) } : {},
|
|
405257
|
-
...!payload.isAdmin && principal.kind === "session" ? await (async () => {
|
|
405258
|
-
const fresh = await refreshScopesFromStore(payload.userId ?? payload.keyId ?? "unknown", addonRegistry);
|
|
405259
|
-
return fresh !== null ? { scopes: fresh } : {};
|
|
405260
|
-
})() : {},
|
|
405261
|
-
...credential.credential !== void 0 ? { credential: credential.credential } : {},
|
|
405262
|
-
...credential.sessionId !== void 0 ? { oauthSessionId: credential.sessionId } : {}
|
|
405263
|
-
};
|
|
405264
|
-
} catch {
|
|
405265
|
-
return null;
|
|
405266
|
-
}
|
|
405267
|
-
}
|
|
405268
|
-
function makeDeviceScopeLookup(addonRegistry) {
|
|
405269
|
-
return {
|
|
405270
|
-
getAncestors: (deviceId) => addonRegistry.getPersistedAncestors(deviceId),
|
|
405271
|
-
getType: (deviceId) => addonRegistry.getPersistedType(deviceId),
|
|
405272
|
-
getLocation: (deviceId) => addonRegistry.getPersistedLocation(deviceId)
|
|
405273
|
-
};
|
|
405274
|
-
}
|
|
405275
|
-
function createMeshTrpcContext() {
|
|
405276
|
-
const user = {
|
|
405277
|
-
id: "mesh",
|
|
405278
|
-
username: "mesh",
|
|
405279
|
-
isAdmin: true,
|
|
405280
|
-
permissions: { isAdmin: true, allowedProviders: "*", allowedDevices: {} },
|
|
405281
|
-
isApiKey: true
|
|
405282
|
-
};
|
|
405283
|
-
return { user };
|
|
405284
|
-
}
|
|
405285
|
-
async function createTrpcContext(req, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
405286
|
-
const token2 = extractTokenFromRequest(req);
|
|
405287
|
-
return {
|
|
405288
|
-
user: await resolveUser(token2, authService, addonRegistry, shareTokens, logger),
|
|
405289
|
-
req,
|
|
405290
|
-
deviceScopeLookup: makeDeviceScopeLookup(addonRegistry),
|
|
405291
|
-
deviceFleet: () => addonRegistry.getPersistedDeviceList()
|
|
405292
|
-
};
|
|
405293
|
-
}
|
|
405294
|
-
async function createWsTrpcContext(opts, authService, addonRegistry, shareTokens = null, logger = null) {
|
|
405295
|
-
const paramToken = opts.info.connectionParams?.["token"];
|
|
405296
|
-
const token2 = (typeof paramToken === "string" ? paramToken : null) ?? extractTokenFromRequest(opts.req);
|
|
405297
|
-
const user = await resolveUser(token2, authService, addonRegistry, shareTokens, logger);
|
|
405298
|
-
return {
|
|
405299
|
-
user,
|
|
405300
|
-
req: opts.req,
|
|
405301
|
-
deviceScopeLookup: makeDeviceScopeLookup(addonRegistry),
|
|
405302
|
-
deviceFleet: () => addonRegistry.getPersistedDeviceList()
|
|
405303
|
-
};
|
|
405304
|
-
}
|
|
405305
|
-
}
|
|
405306
|
-
});
|
|
405307
|
-
|
|
405308
405759
|
// ../../server/backend/dist/api/trpc/core-cap-bridge.js
|
|
405309
405760
|
var require_core_cap_bridge = __commonJS({
|
|
405310
405761
|
"../../server/backend/dist/api/trpc/core-cap-bridge.js"(exports) {
|
|
405311
405762
|
"use strict";
|
|
405312
405763
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
405313
405764
|
exports.isCoreServiceCapName = isCoreServiceCapName;
|
|
405765
|
+
exports.describeMeshOrigin = describeMeshOrigin;
|
|
405314
405766
|
exports.buildCoreCapService = buildCoreCapService;
|
|
405315
405767
|
var system_1 = require_dist3();
|
|
405316
|
-
var
|
|
405768
|
+
var http_request_census_singleton_js_1 = require_http_request_census_singleton();
|
|
405317
405769
|
var trpc_context_js_1 = require_trpc_context();
|
|
405770
|
+
var trpc_middleware_js_1 = require_trpc_middleware();
|
|
405318
405771
|
var CORE_NAMESPACES = /* @__PURE__ */ new Set([
|
|
405319
405772
|
// Service-backed cap routers (no addon provider).
|
|
405320
405773
|
"system",
|
|
@@ -405359,6 +405812,24 @@ var require_core_cap_bridge = __commonJS({
|
|
|
405359
405812
|
}
|
|
405360
405813
|
}
|
|
405361
405814
|
}
|
|
405815
|
+
function countMeshCall(census, path, origin) {
|
|
405816
|
+
if (!census.armed)
|
|
405817
|
+
return;
|
|
405818
|
+
census.observe({
|
|
405819
|
+
plane: "mesh",
|
|
405820
|
+
kind: "call",
|
|
405821
|
+
procedures: [path],
|
|
405822
|
+
// A mesh call has no socket and no user-agent. Both render as the named
|
|
405823
|
+
// unknown rather than as a blank, which would read as a logging defect.
|
|
405824
|
+
userAgent: null,
|
|
405825
|
+
ip: null,
|
|
405826
|
+
principal: describeMeshOrigin(origin)
|
|
405827
|
+
});
|
|
405828
|
+
}
|
|
405829
|
+
function describeMeshOrigin(origin) {
|
|
405830
|
+
const node = origin.nodeId ?? "unknown";
|
|
405831
|
+
return origin.caller === null ? `mesh:${node}` : `mesh:${node} via ${origin.caller}`;
|
|
405832
|
+
}
|
|
405362
405833
|
function resolveInvoker(caller, path) {
|
|
405363
405834
|
let node = caller;
|
|
405364
405835
|
for (const segment of path.split(".")) {
|
|
@@ -405368,7 +405839,7 @@ var require_core_cap_bridge = __commonJS({
|
|
|
405368
405839
|
}
|
|
405369
405840
|
return typeof node === "function" ? node : null;
|
|
405370
405841
|
}
|
|
405371
|
-
function buildCoreCapService(appRouter) {
|
|
405842
|
+
function buildCoreCapService(appRouter, census = (0, http_request_census_singleton_js_1.getHttpRequestCensus)()) {
|
|
405372
405843
|
const meshCaller = (0, trpc_middleware_js_1.createCallerFactory)(appRouter)((0, trpc_context_js_1.createMeshTrpcContext)());
|
|
405373
405844
|
const discovered = [];
|
|
405374
405845
|
collectProcedures(appRouter._def.procedures, "", discovered);
|
|
@@ -405386,7 +405857,13 @@ var require_core_cap_bridge = __commonJS({
|
|
|
405386
405857
|
if (invoke === null)
|
|
405387
405858
|
continue;
|
|
405388
405859
|
const method = path.slice(dot + 1);
|
|
405389
|
-
actions.push({
|
|
405860
|
+
actions.push({
|
|
405861
|
+
actionName: `${toKebab(namespace)}.${method}`,
|
|
405862
|
+
invoke: (input, origin) => {
|
|
405863
|
+
countMeshCall(census, path, origin);
|
|
405864
|
+
return invoke(input);
|
|
405865
|
+
}
|
|
405866
|
+
});
|
|
405390
405867
|
}
|
|
405391
405868
|
return (0, system_1.createCoreCapService)({ actions });
|
|
405392
405869
|
}
|
|
@@ -407757,6 +408234,202 @@ var require_trpc_router = __commonJS({
|
|
|
407757
408234
|
}
|
|
407758
408235
|
});
|
|
407759
408236
|
|
|
408237
|
+
// ../../server/backend/dist/api/trpc/ws-request-census.js
|
|
408238
|
+
var require_ws_request_census = __commonJS({
|
|
408239
|
+
"../../server/backend/dist/api/trpc/ws-request-census.js"(exports) {
|
|
408240
|
+
"use strict";
|
|
408241
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
408242
|
+
exports.WsCensusSession = exports.MAX_PENDING_WS_OPERATIONS = exports.WS_PATHLESS_PROCEDURE = void 0;
|
|
408243
|
+
exports.parseTrpcWsFrame = parseTrpcWsFrame;
|
|
408244
|
+
exports.attachWsCensusSession = attachWsCensusSession;
|
|
408245
|
+
exports.identifyWsCensusSession = identifyWsCensusSession;
|
|
408246
|
+
var client_ip_js_1 = require_client_ip();
|
|
408247
|
+
var http_request_census_js_1 = require_http_request_census();
|
|
408248
|
+
var KEEPALIVE_FRAMES = /* @__PURE__ */ new Set(["PING", "PONG"]);
|
|
408249
|
+
exports.WS_PATHLESS_PROCEDURE = "(ws-no-path)";
|
|
408250
|
+
exports.MAX_PENDING_WS_OPERATIONS = 128;
|
|
408251
|
+
var NO_OPERATIONS = { calls: [], subscriptions: [], stops: 0 };
|
|
408252
|
+
function parseTrpcWsFrame(raw) {
|
|
408253
|
+
const text = raw.trim();
|
|
408254
|
+
if (text.length === 0)
|
|
408255
|
+
return NO_OPERATIONS;
|
|
408256
|
+
if (KEEPALIVE_FRAMES.has(text))
|
|
408257
|
+
return NO_OPERATIONS;
|
|
408258
|
+
const parsed = parseJsonSafely(text);
|
|
408259
|
+
if (parsed === null)
|
|
408260
|
+
return NO_OPERATIONS;
|
|
408261
|
+
const messages = Array.isArray(parsed) ? parsed : [parsed];
|
|
408262
|
+
const calls = [];
|
|
408263
|
+
const subscriptions = [];
|
|
408264
|
+
let stops = 0;
|
|
408265
|
+
let overflowed = false;
|
|
408266
|
+
for (const message of messages) {
|
|
408267
|
+
if (typeof message !== "object" || message === null)
|
|
408268
|
+
continue;
|
|
408269
|
+
const method = Reflect.get(message, "method");
|
|
408270
|
+
if (method === "subscription.stop") {
|
|
408271
|
+
stops += 1;
|
|
408272
|
+
continue;
|
|
408273
|
+
}
|
|
408274
|
+
if (method !== "query" && method !== "mutation" && method !== "subscription")
|
|
408275
|
+
continue;
|
|
408276
|
+
if (calls.length + subscriptions.length >= http_request_census_js_1.MAX_BATCH_PROCEDURES) {
|
|
408277
|
+
overflowed = true;
|
|
408278
|
+
continue;
|
|
408279
|
+
}
|
|
408280
|
+
const path = readPath(Reflect.get(message, "params"));
|
|
408281
|
+
if (method === "subscription")
|
|
408282
|
+
subscriptions.push(path);
|
|
408283
|
+
else
|
|
408284
|
+
calls.push(path);
|
|
408285
|
+
}
|
|
408286
|
+
if (overflowed)
|
|
408287
|
+
calls.push(http_request_census_js_1.BATCH_OVERFLOW_PROCEDURE);
|
|
408288
|
+
return { calls, subscriptions, stops };
|
|
408289
|
+
}
|
|
408290
|
+
function parseJsonSafely(text) {
|
|
408291
|
+
try {
|
|
408292
|
+
return JSON.parse(text);
|
|
408293
|
+
} catch {
|
|
408294
|
+
return null;
|
|
408295
|
+
}
|
|
408296
|
+
}
|
|
408297
|
+
function readPath(params) {
|
|
408298
|
+
if (typeof params !== "object" || params === null)
|
|
408299
|
+
return exports.WS_PATHLESS_PROCEDURE;
|
|
408300
|
+
const path = Reflect.get(params, "path");
|
|
408301
|
+
return typeof path === "string" && path.length > 0 ? path : exports.WS_PATHLESS_PROCEDURE;
|
|
408302
|
+
}
|
|
408303
|
+
var WsCensusSession = class {
|
|
408304
|
+
census;
|
|
408305
|
+
userAgent;
|
|
408306
|
+
ip;
|
|
408307
|
+
/** `null` until `createWsTrpcContext` resolved the bearer. */
|
|
408308
|
+
principal = null;
|
|
408309
|
+
pending = [];
|
|
408310
|
+
closed = false;
|
|
408311
|
+
constructor(census, req) {
|
|
408312
|
+
this.census = census;
|
|
408313
|
+
this.userAgent = (0, client_ip_js_1.extractUserAgent)(req);
|
|
408314
|
+
this.ip = (0, client_ip_js_1.extractClientIp)(req);
|
|
408315
|
+
}
|
|
408316
|
+
/**
|
|
408317
|
+
* Count one raw client frame.
|
|
408318
|
+
*
|
|
408319
|
+
* The armed check is the FIRST statement. If it ever moves below a field
|
|
408320
|
+
* access, the hostile-frame spec fails instead of the hub paying for a
|
|
408321
|
+
* diagnostic nobody switched on.
|
|
408322
|
+
*/
|
|
408323
|
+
observeMessage(data) {
|
|
408324
|
+
if (!this.census.armed)
|
|
408325
|
+
return;
|
|
408326
|
+
this.census.observeWsMessage();
|
|
408327
|
+
const text = frameText(data);
|
|
408328
|
+
if (text === null)
|
|
408329
|
+
return;
|
|
408330
|
+
const operations = parseTrpcWsFrame(text);
|
|
408331
|
+
if (operations.stops > 0)
|
|
408332
|
+
this.census.observeSubscriptionStop(operations.stops);
|
|
408333
|
+
if (operations.calls.length === 0 && operations.subscriptions.length === 0)
|
|
408334
|
+
return;
|
|
408335
|
+
if (this.principal !== null) {
|
|
408336
|
+
this.flushFrame(operations, this.principal);
|
|
408337
|
+
return;
|
|
408338
|
+
}
|
|
408339
|
+
if (this.pending.length >= exports.MAX_PENDING_WS_OPERATIONS) {
|
|
408340
|
+
this.flushFrame(operations, http_request_census_js_1.UNKNOWN);
|
|
408341
|
+
return;
|
|
408342
|
+
}
|
|
408343
|
+
this.pending.push(operations);
|
|
408344
|
+
}
|
|
408345
|
+
/** Name the connection, once, and release everything held for it. */
|
|
408346
|
+
identify(principal) {
|
|
408347
|
+
if (this.principal !== null || this.closed)
|
|
408348
|
+
return;
|
|
408349
|
+
this.principal = principal;
|
|
408350
|
+
this.drain(principal);
|
|
408351
|
+
}
|
|
408352
|
+
/** The socket went away. Anything still unnamed is released as {@link UNKNOWN}. */
|
|
408353
|
+
close() {
|
|
408354
|
+
if (this.closed)
|
|
408355
|
+
return;
|
|
408356
|
+
this.closed = true;
|
|
408357
|
+
this.drain(this.principal ?? http_request_census_js_1.UNKNOWN);
|
|
408358
|
+
}
|
|
408359
|
+
drain(principal) {
|
|
408360
|
+
if (this.pending.length === 0)
|
|
408361
|
+
return;
|
|
408362
|
+
const held = this.pending;
|
|
408363
|
+
this.pending = [];
|
|
408364
|
+
for (const frame of held)
|
|
408365
|
+
this.flushFrame(frame, principal);
|
|
408366
|
+
}
|
|
408367
|
+
flushFrame(operations, principal) {
|
|
408368
|
+
if (operations.calls.length > 0) {
|
|
408369
|
+
this.census.observe({
|
|
408370
|
+
plane: "ws",
|
|
408371
|
+
kind: "call",
|
|
408372
|
+
procedures: operations.calls,
|
|
408373
|
+
userAgent: this.userAgent,
|
|
408374
|
+
ip: this.ip,
|
|
408375
|
+
principal
|
|
408376
|
+
});
|
|
408377
|
+
}
|
|
408378
|
+
if (operations.subscriptions.length > 0) {
|
|
408379
|
+
this.census.observe({
|
|
408380
|
+
plane: "ws",
|
|
408381
|
+
kind: "subscription",
|
|
408382
|
+
procedures: operations.subscriptions,
|
|
408383
|
+
userAgent: this.userAgent,
|
|
408384
|
+
ip: this.ip,
|
|
408385
|
+
principal
|
|
408386
|
+
});
|
|
408387
|
+
}
|
|
408388
|
+
}
|
|
408389
|
+
};
|
|
408390
|
+
exports.WsCensusSession = WsCensusSession;
|
|
408391
|
+
var sessions = /* @__PURE__ */ new WeakMap();
|
|
408392
|
+
function attachWsCensusSession(census, client, req, logger) {
|
|
408393
|
+
census.observeWsConnection();
|
|
408394
|
+
const session = new WsCensusSession(census, req);
|
|
408395
|
+
sessions.set(client, session);
|
|
408396
|
+
let broken = false;
|
|
408397
|
+
client.on("message", (data) => {
|
|
408398
|
+
if (broken)
|
|
408399
|
+
return;
|
|
408400
|
+
try {
|
|
408401
|
+
session.observeMessage(data);
|
|
408402
|
+
} catch (err) {
|
|
408403
|
+
broken = true;
|
|
408404
|
+
logger?.warn("transport census: ws frames no longer counted on this socket", {
|
|
408405
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
408406
|
+
});
|
|
408407
|
+
}
|
|
408408
|
+
});
|
|
408409
|
+
client.once("close", () => {
|
|
408410
|
+
session.close();
|
|
408411
|
+
});
|
|
408412
|
+
return session;
|
|
408413
|
+
}
|
|
408414
|
+
function identifyWsCensusSession(client, principal) {
|
|
408415
|
+
sessions.get(client)?.identify(principal);
|
|
408416
|
+
}
|
|
408417
|
+
function frameText(data) {
|
|
408418
|
+
if (typeof data === "string")
|
|
408419
|
+
return data;
|
|
408420
|
+
if (Buffer.isBuffer(data))
|
|
408421
|
+
return data.toString("utf8");
|
|
408422
|
+
if (data instanceof ArrayBuffer)
|
|
408423
|
+
return Buffer.from(data).toString("utf8");
|
|
408424
|
+
if (Array.isArray(data)) {
|
|
408425
|
+
const chunks = data.filter((chunk) => Buffer.isBuffer(chunk));
|
|
408426
|
+
return chunks.length === 0 ? null : Buffer.concat(chunks).toString("utf8");
|
|
408427
|
+
}
|
|
408428
|
+
return null;
|
|
408429
|
+
}
|
|
408430
|
+
}
|
|
408431
|
+
});
|
|
408432
|
+
|
|
407760
408433
|
// ../../server/backend/dist/auth/addon-route-jwt-gate.js
|
|
407761
408434
|
var require_addon_route_jwt_gate = __commonJS({
|
|
407762
408435
|
"../../server/backend/dist/auth/addon-route-jwt-gate.js"(exports) {
|
|
@@ -415525,6 +416198,7 @@ var require_main4 = __commonJS({
|
|
|
415525
416198
|
var trpc_context_1 = require_trpc_context();
|
|
415526
416199
|
var trpc_router_1 = require_trpc_router();
|
|
415527
416200
|
var trpc_error_principal_1 = require_trpc_error_principal();
|
|
416201
|
+
var ws_request_census_1 = require_ws_request_census();
|
|
415528
416202
|
var addon_route_jwt_gate_js_1 = require_addon_route_jwt_gate();
|
|
415529
416203
|
var session_cookie_js_1 = require_session_cookie();
|
|
415530
416204
|
var boot_config_1 = require_boot_config();
|
|
@@ -416191,12 +416865,16 @@ var require_main4 = __commonJS({
|
|
|
416191
416865
|
concurrencyLimit: 10
|
|
416192
416866
|
}
|
|
416193
416867
|
});
|
|
416868
|
+
wss.on("connection", (client, req) => {
|
|
416869
|
+
(0, ws_request_census_1.attachWsCensusSession)(httpRequestCensus, client, req, app.get(logging_service_1.LoggingService).createLogger("tRPC:ws"));
|
|
416870
|
+
});
|
|
416194
416871
|
(0, ws_1.applyWSSHandler)({
|
|
416195
416872
|
wss,
|
|
416196
416873
|
router: appRouter,
|
|
416197
|
-
createContext: (opts) => {
|
|
416198
|
-
|
|
416199
|
-
|
|
416874
|
+
createContext: async (opts) => {
|
|
416875
|
+
const wsCtx = await (0, trpc_context_1.createWsTrpcContext)(opts, authService, addonRegistry, shareTokenService, app.get(logging_service_1.LoggingService).createLogger("tRPC:ws"));
|
|
416876
|
+
(0, ws_request_census_1.identifyWsCensusSession)(opts.res, (0, trpc_error_principal_1.describeTrpcPrincipal)(wsCtx.user));
|
|
416877
|
+
return wsCtx;
|
|
416200
416878
|
},
|
|
416201
416879
|
onError: ({ path: trpcPath, error, ctx }) => {
|
|
416202
416880
|
const trpcLogger = app.get(logging_service_1.LoggingService).createLogger("tRPC:ws");
|