@camstack/addon-notifiers 1.1.23 → 1.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +1354 -51
- package/dist/addon.mjs +1354 -51
- package/package.json +4 -1
package/dist/addon.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
|
|
1
2
|
//#region ../../node_modules/zod/v4/core/core.js
|
|
2
3
|
var _a$1;
|
|
3
4
|
function $constructor(name, initializer, params) {
|
|
@@ -4286,6 +4287,14 @@ function object(shape, params) {
|
|
|
4286
4287
|
...normalizeParams(params)
|
|
4287
4288
|
});
|
|
4288
4289
|
}
|
|
4290
|
+
function looseObject(shape, params) {
|
|
4291
|
+
return new ZodObject({
|
|
4292
|
+
type: "object",
|
|
4293
|
+
shape,
|
|
4294
|
+
catchall: unknown(),
|
|
4295
|
+
...normalizeParams(params)
|
|
4296
|
+
});
|
|
4297
|
+
}
|
|
4289
4298
|
var ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
|
|
4290
4299
|
$ZodUnion.init(inst, def);
|
|
4291
4300
|
ZodType.init(inst, def);
|
|
@@ -4627,7 +4636,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4627
4636
|
return inst;
|
|
4628
4637
|
}
|
|
4629
4638
|
//#endregion
|
|
4630
|
-
//#region ../types/dist/sleep-
|
|
4639
|
+
//#region ../types/dist/sleep-_sv7WKkq.mjs
|
|
4631
4640
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4632
4641
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4633
4642
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5037,10 +5046,51 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
5037
5046
|
EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
|
|
5038
5047
|
EventCategory["EnrichmentSceneStateChanged"] = "enrichment.scene.state-changed";
|
|
5039
5048
|
EventCategory["EnrichmentActivitySummary"] = "enrichment.activity.summary";
|
|
5049
|
+
/**
|
|
5050
|
+
* Unified track-lifecycle event: ONE category carrying `phase:
|
|
5051
|
+
* 'start' | 'update' | 'end'` with a rich, typed
|
|
5052
|
+
* `PipelineAnalyticsTrackLifecyclePayload`. Supersedes the thin
|
|
5053
|
+
* `PipelineAnalyticsTrackStarted` / `PipelineAnalyticsTrackEnded`
|
|
5054
|
+
* pair — a consumer subscribes once and branches on `phase`.
|
|
5055
|
+
*/
|
|
5056
|
+
EventCategory["PipelineAnalyticsTrackLifecycle"] = "pipeline-analytics.track-lifecycle";
|
|
5057
|
+
/**
|
|
5058
|
+
* @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
|
|
5059
|
+
* (`phase:'start'`). Kept as a soft alias — no known subscribers.
|
|
5060
|
+
*/
|
|
5040
5061
|
EventCategory["PipelineAnalyticsTrackStarted"] = "pipeline-analytics.track-started";
|
|
5062
|
+
/**
|
|
5063
|
+
* @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
|
|
5064
|
+
* (`phase:'end'`). Kept as a soft alias — no known subscribers.
|
|
5065
|
+
*/
|
|
5041
5066
|
EventCategory["PipelineAnalyticsTrackEnded"] = "pipeline-analytics.track-ended";
|
|
5042
5067
|
EventCategory["PipelineAnalyticsDetectionEvent"] = "pipeline-analytics.detection-event";
|
|
5043
5068
|
EventCategory["PipelineAnalyticsFrameTracked"] = "pipeline-analytics.frame-tracked";
|
|
5069
|
+
/**
|
|
5070
|
+
* Fired by `addon-post-analysis` when a parked (stationary) object appears
|
|
5071
|
+
* (a track was promoted to a stationary-registry entry) or departs (the
|
|
5072
|
+
* object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
|
|
5073
|
+
* the dedicated "Stationary" section — never the live event feed. Payload:
|
|
5074
|
+
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
|
|
5075
|
+
*/
|
|
5076
|
+
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
5077
|
+
/**
|
|
5078
|
+
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
5079
|
+
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
5080
|
+
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
5081
|
+
* removed. Telemetry semantics (D8): a lost event only delays a refresh,
|
|
5082
|
+
* never a correctness issue. Payload `PipelineAnalyticsFaceGalleryChangedPayload`.
|
|
5083
|
+
*/
|
|
5084
|
+
EventCategory["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
|
|
5085
|
+
/**
|
|
5086
|
+
* Fired by `addon-post-analysis` whenever a gallery plate row changes:
|
|
5087
|
+
* `kind:'buffered'` a new read was persisted (`PlateRecognizer.onTrackEnd`),
|
|
5088
|
+
* `'assigned'` / `'unassigned'` its vehicle link changed
|
|
5089
|
+
* (`PlateGalleryProvider`), `'deleted'` the row was removed. Telemetry
|
|
5090
|
+
* semantics (D8): a lost event only delays a refresh, never a correctness
|
|
5091
|
+
* issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
|
|
5092
|
+
*/
|
|
5093
|
+
EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
|
|
5044
5094
|
EventCategory["FrigateLiveEvent"] = "frigate.live-event";
|
|
5045
5095
|
EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
|
|
5046
5096
|
/**
|
|
@@ -6869,7 +6919,8 @@ var MODEL_FORMATS = [
|
|
|
6869
6919
|
"coreml",
|
|
6870
6920
|
"openvino",
|
|
6871
6921
|
"tflite",
|
|
6872
|
-
"pt"
|
|
6922
|
+
"pt",
|
|
6923
|
+
"gguf"
|
|
6873
6924
|
];
|
|
6874
6925
|
/**
|
|
6875
6926
|
* Multi-file format payload.
|
|
@@ -6913,7 +6964,8 @@ var ModelFormatsSchema = object({
|
|
|
6913
6964
|
coreml: ModelFormatEntrySchema.optional(),
|
|
6914
6965
|
openvino: ModelFormatEntrySchema.optional(),
|
|
6915
6966
|
tflite: ModelFormatEntrySchema.optional(),
|
|
6916
|
-
pt: ModelFormatEntrySchema.optional()
|
|
6967
|
+
pt: ModelFormatEntrySchema.optional(),
|
|
6968
|
+
gguf: ModelFormatEntrySchema.optional()
|
|
6917
6969
|
});
|
|
6918
6970
|
/**
|
|
6919
6971
|
* Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
|
|
@@ -6954,6 +7006,15 @@ var ModelCatalogEntrySchema = object({
|
|
|
6954
7006
|
width: number(),
|
|
6955
7007
|
height: number()
|
|
6956
7008
|
}),
|
|
7009
|
+
/**
|
|
7010
|
+
* Channel count of the model input tensor. Omit ⇒ 3 (RGB), the default for
|
|
7011
|
+
* every detector / classifier / embedder. Set to 1 for a grayscale CTC text
|
|
7012
|
+
* recognizer (EasyOCR VGG plate-OCR: input `[N,1,H,W]`) so the preprocess
|
|
7013
|
+
* feeds a single-channel, EasyOCR-normalized tensor instead of the default
|
|
7014
|
+
* 3-channel RGB one. Threaded through `PoolModelConfig.inputChannels` to the
|
|
7015
|
+
* Python inference pool.
|
|
7016
|
+
*/
|
|
7017
|
+
inputChannels: number().int().positive().optional(),
|
|
6957
7018
|
labels: array(LabelDefinitionSchema).readonly(),
|
|
6958
7019
|
inputLayout: _enum(["nchw", "nhwc"]).optional(),
|
|
6959
7020
|
inputNormalization: _enum([
|
|
@@ -6963,6 +7024,16 @@ var ModelCatalogEntrySchema = object({
|
|
|
6963
7024
|
]).optional(),
|
|
6964
7025
|
preprocessMode: _enum(["letterbox", "resize"]).optional(),
|
|
6965
7026
|
/**
|
|
7027
|
+
* Per-MODEL postprocessor override. Absent ⇒ the step's own
|
|
7028
|
+
* `StepDefinition.postprocessor` applies (the normal case — every model in a
|
|
7029
|
+
* step shares its decode). Set it when a step hosts models with DIFFERENT raw
|
|
7030
|
+
* output layouts under one slot: e.g. object-detection is `'yolo'` by default,
|
|
7031
|
+
* but a Coral SSD MobileNet build emits the `TFLite_Detection_PostProcess`
|
|
7032
|
+
* 4-tensor layout and needs `'ssd'`. Threaded into `PoolModelConfig.postprocessor`
|
|
7033
|
+
* by the engine factory (`modelEntry.postprocessor ?? def.postprocessor`).
|
|
7034
|
+
*/
|
|
7035
|
+
postprocessor: custom().optional(),
|
|
7036
|
+
/**
|
|
6966
7037
|
* When true, the executor produces a landmark-aligned crop (similarity warp
|
|
6967
7038
|
* onto the canonical template) before this step runs, instead of a plain
|
|
6968
7039
|
* axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
|
|
@@ -7052,6 +7123,123 @@ var ConvertResultSchema = object({
|
|
|
7052
7123
|
})).readonly()
|
|
7053
7124
|
});
|
|
7054
7125
|
/**
|
|
7126
|
+
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
7127
|
+
* both the operator-facing `getRoutes` (returning route descriptors
|
|
7128
|
+
* minus the handlers, which can't cross JSON) and the framework-
|
|
7129
|
+
* private `invoke` method that the hub calls when this provider lives
|
|
7130
|
+
* in a forked worker.
|
|
7131
|
+
*
|
|
7132
|
+
* Co-located addons use the returned `getRoutes` directly because
|
|
7133
|
+
* their handlers don't need to cross any wire. The `invoke` method
|
|
7134
|
+
* is present anyway so the bridge code on the hub is uniform — it
|
|
7135
|
+
* doesn't need to switch on "local vs remote provider" at the call
|
|
7136
|
+
* site.
|
|
7137
|
+
*
|
|
7138
|
+
* Example:
|
|
7139
|
+
* const routes: IAddonHttpRoute[] = [
|
|
7140
|
+
* { method: 'GET', path: '/start', access: 'public', handler: this.handleStart },
|
|
7141
|
+
* ]
|
|
7142
|
+
* return [
|
|
7143
|
+
* {
|
|
7144
|
+
* capability: addonRoutesCapability,
|
|
7145
|
+
* provider: buildAddonRouteProvider('auth-oidc', routes),
|
|
7146
|
+
* },
|
|
7147
|
+
* ]
|
|
7148
|
+
*/
|
|
7149
|
+
function buildAddonRouteProvider(id, routes) {
|
|
7150
|
+
return {
|
|
7151
|
+
id,
|
|
7152
|
+
getRoutes: () => routes,
|
|
7153
|
+
invoke: async (input) => {
|
|
7154
|
+
const match = matchRoute(routes, input.method, input.path);
|
|
7155
|
+
if (!match) return {
|
|
7156
|
+
status: 404,
|
|
7157
|
+
headers: {},
|
|
7158
|
+
redirectUrl: null,
|
|
7159
|
+
body: { error: `No route matches ${input.method} ${input.path}` }
|
|
7160
|
+
};
|
|
7161
|
+
const envelope = {
|
|
7162
|
+
status: 200,
|
|
7163
|
+
headers: {},
|
|
7164
|
+
redirectUrl: null
|
|
7165
|
+
};
|
|
7166
|
+
const reply = buildCapturingReply(envelope);
|
|
7167
|
+
const request = {
|
|
7168
|
+
params: {
|
|
7169
|
+
...input.params,
|
|
7170
|
+
...match.params
|
|
7171
|
+
},
|
|
7172
|
+
query: input.query,
|
|
7173
|
+
body: input.body,
|
|
7174
|
+
headers: input.headers,
|
|
7175
|
+
...input.user ? { user: input.user } : {},
|
|
7176
|
+
...input.scopedToken !== void 0 ? { scopedToken: input.scopedToken } : {}
|
|
7177
|
+
};
|
|
7178
|
+
await match.route.handler(request, reply);
|
|
7179
|
+
return envelope;
|
|
7180
|
+
}
|
|
7181
|
+
};
|
|
7182
|
+
}
|
|
7183
|
+
/**
|
|
7184
|
+
* Pattern matcher: same semantics as `AddonRouteRegistry.matchRoute`
|
|
7185
|
+
* but operating on a flat list and bypassing the `/addon/<id>/` prefix
|
|
7186
|
+
* — the bridge sends the post-prefix path directly so we don't need
|
|
7187
|
+
* to round-trip it through normalization.
|
|
7188
|
+
*/
|
|
7189
|
+
function matchRoute(routes, method, path) {
|
|
7190
|
+
const normalizedMethod = method.toUpperCase();
|
|
7191
|
+
for (const route of routes) {
|
|
7192
|
+
if (route.method !== normalizedMethod) continue;
|
|
7193
|
+
const params = matchPath(route.path, path);
|
|
7194
|
+
if (params !== null) return {
|
|
7195
|
+
route,
|
|
7196
|
+
params
|
|
7197
|
+
};
|
|
7198
|
+
}
|
|
7199
|
+
return null;
|
|
7200
|
+
}
|
|
7201
|
+
function matchPath(pattern, p) {
|
|
7202
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
7203
|
+
const pathParts = p.split("/").filter(Boolean);
|
|
7204
|
+
if (patternParts.length !== pathParts.length) return null;
|
|
7205
|
+
const params = {};
|
|
7206
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
7207
|
+
const a = patternParts[i];
|
|
7208
|
+
const b = pathParts[i];
|
|
7209
|
+
if (a.startsWith(":")) params[a.slice(1)] = b;
|
|
7210
|
+
else if (a !== b) return null;
|
|
7211
|
+
}
|
|
7212
|
+
return params;
|
|
7213
|
+
}
|
|
7214
|
+
function buildCapturingReply(envelope) {
|
|
7215
|
+
const wrapper = {
|
|
7216
|
+
status(code) {
|
|
7217
|
+
envelope.status = code;
|
|
7218
|
+
return wrapper;
|
|
7219
|
+
},
|
|
7220
|
+
code(code) {
|
|
7221
|
+
envelope.status = code;
|
|
7222
|
+
return wrapper;
|
|
7223
|
+
},
|
|
7224
|
+
send(data) {
|
|
7225
|
+
envelope.body = data;
|
|
7226
|
+
},
|
|
7227
|
+
redirect(url) {
|
|
7228
|
+
envelope.redirectUrl = url;
|
|
7229
|
+
if (envelope.status === 200) envelope.status = 302;
|
|
7230
|
+
},
|
|
7231
|
+
header(name, value) {
|
|
7232
|
+
envelope.headers[name.toLowerCase()] = value;
|
|
7233
|
+
return wrapper;
|
|
7234
|
+
},
|
|
7235
|
+
type(mime) {
|
|
7236
|
+
envelope.contentType = mime;
|
|
7237
|
+
return wrapper;
|
|
7238
|
+
}
|
|
7239
|
+
};
|
|
7240
|
+
return wrapper;
|
|
7241
|
+
}
|
|
7242
|
+
/**
|
|
7055
7243
|
* Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
|
|
7056
7244
|
* Named `RecordingWeekday` to avoid collision with the string-union
|
|
7057
7245
|
* `Weekday` exported from `interfaces/timezones.ts`.
|
|
@@ -10601,7 +10789,8 @@ var ModelFormatSchema$1 = _enum([
|
|
|
10601
10789
|
"coreml",
|
|
10602
10790
|
"openvino",
|
|
10603
10791
|
"tflite",
|
|
10604
|
-
"pt"
|
|
10792
|
+
"pt",
|
|
10793
|
+
"gguf"
|
|
10605
10794
|
]);
|
|
10606
10795
|
var PipelineSlotSchema = _enum([
|
|
10607
10796
|
"detector",
|
|
@@ -10695,7 +10884,8 @@ var EngineProvisioningSchema = object({
|
|
|
10695
10884
|
runtimeId: _enum([
|
|
10696
10885
|
"onnx",
|
|
10697
10886
|
"openvino",
|
|
10698
|
-
"coreml"
|
|
10887
|
+
"coreml",
|
|
10888
|
+
"edgetpu"
|
|
10699
10889
|
]).nullable(),
|
|
10700
10890
|
device: string().nullable(),
|
|
10701
10891
|
state: _enum([
|
|
@@ -11907,6 +12097,140 @@ DeviceType.Camera, method(object({ deviceId: number() }), PtzAutotrackStatusSche
|
|
|
11907
12097
|
deviceId: number(),
|
|
11908
12098
|
status: PtzAutotrackStatusSchema
|
|
11909
12099
|
});
|
|
12100
|
+
/**
|
|
12101
|
+
* scene-monitor — device-scoped reference-region state cap. An operator marks
|
|
12102
|
+
* a rect ROI on a camera frame and names one or more states; the engine
|
|
12103
|
+
* (pipeline-analytics, designated post-processing node) reports which state is
|
|
12104
|
+
* active on an ongoing basis. Two operator-selectable check modes share every-
|
|
12105
|
+
* thing except the comparator: `similarity` (CLIP cosine at the same ROI coords
|
|
12106
|
+
* vs condition-tagged references) and `llm` (vision-LLM judgment over the crop).
|
|
12107
|
+
*
|
|
12108
|
+
* D14 device-config archetype (`deviceConfig.ui.kind:'widget'`) — the framework
|
|
12109
|
+
* derives the device-detail contribution; the provider carries NO hand-written
|
|
12110
|
+
* settings-contribution methods. `status.kind:'push'` — the engine pushes on
|
|
12111
|
+
* every hysteresis flip / availability change; consumers never poll.
|
|
12112
|
+
*/
|
|
12113
|
+
/** Extensible condition tag. Seeded 'day' | 'night'; open by design so more can
|
|
12114
|
+
* be added without a wire break (matching falls back to any-condition refs). */
|
|
12115
|
+
var SceneConditionSchema = string();
|
|
12116
|
+
/** One captured reference — condition-tagged, model-version-gated. `embedding`
|
|
12117
|
+
* is `number[]` (Float32Array does NOT survive MsgPack/UDS). */
|
|
12118
|
+
var SceneReferenceSchema = object({
|
|
12119
|
+
embedding: array(number()),
|
|
12120
|
+
modelId: string(),
|
|
12121
|
+
condition: SceneConditionSchema,
|
|
12122
|
+
capturedAt: number(),
|
|
12123
|
+
thumbnailMediaId: string().optional()
|
|
12124
|
+
});
|
|
12125
|
+
var SceneMonitorStateSchema = object({
|
|
12126
|
+
id: string(),
|
|
12127
|
+
label: string(),
|
|
12128
|
+
references: array(SceneReferenceSchema),
|
|
12129
|
+
textPrompts: array(string()).optional(),
|
|
12130
|
+
referenceCount: number(),
|
|
12131
|
+
currentlyMatched: boolean()
|
|
12132
|
+
});
|
|
12133
|
+
/** Per-mode comparator params in a discriminated union so an `llm` scene never
|
|
12134
|
+
* carries similarity knobs and vice-versa. */
|
|
12135
|
+
var SceneCheckSchema = discriminatedUnion("mode", [object({
|
|
12136
|
+
mode: literal("similarity"),
|
|
12137
|
+
threshold: number().min(0).max(1),
|
|
12138
|
+
hysteresisCount: number().int().positive()
|
|
12139
|
+
}), object({
|
|
12140
|
+
mode: literal("llm"),
|
|
12141
|
+
prompt: string(),
|
|
12142
|
+
profileId: string().optional(),
|
|
12143
|
+
hysteresisCount: number().int().positive()
|
|
12144
|
+
})]);
|
|
12145
|
+
var SceneMonitorSchema = object({
|
|
12146
|
+
id: string(),
|
|
12147
|
+
label: string(),
|
|
12148
|
+
roi: MaskRectShapeSchema,
|
|
12149
|
+
enabled: boolean(),
|
|
12150
|
+
triggerMode: _enum([
|
|
12151
|
+
"periodic",
|
|
12152
|
+
"on-motion",
|
|
12153
|
+
"both"
|
|
12154
|
+
]),
|
|
12155
|
+
checkIntervalSec: number().optional(),
|
|
12156
|
+
check: SceneCheckSchema,
|
|
12157
|
+
states: array(SceneMonitorStateSchema),
|
|
12158
|
+
currentStateId: string().nullable(),
|
|
12159
|
+
lastCheckedAt: number().nullable(),
|
|
12160
|
+
lastConfidence: number().nullable(),
|
|
12161
|
+
currentCondition: SceneConditionSchema.nullable(),
|
|
12162
|
+
availability: _enum(["ok", "unavailable"]),
|
|
12163
|
+
unavailableReason: string().nullable()
|
|
12164
|
+
});
|
|
12165
|
+
var SceneMonitorStatusSchema = object({
|
|
12166
|
+
monitors: array(SceneMonitorSchema),
|
|
12167
|
+
lastFetchedAt: number()
|
|
12168
|
+
});
|
|
12169
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
|
|
12170
|
+
deviceId: number(),
|
|
12171
|
+
label: string(),
|
|
12172
|
+
roi: MaskRectShapeSchema,
|
|
12173
|
+
check: SceneCheckSchema,
|
|
12174
|
+
triggerMode: _enum([
|
|
12175
|
+
"periodic",
|
|
12176
|
+
"on-motion",
|
|
12177
|
+
"both"
|
|
12178
|
+
]).optional(),
|
|
12179
|
+
checkIntervalSec: number().optional()
|
|
12180
|
+
}), SceneMonitorSchema, {
|
|
12181
|
+
kind: "mutation",
|
|
12182
|
+
auth: "admin"
|
|
12183
|
+
}), method(object({
|
|
12184
|
+
deviceId: number(),
|
|
12185
|
+
monitorId: string(),
|
|
12186
|
+
patch: object({
|
|
12187
|
+
label: string().optional(),
|
|
12188
|
+
roi: MaskRectShapeSchema.optional(),
|
|
12189
|
+
enabled: boolean().optional(),
|
|
12190
|
+
triggerMode: _enum([
|
|
12191
|
+
"periodic",
|
|
12192
|
+
"on-motion",
|
|
12193
|
+
"both"
|
|
12194
|
+
]).optional(),
|
|
12195
|
+
checkIntervalSec: number().optional(),
|
|
12196
|
+
check: SceneCheckSchema.optional()
|
|
12197
|
+
})
|
|
12198
|
+
}), _void(), {
|
|
12199
|
+
kind: "mutation",
|
|
12200
|
+
auth: "admin"
|
|
12201
|
+
}), method(object({
|
|
12202
|
+
deviceId: number(),
|
|
12203
|
+
monitorId: string()
|
|
12204
|
+
}), _void(), {
|
|
12205
|
+
kind: "mutation",
|
|
12206
|
+
auth: "admin"
|
|
12207
|
+
}), method(object({
|
|
12208
|
+
deviceId: number(),
|
|
12209
|
+
monitorId: string(),
|
|
12210
|
+
stateId: string().optional(),
|
|
12211
|
+
label: string().optional(),
|
|
12212
|
+
condition: SceneConditionSchema.optional()
|
|
12213
|
+
}), object({
|
|
12214
|
+
stateId: string(),
|
|
12215
|
+
referenceCount: number()
|
|
12216
|
+
}), {
|
|
12217
|
+
kind: "mutation",
|
|
12218
|
+
auth: "admin"
|
|
12219
|
+
}), method(object({
|
|
12220
|
+
deviceId: number(),
|
|
12221
|
+
monitorId: string(),
|
|
12222
|
+
stateId: string(),
|
|
12223
|
+
index: number()
|
|
12224
|
+
}), _void(), {
|
|
12225
|
+
kind: "mutation",
|
|
12226
|
+
auth: "admin"
|
|
12227
|
+
}), method(object({
|
|
12228
|
+
deviceId: number(),
|
|
12229
|
+
monitorId: string()
|
|
12230
|
+
}), _void(), {
|
|
12231
|
+
kind: "mutation",
|
|
12232
|
+
auth: "admin"
|
|
12233
|
+
});
|
|
11910
12234
|
object({
|
|
11911
12235
|
/** Whether the script is currently executing. */
|
|
11912
12236
|
isRunning: boolean(),
|
|
@@ -12314,6 +12638,36 @@ var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
|
|
|
12314
12638
|
* with the per-track detail panel and live overlay. */
|
|
12315
12639
|
trackIds: array(string()).readonly()
|
|
12316
12640
|
});
|
|
12641
|
+
/**
|
|
12642
|
+
* A parked ("stationary") object surfaced alongside occupancy — an object that
|
|
12643
|
+
* settled and stopped moving. It is NO LONGER a tracked object (the tracker was
|
|
12644
|
+
* told to forget it so it stops re-spawning tracks/events), but it IS still
|
|
12645
|
+
* physically present, so it keeps counting toward `frame` occupancy and is
|
|
12646
|
+
* listed here so the UI can show it in a dedicated "Stationary" section instead
|
|
12647
|
+
* of flooding the live event feed.
|
|
12648
|
+
*/
|
|
12649
|
+
var StationaryObjectSchema = object({
|
|
12650
|
+
id: string(),
|
|
12651
|
+
className: string(),
|
|
12652
|
+
bbox: object({
|
|
12653
|
+
x: number(),
|
|
12654
|
+
y: number(),
|
|
12655
|
+
w: number(),
|
|
12656
|
+
h: number()
|
|
12657
|
+
}),
|
|
12658
|
+
frameWidth: number().int().nonnegative(),
|
|
12659
|
+
frameHeight: number().int().nonnegative(),
|
|
12660
|
+
/** When the source track was first seen. */
|
|
12661
|
+
firstSeenAt: number().int(),
|
|
12662
|
+
/** When the object was recognised as parked (promotion time). */
|
|
12663
|
+
becameStationaryAt: number().int(),
|
|
12664
|
+
/** Last frame a detection confirmed the object is still there. */
|
|
12665
|
+
lastConfirmedAt: number().int(),
|
|
12666
|
+
/** Enrichment label carried from the source track (identity / plate). */
|
|
12667
|
+
label: string().optional(),
|
|
12668
|
+
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
12669
|
+
keyFrameMediaKey: string().optional()
|
|
12670
|
+
});
|
|
12317
12671
|
var CameraOccupancySnapshotSchema = object({
|
|
12318
12672
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
12319
12673
|
ts: number().int(),
|
|
@@ -12322,10 +12676,15 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
12322
12676
|
frameHeight: number().int().nonnegative(),
|
|
12323
12677
|
/** Per-zone breakdown — one entry per defined zone (user + onboard). */
|
|
12324
12678
|
zones: array(ZoneScopeBreakdownSchema).readonly(),
|
|
12325
|
-
/** Frame-wide aggregate (everywhere, regardless of zone membership).
|
|
12679
|
+
/** Frame-wide aggregate (everywhere, regardless of zone membership).
|
|
12680
|
+
* INCLUDES currently-confirmed stationary objects (they are still present). */
|
|
12326
12681
|
frame: PerScopeBreakdownSchema,
|
|
12327
12682
|
/** Detections that landed outside every zone. Empty when no zones defined. */
|
|
12328
|
-
unzoned: PerScopeBreakdownSchema
|
|
12683
|
+
unzoned: PerScopeBreakdownSchema,
|
|
12684
|
+
/** Parked objects on this camera (additive — absent on legacy snapshots).
|
|
12685
|
+
* Surfaced separately so the UI shows them in a dedicated section rather
|
|
12686
|
+
* than as repeated tracks/events. */
|
|
12687
|
+
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
12329
12688
|
});
|
|
12330
12689
|
/**
|
|
12331
12690
|
* Time-series resolution. The history methods return one bucket per
|
|
@@ -12695,7 +13054,26 @@ var InvokeReplyEnvelopeSchema = object({
|
|
|
12695
13054
|
/** Set when the handler called `reply.type(mime)`. */
|
|
12696
13055
|
contentType: string().optional()
|
|
12697
13056
|
});
|
|
12698
|
-
|
|
13057
|
+
var addonRoutesCapability = {
|
|
13058
|
+
name: "addon-routes",
|
|
13059
|
+
scope: "system",
|
|
13060
|
+
mode: "collection",
|
|
13061
|
+
internal: true,
|
|
13062
|
+
methods: {
|
|
13063
|
+
getRoutes: method(_void(), array(AddonHttpRouteSchema)),
|
|
13064
|
+
/**
|
|
13065
|
+
* Cross-process dispatch entry point. Forked addons implement this
|
|
13066
|
+
* (via `buildAddonRouteProvider`) so the hub's Fastify catch-all
|
|
13067
|
+
* can route through Moleculer when the handler lives in a worker.
|
|
13068
|
+
*
|
|
13069
|
+
* Local addons can implement it for free with the same helper;
|
|
13070
|
+
* the hub bypasses the wire on co-located addons.
|
|
13071
|
+
*/
|
|
13072
|
+
invoke: method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" })
|
|
13073
|
+
},
|
|
13074
|
+
/** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
|
|
13075
|
+
mount: { kind: "skip" }
|
|
13076
|
+
};
|
|
12699
13077
|
var ConfigTabDeclarationSchema = object({
|
|
12700
13078
|
id: string(),
|
|
12701
13079
|
label: string(),
|
|
@@ -12928,7 +13306,12 @@ var NotificationRuleConditionsSchema = object({
|
|
|
12928
13306
|
clipDescription: object({
|
|
12929
13307
|
text: string().min(1),
|
|
12930
13308
|
minSimilarity: number().min(0).max(1)
|
|
12931
|
-
}).optional()
|
|
13309
|
+
}).optional(),
|
|
13310
|
+
/** Match events whose recognized-entity label (face identity name or plate
|
|
13311
|
+
* vehicle name, propagated onto `event.data.label`) is one of these values.
|
|
13312
|
+
* Empty/absent → unaffected (back-compat). Enables "notify me when <named
|
|
13313
|
+
* vehicle/person> is seen". */
|
|
13314
|
+
labels: array(string()).readonly().optional()
|
|
12932
13315
|
});
|
|
12933
13316
|
var NotificationRuleTemplateSchema = object({
|
|
12934
13317
|
title: string(),
|
|
@@ -13186,11 +13569,19 @@ method(object({
|
|
|
13186
13569
|
* login page needs NO change.
|
|
13187
13570
|
*
|
|
13188
13571
|
* - `widget` — a Module-Federation widget the login page mounts (via
|
|
13189
|
-
* `loadRemoteBundle`) for an in-page ceremony.
|
|
13190
|
-
*
|
|
13191
|
-
*
|
|
13192
|
-
*
|
|
13193
|
-
*
|
|
13572
|
+
* `loadRemoteBundle`) for an in-page ceremony. `auth.listLoginMethods`
|
|
13573
|
+
* stamps a public `bundleUrl` from `addonId` + `bundle`. Generic
|
|
13574
|
+
* mechanism kept for future use; no shipped addon uses it on the login
|
|
13575
|
+
* page (the passkey ceremony below runs natively in the shell instead).
|
|
13576
|
+
*
|
|
13577
|
+
* - `passkey` — a declarative WebAuthn ceremony the shell renders
|
|
13578
|
+
* natively (`@simplewebauthn/browser` lives in `addon-admin-ui`, not in
|
|
13579
|
+
* a remotely-loaded bundle). Carries the addon's effective `rpId` /
|
|
13580
|
+
* `origin` (from its `resolveRpID()` / `resolveOrigin()`) so the shell
|
|
13581
|
+
* can gate visibility (IP-literal origin, hostname/rpId mismatch) WITHOUT
|
|
13582
|
+
* fetching any remote code pre-auth. Contribution stays unconditional —
|
|
13583
|
+
* enrollment state is never leaked pre-auth; visibility is a shell
|
|
13584
|
+
* decision.
|
|
13194
13585
|
*
|
|
13195
13586
|
* Every contribution carries a `stage`:
|
|
13196
13587
|
* - `primary` — shown on the first credentials screen (OIDC /
|
|
@@ -13204,30 +13595,45 @@ method(object({
|
|
|
13204
13595
|
*/
|
|
13205
13596
|
/** When a login method renders in the two-phase login flow. */
|
|
13206
13597
|
var LoginStageEnum = _enum(["primary", "second-factor"]);
|
|
13207
|
-
/** One login-method contribution — redirect button
|
|
13208
|
-
var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13598
|
+
/** One login-method contribution — redirect button, pre-auth widget, or native passkey ceremony. */
|
|
13599
|
+
var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
13600
|
+
object({
|
|
13601
|
+
kind: literal("redirect"),
|
|
13602
|
+
/** Stable id within the login-method set (e.g. `auth-oidc/google`). */
|
|
13603
|
+
id: string(),
|
|
13604
|
+
/** Operator-facing button label. */
|
|
13605
|
+
label: string(),
|
|
13606
|
+
/** lucide-react icon name. */
|
|
13607
|
+
icon: string().optional(),
|
|
13608
|
+
/** Addon-owned HTTP route the button navigates to (GET). */
|
|
13609
|
+
startUrl: string(),
|
|
13610
|
+
stage: LoginStageEnum
|
|
13611
|
+
}),
|
|
13612
|
+
object({
|
|
13613
|
+
kind: literal("widget"),
|
|
13614
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
|
|
13615
|
+
id: string(),
|
|
13616
|
+
/** Owning addon id — drives the public bundle URL + the MF namespace. */
|
|
13617
|
+
addonId: string(),
|
|
13618
|
+
/** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
|
|
13619
|
+
bundle: string(),
|
|
13620
|
+
/** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
|
|
13621
|
+
remote: WidgetRemoteSchema,
|
|
13622
|
+
stage: LoginStageEnum
|
|
13623
|
+
}),
|
|
13624
|
+
object({
|
|
13625
|
+
kind: literal("passkey"),
|
|
13626
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-direct-login`). */
|
|
13627
|
+
id: string(),
|
|
13628
|
+
/** Operator-facing button label. */
|
|
13629
|
+
label: string(),
|
|
13630
|
+
stage: LoginStageEnum,
|
|
13631
|
+
/** Effective WebAuthn RP ID (`resolveRpID()`) — the shell gates visibility on it. */
|
|
13632
|
+
rpId: string(),
|
|
13633
|
+
/** Effective expected origin (`resolveOrigin()`), null when unconfigured. */
|
|
13634
|
+
origin: string().nullable()
|
|
13635
|
+
})
|
|
13636
|
+
]);
|
|
13231
13637
|
method(_void(), array(LoginMethodContributionSchema).readonly());
|
|
13232
13638
|
/**
|
|
13233
13639
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
@@ -15055,14 +15461,14 @@ var TargetKindCapsSchema = object({
|
|
|
15055
15461
|
* the union is large and not meant for runtime validation here; the exported
|
|
15056
15462
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
15057
15463
|
*/
|
|
15058
|
-
var ConfigSchemaPassthrough = unknown();
|
|
15464
|
+
var ConfigSchemaPassthrough$1 = unknown();
|
|
15059
15465
|
var TargetKindSchema = object({
|
|
15060
15466
|
kind: string(),
|
|
15061
15467
|
label: string(),
|
|
15062
15468
|
icon: string(),
|
|
15063
15469
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
15064
15470
|
addonId: string(),
|
|
15065
|
-
configSchema: ConfigSchemaPassthrough,
|
|
15471
|
+
configSchema: ConfigSchemaPassthrough$1,
|
|
15066
15472
|
supportsDiscovery: boolean(),
|
|
15067
15473
|
caps: TargetKindCapsSchema
|
|
15068
15474
|
});
|
|
@@ -15129,6 +15535,298 @@ var notificationOutputCapability = {
|
|
|
15129
15535
|
}
|
|
15130
15536
|
};
|
|
15131
15537
|
/**
|
|
15538
|
+
* Shared LLM generate contracts — imported by BOTH `llm.cap.ts` (consumer
|
|
15539
|
+
* surface) and `llm-runtime.cap.ts` (node-side managed executor) so the two
|
|
15540
|
+
* caps stay wire-compatible without a circular cap→cap import.
|
|
15541
|
+
*
|
|
15542
|
+
* Errors are a discriminated-union RESULT, never thrown: the shape survives
|
|
15543
|
+
* every transport tier structurally, and failed calls still write usage rows.
|
|
15544
|
+
* Token counts only in v1 — no costUsd (operator decision, 2026-07-15).
|
|
15545
|
+
*/
|
|
15546
|
+
var LlmUsageSchema = object({
|
|
15547
|
+
inputTokens: number(),
|
|
15548
|
+
outputTokens: number()
|
|
15549
|
+
});
|
|
15550
|
+
var LlmErrorCodeSchema = _enum([
|
|
15551
|
+
"timeout",
|
|
15552
|
+
"rate-limited",
|
|
15553
|
+
"auth",
|
|
15554
|
+
"refusal",
|
|
15555
|
+
"bad-request",
|
|
15556
|
+
"unavailable",
|
|
15557
|
+
"no-profile",
|
|
15558
|
+
"budget-exceeded",
|
|
15559
|
+
"adapter-error"
|
|
15560
|
+
]);
|
|
15561
|
+
var LlmGenerateResultSchema = discriminatedUnion("ok", [object({
|
|
15562
|
+
ok: literal(true),
|
|
15563
|
+
text: string(),
|
|
15564
|
+
model: string(),
|
|
15565
|
+
usage: LlmUsageSchema,
|
|
15566
|
+
truncated: boolean(),
|
|
15567
|
+
latencyMs: number()
|
|
15568
|
+
}), object({
|
|
15569
|
+
ok: literal(false),
|
|
15570
|
+
code: LlmErrorCodeSchema,
|
|
15571
|
+
message: string(),
|
|
15572
|
+
retryAfterMs: number().optional()
|
|
15573
|
+
})]);
|
|
15574
|
+
/**
|
|
15575
|
+
* `Uint8Array` is the sanctioned binary convention — superjson + the UDS
|
|
15576
|
+
* MsgPack channel round-trip typed arrays (embedding-encoder.cap.ts:29,
|
|
15577
|
+
* notification-output.cap.ts:27-31 precedents).
|
|
15578
|
+
*/
|
|
15579
|
+
var LlmImageSchema = object({
|
|
15580
|
+
bytes: _instanceof(Uint8Array),
|
|
15581
|
+
mimeType: string()
|
|
15582
|
+
});
|
|
15583
|
+
var LlmGenerateBaseInputSchema = object({
|
|
15584
|
+
/** Collection routing (the notification-output posture). */
|
|
15585
|
+
addonId: string().optional(),
|
|
15586
|
+
/** Explicit profile; else the resolution chain (spec §3). */
|
|
15587
|
+
profileId: string().optional(),
|
|
15588
|
+
/** MANDATORY usage tag: 'ai-summary', 'notifier-rules', 'adhoc-ui', … */
|
|
15589
|
+
consumer: string(),
|
|
15590
|
+
system: string().optional(),
|
|
15591
|
+
/** v1: single-turn. `messages[]` is a v2 additive field. */
|
|
15592
|
+
prompt: string(),
|
|
15593
|
+
/** Structured output — adapter-mapped (response_format / forced tool / responseSchema). */
|
|
15594
|
+
jsonSchema: record(string(), unknown()).optional(),
|
|
15595
|
+
/** Per-call override of the profile default. */
|
|
15596
|
+
maxTokens: number().int().positive().optional(),
|
|
15597
|
+
temperature: number().optional()
|
|
15598
|
+
});
|
|
15599
|
+
/**
|
|
15600
|
+
* `llm-runtime` — node-side managed llama.cpp executor (spec §4). Registered
|
|
15601
|
+
* on EVERY node where `addon-ai` is installed; the hub `llm` provider reaches
|
|
15602
|
+
* a specific node's runtime with `nodePin(profile.runtime.nodeId)` — normal
|
|
15603
|
+
* cap routing, zero bespoke plumbing. `internal: true`: the operator reaches
|
|
15604
|
+
* this only through the `llm` cap's methods.
|
|
15605
|
+
*
|
|
15606
|
+
* One running llama-server child per node in v1 (models are RAM-heavy).
|
|
15607
|
+
* Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
|
|
15608
|
+
* watchdog — operator decision #3).
|
|
15609
|
+
*/
|
|
15610
|
+
var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
15611
|
+
object({
|
|
15612
|
+
kind: literal("catalog"),
|
|
15613
|
+
catalogId: string()
|
|
15614
|
+
}),
|
|
15615
|
+
object({
|
|
15616
|
+
kind: literal("url"),
|
|
15617
|
+
url: string(),
|
|
15618
|
+
sha256: string().optional()
|
|
15619
|
+
}),
|
|
15620
|
+
object({
|
|
15621
|
+
kind: literal("path"),
|
|
15622
|
+
path: string()
|
|
15623
|
+
})
|
|
15624
|
+
]);
|
|
15625
|
+
var ManagedRuntimeConfigSchema = object({
|
|
15626
|
+
/** WHERE the runtime lives — hub or any agent. */
|
|
15627
|
+
nodeId: string(),
|
|
15628
|
+
/** Closed for v1; 'ollama' is a v2 candidate. */
|
|
15629
|
+
engine: _enum(["llama-cpp"]),
|
|
15630
|
+
model: ManagedModelRefSchema,
|
|
15631
|
+
contextSize: number().int().default(4096),
|
|
15632
|
+
/** 0 = CPU-only. */
|
|
15633
|
+
gpuLayers: number().int().default(0),
|
|
15634
|
+
/** Default: cpus-2, clamped ≥1 (resolved node-side). */
|
|
15635
|
+
threads: number().int().optional(),
|
|
15636
|
+
/** Concurrent slots. */
|
|
15637
|
+
parallel: number().int().default(1),
|
|
15638
|
+
/** Else lazy: first generate boots it. */
|
|
15639
|
+
autoStart: boolean().default(false),
|
|
15640
|
+
/** 0 = never; frees RAM after quiet periods. */
|
|
15641
|
+
idleStopMinutes: number().int().default(30)
|
|
15642
|
+
});
|
|
15643
|
+
var LlmRuntimeStatusSchema = object({
|
|
15644
|
+
/** Status is ALWAYS node-qualified. */
|
|
15645
|
+
nodeId: string(),
|
|
15646
|
+
state: _enum([
|
|
15647
|
+
"stopped",
|
|
15648
|
+
"downloading",
|
|
15649
|
+
"starting",
|
|
15650
|
+
"ready",
|
|
15651
|
+
"crashed",
|
|
15652
|
+
"failed"
|
|
15653
|
+
]),
|
|
15654
|
+
pid: number().optional(),
|
|
15655
|
+
port: number().optional(),
|
|
15656
|
+
modelPath: string().optional(),
|
|
15657
|
+
modelId: string().optional(),
|
|
15658
|
+
downloadProgress: number().min(0).max(1).optional(),
|
|
15659
|
+
lastError: string().optional(),
|
|
15660
|
+
crashesInWindow: number(),
|
|
15661
|
+
/** Child RSS (sampled best-effort). */
|
|
15662
|
+
memoryBytes: number().optional(),
|
|
15663
|
+
vramBytes: number().optional()
|
|
15664
|
+
});
|
|
15665
|
+
var LlmNodeModelSchema = object({
|
|
15666
|
+
file: string(),
|
|
15667
|
+
sizeBytes: number(),
|
|
15668
|
+
catalogId: string().optional(),
|
|
15669
|
+
installedAt: number().optional()
|
|
15670
|
+
});
|
|
15671
|
+
var LlmRuntimeDiskUsageSchema = object({
|
|
15672
|
+
nodeId: string(),
|
|
15673
|
+
modelsBytes: number(),
|
|
15674
|
+
freeBytes: number().optional()
|
|
15675
|
+
});
|
|
15676
|
+
method(LlmGenerateBaseInputSchema.extend({
|
|
15677
|
+
images: array(LlmImageSchema).optional(),
|
|
15678
|
+
runtime: ManagedRuntimeConfigSchema,
|
|
15679
|
+
/** The managed profile's timeout, threaded by the hub provider. */
|
|
15680
|
+
timeoutMs: number().int().positive().optional()
|
|
15681
|
+
}), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
|
|
15682
|
+
kind: "mutation",
|
|
15683
|
+
auth: "admin"
|
|
15684
|
+
}), method(object({}), _void(), {
|
|
15685
|
+
kind: "mutation",
|
|
15686
|
+
auth: "admin"
|
|
15687
|
+
}), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
|
|
15688
|
+
kind: "mutation",
|
|
15689
|
+
auth: "admin"
|
|
15690
|
+
}), method(object({ file: string() }), _void(), {
|
|
15691
|
+
kind: "mutation",
|
|
15692
|
+
auth: "admin"
|
|
15693
|
+
}), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
|
|
15694
|
+
/**
|
|
15695
|
+
* `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
|
|
15696
|
+
* methods concat-fan across providers; single-row methods route to ONE
|
|
15697
|
+
* provider by the `addonId` in the call input (the notification-output
|
|
15698
|
+
* posture, notification-output.cap.ts:215-250). Provided by `addon-ai`
|
|
15699
|
+
* (hub-placed); the cap stays open for future providers.
|
|
15700
|
+
*
|
|
15701
|
+
* Profiles are ROWS (data), not addons: one row = one usable model endpoint.
|
|
15702
|
+
* `apiKey` is a password field — providers REDACT it on read and merge on
|
|
15703
|
+
* write; a stored key NEVER round-trips to a client.
|
|
15704
|
+
*/
|
|
15705
|
+
var LlmProfileKindSchema = _enum([
|
|
15706
|
+
"openai-compatible",
|
|
15707
|
+
"openai",
|
|
15708
|
+
"anthropic",
|
|
15709
|
+
"google",
|
|
15710
|
+
"managed-local"
|
|
15711
|
+
]);
|
|
15712
|
+
var LlmProfileSchema = object({
|
|
15713
|
+
id: string(),
|
|
15714
|
+
name: string(),
|
|
15715
|
+
kind: LlmProfileKindSchema,
|
|
15716
|
+
/** Stamped by the provider — keeps the fanned catalog routable. */
|
|
15717
|
+
addonId: string(),
|
|
15718
|
+
enabled: boolean(),
|
|
15719
|
+
/** Vendor model id, or the managed runtime's loaded model. */
|
|
15720
|
+
model: string(),
|
|
15721
|
+
/** Required for openai-compatible; override for cloud kinds. */
|
|
15722
|
+
baseUrl: string().optional(),
|
|
15723
|
+
/** ConfigUISchema type:'password' — never round-trips (spec §5). */
|
|
15724
|
+
apiKey: string().optional(),
|
|
15725
|
+
supportsVision: boolean(),
|
|
15726
|
+
temperature: number().min(0).max(2).optional(),
|
|
15727
|
+
maxTokens: number().int().positive().optional(),
|
|
15728
|
+
timeoutMs: number().int().positive().default(6e4),
|
|
15729
|
+
extraHeaders: record(string(), string()).optional(),
|
|
15730
|
+
/** kind === 'managed-local' only (spec §4). */
|
|
15731
|
+
runtime: ManagedRuntimeConfigSchema.optional()
|
|
15732
|
+
});
|
|
15733
|
+
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
15734
|
+
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
15735
|
+
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
15736
|
+
var ConfigSchemaPassthrough = unknown();
|
|
15737
|
+
var LlmProfileKindDescriptorSchema = object({
|
|
15738
|
+
kind: LlmProfileKindSchema,
|
|
15739
|
+
label: string(),
|
|
15740
|
+
icon: string(),
|
|
15741
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
15742
|
+
addonId: string(),
|
|
15743
|
+
configSchema: ConfigSchemaPassthrough
|
|
15744
|
+
});
|
|
15745
|
+
var LlmDefaultSelectorSchema = union([object({ consumer: string() }), object({ purpose: _enum(["text", "vision"]) })]);
|
|
15746
|
+
var LlmDefaultSchema = object({
|
|
15747
|
+
selector: LlmDefaultSelectorSchema,
|
|
15748
|
+
profileId: string()
|
|
15749
|
+
});
|
|
15750
|
+
/** Server-side rollup row — getUsage never dumps raw call rows (spec §6). */
|
|
15751
|
+
var LlmUsageRollupSchema = object({
|
|
15752
|
+
day: string(),
|
|
15753
|
+
consumer: string(),
|
|
15754
|
+
profileId: string(),
|
|
15755
|
+
calls: number(),
|
|
15756
|
+
okCalls: number(),
|
|
15757
|
+
errorCalls: number(),
|
|
15758
|
+
inputTokens: number(),
|
|
15759
|
+
outputTokens: number(),
|
|
15760
|
+
avgLatencyMs: number()
|
|
15761
|
+
});
|
|
15762
|
+
/** LLM-facing view over the reused ModelCatalogEntry mechanism (spec §4.2). */
|
|
15763
|
+
var ManagedModelCatalogEntrySchema = object({
|
|
15764
|
+
id: string(),
|
|
15765
|
+
label: string(),
|
|
15766
|
+
family: string(),
|
|
15767
|
+
purpose: _enum(["text", "vision"]),
|
|
15768
|
+
url: string(),
|
|
15769
|
+
sha256: string(),
|
|
15770
|
+
sizeBytes: number(),
|
|
15771
|
+
quantization: string(),
|
|
15772
|
+
/** Load-time guidance shown in the picker. */
|
|
15773
|
+
minRamBytes: number(),
|
|
15774
|
+
contextSizeDefault: number().int(),
|
|
15775
|
+
/** Vision models: companion projector file. */
|
|
15776
|
+
mmprojUrl: string().optional()
|
|
15777
|
+
});
|
|
15778
|
+
var LlmRuntimeNodeSchema = object({
|
|
15779
|
+
nodeId: string(),
|
|
15780
|
+
reachable: boolean(),
|
|
15781
|
+
status: LlmRuntimeStatusSchema.optional(),
|
|
15782
|
+
disk: LlmRuntimeDiskUsageSchema.optional(),
|
|
15783
|
+
error: string().optional()
|
|
15784
|
+
});
|
|
15785
|
+
var GenerateVisionInputSchema = LlmGenerateBaseInputSchema.extend({ images: array(LlmImageSchema).min(1) });
|
|
15786
|
+
var ProfileRefInputSchema = object({
|
|
15787
|
+
addonId: string(),
|
|
15788
|
+
profileId: string()
|
|
15789
|
+
});
|
|
15790
|
+
method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(GenerateVisionInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
|
|
15791
|
+
kind: "mutation",
|
|
15792
|
+
auth: "admin"
|
|
15793
|
+
}), method(ProfileRefInputSchema, _void(), {
|
|
15794
|
+
kind: "mutation",
|
|
15795
|
+
auth: "admin"
|
|
15796
|
+
}), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
|
|
15797
|
+
kind: "mutation",
|
|
15798
|
+
auth: "admin"
|
|
15799
|
+
}), method(ProfileRefInputSchema, array(string())), method(object({}), array(LlmDefaultSchema)), method(object({
|
|
15800
|
+
selector: LlmDefaultSelectorSchema,
|
|
15801
|
+
profileId: string().nullable()
|
|
15802
|
+
}), _void(), {
|
|
15803
|
+
kind: "mutation",
|
|
15804
|
+
auth: "admin"
|
|
15805
|
+
}), method(object({
|
|
15806
|
+
since: number().optional(),
|
|
15807
|
+
until: number().optional(),
|
|
15808
|
+
consumer: string().optional(),
|
|
15809
|
+
profileId: string().optional()
|
|
15810
|
+
}), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
|
|
15811
|
+
nodeId: string(),
|
|
15812
|
+
model: ManagedModelRefSchema
|
|
15813
|
+
}), _void(), {
|
|
15814
|
+
kind: "mutation",
|
|
15815
|
+
auth: "admin"
|
|
15816
|
+
}), method(object({
|
|
15817
|
+
nodeId: string(),
|
|
15818
|
+
file: string()
|
|
15819
|
+
}), _void(), {
|
|
15820
|
+
kind: "mutation",
|
|
15821
|
+
auth: "admin"
|
|
15822
|
+
}), method(ProfileRefInputSchema, LlmRuntimeStatusSchema), method(ProfileRefInputSchema, LlmRuntimeStatusSchema, {
|
|
15823
|
+
kind: "mutation",
|
|
15824
|
+
auth: "admin"
|
|
15825
|
+
}), method(ProfileRefInputSchema, _void(), {
|
|
15826
|
+
kind: "mutation",
|
|
15827
|
+
auth: "admin"
|
|
15828
|
+
});
|
|
15829
|
+
/**
|
|
15132
15830
|
* Zod schemas for persisted record types.
|
|
15133
15831
|
*
|
|
15134
15832
|
* These schemas serve as the single source of truth for types that are
|
|
@@ -15330,6 +16028,22 @@ var TrackSnapshotSchema = object({
|
|
|
15330
16028
|
/** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
|
|
15331
16029
|
mediaKey: string()
|
|
15332
16030
|
});
|
|
16031
|
+
/**
|
|
16032
|
+
* One audio-classification label heard on the track's camera while the
|
|
16033
|
+
* track was alive, aggregated per label. An "episode" is one persisted
|
|
16034
|
+
* audio event (the confident-classification path: score ≥ the device's
|
|
16035
|
+
* `classificationMinScore`, class-change-or-heartbeat coalesced) — NOT
|
|
16036
|
+
* one 32 ms inference chunk, so counts stay human-scaled.
|
|
16037
|
+
*/
|
|
16038
|
+
var TrackAudioLabelSchema = object({
|
|
16039
|
+
label: string(),
|
|
16040
|
+
/** Highest classification score observed across the label's episodes. */
|
|
16041
|
+
peakScore: number(),
|
|
16042
|
+
/** Number of coalesced audio-event episodes carrying this label. */
|
|
16043
|
+
count: number(),
|
|
16044
|
+
firstAt: number(),
|
|
16045
|
+
lastAt: number()
|
|
16046
|
+
});
|
|
15333
16047
|
var TrackSchema = object({
|
|
15334
16048
|
trackId: string(),
|
|
15335
16049
|
deviceId: number(),
|
|
@@ -15344,6 +16058,10 @@ var TrackSchema = object({
|
|
|
15344
16058
|
snapshots: array(TrackSnapshotSchema).readonly(),
|
|
15345
16059
|
/** Deduplicated zones the track has entered at least once. */
|
|
15346
16060
|
zonesVisited: array(string()).readonly(),
|
|
16061
|
+
/** Deduplicated set of detector classes observed for this track over its
|
|
16062
|
+
* life (a track may be reclassified, e.g. person→vehicle). Absent on
|
|
16063
|
+
* legacy rows written before class accumulation shipped. */
|
|
16064
|
+
classes: array(string()).readonly().optional(),
|
|
15347
16065
|
/** Cumulative normalized distance travelled (0..1 units = full frame width). */
|
|
15348
16066
|
totalDistance: number(),
|
|
15349
16067
|
state: TrackStateSchema,
|
|
@@ -15357,7 +16075,11 @@ var TrackSchema = object({
|
|
|
15357
16075
|
bestEventId: string().optional(),
|
|
15358
16076
|
/** Tag of the importance sub-signal that dominated the score
|
|
15359
16077
|
* (identity|dwell|proximity|class|confidence|travel|zone). */
|
|
15360
|
-
importanceReason: string().optional()
|
|
16078
|
+
importanceReason: string().optional(),
|
|
16079
|
+
/** Audio-classification labels heard on the camera during the track's
|
|
16080
|
+
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
16081
|
+
* Absent on legacy rows / tracks with no confident audio. */
|
|
16082
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
15361
16083
|
});
|
|
15362
16084
|
var BaseEventFields = {
|
|
15363
16085
|
id: string(),
|
|
@@ -15505,7 +16227,7 @@ var KeyEventSchema = object({
|
|
|
15505
16227
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
15506
16228
|
windowMs: number().optional()
|
|
15507
16229
|
});
|
|
15508
|
-
|
|
16230
|
+
object({
|
|
15509
16231
|
trackId: string(),
|
|
15510
16232
|
className: string(),
|
|
15511
16233
|
confidence: number(),
|
|
@@ -15513,7 +16235,24 @@ var TrackedDetectionSchema = object({
|
|
|
15513
16235
|
zones: array(string()).readonly(),
|
|
15514
16236
|
state: TrackStateSchema
|
|
15515
16237
|
});
|
|
15516
|
-
var
|
|
16238
|
+
var OverlayDetectionSchema = looseObject({
|
|
16239
|
+
id: string(),
|
|
16240
|
+
kind: _enum(["first-level", "detail"]),
|
|
16241
|
+
macroClass: string(),
|
|
16242
|
+
score: number(),
|
|
16243
|
+
bbox: object({
|
|
16244
|
+
x: number(),
|
|
16245
|
+
y: number(),
|
|
16246
|
+
width: number(),
|
|
16247
|
+
height: number()
|
|
16248
|
+
}),
|
|
16249
|
+
labels: array(looseObject({
|
|
16250
|
+
label: string(),
|
|
16251
|
+
score: number()
|
|
16252
|
+
})).readonly(),
|
|
16253
|
+
parentId: string().optional()
|
|
16254
|
+
});
|
|
16255
|
+
var ScoredObjectEventSchema = ObjectEventSchema.extend({ score: number() });
|
|
15517
16256
|
var SearchObjectEventsInput = object({
|
|
15518
16257
|
text: string(),
|
|
15519
16258
|
deviceId: number().optional(),
|
|
@@ -15523,6 +16262,20 @@ var SearchObjectEventsInput = object({
|
|
|
15523
16262
|
limit: number().default(50),
|
|
15524
16263
|
minScore: number().min(0).max(1).default(.2)
|
|
15525
16264
|
});
|
|
16265
|
+
var TrackCascadeCountsSchema = object({
|
|
16266
|
+
/** Persisted track roots deleted (authoritative). */
|
|
16267
|
+
tracks: number().int(),
|
|
16268
|
+
/** Object events removed with their tracks (best-effort; see note above). */
|
|
16269
|
+
events: number().int(),
|
|
16270
|
+
/** Track/face/plate-owned media removed (best-effort). Never identity media. */
|
|
16271
|
+
media: number().int(),
|
|
16272
|
+
/** Unassigned (non-enrolled) face reads removed (best-effort). */
|
|
16273
|
+
faces: number().int(),
|
|
16274
|
+
/** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
|
|
16275
|
+
plates: number().int(),
|
|
16276
|
+
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16277
|
+
embeddings: number().int()
|
|
16278
|
+
});
|
|
15526
16279
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
15527
16280
|
deviceId: number(),
|
|
15528
16281
|
trackId: string()
|
|
@@ -15554,6 +16307,24 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15554
16307
|
}), {
|
|
15555
16308
|
kind: "mutation",
|
|
15556
16309
|
auth: "admin"
|
|
16310
|
+
}), method(object({
|
|
16311
|
+
deviceId: number(),
|
|
16312
|
+
cutoffMs: number()
|
|
16313
|
+
}), TrackCascadeCountsSchema, {
|
|
16314
|
+
kind: "mutation",
|
|
16315
|
+
auth: "admin"
|
|
16316
|
+
}), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
|
|
16317
|
+
kind: "mutation",
|
|
16318
|
+
auth: "admin"
|
|
16319
|
+
}), method(object({
|
|
16320
|
+
deviceId: number(),
|
|
16321
|
+
trackIds: array(string()).min(1)
|
|
16322
|
+
}), object({
|
|
16323
|
+
deleted: number().int(),
|
|
16324
|
+
failed: array(string()).readonly()
|
|
16325
|
+
}), {
|
|
16326
|
+
kind: "mutation",
|
|
16327
|
+
auth: "admin"
|
|
15557
16328
|
}), method(object({
|
|
15558
16329
|
eventId: string(),
|
|
15559
16330
|
kind: MediaFileKindEnum.optional()
|
|
@@ -15562,7 +16333,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
15562
16333
|
timestamp: number(),
|
|
15563
16334
|
frameWidth: number(),
|
|
15564
16335
|
frameHeight: number(),
|
|
15565
|
-
detections: array(
|
|
16336
|
+
detections: array(OverlayDetectionSchema).readonly()
|
|
15566
16337
|
}), object({
|
|
15567
16338
|
deviceId: number(),
|
|
15568
16339
|
trackId: string(),
|
|
@@ -18331,6 +19102,24 @@ DeviceType.Camera, method(object({
|
|
|
18331
19102
|
deviceId: number(),
|
|
18332
19103
|
status: OsdStatusSchema
|
|
18333
19104
|
});
|
|
19105
|
+
var VehicleSchema = object({
|
|
19106
|
+
id: string(),
|
|
19107
|
+
name: string(),
|
|
19108
|
+
sampleCount: number().int().nonnegative(),
|
|
19109
|
+
coverMediaKey: string().optional(),
|
|
19110
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
|
|
19111
|
+
coverBase64: string().optional()
|
|
19112
|
+
});
|
|
19113
|
+
var VehicleSampleInfoSchema = object({
|
|
19114
|
+
id: string(),
|
|
19115
|
+
/** The plate text this sample enrolled (self-labeling — no embedding). */
|
|
19116
|
+
text: string(),
|
|
19117
|
+
/** OCR confidence of the enrolled read (0..1). */
|
|
19118
|
+
score: number(),
|
|
19119
|
+
addedAt: number().int(),
|
|
19120
|
+
deviceId: number().int().optional(),
|
|
19121
|
+
base64: string().optional()
|
|
19122
|
+
});
|
|
18334
19123
|
var PlateInfoSchema = object({
|
|
18335
19124
|
plateId: string(),
|
|
18336
19125
|
deviceId: number().int(),
|
|
@@ -18342,6 +19131,16 @@ var PlateInfoSchema = object({
|
|
|
18342
19131
|
score: number(),
|
|
18343
19132
|
/** True when the text was manually corrected (exempt from retention). */
|
|
18344
19133
|
corrected: boolean(),
|
|
19134
|
+
/** Recognized vehicle id when a matcher lookup named this read (SQL NULL → absent). */
|
|
19135
|
+
recognizedVehicleId: string().optional(),
|
|
19136
|
+
/** Resolved vehicle name for `recognizedVehicleId` (UI convenience). */
|
|
19137
|
+
vehicleName: string().optional(),
|
|
19138
|
+
/** True once the read was assigned to a vehicle (enrolled as a sample). */
|
|
19139
|
+
assigned: boolean(),
|
|
19140
|
+
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
19141
|
+
plateBbox: BoundingBoxSchema.optional(),
|
|
19142
|
+
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
19143
|
+
keyFrameMediaKey: string().optional(),
|
|
18345
19144
|
base64: string().optional()
|
|
18346
19145
|
});
|
|
18347
19146
|
var MediaFileLiteSchema = object({
|
|
@@ -18381,6 +19180,48 @@ method(object({
|
|
|
18381
19180
|
}), method(object({ plateId: string() }), _void(), {
|
|
18382
19181
|
kind: "mutation",
|
|
18383
19182
|
auth: "admin"
|
|
19183
|
+
}), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
19184
|
+
kind: "mutation",
|
|
19185
|
+
auth: "admin"
|
|
19186
|
+
}), method(object({
|
|
19187
|
+
id: string(),
|
|
19188
|
+
name: string().min(1)
|
|
19189
|
+
}), _void(), {
|
|
19190
|
+
kind: "mutation",
|
|
19191
|
+
auth: "admin"
|
|
19192
|
+
}), method(object({ id: string() }), _void(), {
|
|
19193
|
+
kind: "mutation",
|
|
19194
|
+
auth: "admin"
|
|
19195
|
+
}), method(object({ vehicleId: string() }), array(VehicleSampleInfoSchema).readonly()), method(object({
|
|
19196
|
+
vehicleId: string(),
|
|
19197
|
+
sampleId: string()
|
|
19198
|
+
}), _void(), {
|
|
19199
|
+
kind: "mutation",
|
|
19200
|
+
auth: "admin"
|
|
19201
|
+
}), method(object({
|
|
19202
|
+
plateId: string(),
|
|
19203
|
+
vehicleId: string()
|
|
19204
|
+
}), _void(), {
|
|
19205
|
+
kind: "mutation",
|
|
19206
|
+
auth: "admin"
|
|
19207
|
+
}), method(object({ plateId: string() }), _void(), {
|
|
19208
|
+
kind: "mutation",
|
|
19209
|
+
auth: "admin"
|
|
19210
|
+
}), method(object({
|
|
19211
|
+
plateIds: array(string()).min(1),
|
|
19212
|
+
vehicleId: string()
|
|
19213
|
+
}), object({
|
|
19214
|
+
assigned: number().int(),
|
|
19215
|
+
failed: array(string()).readonly()
|
|
19216
|
+
}), {
|
|
19217
|
+
kind: "mutation",
|
|
19218
|
+
auth: "admin"
|
|
19219
|
+
}), method(object({ plateIds: array(string()).min(1) }), object({
|
|
19220
|
+
unassigned: number().int(),
|
|
19221
|
+
failed: array(string()).readonly()
|
|
19222
|
+
}), {
|
|
19223
|
+
kind: "mutation",
|
|
19224
|
+
auth: "admin"
|
|
18384
19225
|
});
|
|
18385
19226
|
var ModelFormatSchema = _enum(MODEL_FORMATS);
|
|
18386
19227
|
var HwAccelBackendInputSchema = _enum([
|
|
@@ -18459,6 +19300,10 @@ var GpuInfoSchema = object({
|
|
|
18459
19300
|
memoryMB: number().optional()
|
|
18460
19301
|
});
|
|
18461
19302
|
var NpuInfoSchema = object({ type: _enum(["apple-ane", "intel-npu"]) });
|
|
19303
|
+
var CoralInfoSchema = object({
|
|
19304
|
+
type: literal("coral-edgetpu"),
|
|
19305
|
+
bus: string().optional()
|
|
19306
|
+
});
|
|
18462
19307
|
var HardwareInfoSchema = object({
|
|
18463
19308
|
platform: HardwarePlatformSchema,
|
|
18464
19309
|
arch: HardwareArchSchema,
|
|
@@ -18467,7 +19312,8 @@ var HardwareInfoSchema = object({
|
|
|
18467
19312
|
totalRAM_MB: number(),
|
|
18468
19313
|
availableRAM_MB: number(),
|
|
18469
19314
|
gpu: GpuInfoSchema.nullable(),
|
|
18470
|
-
npu: NpuInfoSchema.nullable()
|
|
19315
|
+
npu: NpuInfoSchema.nullable(),
|
|
19316
|
+
coral: CoralInfoSchema.nullable().optional()
|
|
18471
19317
|
});
|
|
18472
19318
|
var PlatformScoreSchema = object({
|
|
18473
19319
|
runtime: _enum(["node", "python"]),
|
|
@@ -20926,6 +21772,168 @@ Object.freeze({
|
|
|
20926
21772
|
addonId: null,
|
|
20927
21773
|
access: "create"
|
|
20928
21774
|
},
|
|
21775
|
+
"llm.deleteModel": {
|
|
21776
|
+
capName: "llm",
|
|
21777
|
+
capScope: "system",
|
|
21778
|
+
addonId: null,
|
|
21779
|
+
access: "delete"
|
|
21780
|
+
},
|
|
21781
|
+
"llm.deleteProfile": {
|
|
21782
|
+
capName: "llm",
|
|
21783
|
+
capScope: "system",
|
|
21784
|
+
addonId: null,
|
|
21785
|
+
access: "delete"
|
|
21786
|
+
},
|
|
21787
|
+
"llm.generate": {
|
|
21788
|
+
capName: "llm",
|
|
21789
|
+
capScope: "system",
|
|
21790
|
+
addonId: null,
|
|
21791
|
+
access: "create"
|
|
21792
|
+
},
|
|
21793
|
+
"llm.generateVision": {
|
|
21794
|
+
capName: "llm",
|
|
21795
|
+
capScope: "system",
|
|
21796
|
+
addonId: null,
|
|
21797
|
+
access: "create"
|
|
21798
|
+
},
|
|
21799
|
+
"llm.getDefaults": {
|
|
21800
|
+
capName: "llm",
|
|
21801
|
+
capScope: "system",
|
|
21802
|
+
addonId: null,
|
|
21803
|
+
access: "view"
|
|
21804
|
+
},
|
|
21805
|
+
"llm.getRuntimeStatus": {
|
|
21806
|
+
capName: "llm",
|
|
21807
|
+
capScope: "system",
|
|
21808
|
+
addonId: null,
|
|
21809
|
+
access: "view"
|
|
21810
|
+
},
|
|
21811
|
+
"llm.getUsage": {
|
|
21812
|
+
capName: "llm",
|
|
21813
|
+
capScope: "system",
|
|
21814
|
+
addonId: null,
|
|
21815
|
+
access: "view"
|
|
21816
|
+
},
|
|
21817
|
+
"llm.installModel": {
|
|
21818
|
+
capName: "llm",
|
|
21819
|
+
capScope: "system",
|
|
21820
|
+
addonId: null,
|
|
21821
|
+
access: "create"
|
|
21822
|
+
},
|
|
21823
|
+
"llm.listModelCatalog": {
|
|
21824
|
+
capName: "llm",
|
|
21825
|
+
capScope: "system",
|
|
21826
|
+
addonId: null,
|
|
21827
|
+
access: "view"
|
|
21828
|
+
},
|
|
21829
|
+
"llm.listModels": {
|
|
21830
|
+
capName: "llm",
|
|
21831
|
+
capScope: "system",
|
|
21832
|
+
addonId: null,
|
|
21833
|
+
access: "view"
|
|
21834
|
+
},
|
|
21835
|
+
"llm.listNodeModels": {
|
|
21836
|
+
capName: "llm",
|
|
21837
|
+
capScope: "system",
|
|
21838
|
+
addonId: null,
|
|
21839
|
+
access: "view"
|
|
21840
|
+
},
|
|
21841
|
+
"llm.listProfileKinds": {
|
|
21842
|
+
capName: "llm",
|
|
21843
|
+
capScope: "system",
|
|
21844
|
+
addonId: null,
|
|
21845
|
+
access: "view"
|
|
21846
|
+
},
|
|
21847
|
+
"llm.listProfiles": {
|
|
21848
|
+
capName: "llm",
|
|
21849
|
+
capScope: "system",
|
|
21850
|
+
addonId: null,
|
|
21851
|
+
access: "view"
|
|
21852
|
+
},
|
|
21853
|
+
"llm.listRuntimeNodes": {
|
|
21854
|
+
capName: "llm",
|
|
21855
|
+
capScope: "system",
|
|
21856
|
+
addonId: null,
|
|
21857
|
+
access: "view"
|
|
21858
|
+
},
|
|
21859
|
+
"llm.setDefault": {
|
|
21860
|
+
capName: "llm",
|
|
21861
|
+
capScope: "system",
|
|
21862
|
+
addonId: null,
|
|
21863
|
+
access: "create"
|
|
21864
|
+
},
|
|
21865
|
+
"llm.startRuntime": {
|
|
21866
|
+
capName: "llm",
|
|
21867
|
+
capScope: "system",
|
|
21868
|
+
addonId: null,
|
|
21869
|
+
access: "create"
|
|
21870
|
+
},
|
|
21871
|
+
"llm.stopRuntime": {
|
|
21872
|
+
capName: "llm",
|
|
21873
|
+
capScope: "system",
|
|
21874
|
+
addonId: null,
|
|
21875
|
+
access: "create"
|
|
21876
|
+
},
|
|
21877
|
+
"llm.testProfile": {
|
|
21878
|
+
capName: "llm",
|
|
21879
|
+
capScope: "system",
|
|
21880
|
+
addonId: null,
|
|
21881
|
+
access: "create"
|
|
21882
|
+
},
|
|
21883
|
+
"llm.upsertProfile": {
|
|
21884
|
+
capName: "llm",
|
|
21885
|
+
capScope: "system",
|
|
21886
|
+
addonId: null,
|
|
21887
|
+
access: "create"
|
|
21888
|
+
},
|
|
21889
|
+
"llmRuntime.complete": {
|
|
21890
|
+
capName: "llm-runtime",
|
|
21891
|
+
capScope: "system",
|
|
21892
|
+
addonId: null,
|
|
21893
|
+
access: "create"
|
|
21894
|
+
},
|
|
21895
|
+
"llmRuntime.deleteModel": {
|
|
21896
|
+
capName: "llm-runtime",
|
|
21897
|
+
capScope: "system",
|
|
21898
|
+
addonId: null,
|
|
21899
|
+
access: "delete"
|
|
21900
|
+
},
|
|
21901
|
+
"llmRuntime.ensureStarted": {
|
|
21902
|
+
capName: "llm-runtime",
|
|
21903
|
+
capScope: "system",
|
|
21904
|
+
addonId: null,
|
|
21905
|
+
access: "create"
|
|
21906
|
+
},
|
|
21907
|
+
"llmRuntime.getDiskUsage": {
|
|
21908
|
+
capName: "llm-runtime",
|
|
21909
|
+
capScope: "system",
|
|
21910
|
+
addonId: null,
|
|
21911
|
+
access: "view"
|
|
21912
|
+
},
|
|
21913
|
+
"llmRuntime.installModel": {
|
|
21914
|
+
capName: "llm-runtime",
|
|
21915
|
+
capScope: "system",
|
|
21916
|
+
addonId: null,
|
|
21917
|
+
access: "create"
|
|
21918
|
+
},
|
|
21919
|
+
"llmRuntime.listLocalModels": {
|
|
21920
|
+
capName: "llm-runtime",
|
|
21921
|
+
capScope: "system",
|
|
21922
|
+
addonId: null,
|
|
21923
|
+
access: "view"
|
|
21924
|
+
},
|
|
21925
|
+
"llmRuntime.status": {
|
|
21926
|
+
capName: "llm-runtime",
|
|
21927
|
+
capScope: "system",
|
|
21928
|
+
addonId: null,
|
|
21929
|
+
access: "view"
|
|
21930
|
+
},
|
|
21931
|
+
"llmRuntime.stop": {
|
|
21932
|
+
capName: "llm-runtime",
|
|
21933
|
+
capScope: "system",
|
|
21934
|
+
addonId: null,
|
|
21935
|
+
access: "create"
|
|
21936
|
+
},
|
|
20929
21937
|
"localNetwork.getAllowedAddresses": {
|
|
20930
21938
|
capName: "local-network",
|
|
20931
21939
|
capScope: "system",
|
|
@@ -21556,6 +22564,12 @@ Object.freeze({
|
|
|
21556
22564
|
addonId: null,
|
|
21557
22565
|
access: "delete"
|
|
21558
22566
|
},
|
|
22567
|
+
"pipelineAnalytics.deleteTracks": {
|
|
22568
|
+
capName: "pipeline-analytics",
|
|
22569
|
+
capScope: "device",
|
|
22570
|
+
addonId: null,
|
|
22571
|
+
access: "delete"
|
|
22572
|
+
},
|
|
21559
22573
|
"pipelineAnalytics.getActiveTracks": {
|
|
21560
22574
|
capName: "pipeline-analytics",
|
|
21561
22575
|
capScope: "device",
|
|
@@ -21622,12 +22636,24 @@ Object.freeze({
|
|
|
21622
22636
|
addonId: null,
|
|
21623
22637
|
access: "create"
|
|
21624
22638
|
},
|
|
22639
|
+
"pipelineAnalytics.pruneTracksBefore": {
|
|
22640
|
+
capName: "pipeline-analytics",
|
|
22641
|
+
capScope: "device",
|
|
22642
|
+
addonId: null,
|
|
22643
|
+
access: "create"
|
|
22644
|
+
},
|
|
21625
22645
|
"pipelineAnalytics.searchObjectEvents": {
|
|
21626
22646
|
capName: "pipeline-analytics",
|
|
21627
22647
|
capScope: "device",
|
|
21628
22648
|
addonId: null,
|
|
21629
22649
|
access: "view"
|
|
21630
22650
|
},
|
|
22651
|
+
"pipelineAnalytics.wipeAllAnalytics": {
|
|
22652
|
+
capName: "pipeline-analytics",
|
|
22653
|
+
capScope: "device",
|
|
22654
|
+
addonId: null,
|
|
22655
|
+
access: "delete"
|
|
22656
|
+
},
|
|
21631
22657
|
"pipelineExecutor.cacheFrameInPool": {
|
|
21632
22658
|
capName: "pipeline-executor",
|
|
21633
22659
|
capScope: "system",
|
|
@@ -22132,18 +23158,42 @@ Object.freeze({
|
|
|
22132
23158
|
addonId: null,
|
|
22133
23159
|
access: "create"
|
|
22134
23160
|
},
|
|
23161
|
+
"plateGallery.assignPlate": {
|
|
23162
|
+
capName: "plate-gallery",
|
|
23163
|
+
capScope: "system",
|
|
23164
|
+
addonId: null,
|
|
23165
|
+
access: "create"
|
|
23166
|
+
},
|
|
23167
|
+
"plateGallery.assignPlates": {
|
|
23168
|
+
capName: "plate-gallery",
|
|
23169
|
+
capScope: "system",
|
|
23170
|
+
addonId: null,
|
|
23171
|
+
access: "create"
|
|
23172
|
+
},
|
|
22135
23173
|
"plateGallery.correctPlateText": {
|
|
22136
23174
|
capName: "plate-gallery",
|
|
22137
23175
|
capScope: "system",
|
|
22138
23176
|
addonId: null,
|
|
22139
23177
|
access: "create"
|
|
22140
23178
|
},
|
|
23179
|
+
"plateGallery.createVehicle": {
|
|
23180
|
+
capName: "plate-gallery",
|
|
23181
|
+
capScope: "system",
|
|
23182
|
+
addonId: null,
|
|
23183
|
+
access: "create"
|
|
23184
|
+
},
|
|
22141
23185
|
"plateGallery.deletePlate": {
|
|
22142
23186
|
capName: "plate-gallery",
|
|
22143
23187
|
capScope: "system",
|
|
22144
23188
|
addonId: null,
|
|
22145
23189
|
access: "delete"
|
|
22146
23190
|
},
|
|
23191
|
+
"plateGallery.deleteVehicle": {
|
|
23192
|
+
capName: "plate-gallery",
|
|
23193
|
+
capScope: "system",
|
|
23194
|
+
addonId: null,
|
|
23195
|
+
access: "delete"
|
|
23196
|
+
},
|
|
22147
23197
|
"plateGallery.getPlateByTrack": {
|
|
22148
23198
|
capName: "plate-gallery",
|
|
22149
23199
|
capScope: "system",
|
|
@@ -22162,6 +23212,30 @@ Object.freeze({
|
|
|
22162
23212
|
addonId: null,
|
|
22163
23213
|
access: "view"
|
|
22164
23214
|
},
|
|
23215
|
+
"plateGallery.listVehicles": {
|
|
23216
|
+
capName: "plate-gallery",
|
|
23217
|
+
capScope: "system",
|
|
23218
|
+
addonId: null,
|
|
23219
|
+
access: "view"
|
|
23220
|
+
},
|
|
23221
|
+
"plateGallery.listVehicleSamples": {
|
|
23222
|
+
capName: "plate-gallery",
|
|
23223
|
+
capScope: "system",
|
|
23224
|
+
addonId: null,
|
|
23225
|
+
access: "view"
|
|
23226
|
+
},
|
|
23227
|
+
"plateGallery.removeVehicleSample": {
|
|
23228
|
+
capName: "plate-gallery",
|
|
23229
|
+
capScope: "system",
|
|
23230
|
+
addonId: null,
|
|
23231
|
+
access: "delete"
|
|
23232
|
+
},
|
|
23233
|
+
"plateGallery.renameVehicle": {
|
|
23234
|
+
capName: "plate-gallery",
|
|
23235
|
+
capScope: "system",
|
|
23236
|
+
addonId: null,
|
|
23237
|
+
access: "create"
|
|
23238
|
+
},
|
|
22165
23239
|
"plateGallery.searchPlates": {
|
|
22166
23240
|
capName: "plate-gallery",
|
|
22167
23241
|
capScope: "system",
|
|
@@ -22174,6 +23248,18 @@ Object.freeze({
|
|
|
22174
23248
|
addonId: null,
|
|
22175
23249
|
access: "view"
|
|
22176
23250
|
},
|
|
23251
|
+
"plateGallery.unassignPlate": {
|
|
23252
|
+
capName: "plate-gallery",
|
|
23253
|
+
capScope: "system",
|
|
23254
|
+
addonId: null,
|
|
23255
|
+
access: "create"
|
|
23256
|
+
},
|
|
23257
|
+
"plateGallery.unassignPlates": {
|
|
23258
|
+
capName: "plate-gallery",
|
|
23259
|
+
capScope: "system",
|
|
23260
|
+
addonId: null,
|
|
23261
|
+
access: "create"
|
|
23262
|
+
},
|
|
22177
23263
|
"platformProbe.getCapabilities": {
|
|
22178
23264
|
capName: "platform-probe",
|
|
22179
23265
|
capScope: "system",
|
|
@@ -22366,6 +23452,48 @@ Object.freeze({
|
|
|
22366
23452
|
addonId: null,
|
|
22367
23453
|
access: "create"
|
|
22368
23454
|
},
|
|
23455
|
+
"sceneMonitor.captureReference": {
|
|
23456
|
+
capName: "scene-monitor",
|
|
23457
|
+
capScope: "device",
|
|
23458
|
+
addonId: null,
|
|
23459
|
+
access: "create"
|
|
23460
|
+
},
|
|
23461
|
+
"sceneMonitor.createScene": {
|
|
23462
|
+
capName: "scene-monitor",
|
|
23463
|
+
capScope: "device",
|
|
23464
|
+
addonId: null,
|
|
23465
|
+
access: "create"
|
|
23466
|
+
},
|
|
23467
|
+
"sceneMonitor.deleteReference": {
|
|
23468
|
+
capName: "scene-monitor",
|
|
23469
|
+
capScope: "device",
|
|
23470
|
+
addonId: null,
|
|
23471
|
+
access: "delete"
|
|
23472
|
+
},
|
|
23473
|
+
"sceneMonitor.deleteScene": {
|
|
23474
|
+
capName: "scene-monitor",
|
|
23475
|
+
capScope: "device",
|
|
23476
|
+
addonId: null,
|
|
23477
|
+
access: "delete"
|
|
23478
|
+
},
|
|
23479
|
+
"sceneMonitor.listScenes": {
|
|
23480
|
+
capName: "scene-monitor",
|
|
23481
|
+
capScope: "device",
|
|
23482
|
+
addonId: null,
|
|
23483
|
+
access: "view"
|
|
23484
|
+
},
|
|
23485
|
+
"sceneMonitor.recheckNow": {
|
|
23486
|
+
capName: "scene-monitor",
|
|
23487
|
+
capScope: "device",
|
|
23488
|
+
addonId: null,
|
|
23489
|
+
access: "create"
|
|
23490
|
+
},
|
|
23491
|
+
"sceneMonitor.updateScene": {
|
|
23492
|
+
capName: "scene-monitor",
|
|
23493
|
+
capScope: "device",
|
|
23494
|
+
addonId: null,
|
|
23495
|
+
access: "create"
|
|
23496
|
+
},
|
|
22369
23497
|
"scriptRunner.run": {
|
|
22370
23498
|
capName: "script-runner",
|
|
22371
23499
|
capScope: "device",
|
|
@@ -23450,6 +24578,7 @@ Object.freeze({
|
|
|
23450
24578
|
Object.freeze({
|
|
23451
24579
|
"broker": "broker",
|
|
23452
24580
|
"device-export": "device-export",
|
|
24581
|
+
"llm": "ai",
|
|
23453
24582
|
"mesh-network": "mesh",
|
|
23454
24583
|
"mqtt-broker": "broker",
|
|
23455
24584
|
"network-access": "ingress",
|
|
@@ -23481,6 +24610,143 @@ object({
|
|
|
23481
24610
|
bootAttempts: number(),
|
|
23482
24611
|
schemaVersion: literal(1)
|
|
23483
24612
|
});
|
|
24613
|
+
var NOTIFIER_ICONS = {
|
|
24614
|
+
telegram: {
|
|
24615
|
+
contentType: "image/svg+xml",
|
|
24616
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#26A5E4\"><path d=\"M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z\"/></svg>"
|
|
24617
|
+
},
|
|
24618
|
+
discord: {
|
|
24619
|
+
contentType: "image/svg+xml",
|
|
24620
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#5865F2\"><path d=\"M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z\"/></svg>"
|
|
24621
|
+
},
|
|
24622
|
+
whatsapp: {
|
|
24623
|
+
contentType: "image/svg+xml",
|
|
24624
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#25D366\"><path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z\"/></svg>"
|
|
24625
|
+
},
|
|
24626
|
+
ntfy: {
|
|
24627
|
+
contentType: "image/svg+xml",
|
|
24628
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#317F6F\"><path d=\"M12.597 13.693v2.156h6.205v-2.156ZM5.183 6.549v2.363l3.591 1.901.023.01-.023.009-3.591 1.901v2.35l.386-.211 5.456-2.969V9.729ZM3.659 2.037C1.915 2.037.42 3.41.42 5.154v.002L.438 18.73 0 21.963l5.956-1.583h14.806c1.744 0 3.238-1.374 3.238-3.118V5.154c0-1.744-1.493-3.116-3.237-3.117h-.001zm0 2.2h17.104c.613.001 1.037.447 1.037.917v12.108c0 .47-.424.916-1.038.916H5.633l-3.026.915.031-.179-.017-13.76c0-.47.424-.917 1.038-.917z\"/></svg>"
|
|
24629
|
+
},
|
|
24630
|
+
pushover: {
|
|
24631
|
+
contentType: "image/svg+xml",
|
|
24632
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#249DF1\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6.16 10.985c-.83 -1.935 1.53 -7.985 8.195 -7.985c3.333 0 4.645 1.382 4.645 3.9c0 2.597 -2.612 6.1 -9 6.1\" /><path d=\"M12.5 6l-5.5 15\" /></svg>"
|
|
24633
|
+
},
|
|
24634
|
+
webhook: {
|
|
24635
|
+
contentType: "image/svg+xml",
|
|
24636
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#7C3AED\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4.876 13.61a4 4 0 1 0 6.124 3.39h6\" /><path d=\"M15.066 20.502a4 4 0 1 0 1.934 -7.502c-.706 0 -1.424 .179 -2 .5l-3 -5.5\" /><path d=\"M16 8a4 4 0 1 0 -8 0c0 1.506 .77 2.818 2 3.5l-3 5.5\" /></svg>"
|
|
24637
|
+
},
|
|
24638
|
+
gotify: {
|
|
24639
|
+
contentType: "image/svg+xml",
|
|
24640
|
+
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500 500\" width=\"500\" height=\"500\"><style type=\"text/css\" id=\"style1\"> .st0{fill:#DDCBA2;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st1{fill:#71CAEE;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st2{fill:#FFFFFF;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st3{fill:#888E93;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st4{fill:#F0F0F0;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st5{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} .st6{fill:url(#SVGID_1_);} .st7{fill:url(#SVGID_2_);} .st8{fill:#FFFFFF;} .st9{fill:url(#SVGID_3_);} .st10{fill:url(#SVGID_4_);} .st11{fill:url(#SVGID_5_);} .st12{fill:none;stroke:#FFFFFF;stroke-width:63;stroke-linecap:round;stroke-miterlimit:10;} .st13{fill:none;stroke:#FFFFFF;stroke-width:56;stroke-linecap:round;stroke-miterlimit:10;} .st14{fill:none;stroke:#A4C639;stroke-width:45.1385;stroke-linecap:round;stroke-miterlimit:10;} .st15{fill:none;stroke:#FFFFFF;stroke-width:16;} .st16{fill:#A4C639;} .st17{fill:#E6E6E6;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st18{fill:none;stroke:#FFFFFF;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} .st19{fill:url(#SVGID_6_);} .st20{fill:url(#SVGID_7_);} .st21{fill:url(#SVGID_8_);} </style><g transform=\"matrix(2.3327641,0,0,2.3327641,-431.80457,-323.21807)\"><g id=\"g48\" transform=\"translate(-24.881692,25.94805)\"><g id=\"g47\"><path class=\"st1\" d=\"m 258.9,119.7 c -3,-0.9 -6,-1.8 -9,-2.7 -4.6,-1.4 -9.2,-2.8 -14,-2.5 -2.8,0.2 -6.1,1.3 -6.9,4 -0.6,2 -1.6,7.3 -1.3,7.9 1.5,3.4 13.9,6.7 18.3,6.7\" id=\"path2\" /><path d=\"m 392.6,177.9 c -1.4,1.4 -2.2,3.5 -2.5,5.5 -0.2,1.4 -0.1,3 0.5,4.3 0.6,1.3 1.8,2.3 3.1,3 1.3,0.6 2.8,0.9 4.3,0.9 1.1,0 2.3,-0.1 3.1,-0.9 0.6,-0.7 0.8,-1.6 0.9,-2.5 0.2,-2.3 -0.1,-4.7 -0.9,-6.9 -0.4,-1.1 -0.9,-2.3 -1.8,-3.1 -1.7,-1.8 -4.5,-2.2 -6.4,-0.5 -0.1,0 -0.2,0.1 -0.3,0.2 z\" id=\"path3\" /><path class=\"st2\" d=\"m 358.5,164.2 c -1,-1 0,-2.7 1,-3.7 5.8,-5.2 15.1,-4.6 21.8,-0.6 10.9,6.6 15.6,19.9 17.2,32.5 0.6,5.2 0.9,10.6 -0.5,15.7 -1.4,5.1 -4.6,9.9 -9.3,12.1 -1.1,0.5 -2.3,0.9 -3.4,0.5 -1.1,-0.4 -1.9,-1.8 -1.2,-2.8 -9.4,-13.6 -19,-26.8 -20.9,-43.2 -0.5,-4.1 -1.8,-7.4 -4.7,-10.5 z\" id=\"path4\" /><path class=\"st1\" d=\"m 220.05771,133 c 34.58546,-18 79.30862,-19.6 112.16964,-8.7 23.69194,7.9 41.3449,26.7 49.4515,50 7.11442,20.6 7.1441,43.6 3.04307,65.7 -7.4942,40.2 -26.19597,77.9 -48.96683,112.6 -12.56244,19 -24.57093,36 -44.23305,48.5 -38.69347,24.6 -88.90104,22.1 -129.28516,11.5 -19.50745,-5.1 -38.36842,-17.3 -44.32901,-37.3 -3.81479,-12.8 -2.07563,-27.6 4.5788,-40 13.50886,-24.8 46.15565,-38.4 50.82627,-67.9 1.36964,-8.7 -0.26842,-17.3 -1.62187,-25.7 -3.7989,-23.4 -5.37477,-45.8 6.68784,-68.7 9.46237,-17.7 24.28607,-31 41.6788,-40 z\" id=\"path6\" /><path class=\"st2\" d=\"m 264.5,174.9 c -0.5,0.5 -0.9,1 -1.3,1.6 -9,11.6 -12,27.9 -9.3,42.1 1.7,9 5.9,17.9 13.2,23.4 19.3,14.6 51.5,13.5 68.4,-1.5 24.4,-21.7 13,-67.6 -14,-78.8 -17.6,-7.2 -43.7,-1.6 -57,13.2 z\" id=\"path9\" /><g id=\"g11\"><path class=\"st2\" d=\"m 382.1,237.1 c 1.4,-0.1 2.9,-0.1 4.3,0.1 0.3,0 0.7,0.1 1,0.4 0.2,0.3 0.4,0.7 0.5,1.1 1,3.9 0.5,8.2 0.1,12.4 -0.1,0.9 -0.2,1.8 -0.6,2.6 -1,2.1 -3.1,2.7 -4.7,2.7 -0.1,0 -0.2,0 -0.3,-0.1 -0.3,-0.2 -0.3,-0.7 -0.2,-1.2 0.3,-5.9 -0.1,-11.9 -0.1,-18 0,0.1 0,0.1 0,0 z\" id=\"path10\" /><path class=\"st2\" d=\"m 378.7,236.8 c -1.4,0.4 -2.5,2 -2.8,4.4 -0.5,4.4 -0.7,8.9 -0.5,13.4 0,0.9 0.1,1.9 0.5,2.4 0.2,0.3 0.5,0.4 0.8,0.4 1.6,0.3 4.1,-0.6 5.6,-1 0,0 0,-5.2 -0.1,-8 -0.1,-2.8 -0.1,-6.1 -0.2,-8.9 0,-0.6 0,-1.5 0,-2.2 0.1,-0.7 -2.6,-0.7 -3.3,-0.5 z\" id=\"path11\" /></g><path class=\"st0\" d=\"m 358.3,231.8 c -0.3,2.2 0.1,4.7 1.7,7.4 2.6,4.4 7,6.1 11.9,5.8 8.9,-0.6 25.3,-5.4 27.5,-15.7 0.6,-3 -0.3,-6.1 -2.2,-8.5 -6.2,-7.8 -17.8,-5.7 -25.6,-2 -5.9,2.7 -12.4,7 -13.3,13 z\" id=\"path12\" /><path class=\"st3\" d=\"m 386.4,208.6 c 2.2,1.4 3.7,3.8 4,7 0.3,3.6 -1.4,7.5 -5,8.8 -2.9,1.1 -6.2,0.6 -9.1,-0.4 -2.9,-1 -5.8,-2.8 -6.8,-5.7 -0.7,-2 -0.3,-4.3 0.7,-6.1 1.1,-1.8 2.8,-3.2 4.7,-4.1 3.9,-1.8 8.4,-1.6 11.5,0.5 z\" id=\"path13\" /><path class=\"st0\" d=\"m 414.7,262.6 c 2.4,0.6 4.8,2.1 5.6,4.4 0.8,2.3 0.1,4.9 -1.6,6.7 -1.7,1.8 -4.2,2.5 -6.6,2.5 -0.8,0 -1.7,-0.1 -2.4,-0.5 -2.5,-1.1 -3.5,-4 -4.2,-6.6 -1.8,-6.8 3.6,-7.8 9.2,-6.5 z\" id=\"path14\" /><g id=\"g17\"><path class=\"st4\" d=\"m 267.1,284.7 c 2.3,-4.5 141.3,-36.2 144.7,-31.6 3.4,4.5 15.8,88.2 9,90.4 -6.8,2.3 -119.8,37.3 -126.6,35 -6.8,-2.3 -29.4,-89.3 -27.1,-93.8 z\" id=\"path15\" /><path class=\"st5\" d=\"m 294.2,378.5 c 0,0 54.3,-74.6 59.9,-76.9 5.7,-2.3 67.3,41.3 67.3,41.3\" id=\"path16\" /><path class=\"st4\" d=\"m 267,287.7 c 0,0 86,38.8 91.6,36.6 5.7,-2.3 53.1,-71.2 53.1,-71.2\" id=\"path17\" /></g><g id=\"g33\"><linearGradient id=\"SVGID_2_\" gradientUnits=\"userSpaceOnUse\" x1=\"265.03339\" y1=\"280.2951\" x2=\"275.3009\" y2=\"302.31369\"><stop offset=\"5.152266e-07\" style=\"stop-color:#71CAEE\" id=\"stop25\" /><stop offset=\"4.104413e-02\" style=\"stop-color:#83CAE2\" id=\"stop26\" /><stop offset=\"0.1206\" style=\"stop-color:#9FCACE\" id=\"stop27\" /><stop offset=\"0.2107\" style=\"stop-color:#B6CBBE\" id=\"stop28\" /><stop offset=\"0.3139\" style=\"stop-color:#C7CBB1\" id=\"stop29\" /><stop offset=\"0.4384\" style=\"stop-color:#D4CBA8\" id=\"stop30\" /><stop offset=\"0.6058\" style=\"stop-color:#DBCBA3\" id=\"stop31\" /><stop offset=\"1\" style=\"stop-color:#DDCBA2\" id=\"stop32\" /></linearGradient><path class=\"st7\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path32\" style=\"fill:url(#SVGID_2_)\" /><path class=\"st5\" d=\"m 261.9,283.5 c -0.1,4.2 4.3,7.3 8.4,7.6 4.1,0.3 8.2,-1.3 12.2,-2.6 1.4,-0.4 2.9,-0.8 4.2,-0.2 1.8,0.9 2.7,4.1 1.8,5.9 -0.9,1.8 -3.4,3.5 -5.3,4.4 -6.5,3 -12.9,3.6 -19.9,2 -5.3,-1.2 -11.3,-4.3 -13,-13.5\" id=\"path33\" /></g><path d=\"m 318.4,198.4 c -2,-0.3 -4.1,0.1 -5.9,1.3 -3.2,2.1 -4.7,6.2 -4.7,9.9 0,1.9 0.4,3.8 1.4,5.3 1.2,1.7 3.1,2.9 5.2,3.4 3.4,0.8 8.2,0.7 10.5,-2.5 1,-1.5 1.4,-3.3 1.5,-5.1 0.5,-5.7 -1.8,-11.4 -8,-12.3 z\" id=\"path34\" /><path class=\"st8\" d=\"m 320.4,203.3 c 0.9,0.3 1.7,0.8 2.1,1.7 0.4,0.8 0.4,1.7 0.3,2.5 -0.1,1 -0.6,2 -1.5,2.7 -0.7,0.5 -1.7,0.7 -2.6,0.5 -0.9,-0.2 -1.7,-0.8 -2.2,-1.6 -1.1,-1.6 -0.9,-4.4 0.9,-5.5 0.9,-0.4 2,-0.6 3,-0.3 z\" id=\"path35\" /></g></g></g></svg>"
|
|
24641
|
+
},
|
|
24642
|
+
zentik: {
|
|
24643
|
+
contentType: "image/png",
|
|
24644
|
+
body: Uint8Array.from(Buffer.from("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", "base64"))
|
|
24645
|
+
}
|
|
24646
|
+
};
|
|
24647
|
+
//#endregion
|
|
24648
|
+
//#region src/icon-routes.ts
|
|
24649
|
+
/**
|
|
24650
|
+
* Serves the bundled per-kind brand icons (`icons-data.ts`) over the addon's
|
|
24651
|
+
* own HTTP surface via the `addon-routes` cap. One public GET route per kind:
|
|
24652
|
+
*
|
|
24653
|
+
* GET /addon/notifiers/icons/<kind> → the bundled brand icon
|
|
24654
|
+
*
|
|
24655
|
+
* Each route sets the icon's OWN content-type (`image/svg+xml` for the vector
|
|
24656
|
+
* icons, `image/png` for the raster zentik logo) so a browser `<img src>`
|
|
24657
|
+
* renders it — an SVG that wraps a raster `data:` URI is blocked by the strict
|
|
24658
|
+
* `<img>` SVG mode, so zentik ships as its real PNG bytes instead.
|
|
24659
|
+
*
|
|
24660
|
+
* The bytes ship INSIDE the addon — no external CDN / hotlink — so the icons are
|
|
24661
|
+
* self-contained and CSP-safe. `listTargetKinds` stamps each kind with the
|
|
24662
|
+
* matching `iconUrl` (see `iconUrlFor`), letting the admin UI render
|
|
24663
|
+
* `<img src=iconUrl>` instead of a text label.
|
|
24664
|
+
*
|
|
24665
|
+
* We register a STATIC route per kind rather than one `/:kind` param route: the
|
|
24666
|
+
* forked-addon route bridge re-matches the pattern against itself, which would
|
|
24667
|
+
* clobber a `:kind` path param with the literal token `':kind'`. Static paths
|
|
24668
|
+
* carry no param, so they route correctly across the process boundary.
|
|
24669
|
+
*
|
|
24670
|
+
* ── Why the addon pre-encodes and owns `content-encoding` ────────────────────
|
|
24671
|
+
* The hub serves an addon route by piping the response THROUGH its global
|
|
24672
|
+
* `@fastify/compress`. For a forked addon, our reply body crosses the UDS route
|
|
24673
|
+
* bridge as opaque bytes and the hub then re-encodes them — and on that bridged
|
|
24674
|
+
* path the compressor emits an EMPTY brotli stream for any compressible body
|
|
24675
|
+
* over its 1 KiB threshold (`content-encoding: br` + `content-length: 0`), so a
|
|
24676
|
+
* browser `<img>` decodes nothing and shows a broken icon. Small icons (< 1 KiB)
|
|
24677
|
+
* and the raster PNG (a non-compressible type) slip under the compressor and
|
|
24678
|
+
* render, which is why only the larger SVGs broke.
|
|
24679
|
+
*
|
|
24680
|
+
* The fix is to make the compressor SKIP us: it leaves a response untouched when
|
|
24681
|
+
* `content-encoding` is already set to a non-identity coding. So each route
|
|
24682
|
+
* negotiates the request's `Accept-Encoding`, serves a pre-computed br/gzip/
|
|
24683
|
+
* deflate variant (or identity when the client accepts none), and stamps the
|
|
24684
|
+
* matching `content-encoding` itself. Bytes we own, correctly framed, reach the
|
|
24685
|
+
* browser intact. Mirrors the `compress: false` treatment the hub's own binary
|
|
24686
|
+
* pull route already uses for the same class of bug.
|
|
24687
|
+
*/
|
|
24688
|
+
/** The addon id — also the `/addon/<id>/…` route prefix. Mirrors `NOTIFIERS_ADDON_ID`. */
|
|
24689
|
+
var NOTIFIERS_ROUTE_ID = "notifiers";
|
|
24690
|
+
/** One day; icons are immutable per addon version. */
|
|
24691
|
+
var CACHE_CONTROL = "public, max-age=86400, immutable";
|
|
24692
|
+
var ICON_KINDS = new Set(Object.keys(NOTIFIER_ICONS));
|
|
24693
|
+
/** `true` when a bundled brand icon exists for `kind`. */
|
|
24694
|
+
function hasIcon(kind) {
|
|
24695
|
+
return ICON_KINDS.has(kind);
|
|
24696
|
+
}
|
|
24697
|
+
/**
|
|
24698
|
+
* The stable per-kind icon URL, or `undefined` when no icon is bundled. Stamped
|
|
24699
|
+
* onto each descriptor by `listTargetKinds`. Root-relative so it resolves
|
|
24700
|
+
* against whatever origin the admin UI is served from.
|
|
24701
|
+
*/
|
|
24702
|
+
function iconUrlFor(kind) {
|
|
24703
|
+
return hasIcon(kind) ? `/addon/${NOTIFIERS_ROUTE_ID}/icons/${kind}` : void 0;
|
|
24704
|
+
}
|
|
24705
|
+
/** Pre-encode one bundled icon into every content coding. */
|
|
24706
|
+
function encodeIcon(icon) {
|
|
24707
|
+
const identity = typeof icon.body === "string" ? Buffer.from(icon.body, "utf8") : Buffer.from(icon.body);
|
|
24708
|
+
return {
|
|
24709
|
+
contentType: icon.contentType,
|
|
24710
|
+
identity,
|
|
24711
|
+
br: brotliCompressSync(identity),
|
|
24712
|
+
gzip: gzipSync(identity),
|
|
24713
|
+
deflate: deflateSync(identity)
|
|
24714
|
+
};
|
|
24715
|
+
}
|
|
24716
|
+
/** Pick the best coding the client accepts (br › gzip › deflate), or `null` for
|
|
24717
|
+
* identity when the header names none of them. Token-matched so `gzipx` or a
|
|
24718
|
+
* `q=0` refusal don't false-positive. */
|
|
24719
|
+
function negotiateEncoding(acceptEncoding) {
|
|
24720
|
+
const tokens = acceptEncoding.toLowerCase().split(",").map((part) => part.trim().split(";")[0]?.trim());
|
|
24721
|
+
for (const coding of [
|
|
24722
|
+
"br",
|
|
24723
|
+
"gzip",
|
|
24724
|
+
"deflate"
|
|
24725
|
+
]) if (tokens.includes(coding)) return coding;
|
|
24726
|
+
return null;
|
|
24727
|
+
}
|
|
24728
|
+
/** One static GET route serving the bundled icon for a single kind, with the
|
|
24729
|
+
* icon's own content-type (svg vs png) and a client-negotiated content-coding
|
|
24730
|
+
* the addon owns end-to-end (see the file header for why). */
|
|
24731
|
+
function iconRoute(kind) {
|
|
24732
|
+
const encoded = encodeIcon(NOTIFIER_ICONS[kind]);
|
|
24733
|
+
return {
|
|
24734
|
+
method: "GET",
|
|
24735
|
+
path: `/icons/${kind}`,
|
|
24736
|
+
access: "public",
|
|
24737
|
+
description: `Official brand icon (${encoded.contentType}) for the '${kind}' notifier kind.`,
|
|
24738
|
+
handler: async (request, reply) => {
|
|
24739
|
+
const coding = negotiateEncoding(String(request.headers["accept-encoding"] ?? ""));
|
|
24740
|
+
reply.code(200).type(encoded.contentType).header("cache-control", CACHE_CONTROL).header("vary", "accept-encoding");
|
|
24741
|
+
if (coding !== null) reply.header("content-encoding", coding);
|
|
24742
|
+
reply.send(coding !== null ? encoded[coding] : encoded.identity);
|
|
24743
|
+
}
|
|
24744
|
+
};
|
|
24745
|
+
}
|
|
24746
|
+
/** Build the `addon-routes` provider that serves the bundled icons. */
|
|
24747
|
+
function createIconRouteProvider() {
|
|
24748
|
+
return buildAddonRouteProvider(NOTIFIERS_ROUTE_ID, Object.keys(NOTIFIER_ICONS).map(iconRoute));
|
|
24749
|
+
}
|
|
23484
24750
|
//#endregion
|
|
23485
24751
|
//#region src/adapters/discord.ts
|
|
23486
24752
|
/** Discord message `content` hard limit. */
|
|
@@ -25921,11 +27187,19 @@ function createNotificationOutputProvider(deps) {
|
|
|
25921
27187
|
renderedAs: prepared.renderedAs
|
|
25922
27188
|
};
|
|
25923
27189
|
}
|
|
27190
|
+
const iconUrlFor = deps.iconUrlFor;
|
|
25924
27191
|
return {
|
|
25925
|
-
listTargetKinds: async () => deps.adapters.map((a) =>
|
|
25926
|
-
|
|
25927
|
-
|
|
25928
|
-
|
|
27192
|
+
listTargetKinds: async () => deps.adapters.map((a) => {
|
|
27193
|
+
const descriptor = {
|
|
27194
|
+
...a.descriptor,
|
|
27195
|
+
addonId
|
|
27196
|
+
};
|
|
27197
|
+
const iconUrl = iconUrlFor?.(a.descriptor.kind);
|
|
27198
|
+
return iconUrl !== void 0 ? {
|
|
27199
|
+
...descriptor,
|
|
27200
|
+
iconUrl
|
|
27201
|
+
} : descriptor;
|
|
27202
|
+
}),
|
|
25929
27203
|
listTargets: async () => {
|
|
25930
27204
|
return (await store.list()).map((target) => {
|
|
25931
27205
|
const adapter = adapterByKind.get(target.kind);
|
|
@@ -26022,6 +27296,12 @@ function createApiSettingsStorePort(api) {
|
|
|
26022
27296
|
collection,
|
|
26023
27297
|
key: id
|
|
26024
27298
|
});
|
|
27299
|
+
},
|
|
27300
|
+
declareCollection: async (collection, columns) => {
|
|
27301
|
+
await api.settingsStore.declareCollection.mutate({
|
|
27302
|
+
collection,
|
|
27303
|
+
columns: columns.map((c) => ({ ...c }))
|
|
27304
|
+
});
|
|
26025
27305
|
}
|
|
26026
27306
|
};
|
|
26027
27307
|
}
|
|
@@ -26052,6 +27332,9 @@ function createMemorySettingsStorePort() {
|
|
|
26052
27332
|
},
|
|
26053
27333
|
remove: async (collection, id) => {
|
|
26054
27334
|
bucket(collection).delete(id);
|
|
27335
|
+
},
|
|
27336
|
+
declareCollection: async (collection) => {
|
|
27337
|
+
bucket(collection);
|
|
26055
27338
|
}
|
|
26056
27339
|
};
|
|
26057
27340
|
}
|
|
@@ -26072,6 +27355,13 @@ function createMemorySettingsStorePort() {
|
|
|
26072
27355
|
*/
|
|
26073
27356
|
/** The default collection name (see `settings-store` addonId-prefix note). */
|
|
26074
27357
|
var TARGETS_COLLECTION = "notification-targets";
|
|
27358
|
+
/** KV JSON-blob shape — a single `data` column routes the row through the
|
|
27359
|
+
* settings backend's canonical key/value path (id TEXT PK, data TEXT). */
|
|
27360
|
+
var KV_BLOB_COLUMNS = [{
|
|
27361
|
+
name: "data",
|
|
27362
|
+
type: "TEXT",
|
|
27363
|
+
notNull: true
|
|
27364
|
+
}];
|
|
26075
27365
|
function rowToTarget(row) {
|
|
26076
27366
|
const candidate = {
|
|
26077
27367
|
id: row.id,
|
|
@@ -26096,6 +27386,12 @@ var TargetStore = class {
|
|
|
26096
27386
|
this.store = store;
|
|
26097
27387
|
this.collection = collection;
|
|
26098
27388
|
}
|
|
27389
|
+
/** Declare the backing collection before any read/write. The SQLite settings
|
|
27390
|
+
* backend rejects undeclared collections (fail-fast), so this MUST run before
|
|
27391
|
+
* `list`/`getById`/`upsert`/`delete` — mirrors addon-ai's ProfileStore.init. */
|
|
27392
|
+
async init() {
|
|
27393
|
+
await this.store.declareCollection(this.collection, KV_BLOB_COLUMNS);
|
|
27394
|
+
}
|
|
26099
27395
|
async list() {
|
|
26100
27396
|
const rows = await this.store.query(this.collection);
|
|
26101
27397
|
const targets = [];
|
|
@@ -26167,15 +27463,22 @@ var NotifiersAddon = class extends BaseAddon {
|
|
|
26167
27463
|
const api = this.ctx.api;
|
|
26168
27464
|
const port = api ? createApiSettingsStorePort(api) : createMemorySettingsStorePort();
|
|
26169
27465
|
if (!api) this.ctx.logger.warn("notifiers: no ctx.api — targets persist in-memory only");
|
|
27466
|
+
const store = new TargetStore(port);
|
|
27467
|
+
await store.init();
|
|
26170
27468
|
const provider = createNotificationOutputProvider({
|
|
26171
|
-
store
|
|
27469
|
+
store,
|
|
26172
27470
|
adapters: ADAPTERS,
|
|
26173
|
-
logger: this.ctx.logger.child("notification-output")
|
|
27471
|
+
logger: this.ctx.logger.child("notification-output"),
|
|
27472
|
+
iconUrlFor
|
|
26174
27473
|
});
|
|
27474
|
+
const iconRouteProvider = createIconRouteProvider();
|
|
26175
27475
|
this.ctx.logger.info("NotifiersAddon initialized", { meta: { adapterCount: ADAPTERS.length } });
|
|
26176
27476
|
return [{
|
|
26177
27477
|
capability: notificationOutputCapability,
|
|
26178
27478
|
provider
|
|
27479
|
+
}, {
|
|
27480
|
+
capability: addonRoutesCapability,
|
|
27481
|
+
provider: iconRouteProvider
|
|
26179
27482
|
}];
|
|
26180
27483
|
}
|
|
26181
27484
|
async onShutdown() {
|