@camstack/sdk 0.1.56 → 0.2.1
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/backend-router.d.ts +1 -1
- package/dist/camera.d.ts +4 -4
- package/dist/detection.d.ts +1 -1
- package/dist/devices.d.ts +6 -6
- package/dist/features.d.ts +3 -3
- package/dist/index.cjs +1788 -1857
- package/dist/index.d.ts +15 -15
- package/dist/index.js +1789 -1905
- package/dist/nvr.d.ts +8 -8
- package/dist/timeline.d.ts +4 -4
- package/dist/types.d.ts +2 -2
- package/package.json +10 -4
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,761 +1,641 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
2
|
+
let _trpc_client = require("@trpc/client");
|
|
3
|
+
let _camstack_types = require("@camstack/types");
|
|
4
|
+
//#region ../../node_modules/superjson/dist/double-indexed-kv.js
|
|
5
|
+
var DoubleIndexedKV = class {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.keyToValue = /* @__PURE__ */ new Map();
|
|
8
|
+
this.valueToKey = /* @__PURE__ */ new Map();
|
|
9
|
+
}
|
|
10
|
+
set(key, value) {
|
|
11
|
+
this.keyToValue.set(key, value);
|
|
12
|
+
this.valueToKey.set(value, key);
|
|
13
|
+
}
|
|
14
|
+
getByKey(key) {
|
|
15
|
+
return this.keyToValue.get(key);
|
|
16
|
+
}
|
|
17
|
+
getByValue(value) {
|
|
18
|
+
return this.valueToKey.get(value);
|
|
19
|
+
}
|
|
20
|
+
clear() {
|
|
21
|
+
this.keyToValue.clear();
|
|
22
|
+
this.valueToKey.clear();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region ../../node_modules/superjson/dist/registry.js
|
|
27
|
+
var Registry = class {
|
|
28
|
+
constructor(generateIdentifier) {
|
|
29
|
+
this.generateIdentifier = generateIdentifier;
|
|
30
|
+
this.kv = new DoubleIndexedKV();
|
|
31
|
+
}
|
|
32
|
+
register(value, identifier) {
|
|
33
|
+
if (this.kv.getByValue(value)) return;
|
|
34
|
+
if (!identifier) identifier = this.generateIdentifier(value);
|
|
35
|
+
this.kv.set(identifier, value);
|
|
36
|
+
}
|
|
37
|
+
clear() {
|
|
38
|
+
this.kv.clear();
|
|
39
|
+
}
|
|
40
|
+
getIdentifier(value) {
|
|
41
|
+
return this.kv.getByValue(value);
|
|
42
|
+
}
|
|
43
|
+
getValue(identifier) {
|
|
44
|
+
return this.kv.getByKey(identifier);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region ../../node_modules/superjson/dist/class-registry.js
|
|
49
|
+
var ClassRegistry = class extends Registry {
|
|
50
|
+
constructor() {
|
|
51
|
+
super((c) => c.name);
|
|
52
|
+
this.classToAllowedProps = /* @__PURE__ */ new Map();
|
|
53
|
+
}
|
|
54
|
+
register(value, options) {
|
|
55
|
+
if (typeof options === "object") {
|
|
56
|
+
if (options.allowProps) this.classToAllowedProps.set(value, options.allowProps);
|
|
57
|
+
super.register(value, options.identifier);
|
|
58
|
+
} else super.register(value, options);
|
|
59
|
+
}
|
|
60
|
+
getAllowedProps(value) {
|
|
61
|
+
return this.classToAllowedProps.get(value);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region ../../node_modules/superjson/dist/util.js
|
|
68
66
|
function valuesOfObj(record) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (const key in record) {
|
|
74
|
-
if (record.hasOwnProperty(key)) {
|
|
75
|
-
values.push(record[key]);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return values;
|
|
67
|
+
if ("values" in Object) return Object.values(record);
|
|
68
|
+
const values = [];
|
|
69
|
+
for (const key in record) if (record.hasOwnProperty(key)) values.push(record[key]);
|
|
70
|
+
return values;
|
|
79
71
|
}
|
|
80
72
|
function find(record, predicate) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (predicate(value)) {
|
|
89
|
-
return value;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return void 0;
|
|
73
|
+
const values = valuesOfObj(record);
|
|
74
|
+
if ("find" in values) return values.find(predicate);
|
|
75
|
+
const valuesNotNever = values;
|
|
76
|
+
for (let i = 0; i < valuesNotNever.length; i++) {
|
|
77
|
+
const value = valuesNotNever[i];
|
|
78
|
+
if (predicate(value)) return value;
|
|
79
|
+
}
|
|
93
80
|
}
|
|
94
81
|
function forEach(record, run) {
|
|
95
|
-
|
|
82
|
+
Object.entries(record).forEach(([key, value]) => run(value, key));
|
|
96
83
|
}
|
|
97
84
|
function includes(arr, value) {
|
|
98
|
-
|
|
85
|
+
return arr.indexOf(value) !== -1;
|
|
99
86
|
}
|
|
100
87
|
function findArr(record, predicate) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return void 0;
|
|
108
|
-
}
|
|
109
|
-
class CustomTransformerRegistry {
|
|
110
|
-
constructor() {
|
|
111
|
-
this.transfomers = {};
|
|
112
|
-
}
|
|
113
|
-
register(transformer) {
|
|
114
|
-
this.transfomers[transformer.name] = transformer;
|
|
115
|
-
}
|
|
116
|
-
findApplicable(v) {
|
|
117
|
-
return find(this.transfomers, (transformer) => transformer.isApplicable(v));
|
|
118
|
-
}
|
|
119
|
-
findByName(name) {
|
|
120
|
-
return this.transfomers[name];
|
|
121
|
-
}
|
|
88
|
+
for (let i = 0; i < record.length; i++) {
|
|
89
|
+
const value = record[i];
|
|
90
|
+
if (predicate(value)) return value;
|
|
91
|
+
}
|
|
122
92
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region ../../node_modules/superjson/dist/custom-transformer-registry.js
|
|
95
|
+
var CustomTransformerRegistry = class {
|
|
96
|
+
constructor() {
|
|
97
|
+
this.transfomers = {};
|
|
98
|
+
}
|
|
99
|
+
register(transformer) {
|
|
100
|
+
this.transfomers[transformer.name] = transformer;
|
|
101
|
+
}
|
|
102
|
+
findApplicable(v) {
|
|
103
|
+
return find(this.transfomers, (transformer) => transformer.isApplicable(v));
|
|
104
|
+
}
|
|
105
|
+
findByName(name) {
|
|
106
|
+
return this.transfomers[name];
|
|
107
|
+
}
|
|
134
108
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const isError = (payload) => payload instanceof Error;
|
|
146
|
-
const isNaNValue = (payload) => typeof payload === "number" && isNaN(payload);
|
|
147
|
-
const isPrimitive = (payload) => isBoolean(payload) || isNull(payload) || isUndefined(payload) || isNumber(payload) || isString(payload) || isSymbol(payload);
|
|
148
|
-
const isBigint = (payload) => typeof payload === "bigint";
|
|
149
|
-
const isInfinite = (payload) => payload === Infinity || payload === -Infinity;
|
|
150
|
-
const isTypedArray = (payload) => ArrayBuffer.isView(payload) && !(payload instanceof DataView);
|
|
151
|
-
const isURL = (payload) => payload instanceof URL;
|
|
152
|
-
const escapeKey = (key) => key.replace(/\\/g, "\\\\").replace(/\./g, "\\.");
|
|
153
|
-
const stringifyPath = (path) => path.map(String).map(escapeKey).join(".");
|
|
154
|
-
const parsePath = (string, legacyPaths) => {
|
|
155
|
-
const result = [];
|
|
156
|
-
let segment = "";
|
|
157
|
-
for (let i = 0; i < string.length; i++) {
|
|
158
|
-
let char = string.charAt(i);
|
|
159
|
-
if (!legacyPaths && char === "\\") {
|
|
160
|
-
const escaped = string.charAt(i + 1);
|
|
161
|
-
if (escaped === "\\") {
|
|
162
|
-
segment += "\\";
|
|
163
|
-
i++;
|
|
164
|
-
continue;
|
|
165
|
-
} else if (escaped !== ".") {
|
|
166
|
-
throw Error("invalid path");
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const isEscapedDot = char === "\\" && string.charAt(i + 1) === ".";
|
|
170
|
-
if (isEscapedDot) {
|
|
171
|
-
segment += ".";
|
|
172
|
-
i++;
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
const isEndOfSegment = char === ".";
|
|
176
|
-
if (isEndOfSegment) {
|
|
177
|
-
result.push(segment);
|
|
178
|
-
segment = "";
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
segment += char;
|
|
182
|
-
}
|
|
183
|
-
const lastSegment = segment;
|
|
184
|
-
result.push(lastSegment);
|
|
185
|
-
return result;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region ../../node_modules/superjson/dist/is.js
|
|
111
|
+
var getType$1 = (payload) => Object.prototype.toString.call(payload).slice(8, -1);
|
|
112
|
+
var isUndefined = (payload) => typeof payload === "undefined";
|
|
113
|
+
var isNull = (payload) => payload === null;
|
|
114
|
+
var isPlainObject$1 = (payload) => {
|
|
115
|
+
if (typeof payload !== "object" || payload === null) return false;
|
|
116
|
+
if (payload === Object.prototype) return false;
|
|
117
|
+
if (Object.getPrototypeOf(payload) === null) return true;
|
|
118
|
+
return Object.getPrototypeOf(payload) === Object.prototype;
|
|
186
119
|
};
|
|
120
|
+
var isEmptyObject = (payload) => isPlainObject$1(payload) && Object.keys(payload).length === 0;
|
|
121
|
+
var isArray$1 = (payload) => Array.isArray(payload);
|
|
122
|
+
var isString = (payload) => typeof payload === "string";
|
|
123
|
+
var isNumber = (payload) => typeof payload === "number" && !isNaN(payload);
|
|
124
|
+
var isBoolean = (payload) => typeof payload === "boolean";
|
|
125
|
+
var isRegExp = (payload) => payload instanceof RegExp;
|
|
126
|
+
var isMap = (payload) => payload instanceof Map;
|
|
127
|
+
var isSet = (payload) => payload instanceof Set;
|
|
128
|
+
var isSymbol = (payload) => getType$1(payload) === "Symbol";
|
|
129
|
+
var isDate = (payload) => payload instanceof Date && !isNaN(payload.valueOf());
|
|
130
|
+
var isError = (payload) => payload instanceof Error;
|
|
131
|
+
var isNaNValue = (payload) => typeof payload === "number" && isNaN(payload);
|
|
132
|
+
var isPrimitive = (payload) => isBoolean(payload) || isNull(payload) || isUndefined(payload) || isNumber(payload) || isString(payload) || isSymbol(payload);
|
|
133
|
+
var isBigint = (payload) => typeof payload === "bigint";
|
|
134
|
+
var isInfinite = (payload) => payload === Infinity || payload === -Infinity;
|
|
135
|
+
var isTypedArray = (payload) => ArrayBuffer.isView(payload) && !(payload instanceof DataView);
|
|
136
|
+
var isURL = (payload) => payload instanceof URL;
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region ../../node_modules/superjson/dist/pathstringifier.js
|
|
139
|
+
var escapeKey = (key) => key.replace(/\\/g, "\\\\").replace(/\./g, "\\.");
|
|
140
|
+
var stringifyPath = (path) => path.map(String).map(escapeKey).join(".");
|
|
141
|
+
var parsePath = (string, legacyPaths) => {
|
|
142
|
+
const result = [];
|
|
143
|
+
let segment = "";
|
|
144
|
+
for (let i = 0; i < string.length; i++) {
|
|
145
|
+
let char = string.charAt(i);
|
|
146
|
+
if (!legacyPaths && char === "\\") {
|
|
147
|
+
const escaped = string.charAt(i + 1);
|
|
148
|
+
if (escaped === "\\") {
|
|
149
|
+
segment += "\\";
|
|
150
|
+
i++;
|
|
151
|
+
continue;
|
|
152
|
+
} else if (escaped !== ".") throw Error("invalid path");
|
|
153
|
+
}
|
|
154
|
+
if (char === "\\" && string.charAt(i + 1) === ".") {
|
|
155
|
+
segment += ".";
|
|
156
|
+
i++;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (char === ".") {
|
|
160
|
+
result.push(segment);
|
|
161
|
+
segment = "";
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
segment += char;
|
|
165
|
+
}
|
|
166
|
+
const lastSegment = segment;
|
|
167
|
+
result.push(lastSegment);
|
|
168
|
+
return result;
|
|
169
|
+
};
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region ../../node_modules/superjson/dist/transformer.js
|
|
187
172
|
function simpleTransformation(isApplicable, annotation, transform, untransform) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
173
|
+
return {
|
|
174
|
+
isApplicable,
|
|
175
|
+
annotation,
|
|
176
|
+
transform,
|
|
177
|
+
untransform
|
|
178
|
+
};
|
|
194
179
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
),
|
|
239
|
-
simpleTransformation(isMap, "map", (v) => [...v.entries()], (v) => new Map(v)),
|
|
240
|
-
simpleTransformation((v) => isNaNValue(v) || isInfinite(v), "number", (v) => {
|
|
241
|
-
if (isNaNValue(v)) {
|
|
242
|
-
return "NaN";
|
|
243
|
-
}
|
|
244
|
-
if (v > 0) {
|
|
245
|
-
return "Infinity";
|
|
246
|
-
} else {
|
|
247
|
-
return "-Infinity";
|
|
248
|
-
}
|
|
249
|
-
}, Number),
|
|
250
|
-
simpleTransformation((v) => v === 0 && 1 / v === -Infinity, "number", () => {
|
|
251
|
-
return "-0";
|
|
252
|
-
}, Number),
|
|
253
|
-
simpleTransformation(isURL, "URL", (v) => v.toString(), (v) => new URL(v))
|
|
180
|
+
var simpleRules = [
|
|
181
|
+
simpleTransformation(isUndefined, "undefined", () => null, () => void 0),
|
|
182
|
+
simpleTransformation(isBigint, "bigint", (v) => v.toString(), (v) => {
|
|
183
|
+
if (typeof BigInt !== "undefined") return BigInt(v);
|
|
184
|
+
console.error("Please add a BigInt polyfill.");
|
|
185
|
+
return v;
|
|
186
|
+
}),
|
|
187
|
+
simpleTransformation(isDate, "Date", (v) => v.toISOString(), (v) => new Date(v)),
|
|
188
|
+
simpleTransformation(isError, "Error", (v, superJson) => {
|
|
189
|
+
const baseError = {
|
|
190
|
+
name: v.name,
|
|
191
|
+
message: v.message
|
|
192
|
+
};
|
|
193
|
+
if ("cause" in v) baseError.cause = v.cause;
|
|
194
|
+
superJson.allowedErrorProps.forEach((prop) => {
|
|
195
|
+
baseError[prop] = v[prop];
|
|
196
|
+
});
|
|
197
|
+
return baseError;
|
|
198
|
+
}, (v, superJson) => {
|
|
199
|
+
const e = new Error(v.message, { cause: v.cause });
|
|
200
|
+
e.name = v.name;
|
|
201
|
+
e.stack = v.stack;
|
|
202
|
+
superJson.allowedErrorProps.forEach((prop) => {
|
|
203
|
+
e[prop] = v[prop];
|
|
204
|
+
});
|
|
205
|
+
return e;
|
|
206
|
+
}),
|
|
207
|
+
simpleTransformation(isRegExp, "regexp", (v) => "" + v, (regex) => {
|
|
208
|
+
const body = regex.slice(1, regex.lastIndexOf("/"));
|
|
209
|
+
const flags = regex.slice(regex.lastIndexOf("/") + 1);
|
|
210
|
+
return new RegExp(body, flags);
|
|
211
|
+
}),
|
|
212
|
+
simpleTransformation(isSet, "set", (v) => [...v.values()], (v) => new Set(v)),
|
|
213
|
+
simpleTransformation(isMap, "map", (v) => [...v.entries()], (v) => new Map(v)),
|
|
214
|
+
simpleTransformation((v) => isNaNValue(v) || isInfinite(v), "number", (v) => {
|
|
215
|
+
if (isNaNValue(v)) return "NaN";
|
|
216
|
+
if (v > 0) return "Infinity";
|
|
217
|
+
else return "-Infinity";
|
|
218
|
+
}, Number),
|
|
219
|
+
simpleTransformation((v) => v === 0 && 1 / v === -Infinity, "number", () => {
|
|
220
|
+
return "-0";
|
|
221
|
+
}, Number),
|
|
222
|
+
simpleTransformation(isURL, "URL", (v) => v.toString(), (v) => new URL(v))
|
|
254
223
|
];
|
|
255
224
|
function compositeTransformation(isApplicable, annotation, transform, untransform) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
225
|
+
return {
|
|
226
|
+
isApplicable,
|
|
227
|
+
annotation,
|
|
228
|
+
transform,
|
|
229
|
+
untransform
|
|
230
|
+
};
|
|
262
231
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return isRegistered;
|
|
267
|
-
}
|
|
268
|
-
return false;
|
|
232
|
+
var symbolRule = compositeTransformation((s, superJson) => {
|
|
233
|
+
if (isSymbol(s)) return !!superJson.symbolRegistry.getIdentifier(s);
|
|
234
|
+
return false;
|
|
269
235
|
}, (s, superJson) => {
|
|
270
|
-
|
|
271
|
-
return ["symbol", identifier];
|
|
236
|
+
return ["symbol", superJson.symbolRegistry.getIdentifier(s)];
|
|
272
237
|
}, (v) => v.description, (_, a, superJson) => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
return value;
|
|
238
|
+
const value = superJson.symbolRegistry.getValue(a[1]);
|
|
239
|
+
if (!value) throw new Error("Trying to deserialize unknown symbol");
|
|
240
|
+
return value;
|
|
278
241
|
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
242
|
+
var constructorToName = [
|
|
243
|
+
Int8Array,
|
|
244
|
+
Uint8Array,
|
|
245
|
+
Int16Array,
|
|
246
|
+
Uint16Array,
|
|
247
|
+
Int32Array,
|
|
248
|
+
Uint32Array,
|
|
249
|
+
Float32Array,
|
|
250
|
+
Float64Array,
|
|
251
|
+
Uint8ClampedArray
|
|
289
252
|
].reduce((obj, ctor) => {
|
|
290
|
-
|
|
291
|
-
|
|
253
|
+
obj[ctor.name] = ctor;
|
|
254
|
+
return obj;
|
|
292
255
|
}, {});
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
return new ctor(v);
|
|
256
|
+
var typedArrayRule = compositeTransformation(isTypedArray, (v) => ["typed-array", v.constructor.name], (v) => [...v], (v, a) => {
|
|
257
|
+
const ctor = constructorToName[a[1]];
|
|
258
|
+
if (!ctor) throw new Error("Trying to deserialize unknown typed array");
|
|
259
|
+
return new ctor(v);
|
|
299
260
|
});
|
|
300
261
|
function isInstanceOfRegisteredClass(potentialClass, superJson) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
return isRegistered;
|
|
304
|
-
}
|
|
305
|
-
return false;
|
|
262
|
+
if (potentialClass?.constructor) return !!superJson.classRegistry.getIdentifier(potentialClass.constructor);
|
|
263
|
+
return false;
|
|
306
264
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return ["class", identifier];
|
|
265
|
+
var classRule = compositeTransformation(isInstanceOfRegisteredClass, (clazz, superJson) => {
|
|
266
|
+
return ["class", superJson.classRegistry.getIdentifier(clazz.constructor)];
|
|
310
267
|
}, (clazz, superJson) => {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
});
|
|
319
|
-
return result;
|
|
268
|
+
const allowedProps = superJson.classRegistry.getAllowedProps(clazz.constructor);
|
|
269
|
+
if (!allowedProps) return { ...clazz };
|
|
270
|
+
const result = {};
|
|
271
|
+
allowedProps.forEach((prop) => {
|
|
272
|
+
result[prop] = clazz[prop];
|
|
273
|
+
});
|
|
274
|
+
return result;
|
|
320
275
|
}, (v, a, superJson) => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
return Object.assign(Object.create(clazz.prototype), v);
|
|
276
|
+
const clazz = superJson.classRegistry.getValue(a[1]);
|
|
277
|
+
if (!clazz) throw new Error(`Trying to deserialize unknown class '${a[1]}' - check https://github.com/blitz-js/superjson/issues/116#issuecomment-773996564`);
|
|
278
|
+
return Object.assign(Object.create(clazz.prototype), v);
|
|
326
279
|
});
|
|
327
|
-
|
|
328
|
-
|
|
280
|
+
var customRule = compositeTransformation((value, superJson) => {
|
|
281
|
+
return !!superJson.customTransformerRegistry.findApplicable(value);
|
|
329
282
|
}, (value, superJson) => {
|
|
330
|
-
|
|
331
|
-
return ["custom", transformer.name];
|
|
283
|
+
return ["custom", superJson.customTransformerRegistry.findApplicable(value).name];
|
|
332
284
|
}, (value, superJson) => {
|
|
333
|
-
|
|
334
|
-
return transformer.serialize(value);
|
|
285
|
+
return superJson.customTransformerRegistry.findApplicable(value).serialize(value);
|
|
335
286
|
}, (v, a, superJson) => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
return transformer.deserialize(v);
|
|
287
|
+
const transformer = superJson.customTransformerRegistry.findByName(a[1]);
|
|
288
|
+
if (!transformer) throw new Error("Trying to deserialize unknown custom value");
|
|
289
|
+
return transformer.deserialize(v);
|
|
341
290
|
});
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
291
|
+
var compositeRules = [
|
|
292
|
+
classRule,
|
|
293
|
+
symbolRule,
|
|
294
|
+
customRule,
|
|
295
|
+
typedArrayRule
|
|
296
|
+
];
|
|
297
|
+
var transformValue = (value, superJson) => {
|
|
298
|
+
const applicableCompositeRule = findArr(compositeRules, (rule) => rule.isApplicable(value, superJson));
|
|
299
|
+
if (applicableCompositeRule) return {
|
|
300
|
+
value: applicableCompositeRule.transform(value, superJson),
|
|
301
|
+
type: applicableCompositeRule.annotation(value, superJson)
|
|
302
|
+
};
|
|
303
|
+
const applicableSimpleRule = findArr(simpleRules, (rule) => rule.isApplicable(value, superJson));
|
|
304
|
+
if (applicableSimpleRule) return {
|
|
305
|
+
value: applicableSimpleRule.transform(value, superJson),
|
|
306
|
+
type: applicableSimpleRule.annotation
|
|
307
|
+
};
|
|
359
308
|
};
|
|
360
|
-
|
|
309
|
+
var simpleRulesByAnnotation = {};
|
|
361
310
|
simpleRules.forEach((rule) => {
|
|
362
|
-
|
|
311
|
+
simpleRulesByAnnotation[rule.annotation] = rule;
|
|
363
312
|
});
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
} else {
|
|
379
|
-
const transformation = simpleRulesByAnnotation[type];
|
|
380
|
-
if (!transformation) {
|
|
381
|
-
throw new Error("Unknown transformation: " + type);
|
|
382
|
-
}
|
|
383
|
-
return transformation.untransform(json, superJson);
|
|
384
|
-
}
|
|
313
|
+
var untransformValue = (json, type, superJson) => {
|
|
314
|
+
if (isArray$1(type)) switch (type[0]) {
|
|
315
|
+
case "symbol": return symbolRule.untransform(json, type, superJson);
|
|
316
|
+
case "class": return classRule.untransform(json, type, superJson);
|
|
317
|
+
case "custom": return customRule.untransform(json, type, superJson);
|
|
318
|
+
case "typed-array": return typedArrayRule.untransform(json, type, superJson);
|
|
319
|
+
default: throw new Error("Unknown transformation: " + type);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
const transformation = simpleRulesByAnnotation[type];
|
|
323
|
+
if (!transformation) throw new Error("Unknown transformation: " + type);
|
|
324
|
+
return transformation.untransform(json, superJson);
|
|
325
|
+
}
|
|
385
326
|
};
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region ../../node_modules/superjson/dist/accessDeep.js
|
|
329
|
+
var getNthKey = (value, n) => {
|
|
330
|
+
if (n > value.size) throw new Error("index out of bounds");
|
|
331
|
+
const keys = value.keys();
|
|
332
|
+
while (n > 0) {
|
|
333
|
+
keys.next();
|
|
334
|
+
n--;
|
|
335
|
+
}
|
|
336
|
+
return keys.next().value;
|
|
395
337
|
};
|
|
396
338
|
function validatePath(path) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if (includes(path, "prototype")) {
|
|
401
|
-
throw new Error("prototype is not allowed as a property");
|
|
402
|
-
}
|
|
403
|
-
if (includes(path, "constructor")) {
|
|
404
|
-
throw new Error("constructor is not allowed as a property");
|
|
405
|
-
}
|
|
339
|
+
if (includes(path, "__proto__")) throw new Error("__proto__ is not allowed as a property");
|
|
340
|
+
if (includes(path, "prototype")) throw new Error("prototype is not allowed as a property");
|
|
341
|
+
if (includes(path, "constructor")) throw new Error("constructor is not allowed as a property");
|
|
406
342
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return object;
|
|
343
|
+
var getDeep = (object, path) => {
|
|
344
|
+
validatePath(path);
|
|
345
|
+
for (let i = 0; i < path.length; i++) {
|
|
346
|
+
const key = path[i];
|
|
347
|
+
if (isSet(object)) object = getNthKey(object, +key);
|
|
348
|
+
else if (isMap(object)) {
|
|
349
|
+
const row = +key;
|
|
350
|
+
const type = +path[++i] === 0 ? "key" : "value";
|
|
351
|
+
const keyOfRow = getNthKey(object, row);
|
|
352
|
+
switch (type) {
|
|
353
|
+
case "key":
|
|
354
|
+
object = keyOfRow;
|
|
355
|
+
break;
|
|
356
|
+
case "value":
|
|
357
|
+
object = object.get(keyOfRow);
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
} else object = object[key];
|
|
361
|
+
}
|
|
362
|
+
return object;
|
|
430
363
|
};
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
parent.set(newKey, parent.get(keyToRow));
|
|
487
|
-
if (newKey !== keyToRow) {
|
|
488
|
-
parent.delete(keyToRow);
|
|
489
|
-
}
|
|
490
|
-
break;
|
|
491
|
-
}
|
|
492
|
-
case "value": {
|
|
493
|
-
parent.set(keyToRow, mapper(parent.get(keyToRow)));
|
|
494
|
-
break;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
return object;
|
|
364
|
+
var setDeep = (object, path, mapper) => {
|
|
365
|
+
validatePath(path);
|
|
366
|
+
if (path.length === 0) return mapper(object);
|
|
367
|
+
let parent = object;
|
|
368
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
369
|
+
const key = path[i];
|
|
370
|
+
if (isArray$1(parent)) {
|
|
371
|
+
const index = +key;
|
|
372
|
+
parent = parent[index];
|
|
373
|
+
} else if (isPlainObject$1(parent)) parent = parent[key];
|
|
374
|
+
else if (isSet(parent)) {
|
|
375
|
+
const row = +key;
|
|
376
|
+
parent = getNthKey(parent, row);
|
|
377
|
+
} else if (isMap(parent)) {
|
|
378
|
+
if (i === path.length - 2) break;
|
|
379
|
+
const row = +key;
|
|
380
|
+
const type = +path[++i] === 0 ? "key" : "value";
|
|
381
|
+
const keyOfRow = getNthKey(parent, row);
|
|
382
|
+
switch (type) {
|
|
383
|
+
case "key":
|
|
384
|
+
parent = keyOfRow;
|
|
385
|
+
break;
|
|
386
|
+
case "value":
|
|
387
|
+
parent = parent.get(keyOfRow);
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const lastKey = path[path.length - 1];
|
|
393
|
+
if (isArray$1(parent)) parent[+lastKey] = mapper(parent[+lastKey]);
|
|
394
|
+
else if (isPlainObject$1(parent)) parent[lastKey] = mapper(parent[lastKey]);
|
|
395
|
+
if (isSet(parent)) {
|
|
396
|
+
const oldValue = getNthKey(parent, +lastKey);
|
|
397
|
+
const newValue = mapper(oldValue);
|
|
398
|
+
if (oldValue !== newValue) {
|
|
399
|
+
parent.delete(oldValue);
|
|
400
|
+
parent.add(newValue);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (isMap(parent)) {
|
|
404
|
+
const row = +path[path.length - 2];
|
|
405
|
+
const keyToRow = getNthKey(parent, row);
|
|
406
|
+
switch (+lastKey === 0 ? "key" : "value") {
|
|
407
|
+
case "key": {
|
|
408
|
+
const newKey = mapper(keyToRow);
|
|
409
|
+
parent.set(newKey, parent.get(keyToRow));
|
|
410
|
+
if (newKey !== keyToRow) parent.delete(keyToRow);
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
case "value":
|
|
414
|
+
parent.set(keyToRow, mapper(parent.get(keyToRow)));
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return object;
|
|
499
419
|
};
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
forEach(children, (child, key) => {
|
|
516
|
-
traverse(child, walker2, version, [
|
|
517
|
-
...origin,
|
|
518
|
-
...parsePath(key, legacyPaths)
|
|
519
|
-
]);
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
walker2(nodeValue, origin);
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region ../../node_modules/superjson/dist/plainer.js
|
|
422
|
+
var enableLegacyPaths = (version) => version < 1;
|
|
423
|
+
function traverse(tree, walker, version, origin = []) {
|
|
424
|
+
if (!tree) return;
|
|
425
|
+
const legacyPaths = enableLegacyPaths(version);
|
|
426
|
+
if (!isArray$1(tree)) {
|
|
427
|
+
forEach(tree, (subtree, key) => traverse(subtree, walker, version, [...origin, ...parsePath(key, legacyPaths)]));
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const [nodeValue, children] = tree;
|
|
431
|
+
if (children) forEach(children, (child, key) => {
|
|
432
|
+
traverse(child, walker, version, [...origin, ...parsePath(key, legacyPaths)]);
|
|
433
|
+
});
|
|
434
|
+
walker(nodeValue, origin);
|
|
523
435
|
}
|
|
524
436
|
function applyValueAnnotations(plain, annotations, version, superJson) {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
437
|
+
traverse(annotations, (type, path) => {
|
|
438
|
+
plain = setDeep(plain, path, (v) => untransformValue(v, type, superJson));
|
|
439
|
+
}, version);
|
|
440
|
+
return plain;
|
|
529
441
|
}
|
|
530
442
|
function applyReferentialEqualityAnnotations(plain, annotations, version) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
} else {
|
|
547
|
-
forEach(annotations, apply);
|
|
548
|
-
}
|
|
549
|
-
return plain;
|
|
443
|
+
const legacyPaths = enableLegacyPaths(version);
|
|
444
|
+
function apply(identicalPaths, path) {
|
|
445
|
+
const object = getDeep(plain, parsePath(path, legacyPaths));
|
|
446
|
+
identicalPaths.map((path) => parsePath(path, legacyPaths)).forEach((identicalObjectPath) => {
|
|
447
|
+
plain = setDeep(plain, identicalObjectPath, () => object);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
if (isArray$1(annotations)) {
|
|
451
|
+
const [root, other] = annotations;
|
|
452
|
+
root.forEach((identicalPath) => {
|
|
453
|
+
plain = setDeep(plain, parsePath(identicalPath, legacyPaths), () => plain);
|
|
454
|
+
});
|
|
455
|
+
if (other) forEach(other, apply);
|
|
456
|
+
} else forEach(annotations, apply);
|
|
457
|
+
return plain;
|
|
550
458
|
}
|
|
551
|
-
|
|
459
|
+
var isDeep = (object, superJson) => isPlainObject$1(object) || isArray$1(object) || isMap(object) || isSet(object) || isError(object) || isInstanceOfRegisteredClass(object, superJson);
|
|
552
460
|
function addIdentity(object, path, identities) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
} else {
|
|
557
|
-
identities.set(object, [path]);
|
|
558
|
-
}
|
|
461
|
+
const existingSet = identities.get(object);
|
|
462
|
+
if (existingSet) existingSet.push(path);
|
|
463
|
+
else identities.set(object, [path]);
|
|
559
464
|
}
|
|
560
465
|
function generateReferentialEqualityAnnotations(identitites, dedupe) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
} else {
|
|
574
|
-
result[stringifyPath(representativePath)] = identicalPaths.map(stringifyPath);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
if (rootEqualityPaths) {
|
|
578
|
-
if (isEmptyObject(result)) {
|
|
579
|
-
return [rootEqualityPaths];
|
|
580
|
-
} else {
|
|
581
|
-
return [rootEqualityPaths, result];
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
return isEmptyObject(result) ? void 0 : result;
|
|
585
|
-
}
|
|
466
|
+
const result = {};
|
|
467
|
+
let rootEqualityPaths = void 0;
|
|
468
|
+
identitites.forEach((paths) => {
|
|
469
|
+
if (paths.length <= 1) return;
|
|
470
|
+
if (!dedupe) paths = paths.map((path) => path.map(String)).sort((a, b) => a.length - b.length);
|
|
471
|
+
const [representativePath, ...identicalPaths] = paths;
|
|
472
|
+
if (representativePath.length === 0) rootEqualityPaths = identicalPaths.map(stringifyPath);
|
|
473
|
+
else result[stringifyPath(representativePath)] = identicalPaths.map(stringifyPath);
|
|
474
|
+
});
|
|
475
|
+
if (rootEqualityPaths) if (isEmptyObject(result)) return [rootEqualityPaths];
|
|
476
|
+
else return [rootEqualityPaths, result];
|
|
477
|
+
else return isEmptyObject(result) ? void 0 : result;
|
|
586
478
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (isArray$1(recursiveResult.annotations)) {
|
|
627
|
-
innerAnnotations[escapeKey(index)] = recursiveResult.annotations;
|
|
628
|
-
} else if (isPlainObject$1(recursiveResult.annotations)) {
|
|
629
|
-
forEach(recursiveResult.annotations, (tree, key) => {
|
|
630
|
-
innerAnnotations[escapeKey(index) + "." + key] = tree;
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
});
|
|
634
|
-
const result = isEmptyObject(innerAnnotations) ? {
|
|
635
|
-
transformedValue,
|
|
636
|
-
annotations: !!transformationResult ? [transformationResult.type] : void 0
|
|
637
|
-
} : {
|
|
638
|
-
transformedValue,
|
|
639
|
-
annotations: !!transformationResult ? [transformationResult.type, innerAnnotations] : innerAnnotations
|
|
640
|
-
};
|
|
641
|
-
if (!primitive) {
|
|
642
|
-
seenObjects.set(object, result);
|
|
643
|
-
}
|
|
644
|
-
return result;
|
|
479
|
+
var walker = (object, identities, superJson, dedupe, path = [], objectsInThisPath = [], seenObjects = /* @__PURE__ */ new Map()) => {
|
|
480
|
+
const primitive = isPrimitive(object);
|
|
481
|
+
if (!primitive) {
|
|
482
|
+
addIdentity(object, path, identities);
|
|
483
|
+
const seen = seenObjects.get(object);
|
|
484
|
+
if (seen) return dedupe ? { transformedValue: null } : seen;
|
|
485
|
+
}
|
|
486
|
+
if (!isDeep(object, superJson)) {
|
|
487
|
+
const transformed = transformValue(object, superJson);
|
|
488
|
+
const result = transformed ? {
|
|
489
|
+
transformedValue: transformed.value,
|
|
490
|
+
annotations: [transformed.type]
|
|
491
|
+
} : { transformedValue: object };
|
|
492
|
+
if (!primitive) seenObjects.set(object, result);
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
if (includes(objectsInThisPath, object)) return { transformedValue: null };
|
|
496
|
+
const transformationResult = transformValue(object, superJson);
|
|
497
|
+
const transformed = transformationResult?.value ?? object;
|
|
498
|
+
const transformedValue = isArray$1(transformed) ? [] : {};
|
|
499
|
+
const innerAnnotations = {};
|
|
500
|
+
forEach(transformed, (value, index) => {
|
|
501
|
+
if (index === "__proto__" || index === "constructor" || index === "prototype") throw new Error(`Detected property ${index}. This is a prototype pollution risk, please remove it from your object.`);
|
|
502
|
+
const recursiveResult = walker(value, identities, superJson, dedupe, [...path, index], [...objectsInThisPath, object], seenObjects);
|
|
503
|
+
transformedValue[index] = recursiveResult.transformedValue;
|
|
504
|
+
if (isArray$1(recursiveResult.annotations)) innerAnnotations[escapeKey(index)] = recursiveResult.annotations;
|
|
505
|
+
else if (isPlainObject$1(recursiveResult.annotations)) forEach(recursiveResult.annotations, (tree, key) => {
|
|
506
|
+
innerAnnotations[escapeKey(index) + "." + key] = tree;
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
const result = isEmptyObject(innerAnnotations) ? {
|
|
510
|
+
transformedValue,
|
|
511
|
+
annotations: !!transformationResult ? [transformationResult.type] : void 0
|
|
512
|
+
} : {
|
|
513
|
+
transformedValue,
|
|
514
|
+
annotations: !!transformationResult ? [transformationResult.type, innerAnnotations] : innerAnnotations
|
|
515
|
+
};
|
|
516
|
+
if (!primitive) seenObjects.set(object, result);
|
|
517
|
+
return result;
|
|
645
518
|
};
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region ../../node_modules/is-what/dist/getType.js
|
|
521
|
+
/** Returns the object type of the given payload */
|
|
646
522
|
function getType(payload) {
|
|
647
|
-
|
|
523
|
+
return Object.prototype.toString.call(payload).slice(8, -1);
|
|
648
524
|
}
|
|
525
|
+
//#endregion
|
|
526
|
+
//#region ../../node_modules/is-what/dist/isArray.js
|
|
527
|
+
/** Returns whether the payload is an array */
|
|
649
528
|
function isArray(payload) {
|
|
650
|
-
|
|
529
|
+
return getType(payload) === "Array";
|
|
651
530
|
}
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region ../../node_modules/is-what/dist/isPlainObject.js
|
|
533
|
+
/**
|
|
534
|
+
* Returns whether the payload is a plain JavaScript object (excluding special classes or objects
|
|
535
|
+
* with other prototypes)
|
|
536
|
+
*/
|
|
652
537
|
function isPlainObject(payload) {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
return !!prototype && prototype.constructor === Object && prototype === Object.prototype;
|
|
538
|
+
if (getType(payload) !== "Object") return false;
|
|
539
|
+
const prototype = Object.getPrototypeOf(payload);
|
|
540
|
+
return !!prototype && prototype.constructor === Object && prototype === Object.prototype;
|
|
657
541
|
}
|
|
542
|
+
//#endregion
|
|
543
|
+
//#region ../../node_modules/copy-anything/dist/index.js
|
|
658
544
|
function assignProp(carry, key, newVal, originalObject, includeNonenumerable) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
configurable: true
|
|
668
|
-
});
|
|
669
|
-
}
|
|
545
|
+
const propType = {}.propertyIsEnumerable.call(originalObject, key) ? "enumerable" : "nonenumerable";
|
|
546
|
+
if (propType === "enumerable") carry[key] = newVal;
|
|
547
|
+
if (includeNonenumerable && propType === "nonenumerable") Object.defineProperty(carry, key, {
|
|
548
|
+
value: newVal,
|
|
549
|
+
enumerable: false,
|
|
550
|
+
writable: true,
|
|
551
|
+
configurable: true
|
|
552
|
+
});
|
|
670
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* Copy (clone) an object and all its props recursively to get rid of any prop referenced of the
|
|
556
|
+
* original object. Arrays are also cloned, however objects inside arrays are still linked.
|
|
557
|
+
*
|
|
558
|
+
* @param target Target can be anything
|
|
559
|
+
* @param [options={}] See type {@link Options} for more details.
|
|
560
|
+
*
|
|
561
|
+
* - `{ props: ['key1'] }` will only copy the `key1` property. When using this you will need to cast
|
|
562
|
+
* the return type manually (in order to keep the TS implementation in here simple I didn't
|
|
563
|
+
* built a complex auto resolved type for those few cases people want to use this option)
|
|
564
|
+
* - `{ nonenumerable: true }` will copy all non-enumerable properties. Default is `{}`
|
|
565
|
+
*
|
|
566
|
+
* @returns The target with replaced values
|
|
567
|
+
*/
|
|
671
568
|
function copy(target, options = {}) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
if (isArray(options.props) && !options.props.includes(key)) {
|
|
684
|
-
return carry;
|
|
685
|
-
}
|
|
686
|
-
const val = target[key];
|
|
687
|
-
const newVal = copy(val, options);
|
|
688
|
-
assignProp(carry, key, newVal, target, options.nonenumerable);
|
|
689
|
-
return carry;
|
|
690
|
-
}, {});
|
|
691
|
-
}
|
|
692
|
-
class SuperJSON {
|
|
693
|
-
/**
|
|
694
|
-
* @param dedupeReferentialEqualities If true, SuperJSON will make sure only one instance of referentially equal objects are serialized and the rest are replaced with `null`.
|
|
695
|
-
*/
|
|
696
|
-
constructor({ dedupe = false } = {}) {
|
|
697
|
-
this.classRegistry = new ClassRegistry();
|
|
698
|
-
this.symbolRegistry = new Registry((s) => s.description ?? "");
|
|
699
|
-
this.customTransformerRegistry = new CustomTransformerRegistry();
|
|
700
|
-
this.allowedErrorProps = [];
|
|
701
|
-
this.dedupe = dedupe;
|
|
702
|
-
}
|
|
703
|
-
serialize(object) {
|
|
704
|
-
const identities = /* @__PURE__ */ new Map();
|
|
705
|
-
const output = walker(object, identities, this, this.dedupe);
|
|
706
|
-
const res = {
|
|
707
|
-
json: output.transformedValue
|
|
708
|
-
};
|
|
709
|
-
if (output.annotations) {
|
|
710
|
-
res.meta = {
|
|
711
|
-
...res.meta,
|
|
712
|
-
values: output.annotations
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
const equalityAnnotations = generateReferentialEqualityAnnotations(identities, this.dedupe);
|
|
716
|
-
if (equalityAnnotations) {
|
|
717
|
-
res.meta = {
|
|
718
|
-
...res.meta,
|
|
719
|
-
referentialEqualities: equalityAnnotations
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
if (res.meta)
|
|
723
|
-
res.meta.v = 1;
|
|
724
|
-
return res;
|
|
725
|
-
}
|
|
726
|
-
deserialize(payload, options) {
|
|
727
|
-
const { json, meta } = payload;
|
|
728
|
-
let result = options?.inPlace ? json : copy(json);
|
|
729
|
-
if (meta?.values) {
|
|
730
|
-
result = applyValueAnnotations(result, meta.values, meta.v ?? 0, this);
|
|
731
|
-
}
|
|
732
|
-
if (meta?.referentialEqualities) {
|
|
733
|
-
result = applyReferentialEqualityAnnotations(result, meta.referentialEqualities, meta.v ?? 0);
|
|
734
|
-
}
|
|
735
|
-
return result;
|
|
736
|
-
}
|
|
737
|
-
stringify(object) {
|
|
738
|
-
return JSON.stringify(this.serialize(object));
|
|
739
|
-
}
|
|
740
|
-
parse(string) {
|
|
741
|
-
return this.deserialize(JSON.parse(string), { inPlace: true });
|
|
742
|
-
}
|
|
743
|
-
registerClass(v, options) {
|
|
744
|
-
this.classRegistry.register(v, options);
|
|
745
|
-
}
|
|
746
|
-
registerSymbol(v, identifier) {
|
|
747
|
-
this.symbolRegistry.register(v, identifier);
|
|
748
|
-
}
|
|
749
|
-
registerCustom(transformer, name) {
|
|
750
|
-
this.customTransformerRegistry.register({
|
|
751
|
-
name,
|
|
752
|
-
...transformer
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
allowErrorProps(...props) {
|
|
756
|
-
this.allowedErrorProps.push(...props);
|
|
757
|
-
}
|
|
569
|
+
if (isArray(target)) return target.map((item) => copy(item, options));
|
|
570
|
+
if (!isPlainObject(target)) return target;
|
|
571
|
+
const props = Object.getOwnPropertyNames(target);
|
|
572
|
+
const symbols = Object.getOwnPropertySymbols(target);
|
|
573
|
+
return [...props, ...symbols].reduce((carry, key) => {
|
|
574
|
+
if (key === "__proto__") return carry;
|
|
575
|
+
if (isArray(options.props) && !options.props.includes(key)) return carry;
|
|
576
|
+
const val = target[key];
|
|
577
|
+
assignProp(carry, key, copy(val, options), target, options.nonenumerable);
|
|
578
|
+
return carry;
|
|
579
|
+
}, {});
|
|
758
580
|
}
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region ../../node_modules/superjson/dist/index.js
|
|
583
|
+
var SuperJSON = class {
|
|
584
|
+
/**
|
|
585
|
+
* @param dedupeReferentialEqualities If true, SuperJSON will make sure only one instance of referentially equal objects are serialized and the rest are replaced with `null`.
|
|
586
|
+
*/
|
|
587
|
+
constructor({ dedupe = false } = {}) {
|
|
588
|
+
this.classRegistry = new ClassRegistry();
|
|
589
|
+
this.symbolRegistry = new Registry((s) => s.description ?? "");
|
|
590
|
+
this.customTransformerRegistry = new CustomTransformerRegistry();
|
|
591
|
+
this.allowedErrorProps = [];
|
|
592
|
+
this.dedupe = dedupe;
|
|
593
|
+
}
|
|
594
|
+
serialize(object) {
|
|
595
|
+
const identities = /* @__PURE__ */ new Map();
|
|
596
|
+
const output = walker(object, identities, this, this.dedupe);
|
|
597
|
+
const res = { json: output.transformedValue };
|
|
598
|
+
if (output.annotations) res.meta = {
|
|
599
|
+
...res.meta,
|
|
600
|
+
values: output.annotations
|
|
601
|
+
};
|
|
602
|
+
const equalityAnnotations = generateReferentialEqualityAnnotations(identities, this.dedupe);
|
|
603
|
+
if (equalityAnnotations) res.meta = {
|
|
604
|
+
...res.meta,
|
|
605
|
+
referentialEqualities: equalityAnnotations
|
|
606
|
+
};
|
|
607
|
+
if (res.meta) res.meta.v = 1;
|
|
608
|
+
return res;
|
|
609
|
+
}
|
|
610
|
+
deserialize(payload, options) {
|
|
611
|
+
const { json, meta } = payload;
|
|
612
|
+
let result = options?.inPlace ? json : copy(json);
|
|
613
|
+
if (meta?.values) result = applyValueAnnotations(result, meta.values, meta.v ?? 0, this);
|
|
614
|
+
if (meta?.referentialEqualities) result = applyReferentialEqualityAnnotations(result, meta.referentialEqualities, meta.v ?? 0);
|
|
615
|
+
return result;
|
|
616
|
+
}
|
|
617
|
+
stringify(object) {
|
|
618
|
+
return JSON.stringify(this.serialize(object));
|
|
619
|
+
}
|
|
620
|
+
parse(string) {
|
|
621
|
+
return this.deserialize(JSON.parse(string), { inPlace: true });
|
|
622
|
+
}
|
|
623
|
+
registerClass(v, options) {
|
|
624
|
+
this.classRegistry.register(v, options);
|
|
625
|
+
}
|
|
626
|
+
registerSymbol(v, identifier) {
|
|
627
|
+
this.symbolRegistry.register(v, identifier);
|
|
628
|
+
}
|
|
629
|
+
registerCustom(transformer, name) {
|
|
630
|
+
this.customTransformerRegistry.register({
|
|
631
|
+
name,
|
|
632
|
+
...transformer
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
allowErrorProps(...props) {
|
|
636
|
+
this.allowedErrorProps.push(...props);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
759
639
|
SuperJSON.defaultInstance = new SuperJSON();
|
|
760
640
|
SuperJSON.serialize = SuperJSON.defaultInstance.serialize.bind(SuperJSON.defaultInstance);
|
|
761
641
|
SuperJSON.deserialize = SuperJSON.defaultInstance.deserialize.bind(SuperJSON.defaultInstance);
|
|
@@ -773,1198 +653,1250 @@ SuperJSON.registerClass;
|
|
|
773
653
|
SuperJSON.registerCustom;
|
|
774
654
|
SuperJSON.registerSymbol;
|
|
775
655
|
SuperJSON.allowErrorProps;
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
const headers = () => {
|
|
1334
|
-
const h = {};
|
|
1335
|
-
if (this.token) h["Authorization"] = `Bearer ${this.token}`;
|
|
1336
|
-
return h;
|
|
1337
|
-
};
|
|
1338
|
-
if (this.useWs) {
|
|
1339
|
-
const wsUrl = this._serverUrl.replace(/^http/, "ws") + "/trpc";
|
|
1340
|
-
const baseRetryMs = this.baseRetryMs;
|
|
1341
|
-
const maxRetryMs = this.maxRetryMs;
|
|
1342
|
-
this._wsClient = client.createWSClient({
|
|
1343
|
-
url: wsUrl,
|
|
1344
|
-
connectionParams: () => ({ token: this.token }),
|
|
1345
|
-
retryDelayMs: (attemptIndex) => Math.min(baseRetryMs * Math.pow(2, attemptIndex), maxRetryMs),
|
|
1346
|
-
keepAlive: {
|
|
1347
|
-
enabled: true,
|
|
1348
|
-
intervalMs: WS_KEEP_ALIVE_INTERVAL_MS,
|
|
1349
|
-
pongTimeoutMs: WS_KEEP_ALIVE_PONG_TIMEOUT_MS
|
|
1350
|
-
},
|
|
1351
|
-
onOpen: () => {
|
|
1352
|
-
this._connectionVersion += 1;
|
|
1353
|
-
this.emitConnectionEvent("connected");
|
|
1354
|
-
},
|
|
1355
|
-
onClose: () => {
|
|
1356
|
-
this.emitConnectionEvent("disconnected");
|
|
1357
|
-
}
|
|
1358
|
-
});
|
|
1359
|
-
return client.createTRPCClient({
|
|
1360
|
-
links: [client.wsLink({ client: this._wsClient, transformer: SuperJSON })]
|
|
1361
|
-
});
|
|
1362
|
-
}
|
|
1363
|
-
this._wsClient = null;
|
|
1364
|
-
return client.createTRPCClient({
|
|
1365
|
-
links: [client.httpLink({ url: `${this._serverUrl}/trpc`, headers, transformer: SuperJSON })]
|
|
1366
|
-
});
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
656
|
+
//#endregion
|
|
657
|
+
//#region src/system.ts
|
|
658
|
+
/**
|
|
659
|
+
* System — single, unified entry point for the camstack client API.
|
|
660
|
+
*
|
|
661
|
+
* Devices are returned as typed `DeviceProxy` objects (auto-injecting
|
|
662
|
+
* `deviceId` + `nodeId`), system caps are exposed as typed namespaces
|
|
663
|
+
* (`system.userManagement`, `system.storage`, etc.), and live events
|
|
664
|
+
* flow through a single `subscribeEvent` helper.
|
|
665
|
+
*
|
|
666
|
+
* The escape hatches (`trpcClient`, `wsClient`) are still public so the
|
|
667
|
+
* ui-library Provider can seed React Query with the same WS connection
|
|
668
|
+
* — a future phase will narrow the surface further.
|
|
669
|
+
*/
|
|
670
|
+
var WS_KEEP_ALIVE_INTERVAL_MS = 1e4;
|
|
671
|
+
var WS_KEEP_ALIVE_PONG_TIMEOUT_MS = 6e3;
|
|
672
|
+
var WS_RECONNECT_RETRY_DELAY_MS = 2e3;
|
|
673
|
+
var WS_RECONNECT_MAX_RETRY_DELAY_MS = 3e4;
|
|
674
|
+
var System = class {
|
|
675
|
+
/** Active server base URL. Mutable via `switchServerUrl()` so the
|
|
676
|
+
* endpoint-race helper can pivot the transport onto a LAN candidate
|
|
677
|
+
* after the initial public-URL bootstrap. */
|
|
678
|
+
_serverUrl;
|
|
679
|
+
useWs;
|
|
680
|
+
baseRetryMs;
|
|
681
|
+
maxRetryMs;
|
|
682
|
+
onConnectionChange;
|
|
683
|
+
token;
|
|
684
|
+
_trpcClient;
|
|
685
|
+
_wsClient = null;
|
|
686
|
+
mirror = null;
|
|
687
|
+
mirrorInit = null;
|
|
688
|
+
connected = false;
|
|
689
|
+
connectedPromise = null;
|
|
690
|
+
_systemProxy;
|
|
691
|
+
_connectionVersion = 0;
|
|
692
|
+
connectionListeners = /* @__PURE__ */ new Set();
|
|
693
|
+
constructor(config) {
|
|
694
|
+
this._serverUrl = config.serverUrl.replace(/\/+$/, "");
|
|
695
|
+
this.token = config.token;
|
|
696
|
+
const isBrowser = typeof window !== "undefined";
|
|
697
|
+
this.useWs = config.useWebSocket ?? isBrowser;
|
|
698
|
+
this.onConnectionChange = config.onConnectionChange;
|
|
699
|
+
this.baseRetryMs = config.retryDelayMs ?? WS_RECONNECT_RETRY_DELAY_MS;
|
|
700
|
+
this.maxRetryMs = config.maxRetryDelayMs ?? WS_RECONNECT_MAX_RETRY_DELAY_MS;
|
|
701
|
+
this._trpcClient = this.buildTrpcClient();
|
|
702
|
+
this._systemProxy = (0, _camstack_types.createSystemProxy)(this._trpcClient);
|
|
703
|
+
}
|
|
704
|
+
/** Active server base URL (no trailing slash). */
|
|
705
|
+
get serverUrl() {
|
|
706
|
+
return this._serverUrl;
|
|
707
|
+
}
|
|
708
|
+
get connectionVersion() {
|
|
709
|
+
return this._connectionVersion;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Subscribe to connection-state transitions. Called with `('connected'
|
|
713
|
+
* | 'disconnected' | 'connecting', version)` whenever the SDK opens,
|
|
714
|
+
* closes, or starts a manual reconnect. Listener errors are swallowed
|
|
715
|
+
* so a misbehaving consumer cannot break the SDK's event loop.
|
|
716
|
+
*/
|
|
717
|
+
subscribeConnectionEvents(cb) {
|
|
718
|
+
this.connectionListeners.add(cb);
|
|
719
|
+
return () => {
|
|
720
|
+
this.connectionListeners.delete(cb);
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
emitConnectionEvent(state) {
|
|
724
|
+
try {
|
|
725
|
+
this.onConnectionChange?.(state);
|
|
726
|
+
} catch {}
|
|
727
|
+
for (const l of this.connectionListeners) try {
|
|
728
|
+
l(state, this._connectionVersion);
|
|
729
|
+
} catch {}
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Wait until the underlying tRPC transport is connected AND the
|
|
733
|
+
* server has responded to a cheap auth round-trip (`auth.me`). This
|
|
734
|
+
* is the canonical "ready to issue queries" gate.
|
|
735
|
+
*
|
|
736
|
+
* Why a probe, not just `ws.readyState === OPEN`?
|
|
737
|
+
* The WS handshake completes asynchronously: tRPC's `wsLink`
|
|
738
|
+
* queues outgoing messages and only flushes them after `open()`
|
|
739
|
+
* resolves (post `connectionParams` send). On the server, the
|
|
740
|
+
* tRPC context is created lazily once the connectionParams
|
|
741
|
+
* message is received. A query fired between WS-open and
|
|
742
|
+
* connection-params-processed is technically queued by tRPC, but
|
|
743
|
+
* the auth context for that query is only resolved once the
|
|
744
|
+
* handshake message is decoded server-side. A probe round-trip is
|
|
745
|
+
* the safest way to confirm both sides have agreed on the auth
|
|
746
|
+
* identity before the React tree starts firing parallel queries
|
|
747
|
+
* (which can otherwise land before any addon-side service
|
|
748
|
+
* discovery has settled, returning empty results that get cached).
|
|
749
|
+
*
|
|
750
|
+
* Idempotent — concurrent callers await the same in-flight Promise.
|
|
751
|
+
* Bounded by `timeoutMs` (default 15s) — beyond which a
|
|
752
|
+
* `Error('System.awaitConnected: probe timed out after Xms')` is
|
|
753
|
+
* thrown so the host can render a clear error state instead of
|
|
754
|
+
* hanging on a bricked socket.
|
|
755
|
+
*/
|
|
756
|
+
async awaitConnected(timeoutMs) {
|
|
757
|
+
if (this.connected) return;
|
|
758
|
+
if (this.connectedPromise) return this.connectedPromise;
|
|
759
|
+
const effectiveTimeoutMs = timeoutMs ?? 15e3;
|
|
760
|
+
this.connectedPromise = (async () => {
|
|
761
|
+
const probe = this._trpcClient.auth.me.query();
|
|
762
|
+
if (!Number.isFinite(effectiveTimeoutMs)) await probe;
|
|
763
|
+
else await new Promise((resolve, reject) => {
|
|
764
|
+
const timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`System.awaitConnected: probe timed out after ${effectiveTimeoutMs}ms`)), effectiveTimeoutMs);
|
|
765
|
+
probe.then(() => {
|
|
766
|
+
clearTimeout(timer);
|
|
767
|
+
resolve();
|
|
768
|
+
}, (err) => {
|
|
769
|
+
clearTimeout(timer);
|
|
770
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
this.connected = true;
|
|
774
|
+
})();
|
|
775
|
+
try {
|
|
776
|
+
await this.connectedPromise;
|
|
777
|
+
} finally {
|
|
778
|
+
this.connectedPromise = null;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Warm-boot the device mirror. Awaits the transport probe first
|
|
783
|
+
* (`awaitConnected`) so the three mirror round-trips
|
|
784
|
+
* (`getAllBindings` + `getAllSnapshots` + `listAll`) cannot race
|
|
785
|
+
* against the WS auth handshake. Subsequent `getDevice(id)` calls
|
|
786
|
+
* are sync; live `device.*` event subscriptions keep the caches
|
|
787
|
+
* fresh.
|
|
788
|
+
*
|
|
789
|
+
* Idempotent — concurrent callers await the same in-flight Promise.
|
|
790
|
+
*/
|
|
791
|
+
async init(timeoutMs) {
|
|
792
|
+
if (this.mirror?.isReady()) return;
|
|
793
|
+
if (this.mirrorInit) return this.mirrorInit;
|
|
794
|
+
const m = new _camstack_types.SystemMirror(this._trpcClient);
|
|
795
|
+
this.mirror = m;
|
|
796
|
+
this.mirrorInit = (async () => {
|
|
797
|
+
await this.awaitConnected(timeoutMs);
|
|
798
|
+
await m.init(timeoutMs);
|
|
799
|
+
})().finally(() => {
|
|
800
|
+
this.mirrorInit = null;
|
|
801
|
+
});
|
|
802
|
+
return this.mirrorInit;
|
|
803
|
+
}
|
|
804
|
+
/** Promise that resolves once `init()` has completed. */
|
|
805
|
+
async awaitReady() {
|
|
806
|
+
if (this.mirror?.isReady()) return;
|
|
807
|
+
if (this.mirrorInit) return this.mirrorInit;
|
|
808
|
+
return this.init();
|
|
809
|
+
}
|
|
810
|
+
/** True after `init()` resolves. */
|
|
811
|
+
isReady() {
|
|
812
|
+
return this.mirror?.isReady() ?? false;
|
|
813
|
+
}
|
|
814
|
+
/** True after the transport probe has succeeded at least once. */
|
|
815
|
+
isConnected() {
|
|
816
|
+
return this.connected;
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Force a fresh WebSocket handshake. Tears down the wsClient + tRPC
|
|
820
|
+
* client + mirror (the mirror captures the tRPC reference at
|
|
821
|
+
* construction time and would otherwise dispatch through a closed
|
|
822
|
+
* client) and rebuilds them. No-op for HTTP transport.
|
|
823
|
+
*/
|
|
824
|
+
reconnect() {
|
|
825
|
+
if (!this.useWs) return;
|
|
826
|
+
this.emitConnectionEvent("connecting");
|
|
827
|
+
this._wsClient?.close();
|
|
828
|
+
this.disposeMirror();
|
|
829
|
+
this.connected = false;
|
|
830
|
+
this.connectedPromise = null;
|
|
831
|
+
this._trpcClient = this.buildTrpcClient();
|
|
832
|
+
this._systemProxy = (0, _camstack_types.createSystemProxy)(this._trpcClient);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Pivot the underlying tRPC transport onto a different base URL.
|
|
836
|
+
* Used by the endpoint-race flow: the SDK opens against the public
|
|
837
|
+
* URL the operator provided, calls `localNetwork.getConnectionEndpoints`
|
|
838
|
+
* to discover LAN candidates, races them, and (when a faster one wins)
|
|
839
|
+
* calls `switchServerUrl(winner)` to migrate every subsequent query
|
|
840
|
+
* onto the LAN path without losing auth state.
|
|
841
|
+
*
|
|
842
|
+
* Keeps the auth token. Tears down the WS + mirror and rebuilds them
|
|
843
|
+
* against the new URL — same machinery as `reconnect()` but with a
|
|
844
|
+
* different target.
|
|
845
|
+
*/
|
|
846
|
+
switchServerUrl(nextUrl) {
|
|
847
|
+
const normalized = nextUrl.replace(/\/+$/, "");
|
|
848
|
+
if (normalized === this._serverUrl) return;
|
|
849
|
+
this._serverUrl = normalized;
|
|
850
|
+
this.reconnect();
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Race the candidate base URLs reported by the hub's `local-network`
|
|
854
|
+
* cap, pick the fastest one that responds, and (if it's different
|
|
855
|
+
* from the current URL) pivot the transport onto it.
|
|
856
|
+
*
|
|
857
|
+
* Flow:
|
|
858
|
+
* 1. Query `localNetwork.getConnectionEndpoints({ port })` over the
|
|
859
|
+
* already-authenticated tRPC channel — the cap is auth-gated,
|
|
860
|
+
* so the LAN IPs never leak to anonymous callers.
|
|
861
|
+
* 2. For each candidate, fire a HEAD on `{baseUrl}/trpc/health`
|
|
862
|
+
* with a short timeout (default 1500ms). The first 2xx wins.
|
|
863
|
+
* 3. If the winner differs from `this.serverUrl`, call
|
|
864
|
+
* `switchServerUrl(winner)` and return it. Otherwise return
|
|
865
|
+
* the current URL unchanged.
|
|
866
|
+
*
|
|
867
|
+
* Bounded — if every candidate times out we keep the current URL.
|
|
868
|
+
* Idempotent — safe to call on every connect / reconnect / network
|
|
869
|
+
* change event.
|
|
870
|
+
*/
|
|
871
|
+
async raceConnectionEndpoints(options) {
|
|
872
|
+
const timeoutMs = options?.perCandidateTimeoutMs ?? 1500;
|
|
873
|
+
const url = (() => {
|
|
874
|
+
try {
|
|
875
|
+
return new URL(this._serverUrl);
|
|
876
|
+
} catch {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
})();
|
|
880
|
+
const port = url?.port ? Number(url.port) : url?.protocol === "https:" ? 443 : 80;
|
|
881
|
+
const scheme = url?.protocol === "https:" ? "https" : "http";
|
|
882
|
+
const cap = this._trpcClient.localNetwork?.getConnectionEndpoints;
|
|
883
|
+
if (!cap) return {
|
|
884
|
+
winner: this._serverUrl,
|
|
885
|
+
switched: false
|
|
886
|
+
};
|
|
887
|
+
let endpoints;
|
|
888
|
+
try {
|
|
889
|
+
endpoints = (await cap.query({
|
|
890
|
+
port,
|
|
891
|
+
ipv4Only: options?.ipv4Only,
|
|
892
|
+
scheme
|
|
893
|
+
})).endpoints;
|
|
894
|
+
} catch {
|
|
895
|
+
return {
|
|
896
|
+
winner: this._serverUrl,
|
|
897
|
+
switched: false
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
if (endpoints.length === 0) return {
|
|
901
|
+
winner: this._serverUrl,
|
|
902
|
+
switched: false
|
|
903
|
+
};
|
|
904
|
+
const winner = await raceFastestEndpoint(endpoints.map((e) => e.baseUrl), timeoutMs);
|
|
905
|
+
if (!winner || winner === this._serverUrl) return {
|
|
906
|
+
winner: winner ?? this._serverUrl,
|
|
907
|
+
switched: false
|
|
908
|
+
};
|
|
909
|
+
this.switchServerUrl(winner);
|
|
910
|
+
return {
|
|
911
|
+
winner,
|
|
912
|
+
switched: true
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
/** Tear down WS connection + mirror. The instance is unusable afterwards. */
|
|
916
|
+
close() {
|
|
917
|
+
this.disposeMirror();
|
|
918
|
+
this.connected = false;
|
|
919
|
+
this.connectedPromise = null;
|
|
920
|
+
this._wsClient?.close();
|
|
921
|
+
}
|
|
922
|
+
disposeMirror() {
|
|
923
|
+
this.mirror?.dispose();
|
|
924
|
+
this.mirror = null;
|
|
925
|
+
this.mirrorInit = null;
|
|
926
|
+
}
|
|
927
|
+
async login(username, password) {
|
|
928
|
+
const result = await this._trpcClient.auth.login.mutate({
|
|
929
|
+
username,
|
|
930
|
+
password
|
|
931
|
+
});
|
|
932
|
+
if (typeof result === "object" && result !== null && "token" in result) {
|
|
933
|
+
const r = result;
|
|
934
|
+
const token = r.token;
|
|
935
|
+
if (typeof token === "string" && r.requiresTotp !== true) this.setToken(token);
|
|
936
|
+
}
|
|
937
|
+
return result;
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Second leg of the 2FA login. The caller passes the challenge
|
|
941
|
+
* token returned by `login` (when `requiresTotp: true`) plus the
|
|
942
|
+
* 6-digit code from the user's authenticator app. On success the
|
|
943
|
+
* server mints the real session JWT, which we set as the active
|
|
944
|
+
* token on this client.
|
|
945
|
+
*/
|
|
946
|
+
async loginVerifyTotp(challengeToken, code) {
|
|
947
|
+
const result = await this._trpcClient.auth.loginVerifyTotp.mutate({
|
|
948
|
+
challengeToken,
|
|
949
|
+
code
|
|
950
|
+
});
|
|
951
|
+
if (typeof result === "object" && result !== null && "token" in result) {
|
|
952
|
+
const token = result.token;
|
|
953
|
+
if (typeof token === "string") this.setToken(token);
|
|
954
|
+
}
|
|
955
|
+
return result;
|
|
956
|
+
}
|
|
957
|
+
async logout() {
|
|
958
|
+
await this._trpcClient.auth.logout.mutate();
|
|
959
|
+
}
|
|
960
|
+
async getMe() {
|
|
961
|
+
return await this._trpcClient.auth.me.query();
|
|
962
|
+
}
|
|
963
|
+
async changeOwnPassword(input) {
|
|
964
|
+
return await this._trpcClient.auth.changeOwnPassword.mutate(input);
|
|
965
|
+
}
|
|
966
|
+
async setupOwnTotp() {
|
|
967
|
+
return await this._trpcClient.auth.setupOwnTotp.mutate();
|
|
968
|
+
}
|
|
969
|
+
async confirmOwnTotp(input) {
|
|
970
|
+
return await this._trpcClient.auth.confirmOwnTotp.mutate(input);
|
|
971
|
+
}
|
|
972
|
+
async disableOwnTotp() {
|
|
973
|
+
return await this._trpcClient.auth.disableOwnTotp.mutate();
|
|
974
|
+
}
|
|
975
|
+
async getOwnTotpStatus() {
|
|
976
|
+
return await this._trpcClient.auth.getOwnTotpStatus.query();
|
|
977
|
+
}
|
|
978
|
+
/** Update the auth token (e.g. after login or token refresh). */
|
|
979
|
+
setToken(token) {
|
|
980
|
+
this.token = token;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Synchronous snapshot of every device matching the optional filters.
|
|
984
|
+
* Backed by the `SystemMirror` warm-boot cache — call `init()` first
|
|
985
|
+
* (or `awaitReady()`) before invoking. Returns an empty array if the
|
|
986
|
+
* mirror has not yet been booted.
|
|
987
|
+
*
|
|
988
|
+
* Each returned proxy has `binding` populated from the mirror's
|
|
989
|
+
* binding cache (Phase 5 dedup), so consumers no longer need to
|
|
990
|
+
* make a separate `deviceManager.getBindings` round-trip.
|
|
991
|
+
*/
|
|
992
|
+
listDevices(filters) {
|
|
993
|
+
if (!this.mirror) return [];
|
|
994
|
+
return (filters ? this.mirror.query(filters) : this.mirror.getAllDevices()).map((p) => this.attachBinding(p));
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Sync `DeviceInfo` snapshot (name, canonical type, online, …) for one device
|
|
998
|
+
* from the warm-boot mirror — `null` if the mirror isn't booted or the device
|
|
999
|
+
* is unknown. Unlike a `DeviceProxy` (cap accessors only), this carries the
|
|
1000
|
+
* display identity the UI needs to render a device on first paint.
|
|
1001
|
+
*/
|
|
1002
|
+
getDeviceInfo(deviceId) {
|
|
1003
|
+
return this.mirror?.getDeviceInfo(deviceId) ?? null;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* The `DeviceInfo` snapshots for the current device set (the warm-boot cache),
|
|
1007
|
+
* honouring the same `filters` as {@link listDevices}. Lets a UI render a named
|
|
1008
|
+
* device list immediately without waiting for per-device lifecycle events.
|
|
1009
|
+
*/
|
|
1010
|
+
listDeviceInfos(filters) {
|
|
1011
|
+
const mirror = this.mirror;
|
|
1012
|
+
if (!mirror) return [];
|
|
1013
|
+
const proxies = filters ? mirror.query(filters) : mirror.getAllDevices();
|
|
1014
|
+
const out = [];
|
|
1015
|
+
for (const p of proxies) {
|
|
1016
|
+
const info = mirror.getDeviceInfo(p.deviceId);
|
|
1017
|
+
if (info) out.push(info);
|
|
1018
|
+
}
|
|
1019
|
+
return out;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Sync lookup by numeric id. `null` if the mirror has not been booted
|
|
1023
|
+
* or the device is unknown.
|
|
1024
|
+
*/
|
|
1025
|
+
getDevice(deviceId) {
|
|
1026
|
+
const proxy = this.mirror?.getDeviceById(deviceId) ?? null;
|
|
1027
|
+
return proxy ? this.attachBinding(proxy) : null;
|
|
1028
|
+
}
|
|
1029
|
+
/** Sync lookup by display name (exact match). */
|
|
1030
|
+
getDeviceByName(name) {
|
|
1031
|
+
const proxy = this.mirror?.getDeviceByName(name) ?? null;
|
|
1032
|
+
return proxy ? this.attachBinding(proxy) : null;
|
|
1033
|
+
}
|
|
1034
|
+
/** Sync lookup by stableId. */
|
|
1035
|
+
getDeviceByStableId(stableId) {
|
|
1036
|
+
const proxy = this.mirror?.getDeviceByStableId(stableId) ?? null;
|
|
1037
|
+
return proxy ? this.attachBinding(proxy) : null;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Resolve when a device with `deviceId` becomes available. Resolves
|
|
1041
|
+
* immediately if already known; rejects with a timeout error
|
|
1042
|
+
* otherwise (default 30s).
|
|
1043
|
+
*/
|
|
1044
|
+
async waitForDevice(deviceId, timeoutMs) {
|
|
1045
|
+
if (!this.mirror) await this.init();
|
|
1046
|
+
const proxy = await this.mirror.waitForDevice(deviceId, timeoutMs ?? 3e4);
|
|
1047
|
+
return this.attachBinding(proxy);
|
|
1048
|
+
}
|
|
1049
|
+
/** Subscribe to `device.registered` events. */
|
|
1050
|
+
onDeviceAdded(cb) {
|
|
1051
|
+
if (!this.mirror) throw new Error("System.onDeviceAdded: call init() before subscribing");
|
|
1052
|
+
return this.mirror.onDeviceAdded(cb);
|
|
1053
|
+
}
|
|
1054
|
+
/** Subscribe to `device.unregistered` events. */
|
|
1055
|
+
onDeviceRemoved(cb) {
|
|
1056
|
+
if (!this.mirror) throw new Error("System.onDeviceRemoved: call init() before subscribing");
|
|
1057
|
+
return this.mirror.onDeviceRemoved(cb);
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Patch the proxy's `binding` field from the mirror's cache. The
|
|
1061
|
+
* generated `createDeviceProxy()` already sets `binding` to the
|
|
1062
|
+
* binding it was constructed with — this is a defensive overwrite
|
|
1063
|
+
* that uses the latest cached entry in case a `binding-changed`
|
|
1064
|
+
* event landed between proxy creation and access.
|
|
1065
|
+
*/
|
|
1066
|
+
attachBinding(proxy) {
|
|
1067
|
+
const binding = this.lookupBinding(proxy.deviceId);
|
|
1068
|
+
if (binding === proxy.binding) return proxy;
|
|
1069
|
+
const writable = proxy;
|
|
1070
|
+
writable.binding = binding;
|
|
1071
|
+
return proxy;
|
|
1072
|
+
}
|
|
1073
|
+
/** Fetch the latest cached binding from the mirror, or `null`. */
|
|
1074
|
+
lookupBinding(deviceId) {
|
|
1075
|
+
if (!this.mirror) return null;
|
|
1076
|
+
return this.mirror.getDeviceById(deviceId)?.binding ?? null;
|
|
1077
|
+
}
|
|
1078
|
+
get addonPages() {
|
|
1079
|
+
return this._systemProxy.addonPages;
|
|
1080
|
+
}
|
|
1081
|
+
get addonSettings() {
|
|
1082
|
+
return this._systemProxy.addonSettings;
|
|
1083
|
+
}
|
|
1084
|
+
get alerts() {
|
|
1085
|
+
return this._systemProxy.alerts;
|
|
1086
|
+
}
|
|
1087
|
+
get audioAnalyzer() {
|
|
1088
|
+
return this._systemProxy.audioAnalyzer;
|
|
1089
|
+
}
|
|
1090
|
+
get audioCodec() {
|
|
1091
|
+
return this._systemProxy.audioCodec;
|
|
1092
|
+
}
|
|
1093
|
+
get backup() {
|
|
1094
|
+
return this._systemProxy.backup;
|
|
1095
|
+
}
|
|
1096
|
+
get decoder() {
|
|
1097
|
+
return this._systemProxy.decoder;
|
|
1098
|
+
}
|
|
1099
|
+
get deviceManager() {
|
|
1100
|
+
return this._systemProxy.deviceManager;
|
|
1101
|
+
}
|
|
1102
|
+
get deviceProvider() {
|
|
1103
|
+
return this._systemProxy.deviceProvider;
|
|
1104
|
+
}
|
|
1105
|
+
get deviceState() {
|
|
1106
|
+
return this._systemProxy.deviceState;
|
|
1107
|
+
}
|
|
1108
|
+
get metricsProvider() {
|
|
1109
|
+
return this._systemProxy.metricsProvider;
|
|
1110
|
+
}
|
|
1111
|
+
get notificationOutput() {
|
|
1112
|
+
return this._systemProxy.notificationOutput;
|
|
1113
|
+
}
|
|
1114
|
+
get pipelineExecutor() {
|
|
1115
|
+
return this._systemProxy.pipelineExecutor;
|
|
1116
|
+
}
|
|
1117
|
+
get pipelineOrchestrator() {
|
|
1118
|
+
return this._systemProxy.pipelineOrchestrator;
|
|
1119
|
+
}
|
|
1120
|
+
get pipelineRunner() {
|
|
1121
|
+
return this._systemProxy.pipelineRunner;
|
|
1122
|
+
}
|
|
1123
|
+
get settingsStore() {
|
|
1124
|
+
return this._systemProxy.settingsStore;
|
|
1125
|
+
}
|
|
1126
|
+
get storage() {
|
|
1127
|
+
return this._systemProxy.storage;
|
|
1128
|
+
}
|
|
1129
|
+
get streamBroker() {
|
|
1130
|
+
return this._systemProxy.streamBroker;
|
|
1131
|
+
}
|
|
1132
|
+
get turnProvider() {
|
|
1133
|
+
return this._systemProxy.turnProvider;
|
|
1134
|
+
}
|
|
1135
|
+
get userManagement() {
|
|
1136
|
+
return this._systemProxy.userManagement;
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Subscribe to a single event category. Returns an unsubscribe
|
|
1140
|
+
* handle. Errors thrown by the listener are swallowed so a single
|
|
1141
|
+
* misbehaving consumer cannot tear down the WS subscription.
|
|
1142
|
+
*
|
|
1143
|
+
* Categories should be values from the `EventCategory` enum
|
|
1144
|
+
* (`@camstack/types`) — passing a raw string works for forward-compat
|
|
1145
|
+
* but loses type safety. The SDK forwards the value verbatim to the
|
|
1146
|
+
* server's `live.onEvent` subscription.
|
|
1147
|
+
*/
|
|
1148
|
+
subscribeEvent(category, cb) {
|
|
1149
|
+
const sub = this._trpcClient.live.onEvent.subscribe({ category }, { onData: (event) => {
|
|
1150
|
+
try {
|
|
1151
|
+
cb(event);
|
|
1152
|
+
} catch {}
|
|
1153
|
+
} });
|
|
1154
|
+
return () => {
|
|
1155
|
+
try {
|
|
1156
|
+
sub.unsubscribe();
|
|
1157
|
+
} catch {}
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
/** Direct tRPC client. Read once per call; rebuilt on `reconnect()`. */
|
|
1161
|
+
get trpcClient() {
|
|
1162
|
+
return this._trpcClient;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Underlying WSClient (or `null` for HTTP transport). Used by
|
|
1166
|
+
* advanced consumers that need direct access to the WebSocket
|
|
1167
|
+
* (e.g. for keep-alive metrics). Rebuilt on `reconnect()`.
|
|
1168
|
+
*/
|
|
1169
|
+
get wsClient() {
|
|
1170
|
+
return this._wsClient;
|
|
1171
|
+
}
|
|
1172
|
+
buildTrpcClient() {
|
|
1173
|
+
const headers = () => {
|
|
1174
|
+
const h = {};
|
|
1175
|
+
if (this.token) h["Authorization"] = `Bearer ${this.token}`;
|
|
1176
|
+
return h;
|
|
1177
|
+
};
|
|
1178
|
+
if (this.useWs) {
|
|
1179
|
+
const wsUrl = this._serverUrl.replace(/^http/, "ws") + "/trpc";
|
|
1180
|
+
const baseRetryMs = this.baseRetryMs;
|
|
1181
|
+
const maxRetryMs = this.maxRetryMs;
|
|
1182
|
+
this._wsClient = (0, _trpc_client.createWSClient)({
|
|
1183
|
+
url: wsUrl,
|
|
1184
|
+
connectionParams: () => ({ token: this.token }),
|
|
1185
|
+
retryDelayMs: (attemptIndex) => Math.min(baseRetryMs * Math.pow(2, attemptIndex), maxRetryMs),
|
|
1186
|
+
keepAlive: {
|
|
1187
|
+
enabled: true,
|
|
1188
|
+
intervalMs: WS_KEEP_ALIVE_INTERVAL_MS,
|
|
1189
|
+
pongTimeoutMs: WS_KEEP_ALIVE_PONG_TIMEOUT_MS
|
|
1190
|
+
},
|
|
1191
|
+
onOpen: () => {
|
|
1192
|
+
this._connectionVersion += 1;
|
|
1193
|
+
this.emitConnectionEvent("connected");
|
|
1194
|
+
},
|
|
1195
|
+
onClose: () => {
|
|
1196
|
+
this.emitConnectionEvent("disconnected");
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
return (0, _trpc_client.createTRPCClient)({ links: [(0, _trpc_client.wsLink)({
|
|
1200
|
+
client: this._wsClient,
|
|
1201
|
+
transformer: SuperJSON
|
|
1202
|
+
})] });
|
|
1203
|
+
}
|
|
1204
|
+
this._wsClient = null;
|
|
1205
|
+
return (0, _trpc_client.createTRPCClient)({ links: [(0, _trpc_client.httpLink)({
|
|
1206
|
+
url: `${this._serverUrl}/trpc`,
|
|
1207
|
+
headers,
|
|
1208
|
+
transformer: SuperJSON
|
|
1209
|
+
})] });
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
/** Create a `System` instance. Convenience factory. */
|
|
1369
1213
|
function createSystem(config) {
|
|
1370
|
-
|
|
1214
|
+
return new System(config);
|
|
1371
1215
|
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Race a list of candidate base URLs and return the first one that
|
|
1218
|
+
* responds to `GET {baseUrl}/trpc/health` with a 2xx within
|
|
1219
|
+
* `timeoutMs`. Returns `null` if every candidate fails / times out.
|
|
1220
|
+
*
|
|
1221
|
+
* Implementation notes:
|
|
1222
|
+
* - Uses `fetch` with `AbortController` for per-candidate cutoff so a
|
|
1223
|
+
* stalled candidate doesn't pin the wallclock for the whole race.
|
|
1224
|
+
* - Cancels every still-pending probe as soon as the first one
|
|
1225
|
+
* succeeds — no wasted bandwidth on the loser candidates.
|
|
1226
|
+
* - `/trpc/health` is the only endpoint guaranteed to respond on every
|
|
1227
|
+
* CamStack deployment (registered alongside the tRPC plugin). It is
|
|
1228
|
+
* intentionally NOT auth-gated since it's used by load balancers /
|
|
1229
|
+
* uptime probes — same surface every reverse proxy already monitors.
|
|
1230
|
+
* - HEAD would be nicer but Cloudflare Tunnel + some browsers
|
|
1231
|
+
* mishandle HEAD on the ingress path; GET is safer.
|
|
1232
|
+
*
|
|
1233
|
+
* Exported so non-System callers (CLI helpers, tests) can race their
|
|
1234
|
+
* own candidate lists without instantiating a full System.
|
|
1235
|
+
*/
|
|
1372
1236
|
async function raceFastestEndpoint(candidates, timeoutMs) {
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
c.abort();
|
|
1403
|
-
} catch {
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
return winner;
|
|
1407
|
-
} catch {
|
|
1408
|
-
return null;
|
|
1409
|
-
}
|
|
1237
|
+
if (candidates.length === 0) return null;
|
|
1238
|
+
if (typeof fetch !== "function") return candidates[0] ?? null;
|
|
1239
|
+
const reachable = typeof window !== "undefined" && typeof window.location !== "undefined" && window.location.protocol === "https:" ? candidates.filter((u) => u.toLowerCase().startsWith("https://")) : candidates;
|
|
1240
|
+
if (reachable.length === 0) return null;
|
|
1241
|
+
const controllers = reachable.map(() => new AbortController());
|
|
1242
|
+
const probes = reachable.map(async (baseUrl, i) => {
|
|
1243
|
+
const ctrl = controllers[i];
|
|
1244
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
1245
|
+
try {
|
|
1246
|
+
const res = await fetch(`${baseUrl.replace(/\/+$/, "")}/trpc/health`, {
|
|
1247
|
+
method: "GET",
|
|
1248
|
+
signal: ctrl.signal,
|
|
1249
|
+
credentials: "omit"
|
|
1250
|
+
});
|
|
1251
|
+
if (!res.ok) throw new Error(`${res.status}`);
|
|
1252
|
+
return baseUrl;
|
|
1253
|
+
} finally {
|
|
1254
|
+
clearTimeout(timer);
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1257
|
+
try {
|
|
1258
|
+
const winner = await Promise.any(probes);
|
|
1259
|
+
for (const c of controllers) try {
|
|
1260
|
+
c.abort();
|
|
1261
|
+
} catch {}
|
|
1262
|
+
return winner;
|
|
1263
|
+
} catch {
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1410
1266
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1267
|
+
//#endregion
|
|
1268
|
+
//#region src/detection.ts
|
|
1269
|
+
/**
|
|
1270
|
+
* Detection classes — shared between CamStack app and proxy.
|
|
1271
|
+
* Aligned with scrypted-advanced-notifier/src/detectionClasses.ts.
|
|
1272
|
+
*/
|
|
1273
|
+
var DetectionClass = /* @__PURE__ */ function(DetectionClass) {
|
|
1274
|
+
DetectionClass["Motion"] = "motion";
|
|
1275
|
+
DetectionClass["Person"] = "person";
|
|
1276
|
+
DetectionClass["Vehicle"] = "vehicle";
|
|
1277
|
+
DetectionClass["Animal"] = "animal";
|
|
1278
|
+
DetectionClass["Audio"] = "audio";
|
|
1279
|
+
DetectionClass["Face"] = "face";
|
|
1280
|
+
DetectionClass["Plate"] = "plate";
|
|
1281
|
+
DetectionClass["Package"] = "package";
|
|
1282
|
+
DetectionClass["Doorbell"] = "doorbell";
|
|
1283
|
+
DetectionClass["Sensor"] = "sensor";
|
|
1284
|
+
return DetectionClass;
|
|
1285
|
+
}({});
|
|
1286
|
+
var animalClasses = [
|
|
1287
|
+
"animal",
|
|
1288
|
+
"dog_cat",
|
|
1289
|
+
"dog",
|
|
1290
|
+
"cat",
|
|
1291
|
+
"horse",
|
|
1292
|
+
"sheep",
|
|
1293
|
+
"cow",
|
|
1294
|
+
"elephant",
|
|
1295
|
+
"bear",
|
|
1296
|
+
"zebra",
|
|
1297
|
+
"giraffe",
|
|
1298
|
+
"mouse",
|
|
1299
|
+
"rabbit",
|
|
1300
|
+
"deer",
|
|
1301
|
+
"lion",
|
|
1302
|
+
"tiger",
|
|
1303
|
+
"bird",
|
|
1304
|
+
"eagle",
|
|
1305
|
+
"owl",
|
|
1306
|
+
"pigeon",
|
|
1307
|
+
"fish",
|
|
1308
|
+
"whale",
|
|
1309
|
+
"dolphin",
|
|
1310
|
+
"snake",
|
|
1311
|
+
"turtle",
|
|
1312
|
+
"lizard"
|
|
1451
1313
|
];
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1314
|
+
var personClasses = [
|
|
1315
|
+
"person",
|
|
1316
|
+
"people",
|
|
1317
|
+
"pedestrian",
|
|
1318
|
+
"rider",
|
|
1319
|
+
"driver",
|
|
1320
|
+
"cyclist",
|
|
1321
|
+
"skier",
|
|
1322
|
+
"skateboarder",
|
|
1323
|
+
"face",
|
|
1324
|
+
"hand",
|
|
1325
|
+
"head",
|
|
1326
|
+
"body"
|
|
1465
1327
|
];
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1328
|
+
var vehicleClasses = [
|
|
1329
|
+
"vehicle",
|
|
1330
|
+
"car",
|
|
1331
|
+
"truck",
|
|
1332
|
+
"bus",
|
|
1333
|
+
"motorcycle",
|
|
1334
|
+
"bicycle",
|
|
1335
|
+
"van",
|
|
1336
|
+
"ambulance",
|
|
1337
|
+
"police_car",
|
|
1338
|
+
"fire_truck",
|
|
1339
|
+
"train",
|
|
1340
|
+
"subway",
|
|
1341
|
+
"tram",
|
|
1342
|
+
"airplane",
|
|
1343
|
+
"boat",
|
|
1344
|
+
"ship",
|
|
1345
|
+
"helicopter"
|
|
1484
1346
|
];
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1347
|
+
var faceClasses = [
|
|
1348
|
+
"face",
|
|
1349
|
+
"eyes",
|
|
1350
|
+
"nose",
|
|
1351
|
+
"mouth",
|
|
1352
|
+
"ears",
|
|
1353
|
+
"eyebrows",
|
|
1354
|
+
"left_eye",
|
|
1355
|
+
"right_eye",
|
|
1356
|
+
"pupil",
|
|
1357
|
+
"iris",
|
|
1358
|
+
"eyelid",
|
|
1359
|
+
"eye_corner",
|
|
1360
|
+
"upper_lip",
|
|
1361
|
+
"lower_lip",
|
|
1362
|
+
"teeth",
|
|
1363
|
+
"chin",
|
|
1364
|
+
"cheek",
|
|
1365
|
+
"forehead",
|
|
1366
|
+
"jaw",
|
|
1367
|
+
"glasses",
|
|
1368
|
+
"sunglasses",
|
|
1369
|
+
"facial_hair",
|
|
1370
|
+
"beard",
|
|
1371
|
+
"mustache",
|
|
1372
|
+
"facial_landmark",
|
|
1373
|
+
"facial_keypoint"
|
|
1512
1374
|
];
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1375
|
+
var licensePlateClasses = [
|
|
1376
|
+
"plate",
|
|
1377
|
+
"license_plate",
|
|
1378
|
+
"front_plate",
|
|
1379
|
+
"rear_plate",
|
|
1380
|
+
"motorcycle_plate",
|
|
1381
|
+
"temporary_plate",
|
|
1382
|
+
"dealer_plate",
|
|
1383
|
+
"licensePlate",
|
|
1384
|
+
"plate_number",
|
|
1385
|
+
"plate_character",
|
|
1386
|
+
"plate_digit",
|
|
1387
|
+
"plate_letter",
|
|
1388
|
+
"plate_symbol",
|
|
1389
|
+
"plate_region",
|
|
1390
|
+
"plate_country_identifier",
|
|
1391
|
+
"plate_frame",
|
|
1392
|
+
"plate_bolt",
|
|
1393
|
+
"plate_sticker",
|
|
1394
|
+
"plate_validation_tag",
|
|
1395
|
+
"damaged_plate",
|
|
1396
|
+
"obscured_plate",
|
|
1397
|
+
"dirty_plate"
|
|
1536
1398
|
];
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
/* Audio */
|
|
1399
|
+
var motionClasses = [
|
|
1400
|
+
"motion",
|
|
1401
|
+
"movement",
|
|
1402
|
+
"other"
|
|
1542
1403
|
];
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1404
|
+
var packageClasses = ["package", "packet"];
|
|
1405
|
+
var audioClasses = ["audio"];
|
|
1406
|
+
/** Common YAMNet audio labels (advanced-notifier). Parent: Audio. */
|
|
1407
|
+
var audioLabelClasses = [
|
|
1408
|
+
"speech",
|
|
1409
|
+
"scream",
|
|
1410
|
+
"babbling",
|
|
1411
|
+
"yell",
|
|
1412
|
+
"bellow",
|
|
1413
|
+
"whoop",
|
|
1414
|
+
"whispering",
|
|
1415
|
+
"laughter",
|
|
1416
|
+
"snicker",
|
|
1417
|
+
"crying",
|
|
1418
|
+
"cry",
|
|
1419
|
+
"sigh",
|
|
1420
|
+
"singing",
|
|
1421
|
+
"choir",
|
|
1422
|
+
"chant",
|
|
1423
|
+
"mantra",
|
|
1424
|
+
"child_singing",
|
|
1425
|
+
"rapping",
|
|
1426
|
+
"humming",
|
|
1427
|
+
"groan",
|
|
1428
|
+
"grunt",
|
|
1429
|
+
"whistling",
|
|
1430
|
+
"breathing",
|
|
1431
|
+
"wheeze",
|
|
1432
|
+
"snoring",
|
|
1433
|
+
"gasp",
|
|
1434
|
+
"pant",
|
|
1435
|
+
"snort",
|
|
1436
|
+
"cough",
|
|
1437
|
+
"throat_clearing",
|
|
1438
|
+
"sneeze",
|
|
1439
|
+
"sniff",
|
|
1440
|
+
"cheering",
|
|
1441
|
+
"applause",
|
|
1442
|
+
"chatter",
|
|
1443
|
+
"crowd",
|
|
1444
|
+
"children_playing",
|
|
1445
|
+
"bark",
|
|
1446
|
+
"yip",
|
|
1447
|
+
"howl",
|
|
1448
|
+
"bow-wow",
|
|
1449
|
+
"growling",
|
|
1450
|
+
"whimper_dog",
|
|
1451
|
+
"purr",
|
|
1452
|
+
"meow",
|
|
1453
|
+
"hiss",
|
|
1454
|
+
"caterwaul",
|
|
1455
|
+
"pets",
|
|
1456
|
+
"livestock",
|
|
1457
|
+
"doorbell",
|
|
1458
|
+
"ding-dong",
|
|
1459
|
+
"door",
|
|
1460
|
+
"slam",
|
|
1461
|
+
"knock",
|
|
1462
|
+
"alarm",
|
|
1463
|
+
"telephone",
|
|
1464
|
+
"music",
|
|
1465
|
+
"dog",
|
|
1466
|
+
"dogs"
|
|
1603
1467
|
];
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1468
|
+
var doorbellClasses = ["doorbell", "ring"];
|
|
1469
|
+
/** Sensor types (advanced-notifier SupportedSensorType). Parent: Sensor. */
|
|
1470
|
+
var sensorLabelClasses = [
|
|
1471
|
+
"lock",
|
|
1472
|
+
"binary",
|
|
1473
|
+
"flood",
|
|
1474
|
+
"entry",
|
|
1475
|
+
"door",
|
|
1476
|
+
"leak",
|
|
1477
|
+
"door_open",
|
|
1478
|
+
"flooded",
|
|
1479
|
+
"entry_open"
|
|
1615
1480
|
];
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
}), {}),
|
|
1662
|
-
...doorbellClasses.reduce((tot, curr) => ({
|
|
1663
|
-
...tot,
|
|
1664
|
-
[curr]: "doorbell"
|
|
1665
|
-
/* Doorbell */
|
|
1666
|
-
}), {}),
|
|
1667
|
-
...sensorLabelClasses.reduce((tot, curr) => ({
|
|
1668
|
-
...tot,
|
|
1669
|
-
[curr]: "sensor"
|
|
1670
|
-
/* Sensor */
|
|
1671
|
-
}), {})
|
|
1481
|
+
var detectionClassesDefaultMap = {
|
|
1482
|
+
...animalClasses.reduce((tot, curr) => ({
|
|
1483
|
+
...tot,
|
|
1484
|
+
[curr]: "animal"
|
|
1485
|
+
}), {}),
|
|
1486
|
+
...personClasses.reduce((tot, curr) => ({
|
|
1487
|
+
...tot,
|
|
1488
|
+
[curr]: "person"
|
|
1489
|
+
}), {}),
|
|
1490
|
+
...vehicleClasses.reduce((tot, curr) => ({
|
|
1491
|
+
...tot,
|
|
1492
|
+
[curr]: "vehicle"
|
|
1493
|
+
}), {}),
|
|
1494
|
+
...motionClasses.reduce((tot, curr) => ({
|
|
1495
|
+
...tot,
|
|
1496
|
+
[curr]: "motion"
|
|
1497
|
+
}), {}),
|
|
1498
|
+
...packageClasses.reduce((tot, curr) => ({
|
|
1499
|
+
...tot,
|
|
1500
|
+
[curr]: "package"
|
|
1501
|
+
}), {}),
|
|
1502
|
+
...faceClasses.reduce((tot, curr) => ({
|
|
1503
|
+
...tot,
|
|
1504
|
+
[curr]: "face"
|
|
1505
|
+
}), {}),
|
|
1506
|
+
...licensePlateClasses.reduce((tot, curr) => ({
|
|
1507
|
+
...tot,
|
|
1508
|
+
[curr]: "plate"
|
|
1509
|
+
}), {}),
|
|
1510
|
+
...audioClasses.reduce((tot, curr) => ({
|
|
1511
|
+
...tot,
|
|
1512
|
+
[curr]: "audio"
|
|
1513
|
+
}), {}),
|
|
1514
|
+
...audioLabelClasses.reduce((tot, curr) => ({
|
|
1515
|
+
...tot,
|
|
1516
|
+
[curr]: "audio"
|
|
1517
|
+
}), {}),
|
|
1518
|
+
...doorbellClasses.reduce((tot, curr) => ({
|
|
1519
|
+
...tot,
|
|
1520
|
+
[curr]: "doorbell"
|
|
1521
|
+
}), {}),
|
|
1522
|
+
...sensorLabelClasses.reduce((tot, curr) => ({
|
|
1523
|
+
...tot,
|
|
1524
|
+
[curr]: "sensor"
|
|
1525
|
+
}), {})
|
|
1672
1526
|
};
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
/* Plate */
|
|
1695
|
-
]: "vehicle"
|
|
1696
|
-
/* Vehicle */
|
|
1697
|
-
};
|
|
1698
|
-
const parentGroup = detectionClassesDefaultMap[className];
|
|
1699
|
-
if (parentGroup && parentGroup !== className) return parentGroup;
|
|
1700
|
-
return baseMap[className];
|
|
1527
|
+
var isFaceClassname = (c) => faceClasses.includes(c);
|
|
1528
|
+
var isPlateClassname = (c) => licensePlateClasses.includes(c);
|
|
1529
|
+
var isAnimalClassname = (c) => animalClasses.includes(c);
|
|
1530
|
+
var isPersonClassname = (c) => personClasses.includes(c);
|
|
1531
|
+
var isVehicleClassname = (c) => vehicleClasses.includes(c);
|
|
1532
|
+
var isMotionClassname = (c) => motionClasses.includes(c);
|
|
1533
|
+
var isDoorbellClassname = (c) => doorbellClasses.includes(c);
|
|
1534
|
+
var isPackageClassname = (c) => packageClasses.includes(c);
|
|
1535
|
+
var isAudioClassname = (c) => audioClasses.includes(c) || audioLabelClasses.includes(c);
|
|
1536
|
+
var isSensorLabelClassname = (c) => sensorLabelClasses.includes(c);
|
|
1537
|
+
var isLabelDetection = (c) => isFaceClassname(c) || isPlateClassname(c);
|
|
1538
|
+
var getParentClass = (className) => detectionClassesDefaultMap[className];
|
|
1539
|
+
var getParentDetectionClass = (det) => {
|
|
1540
|
+
const { className } = det;
|
|
1541
|
+
const baseMap = {
|
|
1542
|
+
["face"]: "person",
|
|
1543
|
+
["plate"]: "vehicle"
|
|
1544
|
+
};
|
|
1545
|
+
const parentGroup = detectionClassesDefaultMap[className];
|
|
1546
|
+
if (parentGroup && parentGroup !== className) return parentGroup;
|
|
1547
|
+
return baseMap[className];
|
|
1701
1548
|
};
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
"package"
|
|
1711
|
-
/* Package */
|
|
1549
|
+
var defaultDetectionClasses = Object.values(DetectionClass);
|
|
1550
|
+
/** Default enabled classes: all except Motion. */
|
|
1551
|
+
var DEFAULT_ENABLED_CLASSES = defaultDetectionClasses.filter((c) => c !== "motion");
|
|
1552
|
+
/** Classes for "critical" preset: security-relevant only (person, doorbell, package). */
|
|
1553
|
+
var TIMELINE_PRESET_CRITICAL = [
|
|
1554
|
+
"person",
|
|
1555
|
+
"doorbell",
|
|
1556
|
+
"package"
|
|
1712
1557
|
];
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1558
|
+
/** Classes for "important" preset: critical + vehicle, animal, audio, face, plate. */
|
|
1559
|
+
var TIMELINE_PRESET_IMPORTANT = [
|
|
1560
|
+
...TIMELINE_PRESET_CRITICAL,
|
|
1561
|
+
"vehicle",
|
|
1562
|
+
"animal",
|
|
1563
|
+
"audio",
|
|
1564
|
+
"face",
|
|
1565
|
+
"plate"
|
|
1721
1566
|
];
|
|
1722
|
-
|
|
1567
|
+
/** Classes for "all" preset: same as DEFAULT_ENABLED_CLASSES. */
|
|
1568
|
+
var TIMELINE_PRESET_ALL = [...DEFAULT_ENABLED_CLASSES];
|
|
1569
|
+
/** Get enabled classes for a preset. For "custom", pass customClasses. */
|
|
1723
1570
|
function getClassesForTimelinePreset(preset, customClasses) {
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
case "custom":
|
|
1732
|
-
return customClasses?.length ? customClasses : DEFAULT_ENABLED_CLASSES;
|
|
1733
|
-
default:
|
|
1734
|
-
return DEFAULT_ENABLED_CLASSES;
|
|
1735
|
-
}
|
|
1571
|
+
switch (preset) {
|
|
1572
|
+
case "critical": return TIMELINE_PRESET_CRITICAL;
|
|
1573
|
+
case "important": return TIMELINE_PRESET_IMPORTANT;
|
|
1574
|
+
case "all": return TIMELINE_PRESET_ALL;
|
|
1575
|
+
case "custom": return customClasses?.length ? customClasses : DEFAULT_ENABLED_CLASSES;
|
|
1576
|
+
default: return DEFAULT_ENABLED_CLASSES;
|
|
1577
|
+
}
|
|
1736
1578
|
}
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1579
|
+
//#endregion
|
|
1580
|
+
//#region src/devices.ts
|
|
1581
|
+
/**
|
|
1582
|
+
* Maps raw device types from Scrypted (PascalCase) and Home Assistant (lowercase domains)
|
|
1583
|
+
* to canonical CamStack device types.
|
|
1584
|
+
*/
|
|
1585
|
+
var RAW_TO_CANONICAL = {
|
|
1586
|
+
Light: "light",
|
|
1587
|
+
Switch: "switch",
|
|
1588
|
+
WindowCovering: "cover",
|
|
1589
|
+
Lock: "lock",
|
|
1590
|
+
SecuritySystem: "alarm",
|
|
1591
|
+
Buttons: "button",
|
|
1592
|
+
Select: "select",
|
|
1593
|
+
Siren: "siren",
|
|
1594
|
+
Sensor: "sensor",
|
|
1595
|
+
Entry: "entry",
|
|
1596
|
+
Program: "script",
|
|
1597
|
+
MediaPlayer: "media_player",
|
|
1598
|
+
Outlet: "switch",
|
|
1599
|
+
light: "light",
|
|
1600
|
+
switch: "switch",
|
|
1601
|
+
input_boolean: "switch",
|
|
1602
|
+
cover: "cover",
|
|
1603
|
+
lock: "lock",
|
|
1604
|
+
alarm_control_panel: "alarm",
|
|
1605
|
+
input_button: "button",
|
|
1606
|
+
button: "button",
|
|
1607
|
+
input_select: "select",
|
|
1608
|
+
select: "select",
|
|
1609
|
+
siren: "siren",
|
|
1610
|
+
sensor: "sensor",
|
|
1611
|
+
media_player: "media_player",
|
|
1612
|
+
script: "script"
|
|
1767
1613
|
};
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1614
|
+
/**
|
|
1615
|
+
* Extended HA domain → type map (includes non-eligible domains for display/categorization).
|
|
1616
|
+
* Superset of RAW_TO_CANONICAL for HA-specific domains.
|
|
1617
|
+
*/
|
|
1618
|
+
var HA_DOMAIN_TYPE_MAP = {
|
|
1619
|
+
light: "light",
|
|
1620
|
+
switch: "switch",
|
|
1621
|
+
input_boolean: "switch",
|
|
1622
|
+
cover: "cover",
|
|
1623
|
+
lock: "lock",
|
|
1624
|
+
alarm_control_panel: "alarm",
|
|
1625
|
+
input_button: "button",
|
|
1626
|
+
button: "button",
|
|
1627
|
+
input_select: "select",
|
|
1628
|
+
select: "select",
|
|
1629
|
+
siren: "siren",
|
|
1630
|
+
sensor: "sensor",
|
|
1631
|
+
binary_sensor: "sensor",
|
|
1632
|
+
media_player: "media_player",
|
|
1633
|
+
script: "script",
|
|
1634
|
+
climate: "climate",
|
|
1635
|
+
camera: "camera",
|
|
1636
|
+
fan: "fan",
|
|
1637
|
+
vacuum: "vacuum",
|
|
1638
|
+
automation: "automation",
|
|
1639
|
+
scene: "scene",
|
|
1640
|
+
input_number: "sensor",
|
|
1641
|
+
person: "person",
|
|
1642
|
+
device_tracker: "tracker",
|
|
1643
|
+
weather: "weather",
|
|
1644
|
+
water_heater: "climate"
|
|
1795
1645
|
};
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1646
|
+
/**
|
|
1647
|
+
* Extended Scrypted type → canonical map (includes non-eligible types for display).
|
|
1648
|
+
* Superset of RAW_TO_CANONICAL for Scrypted-specific types.
|
|
1649
|
+
*/
|
|
1650
|
+
var SCRYPTED_TYPE_TO_CANONICAL = {
|
|
1651
|
+
Light: "light",
|
|
1652
|
+
Switch: "switch",
|
|
1653
|
+
WindowCovering: "cover",
|
|
1654
|
+
Lock: "lock",
|
|
1655
|
+
SecuritySystem: "alarm",
|
|
1656
|
+
Buttons: "button",
|
|
1657
|
+
Select: "select",
|
|
1658
|
+
Siren: "siren",
|
|
1659
|
+
Sensor: "sensor",
|
|
1660
|
+
Entry: "entry",
|
|
1661
|
+
Program: "script",
|
|
1662
|
+
MediaPlayer: "media_player",
|
|
1663
|
+
Camera: "camera",
|
|
1664
|
+
Doorbell: "doorbell",
|
|
1665
|
+
Fan: "fan",
|
|
1666
|
+
Outlet: "switch"
|
|
1813
1667
|
};
|
|
1668
|
+
/** Normalize raw type (Scrypted or HA) to canonical key for filtering and display. */
|
|
1814
1669
|
function getCanonicalDeviceType(rawType) {
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
return RAW_TO_CANONICAL[lower] ?? null;
|
|
1670
|
+
const canonical = RAW_TO_CANONICAL[rawType];
|
|
1671
|
+
if (canonical) return canonical;
|
|
1672
|
+
return RAW_TO_CANONICAL[rawType.toLowerCase()] ?? null;
|
|
1819
1673
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1674
|
+
/** Scrypted device types eligible for device control in CamStack. PascalCase. */
|
|
1675
|
+
var ELIGIBLE_SCRYPTED_DEVICE_TYPES = [
|
|
1676
|
+
"Entry",
|
|
1677
|
+
"Light",
|
|
1678
|
+
"Switch",
|
|
1679
|
+
"Lock",
|
|
1680
|
+
"SecuritySystem",
|
|
1681
|
+
"Buttons",
|
|
1682
|
+
"WindowCovering",
|
|
1683
|
+
"Siren",
|
|
1684
|
+
"Sensor",
|
|
1685
|
+
"Select",
|
|
1686
|
+
"Program"
|
|
1832
1687
|
];
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1688
|
+
/** Set version for O(1) lookup. */
|
|
1689
|
+
var ELIGIBLE_SCRYPTED_DEVICE_TYPES_SET = new Set(ELIGIBLE_SCRYPTED_DEVICE_TYPES);
|
|
1690
|
+
/** Home Assistant domains eligible for device control in CamStack. */
|
|
1691
|
+
var ELIGIBLE_HA_DOMAINS = [
|
|
1692
|
+
"light",
|
|
1693
|
+
"switch",
|
|
1694
|
+
"input_boolean",
|
|
1695
|
+
"cover",
|
|
1696
|
+
"lock",
|
|
1697
|
+
"alarm_control_panel",
|
|
1698
|
+
"input_button",
|
|
1699
|
+
"button",
|
|
1700
|
+
"input_select",
|
|
1701
|
+
"select",
|
|
1702
|
+
"siren",
|
|
1703
|
+
"media_player",
|
|
1704
|
+
"script"
|
|
1848
1705
|
];
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1706
|
+
/** Set version for O(1) lookup. */
|
|
1707
|
+
var ELIGIBLE_HA_DOMAINS_SET = new Set(ELIGIBLE_HA_DOMAINS);
|
|
1708
|
+
//#endregion
|
|
1709
|
+
//#region src/features.ts
|
|
1710
|
+
var FEATURE_MATRIX = [
|
|
1711
|
+
{
|
|
1712
|
+
id: "liveStream",
|
|
1713
|
+
label: "Live Stream",
|
|
1714
|
+
sources: {
|
|
1715
|
+
frigate: true,
|
|
1716
|
+
scrypted: true,
|
|
1717
|
+
rtsp: true
|
|
1718
|
+
},
|
|
1719
|
+
adapterMethod: "getLiveStream"
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
id: "multiResolution",
|
|
1723
|
+
label: "Multi-Resolution",
|
|
1724
|
+
sources: {
|
|
1725
|
+
frigate: true,
|
|
1726
|
+
scrypted: true,
|
|
1727
|
+
rtsp: false
|
|
1728
|
+
},
|
|
1729
|
+
adapterMethod: "getResolutions"
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
id: "motion",
|
|
1733
|
+
label: "Motion Detection",
|
|
1734
|
+
sources: {
|
|
1735
|
+
frigate: false,
|
|
1736
|
+
scrypted: true,
|
|
1737
|
+
rtsp: false
|
|
1738
|
+
},
|
|
1739
|
+
adapterMethod: "getMotion"
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
id: "objectDetection",
|
|
1743
|
+
label: "Object Detection",
|
|
1744
|
+
sources: {
|
|
1745
|
+
frigate: false,
|
|
1746
|
+
scrypted: true,
|
|
1747
|
+
rtsp: false
|
|
1748
|
+
},
|
|
1749
|
+
adapterMethod: "getObjectDetections"
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
id: "audioVolume",
|
|
1753
|
+
label: "Audio Level",
|
|
1754
|
+
sources: {
|
|
1755
|
+
frigate: false,
|
|
1756
|
+
scrypted: true,
|
|
1757
|
+
rtsp: false
|
|
1758
|
+
},
|
|
1759
|
+
adapterMethod: "getAudioVolume"
|
|
1760
|
+
},
|
|
1761
|
+
{
|
|
1762
|
+
id: "audioVolumes",
|
|
1763
|
+
label: "Audio Volumes (dBFS)",
|
|
1764
|
+
sources: {
|
|
1765
|
+
frigate: false,
|
|
1766
|
+
scrypted: true,
|
|
1767
|
+
rtsp: false
|
|
1768
|
+
},
|
|
1769
|
+
adapterMethod: "getAudioVolumes"
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
id: "ptz",
|
|
1773
|
+
label: "PTZ Control",
|
|
1774
|
+
sources: {
|
|
1775
|
+
frigate: false,
|
|
1776
|
+
scrypted: true,
|
|
1777
|
+
rtsp: false
|
|
1778
|
+
},
|
|
1779
|
+
adapterMethod: "getPTZ"
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
id: "intercom",
|
|
1783
|
+
label: "Intercom (Mic)",
|
|
1784
|
+
sources: {
|
|
1785
|
+
frigate: false,
|
|
1786
|
+
scrypted: true,
|
|
1787
|
+
rtsp: false
|
|
1788
|
+
},
|
|
1789
|
+
adapterMethod: "getIntercomSupport"
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
id: "deviceStatus",
|
|
1793
|
+
label: "Device Status",
|
|
1794
|
+
sources: {
|
|
1795
|
+
frigate: false,
|
|
1796
|
+
scrypted: true,
|
|
1797
|
+
rtsp: false
|
|
1798
|
+
},
|
|
1799
|
+
adapterMethod: "getStatus"
|
|
1800
|
+
},
|
|
1801
|
+
{
|
|
1802
|
+
id: "timeline",
|
|
1803
|
+
label: "Detection Timeline",
|
|
1804
|
+
sources: {
|
|
1805
|
+
frigate: true,
|
|
1806
|
+
scrypted: true,
|
|
1807
|
+
rtsp: false
|
|
1808
|
+
},
|
|
1809
|
+
adapterMethod: "getCameraDayData"
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
id: "clusteredTimeline",
|
|
1813
|
+
label: "Clustered Timeline",
|
|
1814
|
+
sources: {
|
|
1815
|
+
frigate: true,
|
|
1816
|
+
scrypted: true,
|
|
1817
|
+
rtsp: false
|
|
1818
|
+
},
|
|
1819
|
+
requiresBackend: true,
|
|
1820
|
+
adapterMethod: "getClusteredDayData"
|
|
1821
|
+
},
|
|
1822
|
+
{
|
|
1823
|
+
id: "detectionClasses",
|
|
1824
|
+
label: "Detection Classes",
|
|
1825
|
+
sources: {
|
|
1826
|
+
frigate: true,
|
|
1827
|
+
scrypted: true,
|
|
1828
|
+
rtsp: false
|
|
1829
|
+
},
|
|
1830
|
+
adapterMethod: "getDetectionClasses"
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
id: "videoClips",
|
|
1834
|
+
label: "Video Clips",
|
|
1835
|
+
sources: {
|
|
1836
|
+
frigate: true,
|
|
1837
|
+
scrypted: true,
|
|
1838
|
+
rtsp: false
|
|
1839
|
+
},
|
|
1840
|
+
adapterMethod: "getVideoClips"
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
id: "nvrPlayback",
|
|
1844
|
+
label: "NVR Playback",
|
|
1845
|
+
sources: {
|
|
1846
|
+
frigate: true,
|
|
1847
|
+
scrypted: true,
|
|
1848
|
+
rtsp: false
|
|
1849
|
+
},
|
|
1850
|
+
adapterMethod: "getNvrPlaybackSupported"
|
|
1851
|
+
},
|
|
1852
|
+
{
|
|
1853
|
+
id: "nvrScrub",
|
|
1854
|
+
label: "NVR Scrub/Seek",
|
|
1855
|
+
sources: {
|
|
1856
|
+
frigate: false,
|
|
1857
|
+
scrypted: true,
|
|
1858
|
+
rtsp: false
|
|
1859
|
+
},
|
|
1860
|
+
adapterMethod: "seekRecordingStream"
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
id: "recordingThumbnail",
|
|
1864
|
+
label: "Recording Thumbnails",
|
|
1865
|
+
sources: {
|
|
1866
|
+
frigate: true,
|
|
1867
|
+
scrypted: true,
|
|
1868
|
+
rtsp: false
|
|
1869
|
+
},
|
|
1870
|
+
adapterMethod: "getRecordingStreamThumbnail"
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
id: "nvrSeekToLive",
|
|
1874
|
+
label: "Seek to Live",
|
|
1875
|
+
sources: {
|
|
1876
|
+
frigate: false,
|
|
1877
|
+
scrypted: true,
|
|
1878
|
+
rtsp: false
|
|
1879
|
+
},
|
|
1880
|
+
adapterMethod: "seekNvrToLive"
|
|
1881
|
+
}
|
|
1954
1882
|
];
|
|
1883
|
+
/** Check if a feature is available for a given source type and platform. */
|
|
1955
1884
|
function isFeatureAvailable(featureId, source, platform) {
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1885
|
+
const entry = FEATURE_MATRIX.find((f) => f.id === featureId);
|
|
1886
|
+
if (!entry) return false;
|
|
1887
|
+
if (!entry.sources[source]) return false;
|
|
1888
|
+
if (entry.platforms && entry.platforms[platform] === false) return false;
|
|
1889
|
+
return true;
|
|
1961
1890
|
}
|
|
1891
|
+
/** Get all features supported by a source type. */
|
|
1962
1892
|
function getSourceFeatures(source) {
|
|
1963
|
-
|
|
1893
|
+
return FEATURE_MATRIX.filter((f) => f.sources[source]);
|
|
1964
1894
|
}
|
|
1895
|
+
/** Get all features that require the backend proxy. */
|
|
1965
1896
|
function getBackendRequiredFeatures() {
|
|
1966
|
-
|
|
1897
|
+
return FEATURE_MATRIX.filter((f) => f.requiresBackend);
|
|
1967
1898
|
}
|
|
1899
|
+
//#endregion
|
|
1968
1900
|
exports.DEFAULT_ENABLED_CLASSES = DEFAULT_ENABLED_CLASSES;
|
|
1969
1901
|
exports.DetectionClass = DetectionClass;
|
|
1970
1902
|
exports.ELIGIBLE_HA_DOMAINS = ELIGIBLE_HA_DOMAINS;
|
|
@@ -2012,4 +1944,3 @@ exports.personClasses = personClasses;
|
|
|
2012
1944
|
exports.raceFastestEndpoint = raceFastestEndpoint;
|
|
2013
1945
|
exports.sensorLabelClasses = sensorLabelClasses;
|
|
2014
1946
|
exports.vehicleClasses = vehicleClasses;
|
|
2015
|
-
//# sourceMappingURL=index.cjs.map
|