@camstack/addon-post-analysis 1.2.53 → 1.2.54
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/{dist-DGdY1GSf.js → dist-BJ65Xxa1.js} +39 -1
- package/dist/{dist-Da97q0x6.mjs → dist-BVOgkikr.mjs} +39 -1
- package/dist/embedding-encoder/index.js +5 -2
- package/dist/embedding-encoder/index.mjs +5 -3
- package/dist/{node-CpXZkQ6V.js → node-DTrkngzv.js} +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-tCAuhv5m.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-uW2bbQBi.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-CyLkuQ7j.mjs → hostInit-BC7FXncY.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +108 -51
- package/dist/pipeline-analytics/index.mjs +107 -50
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -20953,7 +20953,29 @@ var FaceInfoSchema = object({
|
|
|
20953
20953
|
recognizedIdentityId: string().optional(),
|
|
20954
20954
|
identityName: string().optional(),
|
|
20955
20955
|
assigned: boolean(),
|
|
20956
|
+
/**
|
|
20957
|
+
* The crop, inline, base64.
|
|
20958
|
+
*
|
|
20959
|
+
* **Prefer {@link cropUrl}.** At the 500 rows the Faces view asks for this
|
|
20960
|
+
* field alone is ~2.87 MiB, re-sent in full on every operator assign and
|
|
20961
|
+
* every 30 s poll, base64-inflated over the msgpack socket and held in the
|
|
20962
|
+
* query heap. It stays for callers that have not migrated; `includeCrops:
|
|
20963
|
+
* false` turns it off once they have.
|
|
20964
|
+
*/
|
|
20956
20965
|
base64: string().optional(),
|
|
20966
|
+
/**
|
|
20967
|
+
* Same crop, as a data-plane URL for `<img src>` — the move the admin
|
|
20968
|
+
* snapshot surfaces made on 2026-08-08.
|
|
20969
|
+
*
|
|
20970
|
+
* Served by the `event-media` plane, which resolves a raw MediaStore key and
|
|
20971
|
+
* is `access: 'authenticated'`: a bare `<img>` carries the `camstack_session`
|
|
20972
|
+
* cookie, so no header plumbing is needed. The bytes then ride the browser's
|
|
20973
|
+
* HTTP cache with an ETag and `immutable`, instead of the WebSocket.
|
|
20974
|
+
*
|
|
20975
|
+
* Absent when the face has no stored crop, or when the addon has no data
|
|
20976
|
+
* plane — callers fall back to {@link base64}.
|
|
20977
|
+
*/
|
|
20978
|
+
cropUrl: string().optional(),
|
|
20957
20979
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
20958
20980
|
* view draw the box over the native `keyFrameMediaKey` frame. Absent on
|
|
20959
20981
|
* legacy rows written before design B. */
|
|
@@ -21029,7 +21051,23 @@ var faceGalleryCapability = {
|
|
|
21029
21051
|
}),
|
|
21030
21052
|
listRecentFaces: method(object({
|
|
21031
21053
|
limit: number().int().positive().optional(),
|
|
21032
|
-
filter: FaceFilterEnum.optional()
|
|
21054
|
+
filter: FaceFilterEnum.optional(),
|
|
21055
|
+
/**
|
|
21056
|
+
* Inline the base64 crop on every row. Default `true` — the existing
|
|
21057
|
+
* behaviour, kept so no caller breaks.
|
|
21058
|
+
*
|
|
21059
|
+
* Set `false` once the caller renders {@link FaceInfo.cropUrl}: that
|
|
21060
|
+
* drops ~2.87 MiB per 500-row page to a few KiB of metadata and lets
|
|
21061
|
+
* the browser cache the images.
|
|
21062
|
+
*
|
|
21063
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
21064
|
+
* next train.** The hub router validates cap inputs against its own
|
|
21065
|
+
* compiled Zod, which strips a key it does not know — verified today
|
|
21066
|
+
* on the OUTPUT side, where an additive field DOES arrive immediately
|
|
21067
|
+
* (`Track.hasFace`). Until the train ships, sending `false` is
|
|
21068
|
+
* harmless and simply keeps the crops inline.
|
|
21069
|
+
*/
|
|
21070
|
+
includeCrops: boolean().optional()
|
|
21033
21071
|
}).optional(), array(FaceInfoSchema).readonly()),
|
|
21034
21072
|
getFaceByTrack: method(object({
|
|
21035
21073
|
deviceId: number().int(),
|
|
@@ -20931,7 +20931,29 @@ var FaceInfoSchema = object({
|
|
|
20931
20931
|
recognizedIdentityId: string().optional(),
|
|
20932
20932
|
identityName: string().optional(),
|
|
20933
20933
|
assigned: boolean(),
|
|
20934
|
+
/**
|
|
20935
|
+
* The crop, inline, base64.
|
|
20936
|
+
*
|
|
20937
|
+
* **Prefer {@link cropUrl}.** At the 500 rows the Faces view asks for this
|
|
20938
|
+
* field alone is ~2.87 MiB, re-sent in full on every operator assign and
|
|
20939
|
+
* every 30 s poll, base64-inflated over the msgpack socket and held in the
|
|
20940
|
+
* query heap. It stays for callers that have not migrated; `includeCrops:
|
|
20941
|
+
* false` turns it off once they have.
|
|
20942
|
+
*/
|
|
20934
20943
|
base64: string().optional(),
|
|
20944
|
+
/**
|
|
20945
|
+
* Same crop, as a data-plane URL for `<img src>` — the move the admin
|
|
20946
|
+
* snapshot surfaces made on 2026-08-08.
|
|
20947
|
+
*
|
|
20948
|
+
* Served by the `event-media` plane, which resolves a raw MediaStore key and
|
|
20949
|
+
* is `access: 'authenticated'`: a bare `<img>` carries the `camstack_session`
|
|
20950
|
+
* cookie, so no header plumbing is needed. The bytes then ride the browser's
|
|
20951
|
+
* HTTP cache with an ETag and `immutable`, instead of the WebSocket.
|
|
20952
|
+
*
|
|
20953
|
+
* Absent when the face has no stored crop, or when the addon has no data
|
|
20954
|
+
* plane — callers fall back to {@link base64}.
|
|
20955
|
+
*/
|
|
20956
|
+
cropUrl: string().optional(),
|
|
20935
20957
|
/** Design B: the face bbox (pixel space) on the key frame — lets a detail
|
|
20936
20958
|
* view draw the box over the native `keyFrameMediaKey` frame. Absent on
|
|
20937
20959
|
* legacy rows written before design B. */
|
|
@@ -21007,7 +21029,23 @@ var faceGalleryCapability = {
|
|
|
21007
21029
|
}),
|
|
21008
21030
|
listRecentFaces: method(object({
|
|
21009
21031
|
limit: number().int().positive().optional(),
|
|
21010
|
-
filter: FaceFilterEnum.optional()
|
|
21032
|
+
filter: FaceFilterEnum.optional(),
|
|
21033
|
+
/**
|
|
21034
|
+
* Inline the base64 crop on every row. Default `true` — the existing
|
|
21035
|
+
* behaviour, kept so no caller breaks.
|
|
21036
|
+
*
|
|
21037
|
+
* Set `false` once the caller renders {@link FaceInfo.cropUrl}: that
|
|
21038
|
+
* drops ~2.87 MiB per 500-row page to a few KiB of metadata and lets
|
|
21039
|
+
* the browser cache the images.
|
|
21040
|
+
*
|
|
21041
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
21042
|
+
* next train.** The hub router validates cap inputs against its own
|
|
21043
|
+
* compiled Zod, which strips a key it does not know — verified today
|
|
21044
|
+
* on the OUTPUT side, where an additive field DOES arrive immediately
|
|
21045
|
+
* (`Track.hasFace`). Until the train ships, sending `false` is
|
|
21046
|
+
* harmless and simply keeps the crops inline.
|
|
21047
|
+
*/
|
|
21048
|
+
includeCrops: boolean().optional()
|
|
21011
21049
|
}).optional(), array(FaceInfoSchema).readonly()),
|
|
21012
21050
|
getFaceByTrack: method(object({
|
|
21013
21051
|
deviceId: number().int(),
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BJ65Xxa1.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_fs$1 = require_dist.__toESM(node_fs, 1);
|
|
8
8
|
node_fs = require_dist.__toESM(node_fs);
|
|
@@ -10,8 +10,11 @@ let node_path = require("node:path");
|
|
|
10
10
|
let node_path$1 = require_dist.__toESM(node_path, 1);
|
|
11
11
|
node_path = require_dist.__toESM(node_path);
|
|
12
12
|
require("node:crypto");
|
|
13
|
+
let node_util = require("node:util");
|
|
14
|
+
let node_zlib = require("node:zlib");
|
|
13
15
|
let node_child_process = require("node:child_process");
|
|
14
|
-
|
|
16
|
+
(0, node_util.promisify)(node_zlib.brotliCompress);
|
|
17
|
+
(0, node_util.promisify)(node_zlib.gzip);
|
|
15
18
|
function isNonEmptyFile(filePath) {
|
|
16
19
|
return node_fs$1.existsSync(filePath) && node_fs$1.statSync(filePath).size > 0;
|
|
17
20
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { A as embeddingEncoderCapability, G as BaseAddon, N as hfModelUrl } from "../dist-
|
|
1
|
+
import { A as embeddingEncoderCapability, G as BaseAddon, N as hfModelUrl } from "../dist-BVOgkikr.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import "node:fs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import "node:path";
|
|
7
7
|
import "node:crypto";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { brotliCompress, gzip } from "node:zlib";
|
|
8
10
|
import { spawn } from "node:child_process";
|
|
9
11
|
//#region \0rolldown/runtime.js
|
|
10
12
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
promisify(brotliCompress);
|
|
14
|
+
promisify(gzip);
|
|
13
15
|
function isNonEmptyFile(filePath) {
|
|
14
16
|
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
15
17
|
}
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BJ65Xxa1.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_dist.__toESM(node_path);
|
|
@@ -6771,6 +6771,40 @@ function makeNcActionHandlers(deps) {
|
|
|
6771
6771
|
}
|
|
6772
6772
|
};
|
|
6773
6773
|
}
|
|
6774
|
+
//#endregion
|
|
6775
|
+
//#region src/pipeline-analytics/data-plane-access.ts
|
|
6776
|
+
/**
|
|
6777
|
+
* Prefix literals for the export planes, mirrored here so the policy reads as
|
|
6778
|
+
* a table without importing three handler modules into the addon's boot path.
|
|
6779
|
+
* `data-plane-access.spec.ts` asserts they still match the constants their
|
|
6780
|
+
* handlers register with — a mirror nothing checks is a lie waiting to happen.
|
|
6781
|
+
*/
|
|
6782
|
+
var TRAINING_EXPORT_PREFIX_REF = "training-export";
|
|
6783
|
+
var RETRAIN_EXPORT_PREFIX_REF = "retrain-export";
|
|
6784
|
+
var DEBUG_EXPORT_PREFIX_REF = "debug-export";
|
|
6785
|
+
/**
|
|
6786
|
+
* Every data plane this addon serves, and the level the HUB enforces before it
|
|
6787
|
+
* proxies. Exhaustive by test: a new plane that forgets to appear here fails
|
|
6788
|
+
* `data-plane-access.spec.ts`.
|
|
6789
|
+
*/
|
|
6790
|
+
var PIPELINE_ANALYTICS_PLANE_ACCESS = {
|
|
6791
|
+
/** One stored crop/thumbnail by an unguessable id the caller already holds. */
|
|
6792
|
+
"event-media": "authenticated",
|
|
6793
|
+
/** Self-authenticating single-use action token (D47). */
|
|
6794
|
+
"nc-action": "public",
|
|
6795
|
+
/** Self-authenticating single-use artifact token (D47). */
|
|
6796
|
+
"nc-artifact": "public",
|
|
6797
|
+
/** Every frame behind a marked selection — a corpus, not an item. */
|
|
6798
|
+
[TRAINING_EXPORT_PREFIX_REF]: "admin",
|
|
6799
|
+
[RETRAIN_EXPORT_PREFIX_REF]: "admin",
|
|
6800
|
+
/** Diagnostic bundle: logs, config and frames. */
|
|
6801
|
+
[DEBUG_EXPORT_PREFIX_REF]: "admin"
|
|
6802
|
+
};
|
|
6803
|
+
/** The declared level for a plane prefix. Typed, so a prefix with no declared
|
|
6804
|
+
* policy is a compile error rather than a silent default. */
|
|
6805
|
+
function planeAccess(prefix) {
|
|
6806
|
+
return PIPELINE_ANALYTICS_PLANE_ACCESS[prefix];
|
|
6807
|
+
}
|
|
6774
6808
|
var MAX_EXPORT_BYTES = 256 * 1024 * 1024;
|
|
6775
6809
|
var DebugFindingSchema = require_dist.object({
|
|
6776
6810
|
code: require_dist.string(),
|
|
@@ -7129,40 +7163,6 @@ function parseDebugDeviceIds(url) {
|
|
|
7129
7163
|
return out;
|
|
7130
7164
|
}
|
|
7131
7165
|
//#endregion
|
|
7132
|
-
//#region src/pipeline-analytics/data-plane-access.ts
|
|
7133
|
-
/**
|
|
7134
|
-
* Prefix literals for the export planes, mirrored here so the policy reads as
|
|
7135
|
-
* a table without importing three handler modules into the addon's boot path.
|
|
7136
|
-
* `data-plane-access.spec.ts` asserts they still match the constants their
|
|
7137
|
-
* handlers register with — a mirror nothing checks is a lie waiting to happen.
|
|
7138
|
-
*/
|
|
7139
|
-
var TRAINING_EXPORT_PREFIX_REF = "training-export";
|
|
7140
|
-
var RETRAIN_EXPORT_PREFIX_REF = "retrain-export";
|
|
7141
|
-
var DEBUG_EXPORT_PREFIX_REF = "debug-export";
|
|
7142
|
-
/**
|
|
7143
|
-
* Every data plane this addon serves, and the level the HUB enforces before it
|
|
7144
|
-
* proxies. Exhaustive by test: a new plane that forgets to appear here fails
|
|
7145
|
-
* `data-plane-access.spec.ts`.
|
|
7146
|
-
*/
|
|
7147
|
-
var PIPELINE_ANALYTICS_PLANE_ACCESS = {
|
|
7148
|
-
/** One stored crop/thumbnail by an unguessable id the caller already holds. */
|
|
7149
|
-
"event-media": "authenticated",
|
|
7150
|
-
/** Self-authenticating single-use action token (D47). */
|
|
7151
|
-
"nc-action": "public",
|
|
7152
|
-
/** Self-authenticating single-use artifact token (D47). */
|
|
7153
|
-
"nc-artifact": "public",
|
|
7154
|
-
/** Every frame behind a marked selection — a corpus, not an item. */
|
|
7155
|
-
[TRAINING_EXPORT_PREFIX_REF]: "admin",
|
|
7156
|
-
[RETRAIN_EXPORT_PREFIX_REF]: "admin",
|
|
7157
|
-
/** Diagnostic bundle: logs, config and frames. */
|
|
7158
|
-
[DEBUG_EXPORT_PREFIX_REF]: "admin"
|
|
7159
|
-
};
|
|
7160
|
-
/** The declared level for a plane prefix. Typed, so a prefix with no declared
|
|
7161
|
-
* policy is a compile error rather than a silent default. */
|
|
7162
|
-
function planeAccess(prefix) {
|
|
7163
|
-
return PIPELINE_ANALYTICS_PLANE_ACCESS[prefix];
|
|
7164
|
-
}
|
|
7165
|
-
//#endregion
|
|
7166
7166
|
//#region src/pipeline-analytics/debug/debug-export-handler.ts
|
|
7167
7167
|
/**
|
|
7168
7168
|
* Pacing. The export is a BACKGROUND job sharing a thread with live decode, so
|
|
@@ -7689,6 +7689,25 @@ var embeddingActions = require_dist.defineCustomActions({
|
|
|
7689
7689
|
"embedding.wipe": require_dist.customAction(NoInputSchema, WipeResultSchema, { auth: "admin" })
|
|
7690
7690
|
});
|
|
7691
7691
|
//#endregion
|
|
7692
|
+
//#region src/pipeline-analytics/map-with-concurrency.ts
|
|
7693
|
+
/**
|
|
7694
|
+
* Apply `mapper` to every item with at most `limit` in flight at once.
|
|
7695
|
+
*
|
|
7696
|
+
* A rejecting mapper rejects the whole call (same contract as `Promise.all`);
|
|
7697
|
+
* callers that must not fail a page for one bad row catch inside the mapper.
|
|
7698
|
+
*/
|
|
7699
|
+
async function mapWithConcurrency(items, limit, mapper) {
|
|
7700
|
+
const results = new Array(items.length);
|
|
7701
|
+
if (items.length === 0) return results;
|
|
7702
|
+
const effectiveLimit = Math.max(1, Math.min(Math.trunc(limit), items.length));
|
|
7703
|
+
const entries = items.entries();
|
|
7704
|
+
const worker = async () => {
|
|
7705
|
+
for (const [index, item] of entries) results[index] = await mapper(item, index);
|
|
7706
|
+
};
|
|
7707
|
+
await Promise.all(Array.from({ length: effectiveLimit }, () => worker()));
|
|
7708
|
+
return results;
|
|
7709
|
+
}
|
|
7710
|
+
//#endregion
|
|
7692
7711
|
//#region src/pipeline-analytics/pipeline/key-event-scoring.ts
|
|
7693
7712
|
/**
|
|
7694
7713
|
* key-event-scoring — the SINGLE deterministic "importance" scorer for a
|
|
@@ -7960,6 +7979,16 @@ function clusterByEmbedding(items, threshold = .5) {
|
|
|
7960
7979
|
var OPERATOR_FACE_STEP_ID = "operator:face-gallery";
|
|
7961
7980
|
/** Embedding model id used when enrolling face crops as identity samples. */
|
|
7962
7981
|
var MODEL_ID = "arcface-r100";
|
|
7982
|
+
/**
|
|
7983
|
+
* How many face crops `listRecentFaces` resolves at once.
|
|
7984
|
+
*
|
|
7985
|
+
* Each crop costs a store round-trip plus a disk read, so the page is I/O-bound
|
|
7986
|
+
* and the serial form dominated the operator's assign latency. 16 recovers
|
|
7987
|
+
* nearly all of the win while leaving the UDS channel — shared with the live
|
|
7988
|
+
* detection path — far from saturated; unbounded would trade a slow page for a
|
|
7989
|
+
* stalled pipeline.
|
|
7990
|
+
*/
|
|
7991
|
+
var FACE_CROP_FETCH_CONCURRENCY = 16;
|
|
7963
7992
|
var FaceGalleryProvider = class {
|
|
7964
7993
|
identityStore;
|
|
7965
7994
|
faceStore;
|
|
@@ -7968,6 +7997,7 @@ var FaceGalleryProvider = class {
|
|
|
7968
7997
|
eventStore;
|
|
7969
7998
|
logger;
|
|
7970
7999
|
refreshGallery;
|
|
8000
|
+
eventMediaBaseUrl;
|
|
7971
8001
|
emitFaceGalleryChanged;
|
|
7972
8002
|
constructor(deps) {
|
|
7973
8003
|
this.identityStore = deps.identityStore;
|
|
@@ -7977,6 +8007,7 @@ var FaceGalleryProvider = class {
|
|
|
7977
8007
|
this.eventStore = deps.eventStore;
|
|
7978
8008
|
this.logger = deps.logger;
|
|
7979
8009
|
this.refreshGallery = deps.refreshGallery;
|
|
8010
|
+
this.eventMediaBaseUrl = deps.eventMediaBaseUrl;
|
|
7980
8011
|
this.emitFaceGalleryChanged = deps.emitFaceGalleryChanged;
|
|
7981
8012
|
}
|
|
7982
8013
|
/** Best-effort emit — never allowed to fail the mutation it follows. */
|
|
@@ -8068,6 +8099,21 @@ var FaceGalleryProvider = class {
|
|
|
8068
8099
|
const media = await this.mediaStore.listByOwner("face", face.id);
|
|
8069
8100
|
return media.length > 0 ? media[0].base64 : void 0;
|
|
8070
8101
|
}
|
|
8102
|
+
/**
|
|
8103
|
+
* The crop as a data-plane URL, or undefined when there is no stored key or
|
|
8104
|
+
* no plane to serve it.
|
|
8105
|
+
*
|
|
8106
|
+
* The `event-media` plane resolves a raw MediaStore key (any id containing
|
|
8107
|
+
* `:` goes to `getByKey`), so a face crop needs NO new plane and no new
|
|
8108
|
+
* access decision — the same `authenticated` level already serves the track
|
|
8109
|
+
* thumbnails the same operator is looking at.
|
|
8110
|
+
*/
|
|
8111
|
+
cropUrlFor(face) {
|
|
8112
|
+
if (face.mediaKey === void 0 || face.mediaKey === "") return void 0;
|
|
8113
|
+
const base = this.eventMediaBaseUrl();
|
|
8114
|
+
if (base === null) return void 0;
|
|
8115
|
+
return `${base}/${encodeURIComponent(face.mediaKey)}`;
|
|
8116
|
+
}
|
|
8071
8117
|
async listRecentFaces(input) {
|
|
8072
8118
|
const faces = await this.faceStore.listAllRecentFaces({
|
|
8073
8119
|
limit: input?.limit,
|
|
@@ -8075,11 +8121,12 @@ var FaceGalleryProvider = class {
|
|
|
8075
8121
|
});
|
|
8076
8122
|
const identities = await this.identityStore.listIdentities();
|
|
8077
8123
|
const nameMap = new Map(identities.map((i) => [i.id, i.name]));
|
|
8078
|
-
const
|
|
8079
|
-
|
|
8080
|
-
const base64 = await this.faceCropBase64(face);
|
|
8124
|
+
const includeCrops = input?.includeCrops ?? true;
|
|
8125
|
+
return mapWithConcurrency(faces, FACE_CROP_FETCH_CONCURRENCY, async (face) => {
|
|
8126
|
+
const base64 = includeCrops ? await this.faceCropBase64(face) : void 0;
|
|
8127
|
+
const cropUrl = this.cropUrlFor(face);
|
|
8081
8128
|
const identityName = face.recognizedIdentityId ? nameMap.get(face.recognizedIdentityId) : void 0;
|
|
8082
|
-
|
|
8129
|
+
return {
|
|
8083
8130
|
faceId: face.id,
|
|
8084
8131
|
deviceId: face.deviceId,
|
|
8085
8132
|
trackId: face.trackId,
|
|
@@ -8088,15 +8135,15 @@ var FaceGalleryProvider = class {
|
|
|
8088
8135
|
...identityName !== void 0 ? { identityName } : {},
|
|
8089
8136
|
assigned: face.assigned,
|
|
8090
8137
|
...base64 !== void 0 ? { base64 } : {},
|
|
8138
|
+
...cropUrl !== void 0 ? { cropUrl } : {},
|
|
8091
8139
|
...face.faceBbox !== void 0 ? { faceBbox: face.faceBbox } : {},
|
|
8092
8140
|
...face.keyFrameMediaKey !== void 0 ? { keyFrameMediaKey: face.keyFrameMediaKey } : {},
|
|
8093
8141
|
...face.bestMatchScore != null ? { bestMatchScore: face.bestMatchScore } : {},
|
|
8094
8142
|
...face.nativeFaceShortSidePx != null ? { nativeFaceShortSidePx: face.nativeFaceShortSidePx } : {},
|
|
8095
8143
|
...face.suggestedIdentityId != null ? { suggestedIdentityId: face.suggestedIdentityId } : {},
|
|
8096
8144
|
...face.suggestedMatchScore != null ? { suggestedMatchScore: face.suggestedMatchScore } : {}
|
|
8097
|
-
}
|
|
8098
|
-
}
|
|
8099
|
-
return result;
|
|
8145
|
+
};
|
|
8146
|
+
});
|
|
8100
8147
|
}
|
|
8101
8148
|
/**
|
|
8102
8149
|
* Get a face by deviceId + trackId. Returns null if not found or if
|
|
@@ -20124,6 +20171,21 @@ var PlateRecognizer = class {
|
|
|
20124
20171
|
}
|
|
20125
20172
|
};
|
|
20126
20173
|
//#endregion
|
|
20174
|
+
//#region src/pipeline-analytics/read-slice.ts
|
|
20175
|
+
/**
|
|
20176
|
+
* The loaded slice, or `undefined` when it has never loaded and the one
|
|
20177
|
+
* permitted refresh also failed to produce it.
|
|
20178
|
+
*
|
|
20179
|
+
* A failing refresh is swallowed deliberately: every caller degrades to "no
|
|
20180
|
+
* zones / no rules", and a zone read must never take down the frame that asked.
|
|
20181
|
+
*/
|
|
20182
|
+
async function readSliceOnce(handle) {
|
|
20183
|
+
const loaded = handle.value;
|
|
20184
|
+
if (loaded !== void 0) return loaded;
|
|
20185
|
+
await handle.refresh().catch(() => void 0);
|
|
20186
|
+
return handle.value;
|
|
20187
|
+
}
|
|
20188
|
+
//#endregion
|
|
20127
20189
|
//#region src/pipeline-analytics/rebuild-detail-request.ts
|
|
20128
20190
|
/** The one step a rebuild runs. */
|
|
20129
20191
|
var REBUILD_DETAIL_STEP_ID = "clip-embedding";
|
|
@@ -31305,7 +31367,7 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
31305
31367
|
let storage = this.ctx.kernel.storage;
|
|
31306
31368
|
const mediaRoot = process.env.CAMSTACK_MEDIA_ROOT?.trim();
|
|
31307
31369
|
if (mediaRoot) {
|
|
31308
|
-
const { FilesystemStorageProvider } = await Promise.resolve().then(() => require("../node-
|
|
31370
|
+
const { FilesystemStorageProvider } = await Promise.resolve().then(() => require("../node-DTrkngzv.js"));
|
|
31309
31371
|
storage = new FilesystemStorageProvider(mediaRoot, { eventMedia: mediaRoot });
|
|
31310
31372
|
logger.info("pipeline-analytics: event media rooted at CAMSTACK_MEDIA_ROOT", { meta: { mediaRoot } });
|
|
31311
31373
|
}
|
|
@@ -32316,6 +32378,7 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
32316
32378
|
eventStore: stores.eventStore,
|
|
32317
32379
|
logger: this.ctx.logger,
|
|
32318
32380
|
refreshGallery: () => this.faceRecognizer?.refreshGallery(),
|
|
32381
|
+
eventMediaBaseUrl: () => this.eventMediaBaseUrl,
|
|
32319
32382
|
emitFaceGalleryChanged: (payload) => this.emitFaceGalleryChanged(payload)
|
|
32320
32383
|
});
|
|
32321
32384
|
const plateGallery = new PlateGalleryProvider({
|
|
@@ -33327,10 +33390,7 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
33327
33390
|
async resolveDevicePackageRules(deviceId) {
|
|
33328
33391
|
const proxy = await this.ensureProxy(deviceId);
|
|
33329
33392
|
if (!proxy) return [];
|
|
33330
|
-
|
|
33331
|
-
if (cached && cached.length > 0) return cached;
|
|
33332
|
-
await proxy.state.zoneRules.refresh().catch(() => void 0);
|
|
33333
|
-
return proxy.state.zoneRules.value?.package ?? [];
|
|
33393
|
+
return (await readSliceOnce(proxy.state.zoneRules))?.package ?? [];
|
|
33334
33394
|
}
|
|
33335
33395
|
/**
|
|
33336
33396
|
* Route one track's `runDetailSubtree` results (two-plane detail dispatch)
|
|
@@ -34638,10 +34698,7 @@ var PipelineAnalyticsAddon = class extends require_dist.BaseAddon {
|
|
|
34638
34698
|
async resolveDeviceZones(deviceId) {
|
|
34639
34699
|
const proxy = await this.ensureProxy(deviceId);
|
|
34640
34700
|
if (!proxy) return [];
|
|
34641
|
-
|
|
34642
|
-
if (cached && cached.length > 0) return cached;
|
|
34643
|
-
await proxy.state.zones.refresh().catch(() => void 0);
|
|
34644
|
-
return proxy.state.zones.value?.zones ?? [];
|
|
34701
|
+
return (await readSliceOnce(proxy.state.zones))?.zones ?? [];
|
|
34645
34702
|
}
|
|
34646
34703
|
releaseProxy(deviceId) {
|
|
34647
34704
|
const unsubs = this.proxyUnsubs.get(deviceId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as array, B as subKindsOf, C as addonWidgetsSourceCapability, D as cosineSimilarity, E as buildEventKindDescriptor, F as kebabToCamel, G as BaseAddon, H as videoclipsCapability, I as notificationRulesCapability, J as hydrateSchema, K as DeviceType, L as pipelineAnalyticsCapability, M as faceGalleryCapability, O as customAction, P as isScheduleActive, Q as _enum, R as plateGalleryCapability, S as TrackSourceSchema, T as audioMetricsCapability, U as zoneAnalyticsCapability, V as vectorDimFromBase64, W as errMsg, X as nodePin, Y as isDeviceScopedCap, Z as sleep, _ as NcTaxonomySchema, a as EVENT_PAD_MS, at as string, b as TimelapseRuleInputSchema, c as NC_CONDITION_CATALOG, d as NcRuleInputSchema, et as boolean, f as NcRulePatchSchema, g as NcSnoozeSuppressedSchema, h as NcSnoozeSchema, i as EVENT_KIND_BY_CAP, it as record, j as encodeVectorBase64, k as defineCustomActions, l as NC_TAXONOMY, m as NcSnoozeInputSchema, n as DEFAULT_EVENT_COLOR, nt as number, o as LabelAttributionSchema, ot as unknown, p as NcRuleSchema, q as createEvent, r as DeclaredDevices, rt as object, s as MACRO_LABELS, st as EventCategory, t as BaseDevice, tt as literal, u as NcConditionDescriptorSchema, v as OpsLogEntrySchema, w as alarmPanelCapability, x as TimelapseRuleSchema, y as RetrainStatusSchema, z as readDeviceStateFrom } from "../dist-
|
|
1
|
+
import { $ as array, B as subKindsOf, C as addonWidgetsSourceCapability, D as cosineSimilarity, E as buildEventKindDescriptor, F as kebabToCamel, G as BaseAddon, H as videoclipsCapability, I as notificationRulesCapability, J as hydrateSchema, K as DeviceType, L as pipelineAnalyticsCapability, M as faceGalleryCapability, O as customAction, P as isScheduleActive, Q as _enum, R as plateGalleryCapability, S as TrackSourceSchema, T as audioMetricsCapability, U as zoneAnalyticsCapability, V as vectorDimFromBase64, W as errMsg, X as nodePin, Y as isDeviceScopedCap, Z as sleep, _ as NcTaxonomySchema, a as EVENT_PAD_MS, at as string, b as TimelapseRuleInputSchema, c as NC_CONDITION_CATALOG, d as NcRuleInputSchema, et as boolean, f as NcRulePatchSchema, g as NcSnoozeSuppressedSchema, h as NcSnoozeSchema, i as EVENT_KIND_BY_CAP, it as record, j as encodeVectorBase64, k as defineCustomActions, l as NC_TAXONOMY, m as NcSnoozeInputSchema, n as DEFAULT_EVENT_COLOR, nt as number, o as LabelAttributionSchema, ot as unknown, p as NcRuleSchema, q as createEvent, r as DeclaredDevices, rt as object, s as MACRO_LABELS, st as EventCategory, t as BaseDevice, tt as literal, u as NcConditionDescriptorSchema, v as OpsLogEntrySchema, w as alarmPanelCapability, x as TimelapseRuleSchema, y as RetrainStatusSchema, z as readDeviceStateFrom } from "../dist-BVOgkikr.mjs";
|
|
2
2
|
import { promises } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -6757,6 +6757,40 @@ function makeNcActionHandlers(deps) {
|
|
|
6757
6757
|
}
|
|
6758
6758
|
};
|
|
6759
6759
|
}
|
|
6760
|
+
//#endregion
|
|
6761
|
+
//#region src/pipeline-analytics/data-plane-access.ts
|
|
6762
|
+
/**
|
|
6763
|
+
* Prefix literals for the export planes, mirrored here so the policy reads as
|
|
6764
|
+
* a table without importing three handler modules into the addon's boot path.
|
|
6765
|
+
* `data-plane-access.spec.ts` asserts they still match the constants their
|
|
6766
|
+
* handlers register with — a mirror nothing checks is a lie waiting to happen.
|
|
6767
|
+
*/
|
|
6768
|
+
var TRAINING_EXPORT_PREFIX_REF = "training-export";
|
|
6769
|
+
var RETRAIN_EXPORT_PREFIX_REF = "retrain-export";
|
|
6770
|
+
var DEBUG_EXPORT_PREFIX_REF = "debug-export";
|
|
6771
|
+
/**
|
|
6772
|
+
* Every data plane this addon serves, and the level the HUB enforces before it
|
|
6773
|
+
* proxies. Exhaustive by test: a new plane that forgets to appear here fails
|
|
6774
|
+
* `data-plane-access.spec.ts`.
|
|
6775
|
+
*/
|
|
6776
|
+
var PIPELINE_ANALYTICS_PLANE_ACCESS = {
|
|
6777
|
+
/** One stored crop/thumbnail by an unguessable id the caller already holds. */
|
|
6778
|
+
"event-media": "authenticated",
|
|
6779
|
+
/** Self-authenticating single-use action token (D47). */
|
|
6780
|
+
"nc-action": "public",
|
|
6781
|
+
/** Self-authenticating single-use artifact token (D47). */
|
|
6782
|
+
"nc-artifact": "public",
|
|
6783
|
+
/** Every frame behind a marked selection — a corpus, not an item. */
|
|
6784
|
+
[TRAINING_EXPORT_PREFIX_REF]: "admin",
|
|
6785
|
+
[RETRAIN_EXPORT_PREFIX_REF]: "admin",
|
|
6786
|
+
/** Diagnostic bundle: logs, config and frames. */
|
|
6787
|
+
[DEBUG_EXPORT_PREFIX_REF]: "admin"
|
|
6788
|
+
};
|
|
6789
|
+
/** The declared level for a plane prefix. Typed, so a prefix with no declared
|
|
6790
|
+
* policy is a compile error rather than a silent default. */
|
|
6791
|
+
function planeAccess(prefix) {
|
|
6792
|
+
return PIPELINE_ANALYTICS_PLANE_ACCESS[prefix];
|
|
6793
|
+
}
|
|
6760
6794
|
var MAX_EXPORT_BYTES = 256 * 1024 * 1024;
|
|
6761
6795
|
var DebugFindingSchema = object({
|
|
6762
6796
|
code: string(),
|
|
@@ -7115,40 +7149,6 @@ function parseDebugDeviceIds(url) {
|
|
|
7115
7149
|
return out;
|
|
7116
7150
|
}
|
|
7117
7151
|
//#endregion
|
|
7118
|
-
//#region src/pipeline-analytics/data-plane-access.ts
|
|
7119
|
-
/**
|
|
7120
|
-
* Prefix literals for the export planes, mirrored here so the policy reads as
|
|
7121
|
-
* a table without importing three handler modules into the addon's boot path.
|
|
7122
|
-
* `data-plane-access.spec.ts` asserts they still match the constants their
|
|
7123
|
-
* handlers register with — a mirror nothing checks is a lie waiting to happen.
|
|
7124
|
-
*/
|
|
7125
|
-
var TRAINING_EXPORT_PREFIX_REF = "training-export";
|
|
7126
|
-
var RETRAIN_EXPORT_PREFIX_REF = "retrain-export";
|
|
7127
|
-
var DEBUG_EXPORT_PREFIX_REF = "debug-export";
|
|
7128
|
-
/**
|
|
7129
|
-
* Every data plane this addon serves, and the level the HUB enforces before it
|
|
7130
|
-
* proxies. Exhaustive by test: a new plane that forgets to appear here fails
|
|
7131
|
-
* `data-plane-access.spec.ts`.
|
|
7132
|
-
*/
|
|
7133
|
-
var PIPELINE_ANALYTICS_PLANE_ACCESS = {
|
|
7134
|
-
/** One stored crop/thumbnail by an unguessable id the caller already holds. */
|
|
7135
|
-
"event-media": "authenticated",
|
|
7136
|
-
/** Self-authenticating single-use action token (D47). */
|
|
7137
|
-
"nc-action": "public",
|
|
7138
|
-
/** Self-authenticating single-use artifact token (D47). */
|
|
7139
|
-
"nc-artifact": "public",
|
|
7140
|
-
/** Every frame behind a marked selection — a corpus, not an item. */
|
|
7141
|
-
[TRAINING_EXPORT_PREFIX_REF]: "admin",
|
|
7142
|
-
[RETRAIN_EXPORT_PREFIX_REF]: "admin",
|
|
7143
|
-
/** Diagnostic bundle: logs, config and frames. */
|
|
7144
|
-
[DEBUG_EXPORT_PREFIX_REF]: "admin"
|
|
7145
|
-
};
|
|
7146
|
-
/** The declared level for a plane prefix. Typed, so a prefix with no declared
|
|
7147
|
-
* policy is a compile error rather than a silent default. */
|
|
7148
|
-
function planeAccess(prefix) {
|
|
7149
|
-
return PIPELINE_ANALYTICS_PLANE_ACCESS[prefix];
|
|
7150
|
-
}
|
|
7151
|
-
//#endregion
|
|
7152
7152
|
//#region src/pipeline-analytics/debug/debug-export-handler.ts
|
|
7153
7153
|
/**
|
|
7154
7154
|
* Pacing. The export is a BACKGROUND job sharing a thread with live decode, so
|
|
@@ -7675,6 +7675,25 @@ var embeddingActions = defineCustomActions({
|
|
|
7675
7675
|
"embedding.wipe": customAction(NoInputSchema, WipeResultSchema, { auth: "admin" })
|
|
7676
7676
|
});
|
|
7677
7677
|
//#endregion
|
|
7678
|
+
//#region src/pipeline-analytics/map-with-concurrency.ts
|
|
7679
|
+
/**
|
|
7680
|
+
* Apply `mapper` to every item with at most `limit` in flight at once.
|
|
7681
|
+
*
|
|
7682
|
+
* A rejecting mapper rejects the whole call (same contract as `Promise.all`);
|
|
7683
|
+
* callers that must not fail a page for one bad row catch inside the mapper.
|
|
7684
|
+
*/
|
|
7685
|
+
async function mapWithConcurrency(items, limit, mapper) {
|
|
7686
|
+
const results = new Array(items.length);
|
|
7687
|
+
if (items.length === 0) return results;
|
|
7688
|
+
const effectiveLimit = Math.max(1, Math.min(Math.trunc(limit), items.length));
|
|
7689
|
+
const entries = items.entries();
|
|
7690
|
+
const worker = async () => {
|
|
7691
|
+
for (const [index, item] of entries) results[index] = await mapper(item, index);
|
|
7692
|
+
};
|
|
7693
|
+
await Promise.all(Array.from({ length: effectiveLimit }, () => worker()));
|
|
7694
|
+
return results;
|
|
7695
|
+
}
|
|
7696
|
+
//#endregion
|
|
7678
7697
|
//#region src/pipeline-analytics/pipeline/key-event-scoring.ts
|
|
7679
7698
|
/**
|
|
7680
7699
|
* key-event-scoring — the SINGLE deterministic "importance" scorer for a
|
|
@@ -7946,6 +7965,16 @@ function clusterByEmbedding(items, threshold = .5) {
|
|
|
7946
7965
|
var OPERATOR_FACE_STEP_ID = "operator:face-gallery";
|
|
7947
7966
|
/** Embedding model id used when enrolling face crops as identity samples. */
|
|
7948
7967
|
var MODEL_ID = "arcface-r100";
|
|
7968
|
+
/**
|
|
7969
|
+
* How many face crops `listRecentFaces` resolves at once.
|
|
7970
|
+
*
|
|
7971
|
+
* Each crop costs a store round-trip plus a disk read, so the page is I/O-bound
|
|
7972
|
+
* and the serial form dominated the operator's assign latency. 16 recovers
|
|
7973
|
+
* nearly all of the win while leaving the UDS channel — shared with the live
|
|
7974
|
+
* detection path — far from saturated; unbounded would trade a slow page for a
|
|
7975
|
+
* stalled pipeline.
|
|
7976
|
+
*/
|
|
7977
|
+
var FACE_CROP_FETCH_CONCURRENCY = 16;
|
|
7949
7978
|
var FaceGalleryProvider = class {
|
|
7950
7979
|
identityStore;
|
|
7951
7980
|
faceStore;
|
|
@@ -7954,6 +7983,7 @@ var FaceGalleryProvider = class {
|
|
|
7954
7983
|
eventStore;
|
|
7955
7984
|
logger;
|
|
7956
7985
|
refreshGallery;
|
|
7986
|
+
eventMediaBaseUrl;
|
|
7957
7987
|
emitFaceGalleryChanged;
|
|
7958
7988
|
constructor(deps) {
|
|
7959
7989
|
this.identityStore = deps.identityStore;
|
|
@@ -7963,6 +7993,7 @@ var FaceGalleryProvider = class {
|
|
|
7963
7993
|
this.eventStore = deps.eventStore;
|
|
7964
7994
|
this.logger = deps.logger;
|
|
7965
7995
|
this.refreshGallery = deps.refreshGallery;
|
|
7996
|
+
this.eventMediaBaseUrl = deps.eventMediaBaseUrl;
|
|
7966
7997
|
this.emitFaceGalleryChanged = deps.emitFaceGalleryChanged;
|
|
7967
7998
|
}
|
|
7968
7999
|
/** Best-effort emit — never allowed to fail the mutation it follows. */
|
|
@@ -8054,6 +8085,21 @@ var FaceGalleryProvider = class {
|
|
|
8054
8085
|
const media = await this.mediaStore.listByOwner("face", face.id);
|
|
8055
8086
|
return media.length > 0 ? media[0].base64 : void 0;
|
|
8056
8087
|
}
|
|
8088
|
+
/**
|
|
8089
|
+
* The crop as a data-plane URL, or undefined when there is no stored key or
|
|
8090
|
+
* no plane to serve it.
|
|
8091
|
+
*
|
|
8092
|
+
* The `event-media` plane resolves a raw MediaStore key (any id containing
|
|
8093
|
+
* `:` goes to `getByKey`), so a face crop needs NO new plane and no new
|
|
8094
|
+
* access decision — the same `authenticated` level already serves the track
|
|
8095
|
+
* thumbnails the same operator is looking at.
|
|
8096
|
+
*/
|
|
8097
|
+
cropUrlFor(face) {
|
|
8098
|
+
if (face.mediaKey === void 0 || face.mediaKey === "") return void 0;
|
|
8099
|
+
const base = this.eventMediaBaseUrl();
|
|
8100
|
+
if (base === null) return void 0;
|
|
8101
|
+
return `${base}/${encodeURIComponent(face.mediaKey)}`;
|
|
8102
|
+
}
|
|
8057
8103
|
async listRecentFaces(input) {
|
|
8058
8104
|
const faces = await this.faceStore.listAllRecentFaces({
|
|
8059
8105
|
limit: input?.limit,
|
|
@@ -8061,11 +8107,12 @@ var FaceGalleryProvider = class {
|
|
|
8061
8107
|
});
|
|
8062
8108
|
const identities = await this.identityStore.listIdentities();
|
|
8063
8109
|
const nameMap = new Map(identities.map((i) => [i.id, i.name]));
|
|
8064
|
-
const
|
|
8065
|
-
|
|
8066
|
-
const base64 = await this.faceCropBase64(face);
|
|
8110
|
+
const includeCrops = input?.includeCrops ?? true;
|
|
8111
|
+
return mapWithConcurrency(faces, FACE_CROP_FETCH_CONCURRENCY, async (face) => {
|
|
8112
|
+
const base64 = includeCrops ? await this.faceCropBase64(face) : void 0;
|
|
8113
|
+
const cropUrl = this.cropUrlFor(face);
|
|
8067
8114
|
const identityName = face.recognizedIdentityId ? nameMap.get(face.recognizedIdentityId) : void 0;
|
|
8068
|
-
|
|
8115
|
+
return {
|
|
8069
8116
|
faceId: face.id,
|
|
8070
8117
|
deviceId: face.deviceId,
|
|
8071
8118
|
trackId: face.trackId,
|
|
@@ -8074,15 +8121,15 @@ var FaceGalleryProvider = class {
|
|
|
8074
8121
|
...identityName !== void 0 ? { identityName } : {},
|
|
8075
8122
|
assigned: face.assigned,
|
|
8076
8123
|
...base64 !== void 0 ? { base64 } : {},
|
|
8124
|
+
...cropUrl !== void 0 ? { cropUrl } : {},
|
|
8077
8125
|
...face.faceBbox !== void 0 ? { faceBbox: face.faceBbox } : {},
|
|
8078
8126
|
...face.keyFrameMediaKey !== void 0 ? { keyFrameMediaKey: face.keyFrameMediaKey } : {},
|
|
8079
8127
|
...face.bestMatchScore != null ? { bestMatchScore: face.bestMatchScore } : {},
|
|
8080
8128
|
...face.nativeFaceShortSidePx != null ? { nativeFaceShortSidePx: face.nativeFaceShortSidePx } : {},
|
|
8081
8129
|
...face.suggestedIdentityId != null ? { suggestedIdentityId: face.suggestedIdentityId } : {},
|
|
8082
8130
|
...face.suggestedMatchScore != null ? { suggestedMatchScore: face.suggestedMatchScore } : {}
|
|
8083
|
-
}
|
|
8084
|
-
}
|
|
8085
|
-
return result;
|
|
8131
|
+
};
|
|
8132
|
+
});
|
|
8086
8133
|
}
|
|
8087
8134
|
/**
|
|
8088
8135
|
* Get a face by deviceId + trackId. Returns null if not found or if
|
|
@@ -20110,6 +20157,21 @@ var PlateRecognizer = class {
|
|
|
20110
20157
|
}
|
|
20111
20158
|
};
|
|
20112
20159
|
//#endregion
|
|
20160
|
+
//#region src/pipeline-analytics/read-slice.ts
|
|
20161
|
+
/**
|
|
20162
|
+
* The loaded slice, or `undefined` when it has never loaded and the one
|
|
20163
|
+
* permitted refresh also failed to produce it.
|
|
20164
|
+
*
|
|
20165
|
+
* A failing refresh is swallowed deliberately: every caller degrades to "no
|
|
20166
|
+
* zones / no rules", and a zone read must never take down the frame that asked.
|
|
20167
|
+
*/
|
|
20168
|
+
async function readSliceOnce(handle) {
|
|
20169
|
+
const loaded = handle.value;
|
|
20170
|
+
if (loaded !== void 0) return loaded;
|
|
20171
|
+
await handle.refresh().catch(() => void 0);
|
|
20172
|
+
return handle.value;
|
|
20173
|
+
}
|
|
20174
|
+
//#endregion
|
|
20113
20175
|
//#region src/pipeline-analytics/rebuild-detail-request.ts
|
|
20114
20176
|
/** The one step a rebuild runs. */
|
|
20115
20177
|
var REBUILD_DETAIL_STEP_ID = "clip-embedding";
|
|
@@ -32302,6 +32364,7 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
32302
32364
|
eventStore: stores.eventStore,
|
|
32303
32365
|
logger: this.ctx.logger,
|
|
32304
32366
|
refreshGallery: () => this.faceRecognizer?.refreshGallery(),
|
|
32367
|
+
eventMediaBaseUrl: () => this.eventMediaBaseUrl,
|
|
32305
32368
|
emitFaceGalleryChanged: (payload) => this.emitFaceGalleryChanged(payload)
|
|
32306
32369
|
});
|
|
32307
32370
|
const plateGallery = new PlateGalleryProvider({
|
|
@@ -33313,10 +33376,7 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
33313
33376
|
async resolveDevicePackageRules(deviceId) {
|
|
33314
33377
|
const proxy = await this.ensureProxy(deviceId);
|
|
33315
33378
|
if (!proxy) return [];
|
|
33316
|
-
|
|
33317
|
-
if (cached && cached.length > 0) return cached;
|
|
33318
|
-
await proxy.state.zoneRules.refresh().catch(() => void 0);
|
|
33319
|
-
return proxy.state.zoneRules.value?.package ?? [];
|
|
33379
|
+
return (await readSliceOnce(proxy.state.zoneRules))?.package ?? [];
|
|
33320
33380
|
}
|
|
33321
33381
|
/**
|
|
33322
33382
|
* Route one track's `runDetailSubtree` results (two-plane detail dispatch)
|
|
@@ -34624,10 +34684,7 @@ var PipelineAnalyticsAddon = class extends BaseAddon {
|
|
|
34624
34684
|
async resolveDeviceZones(deviceId) {
|
|
34625
34685
|
const proxy = await this.ensureProxy(deviceId);
|
|
34626
34686
|
if (!proxy) return [];
|
|
34627
|
-
|
|
34628
|
-
if (cached && cached.length > 0) return cached;
|
|
34629
|
-
await proxy.state.zones.refresh().catch(() => void 0);
|
|
34630
|
-
return proxy.state.zones.value?.zones ?? [];
|
|
34687
|
+
return (await readSliceOnce(proxy.state.zones))?.zones ?? [];
|
|
34631
34688
|
}
|
|
34632
34689
|
releaseProxy(deviceId) {
|
|
34633
34690
|
const unsubs = this.proxyUnsubs.get(deviceId);
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-uW2bbQBi.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-post-analysis",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.54",
|
|
4
4
|
"description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|