@camstack/addon-provider-homeassistant 1.1.24 → 1.1.26
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 +1321 -47
- package/dist/addon.mjs +1321 -47
- package/package.json +8 -1
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let node_crypto = require("node:crypto");
|
|
3
|
+
let node_zlib = require("node:zlib");
|
|
3
4
|
//#region ../../node_modules/zod/v4/core/core.js
|
|
4
5
|
var _a$1;
|
|
5
6
|
function $constructor(name, initializer, params) {
|
|
@@ -4288,6 +4289,14 @@ function object(shape, params) {
|
|
|
4288
4289
|
...normalizeParams(params)
|
|
4289
4290
|
});
|
|
4290
4291
|
}
|
|
4292
|
+
function looseObject(shape, params) {
|
|
4293
|
+
return new ZodObject({
|
|
4294
|
+
type: "object",
|
|
4295
|
+
shape,
|
|
4296
|
+
catchall: unknown(),
|
|
4297
|
+
...normalizeParams(params)
|
|
4298
|
+
});
|
|
4299
|
+
}
|
|
4291
4300
|
var ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
|
|
4292
4301
|
$ZodUnion.init(inst, def);
|
|
4293
4302
|
ZodType.init(inst, def);
|
|
@@ -4629,7 +4638,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4629
4638
|
return inst;
|
|
4630
4639
|
}
|
|
4631
4640
|
//#endregion
|
|
4632
|
-
//#region ../types/dist/sleep-
|
|
4641
|
+
//#region ../types/dist/sleep-_sv7WKkq.mjs
|
|
4633
4642
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4634
4643
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4635
4644
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -5039,10 +5048,51 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
5039
5048
|
EventCategory["EnrichmentEmbeddingStored"] = "enrichment.embedding.stored";
|
|
5040
5049
|
EventCategory["EnrichmentSceneStateChanged"] = "enrichment.scene.state-changed";
|
|
5041
5050
|
EventCategory["EnrichmentActivitySummary"] = "enrichment.activity.summary";
|
|
5051
|
+
/**
|
|
5052
|
+
* Unified track-lifecycle event: ONE category carrying `phase:
|
|
5053
|
+
* 'start' | 'update' | 'end'` with a rich, typed
|
|
5054
|
+
* `PipelineAnalyticsTrackLifecyclePayload`. Supersedes the thin
|
|
5055
|
+
* `PipelineAnalyticsTrackStarted` / `PipelineAnalyticsTrackEnded`
|
|
5056
|
+
* pair — a consumer subscribes once and branches on `phase`.
|
|
5057
|
+
*/
|
|
5058
|
+
EventCategory["PipelineAnalyticsTrackLifecycle"] = "pipeline-analytics.track-lifecycle";
|
|
5059
|
+
/**
|
|
5060
|
+
* @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
|
|
5061
|
+
* (`phase:'start'`). Kept as a soft alias — no known subscribers.
|
|
5062
|
+
*/
|
|
5042
5063
|
EventCategory["PipelineAnalyticsTrackStarted"] = "pipeline-analytics.track-started";
|
|
5064
|
+
/**
|
|
5065
|
+
* @deprecated Superseded by {@link PipelineAnalyticsTrackLifecycle}
|
|
5066
|
+
* (`phase:'end'`). Kept as a soft alias — no known subscribers.
|
|
5067
|
+
*/
|
|
5043
5068
|
EventCategory["PipelineAnalyticsTrackEnded"] = "pipeline-analytics.track-ended";
|
|
5044
5069
|
EventCategory["PipelineAnalyticsDetectionEvent"] = "pipeline-analytics.detection-event";
|
|
5045
5070
|
EventCategory["PipelineAnalyticsFrameTracked"] = "pipeline-analytics.frame-tracked";
|
|
5071
|
+
/**
|
|
5072
|
+
* Fired by `addon-post-analysis` when a parked (stationary) object appears
|
|
5073
|
+
* (a track was promoted to a stationary-registry entry) or departs (the
|
|
5074
|
+
* object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
|
|
5075
|
+
* the dedicated "Stationary" section — never the live event feed. Payload:
|
|
5076
|
+
* `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
|
|
5077
|
+
*/
|
|
5078
|
+
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
5079
|
+
/**
|
|
5080
|
+
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
5081
|
+
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
5082
|
+
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
5083
|
+
* removed. Telemetry semantics (D8): a lost event only delays a refresh,
|
|
5084
|
+
* never a correctness issue. Payload `PipelineAnalyticsFaceGalleryChangedPayload`.
|
|
5085
|
+
*/
|
|
5086
|
+
EventCategory["PipelineAnalyticsFaceGalleryChanged"] = "pipeline-analytics.face-gallery-changed";
|
|
5087
|
+
/**
|
|
5088
|
+
* Fired by `addon-post-analysis` whenever a gallery plate row changes:
|
|
5089
|
+
* `kind:'buffered'` a new read was persisted (`PlateRecognizer.onTrackEnd`),
|
|
5090
|
+
* `'assigned'` / `'unassigned'` its vehicle link changed
|
|
5091
|
+
* (`PlateGalleryProvider`), `'deleted'` the row was removed. Telemetry
|
|
5092
|
+
* semantics (D8): a lost event only delays a refresh, never a correctness
|
|
5093
|
+
* issue. Payload `PipelineAnalyticsPlateGalleryChangedPayload`.
|
|
5094
|
+
*/
|
|
5095
|
+
EventCategory["PipelineAnalyticsPlateGalleryChanged"] = "pipeline-analytics.plate-gallery-changed";
|
|
5046
5096
|
EventCategory["FrigateLiveEvent"] = "frigate.live-event";
|
|
5047
5097
|
EventCategory["CameraStreamsProfileSlotsChanged"] = "camera-streams.onProfileSlotsChanged";
|
|
5048
5098
|
/**
|
|
@@ -6887,7 +6937,8 @@ var MODEL_FORMATS = [
|
|
|
6887
6937
|
"coreml",
|
|
6888
6938
|
"openvino",
|
|
6889
6939
|
"tflite",
|
|
6890
|
-
"pt"
|
|
6940
|
+
"pt",
|
|
6941
|
+
"gguf"
|
|
6891
6942
|
];
|
|
6892
6943
|
/**
|
|
6893
6944
|
* Multi-file format payload.
|
|
@@ -6931,7 +6982,8 @@ var ModelFormatsSchema = object({
|
|
|
6931
6982
|
coreml: ModelFormatEntrySchema.optional(),
|
|
6932
6983
|
openvino: ModelFormatEntrySchema.optional(),
|
|
6933
6984
|
tflite: ModelFormatEntrySchema.optional(),
|
|
6934
|
-
pt: ModelFormatEntrySchema.optional()
|
|
6985
|
+
pt: ModelFormatEntrySchema.optional(),
|
|
6986
|
+
gguf: ModelFormatEntrySchema.optional()
|
|
6935
6987
|
});
|
|
6936
6988
|
/**
|
|
6937
6989
|
* Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
|
|
@@ -6972,6 +7024,15 @@ var ModelCatalogEntrySchema = object({
|
|
|
6972
7024
|
width: number(),
|
|
6973
7025
|
height: number()
|
|
6974
7026
|
}),
|
|
7027
|
+
/**
|
|
7028
|
+
* Channel count of the model input tensor. Omit ⇒ 3 (RGB), the default for
|
|
7029
|
+
* every detector / classifier / embedder. Set to 1 for a grayscale CTC text
|
|
7030
|
+
* recognizer (EasyOCR VGG plate-OCR: input `[N,1,H,W]`) so the preprocess
|
|
7031
|
+
* feeds a single-channel, EasyOCR-normalized tensor instead of the default
|
|
7032
|
+
* 3-channel RGB one. Threaded through `PoolModelConfig.inputChannels` to the
|
|
7033
|
+
* Python inference pool.
|
|
7034
|
+
*/
|
|
7035
|
+
inputChannels: number().int().positive().optional(),
|
|
6975
7036
|
labels: array(LabelDefinitionSchema).readonly(),
|
|
6976
7037
|
inputLayout: _enum(["nchw", "nhwc"]).optional(),
|
|
6977
7038
|
inputNormalization: _enum([
|
|
@@ -6981,6 +7042,16 @@ var ModelCatalogEntrySchema = object({
|
|
|
6981
7042
|
]).optional(),
|
|
6982
7043
|
preprocessMode: _enum(["letterbox", "resize"]).optional(),
|
|
6983
7044
|
/**
|
|
7045
|
+
* Per-MODEL postprocessor override. Absent ⇒ the step's own
|
|
7046
|
+
* `StepDefinition.postprocessor` applies (the normal case — every model in a
|
|
7047
|
+
* step shares its decode). Set it when a step hosts models with DIFFERENT raw
|
|
7048
|
+
* output layouts under one slot: e.g. object-detection is `'yolo'` by default,
|
|
7049
|
+
* but a Coral SSD MobileNet build emits the `TFLite_Detection_PostProcess`
|
|
7050
|
+
* 4-tensor layout and needs `'ssd'`. Threaded into `PoolModelConfig.postprocessor`
|
|
7051
|
+
* by the engine factory (`modelEntry.postprocessor ?? def.postprocessor`).
|
|
7052
|
+
*/
|
|
7053
|
+
postprocessor: custom().optional(),
|
|
7054
|
+
/**
|
|
6984
7055
|
* When true, the executor produces a landmark-aligned crop (similarity warp
|
|
6985
7056
|
* onto the canonical template) before this step runs, instead of a plain
|
|
6986
7057
|
* axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
|
|
@@ -7070,6 +7141,123 @@ var ConvertResultSchema = object({
|
|
|
7070
7141
|
})).readonly()
|
|
7071
7142
|
});
|
|
7072
7143
|
/**
|
|
7144
|
+
* Build an `IAddonRouteProvider` from a list of routes. Implements
|
|
7145
|
+
* both the operator-facing `getRoutes` (returning route descriptors
|
|
7146
|
+
* minus the handlers, which can't cross JSON) and the framework-
|
|
7147
|
+
* private `invoke` method that the hub calls when this provider lives
|
|
7148
|
+
* in a forked worker.
|
|
7149
|
+
*
|
|
7150
|
+
* Co-located addons use the returned `getRoutes` directly because
|
|
7151
|
+
* their handlers don't need to cross any wire. The `invoke` method
|
|
7152
|
+
* is present anyway so the bridge code on the hub is uniform — it
|
|
7153
|
+
* doesn't need to switch on "local vs remote provider" at the call
|
|
7154
|
+
* site.
|
|
7155
|
+
*
|
|
7156
|
+
* Example:
|
|
7157
|
+
* const routes: IAddonHttpRoute[] = [
|
|
7158
|
+
* { method: 'GET', path: '/start', access: 'public', handler: this.handleStart },
|
|
7159
|
+
* ]
|
|
7160
|
+
* return [
|
|
7161
|
+
* {
|
|
7162
|
+
* capability: addonRoutesCapability,
|
|
7163
|
+
* provider: buildAddonRouteProvider('auth-oidc', routes),
|
|
7164
|
+
* },
|
|
7165
|
+
* ]
|
|
7166
|
+
*/
|
|
7167
|
+
function buildAddonRouteProvider(id, routes) {
|
|
7168
|
+
return {
|
|
7169
|
+
id,
|
|
7170
|
+
getRoutes: () => routes,
|
|
7171
|
+
invoke: async (input) => {
|
|
7172
|
+
const match = matchRoute(routes, input.method, input.path);
|
|
7173
|
+
if (!match) return {
|
|
7174
|
+
status: 404,
|
|
7175
|
+
headers: {},
|
|
7176
|
+
redirectUrl: null,
|
|
7177
|
+
body: { error: `No route matches ${input.method} ${input.path}` }
|
|
7178
|
+
};
|
|
7179
|
+
const envelope = {
|
|
7180
|
+
status: 200,
|
|
7181
|
+
headers: {},
|
|
7182
|
+
redirectUrl: null
|
|
7183
|
+
};
|
|
7184
|
+
const reply = buildCapturingReply(envelope);
|
|
7185
|
+
const request = {
|
|
7186
|
+
params: {
|
|
7187
|
+
...input.params,
|
|
7188
|
+
...match.params
|
|
7189
|
+
},
|
|
7190
|
+
query: input.query,
|
|
7191
|
+
body: input.body,
|
|
7192
|
+
headers: input.headers,
|
|
7193
|
+
...input.user ? { user: input.user } : {},
|
|
7194
|
+
...input.scopedToken !== void 0 ? { scopedToken: input.scopedToken } : {}
|
|
7195
|
+
};
|
|
7196
|
+
await match.route.handler(request, reply);
|
|
7197
|
+
return envelope;
|
|
7198
|
+
}
|
|
7199
|
+
};
|
|
7200
|
+
}
|
|
7201
|
+
/**
|
|
7202
|
+
* Pattern matcher: same semantics as `AddonRouteRegistry.matchRoute`
|
|
7203
|
+
* but operating on a flat list and bypassing the `/addon/<id>/` prefix
|
|
7204
|
+
* — the bridge sends the post-prefix path directly so we don't need
|
|
7205
|
+
* to round-trip it through normalization.
|
|
7206
|
+
*/
|
|
7207
|
+
function matchRoute(routes, method, path) {
|
|
7208
|
+
const normalizedMethod = method.toUpperCase();
|
|
7209
|
+
for (const route of routes) {
|
|
7210
|
+
if (route.method !== normalizedMethod) continue;
|
|
7211
|
+
const params = matchPath(route.path, path);
|
|
7212
|
+
if (params !== null) return {
|
|
7213
|
+
route,
|
|
7214
|
+
params
|
|
7215
|
+
};
|
|
7216
|
+
}
|
|
7217
|
+
return null;
|
|
7218
|
+
}
|
|
7219
|
+
function matchPath(pattern, p) {
|
|
7220
|
+
const patternParts = pattern.split("/").filter(Boolean);
|
|
7221
|
+
const pathParts = p.split("/").filter(Boolean);
|
|
7222
|
+
if (patternParts.length !== pathParts.length) return null;
|
|
7223
|
+
const params = {};
|
|
7224
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
7225
|
+
const a = patternParts[i];
|
|
7226
|
+
const b = pathParts[i];
|
|
7227
|
+
if (a.startsWith(":")) params[a.slice(1)] = b;
|
|
7228
|
+
else if (a !== b) return null;
|
|
7229
|
+
}
|
|
7230
|
+
return params;
|
|
7231
|
+
}
|
|
7232
|
+
function buildCapturingReply(envelope) {
|
|
7233
|
+
const wrapper = {
|
|
7234
|
+
status(code) {
|
|
7235
|
+
envelope.status = code;
|
|
7236
|
+
return wrapper;
|
|
7237
|
+
},
|
|
7238
|
+
code(code) {
|
|
7239
|
+
envelope.status = code;
|
|
7240
|
+
return wrapper;
|
|
7241
|
+
},
|
|
7242
|
+
send(data) {
|
|
7243
|
+
envelope.body = data;
|
|
7244
|
+
},
|
|
7245
|
+
redirect(url) {
|
|
7246
|
+
envelope.redirectUrl = url;
|
|
7247
|
+
if (envelope.status === 200) envelope.status = 302;
|
|
7248
|
+
},
|
|
7249
|
+
header(name, value) {
|
|
7250
|
+
envelope.headers[name.toLowerCase()] = value;
|
|
7251
|
+
return wrapper;
|
|
7252
|
+
},
|
|
7253
|
+
type(mime) {
|
|
7254
|
+
envelope.contentType = mime;
|
|
7255
|
+
return wrapper;
|
|
7256
|
+
}
|
|
7257
|
+
};
|
|
7258
|
+
return wrapper;
|
|
7259
|
+
}
|
|
7260
|
+
/**
|
|
7073
7261
|
* Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
|
|
7074
7262
|
* Named `RecordingWeekday` to avoid collision with the string-union
|
|
7075
7263
|
* `Weekday` exported from `interfaces/timezones.ts`.
|
|
@@ -11925,7 +12113,8 @@ var ModelFormatSchema$1 = _enum([
|
|
|
11925
12113
|
"coreml",
|
|
11926
12114
|
"openvino",
|
|
11927
12115
|
"tflite",
|
|
11928
|
-
"pt"
|
|
12116
|
+
"pt",
|
|
12117
|
+
"gguf"
|
|
11929
12118
|
]);
|
|
11930
12119
|
var PipelineSlotSchema = _enum([
|
|
11931
12120
|
"detector",
|
|
@@ -12019,7 +12208,8 @@ var EngineProvisioningSchema = object({
|
|
|
12019
12208
|
runtimeId: _enum([
|
|
12020
12209
|
"onnx",
|
|
12021
12210
|
"openvino",
|
|
12022
|
-
"coreml"
|
|
12211
|
+
"coreml",
|
|
12212
|
+
"edgetpu"
|
|
12023
12213
|
]).nullable(),
|
|
12024
12214
|
device: string().nullable(),
|
|
12025
12215
|
state: _enum([
|
|
@@ -13660,6 +13850,167 @@ var ptzAutotrackCapability = {
|
|
|
13660
13850
|
runtimeState: PtzAutotrackRuntimeStateSchema
|
|
13661
13851
|
};
|
|
13662
13852
|
/**
|
|
13853
|
+
* scene-monitor — device-scoped reference-region state cap. An operator marks
|
|
13854
|
+
* a rect ROI on a camera frame and names one or more states; the engine
|
|
13855
|
+
* (pipeline-analytics, designated post-processing node) reports which state is
|
|
13856
|
+
* active on an ongoing basis. Two operator-selectable check modes share every-
|
|
13857
|
+
* thing except the comparator: `similarity` (CLIP cosine at the same ROI coords
|
|
13858
|
+
* vs condition-tagged references) and `llm` (vision-LLM judgment over the crop).
|
|
13859
|
+
*
|
|
13860
|
+
* D14 device-config archetype (`deviceConfig.ui.kind:'widget'`) — the framework
|
|
13861
|
+
* derives the device-detail contribution; the provider carries NO hand-written
|
|
13862
|
+
* settings-contribution methods. `status.kind:'push'` — the engine pushes on
|
|
13863
|
+
* every hysteresis flip / availability change; consumers never poll.
|
|
13864
|
+
*/
|
|
13865
|
+
/** Extensible condition tag. Seeded 'day' | 'night'; open by design so more can
|
|
13866
|
+
* be added without a wire break (matching falls back to any-condition refs). */
|
|
13867
|
+
var SceneConditionSchema = string();
|
|
13868
|
+
/** One captured reference — condition-tagged, model-version-gated. `embedding`
|
|
13869
|
+
* is `number[]` (Float32Array does NOT survive MsgPack/UDS). */
|
|
13870
|
+
var SceneReferenceSchema = object({
|
|
13871
|
+
embedding: array(number()),
|
|
13872
|
+
modelId: string(),
|
|
13873
|
+
condition: SceneConditionSchema,
|
|
13874
|
+
capturedAt: number(),
|
|
13875
|
+
thumbnailMediaId: string().optional()
|
|
13876
|
+
});
|
|
13877
|
+
var SceneMonitorStateSchema = object({
|
|
13878
|
+
id: string(),
|
|
13879
|
+
label: string(),
|
|
13880
|
+
references: array(SceneReferenceSchema),
|
|
13881
|
+
textPrompts: array(string()).optional(),
|
|
13882
|
+
referenceCount: number(),
|
|
13883
|
+
currentlyMatched: boolean()
|
|
13884
|
+
});
|
|
13885
|
+
/** Per-mode comparator params in a discriminated union so an `llm` scene never
|
|
13886
|
+
* carries similarity knobs and vice-versa. */
|
|
13887
|
+
var SceneCheckSchema = discriminatedUnion("mode", [object({
|
|
13888
|
+
mode: literal("similarity"),
|
|
13889
|
+
threshold: number().min(0).max(1),
|
|
13890
|
+
hysteresisCount: number().int().positive()
|
|
13891
|
+
}), object({
|
|
13892
|
+
mode: literal("llm"),
|
|
13893
|
+
prompt: string(),
|
|
13894
|
+
profileId: string().optional(),
|
|
13895
|
+
hysteresisCount: number().int().positive()
|
|
13896
|
+
})]);
|
|
13897
|
+
var SceneMonitorSchema = object({
|
|
13898
|
+
id: string(),
|
|
13899
|
+
label: string(),
|
|
13900
|
+
roi: MaskRectShapeSchema,
|
|
13901
|
+
enabled: boolean(),
|
|
13902
|
+
triggerMode: _enum([
|
|
13903
|
+
"periodic",
|
|
13904
|
+
"on-motion",
|
|
13905
|
+
"both"
|
|
13906
|
+
]),
|
|
13907
|
+
checkIntervalSec: number().optional(),
|
|
13908
|
+
check: SceneCheckSchema,
|
|
13909
|
+
states: array(SceneMonitorStateSchema),
|
|
13910
|
+
currentStateId: string().nullable(),
|
|
13911
|
+
lastCheckedAt: number().nullable(),
|
|
13912
|
+
lastConfidence: number().nullable(),
|
|
13913
|
+
currentCondition: SceneConditionSchema.nullable(),
|
|
13914
|
+
availability: _enum(["ok", "unavailable"]),
|
|
13915
|
+
unavailableReason: string().nullable()
|
|
13916
|
+
});
|
|
13917
|
+
var SceneMonitorStatusSchema = object({
|
|
13918
|
+
monitors: array(SceneMonitorSchema),
|
|
13919
|
+
lastFetchedAt: number()
|
|
13920
|
+
});
|
|
13921
|
+
var sceneMonitorCapability = {
|
|
13922
|
+
name: "scene-monitor",
|
|
13923
|
+
scope: "device",
|
|
13924
|
+
mode: "singleton",
|
|
13925
|
+
kind: "wrapper",
|
|
13926
|
+
defaultActive: true,
|
|
13927
|
+
deviceTypes: [DeviceType.Camera],
|
|
13928
|
+
deviceConfig: { ui: {
|
|
13929
|
+
kind: "widget",
|
|
13930
|
+
widgetId: "host/scene-monitor-editor",
|
|
13931
|
+
tab: "scenes",
|
|
13932
|
+
label: "Scenes"
|
|
13933
|
+
} },
|
|
13934
|
+
methods: {
|
|
13935
|
+
listScenes: method(object({ deviceId: number() }), SceneMonitorStatusSchema),
|
|
13936
|
+
createScene: method(object({
|
|
13937
|
+
deviceId: number(),
|
|
13938
|
+
label: string(),
|
|
13939
|
+
roi: MaskRectShapeSchema,
|
|
13940
|
+
check: SceneCheckSchema,
|
|
13941
|
+
triggerMode: _enum([
|
|
13942
|
+
"periodic",
|
|
13943
|
+
"on-motion",
|
|
13944
|
+
"both"
|
|
13945
|
+
]).optional(),
|
|
13946
|
+
checkIntervalSec: number().optional()
|
|
13947
|
+
}), SceneMonitorSchema, {
|
|
13948
|
+
kind: "mutation",
|
|
13949
|
+
auth: "admin"
|
|
13950
|
+
}),
|
|
13951
|
+
updateScene: method(object({
|
|
13952
|
+
deviceId: number(),
|
|
13953
|
+
monitorId: string(),
|
|
13954
|
+
patch: object({
|
|
13955
|
+
label: string().optional(),
|
|
13956
|
+
roi: MaskRectShapeSchema.optional(),
|
|
13957
|
+
enabled: boolean().optional(),
|
|
13958
|
+
triggerMode: _enum([
|
|
13959
|
+
"periodic",
|
|
13960
|
+
"on-motion",
|
|
13961
|
+
"both"
|
|
13962
|
+
]).optional(),
|
|
13963
|
+
checkIntervalSec: number().optional(),
|
|
13964
|
+
check: SceneCheckSchema.optional()
|
|
13965
|
+
})
|
|
13966
|
+
}), _void(), {
|
|
13967
|
+
kind: "mutation",
|
|
13968
|
+
auth: "admin"
|
|
13969
|
+
}),
|
|
13970
|
+
deleteScene: method(object({
|
|
13971
|
+
deviceId: number(),
|
|
13972
|
+
monitorId: string()
|
|
13973
|
+
}), _void(), {
|
|
13974
|
+
kind: "mutation",
|
|
13975
|
+
auth: "admin"
|
|
13976
|
+
}),
|
|
13977
|
+
captureReference: method(object({
|
|
13978
|
+
deviceId: number(),
|
|
13979
|
+
monitorId: string(),
|
|
13980
|
+
stateId: string().optional(),
|
|
13981
|
+
label: string().optional(),
|
|
13982
|
+
condition: SceneConditionSchema.optional()
|
|
13983
|
+
}), object({
|
|
13984
|
+
stateId: string(),
|
|
13985
|
+
referenceCount: number()
|
|
13986
|
+
}), {
|
|
13987
|
+
kind: "mutation",
|
|
13988
|
+
auth: "admin"
|
|
13989
|
+
}),
|
|
13990
|
+
deleteReference: method(object({
|
|
13991
|
+
deviceId: number(),
|
|
13992
|
+
monitorId: string(),
|
|
13993
|
+
stateId: string(),
|
|
13994
|
+
index: number()
|
|
13995
|
+
}), _void(), {
|
|
13996
|
+
kind: "mutation",
|
|
13997
|
+
auth: "admin"
|
|
13998
|
+
}),
|
|
13999
|
+
recheckNow: method(object({
|
|
14000
|
+
deviceId: number(),
|
|
14001
|
+
monitorId: string()
|
|
14002
|
+
}), _void(), {
|
|
14003
|
+
kind: "mutation",
|
|
14004
|
+
auth: "admin"
|
|
14005
|
+
})
|
|
14006
|
+
},
|
|
14007
|
+
status: {
|
|
14008
|
+
schema: SceneMonitorStatusSchema,
|
|
14009
|
+
kind: "push"
|
|
14010
|
+
},
|
|
14011
|
+
runtimeState: SceneMonitorStatusSchema
|
|
14012
|
+
};
|
|
14013
|
+
/**
|
|
13663
14014
|
* Script-runner cap. Models HA `script.*` entities on
|
|
13664
14015
|
* `DeviceType.Script`. A Script is a pre-recorded action sequence
|
|
13665
14016
|
* that can be invoked imperatively — optionally with a variables
|
|
@@ -14391,6 +14742,36 @@ var ZoneScopeBreakdownSchema = PerScopeBreakdownSchema.extend({
|
|
|
14391
14742
|
* with the per-track detail panel and live overlay. */
|
|
14392
14743
|
trackIds: array(string()).readonly()
|
|
14393
14744
|
});
|
|
14745
|
+
/**
|
|
14746
|
+
* A parked ("stationary") object surfaced alongside occupancy — an object that
|
|
14747
|
+
* settled and stopped moving. It is NO LONGER a tracked object (the tracker was
|
|
14748
|
+
* told to forget it so it stops re-spawning tracks/events), but it IS still
|
|
14749
|
+
* physically present, so it keeps counting toward `frame` occupancy and is
|
|
14750
|
+
* listed here so the UI can show it in a dedicated "Stationary" section instead
|
|
14751
|
+
* of flooding the live event feed.
|
|
14752
|
+
*/
|
|
14753
|
+
var StationaryObjectSchema = object({
|
|
14754
|
+
id: string(),
|
|
14755
|
+
className: string(),
|
|
14756
|
+
bbox: object({
|
|
14757
|
+
x: number(),
|
|
14758
|
+
y: number(),
|
|
14759
|
+
w: number(),
|
|
14760
|
+
h: number()
|
|
14761
|
+
}),
|
|
14762
|
+
frameWidth: number().int().nonnegative(),
|
|
14763
|
+
frameHeight: number().int().nonnegative(),
|
|
14764
|
+
/** When the source track was first seen. */
|
|
14765
|
+
firstSeenAt: number().int(),
|
|
14766
|
+
/** When the object was recognised as parked (promotion time). */
|
|
14767
|
+
becameStationaryAt: number().int(),
|
|
14768
|
+
/** Last frame a detection confirmed the object is still there. */
|
|
14769
|
+
lastConfirmedAt: number().int(),
|
|
14770
|
+
/** Enrichment label carried from the source track (identity / plate). */
|
|
14771
|
+
label: string().optional(),
|
|
14772
|
+
/** Native-resolution key-frame media key for the parked object's best image. */
|
|
14773
|
+
keyFrameMediaKey: string().optional()
|
|
14774
|
+
});
|
|
14394
14775
|
var CameraOccupancySnapshotSchema = object({
|
|
14395
14776
|
/** Frame timestamp of the inference result that produced this snapshot. */
|
|
14396
14777
|
ts: number().int(),
|
|
@@ -14399,10 +14780,15 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
14399
14780
|
frameHeight: number().int().nonnegative(),
|
|
14400
14781
|
/** Per-zone breakdown — one entry per defined zone (user + onboard). */
|
|
14401
14782
|
zones: array(ZoneScopeBreakdownSchema).readonly(),
|
|
14402
|
-
/** Frame-wide aggregate (everywhere, regardless of zone membership).
|
|
14783
|
+
/** Frame-wide aggregate (everywhere, regardless of zone membership).
|
|
14784
|
+
* INCLUDES currently-confirmed stationary objects (they are still present). */
|
|
14403
14785
|
frame: PerScopeBreakdownSchema,
|
|
14404
14786
|
/** Detections that landed outside every zone. Empty when no zones defined. */
|
|
14405
|
-
unzoned: PerScopeBreakdownSchema
|
|
14787
|
+
unzoned: PerScopeBreakdownSchema,
|
|
14788
|
+
/** Parked objects on this camera (additive — absent on legacy snapshots).
|
|
14789
|
+
* Surfaced separately so the UI shows them in a dedicated section rather
|
|
14790
|
+
* than as repeated tracks/events. */
|
|
14791
|
+
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
14406
14792
|
});
|
|
14407
14793
|
/**
|
|
14408
14794
|
* Time-series resolution. The history methods return one bucket per
|
|
@@ -14637,6 +15023,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
14637
15023
|
pressureSensor: pressureSensorCapability,
|
|
14638
15024
|
privacyMask: privacyMaskCapability,
|
|
14639
15025
|
ptzAutotrack: ptzAutotrackCapability,
|
|
15026
|
+
sceneMonitor: sceneMonitorCapability,
|
|
14640
15027
|
scriptRunner: scriptRunnerCapability,
|
|
14641
15028
|
smoke: smokeCapability,
|
|
14642
15029
|
streamParams: streamParamsCapability,
|
|
@@ -15689,7 +16076,26 @@ var InvokeReplyEnvelopeSchema = object({
|
|
|
15689
16076
|
/** Set when the handler called `reply.type(mime)`. */
|
|
15690
16077
|
contentType: string().optional()
|
|
15691
16078
|
});
|
|
15692
|
-
|
|
16079
|
+
var addonRoutesCapability = {
|
|
16080
|
+
name: "addon-routes",
|
|
16081
|
+
scope: "system",
|
|
16082
|
+
mode: "collection",
|
|
16083
|
+
internal: true,
|
|
16084
|
+
methods: {
|
|
16085
|
+
getRoutes: method(_void(), array(AddonHttpRouteSchema)),
|
|
16086
|
+
/**
|
|
16087
|
+
* Cross-process dispatch entry point. Forked addons implement this
|
|
16088
|
+
* (via `buildAddonRouteProvider`) so the hub's Fastify catch-all
|
|
16089
|
+
* can route through Moleculer when the handler lives in a worker.
|
|
16090
|
+
*
|
|
16091
|
+
* Local addons can implement it for free with the same helper;
|
|
16092
|
+
* the hub bypasses the wire on co-located addons.
|
|
16093
|
+
*/
|
|
16094
|
+
invoke: method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" })
|
|
16095
|
+
},
|
|
16096
|
+
/** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
|
|
16097
|
+
mount: { kind: "skip" }
|
|
16098
|
+
};
|
|
15693
16099
|
var ConfigTabDeclarationSchema = object({
|
|
15694
16100
|
id: string(),
|
|
15695
16101
|
label: string(),
|
|
@@ -15922,7 +16328,12 @@ var NotificationRuleConditionsSchema = object({
|
|
|
15922
16328
|
clipDescription: object({
|
|
15923
16329
|
text: string().min(1),
|
|
15924
16330
|
minSimilarity: number().min(0).max(1)
|
|
15925
|
-
}).optional()
|
|
16331
|
+
}).optional(),
|
|
16332
|
+
/** Match events whose recognized-entity label (face identity name or plate
|
|
16333
|
+
* vehicle name, propagated onto `event.data.label`) is one of these values.
|
|
16334
|
+
* Empty/absent → unaffected (back-compat). Enables "notify me when <named
|
|
16335
|
+
* vehicle/person> is seen". */
|
|
16336
|
+
labels: array(string()).readonly().optional()
|
|
15926
16337
|
});
|
|
15927
16338
|
var NotificationRuleTemplateSchema = object({
|
|
15928
16339
|
title: string(),
|
|
@@ -16180,11 +16591,19 @@ method(object({
|
|
|
16180
16591
|
* login page needs NO change.
|
|
16181
16592
|
*
|
|
16182
16593
|
* - `widget` — a Module-Federation widget the login page mounts (via
|
|
16183
|
-
* `loadRemoteBundle`) for an in-page ceremony.
|
|
16184
|
-
*
|
|
16185
|
-
*
|
|
16186
|
-
*
|
|
16187
|
-
*
|
|
16594
|
+
* `loadRemoteBundle`) for an in-page ceremony. `auth.listLoginMethods`
|
|
16595
|
+
* stamps a public `bundleUrl` from `addonId` + `bundle`. Generic
|
|
16596
|
+
* mechanism kept for future use; no shipped addon uses it on the login
|
|
16597
|
+
* page (the passkey ceremony below runs natively in the shell instead).
|
|
16598
|
+
*
|
|
16599
|
+
* - `passkey` — a declarative WebAuthn ceremony the shell renders
|
|
16600
|
+
* natively (`@simplewebauthn/browser` lives in `addon-admin-ui`, not in
|
|
16601
|
+
* a remotely-loaded bundle). Carries the addon's effective `rpId` /
|
|
16602
|
+
* `origin` (from its `resolveRpID()` / `resolveOrigin()`) so the shell
|
|
16603
|
+
* can gate visibility (IP-literal origin, hostname/rpId mismatch) WITHOUT
|
|
16604
|
+
* fetching any remote code pre-auth. Contribution stays unconditional —
|
|
16605
|
+
* enrollment state is never leaked pre-auth; visibility is a shell
|
|
16606
|
+
* decision.
|
|
16188
16607
|
*
|
|
16189
16608
|
* Every contribution carries a `stage`:
|
|
16190
16609
|
* - `primary` — shown on the first credentials screen (OIDC /
|
|
@@ -16198,30 +16617,45 @@ method(object({
|
|
|
16198
16617
|
*/
|
|
16199
16618
|
/** When a login method renders in the two-phase login flow. */
|
|
16200
16619
|
var LoginStageEnum = _enum(["primary", "second-factor"]);
|
|
16201
|
-
/** One login-method contribution — redirect button
|
|
16202
|
-
var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
|
|
16215
|
-
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16620
|
+
/** One login-method contribution — redirect button, pre-auth widget, or native passkey ceremony. */
|
|
16621
|
+
var LoginMethodContributionSchema = discriminatedUnion("kind", [
|
|
16622
|
+
object({
|
|
16623
|
+
kind: literal("redirect"),
|
|
16624
|
+
/** Stable id within the login-method set (e.g. `auth-oidc/google`). */
|
|
16625
|
+
id: string(),
|
|
16626
|
+
/** Operator-facing button label. */
|
|
16627
|
+
label: string(),
|
|
16628
|
+
/** lucide-react icon name. */
|
|
16629
|
+
icon: string().optional(),
|
|
16630
|
+
/** Addon-owned HTTP route the button navigates to (GET). */
|
|
16631
|
+
startUrl: string(),
|
|
16632
|
+
stage: LoginStageEnum
|
|
16633
|
+
}),
|
|
16634
|
+
object({
|
|
16635
|
+
kind: literal("widget"),
|
|
16636
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
|
|
16637
|
+
id: string(),
|
|
16638
|
+
/** Owning addon id — drives the public bundle URL + the MF namespace. */
|
|
16639
|
+
addonId: string(),
|
|
16640
|
+
/** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
|
|
16641
|
+
bundle: string(),
|
|
16642
|
+
/** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
|
|
16643
|
+
remote: WidgetRemoteSchema,
|
|
16644
|
+
stage: LoginStageEnum
|
|
16645
|
+
}),
|
|
16646
|
+
object({
|
|
16647
|
+
kind: literal("passkey"),
|
|
16648
|
+
/** Stable id within the login-method set (e.g. `auth-webauthn/passkey-direct-login`). */
|
|
16649
|
+
id: string(),
|
|
16650
|
+
/** Operator-facing button label. */
|
|
16651
|
+
label: string(),
|
|
16652
|
+
stage: LoginStageEnum,
|
|
16653
|
+
/** Effective WebAuthn RP ID (`resolveRpID()`) — the shell gates visibility on it. */
|
|
16654
|
+
rpId: string(),
|
|
16655
|
+
/** Effective expected origin (`resolveOrigin()`), null when unconfigured. */
|
|
16656
|
+
origin: string().nullable()
|
|
16657
|
+
})
|
|
16658
|
+
]);
|
|
16225
16659
|
method(_void(), array(LoginMethodContributionSchema).readonly());
|
|
16226
16660
|
/**
|
|
16227
16661
|
* Orchestrator-side destination metadata. The orchestrator computes
|
|
@@ -18115,14 +18549,14 @@ var TargetKindCapsSchema = object({
|
|
|
18115
18549
|
* the union is large and not meant for runtime validation here; the exported
|
|
18116
18550
|
* `TargetKind` type re-tightens `configSchema` to `ConfigUISchema`.
|
|
18117
18551
|
*/
|
|
18118
|
-
var ConfigSchemaPassthrough = unknown();
|
|
18552
|
+
var ConfigSchemaPassthrough$1 = unknown();
|
|
18119
18553
|
var TargetKindSchema = object({
|
|
18120
18554
|
kind: string(),
|
|
18121
18555
|
label: string(),
|
|
18122
18556
|
icon: string(),
|
|
18123
18557
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
18124
18558
|
addonId: string(),
|
|
18125
|
-
configSchema: ConfigSchemaPassthrough,
|
|
18559
|
+
configSchema: ConfigSchemaPassthrough$1,
|
|
18126
18560
|
supportsDiscovery: boolean(),
|
|
18127
18561
|
caps: TargetKindCapsSchema
|
|
18128
18562
|
});
|
|
@@ -18189,6 +18623,298 @@ var notificationOutputCapability = {
|
|
|
18189
18623
|
}
|
|
18190
18624
|
};
|
|
18191
18625
|
/**
|
|
18626
|
+
* Shared LLM generate contracts — imported by BOTH `llm.cap.ts` (consumer
|
|
18627
|
+
* surface) and `llm-runtime.cap.ts` (node-side managed executor) so the two
|
|
18628
|
+
* caps stay wire-compatible without a circular cap→cap import.
|
|
18629
|
+
*
|
|
18630
|
+
* Errors are a discriminated-union RESULT, never thrown: the shape survives
|
|
18631
|
+
* every transport tier structurally, and failed calls still write usage rows.
|
|
18632
|
+
* Token counts only in v1 — no costUsd (operator decision, 2026-07-15).
|
|
18633
|
+
*/
|
|
18634
|
+
var LlmUsageSchema = object({
|
|
18635
|
+
inputTokens: number(),
|
|
18636
|
+
outputTokens: number()
|
|
18637
|
+
});
|
|
18638
|
+
var LlmErrorCodeSchema = _enum([
|
|
18639
|
+
"timeout",
|
|
18640
|
+
"rate-limited",
|
|
18641
|
+
"auth",
|
|
18642
|
+
"refusal",
|
|
18643
|
+
"bad-request",
|
|
18644
|
+
"unavailable",
|
|
18645
|
+
"no-profile",
|
|
18646
|
+
"budget-exceeded",
|
|
18647
|
+
"adapter-error"
|
|
18648
|
+
]);
|
|
18649
|
+
var LlmGenerateResultSchema = discriminatedUnion("ok", [object({
|
|
18650
|
+
ok: literal(true),
|
|
18651
|
+
text: string(),
|
|
18652
|
+
model: string(),
|
|
18653
|
+
usage: LlmUsageSchema,
|
|
18654
|
+
truncated: boolean(),
|
|
18655
|
+
latencyMs: number()
|
|
18656
|
+
}), object({
|
|
18657
|
+
ok: literal(false),
|
|
18658
|
+
code: LlmErrorCodeSchema,
|
|
18659
|
+
message: string(),
|
|
18660
|
+
retryAfterMs: number().optional()
|
|
18661
|
+
})]);
|
|
18662
|
+
/**
|
|
18663
|
+
* `Uint8Array` is the sanctioned binary convention — superjson + the UDS
|
|
18664
|
+
* MsgPack channel round-trip typed arrays (embedding-encoder.cap.ts:29,
|
|
18665
|
+
* notification-output.cap.ts:27-31 precedents).
|
|
18666
|
+
*/
|
|
18667
|
+
var LlmImageSchema = object({
|
|
18668
|
+
bytes: _instanceof(Uint8Array),
|
|
18669
|
+
mimeType: string()
|
|
18670
|
+
});
|
|
18671
|
+
var LlmGenerateBaseInputSchema = object({
|
|
18672
|
+
/** Collection routing (the notification-output posture). */
|
|
18673
|
+
addonId: string().optional(),
|
|
18674
|
+
/** Explicit profile; else the resolution chain (spec §3). */
|
|
18675
|
+
profileId: string().optional(),
|
|
18676
|
+
/** MANDATORY usage tag: 'ai-summary', 'notifier-rules', 'adhoc-ui', … */
|
|
18677
|
+
consumer: string(),
|
|
18678
|
+
system: string().optional(),
|
|
18679
|
+
/** v1: single-turn. `messages[]` is a v2 additive field. */
|
|
18680
|
+
prompt: string(),
|
|
18681
|
+
/** Structured output — adapter-mapped (response_format / forced tool / responseSchema). */
|
|
18682
|
+
jsonSchema: record(string(), unknown()).optional(),
|
|
18683
|
+
/** Per-call override of the profile default. */
|
|
18684
|
+
maxTokens: number().int().positive().optional(),
|
|
18685
|
+
temperature: number().optional()
|
|
18686
|
+
});
|
|
18687
|
+
/**
|
|
18688
|
+
* `llm-runtime` — node-side managed llama.cpp executor (spec §4). Registered
|
|
18689
|
+
* on EVERY node where `addon-ai` is installed; the hub `llm` provider reaches
|
|
18690
|
+
* a specific node's runtime with `nodePin(profile.runtime.nodeId)` — normal
|
|
18691
|
+
* cap routing, zero bespoke plumbing. `internal: true`: the operator reaches
|
|
18692
|
+
* this only through the `llm` cap's methods.
|
|
18693
|
+
*
|
|
18694
|
+
* One running llama-server child per node in v1 (models are RAM-heavy).
|
|
18695
|
+
* Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
|
|
18696
|
+
* watchdog — operator decision #3).
|
|
18697
|
+
*/
|
|
18698
|
+
var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
18699
|
+
object({
|
|
18700
|
+
kind: literal("catalog"),
|
|
18701
|
+
catalogId: string()
|
|
18702
|
+
}),
|
|
18703
|
+
object({
|
|
18704
|
+
kind: literal("url"),
|
|
18705
|
+
url: string(),
|
|
18706
|
+
sha256: string().optional()
|
|
18707
|
+
}),
|
|
18708
|
+
object({
|
|
18709
|
+
kind: literal("path"),
|
|
18710
|
+
path: string()
|
|
18711
|
+
})
|
|
18712
|
+
]);
|
|
18713
|
+
var ManagedRuntimeConfigSchema = object({
|
|
18714
|
+
/** WHERE the runtime lives — hub or any agent. */
|
|
18715
|
+
nodeId: string(),
|
|
18716
|
+
/** Closed for v1; 'ollama' is a v2 candidate. */
|
|
18717
|
+
engine: _enum(["llama-cpp"]),
|
|
18718
|
+
model: ManagedModelRefSchema,
|
|
18719
|
+
contextSize: number().int().default(4096),
|
|
18720
|
+
/** 0 = CPU-only. */
|
|
18721
|
+
gpuLayers: number().int().default(0),
|
|
18722
|
+
/** Default: cpus-2, clamped ≥1 (resolved node-side). */
|
|
18723
|
+
threads: number().int().optional(),
|
|
18724
|
+
/** Concurrent slots. */
|
|
18725
|
+
parallel: number().int().default(1),
|
|
18726
|
+
/** Else lazy: first generate boots it. */
|
|
18727
|
+
autoStart: boolean().default(false),
|
|
18728
|
+
/** 0 = never; frees RAM after quiet periods. */
|
|
18729
|
+
idleStopMinutes: number().int().default(30)
|
|
18730
|
+
});
|
|
18731
|
+
var LlmRuntimeStatusSchema = object({
|
|
18732
|
+
/** Status is ALWAYS node-qualified. */
|
|
18733
|
+
nodeId: string(),
|
|
18734
|
+
state: _enum([
|
|
18735
|
+
"stopped",
|
|
18736
|
+
"downloading",
|
|
18737
|
+
"starting",
|
|
18738
|
+
"ready",
|
|
18739
|
+
"crashed",
|
|
18740
|
+
"failed"
|
|
18741
|
+
]),
|
|
18742
|
+
pid: number().optional(),
|
|
18743
|
+
port: number().optional(),
|
|
18744
|
+
modelPath: string().optional(),
|
|
18745
|
+
modelId: string().optional(),
|
|
18746
|
+
downloadProgress: number().min(0).max(1).optional(),
|
|
18747
|
+
lastError: string().optional(),
|
|
18748
|
+
crashesInWindow: number(),
|
|
18749
|
+
/** Child RSS (sampled best-effort). */
|
|
18750
|
+
memoryBytes: number().optional(),
|
|
18751
|
+
vramBytes: number().optional()
|
|
18752
|
+
});
|
|
18753
|
+
var LlmNodeModelSchema = object({
|
|
18754
|
+
file: string(),
|
|
18755
|
+
sizeBytes: number(),
|
|
18756
|
+
catalogId: string().optional(),
|
|
18757
|
+
installedAt: number().optional()
|
|
18758
|
+
});
|
|
18759
|
+
var LlmRuntimeDiskUsageSchema = object({
|
|
18760
|
+
nodeId: string(),
|
|
18761
|
+
modelsBytes: number(),
|
|
18762
|
+
freeBytes: number().optional()
|
|
18763
|
+
});
|
|
18764
|
+
method(LlmGenerateBaseInputSchema.extend({
|
|
18765
|
+
images: array(LlmImageSchema).optional(),
|
|
18766
|
+
runtime: ManagedRuntimeConfigSchema,
|
|
18767
|
+
/** The managed profile's timeout, threaded by the hub provider. */
|
|
18768
|
+
timeoutMs: number().int().positive().optional()
|
|
18769
|
+
}), LlmGenerateResultSchema, { kind: "mutation" }), method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
|
|
18770
|
+
kind: "mutation",
|
|
18771
|
+
auth: "admin"
|
|
18772
|
+
}), method(object({}), _void(), {
|
|
18773
|
+
kind: "mutation",
|
|
18774
|
+
auth: "admin"
|
|
18775
|
+
}), method(object({}), LlmRuntimeStatusSchema), method(object({ model: ManagedModelRefSchema }), _void(), {
|
|
18776
|
+
kind: "mutation",
|
|
18777
|
+
auth: "admin"
|
|
18778
|
+
}), method(object({ file: string() }), _void(), {
|
|
18779
|
+
kind: "mutation",
|
|
18780
|
+
auth: "admin"
|
|
18781
|
+
}), method(object({}), array(LlmNodeModelSchema)), method(object({}), LlmRuntimeDiskUsageSchema);
|
|
18782
|
+
/**
|
|
18783
|
+
* `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
|
|
18784
|
+
* methods concat-fan across providers; single-row methods route to ONE
|
|
18785
|
+
* provider by the `addonId` in the call input (the notification-output
|
|
18786
|
+
* posture, notification-output.cap.ts:215-250). Provided by `addon-ai`
|
|
18787
|
+
* (hub-placed); the cap stays open for future providers.
|
|
18788
|
+
*
|
|
18789
|
+
* Profiles are ROWS (data), not addons: one row = one usable model endpoint.
|
|
18790
|
+
* `apiKey` is a password field — providers REDACT it on read and merge on
|
|
18791
|
+
* write; a stored key NEVER round-trips to a client.
|
|
18792
|
+
*/
|
|
18793
|
+
var LlmProfileKindSchema = _enum([
|
|
18794
|
+
"openai-compatible",
|
|
18795
|
+
"openai",
|
|
18796
|
+
"anthropic",
|
|
18797
|
+
"google",
|
|
18798
|
+
"managed-local"
|
|
18799
|
+
]);
|
|
18800
|
+
var LlmProfileSchema = object({
|
|
18801
|
+
id: string(),
|
|
18802
|
+
name: string(),
|
|
18803
|
+
kind: LlmProfileKindSchema,
|
|
18804
|
+
/** Stamped by the provider — keeps the fanned catalog routable. */
|
|
18805
|
+
addonId: string(),
|
|
18806
|
+
enabled: boolean(),
|
|
18807
|
+
/** Vendor model id, or the managed runtime's loaded model. */
|
|
18808
|
+
model: string(),
|
|
18809
|
+
/** Required for openai-compatible; override for cloud kinds. */
|
|
18810
|
+
baseUrl: string().optional(),
|
|
18811
|
+
/** ConfigUISchema type:'password' — never round-trips (spec §5). */
|
|
18812
|
+
apiKey: string().optional(),
|
|
18813
|
+
supportsVision: boolean(),
|
|
18814
|
+
temperature: number().min(0).max(2).optional(),
|
|
18815
|
+
maxTokens: number().int().positive().optional(),
|
|
18816
|
+
timeoutMs: number().int().positive().default(6e4),
|
|
18817
|
+
extraHeaders: record(string(), string()).optional(),
|
|
18818
|
+
/** kind === 'managed-local' only (spec §4). */
|
|
18819
|
+
runtime: ManagedRuntimeConfigSchema.optional()
|
|
18820
|
+
});
|
|
18821
|
+
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
18822
|
+
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
18823
|
+
* notification-output.cap.ts:151); the exported TS type re-tightens it. */
|
|
18824
|
+
var ConfigSchemaPassthrough = unknown();
|
|
18825
|
+
var LlmProfileKindDescriptorSchema = object({
|
|
18826
|
+
kind: LlmProfileKindSchema,
|
|
18827
|
+
label: string(),
|
|
18828
|
+
icon: string(),
|
|
18829
|
+
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
18830
|
+
addonId: string(),
|
|
18831
|
+
configSchema: ConfigSchemaPassthrough
|
|
18832
|
+
});
|
|
18833
|
+
var LlmDefaultSelectorSchema = union([object({ consumer: string() }), object({ purpose: _enum(["text", "vision"]) })]);
|
|
18834
|
+
var LlmDefaultSchema = object({
|
|
18835
|
+
selector: LlmDefaultSelectorSchema,
|
|
18836
|
+
profileId: string()
|
|
18837
|
+
});
|
|
18838
|
+
/** Server-side rollup row — getUsage never dumps raw call rows (spec §6). */
|
|
18839
|
+
var LlmUsageRollupSchema = object({
|
|
18840
|
+
day: string(),
|
|
18841
|
+
consumer: string(),
|
|
18842
|
+
profileId: string(),
|
|
18843
|
+
calls: number(),
|
|
18844
|
+
okCalls: number(),
|
|
18845
|
+
errorCalls: number(),
|
|
18846
|
+
inputTokens: number(),
|
|
18847
|
+
outputTokens: number(),
|
|
18848
|
+
avgLatencyMs: number()
|
|
18849
|
+
});
|
|
18850
|
+
/** LLM-facing view over the reused ModelCatalogEntry mechanism (spec §4.2). */
|
|
18851
|
+
var ManagedModelCatalogEntrySchema = object({
|
|
18852
|
+
id: string(),
|
|
18853
|
+
label: string(),
|
|
18854
|
+
family: string(),
|
|
18855
|
+
purpose: _enum(["text", "vision"]),
|
|
18856
|
+
url: string(),
|
|
18857
|
+
sha256: string(),
|
|
18858
|
+
sizeBytes: number(),
|
|
18859
|
+
quantization: string(),
|
|
18860
|
+
/** Load-time guidance shown in the picker. */
|
|
18861
|
+
minRamBytes: number(),
|
|
18862
|
+
contextSizeDefault: number().int(),
|
|
18863
|
+
/** Vision models: companion projector file. */
|
|
18864
|
+
mmprojUrl: string().optional()
|
|
18865
|
+
});
|
|
18866
|
+
var LlmRuntimeNodeSchema = object({
|
|
18867
|
+
nodeId: string(),
|
|
18868
|
+
reachable: boolean(),
|
|
18869
|
+
status: LlmRuntimeStatusSchema.optional(),
|
|
18870
|
+
disk: LlmRuntimeDiskUsageSchema.optional(),
|
|
18871
|
+
error: string().optional()
|
|
18872
|
+
});
|
|
18873
|
+
var GenerateVisionInputSchema = LlmGenerateBaseInputSchema.extend({ images: array(LlmImageSchema).min(1) });
|
|
18874
|
+
var ProfileRefInputSchema = object({
|
|
18875
|
+
addonId: string(),
|
|
18876
|
+
profileId: string()
|
|
18877
|
+
});
|
|
18878
|
+
method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(GenerateVisionInputSchema, LlmGenerateResultSchema, { kind: "mutation" }), method(object({}), array(LlmProfileKindDescriptorSchema)), method(object({}), array(LlmProfileSchema)), method(object({ profile: LlmProfileSchema }), LlmProfileSchema, {
|
|
18879
|
+
kind: "mutation",
|
|
18880
|
+
auth: "admin"
|
|
18881
|
+
}), method(ProfileRefInputSchema, _void(), {
|
|
18882
|
+
kind: "mutation",
|
|
18883
|
+
auth: "admin"
|
|
18884
|
+
}), method(ProfileRefInputSchema, LlmGenerateResultSchema, {
|
|
18885
|
+
kind: "mutation",
|
|
18886
|
+
auth: "admin"
|
|
18887
|
+
}), method(ProfileRefInputSchema, array(string())), method(object({}), array(LlmDefaultSchema)), method(object({
|
|
18888
|
+
selector: LlmDefaultSelectorSchema,
|
|
18889
|
+
profileId: string().nullable()
|
|
18890
|
+
}), _void(), {
|
|
18891
|
+
kind: "mutation",
|
|
18892
|
+
auth: "admin"
|
|
18893
|
+
}), method(object({
|
|
18894
|
+
since: number().optional(),
|
|
18895
|
+
until: number().optional(),
|
|
18896
|
+
consumer: string().optional(),
|
|
18897
|
+
profileId: string().optional()
|
|
18898
|
+
}), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
|
|
18899
|
+
nodeId: string(),
|
|
18900
|
+
model: ManagedModelRefSchema
|
|
18901
|
+
}), _void(), {
|
|
18902
|
+
kind: "mutation",
|
|
18903
|
+
auth: "admin"
|
|
18904
|
+
}), method(object({
|
|
18905
|
+
nodeId: string(),
|
|
18906
|
+
file: string()
|
|
18907
|
+
}), _void(), {
|
|
18908
|
+
kind: "mutation",
|
|
18909
|
+
auth: "admin"
|
|
18910
|
+
}), method(ProfileRefInputSchema, LlmRuntimeStatusSchema), method(ProfileRefInputSchema, LlmRuntimeStatusSchema, {
|
|
18911
|
+
kind: "mutation",
|
|
18912
|
+
auth: "admin"
|
|
18913
|
+
}), method(ProfileRefInputSchema, _void(), {
|
|
18914
|
+
kind: "mutation",
|
|
18915
|
+
auth: "admin"
|
|
18916
|
+
});
|
|
18917
|
+
/**
|
|
18192
18918
|
* Zod schemas for persisted record types.
|
|
18193
18919
|
*
|
|
18194
18920
|
* These schemas serve as the single source of truth for types that are
|
|
@@ -18390,6 +19116,22 @@ var TrackSnapshotSchema = object({
|
|
|
18390
19116
|
/** MediaStore key; resolve via `getTrackMedia({ trackId })`. */
|
|
18391
19117
|
mediaKey: string()
|
|
18392
19118
|
});
|
|
19119
|
+
/**
|
|
19120
|
+
* One audio-classification label heard on the track's camera while the
|
|
19121
|
+
* track was alive, aggregated per label. An "episode" is one persisted
|
|
19122
|
+
* audio event (the confident-classification path: score ≥ the device's
|
|
19123
|
+
* `classificationMinScore`, class-change-or-heartbeat coalesced) — NOT
|
|
19124
|
+
* one 32 ms inference chunk, so counts stay human-scaled.
|
|
19125
|
+
*/
|
|
19126
|
+
var TrackAudioLabelSchema = object({
|
|
19127
|
+
label: string(),
|
|
19128
|
+
/** Highest classification score observed across the label's episodes. */
|
|
19129
|
+
peakScore: number(),
|
|
19130
|
+
/** Number of coalesced audio-event episodes carrying this label. */
|
|
19131
|
+
count: number(),
|
|
19132
|
+
firstAt: number(),
|
|
19133
|
+
lastAt: number()
|
|
19134
|
+
});
|
|
18393
19135
|
var TrackSchema = object({
|
|
18394
19136
|
trackId: string(),
|
|
18395
19137
|
deviceId: number(),
|
|
@@ -18404,6 +19146,10 @@ var TrackSchema = object({
|
|
|
18404
19146
|
snapshots: array(TrackSnapshotSchema).readonly(),
|
|
18405
19147
|
/** Deduplicated zones the track has entered at least once. */
|
|
18406
19148
|
zonesVisited: array(string()).readonly(),
|
|
19149
|
+
/** Deduplicated set of detector classes observed for this track over its
|
|
19150
|
+
* life (a track may be reclassified, e.g. person→vehicle). Absent on
|
|
19151
|
+
* legacy rows written before class accumulation shipped. */
|
|
19152
|
+
classes: array(string()).readonly().optional(),
|
|
18407
19153
|
/** Cumulative normalized distance travelled (0..1 units = full frame width). */
|
|
18408
19154
|
totalDistance: number(),
|
|
18409
19155
|
state: TrackStateSchema,
|
|
@@ -18417,7 +19163,11 @@ var TrackSchema = object({
|
|
|
18417
19163
|
bestEventId: string().optional(),
|
|
18418
19164
|
/** Tag of the importance sub-signal that dominated the score
|
|
18419
19165
|
* (identity|dwell|proximity|class|confidence|travel|zone). */
|
|
18420
|
-
importanceReason: string().optional()
|
|
19166
|
+
importanceReason: string().optional(),
|
|
19167
|
+
/** Audio-classification labels heard on the camera during the track's
|
|
19168
|
+
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
19169
|
+
* Absent on legacy rows / tracks with no confident audio. */
|
|
19170
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
18421
19171
|
});
|
|
18422
19172
|
var BaseEventFields = {
|
|
18423
19173
|
id: string(),
|
|
@@ -18565,7 +19315,7 @@ var KeyEventSchema = object({
|
|
|
18565
19315
|
/** Track lifetime in ms (lastSeen - firstSeen). */
|
|
18566
19316
|
windowMs: number().optional()
|
|
18567
19317
|
});
|
|
18568
|
-
|
|
19318
|
+
object({
|
|
18569
19319
|
trackId: string(),
|
|
18570
19320
|
className: string(),
|
|
18571
19321
|
confidence: number(),
|
|
@@ -18573,6 +19323,23 @@ var TrackedDetectionSchema = object({
|
|
|
18573
19323
|
zones: array(string()).readonly(),
|
|
18574
19324
|
state: TrackStateSchema
|
|
18575
19325
|
});
|
|
19326
|
+
var OverlayDetectionSchema = looseObject({
|
|
19327
|
+
id: string(),
|
|
19328
|
+
kind: _enum(["first-level", "detail"]),
|
|
19329
|
+
macroClass: string(),
|
|
19330
|
+
score: number(),
|
|
19331
|
+
bbox: object({
|
|
19332
|
+
x: number(),
|
|
19333
|
+
y: number(),
|
|
19334
|
+
width: number(),
|
|
19335
|
+
height: number()
|
|
19336
|
+
}),
|
|
19337
|
+
labels: array(looseObject({
|
|
19338
|
+
label: string(),
|
|
19339
|
+
score: number()
|
|
19340
|
+
})).readonly(),
|
|
19341
|
+
parentId: string().optional()
|
|
19342
|
+
});
|
|
18576
19343
|
var ScoredObjectEventSchema = ObjectEventSchema.extend({ score: number() });
|
|
18577
19344
|
var SearchObjectEventsInput = object({
|
|
18578
19345
|
text: string(),
|
|
@@ -18583,6 +19350,20 @@ var SearchObjectEventsInput = object({
|
|
|
18583
19350
|
limit: number().default(50),
|
|
18584
19351
|
minScore: number().min(0).max(1).default(.2)
|
|
18585
19352
|
});
|
|
19353
|
+
var TrackCascadeCountsSchema = object({
|
|
19354
|
+
/** Persisted track roots deleted (authoritative). */
|
|
19355
|
+
tracks: number().int(),
|
|
19356
|
+
/** Object events removed with their tracks (best-effort; see note above). */
|
|
19357
|
+
events: number().int(),
|
|
19358
|
+
/** Track/face/plate-owned media removed (best-effort). Never identity media. */
|
|
19359
|
+
media: number().int(),
|
|
19360
|
+
/** Unassigned (non-enrolled) face reads removed (best-effort). */
|
|
19361
|
+
faces: number().int(),
|
|
19362
|
+
/** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
|
|
19363
|
+
plates: number().int(),
|
|
19364
|
+
/** Per-track CLIP search vectors removed (best-effort). */
|
|
19365
|
+
embeddings: number().int()
|
|
19366
|
+
});
|
|
18586
19367
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
18587
19368
|
deviceId: number(),
|
|
18588
19369
|
trackId: string()
|
|
@@ -18614,6 +19395,24 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18614
19395
|
}), {
|
|
18615
19396
|
kind: "mutation",
|
|
18616
19397
|
auth: "admin"
|
|
19398
|
+
}), method(object({
|
|
19399
|
+
deviceId: number(),
|
|
19400
|
+
cutoffMs: number()
|
|
19401
|
+
}), TrackCascadeCountsSchema, {
|
|
19402
|
+
kind: "mutation",
|
|
19403
|
+
auth: "admin"
|
|
19404
|
+
}), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
|
|
19405
|
+
kind: "mutation",
|
|
19406
|
+
auth: "admin"
|
|
19407
|
+
}), method(object({
|
|
19408
|
+
deviceId: number(),
|
|
19409
|
+
trackIds: array(string()).min(1)
|
|
19410
|
+
}), object({
|
|
19411
|
+
deleted: number().int(),
|
|
19412
|
+
failed: array(string()).readonly()
|
|
19413
|
+
}), {
|
|
19414
|
+
kind: "mutation",
|
|
19415
|
+
auth: "admin"
|
|
18617
19416
|
}), method(object({
|
|
18618
19417
|
eventId: string(),
|
|
18619
19418
|
kind: MediaFileKindEnum.optional()
|
|
@@ -18622,7 +19421,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18622
19421
|
timestamp: number(),
|
|
18623
19422
|
frameWidth: number(),
|
|
18624
19423
|
frameHeight: number(),
|
|
18625
|
-
detections: array(
|
|
19424
|
+
detections: array(OverlayDetectionSchema).readonly()
|
|
18626
19425
|
}), object({
|
|
18627
19426
|
deviceId: number(),
|
|
18628
19427
|
trackId: string(),
|
|
@@ -21480,6 +22279,24 @@ DeviceType.Camera, method(object({
|
|
|
21480
22279
|
deviceId: number(),
|
|
21481
22280
|
status: OsdStatusSchema
|
|
21482
22281
|
});
|
|
22282
|
+
var VehicleSchema = object({
|
|
22283
|
+
id: string(),
|
|
22284
|
+
name: string(),
|
|
22285
|
+
sampleCount: number().int().nonnegative(),
|
|
22286
|
+
coverMediaKey: string().optional(),
|
|
22287
|
+
/** Inline base64 of the cover sample's plate crop, resolved from `coverMediaKey`. */
|
|
22288
|
+
coverBase64: string().optional()
|
|
22289
|
+
});
|
|
22290
|
+
var VehicleSampleInfoSchema = object({
|
|
22291
|
+
id: string(),
|
|
22292
|
+
/** The plate text this sample enrolled (self-labeling — no embedding). */
|
|
22293
|
+
text: string(),
|
|
22294
|
+
/** OCR confidence of the enrolled read (0..1). */
|
|
22295
|
+
score: number(),
|
|
22296
|
+
addedAt: number().int(),
|
|
22297
|
+
deviceId: number().int().optional(),
|
|
22298
|
+
base64: string().optional()
|
|
22299
|
+
});
|
|
21483
22300
|
var PlateInfoSchema = object({
|
|
21484
22301
|
plateId: string(),
|
|
21485
22302
|
deviceId: number().int(),
|
|
@@ -21491,6 +22308,16 @@ var PlateInfoSchema = object({
|
|
|
21491
22308
|
score: number(),
|
|
21492
22309
|
/** True when the text was manually corrected (exempt from retention). */
|
|
21493
22310
|
corrected: boolean(),
|
|
22311
|
+
/** Recognized vehicle id when a matcher lookup named this read (SQL NULL → absent). */
|
|
22312
|
+
recognizedVehicleId: string().optional(),
|
|
22313
|
+
/** Resolved vehicle name for `recognizedVehicleId` (UI convenience). */
|
|
22314
|
+
vehicleName: string().optional(),
|
|
22315
|
+
/** True once the read was assigned to a vehicle (enrolled as a sample). */
|
|
22316
|
+
assigned: boolean(),
|
|
22317
|
+
/** keyFrame parity: the plate bbox (pixel space) on the native key frame. */
|
|
22318
|
+
plateBbox: BoundingBoxSchema.optional(),
|
|
22319
|
+
/** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
|
|
22320
|
+
keyFrameMediaKey: string().optional(),
|
|
21494
22321
|
base64: string().optional()
|
|
21495
22322
|
});
|
|
21496
22323
|
var MediaFileLiteSchema = object({
|
|
@@ -21530,6 +22357,48 @@ method(object({
|
|
|
21530
22357
|
}), method(object({ plateId: string() }), _void(), {
|
|
21531
22358
|
kind: "mutation",
|
|
21532
22359
|
auth: "admin"
|
|
22360
|
+
}), method(_void(), array(VehicleSchema).readonly()), method(object({ name: string().min(1) }), VehicleSchema, {
|
|
22361
|
+
kind: "mutation",
|
|
22362
|
+
auth: "admin"
|
|
22363
|
+
}), method(object({
|
|
22364
|
+
id: string(),
|
|
22365
|
+
name: string().min(1)
|
|
22366
|
+
}), _void(), {
|
|
22367
|
+
kind: "mutation",
|
|
22368
|
+
auth: "admin"
|
|
22369
|
+
}), method(object({ id: string() }), _void(), {
|
|
22370
|
+
kind: "mutation",
|
|
22371
|
+
auth: "admin"
|
|
22372
|
+
}), method(object({ vehicleId: string() }), array(VehicleSampleInfoSchema).readonly()), method(object({
|
|
22373
|
+
vehicleId: string(),
|
|
22374
|
+
sampleId: string()
|
|
22375
|
+
}), _void(), {
|
|
22376
|
+
kind: "mutation",
|
|
22377
|
+
auth: "admin"
|
|
22378
|
+
}), method(object({
|
|
22379
|
+
plateId: string(),
|
|
22380
|
+
vehicleId: string()
|
|
22381
|
+
}), _void(), {
|
|
22382
|
+
kind: "mutation",
|
|
22383
|
+
auth: "admin"
|
|
22384
|
+
}), method(object({ plateId: string() }), _void(), {
|
|
22385
|
+
kind: "mutation",
|
|
22386
|
+
auth: "admin"
|
|
22387
|
+
}), method(object({
|
|
22388
|
+
plateIds: array(string()).min(1),
|
|
22389
|
+
vehicleId: string()
|
|
22390
|
+
}), object({
|
|
22391
|
+
assigned: number().int(),
|
|
22392
|
+
failed: array(string()).readonly()
|
|
22393
|
+
}), {
|
|
22394
|
+
kind: "mutation",
|
|
22395
|
+
auth: "admin"
|
|
22396
|
+
}), method(object({ plateIds: array(string()).min(1) }), object({
|
|
22397
|
+
unassigned: number().int(),
|
|
22398
|
+
failed: array(string()).readonly()
|
|
22399
|
+
}), {
|
|
22400
|
+
kind: "mutation",
|
|
22401
|
+
auth: "admin"
|
|
21533
22402
|
});
|
|
21534
22403
|
var ModelFormatSchema = _enum(MODEL_FORMATS);
|
|
21535
22404
|
var HwAccelBackendInputSchema = _enum([
|
|
@@ -21608,6 +22477,10 @@ var GpuInfoSchema = object({
|
|
|
21608
22477
|
memoryMB: number().optional()
|
|
21609
22478
|
});
|
|
21610
22479
|
var NpuInfoSchema = object({ type: _enum(["apple-ane", "intel-npu"]) });
|
|
22480
|
+
var CoralInfoSchema = object({
|
|
22481
|
+
type: literal("coral-edgetpu"),
|
|
22482
|
+
bus: string().optional()
|
|
22483
|
+
});
|
|
21611
22484
|
var HardwareInfoSchema = object({
|
|
21612
22485
|
platform: HardwarePlatformSchema,
|
|
21613
22486
|
arch: HardwareArchSchema,
|
|
@@ -21616,7 +22489,8 @@ var HardwareInfoSchema = object({
|
|
|
21616
22489
|
totalRAM_MB: number(),
|
|
21617
22490
|
availableRAM_MB: number(),
|
|
21618
22491
|
gpu: GpuInfoSchema.nullable(),
|
|
21619
|
-
npu: NpuInfoSchema.nullable()
|
|
22492
|
+
npu: NpuInfoSchema.nullable(),
|
|
22493
|
+
coral: CoralInfoSchema.nullable().optional()
|
|
21620
22494
|
});
|
|
21621
22495
|
var PlatformScoreSchema = object({
|
|
21622
22496
|
runtime: _enum(["node", "python"]),
|
|
@@ -24075,6 +24949,168 @@ Object.freeze({
|
|
|
24075
24949
|
addonId: null,
|
|
24076
24950
|
access: "create"
|
|
24077
24951
|
},
|
|
24952
|
+
"llm.deleteModel": {
|
|
24953
|
+
capName: "llm",
|
|
24954
|
+
capScope: "system",
|
|
24955
|
+
addonId: null,
|
|
24956
|
+
access: "delete"
|
|
24957
|
+
},
|
|
24958
|
+
"llm.deleteProfile": {
|
|
24959
|
+
capName: "llm",
|
|
24960
|
+
capScope: "system",
|
|
24961
|
+
addonId: null,
|
|
24962
|
+
access: "delete"
|
|
24963
|
+
},
|
|
24964
|
+
"llm.generate": {
|
|
24965
|
+
capName: "llm",
|
|
24966
|
+
capScope: "system",
|
|
24967
|
+
addonId: null,
|
|
24968
|
+
access: "create"
|
|
24969
|
+
},
|
|
24970
|
+
"llm.generateVision": {
|
|
24971
|
+
capName: "llm",
|
|
24972
|
+
capScope: "system",
|
|
24973
|
+
addonId: null,
|
|
24974
|
+
access: "create"
|
|
24975
|
+
},
|
|
24976
|
+
"llm.getDefaults": {
|
|
24977
|
+
capName: "llm",
|
|
24978
|
+
capScope: "system",
|
|
24979
|
+
addonId: null,
|
|
24980
|
+
access: "view"
|
|
24981
|
+
},
|
|
24982
|
+
"llm.getRuntimeStatus": {
|
|
24983
|
+
capName: "llm",
|
|
24984
|
+
capScope: "system",
|
|
24985
|
+
addonId: null,
|
|
24986
|
+
access: "view"
|
|
24987
|
+
},
|
|
24988
|
+
"llm.getUsage": {
|
|
24989
|
+
capName: "llm",
|
|
24990
|
+
capScope: "system",
|
|
24991
|
+
addonId: null,
|
|
24992
|
+
access: "view"
|
|
24993
|
+
},
|
|
24994
|
+
"llm.installModel": {
|
|
24995
|
+
capName: "llm",
|
|
24996
|
+
capScope: "system",
|
|
24997
|
+
addonId: null,
|
|
24998
|
+
access: "create"
|
|
24999
|
+
},
|
|
25000
|
+
"llm.listModelCatalog": {
|
|
25001
|
+
capName: "llm",
|
|
25002
|
+
capScope: "system",
|
|
25003
|
+
addonId: null,
|
|
25004
|
+
access: "view"
|
|
25005
|
+
},
|
|
25006
|
+
"llm.listModels": {
|
|
25007
|
+
capName: "llm",
|
|
25008
|
+
capScope: "system",
|
|
25009
|
+
addonId: null,
|
|
25010
|
+
access: "view"
|
|
25011
|
+
},
|
|
25012
|
+
"llm.listNodeModels": {
|
|
25013
|
+
capName: "llm",
|
|
25014
|
+
capScope: "system",
|
|
25015
|
+
addonId: null,
|
|
25016
|
+
access: "view"
|
|
25017
|
+
},
|
|
25018
|
+
"llm.listProfileKinds": {
|
|
25019
|
+
capName: "llm",
|
|
25020
|
+
capScope: "system",
|
|
25021
|
+
addonId: null,
|
|
25022
|
+
access: "view"
|
|
25023
|
+
},
|
|
25024
|
+
"llm.listProfiles": {
|
|
25025
|
+
capName: "llm",
|
|
25026
|
+
capScope: "system",
|
|
25027
|
+
addonId: null,
|
|
25028
|
+
access: "view"
|
|
25029
|
+
},
|
|
25030
|
+
"llm.listRuntimeNodes": {
|
|
25031
|
+
capName: "llm",
|
|
25032
|
+
capScope: "system",
|
|
25033
|
+
addonId: null,
|
|
25034
|
+
access: "view"
|
|
25035
|
+
},
|
|
25036
|
+
"llm.setDefault": {
|
|
25037
|
+
capName: "llm",
|
|
25038
|
+
capScope: "system",
|
|
25039
|
+
addonId: null,
|
|
25040
|
+
access: "create"
|
|
25041
|
+
},
|
|
25042
|
+
"llm.startRuntime": {
|
|
25043
|
+
capName: "llm",
|
|
25044
|
+
capScope: "system",
|
|
25045
|
+
addonId: null,
|
|
25046
|
+
access: "create"
|
|
25047
|
+
},
|
|
25048
|
+
"llm.stopRuntime": {
|
|
25049
|
+
capName: "llm",
|
|
25050
|
+
capScope: "system",
|
|
25051
|
+
addonId: null,
|
|
25052
|
+
access: "create"
|
|
25053
|
+
},
|
|
25054
|
+
"llm.testProfile": {
|
|
25055
|
+
capName: "llm",
|
|
25056
|
+
capScope: "system",
|
|
25057
|
+
addonId: null,
|
|
25058
|
+
access: "create"
|
|
25059
|
+
},
|
|
25060
|
+
"llm.upsertProfile": {
|
|
25061
|
+
capName: "llm",
|
|
25062
|
+
capScope: "system",
|
|
25063
|
+
addonId: null,
|
|
25064
|
+
access: "create"
|
|
25065
|
+
},
|
|
25066
|
+
"llmRuntime.complete": {
|
|
25067
|
+
capName: "llm-runtime",
|
|
25068
|
+
capScope: "system",
|
|
25069
|
+
addonId: null,
|
|
25070
|
+
access: "create"
|
|
25071
|
+
},
|
|
25072
|
+
"llmRuntime.deleteModel": {
|
|
25073
|
+
capName: "llm-runtime",
|
|
25074
|
+
capScope: "system",
|
|
25075
|
+
addonId: null,
|
|
25076
|
+
access: "delete"
|
|
25077
|
+
},
|
|
25078
|
+
"llmRuntime.ensureStarted": {
|
|
25079
|
+
capName: "llm-runtime",
|
|
25080
|
+
capScope: "system",
|
|
25081
|
+
addonId: null,
|
|
25082
|
+
access: "create"
|
|
25083
|
+
},
|
|
25084
|
+
"llmRuntime.getDiskUsage": {
|
|
25085
|
+
capName: "llm-runtime",
|
|
25086
|
+
capScope: "system",
|
|
25087
|
+
addonId: null,
|
|
25088
|
+
access: "view"
|
|
25089
|
+
},
|
|
25090
|
+
"llmRuntime.installModel": {
|
|
25091
|
+
capName: "llm-runtime",
|
|
25092
|
+
capScope: "system",
|
|
25093
|
+
addonId: null,
|
|
25094
|
+
access: "create"
|
|
25095
|
+
},
|
|
25096
|
+
"llmRuntime.listLocalModels": {
|
|
25097
|
+
capName: "llm-runtime",
|
|
25098
|
+
capScope: "system",
|
|
25099
|
+
addonId: null,
|
|
25100
|
+
access: "view"
|
|
25101
|
+
},
|
|
25102
|
+
"llmRuntime.status": {
|
|
25103
|
+
capName: "llm-runtime",
|
|
25104
|
+
capScope: "system",
|
|
25105
|
+
addonId: null,
|
|
25106
|
+
access: "view"
|
|
25107
|
+
},
|
|
25108
|
+
"llmRuntime.stop": {
|
|
25109
|
+
capName: "llm-runtime",
|
|
25110
|
+
capScope: "system",
|
|
25111
|
+
addonId: null,
|
|
25112
|
+
access: "create"
|
|
25113
|
+
},
|
|
24078
25114
|
"localNetwork.getAllowedAddresses": {
|
|
24079
25115
|
capName: "local-network",
|
|
24080
25116
|
capScope: "system",
|
|
@@ -24705,6 +25741,12 @@ Object.freeze({
|
|
|
24705
25741
|
addonId: null,
|
|
24706
25742
|
access: "delete"
|
|
24707
25743
|
},
|
|
25744
|
+
"pipelineAnalytics.deleteTracks": {
|
|
25745
|
+
capName: "pipeline-analytics",
|
|
25746
|
+
capScope: "device",
|
|
25747
|
+
addonId: null,
|
|
25748
|
+
access: "delete"
|
|
25749
|
+
},
|
|
24708
25750
|
"pipelineAnalytics.getActiveTracks": {
|
|
24709
25751
|
capName: "pipeline-analytics",
|
|
24710
25752
|
capScope: "device",
|
|
@@ -24771,12 +25813,24 @@ Object.freeze({
|
|
|
24771
25813
|
addonId: null,
|
|
24772
25814
|
access: "create"
|
|
24773
25815
|
},
|
|
25816
|
+
"pipelineAnalytics.pruneTracksBefore": {
|
|
25817
|
+
capName: "pipeline-analytics",
|
|
25818
|
+
capScope: "device",
|
|
25819
|
+
addonId: null,
|
|
25820
|
+
access: "create"
|
|
25821
|
+
},
|
|
24774
25822
|
"pipelineAnalytics.searchObjectEvents": {
|
|
24775
25823
|
capName: "pipeline-analytics",
|
|
24776
25824
|
capScope: "device",
|
|
24777
25825
|
addonId: null,
|
|
24778
25826
|
access: "view"
|
|
24779
25827
|
},
|
|
25828
|
+
"pipelineAnalytics.wipeAllAnalytics": {
|
|
25829
|
+
capName: "pipeline-analytics",
|
|
25830
|
+
capScope: "device",
|
|
25831
|
+
addonId: null,
|
|
25832
|
+
access: "delete"
|
|
25833
|
+
},
|
|
24780
25834
|
"pipelineExecutor.cacheFrameInPool": {
|
|
24781
25835
|
capName: "pipeline-executor",
|
|
24782
25836
|
capScope: "system",
|
|
@@ -25281,18 +26335,42 @@ Object.freeze({
|
|
|
25281
26335
|
addonId: null,
|
|
25282
26336
|
access: "create"
|
|
25283
26337
|
},
|
|
26338
|
+
"plateGallery.assignPlate": {
|
|
26339
|
+
capName: "plate-gallery",
|
|
26340
|
+
capScope: "system",
|
|
26341
|
+
addonId: null,
|
|
26342
|
+
access: "create"
|
|
26343
|
+
},
|
|
26344
|
+
"plateGallery.assignPlates": {
|
|
26345
|
+
capName: "plate-gallery",
|
|
26346
|
+
capScope: "system",
|
|
26347
|
+
addonId: null,
|
|
26348
|
+
access: "create"
|
|
26349
|
+
},
|
|
25284
26350
|
"plateGallery.correctPlateText": {
|
|
25285
26351
|
capName: "plate-gallery",
|
|
25286
26352
|
capScope: "system",
|
|
25287
26353
|
addonId: null,
|
|
25288
26354
|
access: "create"
|
|
25289
26355
|
},
|
|
26356
|
+
"plateGallery.createVehicle": {
|
|
26357
|
+
capName: "plate-gallery",
|
|
26358
|
+
capScope: "system",
|
|
26359
|
+
addonId: null,
|
|
26360
|
+
access: "create"
|
|
26361
|
+
},
|
|
25290
26362
|
"plateGallery.deletePlate": {
|
|
25291
26363
|
capName: "plate-gallery",
|
|
25292
26364
|
capScope: "system",
|
|
25293
26365
|
addonId: null,
|
|
25294
26366
|
access: "delete"
|
|
25295
26367
|
},
|
|
26368
|
+
"plateGallery.deleteVehicle": {
|
|
26369
|
+
capName: "plate-gallery",
|
|
26370
|
+
capScope: "system",
|
|
26371
|
+
addonId: null,
|
|
26372
|
+
access: "delete"
|
|
26373
|
+
},
|
|
25296
26374
|
"plateGallery.getPlateByTrack": {
|
|
25297
26375
|
capName: "plate-gallery",
|
|
25298
26376
|
capScope: "system",
|
|
@@ -25311,6 +26389,30 @@ Object.freeze({
|
|
|
25311
26389
|
addonId: null,
|
|
25312
26390
|
access: "view"
|
|
25313
26391
|
},
|
|
26392
|
+
"plateGallery.listVehicles": {
|
|
26393
|
+
capName: "plate-gallery",
|
|
26394
|
+
capScope: "system",
|
|
26395
|
+
addonId: null,
|
|
26396
|
+
access: "view"
|
|
26397
|
+
},
|
|
26398
|
+
"plateGallery.listVehicleSamples": {
|
|
26399
|
+
capName: "plate-gallery",
|
|
26400
|
+
capScope: "system",
|
|
26401
|
+
addonId: null,
|
|
26402
|
+
access: "view"
|
|
26403
|
+
},
|
|
26404
|
+
"plateGallery.removeVehicleSample": {
|
|
26405
|
+
capName: "plate-gallery",
|
|
26406
|
+
capScope: "system",
|
|
26407
|
+
addonId: null,
|
|
26408
|
+
access: "delete"
|
|
26409
|
+
},
|
|
26410
|
+
"plateGallery.renameVehicle": {
|
|
26411
|
+
capName: "plate-gallery",
|
|
26412
|
+
capScope: "system",
|
|
26413
|
+
addonId: null,
|
|
26414
|
+
access: "create"
|
|
26415
|
+
},
|
|
25314
26416
|
"plateGallery.searchPlates": {
|
|
25315
26417
|
capName: "plate-gallery",
|
|
25316
26418
|
capScope: "system",
|
|
@@ -25323,6 +26425,18 @@ Object.freeze({
|
|
|
25323
26425
|
addonId: null,
|
|
25324
26426
|
access: "view"
|
|
25325
26427
|
},
|
|
26428
|
+
"plateGallery.unassignPlate": {
|
|
26429
|
+
capName: "plate-gallery",
|
|
26430
|
+
capScope: "system",
|
|
26431
|
+
addonId: null,
|
|
26432
|
+
access: "create"
|
|
26433
|
+
},
|
|
26434
|
+
"plateGallery.unassignPlates": {
|
|
26435
|
+
capName: "plate-gallery",
|
|
26436
|
+
capScope: "system",
|
|
26437
|
+
addonId: null,
|
|
26438
|
+
access: "create"
|
|
26439
|
+
},
|
|
25326
26440
|
"platformProbe.getCapabilities": {
|
|
25327
26441
|
capName: "platform-probe",
|
|
25328
26442
|
capScope: "system",
|
|
@@ -25515,6 +26629,48 @@ Object.freeze({
|
|
|
25515
26629
|
addonId: null,
|
|
25516
26630
|
access: "create"
|
|
25517
26631
|
},
|
|
26632
|
+
"sceneMonitor.captureReference": {
|
|
26633
|
+
capName: "scene-monitor",
|
|
26634
|
+
capScope: "device",
|
|
26635
|
+
addonId: null,
|
|
26636
|
+
access: "create"
|
|
26637
|
+
},
|
|
26638
|
+
"sceneMonitor.createScene": {
|
|
26639
|
+
capName: "scene-monitor",
|
|
26640
|
+
capScope: "device",
|
|
26641
|
+
addonId: null,
|
|
26642
|
+
access: "create"
|
|
26643
|
+
},
|
|
26644
|
+
"sceneMonitor.deleteReference": {
|
|
26645
|
+
capName: "scene-monitor",
|
|
26646
|
+
capScope: "device",
|
|
26647
|
+
addonId: null,
|
|
26648
|
+
access: "delete"
|
|
26649
|
+
},
|
|
26650
|
+
"sceneMonitor.deleteScene": {
|
|
26651
|
+
capName: "scene-monitor",
|
|
26652
|
+
capScope: "device",
|
|
26653
|
+
addonId: null,
|
|
26654
|
+
access: "delete"
|
|
26655
|
+
},
|
|
26656
|
+
"sceneMonitor.listScenes": {
|
|
26657
|
+
capName: "scene-monitor",
|
|
26658
|
+
capScope: "device",
|
|
26659
|
+
addonId: null,
|
|
26660
|
+
access: "view"
|
|
26661
|
+
},
|
|
26662
|
+
"sceneMonitor.recheckNow": {
|
|
26663
|
+
capName: "scene-monitor",
|
|
26664
|
+
capScope: "device",
|
|
26665
|
+
addonId: null,
|
|
26666
|
+
access: "create"
|
|
26667
|
+
},
|
|
26668
|
+
"sceneMonitor.updateScene": {
|
|
26669
|
+
capName: "scene-monitor",
|
|
26670
|
+
capScope: "device",
|
|
26671
|
+
addonId: null,
|
|
26672
|
+
access: "create"
|
|
26673
|
+
},
|
|
25518
26674
|
"scriptRunner.run": {
|
|
25519
26675
|
capName: "script-runner",
|
|
25520
26676
|
capScope: "device",
|
|
@@ -26599,6 +27755,7 @@ Object.freeze({
|
|
|
26599
27755
|
Object.freeze({
|
|
26600
27756
|
"broker": "broker",
|
|
26601
27757
|
"device-export": "device-export",
|
|
27758
|
+
"llm": "ai",
|
|
26602
27759
|
"mesh-network": "mesh",
|
|
26603
27760
|
"mqtt-broker": "broker",
|
|
26604
27761
|
"network-access": "ingress",
|
|
@@ -32927,6 +34084,90 @@ function deriveIntegrationDomain(platforms) {
|
|
|
32927
34084
|
return best ?? present[0] ?? null;
|
|
32928
34085
|
}
|
|
32929
34086
|
//#endregion
|
|
34087
|
+
//#region src/ha-notification-icon.ts
|
|
34088
|
+
/**
|
|
34089
|
+
* Bundled brand icon for the `homeassistant` notification-output kind, served
|
|
34090
|
+
* by THIS addon over its own `addon-routes` HTTP surface. Mirrors the pattern
|
|
34091
|
+
* `addon-notifiers` uses for the other notifier kinds (each provider serves the
|
|
34092
|
+
* icon for the kinds it contributes), so `notificationOutput.listTargetKinds`
|
|
34093
|
+
* can stamp a self-hosted `iconUrl` onto the `homeassistant` descriptor and the
|
|
34094
|
+
* admin UI renders `<img src=iconUrl>` instead of a text label.
|
|
34095
|
+
*
|
|
34096
|
+
* GET /addon/provider-homeassistant/icons/homeassistant → image/svg+xml
|
|
34097
|
+
*
|
|
34098
|
+
* The bytes ship INSIDE the addon (no external CDN / hotlink) so the icon is
|
|
34099
|
+
* self-contained and CSP-safe. The SVG is a standalone document (declares the
|
|
34100
|
+
* default `xmlns`, a `viewBox`, and an intrinsic `fill`) with NO editor-tool
|
|
34101
|
+
* namespaces, so a browser `<img src>` renders it in its strict SVG mode.
|
|
34102
|
+
*
|
|
34103
|
+
* We register ONE CONCRETE static route (`/icons/homeassistant`), never a
|
|
34104
|
+
* `/:kind` param route: the forked-addon route bridge re-matches the pattern
|
|
34105
|
+
* against itself and would clobber a `:kind` path param with the literal token
|
|
34106
|
+
* `':kind'`. A static path carries no param, so it routes correctly across the
|
|
34107
|
+
* process boundary.
|
|
34108
|
+
*
|
|
34109
|
+
* The route negotiates `Accept-Encoding` and stamps `content-encoding` itself
|
|
34110
|
+
* (serving a pre-computed br/gzip/deflate variant, or identity). This makes the
|
|
34111
|
+
* hub's global `@fastify/compress` skip the response — on the forked-addon route
|
|
34112
|
+
* bridge that compressor emits an EMPTY brotli stream for any compressible body
|
|
34113
|
+
* over its 1 KiB threshold, which shows as a broken `<img>`. Owning the coding
|
|
34114
|
+
* keeps this icon robust even if its bytes ever grow past the threshold, and
|
|
34115
|
+
* matches how `addon-notifiers` serves its notifier-kind icons.
|
|
34116
|
+
*/
|
|
34117
|
+
/** The single notifier kind this addon contributes an icon for. */
|
|
34118
|
+
var HA_ICON_KIND = "homeassistant";
|
|
34119
|
+
/** The addon id — also the `/addon/<id>/…` route prefix. Mirrors the manifest id. */
|
|
34120
|
+
var HA_ROUTE_ID = "provider-homeassistant";
|
|
34121
|
+
/** One day; the icon is immutable per addon version. */
|
|
34122
|
+
var CACHE_CONTROL = "public, max-age=86400, immutable";
|
|
34123
|
+
/**
|
|
34124
|
+
* Home Assistant's official brand mark (simple-icons `homeassistant`, CC0) —
|
|
34125
|
+
* the blue "house + circuit" glyph — tinted with the official HA brand hex
|
|
34126
|
+
* (#18BCF2) so it reads on the dark admin UI. A standalone SVG document, no
|
|
34127
|
+
* editor-tool namespaces.
|
|
34128
|
+
*/
|
|
34129
|
+
var HOME_ASSISTANT_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"#18BCF2\"><path d=\"M22.939 10.627 13.061.749a1.505 1.505 0 0 0-2.121 0l-9.879 9.878C.478 11.21 0 12.363 0 13.187v9c0 .826.675 1.5 1.5 1.5h9.227l-4.063-4.062a2.034 2.034 0 0 1-.664.113c-1.13 0-2.05-.92-2.05-2.05s.92-2.05 2.05-2.05 2.05.92 2.05 2.05c0 .233-.041.456-.113.665l3.163 3.163V9.928a2.05 2.05 0 0 1-1.15-1.84c0-1.13.92-2.05 2.05-2.05s2.05.92 2.05 2.05a2.05 2.05 0 0 1-1.15 1.84v8.127l3.146-3.146A2.051 2.051 0 0 1 18 12.239c1.13 0 2.05.92 2.05 2.05s-.92 2.05-2.05 2.05c-.25 0-.488-.047-.709-.13L12.9 20.602v3.088h9.6c.825 0 1.5-.675 1.5-1.5v-9c0-.825-.477-1.977-1.061-2.561z\"/></svg>";
|
|
34130
|
+
/**
|
|
34131
|
+
* The stable icon URL for the `homeassistant` kind. Stamped onto the descriptor
|
|
34132
|
+
* by `listTargetKinds`. Root-relative so it resolves against whatever origin
|
|
34133
|
+
* the admin UI is served from.
|
|
34134
|
+
*/
|
|
34135
|
+
var HA_NOTIFICATION_ICON_URL = `/addon/${HA_ROUTE_ID}/icons/${HA_ICON_KIND}`;
|
|
34136
|
+
/** The icon's identity bytes plus every content coding we may serve, computed
|
|
34137
|
+
* once at module load (the icon is immutable). */
|
|
34138
|
+
var HA_ICON_IDENTITY = Buffer.from(HOME_ASSISTANT_SVG, "utf8");
|
|
34139
|
+
var HA_ICON_ENCODED = {
|
|
34140
|
+
br: (0, node_zlib.brotliCompressSync)(HA_ICON_IDENTITY),
|
|
34141
|
+
gzip: (0, node_zlib.gzipSync)(HA_ICON_IDENTITY),
|
|
34142
|
+
deflate: (0, node_zlib.deflateSync)(HA_ICON_IDENTITY)
|
|
34143
|
+
};
|
|
34144
|
+
/** Pick the best coding the client accepts (br › gzip › deflate), or `null` for
|
|
34145
|
+
* identity when the header names none of them. */
|
|
34146
|
+
function negotiateEncoding(acceptEncoding) {
|
|
34147
|
+
const tokens = acceptEncoding.toLowerCase().split(",").map((part) => part.trim().split(";")[0]?.trim());
|
|
34148
|
+
for (const coding of [
|
|
34149
|
+
"br",
|
|
34150
|
+
"gzip",
|
|
34151
|
+
"deflate"
|
|
34152
|
+
]) if (tokens.includes(coding)) return coding;
|
|
34153
|
+
return null;
|
|
34154
|
+
}
|
|
34155
|
+
/** Build the `addon-routes` provider that serves the bundled Home Assistant icon. */
|
|
34156
|
+
function createHaIconRouteProvider() {
|
|
34157
|
+
return buildAddonRouteProvider(HA_ROUTE_ID, [{
|
|
34158
|
+
method: "GET",
|
|
34159
|
+
path: `/icons/${HA_ICON_KIND}`,
|
|
34160
|
+
access: "public",
|
|
34161
|
+
description: "Official brand icon (SVG) for the 'homeassistant' notifier kind.",
|
|
34162
|
+
handler: async (request, reply) => {
|
|
34163
|
+
const coding = negotiateEncoding(String(request.headers["accept-encoding"] ?? ""));
|
|
34164
|
+
reply.code(200).type("image/svg+xml").header("cache-control", CACHE_CONTROL).header("vary", "accept-encoding");
|
|
34165
|
+
if (coding !== null) reply.header("content-encoding", coding);
|
|
34166
|
+
reply.send(coding !== null ? HA_ICON_ENCODED[coding] : HA_ICON_IDENTITY);
|
|
34167
|
+
}
|
|
34168
|
+
}]);
|
|
34169
|
+
}
|
|
34170
|
+
//#endregion
|
|
32930
34171
|
//#region src/ha-notification-output.ts
|
|
32931
34172
|
/**
|
|
32932
34173
|
* `homeassistant` notification-output kind — hosted BY the HA provider addon.
|
|
@@ -33116,6 +34357,13 @@ function parseNotifyServices(result, brokerId) {
|
|
|
33116
34357
|
}
|
|
33117
34358
|
}));
|
|
33118
34359
|
}
|
|
34360
|
+
/** KV JSON-blob shape — a single `data` column routes the row through the
|
|
34361
|
+
* settings backend's canonical key/value path (id TEXT PK, data TEXT). */
|
|
34362
|
+
var KV_BLOB_COLUMNS = [{
|
|
34363
|
+
name: "data",
|
|
34364
|
+
type: "TEXT",
|
|
34365
|
+
notNull: true
|
|
34366
|
+
}];
|
|
33119
34367
|
function rowToTarget(row) {
|
|
33120
34368
|
const parsed = TargetSchema.safeParse({
|
|
33121
34369
|
id: row.id,
|
|
@@ -33140,6 +34388,12 @@ var HaTargetStore = class {
|
|
|
33140
34388
|
this.store = store;
|
|
33141
34389
|
this.collection = collection;
|
|
33142
34390
|
}
|
|
34391
|
+
/** Declare the backing collection before any read/write. The SQLite settings
|
|
34392
|
+
* backend rejects undeclared collections (fail-fast), so this MUST run before
|
|
34393
|
+
* `list`/`getById`/`upsert`/`delete` — mirrors addon-ai's ProfileStore.init. */
|
|
34394
|
+
async init() {
|
|
34395
|
+
await this.store.declareCollection(this.collection, KV_BLOB_COLUMNS);
|
|
34396
|
+
}
|
|
33143
34397
|
async list() {
|
|
33144
34398
|
const rows = await this.store.query(this.collection);
|
|
33145
34399
|
const out = [];
|
|
@@ -33206,6 +34460,12 @@ function createApiHaSettingsStorePort(api) {
|
|
|
33206
34460
|
collection,
|
|
33207
34461
|
key: id
|
|
33208
34462
|
});
|
|
34463
|
+
},
|
|
34464
|
+
declareCollection: async (collection, columns) => {
|
|
34465
|
+
await api.settingsStore.declareCollection.mutate({
|
|
34466
|
+
collection,
|
|
34467
|
+
columns: columns.map((c) => ({ ...c }))
|
|
34468
|
+
});
|
|
33209
34469
|
}
|
|
33210
34470
|
};
|
|
33211
34471
|
}
|
|
@@ -33236,6 +34496,9 @@ function createMemoryHaSettingsStorePort() {
|
|
|
33236
34496
|
},
|
|
33237
34497
|
remove: async (collection, id) => {
|
|
33238
34498
|
bucket(collection).delete(id);
|
|
34499
|
+
},
|
|
34500
|
+
declareCollection: async (collection) => {
|
|
34501
|
+
bucket(collection);
|
|
33239
34502
|
}
|
|
33240
34503
|
};
|
|
33241
34504
|
}
|
|
@@ -33305,7 +34568,12 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
33305
34568
|
}
|
|
33306
34569
|
}
|
|
33307
34570
|
return {
|
|
33308
|
-
listTargetKinds: async () =>
|
|
34571
|
+
listTargetKinds: async () => {
|
|
34572
|
+
return [deps.iconUrl !== void 0 ? {
|
|
34573
|
+
...descriptor,
|
|
34574
|
+
iconUrl: deps.iconUrl
|
|
34575
|
+
} : descriptor];
|
|
34576
|
+
},
|
|
33309
34577
|
listTargets: async () => {
|
|
33310
34578
|
return (await store.list()).map((target) => ({
|
|
33311
34579
|
...target,
|
|
@@ -33871,17 +35139,23 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
|
|
|
33871
35139
|
},
|
|
33872
35140
|
{
|
|
33873
35141
|
capability: notificationOutputCapability,
|
|
33874
|
-
provider: this.buildNotificationOutputProvider()
|
|
35142
|
+
provider: await this.buildNotificationOutputProvider()
|
|
35143
|
+
},
|
|
35144
|
+
{
|
|
35145
|
+
capability: addonRoutesCapability,
|
|
35146
|
+
provider: createHaIconRouteProvider()
|
|
33875
35147
|
}
|
|
33876
35148
|
];
|
|
33877
35149
|
}
|
|
33878
|
-
buildNotificationOutputProvider() {
|
|
35150
|
+
async buildNotificationOutputProvider() {
|
|
33879
35151
|
const api = this.ctx.api;
|
|
33880
35152
|
const port = api ? createApiHaSettingsStorePort(api) : createMemoryHaSettingsStorePort();
|
|
33881
35153
|
if (!api) this.ctx.logger.warn("ha notification-output: no ctx.api — targets persist in-memory only");
|
|
33882
35154
|
const store = new HaTargetStore(port);
|
|
35155
|
+
await store.init();
|
|
33883
35156
|
return createHaNotificationOutputProvider({
|
|
33884
35157
|
addonId: this.ctx.id,
|
|
35158
|
+
iconUrl: HA_NOTIFICATION_ICON_URL,
|
|
33885
35159
|
store,
|
|
33886
35160
|
publish: async (brokerId, service, serviceData) => {
|
|
33887
35161
|
await this.requireRegistry().publish(brokerId, {
|