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