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