@camstack/addon-post-analysis 1.2.5 → 1.2.7

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.
@@ -6837,7 +6837,6 @@ object({ deviceId: number() }), object({ deviceId: number() }), object({
6837
6837
  patch: record(string(), unknown())
6838
6838
  }), object({ success: literal(true) });
6839
6839
  object({ deviceId: number() }), unknown().nullable();
6840
- /** Shorthand to define a method schema */
6841
6840
  function method(input, output, options) {
6842
6841
  return {
6843
6842
  input,
@@ -6845,6 +6844,7 @@ function method(input, output, options) {
6845
6844
  kind: options?.kind ?? "query",
6846
6845
  auth: options?.auth ?? "protected",
6847
6846
  ...options?.access !== void 0 ? { access: options.access } : {},
6847
+ ...options?.caller !== void 0 ? { caller: options.caller } : {},
6848
6848
  timeoutMs: options?.timeoutMs
6849
6849
  };
6850
6850
  }
@@ -11039,6 +11039,22 @@ var CameraMetricsSchema = object({
11039
11039
  ])
11040
11040
  });
11041
11041
  var CameraMetricsWithDeviceIdSchema = CameraMetricsSchema.extend({ deviceId: number() });
11042
+ /**
11043
+ * Reference to the frame's retained NATIVE surface + the parent crop's placement
11044
+ * within the frame, so the executor can re-cut a leaf child ROI at native
11045
+ * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
11046
+ */
11047
+ var NativeCropRefSchema = object({
11048
+ /** Handle keying the retained native surface (node-pinned to its owner). */
11049
+ handle: FrameHandleSchema,
11050
+ /** The parent crop's padded/clamped rectangle in FRAME-space pixels. */
11051
+ cropFrameSpace: object({
11052
+ x: number(),
11053
+ y: number(),
11054
+ w: number(),
11055
+ h: number()
11056
+ })
11057
+ });
11042
11058
  var ModelFormatSchema$1 = _enum([
11043
11059
  "onnx",
11044
11060
  "coreml",
@@ -11314,7 +11330,22 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11314
11330
  * Omitted ⇒ the runner's default device (current single-engine
11315
11331
  * behaviour). Selects WHICH device pool of the node runs the call.
11316
11332
  */
11317
- deviceKey: string().optional()
11333
+ deviceKey: string().optional(),
11334
+ /**
11335
+ * Two-plane NATIVE child-crop reference. Set by `runDetailSubtree` ONLY
11336
+ * when the parent crop was resolved from the frame's retained NATIVE
11337
+ * surface (a frameHandle HIT). Lets the executor re-cut a LEAF crop
11338
+ * child's ROI (plate-ocr, face-embedding, leaf classifiers) at native
11339
+ * resolution from that surface — the SAME quality path faces already
11340
+ * had — instead of the downscaled parent tile. `handle` keys the native
11341
+ * surface (node-pinned to its owner); `cropFrameSpace` is the parent
11342
+ * crop's padded/clamped rectangle in FRAME-space pixels, used to compose
11343
+ * the executor's crop-normalized child ROI back into frame-normalized
11344
+ * coordinates. Auxiliary to the image source (`image`/`frame`/…), NOT one
11345
+ * of the mutually-exclusive image inputs. Absent ⇒ tile-crop children
11346
+ * (today's behaviour on the fallback path).
11347
+ */
11348
+ nativeCropRef: NativeCropRefSchema.optional()
11318
11349
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11319
11350
  engine: PipelineEngineChoiceSchema.optional(),
11320
11351
  steps: array(PipelineStepInputSchema).min(1),
@@ -11530,7 +11561,11 @@ var DetailResultSchema = object({
11530
11561
  bbox: NativeCropBboxSchema.optional(),
11531
11562
  embedding: string().optional(),
11532
11563
  label: string().optional(),
11533
- alignedCropJpeg: string().optional()
11564
+ alignedCropJpeg: string().optional(),
11565
+ /** Face short side (px) measured on the NATIVE crop surface. The `bbox`
11566
+ * above is detection-frame px (≈6× smaller on a 4K camera) — min-face-size
11567
+ * consumers MUST prefer this when present (2026-07-22 native-gate fix). */
11568
+ nativeFaceShortSidePx: number().optional()
11534
11569
  });
11535
11570
  /**
11536
11571
  * Per-camera tunable ranges + defaults. Single source of truth used
@@ -15972,6 +16007,348 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
15972
16007
  enabled: boolean()
15973
16008
  }), _void(), { kind: "mutation" });
15974
16009
  /**
16010
+ * notification-rules — the Notification Center rule surface (P1 core).
16011
+ *
16012
+ * Spec: `docs/superpowers/specs/2026-07-22-notification-center-requirements.md`
16013
+ * (operator decisions D-1/D-2/D-3 are binding):
16014
+ *
16015
+ * - D-2: rule EVALUATION lives in `addon-post-analysis` (the
16016
+ * `notification-center` module), hooked on the durable persistence
16017
+ * moments (object-event insert, TrackCloser.closeExpired) with a
16018
+ * persisted outbox + retry — never the lossy telemetry bus (D8).
16019
+ * - D-3: urgency belongs to the RULE. `delivery: 'immediate'` fires on the
16020
+ * FIRST persisted detection matching the conditions (per-track dedup,
16021
+ * `maxPerTrack` fixed at 1 — see {@link NC_MAX_PER_TRACK_IMMEDIATE});
16022
+ * `delivery: 'track-end'` evaluates the finalized track record at close.
16023
+ * - DISPATCH stays behind `notification-output` (rules reference targets
16024
+ * by id; per-backend params are a passthrough blob capped by the
16025
+ * target kind's own caps/degrade engine).
16026
+ *
16027
+ * P1 scope: admin-authored rules only (`createdBy` stamped from the
16028
+ * server-injected caller identity — the first `caller: 'required'`
16029
+ * adopter). The P1 condition subset is: devices, classes(+exclude),
16030
+ * minConfidence, admin zones (any/all + exclude), weekly schedule
16031
+ * windows, and the optional label/identity/plate matchers. User rules,
16032
+ * private zones, per-recipient fan-out and the wider condition table are
16033
+ * P2+ (see spec §7).
16034
+ *
16035
+ * All schemas here are the single source of truth — `NcRule` etc. are
16036
+ * `z.infer` exports; no duplicate interfaces (the advanced-notifier
16037
+ * schema/interface drift is explicitly not repeated).
16038
+ */
16039
+ /** D-3: the urgency of a rule — which persistence moment evaluates it. */
16040
+ var NcDeliverySchema = _enum(["immediate", "track-end"]);
16041
+ /** Weekly schedule — OR of windows; absence on the rule = always active. */
16042
+ var NcScheduleSchema = object({
16043
+ windows: array(object({
16044
+ /** Days of week the window STARTS on (0 = Sunday … 6 = Saturday). */
16045
+ days: array(number().int().min(0).max(6)).min(1),
16046
+ startMinute: number().int().min(0).max(1439),
16047
+ endMinute: number().int().min(0).max(1439)
16048
+ })).min(1),
16049
+ /** IANA timezone; default = hub host timezone. */
16050
+ timezone: string().optional(),
16051
+ /** Active OUTSIDE the windows (e.g. "only outside business hours"). */
16052
+ invert: boolean().optional()
16053
+ });
16054
+ /** Fuzzy plate matcher — OCR noise makes exact match useless (spec row 12/13). */
16055
+ var NcPlateMatcherSchema = object({
16056
+ values: array(string().min(1)).min(1),
16057
+ /** Max Levenshtein distance after normalization (uppercase alphanumeric). */
16058
+ maxDistance: number().int().min(0).max(3).default(1)
16059
+ });
16060
+ /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
16061
+ var NcZoneConditionSchema = object({
16062
+ ids: array(string().min(1)).min(1),
16063
+ /** Quantifier over `ids` — at least one / every one visited. */
16064
+ match: _enum(["any", "all"]).default("any")
16065
+ });
16066
+ /**
16067
+ * The P1 condition set — a flat AND of groups; absent group = pass;
16068
+ * membership lists are OR within the list (spec §2.3).
16069
+ */
16070
+ var NcConditionsSchema = object({
16071
+ /** Device scope — absent = all devices. */
16072
+ devices: array(number()).optional(),
16073
+ /** Detector class names (any overlap with the record's class set). */
16074
+ classes: array(string().min(1)).optional(),
16075
+ /** Veto classes — any overlap fails the rule. */
16076
+ classesExclude: array(string().min(1)).optional(),
16077
+ /** Minimum detection confidence 0–1 (fails when the record has none). */
16078
+ minConfidence: number().min(0).max(1).optional(),
16079
+ /** Admin zone membership over event `zones` / track `zonesVisited`. */
16080
+ zones: NcZoneConditionSchema.optional(),
16081
+ /** Veto zones — any hit fails the rule. */
16082
+ zonesExclude: array(string().min(1)).optional(),
16083
+ /**
16084
+ * Exact (case-insensitive) match on the record's collapsed `label`
16085
+ * (identity name / plate text / subclass).
16086
+ */
16087
+ labelEquals: array(string().min(1)).optional(),
16088
+ /**
16089
+ * Identity matcher. P1 boundary: matched against the record's collapsed
16090
+ * `label` (the identity display name propagated by the face pipeline) —
16091
+ * identity-ID matching rides in P2 when identity ids reach the record.
16092
+ */
16093
+ identities: array(string().min(1)).optional(),
16094
+ /** Fuzzy plate matcher against the record's `label` (plate text). */
16095
+ plates: NcPlateMatcherSchema.optional()
16096
+ });
16097
+ /** One delivery target: a `notification-output` Target ref + passthrough params. */
16098
+ var NcRuleTargetSchema = object({
16099
+ /** `notification-output` Target id. */
16100
+ targetId: string().min(1),
16101
+ /**
16102
+ * Per-backend passthrough. Recognized keys are mapped onto the canonical
16103
+ * Notification (`priority`, `level`, `sound`, `clickUrl`, `ttl`); the
16104
+ * degrade engine drops what the backend can't render.
16105
+ */
16106
+ params: record(string(), unknown()).optional()
16107
+ });
16108
+ /**
16109
+ * Media attachment policy (P1 still-image subset). `best` = the best
16110
+ * AVAILABLE media at dispatch time (D-3); `best-matching` (track-end
16111
+ * condition-best) is deferred — operator open point.
16112
+ */
16113
+ var NcMediaPolicySchema = object({ attach: _enum([
16114
+ "best",
16115
+ "keyFrame",
16116
+ "none"
16117
+ ]).default("best") });
16118
+ /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
16119
+ var NcThrottleSchema = object({
16120
+ cooldownSec: number().int().min(0).max(86400).default(60),
16121
+ /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
16122
+ scope: _enum(["rule", "rule-device"]).default("rule-device")
16123
+ });
16124
+ /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
16125
+ var NcRuleInputSchema = object({
16126
+ name: string().min(1).max(200),
16127
+ enabled: boolean().default(true),
16128
+ delivery: NcDeliverySchema,
16129
+ conditions: NcConditionsSchema.default({}),
16130
+ schedule: NcScheduleSchema.optional(),
16131
+ targets: array(NcRuleTargetSchema).min(1),
16132
+ media: NcMediaPolicySchema.default({ attach: "best" }),
16133
+ throttle: NcThrottleSchema.default({
16134
+ cooldownSec: 60,
16135
+ scope: "rule-device"
16136
+ }),
16137
+ /** `{{var}}` templating over camera/class/label/zones/confidence/time. */
16138
+ template: object({
16139
+ title: string().max(500).optional(),
16140
+ body: string().max(2e3).optional()
16141
+ }).optional(),
16142
+ /** Canonical notification priority ordinal (1..5); per-target overridable. */
16143
+ priority: number().int().min(1).max(5).default(3)
16144
+ });
16145
+ /** Partial patch for `updateRule` — any subset of the input fields. */
16146
+ var NcRulePatchSchema = NcRuleInputSchema.partial();
16147
+ /** A persisted rule. */
16148
+ var NcRuleSchema = NcRuleInputSchema.extend({
16149
+ id: string(),
16150
+ /** userId of the admin who created the rule (server-stamped caller). */
16151
+ createdBy: string(),
16152
+ createdAt: number(),
16153
+ updatedAt: number()
16154
+ });
16155
+ var NcTestResultSchema = object({
16156
+ recordId: string(),
16157
+ recordKind: _enum(["object-event", "track"]),
16158
+ deviceId: number(),
16159
+ timestamp: number(),
16160
+ wouldFire: boolean(),
16161
+ /** Condition id that failed (first failing group), when `wouldFire` is false. */
16162
+ failedCondition: string().optional(),
16163
+ className: string().optional(),
16164
+ label: string().optional()
16165
+ });
16166
+ var NcConditionDescriptorSchema = object({
16167
+ /** Field id inside `NcConditions` (or `'schedule'` for the rule-level group). */
16168
+ id: string(),
16169
+ group: _enum([
16170
+ "scope",
16171
+ "class",
16172
+ "zones",
16173
+ "quality",
16174
+ "label",
16175
+ "schedule"
16176
+ ]),
16177
+ label: string(),
16178
+ /** Editor widget the UI renders — never hardcode per-condition forms. */
16179
+ valueType: _enum([
16180
+ "deviceIdList",
16181
+ "stringList",
16182
+ "number01",
16183
+ "zoneSelection",
16184
+ "zoneIdList",
16185
+ "schedule",
16186
+ "plateMatcher"
16187
+ ]),
16188
+ operator: _enum([
16189
+ "in",
16190
+ "notIn",
16191
+ "anyOf",
16192
+ "allOf",
16193
+ "gte",
16194
+ "fuzzyIn",
16195
+ "withinSchedule"
16196
+ ]),
16197
+ /** Which delivery kinds the condition applies to. */
16198
+ appliesTo: array(NcDeliverySchema),
16199
+ phase: string(),
16200
+ description: string().optional()
16201
+ });
16202
+ /**
16203
+ * The P1 condition surface as data — served by `getConditionCatalog` so
16204
+ * rule editors render from the catalog, not hardcoded forms (spec §4.2).
16205
+ */
16206
+ var NC_CONDITION_CATALOG = [
16207
+ {
16208
+ id: "devices",
16209
+ group: "scope",
16210
+ label: "Cameras",
16211
+ valueType: "deviceIdList",
16212
+ operator: "in",
16213
+ appliesTo: ["immediate", "track-end"],
16214
+ phase: "P1",
16215
+ description: "Restrict the rule to these devices; absent = all devices."
16216
+ },
16217
+ {
16218
+ id: "classes",
16219
+ group: "class",
16220
+ label: "Object classes",
16221
+ valueType: "stringList",
16222
+ operator: "in",
16223
+ appliesTo: ["immediate", "track-end"],
16224
+ phase: "P1",
16225
+ description: "Any overlap with the detection class set passes."
16226
+ },
16227
+ {
16228
+ id: "classesExclude",
16229
+ group: "class",
16230
+ label: "Excluded classes",
16231
+ valueType: "stringList",
16232
+ operator: "notIn",
16233
+ appliesTo: ["immediate", "track-end"],
16234
+ phase: "P1"
16235
+ },
16236
+ {
16237
+ id: "minConfidence",
16238
+ group: "quality",
16239
+ label: "Minimum confidence",
16240
+ valueType: "number01",
16241
+ operator: "gte",
16242
+ appliesTo: ["immediate", "track-end"],
16243
+ phase: "P1"
16244
+ },
16245
+ {
16246
+ id: "zones",
16247
+ group: "zones",
16248
+ label: "Zones",
16249
+ valueType: "zoneSelection",
16250
+ operator: "anyOf",
16251
+ appliesTo: ["immediate", "track-end"],
16252
+ phase: "P1",
16253
+ description: "Admin zone ids; quantifier any/all over the visited set."
16254
+ },
16255
+ {
16256
+ id: "zonesExclude",
16257
+ group: "zones",
16258
+ label: "Excluded zones",
16259
+ valueType: "zoneIdList",
16260
+ operator: "notIn",
16261
+ appliesTo: ["immediate", "track-end"],
16262
+ phase: "P1"
16263
+ },
16264
+ {
16265
+ id: "labelEquals",
16266
+ group: "label",
16267
+ label: "Label equals",
16268
+ valueType: "stringList",
16269
+ operator: "in",
16270
+ appliesTo: ["immediate", "track-end"],
16271
+ phase: "P1",
16272
+ description: "Exact match on the collapsed label (identity / plate / subclass)."
16273
+ },
16274
+ {
16275
+ id: "identities",
16276
+ group: "label",
16277
+ label: "Identities",
16278
+ valueType: "stringList",
16279
+ operator: "in",
16280
+ appliesTo: ["immediate", "track-end"],
16281
+ phase: "P1",
16282
+ description: "P1: matched against the identity display name on the record label."
16283
+ },
16284
+ {
16285
+ id: "plates",
16286
+ group: "label",
16287
+ label: "License plates",
16288
+ valueType: "plateMatcher",
16289
+ operator: "fuzzyIn",
16290
+ appliesTo: ["immediate", "track-end"],
16291
+ phase: "P1",
16292
+ description: "Levenshtein-tolerant match against the plate text."
16293
+ },
16294
+ {
16295
+ id: "schedule",
16296
+ group: "schedule",
16297
+ label: "Schedule",
16298
+ valueType: "schedule",
16299
+ operator: "withinSchedule",
16300
+ appliesTo: ["immediate", "track-end"],
16301
+ phase: "P1",
16302
+ description: "Weekly activation windows (invertible); absent = always active."
16303
+ }
16304
+ ];
16305
+ var notificationRulesCapability = {
16306
+ name: "notification-rules",
16307
+ scope: "system",
16308
+ mode: "singleton",
16309
+ methods: {
16310
+ listRules: method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }),
16311
+ getRule: method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }),
16312
+ createRule: method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
16313
+ kind: "mutation",
16314
+ auth: "admin",
16315
+ caller: "required"
16316
+ }),
16317
+ updateRule: method(object({
16318
+ ruleId: string(),
16319
+ patch: NcRulePatchSchema
16320
+ }), object({ rule: NcRuleSchema }), {
16321
+ kind: "mutation",
16322
+ auth: "admin",
16323
+ caller: "required"
16324
+ }),
16325
+ deleteRule: method(object({ ruleId: string() }), object({ success: literal(true) }), {
16326
+ kind: "mutation",
16327
+ auth: "admin"
16328
+ }),
16329
+ setRuleEnabled: method(object({
16330
+ ruleId: string(),
16331
+ enabled: boolean()
16332
+ }), object({ success: literal(true) }), {
16333
+ kind: "mutation",
16334
+ auth: "admin"
16335
+ }),
16336
+ /**
16337
+ * Dry-run a rule against recently persisted records (object events for
16338
+ * `immediate`, closed tracks for `track-end`). Mutation kind only to
16339
+ * carry the full rule object safely; no side effects.
16340
+ */
16341
+ testRule: method(object({
16342
+ rule: NcRuleInputSchema,
16343
+ lookbackMinutes: number().int().min(1).max(1440).default(60)
16344
+ }), object({ results: array(NcTestResultSchema) }), {
16345
+ kind: "mutation",
16346
+ auth: "admin"
16347
+ }),
16348
+ getConditionCatalog: method(object({}), object({ catalog: array(NcConditionDescriptorSchema) }))
16349
+ }
16350
+ };
16351
+ /**
15975
16352
  * Shared LLM generate contracts — imported by BOTH `llm.cap.ts` (consumer
15976
16353
  * surface) and `llm-runtime.cap.ts` (node-side managed executor) so the two
15977
16354
  * caps stay wire-compatible without a circular cap→cap import.
@@ -23613,6 +23990,54 @@ Object.freeze({
23613
23990
  addonId: null,
23614
23991
  access: "create"
23615
23992
  },
23993
+ "notificationRules.createRule": {
23994
+ capName: "notification-rules",
23995
+ capScope: "system",
23996
+ addonId: null,
23997
+ access: "create"
23998
+ },
23999
+ "notificationRules.deleteRule": {
24000
+ capName: "notification-rules",
24001
+ capScope: "system",
24002
+ addonId: null,
24003
+ access: "delete"
24004
+ },
24005
+ "notificationRules.getConditionCatalog": {
24006
+ capName: "notification-rules",
24007
+ capScope: "system",
24008
+ addonId: null,
24009
+ access: "view"
24010
+ },
24011
+ "notificationRules.getRule": {
24012
+ capName: "notification-rules",
24013
+ capScope: "system",
24014
+ addonId: null,
24015
+ access: "view"
24016
+ },
24017
+ "notificationRules.listRules": {
24018
+ capName: "notification-rules",
24019
+ capScope: "system",
24020
+ addonId: null,
24021
+ access: "view"
24022
+ },
24023
+ "notificationRules.setRuleEnabled": {
24024
+ capName: "notification-rules",
24025
+ capScope: "system",
24026
+ addonId: null,
24027
+ access: "create"
24028
+ },
24029
+ "notificationRules.testRule": {
24030
+ capName: "notification-rules",
24031
+ capScope: "system",
24032
+ addonId: null,
24033
+ access: "create"
24034
+ },
24035
+ "notificationRules.updateRule": {
24036
+ capName: "notification-rules",
24037
+ capScope: "system",
24038
+ addonId: null,
24039
+ access: "create"
24040
+ },
23616
24041
  "notifier.cancel": {
23617
24042
  capName: "notifier",
23618
24043
  capScope: "device",
@@ -25868,6 +26293,18 @@ Object.defineProperty(exports, "MACRO_LABELS", {
25868
26293
  return MACRO_LABELS;
25869
26294
  }
25870
26295
  });
26296
+ Object.defineProperty(exports, "NC_CONDITION_CATALOG", {
26297
+ enumerable: true,
26298
+ get: function() {
26299
+ return NC_CONDITION_CATALOG;
26300
+ }
26301
+ });
26302
+ Object.defineProperty(exports, "NcRuleSchema", {
26303
+ enumerable: true,
26304
+ get: function() {
26305
+ return NcRuleSchema;
26306
+ }
26307
+ });
25871
26308
  Object.defineProperty(exports, "OpsLogEntrySchema", {
25872
26309
  enumerable: true,
25873
26310
  get: function() {
@@ -25958,6 +26395,12 @@ Object.defineProperty(exports, "nodePin", {
25958
26395
  return nodePin;
25959
26396
  }
25960
26397
  });
26398
+ Object.defineProperty(exports, "notificationRulesCapability", {
26399
+ enumerable: true,
26400
+ get: function() {
26401
+ return notificationRulesCapability;
26402
+ }
26403
+ });
25961
26404
  Object.defineProperty(exports, "number", {
25962
26405
  enumerable: true,
25963
26406
  get: function() {