camstack 1.2.27 → 1.2.29
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.
|
@@ -23631,9 +23631,9 @@ var require_zod = __commonJS({
|
|
|
23631
23631
|
}
|
|
23632
23632
|
});
|
|
23633
23633
|
|
|
23634
|
-
// ../system/dist/dist-
|
|
23635
|
-
var
|
|
23636
|
-
"../system/dist/dist-
|
|
23634
|
+
// ../system/dist/dist-DR1VmGz6.js
|
|
23635
|
+
var require_dist_DR1VmGz6 = __commonJS({
|
|
23636
|
+
"../system/dist/dist-DR1VmGz6.js"(exports) {
|
|
23637
23637
|
"use strict";
|
|
23638
23638
|
var zod = require_zod();
|
|
23639
23639
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
@@ -23650,6 +23650,7 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
23650
23650
|
EventCategory2["AddonInstalled"] = "addon.installed";
|
|
23651
23651
|
EventCategory2["AddonUninstalled"] = "addon.uninstalled";
|
|
23652
23652
|
EventCategory2["AddonCrashed"] = "addon.crashed";
|
|
23653
|
+
EventCategory2["AddonRunnerFailed"] = "addon.runner-failed";
|
|
23653
23654
|
EventCategory2["AddonError"] = "addon.error";
|
|
23654
23655
|
EventCategory2["AddonPageReady"] = "addon.page-ready";
|
|
23655
23656
|
EventCategory2["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -25931,6 +25932,10 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
25931
25932
|
preBufferSec: zod.z.number().min(0).optional(),
|
|
25932
25933
|
postBufferSec: zod.z.number().min(0).optional()
|
|
25933
25934
|
});
|
|
25935
|
+
({
|
|
25936
|
+
preBufferSec: 10,
|
|
25937
|
+
postBufferSec: 30
|
|
25938
|
+
}).postBufferSec * 1e3;
|
|
25934
25939
|
var RecordingRetentionSchema = zod.z.object({
|
|
25935
25940
|
maxAgeDays: zod.z.number().min(0).optional(),
|
|
25936
25941
|
maxSizeGb: zod.z.number().min(0).optional()
|
|
@@ -25947,6 +25952,12 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
25947
25952
|
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
25948
25953
|
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
25949
25954
|
mode: RecordingStorageModeSchema.optional(),
|
|
25955
|
+
/**
|
|
25956
|
+
* Which assigned broker slots to record. Absent / empty = {@link
|
|
25957
|
+
* DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
|
|
25958
|
+
* camera's currently assigned slots — never `mid` unless the operator
|
|
25959
|
+
* picks it, and never a slot the broker has not assigned.
|
|
25960
|
+
*/
|
|
25950
25961
|
profiles: zod.z.array(CamProfileSchema).optional(),
|
|
25951
25962
|
segmentSeconds: zod.z.number().int().positive().optional(),
|
|
25952
25963
|
/**
|
|
@@ -26009,7 +26020,11 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
26009
26020
|
profiles: zod.z.array(zod.z.string()).optional(),
|
|
26010
26021
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
26011
26022
|
* never allowed to starve live writers. */
|
|
26012
|
-
throttleMbps: zod.z.number().min(1).max(1e3).optional()
|
|
26023
|
+
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
26024
|
+
/** Move only segments whose startMs is >= this. Absent = the whole source
|
|
26025
|
+
* pile. Used when a full drain is too expensive and the operator only
|
|
26026
|
+
* wants the recent window on the new disk. */
|
|
26027
|
+
sinceMs: zod.z.number().int().optional()
|
|
26013
26028
|
});
|
|
26014
26029
|
var StorageMigrationLeaseInputSchema = zod.z.object({ leaseId: zod.z.string().min(1) });
|
|
26015
26030
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: zod.z.string().min(1) });
|
|
@@ -33092,6 +33107,7 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
33092
33107
|
"node-offline",
|
|
33093
33108
|
"node-inference-unavailable",
|
|
33094
33109
|
"detection-blind",
|
|
33110
|
+
"addon-crash-loop",
|
|
33095
33111
|
"addon-update-available",
|
|
33096
33112
|
"server-update-available",
|
|
33097
33113
|
"alarm-triggered",
|
|
@@ -33099,6 +33115,9 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
33099
33115
|
"alarm-disarmed",
|
|
33100
33116
|
"alarm-arming",
|
|
33101
33117
|
"alarm-arm-refused",
|
|
33118
|
+
"addon-updated",
|
|
33119
|
+
"server-updated",
|
|
33120
|
+
"export-completed",
|
|
33102
33121
|
"camera-online",
|
|
33103
33122
|
"camera-offline",
|
|
33104
33123
|
"camera-disabled",
|
|
@@ -34512,7 +34531,9 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
34512
34531
|
* `'staging'`. */
|
|
34513
34532
|
markForTrain: zod.z.boolean().optional(),
|
|
34514
34533
|
/** Operator marked this track for diagnostic attention. */
|
|
34515
|
-
debug: zod.z.boolean().optional()
|
|
34534
|
+
debug: zod.z.boolean().optional(),
|
|
34535
|
+
/** Operator favourited this track. Pins it against pruning. */
|
|
34536
|
+
favourited: zod.z.boolean().optional()
|
|
34516
34537
|
};
|
|
34517
34538
|
var TrackRetrainFields = { retrainStatus: RetrainStatusSchema.optional() };
|
|
34518
34539
|
var TrackFlagsPatchSchema = zod.z.object(TrackFlagFields);
|
|
@@ -34520,6 +34541,7 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
34520
34541
|
trackId: zod.z.string(),
|
|
34521
34542
|
markForTrain: zod.z.boolean(),
|
|
34522
34543
|
debug: zod.z.boolean(),
|
|
34544
|
+
favourited: zod.z.boolean(),
|
|
34523
34545
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
34524
34546
|
* a track row) because this shape is only ever produced by the write body,
|
|
34525
34547
|
* which always knows it — and a surface that has just written needs to render
|
|
@@ -35042,6 +35064,11 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
35042
35064
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
35043
35065
|
embeddings: zod.z.number().int()
|
|
35044
35066
|
});
|
|
35067
|
+
var DiskReconcileCountsSchema = zod.z.object({
|
|
35068
|
+
mediaDropped: zod.z.number().int(),
|
|
35069
|
+
tracks: zod.z.number().int(),
|
|
35070
|
+
events: zod.z.number().int()
|
|
35071
|
+
});
|
|
35045
35072
|
var EventStoreDeviceFootprintSchema = zod.z.object({
|
|
35046
35073
|
deviceId: zod.z.number(),
|
|
35047
35074
|
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
@@ -35298,6 +35325,17 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
35298
35325
|
auth: "admin"
|
|
35299
35326
|
}),
|
|
35300
35327
|
/**
|
|
35328
|
+
* Disk-wins reconcile for one camera. Drops media index rows whose blobs
|
|
35329
|
+
* are gone, then cascades tracks (including favourited and staging) that
|
|
35330
|
+
* have no remaining files. Enrolled identity/vehicle/scene media is never
|
|
35331
|
+
* probed. Trackless motion/audio events with no remaining file are dropped,
|
|
35332
|
+
* including snapshot-less rows.
|
|
35333
|
+
*/
|
|
35334
|
+
reconcileFromDisk: method(zod.z.object({ deviceId: zod.z.number() }), DiskReconcileCountsSchema, {
|
|
35335
|
+
kind: "mutation",
|
|
35336
|
+
auth: "admin"
|
|
35337
|
+
}),
|
|
35338
|
+
/**
|
|
35301
35339
|
* Delete whole tracks (object events) by id for the given device,
|
|
35302
35340
|
* cascading their media in lockstep. Returns the number of tracks
|
|
35303
35341
|
* actually deleted plus the ids that could not be removed.
|
|
@@ -35316,7 +35354,7 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
35316
35354
|
auth: "admin"
|
|
35317
35355
|
}),
|
|
35318
35356
|
/**
|
|
35319
|
-
* Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
|
|
35357
|
+
* Set the per-track operator flags (`markForTrain`, `debug`, `favourited`) on ONE track.
|
|
35320
35358
|
* The patch is PARTIAL — an omitted key is left untouched — because the
|
|
35321
35359
|
* three surfaces that write it (admin Events grid, viewer track detail,
|
|
35322
35360
|
* viewer cluster detail) each own one toggle and must not clobber the other.
|
|
@@ -37161,6 +37199,24 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
37161
37199
|
/** Wall-clock ms spent on the stage before it was abandoned. */
|
|
37162
37200
|
elapsedMs: zod.z.number()
|
|
37163
37201
|
});
|
|
37202
|
+
var DiskReconcileJobSchema = zod.z.object({
|
|
37203
|
+
state: zod.z.enum([
|
|
37204
|
+
"idle",
|
|
37205
|
+
"running",
|
|
37206
|
+
"done",
|
|
37207
|
+
"error"
|
|
37208
|
+
]),
|
|
37209
|
+
total: zod.z.number().int().nonnegative(),
|
|
37210
|
+
completed: zod.z.number().int().nonnegative(),
|
|
37211
|
+
currentDeviceId: zod.z.number().int().nullable(),
|
|
37212
|
+
failed: zod.z.array(zod.z.number().int()).readonly(),
|
|
37213
|
+
mediaDropped: zod.z.number().int().nonnegative(),
|
|
37214
|
+
tracks: zod.z.number().int().nonnegative(),
|
|
37215
|
+
events: zod.z.number().int().nonnegative(),
|
|
37216
|
+
startedAtMs: zod.z.number().int().nullable(),
|
|
37217
|
+
finishedAtMs: zod.z.number().int().nullable(),
|
|
37218
|
+
error: zod.z.string().nullable()
|
|
37219
|
+
});
|
|
37164
37220
|
var CameraStatusSchema = zod.z.object({
|
|
37165
37221
|
deviceId: zod.z.number(),
|
|
37166
37222
|
assignment: CameraAssignmentStatusSchema,
|
|
@@ -37685,6 +37741,18 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
37685
37741
|
* rail without issuing N parallel browser round-trips.
|
|
37686
37742
|
*/
|
|
37687
37743
|
getCameraStatuses: method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()).optional() }), zod.z.array(CameraStatusSchema).readonly()),
|
|
37744
|
+
/**
|
|
37745
|
+
* Disk-wins fleet reconcile after a recordings wipe. Starts the walk in
|
|
37746
|
+
* the addon process and returns immediately with the job snapshot — the
|
|
37747
|
+
* work outlives the tRPC/UDS 60s timeout. Poll `getReconcileFromDiskStatus`.
|
|
37748
|
+
* Admin-only. Idempotent while a job is already running.
|
|
37749
|
+
*/
|
|
37750
|
+
reconcileFromDisk: method(zod.z.void(), DiskReconcileJobSchema, {
|
|
37751
|
+
kind: "mutation",
|
|
37752
|
+
auth: "admin"
|
|
37753
|
+
}),
|
|
37754
|
+
/** Snapshot of the in-flight or last disk-wins fleet reconcile. */
|
|
37755
|
+
getReconcileFromDiskStatus: method(zod.z.void(), DiskReconcileJobSchema, { auth: "admin" }),
|
|
37688
37756
|
/** List every template the operator has saved. */
|
|
37689
37757
|
listTemplates: method(zod.z.void(), zod.z.array(PipelineTemplateSchema).readonly()),
|
|
37690
37758
|
/** Create a new named preset from a given CameraPipelineConfig. */
|
|
@@ -38126,7 +38194,14 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
38126
38194
|
"sleeping",
|
|
38127
38195
|
"unreachable",
|
|
38128
38196
|
"waking"
|
|
38129
|
-
]).nullable()
|
|
38197
|
+
]).nullable(),
|
|
38198
|
+
/** A battery camera (whatever its current state). An AWAKE battery
|
|
38199
|
+
* camera is deliberately NOT recaptured on the poll cadence — every
|
|
38200
|
+
* capture is a camera hit that would keep it out of sleep — so its
|
|
38201
|
+
* cached frame legitimately ages past the currency ceiling while
|
|
38202
|
+
* nothing is streaming. A surface must keep painting it (a fresh
|
|
38203
|
+
* frame is captured at each wake), not blank to "unavailable". */
|
|
38204
|
+
battery: zod.z.boolean()
|
|
38130
38205
|
})))
|
|
38131
38206
|
},
|
|
38132
38207
|
status: {
|
|
@@ -38816,8 +38891,57 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
38816
38891
|
startMs: zod.z.number(),
|
|
38817
38892
|
endMs: zod.z.number()
|
|
38818
38893
|
}),
|
|
38819
|
-
/**
|
|
38820
|
-
thumbnail
|
|
38894
|
+
/**
|
|
38895
|
+
* Lazy thumbnail URL, never inlined.
|
|
38896
|
+
*
|
|
38897
|
+
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
38898
|
+
* continuous event+fragment visit) MUST use the snapshot of the **main
|
|
38899
|
+
* event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
|
|
38900
|
+
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
38901
|
+
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
38902
|
+
* mint their own stills.
|
|
38903
|
+
*
|
|
38904
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
38905
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
38906
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
38907
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
38908
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
38909
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
38910
|
+
*/
|
|
38911
|
+
thumbnail: zod.z.string().optional(),
|
|
38912
|
+
/**
|
|
38913
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
38914
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
38915
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
38916
|
+
*
|
|
38917
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
38918
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
38919
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
38920
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
38921
|
+
* construction, so a naive midpoint lands in dead air.
|
|
38922
|
+
*/
|
|
38923
|
+
stillAtMs: zod.z.number().optional(),
|
|
38924
|
+
/**
|
|
38925
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
38926
|
+
* first within kind (object → motion → audio), capped at
|
|
38927
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
38928
|
+
*
|
|
38929
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
38930
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
38931
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
38932
|
+
*/
|
|
38933
|
+
eventIds: zod.z.array(zod.z.string()).optional(),
|
|
38934
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
38935
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
38936
|
+
* list is never mistaken for a quiet visit. */
|
|
38937
|
+
eventCount: zod.z.number().int().nonnegative().optional(),
|
|
38938
|
+
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
38939
|
+
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
38940
|
+
* bar keeps showing them via `recording.getAvailability`. */
|
|
38941
|
+
holes: zod.z.array(zod.z.object({
|
|
38942
|
+
startMs: zod.z.number(),
|
|
38943
|
+
endMs: zod.z.number()
|
|
38944
|
+
})).optional()
|
|
38821
38945
|
});
|
|
38822
38946
|
var ClipPlaybackSchema = zod.z.object({
|
|
38823
38947
|
/** HLS master URL through the hub data-plane (Range + token in path). */
|
|
@@ -39365,7 +39489,14 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
39365
39489
|
});
|
|
39366
39490
|
var AutoUpdateSettingsSchema = zod.z.object({
|
|
39367
39491
|
channel: ChannelSchema,
|
|
39368
|
-
intervalSeconds: zod.z.number()
|
|
39492
|
+
intervalSeconds: zod.z.number(),
|
|
39493
|
+
/**
|
|
39494
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
39495
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
39496
|
+
* about a publish and installing it are different decisions. Clamped
|
|
39497
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
39498
|
+
*/
|
|
39499
|
+
updateCheckIntervalSeconds: zod.z.number()
|
|
39369
39500
|
});
|
|
39370
39501
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
39371
39502
|
var RestartAddonResultSchema = zod.z.unknown();
|
|
@@ -39616,7 +39747,9 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
39616
39747
|
getAutoUpdateSettings: method(zod.z.void(), AutoUpdateSettingsSchema, { auth: "admin" }),
|
|
39617
39748
|
setAutoUpdateSettings: method(zod.z.object({
|
|
39618
39749
|
channel: ChannelSchema,
|
|
39619
|
-
intervalSeconds: zod.z.number().min(300).max(86400).optional()
|
|
39750
|
+
intervalSeconds: zod.z.number().min(300).max(86400).optional(),
|
|
39751
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
39752
|
+
updateCheckIntervalSeconds: zod.z.number().min(900).max(604800).optional()
|
|
39620
39753
|
}), zod.z.unknown(), {
|
|
39621
39754
|
kind: "mutation",
|
|
39622
39755
|
auth: "admin"
|
|
@@ -44898,7 +45031,9 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
44898
45031
|
includeAudio: zod.z.boolean(),
|
|
44899
45032
|
maxLifeMs: zod.z.number().int().positive(),
|
|
44900
45033
|
deleteAfterDownload: zod.z.boolean(),
|
|
44901
|
-
title: zod.z.string().max(200).optional()
|
|
45034
|
+
title: zod.z.string().max(200).optional(),
|
|
45035
|
+
/** Notification-output target ids to ping when this export becomes ready. */
|
|
45036
|
+
notifyTargetIds: zod.z.array(zod.z.string().min(1)).max(20).optional()
|
|
44902
45037
|
}).superRefine((v, ctx) => {
|
|
44903
45038
|
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
44904
45039
|
code: zod.z.ZodIssueCode.custom,
|
|
@@ -44952,14 +45087,23 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
44952
45087
|
scope: "system",
|
|
44953
45088
|
mode: "singleton",
|
|
44954
45089
|
methods: {
|
|
44955
|
-
/** Queue a render of `[fromMs,toMs)` for `deviceId`/`
|
|
44956
|
-
*
|
|
45090
|
+
/** Queue a render of `[fromMs,toMs)` for `deviceId`/`profiles` (legacy
|
|
45091
|
+
* singular `profile` still accepted). Fails fast when no footage covers
|
|
45092
|
+
* the range. One job per profile; returns the first queued record. */
|
|
44957
45093
|
createExport: method(zod.z.object({
|
|
44958
45094
|
deviceId: zod.z.number(),
|
|
44959
|
-
|
|
45095
|
+
/** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
|
|
45096
|
+
profile: zod.z.string().optional(),
|
|
45097
|
+
profiles: zod.z.array(zod.z.string()).min(1).optional(),
|
|
44960
45098
|
fromMs: zod.z.number(),
|
|
44961
45099
|
toMs: zod.z.number(),
|
|
44962
45100
|
options: ExportOptionsSchema
|
|
45101
|
+
}).superRefine((v, ctx) => {
|
|
45102
|
+
if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
|
|
45103
|
+
code: zod.z.ZodIssueCode.custom,
|
|
45104
|
+
message: "pass profiles[] (min 1) or legacy profile",
|
|
45105
|
+
path: ["profiles"]
|
|
45106
|
+
});
|
|
44963
45107
|
}), ExportRecordSchema, {
|
|
44964
45108
|
kind: "mutation",
|
|
44965
45109
|
auth: "protected"
|
|
@@ -50596,6 +50740,12 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
50596
50740
|
addonId: null,
|
|
50597
50741
|
access: "create"
|
|
50598
50742
|
},
|
|
50743
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
50744
|
+
capName: "pipeline-analytics",
|
|
50745
|
+
capScope: "device",
|
|
50746
|
+
addonId: null,
|
|
50747
|
+
access: "create"
|
|
50748
|
+
},
|
|
50599
50749
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
50600
50750
|
capName: "pipeline-analytics",
|
|
50601
50751
|
capScope: "device",
|
|
@@ -50998,6 +51148,12 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
50998
51148
|
addonId: null,
|
|
50999
51149
|
access: "view"
|
|
51000
51150
|
},
|
|
51151
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
51152
|
+
capName: "pipeline-orchestrator",
|
|
51153
|
+
capScope: "system",
|
|
51154
|
+
addonId: null,
|
|
51155
|
+
access: "view"
|
|
51156
|
+
},
|
|
51001
51157
|
"pipelineOrchestrator.listAgentSettings": {
|
|
51002
51158
|
capName: "pipeline-orchestrator",
|
|
51003
51159
|
capScope: "system",
|
|
@@ -51022,6 +51178,12 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
51022
51178
|
addonId: null,
|
|
51023
51179
|
access: "create"
|
|
51024
51180
|
},
|
|
51181
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
51182
|
+
capName: "pipeline-orchestrator",
|
|
51183
|
+
capScope: "system",
|
|
51184
|
+
addonId: null,
|
|
51185
|
+
access: "create"
|
|
51186
|
+
},
|
|
51025
51187
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
51026
51188
|
capName: "pipeline-orchestrator",
|
|
51027
51189
|
capScope: "system",
|
|
@@ -54013,6 +54175,11 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
54013
54175
|
form: "single",
|
|
54014
54176
|
optional: true
|
|
54015
54177
|
}],
|
|
54178
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
54179
|
+
name: "deviceId",
|
|
54180
|
+
form: "single",
|
|
54181
|
+
optional: false
|
|
54182
|
+
}],
|
|
54016
54183
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
54017
54184
|
name: "deviceId",
|
|
54018
54185
|
form: "single",
|
|
@@ -55200,6 +55367,8 @@ var require_dist_Dz8RQmdk = __commonJS({
|
|
|
55200
55367
|
function isSameAddonId(a, b) {
|
|
55201
55368
|
return bareAddonId(a) === bareAddonId(b);
|
|
55202
55369
|
}
|
|
55370
|
+
var MB = 1024 * 1024;
|
|
55371
|
+
1024 * MB, 3072 * MB;
|
|
55203
55372
|
function decodeVectorBase64(encoded) {
|
|
55204
55373
|
const buffer = Buffer.from(encoded, "base64");
|
|
55205
55374
|
if (buffer.byteLength % 4 !== 0) throw new Error(`decodeVectorBase64: ${buffer.byteLength} bytes is not a whole number of Float32 values`);
|
|
@@ -55906,7 +56075,7 @@ var require_alerts_addon = __commonJS({
|
|
|
55906
56075
|
[Symbol.toStringTag]: { value: "Module" }
|
|
55907
56076
|
});
|
|
55908
56077
|
require_chunk_Cek0wNdY();
|
|
55909
|
-
var require_dist10 =
|
|
56078
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
55910
56079
|
function selectExpired(alerts, cutoffMs) {
|
|
55911
56080
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
55912
56081
|
}
|
|
@@ -56719,7 +56888,7 @@ var require_console_logging = __commonJS({
|
|
|
56719
56888
|
[Symbol.toStringTag]: { value: "Module" }
|
|
56720
56889
|
});
|
|
56721
56890
|
require_chunk_Cek0wNdY();
|
|
56722
|
-
var require_dist10 =
|
|
56891
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
56723
56892
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
56724
56893
|
var LEVEL_RANK = {
|
|
56725
56894
|
debug: 0,
|
|
@@ -56813,7 +56982,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
56813
56982
|
"use strict";
|
|
56814
56983
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
56815
56984
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
56816
|
-
var require_dist10 =
|
|
56985
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
56817
56986
|
var node_crypto = __require("crypto");
|
|
56818
56987
|
var node_fs_promises = __require("fs/promises");
|
|
56819
56988
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -59533,7 +59702,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
59533
59702
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59534
59703
|
});
|
|
59535
59704
|
require_chunk_Cek0wNdY();
|
|
59536
|
-
var require_dist10 =
|
|
59705
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
59537
59706
|
var node_crypto = __require("crypto");
|
|
59538
59707
|
var _camstack_types_node = require_node();
|
|
59539
59708
|
var JOB_HISTORY = 20;
|
|
@@ -63521,7 +63690,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
63521
63690
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63522
63691
|
});
|
|
63523
63692
|
require_chunk_Cek0wNdY();
|
|
63524
|
-
var require_dist10 =
|
|
63693
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
63525
63694
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
63526
63695
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
63527
63696
|
var HubForwarderDestination = class {
|
|
@@ -63658,7 +63827,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
63658
63827
|
"use strict";
|
|
63659
63828
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
63660
63829
|
require_chunk_Cek0wNdY();
|
|
63661
|
-
var require_dist10 =
|
|
63830
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
63662
63831
|
var NO_DEVICES = "liveness:no-devices";
|
|
63663
63832
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
63664
63833
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -63848,7 +64017,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
63848
64017
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63849
64018
|
});
|
|
63850
64019
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
63851
|
-
var require_dist10 =
|
|
64020
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
63852
64021
|
var node_crypto = __require("crypto");
|
|
63853
64022
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
63854
64023
|
var crypto$1 = __require("crypto");
|
|
@@ -71532,7 +71701,7 @@ var require_loki_logging = __commonJS({
|
|
|
71532
71701
|
[Symbol.toStringTag]: { value: "Module" }
|
|
71533
71702
|
});
|
|
71534
71703
|
require_chunk_Cek0wNdY();
|
|
71535
|
-
var require_dist10 =
|
|
71704
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
71536
71705
|
function sanitizeLabelName(raw) {
|
|
71537
71706
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
71538
71707
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -72097,7 +72266,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
72097
72266
|
[Symbol.toStringTag]: { value: "Module" }
|
|
72098
72267
|
});
|
|
72099
72268
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
72100
|
-
var require_dist10 =
|
|
72269
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
72101
72270
|
var node_child_process = __require("child_process");
|
|
72102
72271
|
var node_util = __require("util");
|
|
72103
72272
|
var node_os = __require("os");
|
|
@@ -73039,7 +73208,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
73039
73208
|
[Symbol.toStringTag]: { value: "Module" }
|
|
73040
73209
|
});
|
|
73041
73210
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
73042
|
-
var require_dist10 =
|
|
73211
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
73043
73212
|
var node_crypto = __require("crypto");
|
|
73044
73213
|
var node_fs_promises = __require("fs/promises");
|
|
73045
73214
|
var node_path = __require("path");
|
|
@@ -74155,7 +74324,7 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
74155
74324
|
[Symbol.toStringTag]: { value: "Module" }
|
|
74156
74325
|
});
|
|
74157
74326
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
74158
|
-
var require_dist10 =
|
|
74327
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
74159
74328
|
var node_crypto = __require("crypto");
|
|
74160
74329
|
var node_fs = __require("fs");
|
|
74161
74330
|
var node_module = __require("module");
|
|
@@ -75723,7 +75892,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
75723
75892
|
[Symbol.toStringTag]: { value: "Module" }
|
|
75724
75893
|
});
|
|
75725
75894
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
75726
|
-
var require_dist10 =
|
|
75895
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
75727
75896
|
var node_crypto = __require("crypto");
|
|
75728
75897
|
var node_fs_promises = __require("fs/promises");
|
|
75729
75898
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -77602,7 +77771,7 @@ var require_system_config_addon = __commonJS({
|
|
|
77602
77771
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77603
77772
|
});
|
|
77604
77773
|
require_chunk_Cek0wNdY();
|
|
77605
|
-
var require_dist10 =
|
|
77774
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
77606
77775
|
var SECTION_TITLES = {
|
|
77607
77776
|
server: "Server",
|
|
77608
77777
|
auth: "Authentication"
|
|
@@ -95663,7 +95832,7 @@ var require_winston_logging = __commonJS({
|
|
|
95663
95832
|
[Symbol.toStringTag]: { value: "Module" }
|
|
95664
95833
|
});
|
|
95665
95834
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
95666
|
-
var require_dist10 =
|
|
95835
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
95667
95836
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
95668
95837
|
var node_path = __require("path");
|
|
95669
95838
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -96651,9 +96820,9 @@ var require_file_data_plane_DUHPHa_Y = __commonJS({
|
|
|
96651
96820
|
}
|
|
96652
96821
|
});
|
|
96653
96822
|
|
|
96654
|
-
// ../types/dist/event-category-
|
|
96655
|
-
var
|
|
96656
|
-
"../types/dist/event-category-
|
|
96823
|
+
// ../types/dist/event-category-CRPORAAz.js
|
|
96824
|
+
var require_event_category_CRPORAAz = __commonJS({
|
|
96825
|
+
"../types/dist/event-category-CRPORAAz.js"(exports) {
|
|
96657
96826
|
"use strict";
|
|
96658
96827
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
96659
96828
|
EventCategory2["SystemBoot"] = "system.boot";
|
|
@@ -96669,6 +96838,7 @@ var require_event_category_D3gG7oil = __commonJS({
|
|
|
96669
96838
|
EventCategory2["AddonInstalled"] = "addon.installed";
|
|
96670
96839
|
EventCategory2["AddonUninstalled"] = "addon.uninstalled";
|
|
96671
96840
|
EventCategory2["AddonCrashed"] = "addon.crashed";
|
|
96841
|
+
EventCategory2["AddonRunnerFailed"] = "addon.runner-failed";
|
|
96672
96842
|
EventCategory2["AddonError"] = "addon.error";
|
|
96673
96843
|
EventCategory2["AddonPageReady"] = "addon.page-ready";
|
|
96674
96844
|
EventCategory2["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -96816,11 +96986,11 @@ var require_event_category_D3gG7oil = __commonJS({
|
|
|
96816
96986
|
}
|
|
96817
96987
|
});
|
|
96818
96988
|
|
|
96819
|
-
// ../types/dist/sleep-
|
|
96820
|
-
var
|
|
96821
|
-
"../types/dist/sleep-
|
|
96989
|
+
// ../types/dist/sleep-CMRLJj2e.js
|
|
96990
|
+
var require_sleep_CMRLJj2e = __commonJS({
|
|
96991
|
+
"../types/dist/sleep-CMRLJj2e.js"(exports) {
|
|
96822
96992
|
"use strict";
|
|
96823
|
-
var require_event_category =
|
|
96993
|
+
var require_event_category = require_event_category_CRPORAAz();
|
|
96824
96994
|
var zod = require_zod();
|
|
96825
96995
|
var WELL_KNOWN_TABS = [
|
|
96826
96996
|
{
|
|
@@ -99291,6 +99461,7 @@ var require_sleep_EYtyUX0L = __commonJS({
|
|
|
99291
99461
|
pruneEventsBefore: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneEventsBefore", "mutation", input),
|
|
99292
99462
|
pruneTracksBefore: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "pruneTracksBefore", "mutation", input),
|
|
99293
99463
|
wipeAllAnalytics: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "wipeAllAnalytics", "mutation", input),
|
|
99464
|
+
reconcileFromDisk: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "reconcileFromDisk", "mutation", input),
|
|
99294
99465
|
deleteTracks: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "deleteTracks", "mutation", input),
|
|
99295
99466
|
setTrackFlags: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "setTrackFlags", "mutation", input),
|
|
99296
99467
|
getEventStoreFootprint: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "getEventStoreFootprint", "query", input),
|
|
@@ -99593,10 +99764,7 @@ var require_sleep_EYtyUX0L = __commonJS({
|
|
|
99593
99764
|
getDeviceLiveContribution: (input) => dispatchSystem("recording", "getDeviceLiveContribution", "query", input),
|
|
99594
99765
|
applyDeviceSettingsPatch: (input) => dispatchSystem("recording", "applyDeviceSettingsPatch", "mutation", input)
|
|
99595
99766
|
},
|
|
99596
|
-
recordingExport: {
|
|
99597
|
-
createExport: (input) => dispatchSystem("recordingExport", "createExport", "mutation", input),
|
|
99598
|
-
listExports: (input) => dispatchSystem("recordingExport", "listExports", "query", input)
|
|
99599
|
-
},
|
|
99767
|
+
recordingExport: { listExports: (input) => dispatchSystem("recordingExport", "listExports", "query", input) },
|
|
99600
99768
|
streamBroker: {
|
|
99601
99769
|
publishCameraStream: (input) => dispatchSystem("streamBroker", "publishCameraStream", "mutation", input),
|
|
99602
99770
|
retractCameraStream: (input) => dispatchSystem("streamBroker", "retractCameraStream", "mutation", input),
|
|
@@ -100259,8 +100427,8 @@ var require_addon = __commonJS({
|
|
|
100259
100427
|
"../types/dist/addon.js"(exports) {
|
|
100260
100428
|
"use strict";
|
|
100261
100429
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
100262
|
-
var require_event_category =
|
|
100263
|
-
var require_sleep =
|
|
100430
|
+
var require_event_category = require_event_category_CRPORAAz();
|
|
100431
|
+
var require_sleep = require_sleep_CMRLJj2e();
|
|
100264
100432
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
100265
100433
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
100266
100434
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -107134,9 +107302,9 @@ var require_dist2 = __commonJS({
|
|
|
107134
107302
|
}
|
|
107135
107303
|
});
|
|
107136
107304
|
|
|
107137
|
-
// ../system/dist/manifest-python-deps-
|
|
107138
|
-
var
|
|
107139
|
-
"../system/dist/manifest-python-deps-
|
|
107305
|
+
// ../system/dist/manifest-python-deps-GejnH--L.js
|
|
107306
|
+
var require_manifest_python_deps_GejnH_L = __commonJS({
|
|
107307
|
+
"../system/dist/manifest-python-deps-GejnH--L.js"(exports) {
|
|
107140
107308
|
"use strict";
|
|
107141
107309
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
107142
107310
|
var node_crypto = __require("crypto");
|
|
@@ -107152,9 +107320,139 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
107152
107320
|
var node_fs = __require("fs");
|
|
107153
107321
|
node_fs = require_chunk.__toESM(node_fs);
|
|
107154
107322
|
var node_http = __require("http");
|
|
107323
|
+
var node_v8 = __require("v8");
|
|
107324
|
+
node_v8 = require_chunk.__toESM(node_v8);
|
|
107325
|
+
var node_vm = __require("vm");
|
|
107326
|
+
node_vm = require_chunk.__toESM(node_vm);
|
|
107155
107327
|
var _camstack_types_addon = require_addon();
|
|
107156
107328
|
var _trpc_client = require_dist2();
|
|
107157
107329
|
var node_net = __require("net");
|
|
107330
|
+
var HEAP_WATCH_INTERVAL_MS = 6e4;
|
|
107331
|
+
var HEAP_WATCH_WARN_RATIO = 0.8;
|
|
107332
|
+
var HEAP_WATCH_ESCALATE_RATIO = 0.7;
|
|
107333
|
+
var HEAP_WATCH_DEESCALATE_RATIO = 0.6;
|
|
107334
|
+
function nextMode(current, usedRatio, escalateRatio = HEAP_WATCH_ESCALATE_RATIO, deescalateRatio = HEAP_WATCH_DEESCALATE_RATIO) {
|
|
107335
|
+
if (current === "escalated") return usedRatio < deescalateRatio ? "steady" : "escalated";
|
|
107336
|
+
return usedRatio >= escalateRatio ? "escalated" : "steady";
|
|
107337
|
+
}
|
|
107338
|
+
var HEAP_RECLAIM_TRIGGER_MB = 1024;
|
|
107339
|
+
var HEAP_RECLAIM_MIN_INTERVAL_MS = 12e4;
|
|
107340
|
+
var MB = (bytes) => Math.round(bytes / 1048576);
|
|
107341
|
+
function buildHeapSample(mem, heapLimitBytes, warnRatio = HEAP_WATCH_WARN_RATIO) {
|
|
107342
|
+
const usedRatio = heapLimitBytes > 0 ? mem.heapUsed / heapLimitBytes : 0;
|
|
107343
|
+
return {
|
|
107344
|
+
rssMb: MB(mem.rss),
|
|
107345
|
+
heapUsedMb: MB(mem.heapUsed),
|
|
107346
|
+
heapTotalMb: MB(mem.heapTotal),
|
|
107347
|
+
heapLimitMb: MB(heapLimitBytes),
|
|
107348
|
+
externalMb: MB(mem.external),
|
|
107349
|
+
arrayBuffersMb: MB(mem.arrayBuffers),
|
|
107350
|
+
usedRatio: Math.round(usedRatio * 100) / 100,
|
|
107351
|
+
nearLimit: usedRatio >= warnRatio
|
|
107352
|
+
};
|
|
107353
|
+
}
|
|
107354
|
+
var consoleSink = {
|
|
107355
|
+
info: (line) => console.log(line),
|
|
107356
|
+
warn: (line) => console.warn(line)
|
|
107357
|
+
};
|
|
107358
|
+
function strandedMb(s) {
|
|
107359
|
+
return s.rssMb - s.heapUsedMb - s.externalMb;
|
|
107360
|
+
}
|
|
107361
|
+
function shouldReclaim(s, triggerMb = HEAP_RECLAIM_TRIGGER_MB) {
|
|
107362
|
+
return strandedMb(s) > triggerMb;
|
|
107363
|
+
}
|
|
107364
|
+
function isGcFunction(value) {
|
|
107365
|
+
return typeof value === "function";
|
|
107366
|
+
}
|
|
107367
|
+
function createV8Reclaimer() {
|
|
107368
|
+
try {
|
|
107369
|
+
node_v8.setFlagsFromString("--expose-gc");
|
|
107370
|
+
const gc = node_vm.runInNewContext("gc");
|
|
107371
|
+
node_v8.setFlagsFromString("--no-expose-gc");
|
|
107372
|
+
if (!isGcFunction(gc)) return void 0;
|
|
107373
|
+
return () => gc({
|
|
107374
|
+
execution: "sync",
|
|
107375
|
+
flavor: "last-resort"
|
|
107376
|
+
});
|
|
107377
|
+
} catch {
|
|
107378
|
+
return;
|
|
107379
|
+
}
|
|
107380
|
+
}
|
|
107381
|
+
function format2(label, s) {
|
|
107382
|
+
return `[mem] ${label} rss=${s.rssMb}MB heapUsed=${s.heapUsedMb}MB heapTotal=${s.heapTotalMb}MB heapLimit=${s.heapLimitMb}MB used=${Math.round(s.usedRatio * 100)}% external=${s.externalMb}MB arrayBuffers=${s.arrayBuffersMb}MB`;
|
|
107383
|
+
}
|
|
107384
|
+
function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions) {
|
|
107385
|
+
const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
|
|
107386
|
+
const now = reclaimOptions?.now ?? (() => Date.now());
|
|
107387
|
+
const triggerMb = reclaimOptions?.triggerMb ?? 1024;
|
|
107388
|
+
const minIntervalMs = reclaimOptions?.minIntervalMs ?? 12e4;
|
|
107389
|
+
const fastIntervalMs = reclaimOptions?.fastIntervalMs ?? 2e3;
|
|
107390
|
+
const escalateRatio = reclaimOptions?.escalateRatio ?? 0.7;
|
|
107391
|
+
const deescalateRatio = reclaimOptions?.deescalateRatio ?? 0.6;
|
|
107392
|
+
let lastReclaimAt = Number.NEGATIVE_INFINITY;
|
|
107393
|
+
const read = () => {
|
|
107394
|
+
const limit = reclaimOptions?.heapLimitBytes ?? node_v8.getHeapStatistics().heap_size_limit;
|
|
107395
|
+
return buildHeapSample(readMemory(), limit);
|
|
107396
|
+
};
|
|
107397
|
+
const maybeReclaim = (sample) => {
|
|
107398
|
+
if (reclaimOptions === void 0) return;
|
|
107399
|
+
if (!shouldReclaim(sample, triggerMb)) return;
|
|
107400
|
+
if (now() - lastReclaimAt < minIntervalMs) return;
|
|
107401
|
+
lastReclaimAt = now();
|
|
107402
|
+
const startedAt = now();
|
|
107403
|
+
try {
|
|
107404
|
+
reclaimOptions.reclaim();
|
|
107405
|
+
} catch (error) {
|
|
107406
|
+
sink.warn(`[mem] reclaim failed \u2014 ${error instanceof Error ? error.message : String(error)}`);
|
|
107407
|
+
return;
|
|
107408
|
+
}
|
|
107409
|
+
const after = read();
|
|
107410
|
+
sink.info(`[mem] reclaim ${label} stranded=${strandedMb(sample)}MB rss=${sample.rssMb}MB\u2192${after.rssMb}MB freed=${sample.rssMb - after.rssMb}MB arrayBuffers=${sample.arrayBuffersMb}MB\u2192${after.arrayBuffersMb}MB took=${now() - startedAt}ms`);
|
|
107411
|
+
};
|
|
107412
|
+
let mode = "steady";
|
|
107413
|
+
let lastLoggedAt = Number.NEGATIVE_INFINITY;
|
|
107414
|
+
const probeIntervalMs = Math.min(fastIntervalMs, intervalMs);
|
|
107415
|
+
const tick = () => {
|
|
107416
|
+
try {
|
|
107417
|
+
const sample = read();
|
|
107418
|
+
const previous = mode;
|
|
107419
|
+
mode = nextMode(previous, sample.usedRatio, escalateRatio, deescalateRatio);
|
|
107420
|
+
const at = now();
|
|
107421
|
+
const due = at - lastLoggedAt >= intervalMs;
|
|
107422
|
+
if (mode === "escalated" || due) {
|
|
107423
|
+
lastLoggedAt = at;
|
|
107424
|
+
const line = format2(label, sample);
|
|
107425
|
+
if (sample.nearLimit) sink.warn(`${line} \u2014 APPROACHING HEAP LIMIT`);
|
|
107426
|
+
else if (mode === "escalated") sink.warn(`${line} \u2014 heap elevated, sampling every ${probeIntervalMs}ms`);
|
|
107427
|
+
else sink.info(line);
|
|
107428
|
+
}
|
|
107429
|
+
if (previous === "escalated" && mode === "steady") sink.info(`[mem] ${label} heap back to routine \u2014 logging every ${intervalMs}ms`);
|
|
107430
|
+
maybeReclaim(sample);
|
|
107431
|
+
} catch {
|
|
107432
|
+
}
|
|
107433
|
+
};
|
|
107434
|
+
const timer = setInterval(tick, probeIntervalMs);
|
|
107435
|
+
timer.unref?.();
|
|
107436
|
+
tick();
|
|
107437
|
+
let stopped = false;
|
|
107438
|
+
return () => {
|
|
107439
|
+
if (stopped) return;
|
|
107440
|
+
stopped = true;
|
|
107441
|
+
clearInterval(timer);
|
|
107442
|
+
};
|
|
107443
|
+
}
|
|
107444
|
+
var RUNNER_HEAP_WATCH_INTERVAL_MS = 3e5;
|
|
107445
|
+
function startRunnerHeapWatch(options) {
|
|
107446
|
+
if (options.heapProfile !== "heavy") return void 0;
|
|
107447
|
+
const intervalMs = options.intervalMs ?? 3e5;
|
|
107448
|
+
if (options.reclaimSwitch === "off") return startHeapWatch(options.label, options.sink, intervalMs);
|
|
107449
|
+
let reclaimOptions = options.reclaimOptions;
|
|
107450
|
+
if (reclaimOptions === void 0) {
|
|
107451
|
+
const reclaimer = createV8Reclaimer();
|
|
107452
|
+
reclaimOptions = reclaimer === void 0 ? void 0 : { reclaim: reclaimer };
|
|
107453
|
+
}
|
|
107454
|
+
return startHeapWatch(options.label, options.sink, intervalMs, reclaimOptions);
|
|
107455
|
+
}
|
|
107158
107456
|
function trimSlashes(s) {
|
|
107159
107457
|
return s.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
107160
107458
|
}
|
|
@@ -113513,6 +113811,30 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
113513
113811
|
return FrameDecoder;
|
|
113514
113812
|
}
|
|
113515
113813
|
});
|
|
113814
|
+
Object.defineProperty(exports, "HEAP_RECLAIM_MIN_INTERVAL_MS", {
|
|
113815
|
+
enumerable: true,
|
|
113816
|
+
get: function() {
|
|
113817
|
+
return HEAP_RECLAIM_MIN_INTERVAL_MS;
|
|
113818
|
+
}
|
|
113819
|
+
});
|
|
113820
|
+
Object.defineProperty(exports, "HEAP_RECLAIM_TRIGGER_MB", {
|
|
113821
|
+
enumerable: true,
|
|
113822
|
+
get: function() {
|
|
113823
|
+
return HEAP_RECLAIM_TRIGGER_MB;
|
|
113824
|
+
}
|
|
113825
|
+
});
|
|
113826
|
+
Object.defineProperty(exports, "HEAP_WATCH_INTERVAL_MS", {
|
|
113827
|
+
enumerable: true,
|
|
113828
|
+
get: function() {
|
|
113829
|
+
return HEAP_WATCH_INTERVAL_MS;
|
|
113830
|
+
}
|
|
113831
|
+
});
|
|
113832
|
+
Object.defineProperty(exports, "HEAP_WATCH_WARN_RATIO", {
|
|
113833
|
+
enumerable: true,
|
|
113834
|
+
get: function() {
|
|
113835
|
+
return HEAP_WATCH_WARN_RATIO;
|
|
113836
|
+
}
|
|
113837
|
+
});
|
|
113516
113838
|
Object.defineProperty(exports, "HUB_CAP_FWD_ACTION", {
|
|
113517
113839
|
enumerable: true,
|
|
113518
113840
|
get: function() {
|
|
@@ -113543,6 +113865,12 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
113543
113865
|
return NATIVE_PROVIDER_SERVICE_INFIX;
|
|
113544
113866
|
}
|
|
113545
113867
|
});
|
|
113868
|
+
Object.defineProperty(exports, "RUNNER_HEAP_WATCH_INTERVAL_MS", {
|
|
113869
|
+
enumerable: true,
|
|
113870
|
+
get: function() {
|
|
113871
|
+
return RUNNER_HEAP_WATCH_INTERVAL_MS;
|
|
113872
|
+
}
|
|
113873
|
+
});
|
|
113546
113874
|
Object.defineProperty(exports, "SocketChannel", {
|
|
113547
113875
|
enumerable: true,
|
|
113548
113876
|
get: function() {
|
|
@@ -113591,6 +113919,12 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
113591
113919
|
return brokerTransportLink;
|
|
113592
113920
|
}
|
|
113593
113921
|
});
|
|
113922
|
+
Object.defineProperty(exports, "buildHeapSample", {
|
|
113923
|
+
enumerable: true,
|
|
113924
|
+
get: function() {
|
|
113925
|
+
return buildHeapSample;
|
|
113926
|
+
}
|
|
113927
|
+
});
|
|
113594
113928
|
Object.defineProperty(exports, "buildLinkChain", {
|
|
113595
113929
|
enumerable: true,
|
|
113596
113930
|
get: function() {
|
|
@@ -113735,6 +114069,12 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
113735
114069
|
return createUdsLoggerWithControl;
|
|
113736
114070
|
}
|
|
113737
114071
|
});
|
|
114072
|
+
Object.defineProperty(exports, "createV8Reclaimer", {
|
|
114073
|
+
enumerable: true,
|
|
114074
|
+
get: function() {
|
|
114075
|
+
return createV8Reclaimer;
|
|
114076
|
+
}
|
|
114077
|
+
});
|
|
113738
114078
|
Object.defineProperty(exports, "deserializeTypedArrays", {
|
|
113739
114079
|
enumerable: true,
|
|
113740
114080
|
get: function() {
|
|
@@ -113897,6 +114237,30 @@ var require_manifest_python_deps_BtVjvfvj = __commonJS({
|
|
|
113897
114237
|
return setWorkerNativeCapsChangeListener;
|
|
113898
114238
|
}
|
|
113899
114239
|
});
|
|
114240
|
+
Object.defineProperty(exports, "shouldReclaim", {
|
|
114241
|
+
enumerable: true,
|
|
114242
|
+
get: function() {
|
|
114243
|
+
return shouldReclaim;
|
|
114244
|
+
}
|
|
114245
|
+
});
|
|
114246
|
+
Object.defineProperty(exports, "startHeapWatch", {
|
|
114247
|
+
enumerable: true,
|
|
114248
|
+
get: function() {
|
|
114249
|
+
return startHeapWatch;
|
|
114250
|
+
}
|
|
114251
|
+
});
|
|
114252
|
+
Object.defineProperty(exports, "startRunnerHeapWatch", {
|
|
114253
|
+
enumerable: true,
|
|
114254
|
+
get: function() {
|
|
114255
|
+
return startRunnerHeapWatch;
|
|
114256
|
+
}
|
|
114257
|
+
});
|
|
114258
|
+
Object.defineProperty(exports, "strandedMb", {
|
|
114259
|
+
enumerable: true,
|
|
114260
|
+
get: function() {
|
|
114261
|
+
return strandedMb;
|
|
114262
|
+
}
|
|
114263
|
+
});
|
|
113900
114264
|
Object.defineProperty(exports, "subscribePassthrough", {
|
|
113901
114265
|
enumerable: true,
|
|
113902
114266
|
get: function() {
|
|
@@ -117717,7 +118081,7 @@ var require_dist3 = __commonJS({
|
|
|
117717
118081
|
"use strict";
|
|
117718
118082
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
117719
118083
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
117720
|
-
var require_dist10 =
|
|
118084
|
+
var require_dist10 = require_dist_DR1VmGz6();
|
|
117721
118085
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
117722
118086
|
require_alerts();
|
|
117723
118087
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -117742,7 +118106,7 @@ var require_dist3 = __commonJS({
|
|
|
117742
118106
|
require_system_config();
|
|
117743
118107
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
117744
118108
|
var require_file_data_plane = require_file_data_plane_DUHPHa_Y();
|
|
117745
|
-
var require_manifest_python_deps =
|
|
118109
|
+
var require_manifest_python_deps = require_manifest_python_deps_GejnH_L();
|
|
117746
118110
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
117747
118111
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
117748
118112
|
var zod = require_zod();
|
|
@@ -117760,8 +118124,6 @@ var require_dist3 = __commonJS({
|
|
|
117760
118124
|
var node_fs$1 = require_chunk.__toESM(node_fs, 1);
|
|
117761
118125
|
node_fs = require_chunk.__toESM(node_fs);
|
|
117762
118126
|
var node_http = __require("http");
|
|
117763
|
-
var node_v8 = __require("v8");
|
|
117764
|
-
node_v8 = require_chunk.__toESM(node_v8);
|
|
117765
118127
|
var node_vm = __require("vm");
|
|
117766
118128
|
node_vm = require_chunk.__toESM(node_vm);
|
|
117767
118129
|
var _camstack_types_addon = require_addon();
|
|
@@ -118095,120 +118457,6 @@ var require_dist3 = __commonJS({
|
|
|
118095
118457
|
if (replayBody !== void 0) upstream.end(replayBody);
|
|
118096
118458
|
else clientReq.pipe(upstream);
|
|
118097
118459
|
}
|
|
118098
|
-
var HEAP_WATCH_INTERVAL_MS = 6e4;
|
|
118099
|
-
var HEAP_WATCH_WARN_RATIO = 0.8;
|
|
118100
|
-
var HEAP_WATCH_ESCALATE_RATIO = 0.7;
|
|
118101
|
-
var HEAP_WATCH_DEESCALATE_RATIO = 0.6;
|
|
118102
|
-
function nextMode(current, usedRatio, escalateRatio = HEAP_WATCH_ESCALATE_RATIO, deescalateRatio = HEAP_WATCH_DEESCALATE_RATIO) {
|
|
118103
|
-
if (current === "escalated") return usedRatio < deescalateRatio ? "steady" : "escalated";
|
|
118104
|
-
return usedRatio >= escalateRatio ? "escalated" : "steady";
|
|
118105
|
-
}
|
|
118106
|
-
var HEAP_RECLAIM_TRIGGER_MB = 1536;
|
|
118107
|
-
var HEAP_RECLAIM_MIN_INTERVAL_MS = 6e5;
|
|
118108
|
-
var MB = (bytes) => Math.round(bytes / 1048576);
|
|
118109
|
-
function buildHeapSample(mem, heapLimitBytes, warnRatio = HEAP_WATCH_WARN_RATIO) {
|
|
118110
|
-
const usedRatio = heapLimitBytes > 0 ? mem.heapUsed / heapLimitBytes : 0;
|
|
118111
|
-
return {
|
|
118112
|
-
rssMb: MB(mem.rss),
|
|
118113
|
-
heapUsedMb: MB(mem.heapUsed),
|
|
118114
|
-
heapTotalMb: MB(mem.heapTotal),
|
|
118115
|
-
heapLimitMb: MB(heapLimitBytes),
|
|
118116
|
-
externalMb: MB(mem.external),
|
|
118117
|
-
arrayBuffersMb: MB(mem.arrayBuffers),
|
|
118118
|
-
usedRatio: Math.round(usedRatio * 100) / 100,
|
|
118119
|
-
nearLimit: usedRatio >= warnRatio
|
|
118120
|
-
};
|
|
118121
|
-
}
|
|
118122
|
-
var consoleSink = {
|
|
118123
|
-
info: (line) => console.log(line),
|
|
118124
|
-
warn: (line) => console.warn(line)
|
|
118125
|
-
};
|
|
118126
|
-
function strandedMb(s) {
|
|
118127
|
-
return s.rssMb - s.heapUsedMb - s.externalMb;
|
|
118128
|
-
}
|
|
118129
|
-
function shouldReclaim(s, triggerMb = HEAP_RECLAIM_TRIGGER_MB) {
|
|
118130
|
-
return strandedMb(s) > triggerMb;
|
|
118131
|
-
}
|
|
118132
|
-
function isGcFunction(value) {
|
|
118133
|
-
return typeof value === "function";
|
|
118134
|
-
}
|
|
118135
|
-
function createV8Reclaimer() {
|
|
118136
|
-
try {
|
|
118137
|
-
node_v8.setFlagsFromString("--expose-gc");
|
|
118138
|
-
const gc = node_vm.runInNewContext("gc");
|
|
118139
|
-
node_v8.setFlagsFromString("--no-expose-gc");
|
|
118140
|
-
if (!isGcFunction(gc)) return void 0;
|
|
118141
|
-
return () => gc({
|
|
118142
|
-
execution: "sync",
|
|
118143
|
-
flavor: "last-resort"
|
|
118144
|
-
});
|
|
118145
|
-
} catch {
|
|
118146
|
-
return;
|
|
118147
|
-
}
|
|
118148
|
-
}
|
|
118149
|
-
function format$1(label, s) {
|
|
118150
|
-
return `[mem] ${label} rss=${s.rssMb}MB heapUsed=${s.heapUsedMb}MB heapTotal=${s.heapTotalMb}MB heapLimit=${s.heapLimitMb}MB used=${Math.round(s.usedRatio * 100)}% external=${s.externalMb}MB arrayBuffers=${s.arrayBuffersMb}MB`;
|
|
118151
|
-
}
|
|
118152
|
-
function startHeapWatch(label = "hub-main", sink = consoleSink, intervalMs = HEAP_WATCH_INTERVAL_MS, reclaimOptions) {
|
|
118153
|
-
const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
|
|
118154
|
-
const now = reclaimOptions?.now ?? (() => Date.now());
|
|
118155
|
-
const triggerMb = reclaimOptions?.triggerMb ?? 1536;
|
|
118156
|
-
const minIntervalMs = reclaimOptions?.minIntervalMs ?? 6e5;
|
|
118157
|
-
const fastIntervalMs = reclaimOptions?.fastIntervalMs ?? 2e3;
|
|
118158
|
-
const escalateRatio = reclaimOptions?.escalateRatio ?? 0.7;
|
|
118159
|
-
const deescalateRatio = reclaimOptions?.deescalateRatio ?? 0.6;
|
|
118160
|
-
let lastReclaimAt = Number.NEGATIVE_INFINITY;
|
|
118161
|
-
const read = () => {
|
|
118162
|
-
const limit = reclaimOptions?.heapLimitBytes ?? node_v8.getHeapStatistics().heap_size_limit;
|
|
118163
|
-
return buildHeapSample(readMemory(), limit);
|
|
118164
|
-
};
|
|
118165
|
-
const maybeReclaim = (sample) => {
|
|
118166
|
-
if (reclaimOptions === void 0) return;
|
|
118167
|
-
if (!shouldReclaim(sample, triggerMb)) return;
|
|
118168
|
-
if (now() - lastReclaimAt < minIntervalMs) return;
|
|
118169
|
-
lastReclaimAt = now();
|
|
118170
|
-
const startedAt = now();
|
|
118171
|
-
try {
|
|
118172
|
-
reclaimOptions.reclaim();
|
|
118173
|
-
} catch (error) {
|
|
118174
|
-
sink.warn(`[mem] reclaim failed \u2014 ${error instanceof Error ? error.message : String(error)}`);
|
|
118175
|
-
return;
|
|
118176
|
-
}
|
|
118177
|
-
const after = read();
|
|
118178
|
-
sink.info(`[mem] reclaim ${label} stranded=${strandedMb(sample)}MB rss=${sample.rssMb}MB\u2192${after.rssMb}MB freed=${sample.rssMb - after.rssMb}MB arrayBuffers=${sample.arrayBuffersMb}MB\u2192${after.arrayBuffersMb}MB took=${now() - startedAt}ms`);
|
|
118179
|
-
};
|
|
118180
|
-
let mode = "steady";
|
|
118181
|
-
let lastLoggedAt = Number.NEGATIVE_INFINITY;
|
|
118182
|
-
const probeIntervalMs = Math.min(fastIntervalMs, intervalMs);
|
|
118183
|
-
const tick = () => {
|
|
118184
|
-
try {
|
|
118185
|
-
const sample = read();
|
|
118186
|
-
const previous = mode;
|
|
118187
|
-
mode = nextMode(previous, sample.usedRatio, escalateRatio, deescalateRatio);
|
|
118188
|
-
const at2 = now();
|
|
118189
|
-
const due = at2 - lastLoggedAt >= intervalMs;
|
|
118190
|
-
if (mode === "escalated" || due) {
|
|
118191
|
-
lastLoggedAt = at2;
|
|
118192
|
-
const line = format$1(label, sample);
|
|
118193
|
-
if (sample.nearLimit) sink.warn(`${line} \u2014 APPROACHING HEAP LIMIT`);
|
|
118194
|
-
else if (mode === "escalated") sink.warn(`${line} \u2014 heap elevated, sampling every ${probeIntervalMs}ms`);
|
|
118195
|
-
else sink.info(line);
|
|
118196
|
-
}
|
|
118197
|
-
if (previous === "escalated" && mode === "steady") sink.info(`[mem] ${label} heap back to routine \u2014 logging every ${intervalMs}ms`);
|
|
118198
|
-
maybeReclaim(sample);
|
|
118199
|
-
} catch {
|
|
118200
|
-
}
|
|
118201
|
-
};
|
|
118202
|
-
const timer = setInterval(tick, probeIntervalMs);
|
|
118203
|
-
timer.unref?.();
|
|
118204
|
-
tick();
|
|
118205
|
-
let stopped = false;
|
|
118206
|
-
return () => {
|
|
118207
|
-
if (stopped) return;
|
|
118208
|
-
stopped = true;
|
|
118209
|
-
clearInterval(timer);
|
|
118210
|
-
};
|
|
118211
|
-
}
|
|
118212
118460
|
var VALID_TRANSITIONS = {
|
|
118213
118461
|
stopped: ["starting", "disabled"],
|
|
118214
118462
|
starting: [
|
|
@@ -118440,17 +118688,27 @@ var require_dist3 = __commonJS({
|
|
|
118440
118688
|
return bare;
|
|
118441
118689
|
}
|
|
118442
118690
|
var PRUNE_TARGET_RATIO = 0.9;
|
|
118691
|
+
var DEFAULT_MAX_TOTAL_LOG_ENTRIES = 5e4;
|
|
118443
118692
|
var PartitionedLogBuffer = class {
|
|
118444
118693
|
buffers = /* @__PURE__ */ new Map();
|
|
118694
|
+
/**
|
|
118695
|
+
* Bucket key → the write ordinal of its last `push`. A monotonic counter, not
|
|
118696
|
+
* a clock: eviction order must follow the order writes actually happened, and
|
|
118697
|
+
* a wall clock that steps backwards would pick the wrong victim.
|
|
118698
|
+
*/
|
|
118699
|
+
lastWriteSeq = /* @__PURE__ */ new Map();
|
|
118700
|
+
writeSeq = 0;
|
|
118445
118701
|
perAddonCapacity;
|
|
118446
118702
|
maxTotalEntries;
|
|
118447
118703
|
pruneLevel;
|
|
118704
|
+
maxBuckets;
|
|
118448
118705
|
/** Running total, so `push` does not walk every bucket to decide. */
|
|
118449
118706
|
totalEntries = 0;
|
|
118450
118707
|
constructor(perAddonCapacity = 5e3, options = {}) {
|
|
118451
118708
|
this.perAddonCapacity = options.perAddonCapacity ?? perAddonCapacity;
|
|
118452
|
-
this.maxTotalEntries = options.maxTotalEntries
|
|
118709
|
+
this.maxTotalEntries = options.maxTotalEntries === void 0 ? DEFAULT_MAX_TOTAL_LOG_ENTRIES : options.maxTotalEntries;
|
|
118453
118710
|
this.pruneLevel = options.pruneLevel ?? "debug";
|
|
118711
|
+
this.maxBuckets = options.maxBuckets === void 0 ? 128 : options.maxBuckets;
|
|
118454
118712
|
}
|
|
118455
118713
|
/**
|
|
118456
118714
|
* Apply new limits at runtime. Shrinking takes effect as entries are pushed
|
|
@@ -118463,6 +118721,7 @@ var require_dist3 = __commonJS({
|
|
|
118463
118721
|
if (options.perAddonCapacity !== void 0 && options.perAddonCapacity > 0) this.perAddonCapacity = options.perAddonCapacity;
|
|
118464
118722
|
if (options.maxTotalEntries !== void 0) this.maxTotalEntries = options.maxTotalEntries;
|
|
118465
118723
|
if (options.pruneLevel !== void 0) this.pruneLevel = options.pruneLevel;
|
|
118724
|
+
if (options.maxBuckets !== void 0) this.maxBuckets = options.maxBuckets;
|
|
118466
118725
|
}
|
|
118467
118726
|
bufferFor(key) {
|
|
118468
118727
|
let buf = this.buffers.get(key);
|
|
@@ -118473,34 +118732,82 @@ var require_dist3 = __commonJS({
|
|
|
118473
118732
|
return buf;
|
|
118474
118733
|
}
|
|
118475
118734
|
push(entry) {
|
|
118476
|
-
const
|
|
118735
|
+
const key = addonBucketKey(entry.tags?.addonId);
|
|
118736
|
+
const buf = this.bufferFor(key);
|
|
118477
118737
|
const before = buf.size();
|
|
118478
118738
|
buf.push(entry);
|
|
118479
118739
|
this.totalEntries += buf.size() - before;
|
|
118480
|
-
|
|
118740
|
+
this.lastWriteSeq.set(key, ++this.writeSeq);
|
|
118741
|
+
if (this.maxBuckets !== null && this.buffers.size > this.maxBuckets) this.evictBuckets(this.buffers.size - this.maxBuckets, key);
|
|
118742
|
+
if (this.maxTotalEntries !== null && this.totalEntries > this.maxTotalEntries) this.enforceTotalCap(this.maxTotalEntries, key);
|
|
118481
118743
|
}
|
|
118482
118744
|
/**
|
|
118483
|
-
* Bring the total down to `PRUNE_TARGET_RATIO × cap
|
|
118484
|
-
*
|
|
118485
|
-
*
|
|
118486
|
-
*
|
|
118487
|
-
|
|
118488
|
-
|
|
118745
|
+
* Bring the total down to `PRUNE_TARGET_RATIO × cap`.
|
|
118746
|
+
*
|
|
118747
|
+
* Two passes, in this order and no other: first discard prunable entries,
|
|
118748
|
+
* largest bucket first, which is free of information cost. Only if that
|
|
118749
|
+
* cannot reach the target does the second pass drop WHOLE buckets,
|
|
118750
|
+
* least-recently-written first — the bound has to hold even when every
|
|
118751
|
+
* retained entry is above `pruneLevel`, and a bucket nobody has written to is
|
|
118752
|
+
* the cheapest thing in the structure to lose.
|
|
118753
|
+
*/
|
|
118754
|
+
enforceTotalCap(cap, protectedKey) {
|
|
118489
118755
|
const target = Math.max(1, Math.floor(cap * PRUNE_TARGET_RATIO));
|
|
118490
118756
|
let deficit = this.totalEntries - target;
|
|
118491
118757
|
if (deficit <= 0) return;
|
|
118492
|
-
const bySizeDesc = [...this.buffers.
|
|
118493
|
-
for (const buf of bySizeDesc) {
|
|
118758
|
+
const bySizeDesc = [...this.buffers.entries()].toSorted((a, b) => b[1].size() - a[1].size());
|
|
118759
|
+
for (const [key, buf] of bySizeDesc) {
|
|
118494
118760
|
if (deficit <= 0) break;
|
|
118495
118761
|
const removed = buf.pruneOldestAtOrBelow(this.pruneLevel, deficit);
|
|
118496
118762
|
this.totalEntries -= removed;
|
|
118497
118763
|
deficit -= removed;
|
|
118764
|
+
if (buf.size() === 0) this.dropBucket(key);
|
|
118765
|
+
}
|
|
118766
|
+
if (deficit > 0) this.evictBucketsUntil(target, protectedKey);
|
|
118767
|
+
}
|
|
118768
|
+
/**
|
|
118769
|
+
* Drop whole buckets, least-recently-WRITTEN first, until the total is at or
|
|
118770
|
+
* below `target`. Never touches `protectedKey` (the bucket being written to
|
|
118771
|
+
* right now) and always leaves at least one bucket standing.
|
|
118772
|
+
*/
|
|
118773
|
+
evictBucketsUntil(target, protectedKey) {
|
|
118774
|
+
for (const key of this.evictionOrder(protectedKey)) {
|
|
118775
|
+
if (this.totalEntries <= target || this.buffers.size <= 1) return;
|
|
118776
|
+
this.dropBucket(key);
|
|
118498
118777
|
}
|
|
118499
118778
|
}
|
|
118779
|
+
/** Drop exactly `count` buckets, least-recently-written first. */
|
|
118780
|
+
evictBuckets(count, protectedKey) {
|
|
118781
|
+
let remaining = count;
|
|
118782
|
+
for (const key of this.evictionOrder(protectedKey)) {
|
|
118783
|
+
if (remaining <= 0 || this.buffers.size <= 1) return;
|
|
118784
|
+
this.dropBucket(key);
|
|
118785
|
+
remaining -= 1;
|
|
118786
|
+
}
|
|
118787
|
+
}
|
|
118788
|
+
/** Bucket keys ordered least-recently-written first, excluding `protectedKey`.
|
|
118789
|
+
* A bucket with no recorded write sorts first — it can only be a leftover. */
|
|
118790
|
+
evictionOrder(protectedKey) {
|
|
118791
|
+
return [...this.buffers.keys()].filter((key) => key !== protectedKey).toSorted((a, b) => (this.lastWriteSeq.get(a) ?? 0) - (this.lastWriteSeq.get(b) ?? 0));
|
|
118792
|
+
}
|
|
118793
|
+
/** Remove a bucket and everything that indexes it. An empty ring left behind
|
|
118794
|
+
* is the leak this class shipped with — the map only ever grew. */
|
|
118795
|
+
dropBucket(key) {
|
|
118796
|
+
const buf = this.buffers.get(key);
|
|
118797
|
+
if (buf === void 0) return;
|
|
118798
|
+
this.totalEntries -= buf.size();
|
|
118799
|
+
this.buffers.delete(key);
|
|
118800
|
+
this.lastWriteSeq.delete(key);
|
|
118801
|
+
}
|
|
118500
118802
|
/** Entries retained across every bucket. */
|
|
118501
118803
|
size() {
|
|
118502
118804
|
return this.totalEntries;
|
|
118503
118805
|
}
|
|
118806
|
+
/** Buckets currently retained. Observability for the aggregate bound — an
|
|
118807
|
+
* addon roster that only ever grows is what this class had to stop doing. */
|
|
118808
|
+
bucketCount() {
|
|
118809
|
+
return this.buffers.size;
|
|
118810
|
+
}
|
|
118504
118811
|
/** Every retained entry across all buckets, newest-first (mirrors
|
|
118505
118812
|
* {@link LogRingBuffer.getAll}). Used to replay history to a destination. */
|
|
118506
118813
|
getAll() {
|
|
@@ -118528,13 +118835,25 @@ var require_dist3 = __commonJS({
|
|
|
118528
118835
|
if (pinned !== null) {
|
|
118529
118836
|
const removed2 = this.buffers.get(pinned)?.clear(filter) ?? 0;
|
|
118530
118837
|
this.totalEntries -= removed2;
|
|
118838
|
+
this.dropIfEmpty(pinned);
|
|
118531
118839
|
return removed2;
|
|
118532
118840
|
}
|
|
118533
118841
|
let removed = 0;
|
|
118534
|
-
for (const buf of this.buffers.
|
|
118842
|
+
for (const [key, buf] of [...this.buffers.entries()]) {
|
|
118843
|
+
removed += buf.clear(filter);
|
|
118844
|
+
this.dropIfEmpty(key);
|
|
118845
|
+
}
|
|
118535
118846
|
this.totalEntries -= removed;
|
|
118536
118847
|
return removed;
|
|
118537
118848
|
}
|
|
118849
|
+
/** An emptied bucket is removed rather than left as an empty ring: the map
|
|
118850
|
+
* used to grow with every addon id that ever logged and never shrink. */
|
|
118851
|
+
dropIfEmpty(key) {
|
|
118852
|
+
if (this.buffers.get(key)?.size() === 0) {
|
|
118853
|
+
this.buffers.delete(key);
|
|
118854
|
+
this.lastWriteSeq.delete(key);
|
|
118855
|
+
}
|
|
118856
|
+
}
|
|
118538
118857
|
/** The bucket key a filter pins to via `tags.addonId`, or null when the
|
|
118539
118858
|
* filter doesn't constrain the addon (→ scan all buckets). */
|
|
118540
118859
|
pinnedAddonKey(filter) {
|
|
@@ -118630,11 +118949,13 @@ var require_dist3 = __commonJS({
|
|
|
118630
118949
|
* `perAddonCapacity` bounds EACH addon's bucket, not the total — a chatty addon
|
|
118631
118950
|
* evicts only its own lines, so quiet addons keep their sparse history.
|
|
118632
118951
|
*
|
|
118633
|
-
* `options.maxTotalEntries`
|
|
118634
|
-
* per-bucket bound scales with addon count
|
|
118635
|
-
*
|
|
118636
|
-
* `
|
|
118637
|
-
*
|
|
118952
|
+
* `options.maxTotalEntries` ceilings the total across all buckets, because the
|
|
118953
|
+
* per-bucket bound scales with addon count, and `options.maxBuckets` ceilings the
|
|
118954
|
+
* bucket count itself. When the total is exceeded, entries at or below
|
|
118955
|
+
* `options.pruneLevel` (default `debug`) are discarded first — a live addon's
|
|
118956
|
+
* `warn`/`error` are never evicted to satisfy it — and only if that cannot reach
|
|
118957
|
+
* the target are whole least-recently-written buckets dropped. Both bounds are ON
|
|
118958
|
+
* by default; pass an explicit `null` to opt out. See {@link PartitionedLogBuffer}.
|
|
118638
118959
|
*/
|
|
118639
118960
|
constructor(perAddonCapacity = 5e3, options = {}) {
|
|
118640
118961
|
this.ringBuffer = new PartitionedLogBuffer(perAddonCapacity, options);
|
|
@@ -197235,22 +197556,33 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
197235
197556
|
});
|
|
197236
197557
|
});
|
|
197237
197558
|
}
|
|
197559
|
+
var EMPTY_HEAP_DECLARATION = {
|
|
197560
|
+
profile: void 0,
|
|
197561
|
+
maxOldSpaceMb: void 0
|
|
197562
|
+
};
|
|
197238
197563
|
var heapProfileCache = /* @__PURE__ */ new Map();
|
|
197239
|
-
function
|
|
197564
|
+
function readAddonHeapDeclaration(spec) {
|
|
197240
197565
|
const cacheKey = `${spec.addonDir}::${spec.addonId}`;
|
|
197241
197566
|
const cached = heapProfileCache.get(cacheKey);
|
|
197242
|
-
if (cached !== void 0
|
|
197243
|
-
let
|
|
197567
|
+
if (cached !== void 0) return cached;
|
|
197568
|
+
let declaration = EMPTY_HEAP_DECLARATION;
|
|
197244
197569
|
for (const manifestPath of [node_path.join(spec.addonDir, "package.json"), node_path.join(node_path.dirname(spec.addonDir), "package.json")]) try {
|
|
197245
197570
|
const raw = node_fs.readFileSync(manifestPath, "utf8");
|
|
197246
197571
|
const parsed = JSON.parse(raw);
|
|
197247
|
-
profile = extractHeapProfile(parsed, spec.addonId);
|
|
197248
|
-
|
|
197572
|
+
const profile = extractHeapProfile(parsed, spec.addonId);
|
|
197573
|
+
const maxOldSpaceMb = extractMaxOldSpaceMb(parsed, spec.addonId);
|
|
197574
|
+
if (profile !== void 0 || maxOldSpaceMb !== void 0) {
|
|
197575
|
+
declaration = {
|
|
197576
|
+
profile,
|
|
197577
|
+
maxOldSpaceMb
|
|
197578
|
+
};
|
|
197579
|
+
break;
|
|
197580
|
+
}
|
|
197249
197581
|
if (manifestHasAddon(parsed, spec.addonId)) break;
|
|
197250
197582
|
} catch {
|
|
197251
197583
|
}
|
|
197252
|
-
heapProfileCache.set(cacheKey,
|
|
197253
|
-
return
|
|
197584
|
+
heapProfileCache.set(cacheKey, declaration);
|
|
197585
|
+
return declaration;
|
|
197254
197586
|
}
|
|
197255
197587
|
function invalidateHeapProfiles(addons) {
|
|
197256
197588
|
for (const spec of addons) heapProfileCache.delete(`${spec.addonDir}::${spec.addonId}`);
|
|
@@ -197262,6 +197594,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
197262
197594
|
const value = readManifestAddons(parsed).find((a) => a.id === addonId)?.execution?.heapProfile;
|
|
197263
197595
|
return value === "heavy" || value === "light" ? value : void 0;
|
|
197264
197596
|
}
|
|
197597
|
+
function extractMaxOldSpaceMb(parsed, addonId) {
|
|
197598
|
+
const value = readManifestAddons(parsed).find((a) => a.id === addonId)?.execution?.maxOldSpaceMb;
|
|
197599
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
|
|
197600
|
+
}
|
|
197265
197601
|
function readManifestAddons(parsed) {
|
|
197266
197602
|
if (typeof parsed !== "object" || parsed === null) return [];
|
|
197267
197603
|
const camstack = parsed.camstack;
|
|
@@ -197270,15 +197606,25 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
197270
197606
|
return Array.isArray(addons) ? addons : [];
|
|
197271
197607
|
}
|
|
197272
197608
|
function isHeavyRunner(addons) {
|
|
197273
|
-
return addons.some((a) =>
|
|
197609
|
+
return addons.some((a) => readAddonHeapDeclaration(a).profile === "heavy");
|
|
197610
|
+
}
|
|
197611
|
+
var HEAVY_MAX_OLD_MB_DEFAULT = 1024;
|
|
197612
|
+
function runnerMaxOldSpaceMb(addons, heavy) {
|
|
197613
|
+
const envDefault = heavy ? positiveIntEnv("CAMSTACK_RUNNER_HEAVY_MAX_OLD_MB", HEAVY_MAX_OLD_MB_DEFAULT) : positiveIntEnv("CAMSTACK_RUNNER_LIGHT_MAX_OLD_MB", 0);
|
|
197614
|
+
const declared = addons.map((a) => readAddonHeapDeclaration(a).maxOldSpaceMb).filter((mb) => mb !== void 0);
|
|
197615
|
+
if (declared.length === 0) return envDefault;
|
|
197616
|
+
if (declared.includes(0)) return 0;
|
|
197617
|
+
return Math.max(...declared);
|
|
197274
197618
|
}
|
|
197275
197619
|
function runnerHeapFlags(addons) {
|
|
197276
197620
|
if (process.env["CAMSTACK_RUNNER_HEAP_TUNING"] === "off") return [];
|
|
197277
|
-
|
|
197278
|
-
const semiMb = positiveIntEnv("CAMSTACK_RUNNER_LIGHT_SEMI_SPACE_MB", 2);
|
|
197279
|
-
const oldMb = positiveIntEnv("CAMSTACK_RUNNER_LIGHT_MAX_OLD_MB", 0);
|
|
197621
|
+
const heavy = isHeavyRunner(addons);
|
|
197280
197622
|
const flags = [];
|
|
197281
|
-
if (
|
|
197623
|
+
if (!heavy) {
|
|
197624
|
+
const semiMb = positiveIntEnv("CAMSTACK_RUNNER_LIGHT_SEMI_SPACE_MB", 2);
|
|
197625
|
+
if (semiMb > 0) flags.push(`--max-semi-space-size=${semiMb}`);
|
|
197626
|
+
}
|
|
197627
|
+
const oldMb = runnerMaxOldSpaceMb(addons, heavy);
|
|
197282
197628
|
if (oldMb > 0) flags.push(`--max-old-space-size=${oldMb}`);
|
|
197283
197629
|
return flags;
|
|
197284
197630
|
}
|
|
@@ -197325,19 +197671,21 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
197325
197671
|
function spawnRunner(runnerId, addons, env) {
|
|
197326
197672
|
const nodeId = buildNodeId(runnerId);
|
|
197327
197673
|
const runnerPath = node_path.resolve(__dirname, "addon-runner.js");
|
|
197674
|
+
const heavy = isHeavyRunner(addons);
|
|
197328
197675
|
const childEnv = {
|
|
197329
197676
|
...process.env,
|
|
197330
197677
|
CAMSTACK_RUNNER_ID: runnerId,
|
|
197331
197678
|
CAMSTACK_RUNNER_ADDONS: JSON.stringify(addons),
|
|
197332
197679
|
CAMSTACK_PARENT_NODE_ID: parentNodeId,
|
|
197333
197680
|
CAMSTACK_DATA_DIR: dataDir,
|
|
197681
|
+
CAMSTACK_RUNNER_HEAP_PROFILE: heavy ? "heavy" : "light",
|
|
197334
197682
|
CAMSTACK_LOG_LEVEL: process.env["CAMSTACK_LOG_LEVEL"] ?? "info",
|
|
197335
197683
|
...parentTcpPort !== void 0 ? { CAMSTACK_PARENT_TCP_PORT: String(parentTcpPort) } : {},
|
|
197336
197684
|
...parentUdsPath !== void 0 ? { CAMSTACK_PARENT_UDS_PATH: parentUdsPath } : {},
|
|
197337
197685
|
...env
|
|
197338
197686
|
};
|
|
197339
197687
|
const heapFlags = runnerHeapFlags(addons);
|
|
197340
|
-
capturedBroker?.logger.info(`[${runnerId}] heap profile: ${
|
|
197688
|
+
capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}]`);
|
|
197341
197689
|
const child = spawnFn(process.execPath, [...heapFlags, runnerPath], {
|
|
197342
197690
|
env: childEnv,
|
|
197343
197691
|
stdio: [
|
|
@@ -197381,6 +197729,15 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
197381
197729
|
capturedBroker?.logger.error(`[${runnerId}] Crash circuit-breaker tripped \u2014 ${decision.crashesInWindow} crashes in ${CRASH_WINDOW_MS}ms. Not respawning.`);
|
|
197382
197730
|
processes.set(runnerId, entry);
|
|
197383
197731
|
if (capturedBroker) forceMoleculerDisconnect(capturedBroker, entry.nodeId);
|
|
197732
|
+
emitRunnerEvent(require_dist10.EventCategory.AddonRunnerFailed, runnerId, {
|
|
197733
|
+
runnerId,
|
|
197734
|
+
nodeId: parentNodeId,
|
|
197735
|
+
addonIds: entry.runnerAddons.map((addon) => addon.addonId),
|
|
197736
|
+
crashesInWindow: decision.crashesInWindow,
|
|
197737
|
+
windowMs: CRASH_WINDOW_MS,
|
|
197738
|
+
...code !== null ? { exitCode: code } : {},
|
|
197739
|
+
...signal !== null ? { signal } : {}
|
|
197740
|
+
});
|
|
197384
197741
|
for (const addon of entry.runnerAddons) emitRunnerEvent(require_dist10.EventCategory.AddonCrashed, addon.addonId, {
|
|
197385
197742
|
addonId: addon.addonId,
|
|
197386
197743
|
error: `Crash circuit-breaker tripped after ${decision.crashesInWindow} crashes in ${CRASH_WINDOW_MS}ms`
|
|
@@ -198102,10 +198459,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
198102
198459
|
exports.HEALTH_MONITOR_GRACE_PERIOD_MS = HEALTH_MONITOR_GRACE_PERIOD_MS;
|
|
198103
198460
|
exports.HEALTH_MONITOR_RETRY_INTERVALS_MS = HEALTH_MONITOR_RETRY_INTERVALS_MS;
|
|
198104
198461
|
exports.HEALTH_MONITOR_TICK_MS = HEALTH_MONITOR_TICK_MS;
|
|
198105
|
-
exports.HEAP_RECLAIM_MIN_INTERVAL_MS = HEAP_RECLAIM_MIN_INTERVAL_MS;
|
|
198106
|
-
exports.HEAP_RECLAIM_TRIGGER_MB = HEAP_RECLAIM_TRIGGER_MB;
|
|
198107
|
-
exports.HEAP_WATCH_INTERVAL_MS = HEAP_WATCH_INTERVAL_MS;
|
|
198108
|
-
exports.HEAP_WATCH_WARN_RATIO = HEAP_WATCH_WARN_RATIO;
|
|
198462
|
+
exports.HEAP_RECLAIM_MIN_INTERVAL_MS = require_manifest_python_deps.HEAP_RECLAIM_MIN_INTERVAL_MS;
|
|
198463
|
+
exports.HEAP_RECLAIM_TRIGGER_MB = require_manifest_python_deps.HEAP_RECLAIM_TRIGGER_MB;
|
|
198464
|
+
exports.HEAP_WATCH_INTERVAL_MS = require_manifest_python_deps.HEAP_WATCH_INTERVAL_MS;
|
|
198465
|
+
exports.HEAP_WATCH_WARN_RATIO = require_manifest_python_deps.HEAP_WATCH_WARN_RATIO;
|
|
198109
198466
|
exports.HUB_CAP_FWD_ACTION = require_manifest_python_deps.HUB_CAP_FWD_ACTION;
|
|
198110
198467
|
exports.HUB_CAP_FWD_SERVICE = require_manifest_python_deps.HUB_CAP_FWD_SERVICE;
|
|
198111
198468
|
exports.HubForwarderAddon = require_builtins_hub_forwarder_index.HubForwarderAddon$1;
|
|
@@ -198144,6 +198501,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
198144
198501
|
exports.PythonEnvManager = PythonEnvManager;
|
|
198145
198502
|
exports.QUARANTINE_DIRNAME = QUARANTINE_DIRNAME;
|
|
198146
198503
|
exports.RESTART_MARKER_FILE = RESTART_MARKER_FILE;
|
|
198504
|
+
exports.RUNNER_HEAP_WATCH_INTERVAL_MS = require_manifest_python_deps.RUNNER_HEAP_WATCH_INTERVAL_MS;
|
|
198147
198505
|
exports.RUNTIME_DEFAULTS = require_dist10.RUNTIME_DEFAULTS;
|
|
198148
198506
|
exports.ReadinessRegistry = require_dist10.ReadinessRegistry;
|
|
198149
198507
|
exports.ReadinessTimeoutError = require_dist10.ReadinessTimeoutError;
|
|
@@ -198182,7 +198540,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
198182
198540
|
}
|
|
198183
198541
|
});
|
|
198184
198542
|
exports.buildCapRouters = buildCapRouters;
|
|
198185
|
-
exports.buildHeapSample = buildHeapSample;
|
|
198543
|
+
exports.buildHeapSample = require_manifest_python_deps.buildHeapSample;
|
|
198186
198544
|
exports.buildLinkChain = require_manifest_python_deps.buildLinkChain;
|
|
198187
198545
|
exports.buildNativeCapProxy = require_manifest_python_deps.buildNativeCapProxy;
|
|
198188
198546
|
exports.buildNodeManifest = buildNodeManifest;
|
|
@@ -198227,7 +198585,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
198227
198585
|
exports.createUdsEventBus = require_manifest_python_deps.createUdsEventBus;
|
|
198228
198586
|
exports.createUdsLogger = require_manifest_python_deps.createUdsLogger;
|
|
198229
198587
|
exports.createUdsLoggerWithControl = require_manifest_python_deps.createUdsLoggerWithControl;
|
|
198230
|
-
exports.createV8Reclaimer = createV8Reclaimer;
|
|
198588
|
+
exports.createV8Reclaimer = require_manifest_python_deps.createV8Reclaimer;
|
|
198231
198589
|
exports.deleteModelFromDisk = require_file_data_plane.deleteModelFromDisk;
|
|
198232
198590
|
exports.deriveAgentListenPort = deriveAgentListenPort;
|
|
198233
198591
|
exports.describeProviderKindDrift = describeProviderKindDrift;
|
|
@@ -198353,9 +198711,10 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
|
|
|
198353
198711
|
exports.serializeTypedArrays = require_manifest_python_deps.serializeTypedArrays;
|
|
198354
198712
|
exports.setHubConnected = require_manifest_python_deps.setHubConnected;
|
|
198355
198713
|
exports.setNodeEventInterest = require_manifest_python_deps.setNodeEventInterest;
|
|
198356
|
-
exports.shouldReclaim = shouldReclaim;
|
|
198357
|
-
exports.startHeapWatch = startHeapWatch;
|
|
198358
|
-
exports.
|
|
198714
|
+
exports.shouldReclaim = require_manifest_python_deps.shouldReclaim;
|
|
198715
|
+
exports.startHeapWatch = require_manifest_python_deps.startHeapWatch;
|
|
198716
|
+
exports.startRunnerHeapWatch = require_manifest_python_deps.startRunnerHeapWatch;
|
|
198717
|
+
exports.strandedMb = require_manifest_python_deps.strandedMb;
|
|
198359
198718
|
exports.stripCamstackDeps = stripCamstackDeps;
|
|
198360
198719
|
exports.subscribePassthrough = require_manifest_python_deps.subscribePassthrough;
|
|
198361
198720
|
exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
|
|
@@ -237028,7 +237387,7 @@ var require_enums = __commonJS({
|
|
|
237028
237387
|
"../types/dist/enums.js"(exports) {
|
|
237029
237388
|
"use strict";
|
|
237030
237389
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
237031
|
-
var require_event_category =
|
|
237390
|
+
var require_event_category = require_event_category_CRPORAAz();
|
|
237032
237391
|
var EventSourceType = /* @__PURE__ */ (function(EventSourceType2) {
|
|
237033
237392
|
EventSourceType2["Addon"] = "addon";
|
|
237034
237393
|
EventSourceType2["Core"] = "core";
|
|
@@ -237048,8 +237407,8 @@ var require_dist9 = __commonJS({
|
|
|
237048
237407
|
"../types/dist/index.js"(exports) {
|
|
237049
237408
|
"use strict";
|
|
237050
237409
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
237051
|
-
var require_event_category =
|
|
237052
|
-
var require_sleep =
|
|
237410
|
+
var require_event_category = require_event_category_CRPORAAz();
|
|
237411
|
+
var require_sleep = require_sleep_CMRLJj2e();
|
|
237053
237412
|
var require_canonical_hash = require_canonical_hash_DNV8S5ET();
|
|
237054
237413
|
var require_enums2 = require_enums();
|
|
237055
237414
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
@@ -237971,6 +238330,7 @@ var require_dist9 = __commonJS({
|
|
|
237971
238330
|
preBufferSec: 10,
|
|
237972
238331
|
postBufferSec: 30
|
|
237973
238332
|
};
|
|
238333
|
+
var VISIT_MERGE_GAP_MS = DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
|
|
237974
238334
|
var RecordingRetentionSchema = zod.z.object({
|
|
237975
238335
|
maxAgeDays: zod.z.number().min(0).optional(),
|
|
237976
238336
|
maxSizeGb: zod.z.number().min(0).optional()
|
|
@@ -238032,6 +238392,12 @@ var require_dist9 = __commonJS({
|
|
|
238032
238392
|
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
238033
238393
|
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
238034
238394
|
mode: RecordingStorageModeSchema.optional(),
|
|
238395
|
+
/**
|
|
238396
|
+
* Which assigned broker slots to record. Absent / empty = {@link
|
|
238397
|
+
* DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
|
|
238398
|
+
* camera's currently assigned slots — never `mid` unless the operator
|
|
238399
|
+
* picks it, and never a slot the broker has not assigned.
|
|
238400
|
+
*/
|
|
238035
238401
|
profiles: zod.z.array(require_sleep.CamProfileSchema).optional(),
|
|
238036
238402
|
segmentSeconds: zod.z.number().int().positive().optional(),
|
|
238037
238403
|
/**
|
|
@@ -238054,6 +238420,15 @@ var require_dist9 = __commonJS({
|
|
|
238054
238420
|
if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
|
|
238055
238421
|
return "events";
|
|
238056
238422
|
}
|
|
238423
|
+
var DEFAULT_RECORDING_PROFILES = ["high", "low"];
|
|
238424
|
+
function resolveRecordingProfiles(assigned, override) {
|
|
238425
|
+
if (override !== void 0 && override.length > 0) {
|
|
238426
|
+
const selected = assigned.filter((profile) => override.includes(profile));
|
|
238427
|
+
return selected.length > 0 ? selected : [...assigned];
|
|
238428
|
+
}
|
|
238429
|
+
const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
|
|
238430
|
+
return preferred.length > 0 ? preferred : [...assigned];
|
|
238431
|
+
}
|
|
238057
238432
|
var RelocateJobStateSchema = zod.z.enum([
|
|
238058
238433
|
"queued",
|
|
238059
238434
|
"running",
|
|
@@ -238099,7 +238474,11 @@ var require_dist9 = __commonJS({
|
|
|
238099
238474
|
profiles: zod.z.array(zod.z.string()).optional(),
|
|
238100
238475
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
238101
238476
|
* never allowed to starve live writers. */
|
|
238102
|
-
throttleMbps: zod.z.number().min(1).max(1e3).optional()
|
|
238477
|
+
throttleMbps: zod.z.number().min(1).max(1e3).optional(),
|
|
238478
|
+
/** Move only segments whose startMs is >= this. Absent = the whole source
|
|
238479
|
+
* pile. Used when a full drain is too expensive and the operator only
|
|
238480
|
+
* wants the recent window on the new disk. */
|
|
238481
|
+
sinceMs: zod.z.number().int().optional()
|
|
238103
238482
|
});
|
|
238104
238483
|
var StorageMigrationLeaseInputSchema = zod.z.object({ leaseId: zod.z.string().min(1) });
|
|
238105
238484
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: zod.z.string().min(1) });
|
|
@@ -246602,6 +246981,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
246602
246981
|
"node-offline",
|
|
246603
246982
|
"node-inference-unavailable",
|
|
246604
246983
|
"detection-blind",
|
|
246984
|
+
"addon-crash-loop",
|
|
246605
246985
|
"addon-update-available",
|
|
246606
246986
|
"server-update-available",
|
|
246607
246987
|
"alarm-triggered",
|
|
@@ -246609,6 +246989,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
246609
246989
|
"alarm-disarmed",
|
|
246610
246990
|
"alarm-arming",
|
|
246611
246991
|
"alarm-arm-refused",
|
|
246992
|
+
"addon-updated",
|
|
246993
|
+
"server-updated",
|
|
246994
|
+
"export-completed",
|
|
246612
246995
|
"camera-online",
|
|
246613
246996
|
"camera-offline",
|
|
246614
246997
|
"camera-disabled",
|
|
@@ -247438,6 +247821,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247438
247821
|
value: "detection-blind",
|
|
247439
247822
|
label: "Camera detecting nothing"
|
|
247440
247823
|
},
|
|
247824
|
+
{
|
|
247825
|
+
value: "addon-crash-loop",
|
|
247826
|
+
label: "Addon stopped after repeated crashes"
|
|
247827
|
+
},
|
|
247441
247828
|
{
|
|
247442
247829
|
value: "addon-update-available",
|
|
247443
247830
|
label: "Addon update available"
|
|
@@ -247446,6 +247833,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
247446
247833
|
value: "server-update-available",
|
|
247447
247834
|
label: "Server update available"
|
|
247448
247835
|
},
|
|
247836
|
+
{
|
|
247837
|
+
value: "addon-updated",
|
|
247838
|
+
label: "Addons updated"
|
|
247839
|
+
},
|
|
247840
|
+
{
|
|
247841
|
+
value: "server-updated",
|
|
247842
|
+
label: "Server updated"
|
|
247843
|
+
},
|
|
247844
|
+
{
|
|
247845
|
+
value: "export-completed",
|
|
247846
|
+
label: "Export completed"
|
|
247847
|
+
},
|
|
247449
247848
|
{
|
|
247450
247849
|
value: "alarm-arming",
|
|
247451
247850
|
label: "Alarm arming (exit delay)"
|
|
@@ -248462,7 +248861,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248462
248861
|
* `'staging'`. */
|
|
248463
248862
|
markForTrain: zod.z.boolean().optional(),
|
|
248464
248863
|
/** Operator marked this track for diagnostic attention. */
|
|
248465
|
-
debug: zod.z.boolean().optional()
|
|
248864
|
+
debug: zod.z.boolean().optional(),
|
|
248865
|
+
/** Operator favourited this track. Pins it against pruning. */
|
|
248866
|
+
favourited: zod.z.boolean().optional()
|
|
248466
248867
|
};
|
|
248467
248868
|
var TrackRetrainFields = { retrainStatus: RetrainStatusSchema.optional() };
|
|
248468
248869
|
var TrackFlagsPatchSchema = zod.z.object(TrackFlagFields);
|
|
@@ -248470,6 +248871,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248470
248871
|
trackId: zod.z.string(),
|
|
248471
248872
|
markForTrain: zod.z.boolean(),
|
|
248472
248873
|
debug: zod.z.boolean(),
|
|
248874
|
+
favourited: zod.z.boolean(),
|
|
248473
248875
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
248474
248876
|
* a track row) because this shape is only ever produced by the write body,
|
|
248475
248877
|
* which always knows it — and a surface that has just written needs to render
|
|
@@ -248992,6 +249394,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248992
249394
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
248993
249395
|
embeddings: zod.z.number().int()
|
|
248994
249396
|
});
|
|
249397
|
+
var DiskReconcileCountsSchema = zod.z.object({
|
|
249398
|
+
mediaDropped: zod.z.number().int(),
|
|
249399
|
+
tracks: zod.z.number().int(),
|
|
249400
|
+
events: zod.z.number().int()
|
|
249401
|
+
});
|
|
248995
249402
|
var EventStoreDeviceFootprintSchema = zod.z.object({
|
|
248996
249403
|
deviceId: zod.z.number(),
|
|
248997
249404
|
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
@@ -249248,6 +249655,17 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249248
249655
|
auth: "admin"
|
|
249249
249656
|
}),
|
|
249250
249657
|
/**
|
|
249658
|
+
* Disk-wins reconcile for one camera. Drops media index rows whose blobs
|
|
249659
|
+
* are gone, then cascades tracks (including favourited and staging) that
|
|
249660
|
+
* have no remaining files. Enrolled identity/vehicle/scene media is never
|
|
249661
|
+
* probed. Trackless motion/audio events with no remaining file are dropped,
|
|
249662
|
+
* including snapshot-less rows.
|
|
249663
|
+
*/
|
|
249664
|
+
reconcileFromDisk: require_sleep.method(zod.z.object({ deviceId: zod.z.number() }), DiskReconcileCountsSchema, {
|
|
249665
|
+
kind: "mutation",
|
|
249666
|
+
auth: "admin"
|
|
249667
|
+
}),
|
|
249668
|
+
/**
|
|
249251
249669
|
* Delete whole tracks (object events) by id for the given device,
|
|
249252
249670
|
* cascading their media in lockstep. Returns the number of tracks
|
|
249253
249671
|
* actually deleted plus the ids that could not be removed.
|
|
@@ -249266,7 +249684,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249266
249684
|
auth: "admin"
|
|
249267
249685
|
}),
|
|
249268
249686
|
/**
|
|
249269
|
-
* Set the per-track operator flags (`markForTrain`, `debug`) on ONE track.
|
|
249687
|
+
* Set the per-track operator flags (`markForTrain`, `debug`, `favourited`) on ONE track.
|
|
249270
249688
|
* The patch is PARTIAL — an omitted key is left untouched — because the
|
|
249271
249689
|
* three surfaces that write it (admin Events grid, viewer track detail,
|
|
249272
249690
|
* viewer cluster detail) each own one toggle and must not clobber the other.
|
|
@@ -251254,6 +251672,24 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
251254
251672
|
/** Wall-clock ms spent on the stage before it was abandoned. */
|
|
251255
251673
|
elapsedMs: zod.z.number()
|
|
251256
251674
|
});
|
|
251675
|
+
var DiskReconcileJobSchema = zod.z.object({
|
|
251676
|
+
state: zod.z.enum([
|
|
251677
|
+
"idle",
|
|
251678
|
+
"running",
|
|
251679
|
+
"done",
|
|
251680
|
+
"error"
|
|
251681
|
+
]),
|
|
251682
|
+
total: zod.z.number().int().nonnegative(),
|
|
251683
|
+
completed: zod.z.number().int().nonnegative(),
|
|
251684
|
+
currentDeviceId: zod.z.number().int().nullable(),
|
|
251685
|
+
failed: zod.z.array(zod.z.number().int()).readonly(),
|
|
251686
|
+
mediaDropped: zod.z.number().int().nonnegative(),
|
|
251687
|
+
tracks: zod.z.number().int().nonnegative(),
|
|
251688
|
+
events: zod.z.number().int().nonnegative(),
|
|
251689
|
+
startedAtMs: zod.z.number().int().nullable(),
|
|
251690
|
+
finishedAtMs: zod.z.number().int().nullable(),
|
|
251691
|
+
error: zod.z.string().nullable()
|
|
251692
|
+
});
|
|
251257
251693
|
var CameraStatusSchema = zod.z.object({
|
|
251258
251694
|
deviceId: zod.z.number(),
|
|
251259
251695
|
assignment: CameraAssignmentStatusSchema,
|
|
@@ -251778,6 +252214,18 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
251778
252214
|
* rail without issuing N parallel browser round-trips.
|
|
251779
252215
|
*/
|
|
251780
252216
|
getCameraStatuses: require_sleep.method(zod.z.object({ deviceIds: zod.z.array(zod.z.number()).optional() }), zod.z.array(CameraStatusSchema).readonly()),
|
|
252217
|
+
/**
|
|
252218
|
+
* Disk-wins fleet reconcile after a recordings wipe. Starts the walk in
|
|
252219
|
+
* the addon process and returns immediately with the job snapshot — the
|
|
252220
|
+
* work outlives the tRPC/UDS 60s timeout. Poll `getReconcileFromDiskStatus`.
|
|
252221
|
+
* Admin-only. Idempotent while a job is already running.
|
|
252222
|
+
*/
|
|
252223
|
+
reconcileFromDisk: require_sleep.method(zod.z.void(), DiskReconcileJobSchema, {
|
|
252224
|
+
kind: "mutation",
|
|
252225
|
+
auth: "admin"
|
|
252226
|
+
}),
|
|
252227
|
+
/** Snapshot of the in-flight or last disk-wins fleet reconcile. */
|
|
252228
|
+
getReconcileFromDiskStatus: require_sleep.method(zod.z.void(), DiskReconcileJobSchema, { auth: "admin" }),
|
|
251781
252229
|
/** List every template the operator has saved. */
|
|
251782
252230
|
listTemplates: require_sleep.method(zod.z.void(), zod.z.array(PipelineTemplateSchema).readonly()),
|
|
251783
252231
|
/** Create a new named preset from a given CameraPipelineConfig. */
|
|
@@ -252239,7 +252687,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252239
252687
|
"sleeping",
|
|
252240
252688
|
"unreachable",
|
|
252241
252689
|
"waking"
|
|
252242
|
-
]).nullable()
|
|
252690
|
+
]).nullable(),
|
|
252691
|
+
/** A battery camera (whatever its current state). An AWAKE battery
|
|
252692
|
+
* camera is deliberately NOT recaptured on the poll cadence — every
|
|
252693
|
+
* capture is a camera hit that would keep it out of sleep — so its
|
|
252694
|
+
* cached frame legitimately ages past the currency ceiling while
|
|
252695
|
+
* nothing is streaming. A surface must keep painting it (a fresh
|
|
252696
|
+
* frame is captured at each wake), not blank to "unavailable". */
|
|
252697
|
+
battery: zod.z.boolean()
|
|
252243
252698
|
})))
|
|
252244
252699
|
},
|
|
252245
252700
|
status: {
|
|
@@ -252913,6 +253368,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252913
253368
|
stats: require_sleep.method(VectorStatsInputSchema, VectorStatsResultSchema)
|
|
252914
253369
|
}
|
|
252915
253370
|
};
|
|
253371
|
+
var MAX_CLIP_EVENT_IDS = 24;
|
|
252916
253372
|
var ClipSchema = zod.z.object({
|
|
252917
253373
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
252918
253374
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -252929,8 +253385,57 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252929
253385
|
startMs: zod.z.number(),
|
|
252930
253386
|
endMs: zod.z.number()
|
|
252931
253387
|
}),
|
|
252932
|
-
/**
|
|
252933
|
-
thumbnail
|
|
253388
|
+
/**
|
|
253389
|
+
* Lazy thumbnail URL, never inlined.
|
|
253390
|
+
*
|
|
253391
|
+
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
253392
|
+
* continuous event+fragment visit) MUST use the snapshot of the **main
|
|
253393
|
+
* event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
|
|
253394
|
+
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
253395
|
+
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
253396
|
+
* mint their own stills.
|
|
253397
|
+
*
|
|
253398
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
253399
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
253400
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
253401
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
253402
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
253403
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
253404
|
+
*/
|
|
253405
|
+
thumbnail: zod.z.string().optional(),
|
|
253406
|
+
/**
|
|
253407
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
253408
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
253409
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
253410
|
+
*
|
|
253411
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
253412
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
253413
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
253414
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
253415
|
+
* construction, so a naive midpoint lands in dead air.
|
|
253416
|
+
*/
|
|
253417
|
+
stillAtMs: zod.z.number().optional(),
|
|
253418
|
+
/**
|
|
253419
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
253420
|
+
* first within kind (object → motion → audio), capped at
|
|
253421
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
253422
|
+
*
|
|
253423
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
253424
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
253425
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
253426
|
+
*/
|
|
253427
|
+
eventIds: zod.z.array(zod.z.string()).optional(),
|
|
253428
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
253429
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
253430
|
+
* list is never mistaken for a quiet visit. */
|
|
253431
|
+
eventCount: zod.z.number().int().nonnegative().optional(),
|
|
253432
|
+
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
253433
|
+
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
253434
|
+
* bar keeps showing them via `recording.getAvailability`. */
|
|
253435
|
+
holes: zod.z.array(zod.z.object({
|
|
253436
|
+
startMs: zod.z.number(),
|
|
253437
|
+
endMs: zod.z.number()
|
|
253438
|
+
})).optional()
|
|
252934
253439
|
});
|
|
252935
253440
|
var ClipPlaybackSchema = zod.z.object({
|
|
252936
253441
|
/** HLS master URL through the hub data-plane (Range + token in path). */
|
|
@@ -253478,7 +253983,14 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
253478
253983
|
});
|
|
253479
253984
|
var AutoUpdateSettingsSchema = zod.z.object({
|
|
253480
253985
|
channel: ChannelSchema,
|
|
253481
|
-
intervalSeconds: zod.z.number()
|
|
253986
|
+
intervalSeconds: zod.z.number(),
|
|
253987
|
+
/**
|
|
253988
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
253989
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
253990
|
+
* about a publish and installing it are different decisions. Clamped
|
|
253991
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
253992
|
+
*/
|
|
253993
|
+
updateCheckIntervalSeconds: zod.z.number()
|
|
253482
253994
|
});
|
|
253483
253995
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
253484
253996
|
var RestartAddonResultSchema = zod.z.unknown();
|
|
@@ -253729,7 +254241,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
253729
254241
|
getAutoUpdateSettings: require_sleep.method(zod.z.void(), AutoUpdateSettingsSchema, { auth: "admin" }),
|
|
253730
254242
|
setAutoUpdateSettings: require_sleep.method(zod.z.object({
|
|
253731
254243
|
channel: ChannelSchema,
|
|
253732
|
-
intervalSeconds: zod.z.number().min(300).max(86400).optional()
|
|
254244
|
+
intervalSeconds: zod.z.number().min(300).max(86400).optional(),
|
|
254245
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
254246
|
+
updateCheckIntervalSeconds: zod.z.number().min(900).max(604800).optional()
|
|
253733
254247
|
}), zod.z.unknown(), {
|
|
253734
254248
|
kind: "mutation",
|
|
253735
254249
|
auth: "admin"
|
|
@@ -259019,7 +259533,9 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
259019
259533
|
includeAudio: zod.z.boolean(),
|
|
259020
259534
|
maxLifeMs: zod.z.number().int().positive(),
|
|
259021
259535
|
deleteAfterDownload: zod.z.boolean(),
|
|
259022
|
-
title: zod.z.string().max(200).optional()
|
|
259536
|
+
title: zod.z.string().max(200).optional(),
|
|
259537
|
+
/** Notification-output target ids to ping when this export becomes ready. */
|
|
259538
|
+
notifyTargetIds: zod.z.array(zod.z.string().min(1)).max(20).optional()
|
|
259023
259539
|
}).superRefine((v, ctx) => {
|
|
259024
259540
|
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
259025
259541
|
code: zod.z.ZodIssueCode.custom,
|
|
@@ -259069,20 +259585,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
259069
259585
|
name: zod.z.string(),
|
|
259070
259586
|
bytes: zod.z.number().int().nonnegative()
|
|
259071
259587
|
});
|
|
259588
|
+
var CreateExportInputSchema = zod.z.object({
|
|
259589
|
+
deviceId: zod.z.number(),
|
|
259590
|
+
/** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
|
|
259591
|
+
profile: zod.z.string().optional(),
|
|
259592
|
+
profiles: zod.z.array(zod.z.string()).min(1).optional(),
|
|
259593
|
+
fromMs: zod.z.number(),
|
|
259594
|
+
toMs: zod.z.number(),
|
|
259595
|
+
options: ExportOptionsSchema
|
|
259596
|
+
}).superRefine((v, ctx) => {
|
|
259597
|
+
if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
|
|
259598
|
+
code: zod.z.ZodIssueCode.custom,
|
|
259599
|
+
message: "pass profiles[] (min 1) or legacy profile",
|
|
259600
|
+
path: ["profiles"]
|
|
259601
|
+
});
|
|
259602
|
+
});
|
|
259072
259603
|
var recordingExportCapability = {
|
|
259073
259604
|
name: "recording-export",
|
|
259074
259605
|
scope: "system",
|
|
259075
259606
|
mode: "singleton",
|
|
259076
259607
|
methods: {
|
|
259077
|
-
/** Queue a render of `[fromMs,toMs)` for `deviceId`/`
|
|
259078
|
-
*
|
|
259079
|
-
|
|
259080
|
-
|
|
259081
|
-
profile: zod.z.string(),
|
|
259082
|
-
fromMs: zod.z.number(),
|
|
259083
|
-
toMs: zod.z.number(),
|
|
259084
|
-
options: ExportOptionsSchema
|
|
259085
|
-
}), ExportRecordSchema, {
|
|
259608
|
+
/** Queue a render of `[fromMs,toMs)` for `deviceId`/`profiles` (legacy
|
|
259609
|
+
* singular `profile` still accepted). Fails fast when no footage covers
|
|
259610
|
+
* the range. One job per profile; returns the first queued record. */
|
|
259611
|
+
createExport: require_sleep.method(CreateExportInputSchema, ExportRecordSchema, {
|
|
259086
259612
|
kind: "mutation",
|
|
259087
259613
|
auth: "protected"
|
|
259088
259614
|
}),
|
|
@@ -261992,15 +262518,6 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
261992
262518
|
labels: ["probe not implemented"]
|
|
261993
262519
|
};
|
|
261994
262520
|
}
|
|
261995
|
-
/**
|
|
261996
|
-
* Top-level devices restored at once in {@link onRestoreDevices}.
|
|
261997
|
-
*
|
|
261998
|
-
* Four covers the fleets this ships to without turning a boot into a burst a
|
|
261999
|
-
* camera NVR answers with a refusal. A provider whose upstream is a single
|
|
262000
|
-
* session with a serial command channel (a Baichuan hub, an NVR that
|
|
262001
|
-
* serialises ISAPI) should lower it; nothing needs to raise it.
|
|
262002
|
-
*/
|
|
262003
|
-
restoreConcurrency = 4;
|
|
262004
262521
|
async restoreDevices(savedDevices) {
|
|
262005
262522
|
await this.onRestoreDevices(savedDevices);
|
|
262006
262523
|
if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
|
|
@@ -262055,14 +262572,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
262055
262572
|
});
|
|
262056
262573
|
}
|
|
262057
262574
|
};
|
|
262058
|
-
|
|
262059
|
-
await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
|
|
262060
|
-
for (; ; ) {
|
|
262061
|
-
const saved = topLevel[nextTopLevel++];
|
|
262062
|
-
if (saved === void 0) return;
|
|
262063
|
-
await restoreOne(saved);
|
|
262064
|
-
}
|
|
262065
|
-
}));
|
|
262575
|
+
await Promise.all(topLevel.map((saved) => restoreOne(saved)));
|
|
262066
262576
|
const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
|
|
262067
262577
|
for (const saved of childRows) {
|
|
262068
262578
|
const Class = this.deviceClasses[saved.type];
|
|
@@ -267625,6 +268135,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
267625
268135
|
addonId: null,
|
|
267626
268136
|
access: "create"
|
|
267627
268137
|
},
|
|
268138
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
268139
|
+
capName: "pipeline-analytics",
|
|
268140
|
+
capScope: "device",
|
|
268141
|
+
addonId: null,
|
|
268142
|
+
access: "create"
|
|
268143
|
+
},
|
|
267628
268144
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
267629
268145
|
capName: "pipeline-analytics",
|
|
267630
268146
|
capScope: "device",
|
|
@@ -268027,6 +268543,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
268027
268543
|
addonId: null,
|
|
268028
268544
|
access: "view"
|
|
268029
268545
|
},
|
|
268546
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
268547
|
+
capName: "pipeline-orchestrator",
|
|
268548
|
+
capScope: "system",
|
|
268549
|
+
addonId: null,
|
|
268550
|
+
access: "view"
|
|
268551
|
+
},
|
|
268030
268552
|
"pipelineOrchestrator.listAgentSettings": {
|
|
268031
268553
|
capName: "pipeline-orchestrator",
|
|
268032
268554
|
capScope: "system",
|
|
@@ -268051,6 +268573,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
268051
268573
|
addonId: null,
|
|
268052
268574
|
access: "create"
|
|
268053
268575
|
},
|
|
268576
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
268577
|
+
capName: "pipeline-orchestrator",
|
|
268578
|
+
capScope: "system",
|
|
268579
|
+
addonId: null,
|
|
268580
|
+
access: "create"
|
|
268581
|
+
},
|
|
268054
268582
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
268055
268583
|
capName: "pipeline-orchestrator",
|
|
268056
268584
|
capScope: "system",
|
|
@@ -271294,6 +271822,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
271294
271822
|
form: "single",
|
|
271295
271823
|
optional: true
|
|
271296
271824
|
}],
|
|
271825
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
271826
|
+
name: "deviceId",
|
|
271827
|
+
form: "single",
|
|
271828
|
+
optional: false
|
|
271829
|
+
}],
|
|
271297
271830
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
271298
271831
|
name: "deviceId",
|
|
271299
271832
|
form: "single",
|
|
@@ -272912,6 +273445,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
272912
273445
|
getNodeInferenceDevices: (input) => dispatch("pipelineOrchestrator", "getNodeInferenceDevices", "query", input),
|
|
272913
273446
|
resetNodePipelineDefaults: (input) => dispatch("pipelineOrchestrator", "resetNodePipelineDefaults", "mutation", input),
|
|
272914
273447
|
getCameraStatuses: (input) => dispatch("pipelineOrchestrator", "getCameraStatuses", "query", input),
|
|
273448
|
+
reconcileFromDisk: (input) => dispatch("pipelineOrchestrator", "reconcileFromDisk", "mutation", input),
|
|
273449
|
+
getReconcileFromDiskStatus: (input) => dispatch("pipelineOrchestrator", "getReconcileFromDiskStatus", "query", input),
|
|
272915
273450
|
listTemplates: (input) => dispatch("pipelineOrchestrator", "listTemplates", "query", input),
|
|
272916
273451
|
saveTemplate: (input) => dispatch("pipelineOrchestrator", "saveTemplate", "mutation", input),
|
|
272917
273452
|
updateTemplate: (input) => dispatch("pipelineOrchestrator", "updateTemplate", "mutation", input),
|
|
@@ -272960,6 +273495,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
272960
273495
|
startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input)
|
|
272961
273496
|
},
|
|
272962
273497
|
recordingExport: {
|
|
273498
|
+
createExport: (input) => dispatch("recordingExport", "createExport", "mutation", input),
|
|
272963
273499
|
getExport: (input) => dispatch("recordingExport", "getExport", "query", input),
|
|
272964
273500
|
cancelExport: (input) => dispatch("recordingExport", "cancelExport", "mutation", input),
|
|
272965
273501
|
deleteExport: (input) => dispatch("recordingExport", "deleteExport", "mutation", input),
|
|
@@ -273528,6 +274064,27 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
273528
274064
|
}
|
|
273529
274065
|
return schedule.invert === true ? !inside : inside;
|
|
273530
274066
|
}
|
|
274067
|
+
var NC_SYSTEM_EVENT_FILTER_KEYS = [
|
|
274068
|
+
"deviceIds",
|
|
274069
|
+
"deviceTypes",
|
|
274070
|
+
"nodeIds",
|
|
274071
|
+
"packageNames"
|
|
274072
|
+
];
|
|
274073
|
+
function systemEventFilterApplies(kind, filter) {
|
|
274074
|
+
switch (filter) {
|
|
274075
|
+
case "deviceIds":
|
|
274076
|
+
return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind === "alarm-triggered" || kind === "export-completed";
|
|
274077
|
+
case "deviceTypes":
|
|
274078
|
+
return kind.startsWith("device-") || kind === "detection-blind";
|
|
274079
|
+
case "nodeIds":
|
|
274080
|
+
return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "server-updated";
|
|
274081
|
+
case "packageNames":
|
|
274082
|
+
return kind.endsWith("update-available") || kind === "addon-updated" || kind === "server-updated";
|
|
274083
|
+
}
|
|
274084
|
+
}
|
|
274085
|
+
function systemEventFilterAppliesToAnyKind(kinds, filter) {
|
|
274086
|
+
return kinds.some((kind) => systemEventFilterApplies(kind, filter));
|
|
274087
|
+
}
|
|
273531
274088
|
var TimelapseTemplateSchema = zod.z.object({
|
|
273532
274089
|
title: zod.z.string().max(500).optional(),
|
|
273533
274090
|
body: zod.z.string().max(2e3).optional()
|
|
@@ -274578,6 +275135,278 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
274578
275135
|
return rawUrl;
|
|
274579
275136
|
}
|
|
274580
275137
|
}
|
|
275138
|
+
var MB = 1024 * 1024;
|
|
275139
|
+
var DEFAULT_POOL_MEMORY_POLICY = {
|
|
275140
|
+
sampleIntervalMs: 6e4,
|
|
275141
|
+
baselineSettleSamples: 5,
|
|
275142
|
+
baselineSampleCount: 3,
|
|
275143
|
+
restartMultiple: 4,
|
|
275144
|
+
floorBytes: 1024 * MB,
|
|
275145
|
+
ceilingBytes: 3072 * MB,
|
|
275146
|
+
cooldownMs: 30 * 6e4,
|
|
275147
|
+
maxRestartsPerWindow: 6,
|
|
275148
|
+
restartWindowMs: 1440 * 6e4
|
|
275149
|
+
};
|
|
275150
|
+
function resolvePoolMemoryPolicy(env) {
|
|
275151
|
+
const num = (key, fallback, min) => {
|
|
275152
|
+
const raw = env[key];
|
|
275153
|
+
if (raw === void 0) return fallback;
|
|
275154
|
+
const parsed = Number(raw);
|
|
275155
|
+
return Number.isFinite(parsed) && parsed >= min ? parsed : fallback;
|
|
275156
|
+
};
|
|
275157
|
+
const d = DEFAULT_POOL_MEMORY_POLICY;
|
|
275158
|
+
return {
|
|
275159
|
+
sampleIntervalMs: num("CAMSTACK_POOL_MEM_INTERVAL_MS", d.sampleIntervalMs, 5e3),
|
|
275160
|
+
baselineSettleSamples: d.baselineSettleSamples,
|
|
275161
|
+
baselineSampleCount: d.baselineSampleCount,
|
|
275162
|
+
restartMultiple: num("CAMSTACK_POOL_MEM_MULTIPLE", d.restartMultiple, 1.5),
|
|
275163
|
+
floorBytes: num("CAMSTACK_POOL_MEM_FLOOR_MB", d.floorBytes / MB, 128) * MB,
|
|
275164
|
+
ceilingBytes: num("CAMSTACK_POOL_MEM_CEILING_MB", d.ceilingBytes / MB, 256) * MB,
|
|
275165
|
+
cooldownMs: num("CAMSTACK_POOL_MEM_COOLDOWN_MS", d.cooldownMs, 6e4),
|
|
275166
|
+
maxRestartsPerWindow: num("CAMSTACK_POOL_MEM_MAX_RESTARTS", d.maxRestartsPerWindow, 1),
|
|
275167
|
+
restartWindowMs: num("CAMSTACK_POOL_MEM_RESTART_WINDOW_MS", d.restartWindowMs, 6e4)
|
|
275168
|
+
};
|
|
275169
|
+
}
|
|
275170
|
+
function parseProcStatus(text) {
|
|
275171
|
+
const kb = (label) => {
|
|
275172
|
+
const match = text.match(new RegExp(`^${label}:\\s+(\\d+)\\s*kB`, "m"));
|
|
275173
|
+
return match ? Number(match[1]) * 1024 : null;
|
|
275174
|
+
};
|
|
275175
|
+
const rssBytes = kb("VmRSS");
|
|
275176
|
+
if (rssBytes === null) return null;
|
|
275177
|
+
const threadsMatch = text.match(/^Threads:\s+(\d+)/m);
|
|
275178
|
+
return {
|
|
275179
|
+
rssBytes,
|
|
275180
|
+
vmBytes: kb("VmSize") ?? 0,
|
|
275181
|
+
hwmBytes: kb("VmHWM") ?? 0,
|
|
275182
|
+
swapBytes: kb("VmSwap") ?? 0,
|
|
275183
|
+
threads: threadsMatch ? Number(threadsMatch[1]) : 0
|
|
275184
|
+
};
|
|
275185
|
+
}
|
|
275186
|
+
function initialPoolMemoryState() {
|
|
275187
|
+
return {
|
|
275188
|
+
settleSeen: 0,
|
|
275189
|
+
baselineWindow: [],
|
|
275190
|
+
baselineBytes: null,
|
|
275191
|
+
restartsAt: [],
|
|
275192
|
+
lastRestartAt: null
|
|
275193
|
+
};
|
|
275194
|
+
}
|
|
275195
|
+
function median(values) {
|
|
275196
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
275197
|
+
return sorted[Math.floor(sorted.length / 2)];
|
|
275198
|
+
}
|
|
275199
|
+
function advanceBaseline(state, rssBytes, policy) {
|
|
275200
|
+
if (state.baselineBytes !== null) return state;
|
|
275201
|
+
if (state.settleSeen < policy.baselineSettleSamples) return {
|
|
275202
|
+
...state,
|
|
275203
|
+
settleSeen: state.settleSeen + 1
|
|
275204
|
+
};
|
|
275205
|
+
const window2 = [...state.baselineWindow, rssBytes];
|
|
275206
|
+
if (window2.length < policy.baselineSampleCount) return {
|
|
275207
|
+
...state,
|
|
275208
|
+
baselineWindow: window2
|
|
275209
|
+
};
|
|
275210
|
+
return {
|
|
275211
|
+
...state,
|
|
275212
|
+
baselineWindow: window2,
|
|
275213
|
+
baselineBytes: median(window2)
|
|
275214
|
+
};
|
|
275215
|
+
}
|
|
275216
|
+
function poolMemoryThreshold(baselineBytes, policy) {
|
|
275217
|
+
if (baselineBytes === null) return policy.ceilingBytes;
|
|
275218
|
+
return Math.min(policy.ceilingBytes, Math.max(policy.floorBytes, policy.restartMultiple * baselineBytes));
|
|
275219
|
+
}
|
|
275220
|
+
function pruneRestarts(restartsAt, nowMs, policy) {
|
|
275221
|
+
return restartsAt.filter((t) => nowMs - t < policy.restartWindowMs);
|
|
275222
|
+
}
|
|
275223
|
+
function evaluatePoolMemory(state, rssBytes, nowMs, policy) {
|
|
275224
|
+
const next = advanceBaseline(state, rssBytes, policy);
|
|
275225
|
+
const thresholdBytes = poolMemoryThreshold(next.baselineBytes, policy);
|
|
275226
|
+
if (rssBytes <= thresholdBytes) return {
|
|
275227
|
+
state: next,
|
|
275228
|
+
action: next.baselineBytes === null ? "baseline-pending" : "ok",
|
|
275229
|
+
baselineBytes: next.baselineBytes,
|
|
275230
|
+
thresholdBytes
|
|
275231
|
+
};
|
|
275232
|
+
const inWindow = pruneRestarts(next.restartsAt, nowMs, policy);
|
|
275233
|
+
const pruned = {
|
|
275234
|
+
...next,
|
|
275235
|
+
restartsAt: inWindow
|
|
275236
|
+
};
|
|
275237
|
+
if (inWindow.length >= policy.maxRestartsPerWindow) return {
|
|
275238
|
+
state: pruned,
|
|
275239
|
+
action: "exhausted",
|
|
275240
|
+
baselineBytes: next.baselineBytes,
|
|
275241
|
+
thresholdBytes
|
|
275242
|
+
};
|
|
275243
|
+
if (pruned.lastRestartAt !== null && nowMs - pruned.lastRestartAt < policy.cooldownMs) return {
|
|
275244
|
+
state: pruned,
|
|
275245
|
+
action: "cooldown",
|
|
275246
|
+
baselineBytes: next.baselineBytes,
|
|
275247
|
+
thresholdBytes
|
|
275248
|
+
};
|
|
275249
|
+
return {
|
|
275250
|
+
state: pruned,
|
|
275251
|
+
action: "restart",
|
|
275252
|
+
baselineBytes: next.baselineBytes,
|
|
275253
|
+
thresholdBytes
|
|
275254
|
+
};
|
|
275255
|
+
}
|
|
275256
|
+
function commitWatchdogRestart(state, nowMs) {
|
|
275257
|
+
return {
|
|
275258
|
+
...initialPoolMemoryState(),
|
|
275259
|
+
restartsAt: [...state.restartsAt, nowMs],
|
|
275260
|
+
lastRestartAt: nowMs
|
|
275261
|
+
};
|
|
275262
|
+
}
|
|
275263
|
+
function resetPoolBaseline(state) {
|
|
275264
|
+
return {
|
|
275265
|
+
...initialPoolMemoryState(),
|
|
275266
|
+
restartsAt: state.restartsAt,
|
|
275267
|
+
lastRestartAt: state.lastRestartAt
|
|
275268
|
+
};
|
|
275269
|
+
}
|
|
275270
|
+
function pickRestartCandidate(candidates) {
|
|
275271
|
+
if (candidates.length === 0) return null;
|
|
275272
|
+
let worst = candidates[0];
|
|
275273
|
+
for (const c of candidates) if (c.rssBytes / c.thresholdBytes > worst.rssBytes / worst.thresholdBytes) worst = c;
|
|
275274
|
+
return worst.key;
|
|
275275
|
+
}
|
|
275276
|
+
var PoolMemoryWatchdog = class {
|
|
275277
|
+
pools = /* @__PURE__ */ new Map();
|
|
275278
|
+
timer = null;
|
|
275279
|
+
sweeping = false;
|
|
275280
|
+
stopped = false;
|
|
275281
|
+
opts;
|
|
275282
|
+
now;
|
|
275283
|
+
setTimer;
|
|
275284
|
+
clearTimer;
|
|
275285
|
+
constructor(opts) {
|
|
275286
|
+
this.opts = opts;
|
|
275287
|
+
this.now = opts.now ?? (() => Date.now());
|
|
275288
|
+
this.setTimer = opts.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
275289
|
+
this.clearTimer = opts.clearTimer ?? ((t) => clearTimeout(t));
|
|
275290
|
+
}
|
|
275291
|
+
start() {
|
|
275292
|
+
if (this.timer || this.stopped) return;
|
|
275293
|
+
this.arm();
|
|
275294
|
+
}
|
|
275295
|
+
stop() {
|
|
275296
|
+
this.stopped = true;
|
|
275297
|
+
if (this.timer) {
|
|
275298
|
+
this.clearTimer(this.timer);
|
|
275299
|
+
this.timer = null;
|
|
275300
|
+
}
|
|
275301
|
+
}
|
|
275302
|
+
arm() {
|
|
275303
|
+
const timer = this.setTimer(() => {
|
|
275304
|
+
this.sweep().finally(() => {
|
|
275305
|
+
if (!this.stopped) this.arm();
|
|
275306
|
+
});
|
|
275307
|
+
}, this.opts.policy.sampleIntervalMs);
|
|
275308
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
275309
|
+
this.timer = timer;
|
|
275310
|
+
}
|
|
275311
|
+
/** One sweep: sample → log every pool → restart at most one. Public so the
|
|
275312
|
+
* loop is testable without fake global timers. */
|
|
275313
|
+
async sweep() {
|
|
275314
|
+
if (this.sweeping) return;
|
|
275315
|
+
this.sweeping = true;
|
|
275316
|
+
try {
|
|
275317
|
+
await this.doSweep();
|
|
275318
|
+
} catch (err) {
|
|
275319
|
+
this.opts.log.warn("pool memory sweep failed", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
275320
|
+
} finally {
|
|
275321
|
+
this.sweeping = false;
|
|
275322
|
+
}
|
|
275323
|
+
}
|
|
275324
|
+
async doSweep() {
|
|
275325
|
+
const nowMs = this.now();
|
|
275326
|
+
const samples = await this.opts.sample();
|
|
275327
|
+
const candidates = [];
|
|
275328
|
+
const verdictByKey = /* @__PURE__ */ new Map();
|
|
275329
|
+
for (const t of samples) {
|
|
275330
|
+
const tracked2 = this.pools.get(t.key);
|
|
275331
|
+
let state = tracked2?.state ?? initialPoolMemoryState();
|
|
275332
|
+
if (tracked2 && tracked2.pids.length > 0 && !samePids(tracked2.pids, t.pids)) {
|
|
275333
|
+
this.opts.log.warn("pool process changed outside the watchdog \u2014 re-baselining", { meta: {
|
|
275334
|
+
poolKey: t.key,
|
|
275335
|
+
previousPids: tracked2.pids,
|
|
275336
|
+
pids: t.pids
|
|
275337
|
+
} });
|
|
275338
|
+
state = resetPoolBaseline(state);
|
|
275339
|
+
}
|
|
275340
|
+
const verdict2 = evaluatePoolMemory(state, t.rssBytes, nowMs, this.opts.policy);
|
|
275341
|
+
this.pools.set(t.key, {
|
|
275342
|
+
state: verdict2.state,
|
|
275343
|
+
pids: t.pids
|
|
275344
|
+
});
|
|
275345
|
+
verdictByKey.set(t.key, verdict2);
|
|
275346
|
+
this.opts.log.info("pool memory", { meta: {
|
|
275347
|
+
poolKey: t.key,
|
|
275348
|
+
pids: t.pids,
|
|
275349
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
275350
|
+
baselineMb: verdict2.baselineBytes === null ? null : Math.round(verdict2.baselineBytes / MB),
|
|
275351
|
+
thresholdMb: Math.round(verdict2.thresholdBytes / MB),
|
|
275352
|
+
action: verdict2.action,
|
|
275353
|
+
...t.meta
|
|
275354
|
+
} });
|
|
275355
|
+
if (verdict2.action === "restart") candidates.push({
|
|
275356
|
+
key: t.key,
|
|
275357
|
+
rssBytes: t.rssBytes,
|
|
275358
|
+
thresholdBytes: verdict2.thresholdBytes
|
|
275359
|
+
});
|
|
275360
|
+
else if (verdict2.action === "cooldown") this.opts.log.warn("pool over memory threshold but inside restart cooldown", { meta: {
|
|
275361
|
+
poolKey: t.key,
|
|
275362
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
275363
|
+
thresholdMb: Math.round(verdict2.thresholdBytes / MB),
|
|
275364
|
+
cooldownMs: this.opts.policy.cooldownMs
|
|
275365
|
+
} });
|
|
275366
|
+
else if (verdict2.action === "exhausted") this.opts.log.error("pool memory watchdog gave up \u2014 restart budget exhausted, pool leaks faster than restarts can pay for; needs a heap profile (py-spy / tracemalloc)", { meta: {
|
|
275367
|
+
poolKey: t.key,
|
|
275368
|
+
rssMb: Math.round(t.rssBytes / MB),
|
|
275369
|
+
thresholdMb: Math.round(verdict2.thresholdBytes / MB),
|
|
275370
|
+
maxRestartsPerWindow: this.opts.policy.maxRestartsPerWindow,
|
|
275371
|
+
restartWindowMs: this.opts.policy.restartWindowMs
|
|
275372
|
+
} });
|
|
275373
|
+
}
|
|
275374
|
+
for (const key of [...this.pools.keys()]) if (!samples.some((t) => t.key === key)) this.pools.delete(key);
|
|
275375
|
+
const pickedKey = pickRestartCandidate(candidates);
|
|
275376
|
+
if (pickedKey === null) return;
|
|
275377
|
+
const picked = candidates.find((c) => c.key === pickedKey);
|
|
275378
|
+
const verdict = verdictByKey.get(pickedKey);
|
|
275379
|
+
const tracked = this.pools.get(pickedKey);
|
|
275380
|
+
const restartsInWindow = tracked.state.restartsAt.length + 1;
|
|
275381
|
+
this.opts.log.warn("pool memory watchdog restarting pool \u2014 RSS over threshold", { meta: {
|
|
275382
|
+
poolKey: pickedKey,
|
|
275383
|
+
pids: tracked.pids,
|
|
275384
|
+
rssMb: Math.round(picked.rssBytes / MB),
|
|
275385
|
+
thresholdMb: Math.round(picked.thresholdBytes / MB),
|
|
275386
|
+
baselineMb: verdict.baselineBytes === null ? null : Math.round(verdict.baselineBytes / MB),
|
|
275387
|
+
restartsInWindow,
|
|
275388
|
+
deferredCandidates: candidates.filter((c) => c.key !== pickedKey).map((c) => c.key)
|
|
275389
|
+
} });
|
|
275390
|
+
try {
|
|
275391
|
+
await this.opts.restart(pickedKey);
|
|
275392
|
+
this.pools.set(pickedKey, {
|
|
275393
|
+
state: commitWatchdogRestart(tracked.state, this.now()),
|
|
275394
|
+
pids: []
|
|
275395
|
+
});
|
|
275396
|
+
} catch (err) {
|
|
275397
|
+
this.opts.log.error("pool memory watchdog restart failed", { meta: {
|
|
275398
|
+
poolKey: pickedKey,
|
|
275399
|
+
error: err instanceof Error ? err.message : String(err)
|
|
275400
|
+
} });
|
|
275401
|
+
}
|
|
275402
|
+
}
|
|
275403
|
+
};
|
|
275404
|
+
function samePids(a, b) {
|
|
275405
|
+
if (a.length !== b.length) return false;
|
|
275406
|
+
const sortedA = [...a].sort((x, y) => x - y);
|
|
275407
|
+
const sortedB = [...b].sort((x, y) => x - y);
|
|
275408
|
+
return sortedA.every((v, i) => v === sortedB[i]);
|
|
275409
|
+
}
|
|
274581
275410
|
function rectsToCells(rects, gridWidth, gridHeight) {
|
|
274582
275411
|
const total = gridWidth * gridHeight;
|
|
274583
275412
|
if (total <= 0 || rects.length === 0) return Array.from({ length: Math.max(0, total) }).fill(false);
|
|
@@ -275252,6 +276081,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275252
276081
|
exports.DEFAULT_EVENT_COLOR = DEFAULT_EVENT_COLOR;
|
|
275253
276082
|
exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
|
|
275254
276083
|
exports.DEFAULT_NATIVE_LEASE_SETTINGS = DEFAULT_NATIVE_LEASE_SETTINGS;
|
|
276084
|
+
exports.DEFAULT_POOL_MEMORY_POLICY = DEFAULT_POOL_MEMORY_POLICY;
|
|
276085
|
+
exports.DEFAULT_RECORDING_PROFILES = DEFAULT_RECORDING_PROFILES;
|
|
275255
276086
|
exports.DEFAULT_RETENTION = DEFAULT_RETENTION;
|
|
275256
276087
|
exports.DEFAULT_RUNTIME_STATE_DURABILITY = require_sleep.DEFAULT_RUNTIME_STATE_DURABILITY;
|
|
275257
276088
|
exports.DEFAULT_SCRUB_THUMBNAIL_PRESET = DEFAULT_SCRUB_THUMBNAIL_PRESET;
|
|
@@ -275302,6 +276133,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275302
276133
|
exports.DiscoveredChildStatusSchema = DiscoveredChildStatusSchema;
|
|
275303
276134
|
exports.DiscoveredDeviceSchema = DiscoveredDeviceSchema;
|
|
275304
276135
|
exports.DiscoveredTargetSchema = DiscoveredTargetSchema;
|
|
276136
|
+
exports.DiskReconcileJobSchema = DiskReconcileJobSchema;
|
|
275305
276137
|
exports.DisposerChain = require_sleep.DisposerChain;
|
|
275306
276138
|
exports.DoorbellPressEventSchema = DoorbellPressEventSchema;
|
|
275307
276139
|
exports.DoorbellStatusSchema = DoorbellStatusSchema;
|
|
@@ -275441,6 +276273,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275441
276273
|
exports.LoginMethodContributionSchema = LoginMethodContributionSchema;
|
|
275442
276274
|
exports.LoginStageEnum = LoginStageEnum;
|
|
275443
276275
|
exports.MACRO_LABELS = MACRO_LABELS;
|
|
276276
|
+
exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
|
|
275444
276277
|
exports.MAX_CONDITION_DEPTH = MAX_CONDITION_DEPTH;
|
|
275445
276278
|
exports.MAX_CONDITION_LEAVES = MAX_CONDITION_LEAVES;
|
|
275446
276279
|
exports.MAX_EXPRESSION_AST_NODES = MAX_EXPRESSION_AST_NODES;
|
|
@@ -275532,6 +276365,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275532
276365
|
exports.NC_HISTORY_LIMIT_MAX = NC_HISTORY_LIMIT_MAX;
|
|
275533
276366
|
exports.NC_MAX_PER_TRACK_IMMEDIATE = NC_MAX_PER_TRACK_IMMEDIATE;
|
|
275534
276367
|
exports.NC_SNOOZE_MAX_MINUTES = NC_SNOOZE_MAX_MINUTES;
|
|
276368
|
+
exports.NC_SYSTEM_EVENT_FILTER_KEYS = NC_SYSTEM_EVENT_FILTER_KEYS;
|
|
275535
276369
|
exports.NC_TAXONOMY = NC_TAXONOMY;
|
|
275536
276370
|
exports.NativeCropBboxSchema = NativeCropBboxSchema;
|
|
275537
276371
|
exports.NativeCropRefSchema = NativeCropRefSchema;
|
|
@@ -275645,6 +276479,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275645
276479
|
exports.PipelineValidationResultSchema = PipelineValidationResultSchema;
|
|
275646
276480
|
exports.PlaceholderReasonSchema = PlaceholderReasonSchema;
|
|
275647
276481
|
exports.PolygonPointSchema = PolygonPointSchema;
|
|
276482
|
+
exports.PoolMemoryWatchdog = PoolMemoryWatchdog;
|
|
275648
276483
|
exports.PowerMeterStatusSchema = PowerMeterStatusSchema;
|
|
275649
276484
|
exports.PresenceStatusSchema = PresenceStatusSchema;
|
|
275650
276485
|
exports.PressureSensorStatusSchema = PressureSensorStatusSchema;
|
|
@@ -275899,6 +276734,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
275899
276734
|
exports.UpdateUserInputSchema = UpdateUserInputSchema;
|
|
275900
276735
|
exports.UserRecordSchema = UserRecordSchema;
|
|
275901
276736
|
exports.UserSummarySchema = UserSummarySchema;
|
|
276737
|
+
exports.VISIT_MERGE_GAP_MS = VISIT_MERGE_GAP_MS;
|
|
275902
276738
|
exports.VacuumControlStatusSchema = VacuumControlStatusSchema;
|
|
275903
276739
|
exports.VacuumStateSchema = VacuumStateSchema;
|
|
275904
276740
|
exports.ValveStateSchema = ValveStateSchema;
|
|
@@ -276011,6 +276847,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276011
276847
|
exports.collectHydratedFieldValues = require_sleep.collectHydratedFieldValues;
|
|
276012
276848
|
exports.colorCapability = colorCapability;
|
|
276013
276849
|
exports.colorForKind = colorForKind;
|
|
276850
|
+
exports.commitWatchdogRestart = commitWatchdogRestart;
|
|
276014
276851
|
exports.compileExpression = compileExpression;
|
|
276015
276852
|
exports.compileExpressionSafe = compileExpressionSafe;
|
|
276016
276853
|
exports.composeSwitchedOff = composeSwitchedOff;
|
|
@@ -276080,6 +276917,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276080
276917
|
exports.errMsg = require_err_msg.errMsg;
|
|
276081
276918
|
exports.evaluateAst = evaluateAst;
|
|
276082
276919
|
exports.evaluateExpressionSource = evaluateExpressionSource;
|
|
276920
|
+
exports.evaluatePoolMemory = evaluatePoolMemory;
|
|
276083
276921
|
exports.evaluateZoneRules = evaluateZoneRules;
|
|
276084
276922
|
exports.event = require_sleep.event;
|
|
276085
276923
|
exports.eventEmitterCapability = eventEmitterCapability;
|
|
@@ -276109,6 +276947,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276109
276947
|
exports.hydrateSchema = require_sleep.hydrateSchema;
|
|
276110
276948
|
exports.imageCapability = imageCapability;
|
|
276111
276949
|
exports.imageSettingsCapability = imageSettingsCapability;
|
|
276950
|
+
exports.initialPoolMemoryState = initialPoolMemoryState;
|
|
276112
276951
|
exports.integrationsCapability = integrationsCapability;
|
|
276113
276952
|
exports.intercomCapability = intercomCapability;
|
|
276114
276953
|
exports.invocationFromEncodeProfile = require_canonical_hash.invocationFromEncodeProfile;
|
|
@@ -276191,6 +277030,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276191
277030
|
exports.parseJsonArray = require_sleep.parseJsonArray;
|
|
276192
277031
|
exports.parseJsonObject = require_sleep.parseJsonObject;
|
|
276193
277032
|
exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
|
|
277033
|
+
exports.parseProcStatus = parseProcStatus;
|
|
276194
277034
|
exports.parseProfileBrokerId = require_sleep.parseProfileBrokerId;
|
|
276195
277035
|
exports.parseStreamParamsFormPatch = parseStreamParamsFormPatch;
|
|
276196
277036
|
exports.patchAudio = patchAudio;
|
|
@@ -276199,6 +277039,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276199
277039
|
exports.pickDetailCropConvention = pickDetailCropConvention;
|
|
276200
277040
|
exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
|
|
276201
277041
|
exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
|
|
277042
|
+
exports.pickRestartCandidate = pickRestartCandidate;
|
|
276202
277043
|
exports.pickVideoEncoder = require_canonical_hash.pickVideoEncoder;
|
|
276203
277044
|
exports.pickerForCondition = pickerForCondition;
|
|
276204
277045
|
exports.pipelineAnalyticsCapability = pipelineAnalyticsCapability;
|
|
@@ -276207,6 +277048,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276207
277048
|
exports.pipelineRunnerCapability = pipelineRunnerCapability;
|
|
276208
277049
|
exports.plateGalleryCapability = plateGalleryCapability;
|
|
276209
277050
|
exports.platformProbeCapability = platformProbeCapability;
|
|
277051
|
+
exports.poolMemoryThreshold = poolMemoryThreshold;
|
|
276210
277052
|
exports.powerMeterCapability = powerMeterCapability;
|
|
276211
277053
|
exports.prepareNotification = prepareNotification;
|
|
276212
277054
|
exports.presenceCapability = presenceCapability;
|
|
@@ -276228,6 +277070,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276228
277070
|
exports.recordingExportCapability = recordingExportCapability;
|
|
276229
277071
|
exports.rectsToCells = rectsToCells;
|
|
276230
277072
|
exports.requiresPython = requiresPython;
|
|
277073
|
+
exports.resetPoolBaseline = resetPoolBaseline;
|
|
276231
277074
|
exports.resolveAddonExecution = resolveAddonExecution;
|
|
276232
277075
|
exports.resolveAddonGroup = resolveAddonGroup;
|
|
276233
277076
|
exports.resolveAddonPlacement = resolveAddonPlacement;
|
|
@@ -276241,6 +277084,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276241
277084
|
exports.resolveHydratedFieldValue = require_sleep.resolveHydratedFieldValue;
|
|
276242
277085
|
exports.resolveModelFormat = resolveModelFormat;
|
|
276243
277086
|
exports.resolveMutate = resolveMutate;
|
|
277087
|
+
exports.resolvePoolMemoryPolicy = resolvePoolMemoryPolicy;
|
|
277088
|
+
exports.resolveRecordingProfiles = resolveRecordingProfiles;
|
|
276244
277089
|
exports.resolveRunnerId = resolveRunnerId;
|
|
276245
277090
|
exports.resolveScrubThumbnailGeometry = resolveScrubThumbnailGeometry;
|
|
276246
277091
|
exports.resolveVariantModelId = resolveVariantModelId;
|
|
@@ -276285,6 +277130,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
276285
277130
|
exports.switchedOffIds = switchedOffIds;
|
|
276286
277131
|
exports.synthesizeSourceInfo = synthesizeSourceInfo;
|
|
276287
277132
|
exports.systemCapability = systemCapability;
|
|
277133
|
+
exports.systemEventFilterApplies = systemEventFilterApplies;
|
|
277134
|
+
exports.systemEventFilterAppliesToAnyKind = systemEventFilterAppliesToAnyKind;
|
|
276288
277135
|
exports.tamperCapability = tamperCapability;
|
|
276289
277136
|
exports.taskLogEntrySchema = taskLogEntrySchema;
|
|
276290
277137
|
exports.taskPhaseSchema = taskPhaseSchema;
|
|
@@ -276440,6 +277287,314 @@ var require_agent_config = __commonJS({
|
|
|
276440
277287
|
}
|
|
276441
277288
|
});
|
|
276442
277289
|
|
|
277290
|
+
// ../../server/backend/dist/core/server-update/system-ensure-prebuilds.js
|
|
277291
|
+
var require_system_ensure_prebuilds = __commonJS({
|
|
277292
|
+
"../../server/backend/dist/core/server-update/system-ensure-prebuilds.js"(exports) {
|
|
277293
|
+
"use strict";
|
|
277294
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277295
|
+
exports.buildSystemEnsureNativePrebuilds = buildSystemEnsureNativePrebuilds;
|
|
277296
|
+
var system_1 = require_dist3();
|
|
277297
|
+
function buildSystemEnsureNativePrebuilds(logger) {
|
|
277298
|
+
return async (closureDir) => {
|
|
277299
|
+
await (0, system_1.ensureNativePrebuilds)(closureDir, { logger });
|
|
277300
|
+
};
|
|
277301
|
+
}
|
|
277302
|
+
}
|
|
277303
|
+
});
|
|
277304
|
+
|
|
277305
|
+
// ../../server/backend/dist/core/server-update/system-exec-npm.js
|
|
277306
|
+
var require_system_exec_npm = __commonJS({
|
|
277307
|
+
"../../server/backend/dist/core/server-update/system-exec-npm.js"(exports) {
|
|
277308
|
+
"use strict";
|
|
277309
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277310
|
+
exports.buildSystemExecNpm = buildSystemExecNpm;
|
|
277311
|
+
var system_1 = require_dist3();
|
|
277312
|
+
function buildSystemExecNpm(options, runNpmFn = system_1.runNpm) {
|
|
277313
|
+
return async (args, opts) => {
|
|
277314
|
+
const { stdout } = await runNpmFn(args, {
|
|
277315
|
+
cacheDir: options.cacheDir,
|
|
277316
|
+
registry: options.registry,
|
|
277317
|
+
logger: options.logger,
|
|
277318
|
+
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {},
|
|
277319
|
+
timeout: opts.timeoutMs
|
|
277320
|
+
});
|
|
277321
|
+
return { stdout };
|
|
277322
|
+
};
|
|
277323
|
+
}
|
|
277324
|
+
}
|
|
277325
|
+
});
|
|
277326
|
+
|
|
277327
|
+
// ../../server/backend/dist/core/update-availability-emitter.js
|
|
277328
|
+
var require_update_availability_emitter = __commonJS({
|
|
277329
|
+
"../../server/backend/dist/core/update-availability-emitter.js"(exports) {
|
|
277330
|
+
"use strict";
|
|
277331
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277332
|
+
exports.UpdateAvailabilityEmitter = void 0;
|
|
277333
|
+
var types_1 = require_dist9();
|
|
277334
|
+
var UpdateAvailabilityEmitter = class {
|
|
277335
|
+
eventBus;
|
|
277336
|
+
source;
|
|
277337
|
+
store;
|
|
277338
|
+
latestByKey = /* @__PURE__ */ new Map();
|
|
277339
|
+
held = /* @__PURE__ */ new Map();
|
|
277340
|
+
/** Set when in-memory state diverged from what the store last saw. */
|
|
277341
|
+
dirty = false;
|
|
277342
|
+
constructor(eventBus, source, store) {
|
|
277343
|
+
this.eventBus = eventBus;
|
|
277344
|
+
this.source = source;
|
|
277345
|
+
this.store = store;
|
|
277346
|
+
const persisted = store?.load() ?? null;
|
|
277347
|
+
if (persisted === null)
|
|
277348
|
+
return;
|
|
277349
|
+
for (const [key, version] of Object.entries(persisted.latestByKey)) {
|
|
277350
|
+
this.latestByKey.set(key, version);
|
|
277351
|
+
}
|
|
277352
|
+
for (const [key, candidate] of Object.entries(persisted.held)) {
|
|
277353
|
+
this.held.set(key, candidate);
|
|
277354
|
+
}
|
|
277355
|
+
}
|
|
277356
|
+
publishSnapshot(target, candidates, nodeId) {
|
|
277357
|
+
const scope = nodeId ?? "hub";
|
|
277358
|
+
const present = /* @__PURE__ */ new Set();
|
|
277359
|
+
let latestChanged = false;
|
|
277360
|
+
for (const candidate of candidates) {
|
|
277361
|
+
if (candidate.target !== target)
|
|
277362
|
+
continue;
|
|
277363
|
+
const stamped = stampNode(candidate, nodeId);
|
|
277364
|
+
const key = this.key(stamped);
|
|
277365
|
+
present.add(key);
|
|
277366
|
+
if (this.note(stamped))
|
|
277367
|
+
latestChanged = true;
|
|
277368
|
+
}
|
|
277369
|
+
for (const key of [...this.held.keys()]) {
|
|
277370
|
+
if (!key.startsWith(`${target}:${scope}:`))
|
|
277371
|
+
continue;
|
|
277372
|
+
if (present.has(key))
|
|
277373
|
+
continue;
|
|
277374
|
+
this.held.delete(key);
|
|
277375
|
+
this.latestByKey.delete(key);
|
|
277376
|
+
this.dirty = true;
|
|
277377
|
+
}
|
|
277378
|
+
this.persistIfDirty();
|
|
277379
|
+
if (!latestChanged)
|
|
277380
|
+
return;
|
|
277381
|
+
this.emitList(target);
|
|
277382
|
+
}
|
|
277383
|
+
/** Publish a partial candidate set without treating omissions as up-to-date. */
|
|
277384
|
+
publishCandidates(candidates) {
|
|
277385
|
+
let latestChanged = false;
|
|
277386
|
+
const targets = /* @__PURE__ */ new Set();
|
|
277387
|
+
for (const candidate of candidates) {
|
|
277388
|
+
targets.add(candidate.target);
|
|
277389
|
+
if (this.note(candidate))
|
|
277390
|
+
latestChanged = true;
|
|
277391
|
+
}
|
|
277392
|
+
this.persistIfDirty();
|
|
277393
|
+
if (!latestChanged)
|
|
277394
|
+
return;
|
|
277395
|
+
for (const target of targets)
|
|
277396
|
+
this.emitList(target);
|
|
277397
|
+
}
|
|
277398
|
+
note(candidate) {
|
|
277399
|
+
const key = this.key(candidate);
|
|
277400
|
+
const previous = this.latestByKey.get(key);
|
|
277401
|
+
const previousHeld = this.held.get(key);
|
|
277402
|
+
if (previousHeld === void 0 || previousHeld.currentVersion !== candidate.currentVersion || previousHeld.latestVersion !== candidate.latestVersion || previousHeld.nodeId !== candidate.nodeId) {
|
|
277403
|
+
this.dirty = true;
|
|
277404
|
+
}
|
|
277405
|
+
this.held.set(key, candidate);
|
|
277406
|
+
this.latestByKey.set(key, candidate.latestVersion);
|
|
277407
|
+
return previous !== candidate.latestVersion;
|
|
277408
|
+
}
|
|
277409
|
+
/**
|
|
277410
|
+
* Flush to the durable store. Called BEFORE the emit so a crash between the
|
|
277411
|
+
* two costs a duplicate announcement, never a silent one.
|
|
277412
|
+
*/
|
|
277413
|
+
persistIfDirty() {
|
|
277414
|
+
if (!this.dirty)
|
|
277415
|
+
return;
|
|
277416
|
+
this.dirty = false;
|
|
277417
|
+
this.store?.save({
|
|
277418
|
+
latestByKey: Object.fromEntries(this.latestByKey),
|
|
277419
|
+
held: Object.fromEntries(this.held)
|
|
277420
|
+
});
|
|
277421
|
+
}
|
|
277422
|
+
emitList(target) {
|
|
277423
|
+
const list = [...this.held.values()].filter((candidate) => candidate.target === target);
|
|
277424
|
+
if (list.length === 0)
|
|
277425
|
+
return;
|
|
277426
|
+
const packages = list.map((candidate) => ({
|
|
277427
|
+
packageName: candidate.packageName,
|
|
277428
|
+
currentVersion: candidate.currentVersion,
|
|
277429
|
+
latestVersion: candidate.latestVersion,
|
|
277430
|
+
...candidate.nodeId !== void 0 ? { nodeId: candidate.nodeId } : {}
|
|
277431
|
+
}));
|
|
277432
|
+
const nodeIds = unique(packages.map((pkg) => pkg.nodeId).filter((id) => id !== void 0));
|
|
277433
|
+
const head = list[0];
|
|
277434
|
+
this.eventBus.emit({
|
|
277435
|
+
id: `update.available:${target}:${packages.map((pkg) => `${pkg.nodeId ?? "hub"}:${pkg.packageName}@${pkg.latestVersion}`).toSorted().join(",")}`,
|
|
277436
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
277437
|
+
source: this.source,
|
|
277438
|
+
category: types_1.EventCategory.UpdateAvailable,
|
|
277439
|
+
data: {
|
|
277440
|
+
target,
|
|
277441
|
+
packageName: head.packageName,
|
|
277442
|
+
currentVersion: head.currentVersion,
|
|
277443
|
+
latestVersion: head.latestVersion,
|
|
277444
|
+
packages,
|
|
277445
|
+
...head.nodeId !== void 0 ? { nodeId: head.nodeId } : {},
|
|
277446
|
+
...nodeIds.length > 0 ? { nodeIds } : {}
|
|
277447
|
+
}
|
|
277448
|
+
});
|
|
277449
|
+
}
|
|
277450
|
+
key(candidate) {
|
|
277451
|
+
return `${candidate.target}:${candidate.nodeId ?? "hub"}:${candidate.packageName}`;
|
|
277452
|
+
}
|
|
277453
|
+
};
|
|
277454
|
+
exports.UpdateAvailabilityEmitter = UpdateAvailabilityEmitter;
|
|
277455
|
+
function stampNode(candidate, nodeId) {
|
|
277456
|
+
if (nodeId === void 0 || candidate.nodeId !== void 0)
|
|
277457
|
+
return candidate;
|
|
277458
|
+
return { ...candidate, nodeId };
|
|
277459
|
+
}
|
|
277460
|
+
function unique(values) {
|
|
277461
|
+
return [...new Set(values)];
|
|
277462
|
+
}
|
|
277463
|
+
}
|
|
277464
|
+
});
|
|
277465
|
+
|
|
277466
|
+
// ../../server/backend/dist/core/update-availability-store.js
|
|
277467
|
+
var require_update_availability_store = __commonJS({
|
|
277468
|
+
"../../server/backend/dist/core/update-availability-store.js"(exports) {
|
|
277469
|
+
"use strict";
|
|
277470
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
277471
|
+
if (k2 === void 0) k2 = k;
|
|
277472
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
277473
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
277474
|
+
desc = { enumerable: true, get: function() {
|
|
277475
|
+
return m[k];
|
|
277476
|
+
} };
|
|
277477
|
+
}
|
|
277478
|
+
Object.defineProperty(o, k2, desc);
|
|
277479
|
+
}) : (function(o, m, k, k2) {
|
|
277480
|
+
if (k2 === void 0) k2 = k;
|
|
277481
|
+
o[k2] = m[k];
|
|
277482
|
+
}));
|
|
277483
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
|
|
277484
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
277485
|
+
}) : function(o, v) {
|
|
277486
|
+
o["default"] = v;
|
|
277487
|
+
});
|
|
277488
|
+
var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
|
|
277489
|
+
var ownKeys = function(o) {
|
|
277490
|
+
ownKeys = Object.getOwnPropertyNames || function(o2) {
|
|
277491
|
+
var ar = [];
|
|
277492
|
+
for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
|
|
277493
|
+
return ar;
|
|
277494
|
+
};
|
|
277495
|
+
return ownKeys(o);
|
|
277496
|
+
};
|
|
277497
|
+
return function(mod) {
|
|
277498
|
+
if (mod && mod.__esModule) return mod;
|
|
277499
|
+
var result = {};
|
|
277500
|
+
if (mod != null) {
|
|
277501
|
+
for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
277502
|
+
}
|
|
277503
|
+
__setModuleDefault(result, mod);
|
|
277504
|
+
return result;
|
|
277505
|
+
};
|
|
277506
|
+
})();
|
|
277507
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277508
|
+
exports.FileUpdateAvailabilityStore = exports.UPDATE_AVAILABILITY_DIR = void 0;
|
|
277509
|
+
var fs = __importStar(__require("fs"));
|
|
277510
|
+
var path = __importStar(__require("path"));
|
|
277511
|
+
var types_1 = require_dist9();
|
|
277512
|
+
exports.UPDATE_AVAILABILITY_DIR = "update-availability";
|
|
277513
|
+
var FileUpdateAvailabilityStore = class {
|
|
277514
|
+
scopeId;
|
|
277515
|
+
logger;
|
|
277516
|
+
filePath;
|
|
277517
|
+
constructor(dataDir, scopeId, logger) {
|
|
277518
|
+
this.scopeId = scopeId;
|
|
277519
|
+
this.logger = logger;
|
|
277520
|
+
this.filePath = path.join(dataDir, exports.UPDATE_AVAILABILITY_DIR, `${scopeId}.json`);
|
|
277521
|
+
}
|
|
277522
|
+
load() {
|
|
277523
|
+
try {
|
|
277524
|
+
if (!fs.existsSync(this.filePath))
|
|
277525
|
+
return null;
|
|
277526
|
+
const parsed = JSON.parse(fs.readFileSync(this.filePath, "utf-8"));
|
|
277527
|
+
return parseState(parsed);
|
|
277528
|
+
} catch (error) {
|
|
277529
|
+
this.logger.warn("Update-availability state unreadable; starting from empty", {
|
|
277530
|
+
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
277531
|
+
});
|
|
277532
|
+
return null;
|
|
277533
|
+
}
|
|
277534
|
+
}
|
|
277535
|
+
save(state) {
|
|
277536
|
+
try {
|
|
277537
|
+
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
277538
|
+
const tmp = `${this.filePath}.tmp`;
|
|
277539
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
277540
|
+
fs.renameSync(tmp, this.filePath);
|
|
277541
|
+
} catch (error) {
|
|
277542
|
+
this.logger.warn("Failed to persist update-availability state", {
|
|
277543
|
+
meta: { scopeId: this.scopeId, path: this.filePath, error: (0, types_1.errMsg)(error) }
|
|
277544
|
+
});
|
|
277545
|
+
}
|
|
277546
|
+
}
|
|
277547
|
+
};
|
|
277548
|
+
exports.FileUpdateAvailabilityStore = FileUpdateAvailabilityStore;
|
|
277549
|
+
function parseState(raw) {
|
|
277550
|
+
if (raw === null || typeof raw !== "object")
|
|
277551
|
+
return null;
|
|
277552
|
+
const latestRaw = Reflect.get(raw, "latestByKey");
|
|
277553
|
+
const heldRaw = Reflect.get(raw, "held");
|
|
277554
|
+
if (latestRaw === null || typeof latestRaw !== "object")
|
|
277555
|
+
return null;
|
|
277556
|
+
if (heldRaw === null || typeof heldRaw !== "object")
|
|
277557
|
+
return null;
|
|
277558
|
+
const latestByKey = {};
|
|
277559
|
+
for (const [key, value] of Object.entries(latestRaw)) {
|
|
277560
|
+
if (typeof value === "string")
|
|
277561
|
+
latestByKey[key] = value;
|
|
277562
|
+
}
|
|
277563
|
+
const held = {};
|
|
277564
|
+
for (const [key, value] of Object.entries(heldRaw)) {
|
|
277565
|
+
const candidate = parseCandidate(value);
|
|
277566
|
+
if (candidate !== null)
|
|
277567
|
+
held[key] = candidate;
|
|
277568
|
+
}
|
|
277569
|
+
return { latestByKey, held };
|
|
277570
|
+
}
|
|
277571
|
+
function parseCandidate(raw) {
|
|
277572
|
+
if (raw === null || typeof raw !== "object")
|
|
277573
|
+
return null;
|
|
277574
|
+
const target = Reflect.get(raw, "target");
|
|
277575
|
+
const packageName = Reflect.get(raw, "packageName");
|
|
277576
|
+
const currentVersion = Reflect.get(raw, "currentVersion");
|
|
277577
|
+
const latestVersion = Reflect.get(raw, "latestVersion");
|
|
277578
|
+
const nodeId = Reflect.get(raw, "nodeId");
|
|
277579
|
+
if (target !== "addon" && target !== "server")
|
|
277580
|
+
return null;
|
|
277581
|
+
if (typeof packageName !== "string")
|
|
277582
|
+
return null;
|
|
277583
|
+
if (typeof currentVersion !== "string")
|
|
277584
|
+
return null;
|
|
277585
|
+
if (typeof latestVersion !== "string")
|
|
277586
|
+
return null;
|
|
277587
|
+
return {
|
|
277588
|
+
target,
|
|
277589
|
+
packageName,
|
|
277590
|
+
currentVersion,
|
|
277591
|
+
latestVersion,
|
|
277592
|
+
...typeof nodeId === "string" ? { nodeId } : {}
|
|
277593
|
+
};
|
|
277594
|
+
}
|
|
277595
|
+
}
|
|
277596
|
+
});
|
|
277597
|
+
|
|
276443
277598
|
// ../../server/backend/dist/server-root/index.js
|
|
276444
277599
|
var require_server_root = __commonJS({
|
|
276445
277600
|
"../../server/backend/dist/server-root/index.js"(exports, module) {
|
|
@@ -277944,43 +279099,6 @@ var require_server_root = __commonJS({
|
|
|
277944
279099
|
}
|
|
277945
279100
|
});
|
|
277946
279101
|
|
|
277947
|
-
// ../../server/backend/dist/core/server-update/system-exec-npm.js
|
|
277948
|
-
var require_system_exec_npm = __commonJS({
|
|
277949
|
-
"../../server/backend/dist/core/server-update/system-exec-npm.js"(exports) {
|
|
277950
|
-
"use strict";
|
|
277951
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277952
|
-
exports.buildSystemExecNpm = buildSystemExecNpm;
|
|
277953
|
-
var system_1 = require_dist3();
|
|
277954
|
-
function buildSystemExecNpm(options, runNpmFn = system_1.runNpm) {
|
|
277955
|
-
return async (args, opts) => {
|
|
277956
|
-
const { stdout } = await runNpmFn(args, {
|
|
277957
|
-
cacheDir: options.cacheDir,
|
|
277958
|
-
registry: options.registry,
|
|
277959
|
-
logger: options.logger,
|
|
277960
|
-
...opts.cwd !== void 0 ? { cwd: opts.cwd } : {},
|
|
277961
|
-
timeout: opts.timeoutMs
|
|
277962
|
-
});
|
|
277963
|
-
return { stdout };
|
|
277964
|
-
};
|
|
277965
|
-
}
|
|
277966
|
-
}
|
|
277967
|
-
});
|
|
277968
|
-
|
|
277969
|
-
// ../../server/backend/dist/core/server-update/system-ensure-prebuilds.js
|
|
277970
|
-
var require_system_ensure_prebuilds = __commonJS({
|
|
277971
|
-
"../../server/backend/dist/core/server-update/system-ensure-prebuilds.js"(exports) {
|
|
277972
|
-
"use strict";
|
|
277973
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
277974
|
-
exports.buildSystemEnsureNativePrebuilds = buildSystemEnsureNativePrebuilds;
|
|
277975
|
-
var system_1 = require_dist3();
|
|
277976
|
-
function buildSystemEnsureNativePrebuilds(logger) {
|
|
277977
|
-
return async (closureDir) => {
|
|
277978
|
-
await (0, system_1.ensureNativePrebuilds)(closureDir, { logger });
|
|
277979
|
-
};
|
|
277980
|
-
}
|
|
277981
|
-
}
|
|
277982
|
-
});
|
|
277983
|
-
|
|
277984
279102
|
// ../../server/backend/dist/agent/agent-update-service.js
|
|
277985
279103
|
var require_agent_update_service = __commonJS({
|
|
277986
279104
|
"../../server/backend/dist/agent/agent-update-service.js"(exports) {
|
|
@@ -278028,11 +279146,16 @@ var require_agent_update_service = __commonJS({
|
|
|
278028
279146
|
exports.resolveAgentPackageJsonPath = resolveAgentPackageJsonPath;
|
|
278029
279147
|
exports.scheduleAgentRestart = scheduleAgentRestart;
|
|
278030
279148
|
exports.agentRuntimeManifestEntry = agentRuntimeManifestEntry;
|
|
279149
|
+
var node_crypto_1 = __require("crypto");
|
|
278031
279150
|
var fs = __importStar(__require("fs"));
|
|
278032
279151
|
var path = __importStar(__require("path"));
|
|
278033
|
-
var
|
|
278034
|
-
var
|
|
279152
|
+
var system_1 = require_dist3();
|
|
279153
|
+
var types_1 = require_dist9();
|
|
278035
279154
|
var system_ensure_prebuilds_js_1 = require_system_ensure_prebuilds();
|
|
279155
|
+
var system_exec_npm_js_1 = require_system_exec_npm();
|
|
279156
|
+
var update_availability_emitter_js_1 = require_update_availability_emitter();
|
|
279157
|
+
var update_availability_store_js_1 = require_update_availability_store();
|
|
279158
|
+
var index_js_1 = require_server_root();
|
|
278036
279159
|
exports.AGENT_RUNTIME_ADDON_ID = "agent-runtime";
|
|
278037
279160
|
exports.AGENT_RESTART_GRACE_MS = 2e3;
|
|
278038
279161
|
function isRunningInContainer(existsSyncFn) {
|
|
@@ -278077,7 +279200,14 @@ var require_agent_update_service = __commonJS({
|
|
|
278077
279200
|
grace.unref();
|
|
278078
279201
|
}
|
|
278079
279202
|
var AgentUpdateService = class extends index_js_1.RootUpdateService {
|
|
279203
|
+
updateAvailability;
|
|
279204
|
+
eventBus;
|
|
279205
|
+
nodeId;
|
|
279206
|
+
agentDataDir;
|
|
279207
|
+
/** The base class keeps `logger` private; hold our own for the store. */
|
|
279208
|
+
agentLogger;
|
|
278080
279209
|
constructor(options) {
|
|
279210
|
+
const restartAgent = options.restartAgent ?? ((requestedBy) => scheduleAgentRestart(options.logger, requestedBy, options.dataDir));
|
|
278081
279211
|
super({
|
|
278082
279212
|
spec: index_js_1.HUB_ROOT_SPEC,
|
|
278083
279213
|
// The agent's on-disk root IS `@camstack/server` (booted via
|
|
@@ -278089,7 +279219,10 @@ var require_agent_update_service = __commonJS({
|
|
|
278089
279219
|
seedDir: "CAMSTACK_SEED_SERVER_DIR"
|
|
278090
279220
|
},
|
|
278091
279221
|
logger: options.logger,
|
|
278092
|
-
restartServer:
|
|
279222
|
+
restartServer: (requestedBy) => {
|
|
279223
|
+
writeAgentRestartMarker(options.dataDir, requestedBy);
|
|
279224
|
+
restartAgent(requestedBy);
|
|
279225
|
+
},
|
|
278093
279226
|
dataDir: options.dataDir,
|
|
278094
279227
|
runningPackageJsonPath: options.runningPackageJsonPath ?? resolveAgentPackageJsonPath(__dirname),
|
|
278095
279228
|
workspaceProbeDir: __dirname,
|
|
@@ -278107,9 +279240,79 @@ var require_agent_update_service = __commonJS({
|
|
|
278107
279240
|
env: options.env,
|
|
278108
279241
|
now: options.now
|
|
278109
279242
|
});
|
|
279243
|
+
this.nodeId = options.nodeId ?? process.env["CAMSTACK_NODE_ID"] ?? "agent";
|
|
279244
|
+
this.agentDataDir = options.dataDir;
|
|
279245
|
+
this.agentLogger = options.logger;
|
|
279246
|
+
this.eventBus = options.eventBus ?? null;
|
|
279247
|
+
this.updateAvailability = options.eventBus !== void 0 ? new update_availability_emitter_js_1.UpdateAvailabilityEmitter(options.eventBus, { type: "core", id: "agent-update-service" }, options.updateAvailabilityStore) : null;
|
|
279248
|
+
}
|
|
279249
|
+
/**
|
|
279250
|
+
* Bind the agent's real event bus once the mesh is up. The dedup state is
|
|
279251
|
+
* persisted under the agent's data dir from here on — an agent restarts on
|
|
279252
|
+
* every root update, which is exactly when its availability list is longest.
|
|
279253
|
+
*/
|
|
279254
|
+
bindAvailability(eventBus, nodeId) {
|
|
279255
|
+
this.eventBus = eventBus;
|
|
279256
|
+
this.nodeId = nodeId;
|
|
279257
|
+
this.updateAvailability = new update_availability_emitter_js_1.UpdateAvailabilityEmitter(eventBus, { type: "core", id: "agent-update-service" }, new update_availability_store_js_1.FileUpdateAvailabilityStore(this.agentDataDir, "agent-update", this.agentLogger));
|
|
279258
|
+
}
|
|
279259
|
+
async checkServerUpdate() {
|
|
279260
|
+
const result = await super.checkServerUpdate();
|
|
279261
|
+
if (result.error !== null)
|
|
279262
|
+
return result;
|
|
279263
|
+
this.updateAvailability?.publishSnapshot("server", result.updateAvailable && result.runningVersion !== null && result.latestVersion !== null ? [
|
|
279264
|
+
{
|
|
279265
|
+
target: "server",
|
|
279266
|
+
packageName: result.packageName,
|
|
279267
|
+
currentVersion: result.runningVersion,
|
|
279268
|
+
latestVersion: result.latestVersion,
|
|
279269
|
+
nodeId: this.nodeId
|
|
279270
|
+
}
|
|
279271
|
+
] : [], this.nodeId);
|
|
279272
|
+
return result;
|
|
279273
|
+
}
|
|
279274
|
+
/** Consume `.restart-pending` and emit `system.restart-completed` if present. */
|
|
279275
|
+
emitRestartCompletedIfPending() {
|
|
279276
|
+
const bus = this.eventBus;
|
|
279277
|
+
if (bus === null)
|
|
279278
|
+
return;
|
|
279279
|
+
const marker = (0, system_1.readPendingRestart)(this.agentDataDir);
|
|
279280
|
+
if (marker === null)
|
|
279281
|
+
return;
|
|
279282
|
+
const payload = {
|
|
279283
|
+
kind: marker.kind,
|
|
279284
|
+
requestedAt: marker.requestedAt,
|
|
279285
|
+
nodeId: this.nodeId,
|
|
279286
|
+
...marker.packageName !== void 0 ? { packageName: marker.packageName } : {},
|
|
279287
|
+
...marker.fromVersion !== void 0 ? { fromVersion: marker.fromVersion } : {},
|
|
279288
|
+
...marker.toVersion !== void 0 ? { toVersion: marker.toVersion } : {},
|
|
279289
|
+
...marker.requestedBy !== void 0 ? { requestedBy: marker.requestedBy } : {}
|
|
279290
|
+
};
|
|
279291
|
+
bus.emit({
|
|
279292
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
279293
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
279294
|
+
source: { type: "core", id: "agent-update-service" },
|
|
279295
|
+
category: types_1.EventCategory.SystemRestartCompleted,
|
|
279296
|
+
data: payload
|
|
279297
|
+
});
|
|
278110
279298
|
}
|
|
278111
279299
|
};
|
|
278112
279300
|
exports.AgentUpdateService = AgentUpdateService;
|
|
279301
|
+
function writeAgentRestartMarker(dataDir, requestedBy) {
|
|
279302
|
+
const toVersion = /@([^@\s]+)$/.exec(requestedBy)?.[1];
|
|
279303
|
+
try {
|
|
279304
|
+
(0, system_1.writePendingRestart)(dataDir, {
|
|
279305
|
+
kind: requestedBy.startsWith("server-update:") ? "framework-update" : "manual",
|
|
279306
|
+
requestedAt: Date.now(),
|
|
279307
|
+
requestedBy,
|
|
279308
|
+
...requestedBy.startsWith("server-update:") ? {
|
|
279309
|
+
packageName: "@camstack/server",
|
|
279310
|
+
...toVersion !== void 0 ? { toVersion } : {}
|
|
279311
|
+
} : {}
|
|
279312
|
+
});
|
|
279313
|
+
} catch {
|
|
279314
|
+
}
|
|
279315
|
+
}
|
|
278113
279316
|
function agentRuntimeManifestEntry() {
|
|
278114
279317
|
return { addonId: exports.AGENT_RUNTIME_ADDON_ID, capabilities: ["server-management"] };
|
|
278115
279318
|
}
|
|
@@ -370751,6 +371954,7 @@ var require_main2 = __commonJS({
|
|
|
370751
371954
|
agentBootConfirmed = true;
|
|
370752
371955
|
try {
|
|
370753
371956
|
agentUpdateService.confirmBootHealthy();
|
|
371957
|
+
agentUpdateService.emitRestartCompletedIfPending();
|
|
370754
371958
|
} catch (err) {
|
|
370755
371959
|
consoleLogger.warn(`agent root boot confirmation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
370756
371960
|
}
|
|
@@ -370930,9 +372134,10 @@ var require_main2 = __commonJS({
|
|
|
370930
372134
|
return;
|
|
370931
372135
|
reconcileHubUrlFromRegistry();
|
|
370932
372136
|
});
|
|
372137
|
+
const agentBrokerEventBus = (0, system_1.getBrokerEventBus)(broker);
|
|
372138
|
+
agentUpdateService.bindAvailability(agentBrokerEventBus, broker.nodeID);
|
|
370933
372139
|
let udsEventBridgeDispose = null;
|
|
370934
372140
|
if (agentUdsRegistry !== void 0) {
|
|
370935
|
-
const agentBrokerEventBus = (0, system_1.getBrokerEventBus)(broker);
|
|
370936
372141
|
udsEventBridgeDispose = (0, system_1.createUdsEventBridge)({
|
|
370937
372142
|
registry: agentUdsRegistry,
|
|
370938
372143
|
parentBus: agentBrokerEventBus,
|
|
@@ -386575,61 +387780,126 @@ var require_ws3 = __commonJS({
|
|
|
386575
387780
|
}
|
|
386576
387781
|
});
|
|
386577
387782
|
|
|
386578
|
-
// ../../server/backend/dist/core/update-
|
|
386579
|
-
var
|
|
386580
|
-
"../../server/backend/dist/core/update-
|
|
387783
|
+
// ../../server/backend/dist/core/updates/update-check-scheduler.js
|
|
387784
|
+
var require_update_check_scheduler = __commonJS({
|
|
387785
|
+
"../../server/backend/dist/core/updates/update-check-scheduler.js"(exports) {
|
|
386581
387786
|
"use strict";
|
|
386582
387787
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
386583
|
-
exports.
|
|
387788
|
+
exports.UpdateCheckScheduler = exports.MAX_UPDATE_CHECK_INTERVAL_SECONDS = exports.MIN_UPDATE_CHECK_INTERVAL_SECONDS = exports.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS = void 0;
|
|
387789
|
+
exports.clampUpdateCheckInterval = clampUpdateCheckInterval;
|
|
386584
387790
|
var types_1 = require_dist9();
|
|
386585
|
-
|
|
386586
|
-
|
|
386587
|
-
|
|
386588
|
-
|
|
386589
|
-
|
|
386590
|
-
|
|
386591
|
-
|
|
387791
|
+
exports.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS = 6 * 60 * 60;
|
|
387792
|
+
exports.MIN_UPDATE_CHECK_INTERVAL_SECONDS = 15 * 60;
|
|
387793
|
+
exports.MAX_UPDATE_CHECK_INTERVAL_SECONDS = 7 * 24 * 60 * 60;
|
|
387794
|
+
var DEFAULT_INITIAL_DELAY_MS = 9e4;
|
|
387795
|
+
function clampUpdateCheckInterval(seconds) {
|
|
387796
|
+
if (!Number.isFinite(seconds))
|
|
387797
|
+
return exports.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS;
|
|
387798
|
+
const whole = Math.floor(seconds);
|
|
387799
|
+
if (whole < exports.MIN_UPDATE_CHECK_INTERVAL_SECONDS)
|
|
387800
|
+
return exports.MIN_UPDATE_CHECK_INTERVAL_SECONDS;
|
|
387801
|
+
if (whole > exports.MAX_UPDATE_CHECK_INTERVAL_SECONDS)
|
|
387802
|
+
return exports.MAX_UPDATE_CHECK_INTERVAL_SECONDS;
|
|
387803
|
+
return whole;
|
|
387804
|
+
}
|
|
387805
|
+
var UpdateCheckScheduler = class {
|
|
387806
|
+
logger;
|
|
387807
|
+
targets;
|
|
387808
|
+
getIntervalSeconds;
|
|
387809
|
+
initialDelayMs;
|
|
387810
|
+
timer = null;
|
|
387811
|
+
bootTimer = null;
|
|
387812
|
+
intervalSeconds = exports.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS;
|
|
387813
|
+
sweeping = false;
|
|
387814
|
+
constructor(options) {
|
|
387815
|
+
this.logger = options.logger;
|
|
387816
|
+
this.targets = options.targets;
|
|
387817
|
+
this.getIntervalSeconds = options.getIntervalSeconds;
|
|
387818
|
+
this.initialDelayMs = options.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
|
|
386592
387819
|
}
|
|
386593
|
-
|
|
386594
|
-
|
|
386595
|
-
|
|
386596
|
-
|
|
386597
|
-
|
|
386598
|
-
|
|
386599
|
-
|
|
386600
|
-
|
|
386601
|
-
this.
|
|
387820
|
+
/** Interval currently armed, after clamping. Exposed for assertions + logs. */
|
|
387821
|
+
currentIntervalSeconds() {
|
|
387822
|
+
return this.intervalSeconds;
|
|
387823
|
+
}
|
|
387824
|
+
/** Arm the poller. Safe to call twice — the previous timers are replaced. */
|
|
387825
|
+
start() {
|
|
387826
|
+
this.arm();
|
|
387827
|
+
if (this.bootTimer !== null)
|
|
387828
|
+
clearTimeout(this.bootTimer);
|
|
387829
|
+
this.bootTimer = setTimeout(() => {
|
|
387830
|
+
this.bootTimer = null;
|
|
387831
|
+
void this.runSweep();
|
|
387832
|
+
}, this.initialDelayMs);
|
|
387833
|
+
this.bootTimer.unref?.();
|
|
387834
|
+
}
|
|
387835
|
+
/** Re-read the interval from settings and re-arm if it moved. */
|
|
387836
|
+
reschedule() {
|
|
387837
|
+
const next = clampUpdateCheckInterval(this.getIntervalSeconds());
|
|
387838
|
+
if (this.timer !== null && next === this.intervalSeconds)
|
|
387839
|
+
return;
|
|
387840
|
+
this.arm();
|
|
387841
|
+
}
|
|
387842
|
+
stop() {
|
|
387843
|
+
if (this.timer !== null)
|
|
387844
|
+
clearInterval(this.timer);
|
|
387845
|
+
if (this.bootTimer !== null)
|
|
387846
|
+
clearTimeout(this.bootTimer);
|
|
387847
|
+
this.timer = null;
|
|
387848
|
+
this.bootTimer = null;
|
|
387849
|
+
}
|
|
387850
|
+
/**
|
|
387851
|
+
* One full sweep. Never throws and never runs concurrently with itself — an
|
|
387852
|
+
* overlapping tick (slow registry, long agent fan-out) is dropped WITH a log
|
|
387853
|
+
* rather than doubling the npm traffic.
|
|
387854
|
+
*/
|
|
387855
|
+
async runSweep() {
|
|
387856
|
+
if (this.sweeping) {
|
|
387857
|
+
this.logger.warn("Update check skipped \u2014 previous sweep still running");
|
|
387858
|
+
return;
|
|
386602
387859
|
}
|
|
386603
|
-
|
|
386604
|
-
|
|
386605
|
-
|
|
387860
|
+
this.sweeping = true;
|
|
387861
|
+
try {
|
|
387862
|
+
const nodes = this.targets.listNodes();
|
|
387863
|
+
await this.attempt("hub addon packages", "hub", () => this.targets.checkHubAddons());
|
|
387864
|
+
await this.attempt("framework packages", "hub", () => this.targets.checkFrameworkPackages());
|
|
387865
|
+
for (const node of nodes) {
|
|
387866
|
+
if (!node.isOnline) {
|
|
387867
|
+
this.logger.warn("Update check skipped \u2014 node offline", { tags: { nodeId: node.id } });
|
|
387868
|
+
continue;
|
|
387869
|
+
}
|
|
387870
|
+
await this.attempt("node server package", node.id, () => this.targets.checkNodeServerUpdate(node.id, node.isHub));
|
|
387871
|
+
if (node.isHub)
|
|
387872
|
+
continue;
|
|
387873
|
+
await this.attempt("agent addon packages", node.id, () => this.targets.checkAgentAddons(node.id));
|
|
386606
387874
|
}
|
|
387875
|
+
} finally {
|
|
387876
|
+
this.sweeping = false;
|
|
386607
387877
|
}
|
|
386608
387878
|
}
|
|
386609
|
-
|
|
386610
|
-
|
|
386611
|
-
|
|
386612
|
-
|
|
386613
|
-
|
|
386614
|
-
|
|
386615
|
-
const key = this.key(candidate);
|
|
386616
|
-
const signature = `${candidate.currentVersion}->${candidate.latestVersion}`;
|
|
386617
|
-
if (this.signatures.get(key) === signature)
|
|
386618
|
-
return;
|
|
386619
|
-
this.signatures.set(key, signature);
|
|
386620
|
-
this.eventBus.emit({
|
|
386621
|
-
id: `update.available:${key}:${signature}`,
|
|
386622
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
386623
|
-
source: this.source,
|
|
386624
|
-
category: types_1.EventCategory.UpdateAvailable,
|
|
386625
|
-
data: candidate
|
|
387879
|
+
arm() {
|
|
387880
|
+
if (this.timer !== null)
|
|
387881
|
+
clearInterval(this.timer);
|
|
387882
|
+
this.intervalSeconds = clampUpdateCheckInterval(this.getIntervalSeconds());
|
|
387883
|
+
this.logger.info("Update check scheduled", {
|
|
387884
|
+
meta: { intervalSeconds: this.intervalSeconds }
|
|
386626
387885
|
});
|
|
387886
|
+
this.timer = setInterval(() => {
|
|
387887
|
+
void this.runSweep();
|
|
387888
|
+
}, this.intervalSeconds * 1e3);
|
|
387889
|
+
this.timer.unref?.();
|
|
386627
387890
|
}
|
|
386628
|
-
|
|
386629
|
-
|
|
387891
|
+
async attempt(what, nodeId, run) {
|
|
387892
|
+
try {
|
|
387893
|
+
await run();
|
|
387894
|
+
} catch (error) {
|
|
387895
|
+
this.logger.warn(`Update check failed \u2014 ${what}`, {
|
|
387896
|
+
tags: { nodeId },
|
|
387897
|
+
meta: { error: (0, types_1.errMsg)(error) }
|
|
387898
|
+
});
|
|
387899
|
+
}
|
|
386630
387900
|
}
|
|
386631
387901
|
};
|
|
386632
|
-
exports.
|
|
387902
|
+
exports.UpdateCheckScheduler = UpdateCheckScheduler;
|
|
386633
387903
|
}
|
|
386634
387904
|
});
|
|
386635
387905
|
|
|
@@ -386908,8 +388178,9 @@ var require_addon_package_service = __commonJS({
|
|
|
386908
388178
|
var node_util_1 = __require("util");
|
|
386909
388179
|
var system_1 = require_dist3();
|
|
386910
388180
|
var types_1 = require_dist9();
|
|
386911
|
-
var package_dir_utils_js_1 = require_package_dir_utils();
|
|
386912
388181
|
var update_availability_emitter_js_1 = require_update_availability_emitter();
|
|
388182
|
+
var update_check_scheduler_js_1 = require_update_check_scheduler();
|
|
388183
|
+
var package_dir_utils_js_1 = require_package_dir_utils();
|
|
386913
388184
|
var execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
386914
388185
|
exports.SYSTEM_PACKAGE = "@camstack/system";
|
|
386915
388186
|
exports.AUTO_UPDATE_EXCLUDED_PACKAGES = /* @__PURE__ */ new Set([
|
|
@@ -387002,10 +388273,20 @@ var require_addon_package_service = __commonJS({
|
|
|
387002
388273
|
updateAvailability;
|
|
387003
388274
|
// -- Auto-update state ----------------------------------------------------
|
|
387004
388275
|
autoUpdateConfig = {
|
|
387005
|
-
global: {
|
|
388276
|
+
global: {
|
|
388277
|
+
channel: "off",
|
|
388278
|
+
intervalSeconds: 21600,
|
|
388279
|
+
updateCheckIntervalSeconds: update_check_scheduler_js_1.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS
|
|
388280
|
+
},
|
|
387006
388281
|
overrides: {}
|
|
387007
388282
|
};
|
|
387008
388283
|
autoUpdateTimer = null;
|
|
388284
|
+
/**
|
|
388285
|
+
* Re-arm hook for the availability poller, wired at boot (manual-boot). Kept
|
|
388286
|
+
* as a callback rather than a service reference so this module never imports
|
|
388287
|
+
* the scheduler's dependencies back.
|
|
388288
|
+
*/
|
|
388289
|
+
updateCheckRescheduler = null;
|
|
387009
388290
|
// -- Timing constants -----------------------------------------------------
|
|
387010
388291
|
// Short TTL — operators expect to see freshly-published versions
|
|
387011
388292
|
// within minutes of `npm publish`, not hours. The Addons page kicks
|
|
@@ -387019,7 +388300,7 @@ var require_addon_package_service = __commonJS({
|
|
|
387019
388300
|
// 10 minutes
|
|
387020
388301
|
static NPM_REGISTRY = "https://registry.npmjs.org";
|
|
387021
388302
|
static REGISTRY_TIMEOUT_MS = 1e4;
|
|
387022
|
-
constructor(loggingService, eventBusService, configService, addonRegistry, notificationService, toastService) {
|
|
388303
|
+
constructor(loggingService, eventBusService, configService, addonRegistry, notificationService, toastService, updateAvailabilityStore) {
|
|
387023
388304
|
this.loggingService = loggingService;
|
|
387024
388305
|
this.eventBusService = eventBusService;
|
|
387025
388306
|
this.configService = configService;
|
|
@@ -387027,10 +388308,7 @@ var require_addon_package_service = __commonJS({
|
|
|
387027
388308
|
this.notificationService = notificationService;
|
|
387028
388309
|
this.toastService = toastService;
|
|
387029
388310
|
this.logger = this.loggingService.createLogger("AddonPackageService");
|
|
387030
|
-
this.updateAvailability = new update_availability_emitter_js_1.UpdateAvailabilityEmitter(this.eventBusService, {
|
|
387031
|
-
type: "core",
|
|
387032
|
-
id: "addon-package-service"
|
|
387033
|
-
});
|
|
388311
|
+
this.updateAvailability = new update_availability_emitter_js_1.UpdateAvailabilityEmitter(this.eventBusService, { type: "core", id: "addon-package-service" }, updateAvailabilityStore);
|
|
387034
388312
|
try {
|
|
387035
388313
|
const addonsDir = this.resolveAddonsDir();
|
|
387036
388314
|
const workspacePackagesDir = (0, system_1.detectWorkspacePackagesDir)(__dirname);
|
|
@@ -387395,8 +388673,8 @@ var require_addon_package_service = __commonJS({
|
|
|
387395
388673
|
}
|
|
387396
388674
|
this.logger.info("Checking for package updates...");
|
|
387397
388675
|
const updates = [];
|
|
387398
|
-
const
|
|
387399
|
-
updates.push(...
|
|
388676
|
+
const sweep = await this.checkAddonPackageUpdates();
|
|
388677
|
+
updates.push(...sweep.updates);
|
|
387400
388678
|
this.logger.info("Found package updates", {
|
|
387401
388679
|
meta: {
|
|
387402
388680
|
count: updates.length,
|
|
@@ -387411,12 +388689,7 @@ var require_addon_package_service = __commonJS({
|
|
|
387411
388689
|
updates,
|
|
387412
388690
|
expiresAt: now + _AddonPackageService.UPDATE_CACHE_TTL_MS
|
|
387413
388691
|
};
|
|
387414
|
-
this.
|
|
387415
|
-
target: "addon",
|
|
387416
|
-
packageName: update.name,
|
|
387417
|
-
currentVersion: update.currentVersion,
|
|
387418
|
-
latestVersion: update.latestVersion
|
|
387419
|
-
})));
|
|
388692
|
+
this.publishAddonAvailability(updates, sweep.failures);
|
|
387420
388693
|
return updates;
|
|
387421
388694
|
}
|
|
387422
388695
|
/** Clear the cached update check results */
|
|
@@ -387440,12 +388713,22 @@ var require_addon_package_service = __commonJS({
|
|
|
387440
388713
|
seen.set(pkg.name, pkg.version);
|
|
387441
388714
|
}
|
|
387442
388715
|
const updates = [];
|
|
388716
|
+
let failures = 0;
|
|
387443
388717
|
await Promise.all([...seen].map(async ([name, version]) => {
|
|
387444
388718
|
if (!this.isAllowedPackage(name))
|
|
387445
388719
|
return;
|
|
387446
388720
|
if (exports.AUTO_UPDATE_EXCLUDED_PACKAGES.has(name))
|
|
387447
388721
|
return;
|
|
387448
|
-
const
|
|
388722
|
+
const lookup = await this.lookupLatestVersion(name);
|
|
388723
|
+
if (!lookup.ok) {
|
|
388724
|
+
failures += 1;
|
|
388725
|
+
this.logger.warn("Registry lookup failed for installed package", {
|
|
388726
|
+
tags: { nodeId: nodeId ?? "hub" },
|
|
388727
|
+
meta: { name, error: lookup.error }
|
|
388728
|
+
});
|
|
388729
|
+
return;
|
|
388730
|
+
}
|
|
388731
|
+
const latestVersion = lookup.latestVersion;
|
|
387449
388732
|
if (latestVersion === null || !isVersionNewer(latestVersion, version))
|
|
387450
388733
|
return;
|
|
387451
388734
|
const category = this.categorize(name);
|
|
@@ -387457,13 +388740,7 @@ var require_addon_package_service = __commonJS({
|
|
|
387457
388740
|
requiresRestart: category === "core"
|
|
387458
388741
|
});
|
|
387459
388742
|
}));
|
|
387460
|
-
this.
|
|
387461
|
-
target: "addon",
|
|
387462
|
-
packageName: update.name,
|
|
387463
|
-
currentVersion: update.currentVersion,
|
|
387464
|
-
latestVersion: update.latestVersion,
|
|
387465
|
-
...nodeId !== void 0 ? { nodeId } : {}
|
|
387466
|
-
})), nodeId);
|
|
388743
|
+
this.publishAddonAvailability(updates, failures, nodeId);
|
|
387467
388744
|
return updates;
|
|
387468
388745
|
}
|
|
387469
388746
|
/**
|
|
@@ -387840,10 +389117,15 @@ var require_addon_package_service = __commonJS({
|
|
|
387840
389117
|
*/
|
|
387841
389118
|
restartServer(requestedBy) {
|
|
387842
389119
|
this.logger.info("Server restart requested -- initiating graceful shutdown");
|
|
389120
|
+
const toVersion = toVersionFromRestartReason(requestedBy);
|
|
387843
389121
|
const payload = {
|
|
387844
|
-
kind: "manual",
|
|
389122
|
+
kind: isServerUpdateRequest(requestedBy) ? "framework-update" : "manual",
|
|
387845
389123
|
requestedAt: Date.now(),
|
|
387846
|
-
...requestedBy !== void 0 ? { requestedBy } : {}
|
|
389124
|
+
...requestedBy !== void 0 ? { requestedBy } : {},
|
|
389125
|
+
...isServerUpdateRequest(requestedBy) ? {
|
|
389126
|
+
packageName: "@camstack/server",
|
|
389127
|
+
...toVersion !== void 0 ? { toVersion } : {}
|
|
389128
|
+
} : {}
|
|
387847
389129
|
};
|
|
387848
389130
|
try {
|
|
387849
389131
|
(0, system_1.writePendingRestart)(this.resolveDataDir(), payload);
|
|
@@ -387885,6 +389167,7 @@ var require_addon_package_service = __commonJS({
|
|
|
387885
389167
|
const hubPkgDir = (0, package_dir_utils_js_1.resolveHubClosurePackageDir)(packageName);
|
|
387886
389168
|
const buildId = hubPkgDir !== null ? (0, package_dir_utils_js_1.computeDistBuildId)(path.join(hubPkgDir, "dist")) : null;
|
|
387887
389169
|
let latestVersion = null;
|
|
389170
|
+
let lookupFailed = false;
|
|
387888
389171
|
try {
|
|
387889
389172
|
const args = [
|
|
387890
389173
|
"view",
|
|
@@ -387896,21 +389179,65 @@ var require_addon_package_service = __commonJS({
|
|
|
387896
389179
|
const trimmed = stdout.trim();
|
|
387897
389180
|
latestVersion = trimmed.length > 0 ? trimmed : null;
|
|
387898
389181
|
} catch (err) {
|
|
389182
|
+
lookupFailed = true;
|
|
387899
389183
|
this.logger.debug("listFrameworkPackages: npm view failed", {
|
|
387900
389184
|
meta: { packageName, error: (0, types_1.errMsg)(err) }
|
|
387901
389185
|
});
|
|
387902
389186
|
}
|
|
387903
|
-
const hasUpdate = latestVersion !== null && currentVersion !== "unknown" && latestVersion
|
|
389187
|
+
const hasUpdate = latestVersion !== null && currentVersion !== "unknown" && isVersionNewer(latestVersion, currentVersion);
|
|
387904
389188
|
return {
|
|
387905
389189
|
packageName,
|
|
387906
389190
|
currentVersion,
|
|
387907
389191
|
latestVersion,
|
|
387908
389192
|
hasUpdate,
|
|
387909
389193
|
buildId,
|
|
389194
|
+
lookupFailed,
|
|
387910
389195
|
...description !== void 0 ? { description } : {}
|
|
387911
389196
|
};
|
|
387912
389197
|
}));
|
|
387913
|
-
|
|
389198
|
+
this.publishFrameworkAvailability(rows);
|
|
389199
|
+
return rows.map(({ lookupFailed: _lookupFailed, ...row }) => row);
|
|
389200
|
+
}
|
|
389201
|
+
/**
|
|
389202
|
+
* Announce framework updates. This surface SHOWED `@camstack/system` had an
|
|
389203
|
+
* update and emitted nothing, so the operator was never told — it was the
|
|
389204
|
+
* only discovery path with no publish at all.
|
|
389205
|
+
*
|
|
389206
|
+
* Two rules it must not break:
|
|
389207
|
+
* - **Strictly newer only.** `hasUpdate` is `latest !== current`, which is
|
|
389208
|
+
* true for a hub running a `-dev.<timestamp>` build AHEAD of the npm tag.
|
|
389209
|
+
* Announcing that would be telling the operator to downgrade.
|
|
389210
|
+
* - **A failed lookup publishes nothing.** Not even an empty snapshot: an
|
|
389211
|
+
* empty snapshot means "up to date" and would clear the dedup state, so
|
|
389212
|
+
* the next successful poll would re-announce everything.
|
|
389213
|
+
*/
|
|
389214
|
+
publishFrameworkAvailability(rows) {
|
|
389215
|
+
const failed = rows.filter((row) => row.lookupFailed);
|
|
389216
|
+
if (failed.length > 0) {
|
|
389217
|
+
this.logger.warn("Framework update check incomplete \u2014 availability not published", {
|
|
389218
|
+
meta: { packages: failed.map((row) => row.packageName) }
|
|
389219
|
+
});
|
|
389220
|
+
return;
|
|
389221
|
+
}
|
|
389222
|
+
const candidates = [];
|
|
389223
|
+
for (const row of rows) {
|
|
389224
|
+
if (row.latestVersion === null || row.currentVersion === "unknown")
|
|
389225
|
+
continue;
|
|
389226
|
+
if (!isVersionNewer(row.latestVersion, row.currentVersion))
|
|
389227
|
+
continue;
|
|
389228
|
+
candidates.push({
|
|
389229
|
+
target: "server",
|
|
389230
|
+
packageName: row.packageName,
|
|
389231
|
+
currentVersion: row.currentVersion,
|
|
389232
|
+
latestVersion: row.latestVersion,
|
|
389233
|
+
nodeId: this.resolveNodeId()
|
|
389234
|
+
});
|
|
389235
|
+
}
|
|
389236
|
+
this.updateAvailability.publishSnapshot("server", candidates, this.resolveNodeId());
|
|
389237
|
+
}
|
|
389238
|
+
/** Node id stamped on availability events emitted by THIS process. */
|
|
389239
|
+
resolveNodeId() {
|
|
389240
|
+
return process.env["CAMSTACK_NODE_ID"] ?? "hub";
|
|
387914
389241
|
}
|
|
387915
389242
|
// =========================================================================
|
|
387916
389243
|
// Reload
|
|
@@ -387942,21 +389269,37 @@ var require_addon_package_service = __commonJS({
|
|
|
387942
389269
|
// =========================================================================
|
|
387943
389270
|
// Auto-update settings
|
|
387944
389271
|
// =========================================================================
|
|
389272
|
+
/**
|
|
389273
|
+
* Register the availability poller's re-arm hook. Called once at boot so a
|
|
389274
|
+
* `setAutoUpdateSettings` write takes effect without a restart.
|
|
389275
|
+
*/
|
|
389276
|
+
setUpdateCheckRescheduler(reschedule) {
|
|
389277
|
+
this.updateCheckRescheduler = reschedule;
|
|
389278
|
+
}
|
|
387945
389279
|
/** Get global auto-update settings */
|
|
387946
389280
|
getAutoUpdateSettings() {
|
|
387947
389281
|
return { ...this.autoUpdateConfig.global };
|
|
387948
389282
|
}
|
|
387949
389283
|
/** Set global auto-update settings and restart the timer */
|
|
387950
|
-
async setAutoUpdateSettings(channel, intervalSeconds) {
|
|
389284
|
+
async setAutoUpdateSettings(channel, intervalSeconds, updateCheckIntervalSeconds) {
|
|
389285
|
+
const previousCheckInterval = this.autoUpdateConfig.global.updateCheckIntervalSeconds;
|
|
389286
|
+
const nextCheckInterval = updateCheckIntervalSeconds === void 0 ? previousCheckInterval : (0, update_check_scheduler_js_1.clampUpdateCheckInterval)(updateCheckIntervalSeconds);
|
|
387951
389287
|
this.autoUpdateConfig = {
|
|
387952
389288
|
...this.autoUpdateConfig,
|
|
387953
389289
|
global: {
|
|
387954
389290
|
channel,
|
|
387955
|
-
intervalSeconds: intervalSeconds ?? this.autoUpdateConfig.global.intervalSeconds
|
|
389291
|
+
intervalSeconds: intervalSeconds ?? this.autoUpdateConfig.global.intervalSeconds,
|
|
389292
|
+
updateCheckIntervalSeconds: nextCheckInterval
|
|
387956
389293
|
}
|
|
387957
389294
|
};
|
|
387958
389295
|
this.saveAutoUpdateConfig();
|
|
387959
389296
|
this.scheduleAutoUpdate();
|
|
389297
|
+
if (updateCheckIntervalSeconds === void 0)
|
|
389298
|
+
return;
|
|
389299
|
+
this.logger.info("Update-check interval changed", {
|
|
389300
|
+
meta: { from: previousCheckInterval, to: nextCheckInterval }
|
|
389301
|
+
});
|
|
389302
|
+
this.updateCheckRescheduler?.();
|
|
387960
389303
|
}
|
|
387961
389304
|
/** Get per-addon auto-update override */
|
|
387962
389305
|
getAddonAutoUpdate(addonId) {
|
|
@@ -388087,10 +389430,12 @@ var require_addon_package_service = __commonJS({
|
|
|
388087
389430
|
const global2 = asRecord(raw["global"]);
|
|
388088
389431
|
const channel = asString(global2["channel"]);
|
|
388089
389432
|
const validChannel = channel === "latest" || channel === "beta" ? channel : "off";
|
|
389433
|
+
const rawCheckInterval = global2["updateCheckIntervalSeconds"];
|
|
388090
389434
|
return {
|
|
388091
389435
|
global: {
|
|
388092
389436
|
channel: validChannel,
|
|
388093
|
-
intervalSeconds: typeof global2["intervalSeconds"] === "number" ? global2["intervalSeconds"] : 3600
|
|
389437
|
+
intervalSeconds: typeof global2["intervalSeconds"] === "number" ? global2["intervalSeconds"] : 3600,
|
|
389438
|
+
updateCheckIntervalSeconds: typeof rawCheckInterval === "number" ? (0, update_check_scheduler_js_1.clampUpdateCheckInterval)(rawCheckInterval) : update_check_scheduler_js_1.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS
|
|
388094
389439
|
},
|
|
388095
389440
|
overrides: Object.fromEntries(Object.entries(asRecord(raw["overrides"])).map(([k, v]) => {
|
|
388096
389441
|
const s = asString(v);
|
|
@@ -388105,7 +389450,14 @@ var require_addon_package_service = __commonJS({
|
|
|
388105
389450
|
meta: { error: (0, types_1.errMsg)(err) }
|
|
388106
389451
|
});
|
|
388107
389452
|
}
|
|
388108
|
-
return {
|
|
389453
|
+
return {
|
|
389454
|
+
global: {
|
|
389455
|
+
channel: "off",
|
|
389456
|
+
intervalSeconds: 21600,
|
|
389457
|
+
updateCheckIntervalSeconds: update_check_scheduler_js_1.DEFAULT_UPDATE_CHECK_INTERVAL_SECONDS
|
|
389458
|
+
},
|
|
389459
|
+
overrides: {}
|
|
389460
|
+
};
|
|
388109
389461
|
}
|
|
388110
389462
|
/** Save auto-update config to disk */
|
|
388111
389463
|
saveAutoUpdateConfig() {
|
|
@@ -388130,12 +389482,17 @@ var require_addon_package_service = __commonJS({
|
|
|
388130
389482
|
/**
|
|
388131
389483
|
* Check addon packages for updates by reading installed versions from
|
|
388132
389484
|
* data/addons/{name}/package.json and comparing against npm registry.
|
|
389485
|
+
*
|
|
389486
|
+
* Reports `failures` alongside the diff: a registry lookup that could not be
|
|
389487
|
+
* MADE is not evidence that a package is up to date, and the availability
|
|
389488
|
+
* publish branches on it.
|
|
388133
389489
|
*/
|
|
388134
389490
|
async checkAddonPackageUpdates() {
|
|
388135
389491
|
const addonsDir = this.resolveAddonsDir();
|
|
388136
389492
|
const updates = [];
|
|
389493
|
+
let failures = 0;
|
|
388137
389494
|
if (!fs.existsSync(addonsDir))
|
|
388138
|
-
return updates;
|
|
389495
|
+
return { updates, failures };
|
|
388139
389496
|
const pkgJsonPaths = [];
|
|
388140
389497
|
const topDirs = fs.readdirSync(addonsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
388141
389498
|
for (const dir of topDirs) {
|
|
@@ -388172,7 +389529,16 @@ var require_addon_package_service = __commonJS({
|
|
|
388172
389529
|
if (source === "workspace")
|
|
388173
389530
|
continue;
|
|
388174
389531
|
}
|
|
388175
|
-
const
|
|
389532
|
+
const lookup = await this.lookupLatestVersion(name);
|
|
389533
|
+
if (!lookup.ok) {
|
|
389534
|
+
failures += 1;
|
|
389535
|
+
this.logger.warn("Registry lookup failed for installed addon package", {
|
|
389536
|
+
tags: { nodeId: this.resolveNodeId() },
|
|
389537
|
+
meta: { name, error: lookup.error }
|
|
389538
|
+
});
|
|
389539
|
+
continue;
|
|
389540
|
+
}
|
|
389541
|
+
const latestVersion = lookup.latestVersion;
|
|
388176
389542
|
if (!latestVersion)
|
|
388177
389543
|
continue;
|
|
388178
389544
|
if (isVersionNewer(latestVersion, version)) {
|
|
@@ -388185,13 +389551,14 @@ var require_addon_package_service = __commonJS({
|
|
|
388185
389551
|
});
|
|
388186
389552
|
}
|
|
388187
389553
|
} catch (error) {
|
|
389554
|
+
failures += 1;
|
|
388188
389555
|
const msg = (0, types_1.errMsg)(error);
|
|
388189
|
-
this.logger.
|
|
389556
|
+
this.logger.warn("Failed to check updates for addon", {
|
|
388190
389557
|
meta: { pkgJsonPath, error: msg }
|
|
388191
389558
|
});
|
|
388192
389559
|
}
|
|
388193
389560
|
}
|
|
388194
|
-
return updates;
|
|
389561
|
+
return { updates, failures };
|
|
388195
389562
|
}
|
|
388196
389563
|
// =========================================================================
|
|
388197
389564
|
// Private: npm registry helpers
|
|
@@ -388202,7 +389569,7 @@ var require_addon_package_service = __commonJS({
|
|
|
388202
389569
|
* Honours `CAMSTACK_NPM_REGISTRY` so update checks resolve against
|
|
388203
389570
|
* the same registry the installer/pack paths use. Without this, a
|
|
388204
389571
|
* per-node `listUpdates` (which diffs an agent's roster via
|
|
388205
|
-
* `checkUpdatesForInstalled` → `
|
|
389572
|
+
* `checkUpdatesForInstalled` → `lookupLatestVersion`) would bypass a
|
|
388206
389573
|
* private registry — including the e2e harness's verdaccio — and
|
|
388207
389574
|
* silently report "no update" for packages that only exist there.
|
|
388208
389575
|
* Trailing slashes are stripped so the `${base}/${name}` join is clean.
|
|
@@ -388212,28 +389579,60 @@ var require_addon_package_service = __commonJS({
|
|
|
388212
389579
|
const base = override && override.length > 0 ? override : _AddonPackageService.NPM_REGISTRY;
|
|
388213
389580
|
return base.replace(/\/+$/, "");
|
|
388214
389581
|
}
|
|
388215
|
-
/**
|
|
388216
|
-
|
|
389582
|
+
/**
|
|
389583
|
+
* Ask the registry for a package's latest version, distinguishing "there is
|
|
389584
|
+
* no such package" (a definitive answer) from "I could not ask" (a failure).
|
|
389585
|
+
* The difference decides whether an availability SNAPSHOT may be published —
|
|
389586
|
+
* see {@link RegistryLookup}.
|
|
389587
|
+
*/
|
|
389588
|
+
async lookupLatestVersion(packageName) {
|
|
388217
389589
|
try {
|
|
388218
389590
|
const encodedName = packageName.replace("/", "%2F");
|
|
388219
389591
|
const url = `${this.resolveRegistryBase()}/${encodedName}/latest`;
|
|
388220
389592
|
const response = await fetch(url, {
|
|
388221
389593
|
signal: AbortSignal.timeout(_AddonPackageService.REGISTRY_TIMEOUT_MS)
|
|
388222
389594
|
});
|
|
389595
|
+
if (response.status === 404)
|
|
389596
|
+
return { ok: true, latestVersion: null };
|
|
388223
389597
|
if (!response.ok) {
|
|
388224
389598
|
this.logger.debug("Registry returned non-ok status", {
|
|
388225
389599
|
meta: { packageName, status: response.status }
|
|
388226
389600
|
});
|
|
388227
|
-
return
|
|
389601
|
+
return { ok: false, error: `registry status ${response.status}` };
|
|
388228
389602
|
}
|
|
388229
389603
|
const data = await fetchJsonObject(response);
|
|
388230
389604
|
const version = asString(data["version"]);
|
|
388231
|
-
return version || null;
|
|
389605
|
+
return { ok: true, latestVersion: version || null };
|
|
388232
389606
|
} catch (error) {
|
|
388233
|
-
|
|
388234
|
-
|
|
388235
|
-
|
|
389607
|
+
return { ok: false, error: (0, types_1.errMsg)(error) };
|
|
389608
|
+
}
|
|
389609
|
+
}
|
|
389610
|
+
/**
|
|
389611
|
+
* Announce the addon-update set for one scope (hub or a node).
|
|
389612
|
+
*
|
|
389613
|
+
* `failures > 0` means at least one registry lookup could not be made, so
|
|
389614
|
+
* the set is INCOMPLETE — publish it as candidates (additive) rather than a
|
|
389615
|
+
* snapshot (authoritative). A snapshot built from a partial sweep silently
|
|
389616
|
+
* marks the unreachable packages "up to date", clears their dedup state and
|
|
389617
|
+
* re-announces them on the next good poll.
|
|
389618
|
+
*/
|
|
389619
|
+
publishAddonAvailability(updates, failures, nodeId) {
|
|
389620
|
+
const candidates = updates.map((update) => ({
|
|
389621
|
+
target: "addon",
|
|
389622
|
+
packageName: update.name,
|
|
389623
|
+
currentVersion: update.currentVersion,
|
|
389624
|
+
latestVersion: update.latestVersion,
|
|
389625
|
+
...nodeId !== void 0 ? { nodeId } : {}
|
|
389626
|
+
}));
|
|
389627
|
+
if (failures > 0) {
|
|
389628
|
+
this.logger.warn("Addon update check incomplete \u2014 availability published as partial", {
|
|
389629
|
+
tags: { nodeId: nodeId ?? "hub" },
|
|
389630
|
+
meta: { failures, published: candidates.length }
|
|
389631
|
+
});
|
|
389632
|
+
this.updateAvailability.publishCandidates(candidates);
|
|
389633
|
+
return;
|
|
388236
389634
|
}
|
|
389635
|
+
this.updateAvailability.publishSnapshot("addon", candidates, nodeId);
|
|
388237
389636
|
}
|
|
388238
389637
|
/** Fetch npm search results for camstack addon packages (cached 5 min) */
|
|
388239
389638
|
async fetchSearchFromNpm() {
|
|
@@ -388383,6 +389782,15 @@ var require_addon_package_service = __commonJS({
|
|
|
388383
389782
|
}
|
|
388384
389783
|
};
|
|
388385
389784
|
exports.AddonPackageService = AddonPackageService;
|
|
389785
|
+
function isServerUpdateRequest(requestedBy) {
|
|
389786
|
+
return requestedBy !== void 0 && requestedBy.startsWith("server-update:");
|
|
389787
|
+
}
|
|
389788
|
+
function toVersionFromRestartReason(requestedBy) {
|
|
389789
|
+
if (requestedBy === void 0)
|
|
389790
|
+
return void 0;
|
|
389791
|
+
const match = /@([^@\s]+)$/.exec(requestedBy);
|
|
389792
|
+
return match?.[1];
|
|
389793
|
+
}
|
|
388386
389794
|
async function extractTgzStripped(tgz, destDir) {
|
|
388387
389795
|
fs.mkdirSync(destDir, { recursive: true });
|
|
388388
389796
|
const tmpFile = path.join(os.tmpdir(), `camstack-tgz-${(0, node_crypto_1.randomUUID)()}.tgz`);
|
|
@@ -396499,6 +397907,30 @@ var require_integration_id_backfill = __commonJS({
|
|
|
396499
397907
|
}
|
|
396500
397908
|
});
|
|
396501
397909
|
|
|
397910
|
+
// ../../server/backend/dist/core/updates/agent-installed-packages.js
|
|
397911
|
+
var require_agent_installed_packages = __commonJS({
|
|
397912
|
+
"../../server/backend/dist/core/updates/agent-installed-packages.js"(exports) {
|
|
397913
|
+
"use strict";
|
|
397914
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
397915
|
+
exports.AGENT_STATUS_TIMEOUT_MS = void 0;
|
|
397916
|
+
exports.fetchAgentInstalledPackages = fetchAgentInstalledPackages;
|
|
397917
|
+
var addon_package_service_js_1 = require_addon_package_service();
|
|
397918
|
+
exports.AGENT_STATUS_TIMEOUT_MS = 5e3;
|
|
397919
|
+
async function fetchAgentInstalledPackages(broker, nodeId) {
|
|
397920
|
+
const status = await broker.call("$agent.status", {}, { nodeID: nodeId, timeout: exports.AGENT_STATUS_TIMEOUT_MS });
|
|
397921
|
+
const out = [];
|
|
397922
|
+
for (const addon of status.addons ?? []) {
|
|
397923
|
+
if (typeof addon.packageName !== "string" || typeof addon.version !== "string")
|
|
397924
|
+
continue;
|
|
397925
|
+
if ((0, addon_package_service_js_1.isFrameworkPackage)(addon.packageName))
|
|
397926
|
+
continue;
|
|
397927
|
+
out.push({ name: addon.packageName, version: addon.version });
|
|
397928
|
+
}
|
|
397929
|
+
return out;
|
|
397930
|
+
}
|
|
397931
|
+
}
|
|
397932
|
+
});
|
|
397933
|
+
|
|
396502
397934
|
// ../../server/backend/dist/api/core/collection-preference.js
|
|
396503
397935
|
var require_collection_preference = __commonJS({
|
|
396504
397936
|
"../../server/backend/dist/api/core/collection-preference.js"(exports) {
|
|
@@ -396874,6 +398306,7 @@ var require_post_boot_service = __commonJS({
|
|
|
396874
398306
|
const payload = {
|
|
396875
398307
|
kind: marker.kind,
|
|
396876
398308
|
requestedAt: marker.requestedAt,
|
|
398309
|
+
nodeId: process.env["CAMSTACK_NODE_ID"] ?? "hub",
|
|
396877
398310
|
...marker.packageName !== void 0 ? { packageName: marker.packageName } : {},
|
|
396878
398311
|
...marker.fromVersion !== void 0 ? { fromVersion: marker.fromVersion } : {},
|
|
396879
398312
|
...marker.toVersion !== void 0 ? { toVersion: marker.toVersion } : {},
|
|
@@ -396957,6 +398390,7 @@ var require_cap_providers = __commonJS({
|
|
|
396957
398390
|
var integration_id_backfill_1 = require_integration_id_backfill();
|
|
396958
398391
|
var addon_package_service_js_1 = require_addon_package_service();
|
|
396959
398392
|
var lifecycle_runner_singleton_js_1 = require_lifecycle_runner_singleton();
|
|
398393
|
+
var agent_installed_packages_js_1 = require_agent_installed_packages();
|
|
396960
398394
|
var collection_preference_js_1 = require_collection_preference();
|
|
396961
398395
|
var site_location_js_1 = require_site_location();
|
|
396962
398396
|
function getRetention(registry) {
|
|
@@ -397840,18 +399274,6 @@ var require_cap_providers = __commonJS({
|
|
|
397840
399274
|
function isHubNode(nodeId) {
|
|
397841
399275
|
return nodeId === "hub" || nodeId.startsWith("hub/");
|
|
397842
399276
|
}
|
|
397843
|
-
async function fetchAgentInstalledPackages(broker, nodeId) {
|
|
397844
|
-
const status = await broker.call("$agent.status", {}, { nodeID: nodeId, timeout: 5e3 });
|
|
397845
|
-
const out = [];
|
|
397846
|
-
for (const a of status.addons ?? []) {
|
|
397847
|
-
if (typeof a.packageName !== "string" || typeof a.version !== "string")
|
|
397848
|
-
continue;
|
|
397849
|
-
if ((0, addon_package_service_js_1.isFrameworkPackage)(a.packageName))
|
|
397850
|
-
continue;
|
|
397851
|
-
out.push({ name: a.packageName, version: a.version });
|
|
397852
|
-
}
|
|
397853
|
-
return out;
|
|
397854
|
-
}
|
|
397855
399277
|
function buildAddonsProvider(ar, ps, ls, moleculer, configService, ctx) {
|
|
397856
399278
|
const broker = moleculer.broker;
|
|
397857
399279
|
const frameworkAllowSet = /* @__PURE__ */ new Set([addon_package_service_js_1.SYSTEM_PACKAGE]);
|
|
@@ -397892,7 +399314,7 @@ var require_cap_providers = __commonJS({
|
|
|
397892
399314
|
},
|
|
397893
399315
|
listUpdates: async (input) => {
|
|
397894
399316
|
const nodeId = input.nodeId;
|
|
397895
|
-
const updates = nodeId === void 0 || isHubNode(nodeId) ? await ps.checkUpdates() : await ps.checkUpdatesForInstalled(await fetchAgentInstalledPackages(broker, nodeId), nodeId);
|
|
399317
|
+
const updates = nodeId === void 0 || isHubNode(nodeId) ? await ps.checkUpdates() : await ps.checkUpdatesForInstalled(await (0, agent_installed_packages_js_1.fetchAgentInstalledPackages)(broker, nodeId), nodeId);
|
|
397896
399318
|
return updates.map((u) => ({ ...u, isSystem: frameworkAllowSet.has(u.name) }));
|
|
397897
399319
|
},
|
|
397898
399320
|
updatePackage: async (input) => {
|
|
@@ -397921,7 +399343,7 @@ var require_cap_providers = __commonJS({
|
|
|
397921
399343
|
const nodeId = input.nodeId;
|
|
397922
399344
|
if (nodeId === void 0 || isHubNode(nodeId))
|
|
397923
399345
|
return ps.checkUpdates(true);
|
|
397924
|
-
const installed = await fetchAgentInstalledPackages(broker, nodeId);
|
|
399346
|
+
const installed = await (0, agent_installed_packages_js_1.fetchAgentInstalledPackages)(broker, nodeId);
|
|
397925
399347
|
return ps.checkUpdatesForInstalled(installed, nodeId);
|
|
397926
399348
|
},
|
|
397927
399349
|
restartServer: async () => ps.restartServer(ctx.user?.username ?? ctx.user?.id),
|
|
@@ -397982,7 +399404,7 @@ var require_cap_providers = __commonJS({
|
|
|
397982
399404
|
return { success: true };
|
|
397983
399405
|
},
|
|
397984
399406
|
getAutoUpdateSettings: async () => ps.getAutoUpdateSettings(),
|
|
397985
|
-
setAutoUpdateSettings: async (input) => ps.setAutoUpdateSettings(input.channel, input.intervalSeconds),
|
|
399407
|
+
setAutoUpdateSettings: async (input) => ps.setAutoUpdateSettings(input.channel, input.intervalSeconds, input.updateCheckIntervalSeconds),
|
|
397986
399408
|
getAddonAutoUpdate: async (input) => ps.getAddonAutoUpdate(input.addonId),
|
|
397987
399409
|
setAddonAutoUpdate: async (input) => ps.setAddonAutoUpdate(input.addonId, input.channel),
|
|
397988
399410
|
applyAutoUpdateToAll: async (input) => {
|
|
@@ -398229,6 +399651,12 @@ var require_event_bus_proxy_router = __commonJS({
|
|
|
398229
399651
|
}
|
|
398230
399652
|
function createEventBusProxyRouter(eventBus) {
|
|
398231
399653
|
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
399654
|
+
// ADMIN-ONLY. `emit` injects a fully-attributed SystemEvent onto the hub's
|
|
399655
|
+
// real EventBus — including a spoofable `source` (a fake `device`/`addon`
|
|
399656
|
+
// origin). Forked addons that legitimately emit reach this over the
|
|
399657
|
+
// trusted core-cap/UDS mesh, whose context is `createMeshTrpcContext`
|
|
399658
|
+
// (`isAdmin: true`), so gating it here withholds the surface from
|
|
399659
|
+
// non-admin HTTP/WS principals without blinding a worker.
|
|
398232
399660
|
emit: trpc_middleware_js_1.adminProcedure.input(SystemEventInputSchema).output(zod_1.z.object({ ok: zod_1.z.literal(true) })).mutation(({ input }) => {
|
|
398233
399661
|
eventBus.emit({
|
|
398234
399662
|
id: input.id,
|
|
@@ -404144,7 +405572,7 @@ var require_logging_service = __commonJS({
|
|
|
404144
405572
|
deviceNames = /* @__PURE__ */ new Map();
|
|
404145
405573
|
constructor(configService) {
|
|
404146
405574
|
const perAddonCapacity = configService.get("eventBus.perAddonLogBufferSize") ?? 5e3;
|
|
404147
|
-
const maxTotalEntries = configService.get("eventBus.maxTotalLogBufferSize")
|
|
405575
|
+
const maxTotalEntries = configService.get("eventBus.maxTotalLogBufferSize");
|
|
404148
405576
|
const pruneLevel = configService.get("eventBus.logBufferPruneLevel") ?? "debug";
|
|
404149
405577
|
super(perAddonCapacity, { maxTotalEntries, pruneLevel });
|
|
404150
405578
|
this.setDeviceNameLookup((id) => this.deviceNames.get(id) ?? null);
|
|
@@ -405486,11 +406914,12 @@ var require_server_update_service = __commonJS({
|
|
|
405486
406914
|
exports.ServerUpdateService = void 0;
|
|
405487
406915
|
var path = __importStar(__require("path"));
|
|
405488
406916
|
var index_js_1 = require_server_root();
|
|
405489
|
-
var system_exec_npm_js_1 = require_system_exec_npm();
|
|
405490
|
-
var system_ensure_prebuilds_js_1 = require_system_ensure_prebuilds();
|
|
405491
406917
|
var update_availability_emitter_js_1 = require_update_availability_emitter();
|
|
406918
|
+
var system_ensure_prebuilds_js_1 = require_system_ensure_prebuilds();
|
|
406919
|
+
var system_exec_npm_js_1 = require_system_exec_npm();
|
|
405492
406920
|
var ServerUpdateService = class extends index_js_1.RootUpdateService {
|
|
405493
406921
|
updateAvailability;
|
|
406922
|
+
nodeId;
|
|
405494
406923
|
constructor(options) {
|
|
405495
406924
|
const dataDir = path.resolve(options.dataDir ?? options.env?.["CAMSTACK_DATA"] ?? process.env["CAMSTACK_DATA"] ?? "camstack-data");
|
|
405496
406925
|
super({
|
|
@@ -405521,23 +406950,23 @@ var require_server_update_service = __commonJS({
|
|
|
405521
406950
|
env: options.env,
|
|
405522
406951
|
now: options.now
|
|
405523
406952
|
});
|
|
405524
|
-
this.updateAvailability = options.eventBus !== void 0 ? new update_availability_emitter_js_1.UpdateAvailabilityEmitter(options.eventBus, {
|
|
405525
|
-
|
|
405526
|
-
id: "server-update-service"
|
|
405527
|
-
}) : null;
|
|
406953
|
+
this.updateAvailability = options.eventBus !== void 0 ? new update_availability_emitter_js_1.UpdateAvailabilityEmitter(options.eventBus, { type: "core", id: "server-update-service" }, options.updateAvailabilityStore) : null;
|
|
406954
|
+
this.nodeId = options.nodeId ?? "hub";
|
|
405528
406955
|
}
|
|
405529
406956
|
async checkServerUpdate() {
|
|
405530
406957
|
const result = await super.checkServerUpdate();
|
|
405531
406958
|
if (result.error !== null)
|
|
405532
406959
|
return result;
|
|
406960
|
+
const nodeId = this.nodeId;
|
|
405533
406961
|
this.updateAvailability?.publishSnapshot("server", result.updateAvailable && result.runningVersion !== null && result.latestVersion !== null ? [
|
|
405534
406962
|
{
|
|
405535
406963
|
target: "server",
|
|
405536
406964
|
packageName: result.packageName,
|
|
405537
406965
|
currentVersion: result.runningVersion,
|
|
405538
|
-
latestVersion: result.latestVersion
|
|
406966
|
+
latestVersion: result.latestVersion,
|
|
406967
|
+
...nodeId !== void 0 ? { nodeId } : {}
|
|
405539
406968
|
}
|
|
405540
|
-
] : []);
|
|
406969
|
+
] : [], nodeId);
|
|
405541
406970
|
return result;
|
|
405542
406971
|
}
|
|
405543
406972
|
};
|
|
@@ -405558,6 +406987,82 @@ var require_storage_service = __commonJS({
|
|
|
405558
406987
|
}
|
|
405559
406988
|
});
|
|
405560
406989
|
|
|
406990
|
+
// ../../server/backend/dist/core/streaming/ttl-cache.js
|
|
406991
|
+
var require_ttl_cache = __commonJS({
|
|
406992
|
+
"../../server/backend/dist/core/streaming/ttl-cache.js"(exports) {
|
|
406993
|
+
"use strict";
|
|
406994
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
406995
|
+
exports.TtlCache = void 0;
|
|
406996
|
+
var TtlCache = class {
|
|
406997
|
+
entries = /* @__PURE__ */ new Map();
|
|
406998
|
+
ttlMs;
|
|
406999
|
+
maxEntries;
|
|
407000
|
+
now;
|
|
407001
|
+
constructor(options) {
|
|
407002
|
+
this.ttlMs = options.ttlMs;
|
|
407003
|
+
this.maxEntries = options.maxEntries;
|
|
407004
|
+
this.now = options.now ?? (() => Date.now());
|
|
407005
|
+
}
|
|
407006
|
+
/** The live value, or undefined when absent or expired. An expired entry is
|
|
407007
|
+
* DELETED here, not merely reported missing. */
|
|
407008
|
+
get(key) {
|
|
407009
|
+
const slot = this.entries.get(key);
|
|
407010
|
+
if (slot === void 0)
|
|
407011
|
+
return void 0;
|
|
407012
|
+
const at = this.now();
|
|
407013
|
+
if (at - slot.storedAt >= this.ttlMs) {
|
|
407014
|
+
this.entries.delete(key);
|
|
407015
|
+
return void 0;
|
|
407016
|
+
}
|
|
407017
|
+
slot.lastAccessAt = at;
|
|
407018
|
+
return slot.value;
|
|
407019
|
+
}
|
|
407020
|
+
/**
|
|
407021
|
+
* Store a value, then bring the map back inside both bounds.
|
|
407022
|
+
*
|
|
407023
|
+
* The sweep runs on WRITE and not on a timer on purpose: a timer would have
|
|
407024
|
+
* to be owned, unref'd and stopped by every holder of a cache, and a cache
|
|
407025
|
+
* that is never written to is a cache that is not growing.
|
|
407026
|
+
*/
|
|
407027
|
+
set(key, value) {
|
|
407028
|
+
const at = this.now();
|
|
407029
|
+
this.entries.set(key, { value, storedAt: at, lastAccessAt: at });
|
|
407030
|
+
this.sweepExpired(at);
|
|
407031
|
+
this.enforceMaxEntries(key);
|
|
407032
|
+
}
|
|
407033
|
+
delete(key) {
|
|
407034
|
+
this.entries.delete(key);
|
|
407035
|
+
}
|
|
407036
|
+
clear() {
|
|
407037
|
+
this.entries.clear();
|
|
407038
|
+
}
|
|
407039
|
+
/** Entries currently retained. The number that used to only go up. */
|
|
407040
|
+
size() {
|
|
407041
|
+
return this.entries.size;
|
|
407042
|
+
}
|
|
407043
|
+
sweepExpired(at) {
|
|
407044
|
+
for (const [key, slot] of this.entries) {
|
|
407045
|
+
if (at - slot.storedAt >= this.ttlMs)
|
|
407046
|
+
this.entries.delete(key);
|
|
407047
|
+
}
|
|
407048
|
+
}
|
|
407049
|
+
/** Evict least-recently-USED first. `protectedKey` is the entry just written —
|
|
407050
|
+
* evicting it would make `set` a no-op. */
|
|
407051
|
+
enforceMaxEntries(protectedKey) {
|
|
407052
|
+
if (this.entries.size <= this.maxEntries)
|
|
407053
|
+
return;
|
|
407054
|
+
const coldestFirst = [...this.entries.entries()].filter(([key]) => key !== protectedKey).toSorted((a, b) => a[1].lastAccessAt - b[1].lastAccessAt);
|
|
407055
|
+
for (const [key] of coldestFirst) {
|
|
407056
|
+
if (this.entries.size <= this.maxEntries)
|
|
407057
|
+
return;
|
|
407058
|
+
this.entries.delete(key);
|
|
407059
|
+
}
|
|
407060
|
+
}
|
|
407061
|
+
};
|
|
407062
|
+
exports.TtlCache = TtlCache;
|
|
407063
|
+
}
|
|
407064
|
+
});
|
|
407065
|
+
|
|
405561
407066
|
// ../../server/backend/dist/core/streaming/stream-probe.service.js
|
|
405562
407067
|
var require_stream_probe_service = __commonJS({
|
|
405563
407068
|
"../../server/backend/dist/core/streaming/stream-probe.service.js"(exports) {
|
|
@@ -405566,16 +407071,28 @@ var require_stream_probe_service = __commonJS({
|
|
|
405566
407071
|
exports.StreamProbeService = void 0;
|
|
405567
407072
|
var child_process_1 = __require("child_process");
|
|
405568
407073
|
var util_1 = __require("util");
|
|
407074
|
+
var ttl_cache_1 = require_ttl_cache();
|
|
405569
407075
|
var types_1 = require_dist9();
|
|
405570
407076
|
var execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
405571
407077
|
var CACHE_TTL_MS = 36e5;
|
|
405572
407078
|
var PROBE_TIMEOUT_MS = 5e3;
|
|
407079
|
+
var CACHE_MAX_ENTRIES = 512;
|
|
405573
407080
|
var CODEC_ALIASES = {
|
|
405574
407081
|
hevc: "h265"
|
|
405575
407082
|
};
|
|
405576
407083
|
var StreamProbeService = class {
|
|
405577
407084
|
logger;
|
|
405578
|
-
|
|
407085
|
+
/**
|
|
407086
|
+
* Probe results, bounded by BOTH a swept TTL and an entry ceiling.
|
|
407087
|
+
*
|
|
407088
|
+
* It used to be a plain `Map` whose age was consulted only when the same URL
|
|
407089
|
+
* was probed again — so an entry nobody asked about a second time was never
|
|
407090
|
+
* found expired and never removed. See {@link TtlCache}.
|
|
407091
|
+
*/
|
|
407092
|
+
cache = new ttl_cache_1.TtlCache({
|
|
407093
|
+
ttlMs: CACHE_TTL_MS,
|
|
407094
|
+
maxEntries: CACHE_MAX_ENTRIES
|
|
407095
|
+
});
|
|
405579
407096
|
constructor(loggingService) {
|
|
405580
407097
|
this.logger = loggingService.createLogger("StreamProbeService");
|
|
405581
407098
|
}
|
|
@@ -405587,12 +407104,11 @@ var require_stream_probe_service = __commonJS({
|
|
|
405587
407104
|
const force = options?.force ?? false;
|
|
405588
407105
|
if (!force) {
|
|
405589
407106
|
const cached = this.cache.get(url);
|
|
405590
|
-
if (cached
|
|
405591
|
-
return cached
|
|
405592
|
-
}
|
|
407107
|
+
if (cached)
|
|
407108
|
+
return cached;
|
|
405593
407109
|
}
|
|
405594
407110
|
const metadata = await this.runProbe(url);
|
|
405595
|
-
this.cache.set(url,
|
|
407111
|
+
this.cache.set(url, metadata);
|
|
405596
407112
|
return metadata;
|
|
405597
407113
|
}
|
|
405598
407114
|
/**
|
|
@@ -406444,6 +407960,9 @@ var require_manual_boot = __commonJS({
|
|
|
406444
407960
|
var storage_service_1 = require_storage_service();
|
|
406445
407961
|
var stream_probe_service_1 = require_stream_probe_service();
|
|
406446
407962
|
var topology_emitter_service_1 = require_topology_emitter_service();
|
|
407963
|
+
var update_availability_store_js_1 = require_update_availability_store();
|
|
407964
|
+
var agent_installed_packages_js_1 = require_agent_installed_packages();
|
|
407965
|
+
var update_check_scheduler_js_1 = require_update_check_scheduler();
|
|
406447
407966
|
var ServiceContainer = class {
|
|
406448
407967
|
services = /* @__PURE__ */ new Map();
|
|
406449
407968
|
register(ctor, instance) {
|
|
@@ -406489,7 +408008,8 @@ var require_manual_boot = __commonJS({
|
|
|
406489
408008
|
agentRegistryService.setAddonRegistry(addonRegistryService);
|
|
406490
408009
|
agentRegistryService.setClusterNodeHistoryStore(new cluster_node_history_store_1.ClusterNodeHistoryStore(() => capabilityService.getRegistry()?.getSingleton("settings-store") ?? null, loggingService.createLogger("cluster-node-history")));
|
|
406491
408010
|
const addonWidgetsService = new addon_widgets_service_1.AddonWidgetsService(loggingService, capabilityService, addonRegistryService);
|
|
406492
|
-
const
|
|
408011
|
+
const availabilityDataDir = path.resolve(process.env["CAMSTACK_DATA"] ?? "camstack-data");
|
|
408012
|
+
const addonPackageService = new addon_package_service_1.AddonPackageService(loggingService, eventBusService, configService, addonRegistryService, notificationWrapper, toastWrapper, new update_availability_store_js_1.FileUpdateAvailabilityStore(availabilityDataDir, "addon-packages", loggingService.createLogger("UpdateAvailability")));
|
|
406493
408013
|
const backfillLogger = loggingService.createLogger("agent-backfill");
|
|
406494
408014
|
agentRegistryService.setAddonBackfill({
|
|
406495
408015
|
pack: async (name, version) => {
|
|
@@ -406542,10 +408062,40 @@ var require_manual_boot = __commonJS({
|
|
|
406542
408062
|
const serverUpdateService = new server_update_service_1.ServerUpdateService({
|
|
406543
408063
|
logger: loggingService.createLogger("ServerUpdate"),
|
|
406544
408064
|
restartServer: (requestedBy) => addonPackageService.restartServer(requestedBy),
|
|
406545
|
-
eventBus: eventBusService
|
|
408065
|
+
eventBus: eventBusService,
|
|
408066
|
+
updateAvailabilityStore: new update_availability_store_js_1.FileUpdateAvailabilityStore(availabilityDataDir, "server-update", loggingService.createLogger("UpdateAvailability"))
|
|
406546
408067
|
});
|
|
406547
408068
|
const topologyEmitterService = new topology_emitter_service_1.TopologyEmitterService(eventBusService, agentRegistryService, addonRegistryService, (0, cap_providers_1.createNodeRootPackageLookup)(moleculerService, serverUpdateService));
|
|
406548
408069
|
const postBootService = new post_boot_service_1.PostBootService(addonRegistryService, eventBusService, loggingService);
|
|
408070
|
+
const updateCheckLogger = loggingService.createLogger("UpdateCheck");
|
|
408071
|
+
const updateCheckScheduler = new update_check_scheduler_js_1.UpdateCheckScheduler({
|
|
408072
|
+
logger: updateCheckLogger,
|
|
408073
|
+
getIntervalSeconds: () => addonPackageService.getAutoUpdateSettings().updateCheckIntervalSeconds,
|
|
408074
|
+
targets: {
|
|
408075
|
+
listNodes: () => agentRegistryService.listNodeLiveness(),
|
|
408076
|
+
checkHubAddons: () => addonPackageService.checkUpdates(true),
|
|
408077
|
+
checkFrameworkPackages: () => addonPackageService.listFrameworkPackages(),
|
|
408078
|
+
checkAgentAddons: async (nodeId) => {
|
|
408079
|
+
const broker = moleculerService.broker;
|
|
408080
|
+
const installed = await (0, agent_installed_packages_js_1.fetchAgentInstalledPackages)(broker, nodeId);
|
|
408081
|
+
return addonPackageService.checkUpdatesForInstalled(installed, nodeId);
|
|
408082
|
+
},
|
|
408083
|
+
checkNodeServerUpdate: async (nodeId, isHub) => {
|
|
408084
|
+
if (isHub)
|
|
408085
|
+
return serverUpdateService.checkServerUpdate();
|
|
408086
|
+
const proxy = moleculerService.createCapabilityProxy("server-management", nodeId);
|
|
408087
|
+
if (proxy === null) {
|
|
408088
|
+
updateCheckLogger.warn("Update check skipped \u2014 server-management unreachable", {
|
|
408089
|
+
tags: { nodeId }
|
|
408090
|
+
});
|
|
408091
|
+
return void 0;
|
|
408092
|
+
}
|
|
408093
|
+
return proxy["checkServerUpdate"]?.({});
|
|
408094
|
+
}
|
|
408095
|
+
}
|
|
408096
|
+
});
|
|
408097
|
+
addonPackageService.setUpdateCheckRescheduler(() => updateCheckScheduler.reschedule());
|
|
408098
|
+
updateCheckScheduler.start();
|
|
406549
408099
|
const container = new ServiceContainer();
|
|
406550
408100
|
container.register(config_service_1.ConfigService, configService);
|
|
406551
408101
|
container.register(logging_service_1.LoggingService, loggingService);
|
|
@@ -406570,6 +408120,7 @@ var require_manual_boot = __commonJS({
|
|
|
406570
408120
|
container.register(server_update_service_1.ServerUpdateService, serverUpdateService);
|
|
406571
408121
|
container.register(topology_emitter_service_1.TopologyEmitterService, topologyEmitterService);
|
|
406572
408122
|
container.register(post_boot_service_1.PostBootService, postBootService);
|
|
408123
|
+
container.register(update_check_scheduler_js_1.UpdateCheckScheduler, updateCheckScheduler);
|
|
406573
408124
|
const fastify = (0, fastify_1.default)(fastifyOpts);
|
|
406574
408125
|
let closed = false;
|
|
406575
408126
|
let shutdownHooksRegistered = false;
|
|
@@ -406580,6 +408131,11 @@ var require_manual_boot = __commonJS({
|
|
|
406580
408131
|
const logErr = (label, err) => {
|
|
406581
408132
|
console.error(`[manual-boot] ${label} destroy failed:`, err);
|
|
406582
408133
|
};
|
|
408134
|
+
try {
|
|
408135
|
+
updateCheckScheduler.stop();
|
|
408136
|
+
} catch (err) {
|
|
408137
|
+
logErr("UpdateCheckScheduler", err);
|
|
408138
|
+
}
|
|
406583
408139
|
try {
|
|
406584
408140
|
topologyEmitterService.onModuleDestroy();
|
|
406585
408141
|
} catch (err) {
|