@camstack/addon-model-studio 1.1.204 → 1.1.206
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/{MotionZonesSettings-f-Rb4FPx.mjs → MotionZonesSettings-C5YcAYX9.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-DzrwiikK.mjs → PrivacyMaskSettings-B1M6BI5F.mjs} +4 -4
- package/dist/{SceneMonitorEditor-pr_u7JDi.mjs → SceneMonitorEditor-8Nn6yjHl.mjs} +3 -3
- package/dist/_stub.js +5102 -4909
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DD6MdVfP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-B4UQ5mJi.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-2O40KrYq.mjs +26 -0
- package/dist/{hostInit-dZ-iNlYE.mjs → hostInit-95eIoNUt.mjs} +2 -2
- package/dist/model-studio.addon.js +289 -34
- package/dist/model-studio.addon.mjs +289 -34
- package/dist/{player-overlays-DyoPwbMr.mjs → player-overlays-lpfo2ab8.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-_Hjo-SPS.mjs → responsive-CO_rI6GL.mjs} +1 -1
- package/dist/{scene-monitor-copy-DxG4-n1Z.mjs → scene-monitor-copy-Dx3Cq-sD.mjs} +1 -1
- package/dist/{square-BIirO7Z1.mjs → square-DQHBxjsn.mjs} +1 -1
- package/dist/{trash-2-B9qboTSI.mjs → trash-2-C6kfv9xl.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-DExLMP5B.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CXb44kDc.mjs} +1 -1
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Cjm3a0Rl.mjs +0 -26
|
@@ -5773,7 +5773,7 @@ var ZodIssueCode = {
|
|
|
5773
5773
|
var ZodFirstPartyTypeKind;
|
|
5774
5774
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5775
5775
|
//#endregion
|
|
5776
|
-
//#region ../types/dist/sleep-
|
|
5776
|
+
//#region ../types/dist/sleep-C16NCZR2.mjs
|
|
5777
5777
|
/**
|
|
5778
5778
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5779
5779
|
* window to float samples (D455).
|
|
@@ -11150,6 +11150,19 @@ var ModelProviderIdSchema = _enum([
|
|
|
11150
11150
|
"custom"
|
|
11151
11151
|
]);
|
|
11152
11152
|
/**
|
|
11153
|
+
* Resolve a catalog entry's picker provider. An explicit stamp always wins;
|
|
11154
|
+
* otherwise Frigate/Scrypted are recognised from id prefix or description.
|
|
11155
|
+
* Unstamped BYO registry rows fall through to `custom`. Family `yolov9` is
|
|
11156
|
+
* NOT a Scrypted signal — CamStack ships that family too.
|
|
11157
|
+
*/
|
|
11158
|
+
function inferModelProvider(entry) {
|
|
11159
|
+
if (entry.provider !== void 0) return entry.provider;
|
|
11160
|
+
const haystack = `${entry.id} ${entry.description ?? ""}`;
|
|
11161
|
+
if (/scrypted/i.test(haystack)) return "scrypted";
|
|
11162
|
+
if (/frigate/i.test(haystack)) return "frigate";
|
|
11163
|
+
return "custom";
|
|
11164
|
+
}
|
|
11165
|
+
/**
|
|
11153
11166
|
* The licence of a model, as a record rather than a bare SPDX string: a
|
|
11154
11167
|
* permissive CODE licence routinely sits on top of restrictive WEIGHTS or
|
|
11155
11168
|
* DATA, and the obligations (attribution, modification notices, source offers)
|
|
@@ -16549,6 +16562,12 @@ method(_void(), array(string()).readonly(), { auth: "admin" }), method(object({
|
|
|
16549
16562
|
kind: "mutation",
|
|
16550
16563
|
auth: "admin"
|
|
16551
16564
|
});
|
|
16565
|
+
var HUB_ADDRESS_ROLES = [
|
|
16566
|
+
"appConnections",
|
|
16567
|
+
"notificationTaps",
|
|
16568
|
+
"internal",
|
|
16569
|
+
"publicEndpoint"
|
|
16570
|
+
];
|
|
16552
16571
|
/**
|
|
16553
16572
|
* Transport bounds for AI capability methods.
|
|
16554
16573
|
*
|
|
@@ -20726,7 +20745,13 @@ var NcAlarmModeDelaysListSchema = array(object({
|
|
|
20726
20745
|
* Absent = false (logged, not sent). Even when true it is not sent when that same sensor
|
|
20727
20746
|
* is the one that starts the entry delay — the entry-delay notification already names it.
|
|
20728
20747
|
*/
|
|
20729
|
-
notifySensorRewatched: boolean().optional()
|
|
20748
|
+
notifySensorRewatched: boolean().optional(),
|
|
20749
|
+
/**
|
|
20750
|
+
* D735: notify "ignored" when a sensor this arm bypassed really MOVED while armed (its own
|
|
20751
|
+
* change time is after the arm) and set nothing off. Absent = false (logged, not sent). A
|
|
20752
|
+
* re-sync, a recovery from `unavailable` or a duplicate is never announced, switch or not.
|
|
20753
|
+
*/
|
|
20754
|
+
notifySensorIgnored: boolean().optional()
|
|
20730
20755
|
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
20731
20756
|
var NcAlarmModeDelaysEditListSchema = array(object({
|
|
20732
20757
|
mode: AlarmArmModeSchema,
|
|
@@ -20739,7 +20764,9 @@ var NcAlarmModeDelaysEditListSchema = array(object({
|
|
|
20739
20764
|
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
20740
20765
|
notifyDuringEntryDelay: boolean().nullable().optional(),
|
|
20741
20766
|
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
20742
|
-
notifySensorRewatched: boolean().nullable().optional()
|
|
20767
|
+
notifySensorRewatched: boolean().nullable().optional(),
|
|
20768
|
+
/** D735: set the switch, or `null` to clear it (back to the default, false). */
|
|
20769
|
+
notifySensorIgnored: boolean().nullable().optional()
|
|
20743
20770
|
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
20744
20771
|
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
20745
20772
|
var NcAlarmNonBlockingEditSchema = object({
|
|
@@ -28491,6 +28518,14 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
|
|
|
28491
28518
|
*/
|
|
28492
28519
|
alive: boolean()
|
|
28493
28520
|
})), method(object({
|
|
28521
|
+
deviceId: number().int().nonnegative(),
|
|
28522
|
+
sessionId: string(),
|
|
28523
|
+
downlinkMbps: number().nonnegative()
|
|
28524
|
+
}), object({
|
|
28525
|
+
outcome: _enum(["switching", "held"]),
|
|
28526
|
+
tier: CamProfileSchema.nullable(),
|
|
28527
|
+
reason: string()
|
|
28528
|
+
}), { kind: "mutation" }), method(object({
|
|
28494
28529
|
deviceId: number().int().nonnegative(),
|
|
28495
28530
|
sessionId: string()
|
|
28496
28531
|
}), WebrtcSessionDebugSchema, { kind: "query" });
|
|
@@ -31166,7 +31201,8 @@ var ConnectionEndpointSchema = object({
|
|
|
31166
31201
|
"lan-ipv6",
|
|
31167
31202
|
"public",
|
|
31168
31203
|
"loopback",
|
|
31169
|
-
"app-link"
|
|
31204
|
+
"app-link",
|
|
31205
|
+
"custom"
|
|
31170
31206
|
]),
|
|
31171
31207
|
/**
|
|
31172
31208
|
* Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
|
|
@@ -31235,7 +31271,7 @@ var GetConnectionEndpointsResultSchema = object({
|
|
|
31235
31271
|
localPort: AdvertisedLocalPortSchema
|
|
31236
31272
|
});
|
|
31237
31273
|
/**
|
|
31238
|
-
* The address flagged for notification
|
|
31274
|
+
* The address flagged for notification taps (`notificationTaps`). `baseUrl: null` = AUTO, which
|
|
31239
31275
|
* since D709 is the CamStack app link; `resolved` reports the effective value,
|
|
31240
31276
|
* so the UI can show it either way.
|
|
31241
31277
|
*/
|
|
@@ -31269,13 +31305,12 @@ var ViewerEndpointsSchema = object({
|
|
|
31269
31305
|
resolved: array(string()).readonly()
|
|
31270
31306
|
});
|
|
31271
31307
|
/**
|
|
31272
|
-
*
|
|
31273
|
-
*
|
|
31308
|
+
* DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
|
|
31309
|
+
* for addons built against it): `cluster` is the `internal` role, `browser`
|
|
31310
|
+
* the `publicEndpoint` role; `override` is the flagged address.
|
|
31274
31311
|
*/
|
|
31275
31312
|
var HubAddressSnapshotSchema = object({
|
|
31276
|
-
/** The operator's override, or null for automatic. */
|
|
31277
31313
|
override: string().nullable(),
|
|
31278
|
-
/** The address in use, or null when nothing qualifies (never loopback). */
|
|
31279
31314
|
resolved: string().nullable(),
|
|
31280
31315
|
source: _enum([
|
|
31281
31316
|
"override",
|
|
@@ -31284,11 +31319,57 @@ var HubAddressSnapshotSchema = object({
|
|
|
31284
31319
|
])
|
|
31285
31320
|
});
|
|
31286
31321
|
var HubAddressesSchema = object({
|
|
31287
|
-
/** "Hub address for agents" — agents' bundle/model pulls, LAN devices. */
|
|
31288
31322
|
cluster: HubAddressSnapshotSchema,
|
|
31289
|
-
/** "Public address for sign-in links" — e-mail links, OIDC, WebAuthn, OAuth2. */
|
|
31290
31323
|
browser: HubAddressSnapshotSchema
|
|
31291
31324
|
});
|
|
31325
|
+
/**
|
|
31326
|
+
* What an address is used for (`hub-address.ts`, D734). `appConnections` is
|
|
31327
|
+
* many-valued; `notificationTaps`, `publicEndpoint` and `internal` are carried
|
|
31328
|
+
* by at most one address.
|
|
31329
|
+
*/
|
|
31330
|
+
var HubAddressRoleSchema = _enum(HUB_ADDRESS_ROLES);
|
|
31331
|
+
var RoleSourceSchema = _enum([
|
|
31332
|
+
"flagged",
|
|
31333
|
+
"auto",
|
|
31334
|
+
"none"
|
|
31335
|
+
]);
|
|
31336
|
+
/** One single-valued role: the flagged address, the one in use, and why. */
|
|
31337
|
+
var HubAddressRoleResolutionSchema = object({
|
|
31338
|
+
/** The address carrying the flag, or null = automatic. */
|
|
31339
|
+
flagged: string().nullable(),
|
|
31340
|
+
/** The address in use, or null when nothing qualifies (never loopback). */
|
|
31341
|
+
resolved: string().nullable(),
|
|
31342
|
+
source: RoleSourceSchema
|
|
31343
|
+
});
|
|
31344
|
+
var HubAppConnectionsResolutionSchema = object({
|
|
31345
|
+
/** The addresses flagged `appConnections`, or empty = automatic. */
|
|
31346
|
+
flagged: array(string()).readonly(),
|
|
31347
|
+
/** What the apps race right now. */
|
|
31348
|
+
resolved: array(string()).readonly(),
|
|
31349
|
+
source: RoleSourceSchema
|
|
31350
|
+
});
|
|
31351
|
+
var HubAddressBookSchema = object({
|
|
31352
|
+
rows: array(ConnectionEndpointSchema.extend({
|
|
31353
|
+
/** In the hub's detected palette right now. */
|
|
31354
|
+
detected: boolean(),
|
|
31355
|
+
/** Entered by the operator (removable). */
|
|
31356
|
+
custom: boolean(),
|
|
31357
|
+
/** The roles explicitly flagged on this address. */
|
|
31358
|
+
flags: array(HubAddressRoleSchema).readonly(),
|
|
31359
|
+
/** The roles this address serves right now — flagged or automatic. */
|
|
31360
|
+
inUse: array(HubAddressRoleSchema).readonly(),
|
|
31361
|
+
/** The roles this address may be flagged with. */
|
|
31362
|
+
eligible: array(HubAddressRoleSchema).readonly()
|
|
31363
|
+
})).readonly(),
|
|
31364
|
+
roles: object({
|
|
31365
|
+
appConnections: HubAppConnectionsResolutionSchema,
|
|
31366
|
+
notificationTaps: HubAddressRoleResolutionSchema,
|
|
31367
|
+
internal: HubAddressRoleResolutionSchema,
|
|
31368
|
+
publicEndpoint: HubAddressRoleResolutionSchema
|
|
31369
|
+
}),
|
|
31370
|
+
/** The `hub=` an app link carries (D709), or null. */
|
|
31371
|
+
appLinkHub: string().nullable()
|
|
31372
|
+
});
|
|
31292
31373
|
var AllowedAddressesSchema = object({
|
|
31293
31374
|
/**
|
|
31294
31375
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -31332,16 +31413,27 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
31332
31413
|
* tunnel always emits `https://` regardless. */
|
|
31333
31414
|
scheme: _enum(["http", "https"]).optional(),
|
|
31334
31415
|
/** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
|
|
31335
|
-
* an address notification
|
|
31416
|
+
* an address notification taps can be flagged with, not a hub
|
|
31336
31417
|
* route. Default `false`: racers and rankers never see it. */
|
|
31337
31418
|
includeAppLink: boolean().optional()
|
|
31338
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(
|
|
31339
|
-
|
|
31340
|
-
|
|
31341
|
-
}),
|
|
31419
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(object({ scheme: _enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema), method(object({
|
|
31420
|
+
baseUrl: string(),
|
|
31421
|
+
label: string().max(80)
|
|
31422
|
+
}), HubAddressBookSchema, {
|
|
31342
31423
|
kind: "mutation",
|
|
31343
31424
|
auth: "admin"
|
|
31344
|
-
}), method(
|
|
31425
|
+
}), method(object({ baseUrl: string() }), HubAddressBookSchema, {
|
|
31426
|
+
kind: "mutation",
|
|
31427
|
+
auth: "admin"
|
|
31428
|
+
}), method(object({
|
|
31429
|
+
role: HubAddressRoleSchema,
|
|
31430
|
+
baseUrl: string().nullable(),
|
|
31431
|
+
enabled: boolean(),
|
|
31432
|
+
acceptInsecureHttp: boolean().optional()
|
|
31433
|
+
}), HubAddressBookSchema, {
|
|
31434
|
+
kind: "mutation",
|
|
31435
|
+
auth: "admin"
|
|
31436
|
+
}), method(_void(), HubAddressesSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
31345
31437
|
kind: "mutation",
|
|
31346
31438
|
auth: "admin"
|
|
31347
31439
|
}), method(object({
|
|
@@ -39868,12 +39960,24 @@ Object.freeze({
|
|
|
39868
39960
|
addonId: null,
|
|
39869
39961
|
access: "view"
|
|
39870
39962
|
},
|
|
39963
|
+
"localNetwork.addCustomAddress": {
|
|
39964
|
+
capName: "local-network",
|
|
39965
|
+
capScope: "system",
|
|
39966
|
+
addonId: null,
|
|
39967
|
+
access: "create"
|
|
39968
|
+
},
|
|
39871
39969
|
"localNetwork.downloadCa": {
|
|
39872
39970
|
capName: "local-network",
|
|
39873
39971
|
capScope: "system",
|
|
39874
39972
|
addonId: null,
|
|
39875
39973
|
access: "view"
|
|
39876
39974
|
},
|
|
39975
|
+
"localNetwork.getAddresses": {
|
|
39976
|
+
capName: "local-network",
|
|
39977
|
+
capScope: "system",
|
|
39978
|
+
addonId: null,
|
|
39979
|
+
access: "view"
|
|
39980
|
+
},
|
|
39877
39981
|
"localNetwork.getAllowedAddresses": {
|
|
39878
39982
|
capName: "local-network",
|
|
39879
39983
|
capScope: "system",
|
|
@@ -39928,6 +40032,12 @@ Object.freeze({
|
|
|
39928
40032
|
addonId: null,
|
|
39929
40033
|
access: "create"
|
|
39930
40034
|
},
|
|
40035
|
+
"localNetwork.removeCustomAddress": {
|
|
40036
|
+
capName: "local-network",
|
|
40037
|
+
capScope: "system",
|
|
40038
|
+
addonId: null,
|
|
40039
|
+
access: "delete"
|
|
40040
|
+
},
|
|
39931
40041
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
39932
40042
|
capName: "local-network",
|
|
39933
40043
|
capScope: "system",
|
|
@@ -39940,13 +40050,13 @@ Object.freeze({
|
|
|
39940
40050
|
addonId: null,
|
|
39941
40051
|
access: "create"
|
|
39942
40052
|
},
|
|
39943
|
-
"localNetwork.
|
|
40053
|
+
"localNetwork.setAddressRole": {
|
|
39944
40054
|
capName: "local-network",
|
|
39945
40055
|
capScope: "system",
|
|
39946
40056
|
addonId: null,
|
|
39947
40057
|
access: "create"
|
|
39948
40058
|
},
|
|
39949
|
-
"localNetwork.
|
|
40059
|
+
"localNetwork.setAllowedAddresses": {
|
|
39950
40060
|
capName: "local-network",
|
|
39951
40061
|
capScope: "system",
|
|
39952
40062
|
addonId: null,
|
|
@@ -44200,6 +44310,12 @@ Object.freeze({
|
|
|
44200
44310
|
addonId: null,
|
|
44201
44311
|
access: "create"
|
|
44202
44312
|
},
|
|
44313
|
+
"webrtcSession.applyDownlinkProbe": {
|
|
44314
|
+
capName: "webrtc-session",
|
|
44315
|
+
capScope: "device",
|
|
44316
|
+
addonId: null,
|
|
44317
|
+
access: "create"
|
|
44318
|
+
},
|
|
44203
44319
|
"webrtcSession.closeSession": {
|
|
44204
44320
|
capName: "webrtc-session",
|
|
44205
44321
|
capScope: "device",
|
|
@@ -48122,6 +48238,11 @@ Object.freeze({
|
|
|
48122
48238
|
form: "single",
|
|
48123
48239
|
optional: false
|
|
48124
48240
|
}],
|
|
48241
|
+
"webrtcSession.applyDownlinkProbe": [{
|
|
48242
|
+
name: "deviceId",
|
|
48243
|
+
form: "single",
|
|
48244
|
+
optional: false
|
|
48245
|
+
}],
|
|
48125
48246
|
"webrtcSession.closeSession": [{
|
|
48126
48247
|
name: "deviceId",
|
|
48127
48248
|
form: "single",
|
|
@@ -49390,6 +49511,35 @@ function buildModelConvertProvider(deps) {
|
|
|
49390
49511
|
};
|
|
49391
49512
|
} };
|
|
49392
49513
|
}
|
|
49514
|
+
var CONTROL_CHARS = /[\u0000-\u001f\u007f]/;
|
|
49515
|
+
/** Whitespace runs collapse to one space; leading/trailing whitespace goes. */
|
|
49516
|
+
function parseDisplayName(raw) {
|
|
49517
|
+
const name = raw.replace(/\s+/g, " ").trim();
|
|
49518
|
+
if (name.length === 0) return { kind: "reset" };
|
|
49519
|
+
if (CONTROL_CHARS.test(name)) return {
|
|
49520
|
+
kind: "invalid",
|
|
49521
|
+
reason: "The name contains control characters."
|
|
49522
|
+
};
|
|
49523
|
+
if (name.length > 80) return {
|
|
49524
|
+
kind: "invalid",
|
|
49525
|
+
reason: `The name is ${name.length} characters long; the limit is 80.`
|
|
49526
|
+
};
|
|
49527
|
+
return {
|
|
49528
|
+
kind: "set",
|
|
49529
|
+
name
|
|
49530
|
+
};
|
|
49531
|
+
}
|
|
49532
|
+
/**
|
|
49533
|
+
* The optional display name typed on an import card: `undefined` when left
|
|
49534
|
+
* empty (the source's own default applies), the cleaned name otherwise.
|
|
49535
|
+
* Throws with the reason when the input is not acceptable.
|
|
49536
|
+
*/
|
|
49537
|
+
function optionalImportName(raw) {
|
|
49538
|
+
if (raw === void 0) return void 0;
|
|
49539
|
+
const parsed = parseDisplayName(raw);
|
|
49540
|
+
if (parsed.kind === "invalid") throw new Error(`Display name rejected: ${parsed.reason}`);
|
|
49541
|
+
return parsed.kind === "set" ? parsed.name : void 0;
|
|
49542
|
+
}
|
|
49393
49543
|
//#endregion
|
|
49394
49544
|
//#region src/model-registry.ts
|
|
49395
49545
|
/**
|
|
@@ -49421,22 +49571,18 @@ function upsertAvailability(map, modelId, nodeId, entry) {
|
|
|
49421
49571
|
});
|
|
49422
49572
|
}
|
|
49423
49573
|
/**
|
|
49424
|
-
* Pure registry operations over the custom-model list. Kept side-effect-free
|
|
49425
|
-
* so they unit-test without a live `BaseAddon` context — the addon class is a
|
|
49426
|
-
* thin durable-state wrapper around these.
|
|
49427
|
-
*/
|
|
49428
|
-
/**
|
|
49429
49574
|
* Insert or replace a descriptor keyed by `entry.id`. When the id already
|
|
49430
49575
|
* exists, **formats are merged** (Scrypted multi-format accumulate) — sibling
|
|
49431
49576
|
* formats on the prior entry are never dropped. Returns a new array.
|
|
49432
49577
|
*/
|
|
49433
|
-
function upsertCustomModel(list, descriptor) {
|
|
49578
|
+
function upsertCustomModel(list, descriptor, nameOrigin = "source") {
|
|
49434
49579
|
const prev = list.find((m) => m.entry.id === descriptor.entry.id);
|
|
49435
49580
|
const merged = prev === void 0 ? descriptor : {
|
|
49436
49581
|
stepId: descriptor.stepId,
|
|
49437
49582
|
entry: {
|
|
49438
49583
|
...prev.entry,
|
|
49439
49584
|
...descriptor.entry,
|
|
49585
|
+
name: nameOrigin === "operator" ? descriptor.entry.name : prev.entry.name,
|
|
49440
49586
|
formats: {
|
|
49441
49587
|
...prev.entry.formats,
|
|
49442
49588
|
...descriptor.entry.formats
|
|
@@ -49445,6 +49591,43 @@ function upsertCustomModel(list, descriptor) {
|
|
|
49445
49591
|
};
|
|
49446
49592
|
return [...list.filter((m) => m.entry.id !== descriptor.entry.id), merged];
|
|
49447
49593
|
}
|
|
49594
|
+
/**
|
|
49595
|
+
* Rename one IMPORTED registry row in place. Only `entry.name` changes — the
|
|
49596
|
+
* id, step, formats and every pin keyed by the id stay exactly as they were.
|
|
49597
|
+
* An empty name resets the row to the name it was imported with. Throws on an
|
|
49598
|
+
* unknown id, a CamStack catalog row, or a name `parseDisplayName` rejects.
|
|
49599
|
+
*/
|
|
49600
|
+
function renameCustomModel(list, importedNames, modelId, rawName) {
|
|
49601
|
+
const row = list.find((m) => m.entry.id === modelId);
|
|
49602
|
+
if (row === void 0) throw new Error(`renameCustomModel: model "${modelId}" is not registered`);
|
|
49603
|
+
if (!isRenameableEntry(row.entry)) throw new Error(`renameCustomModel: "${modelId}" is a CamStack catalog model and keeps its name`);
|
|
49604
|
+
const parsed = parseDisplayName(rawName);
|
|
49605
|
+
if (parsed.kind === "invalid") throw new Error(`renameCustomModel: ${parsed.reason}`);
|
|
49606
|
+
const original = importedNames[modelId] ?? row.entry.name;
|
|
49607
|
+
const name = parsed.kind === "set" ? parsed.name : original;
|
|
49608
|
+
const nextNames = { ...importedNames };
|
|
49609
|
+
if (parsed.kind === "set" && name !== original) nextNames[modelId] = original;
|
|
49610
|
+
else delete nextNames[modelId];
|
|
49611
|
+
return {
|
|
49612
|
+
list: list.map((m) => m.entry.id === modelId ? {
|
|
49613
|
+
stepId: m.stepId,
|
|
49614
|
+
entry: {
|
|
49615
|
+
...m.entry,
|
|
49616
|
+
name
|
|
49617
|
+
}
|
|
49618
|
+
} : m),
|
|
49619
|
+
importedNames: nextNames,
|
|
49620
|
+
name
|
|
49621
|
+
};
|
|
49622
|
+
}
|
|
49623
|
+
/** An imported row can be renamed; a CamStack catalog model cannot. */
|
|
49624
|
+
function isRenameableEntry(entry) {
|
|
49625
|
+
return inferModelProvider({
|
|
49626
|
+
id: entry.id,
|
|
49627
|
+
description: entry.description,
|
|
49628
|
+
provider: entry.provider
|
|
49629
|
+
}) !== "camstack";
|
|
49630
|
+
}
|
|
49448
49631
|
/** Drop the descriptor with the given `entry.id`. Reports whether anything changed. */
|
|
49449
49632
|
function removeCustomModel(list, modelId) {
|
|
49450
49633
|
const next = list.filter((m) => m.entry.id !== modelId);
|
|
@@ -50292,6 +50475,19 @@ var modelStudioActions = defineCustomActions({
|
|
|
50292
50475
|
clearedPins: number().int().nonnegative()
|
|
50293
50476
|
}), { kind: "mutation" }),
|
|
50294
50477
|
/**
|
|
50478
|
+
* Rename an IMPORTED registry row (Frigate, Frigate+, Scrypted, uploads,
|
|
50479
|
+
* conversions) in place. Only `entry.name` changes — never the id, so pins
|
|
50480
|
+
* and availability are untouched. An empty name restores the name the model
|
|
50481
|
+
* was imported with. CamStack catalog models are refused.
|
|
50482
|
+
*/
|
|
50483
|
+
renameCustomModel: customAction(object({
|
|
50484
|
+
modelId: string().min(1),
|
|
50485
|
+
name: string()
|
|
50486
|
+
}), object({
|
|
50487
|
+
modelId: string(),
|
|
50488
|
+
name: string()
|
|
50489
|
+
}), { kind: "mutation" }),
|
|
50490
|
+
/**
|
|
50295
50491
|
* Delete one format of a Library model from one node. Keeps the registry row
|
|
50296
50492
|
* and sibling formats/nodes; clears only that availability chip.
|
|
50297
50493
|
*/
|
|
@@ -50380,6 +50576,8 @@ var modelStudioActions = defineCustomActions({
|
|
|
50380
50576
|
})),
|
|
50381
50577
|
importScryptedCatalogModel: customAction(object({
|
|
50382
50578
|
manifestId: string(),
|
|
50579
|
+
/** Optional display name typed on the import card. */
|
|
50580
|
+
name: string().optional(),
|
|
50383
50581
|
targetNodeId: string().optional()
|
|
50384
50582
|
}), CustomModelDescriptorSchema, { kind: "mutation" }),
|
|
50385
50583
|
/**
|
|
@@ -50409,7 +50607,8 @@ var modelStudioActions = defineCustomActions({
|
|
|
50409
50607
|
modelId: string().optional(),
|
|
50410
50608
|
name: string().optional(),
|
|
50411
50609
|
/**
|
|
50412
|
-
* Native artifact class
|
|
50610
|
+
* Native artifact class of the chosen build (`plusImportLane`: neural →
|
|
50611
|
+
* onnx, coral → tflite). The
|
|
50413
50612
|
* model-detail API does not always carry `supportedDetectors`, so the
|
|
50414
50613
|
* browser passes what the catalog already knew (fixes ssd/yolo-generic
|
|
50415
50614
|
* EdgeTPU rows that `plusTypeTraits` alone would call onnx).
|
|
@@ -50461,6 +50660,8 @@ var modelStudioActions = defineCustomActions({
|
|
|
50461
50660
|
//#region src/model-studio.addon.ts
|
|
50462
50661
|
var KEY_CUSTOM_MODELS = "customModels";
|
|
50463
50662
|
var KEY_AVAILABILITY = "availability";
|
|
50663
|
+
var KEY_IMPORTED_NAMES = "importedNames";
|
|
50664
|
+
var ImportedNamesSchema = record(string(), string());
|
|
50464
50665
|
var CustomModelsSchema = array(CustomModelDescriptorSchema);
|
|
50465
50666
|
var pythonDirCache;
|
|
50466
50667
|
function resolveAddonPythonDir() {
|
|
@@ -50523,12 +50724,18 @@ function spawnRunConvert(jobPath, pythonPath, onProgress, _sessionId) {
|
|
|
50523
50724
|
});
|
|
50524
50725
|
});
|
|
50525
50726
|
}
|
|
50727
|
+
/** A name the operator typed replaces an existing row's name; a derived one never does. */
|
|
50728
|
+
function nameOriginOf(operatorName) {
|
|
50729
|
+
return operatorName !== void 0 ? { nameOrigin: "operator" } : {};
|
|
50730
|
+
}
|
|
50526
50731
|
/** Global-fetch adapter for the injected Frigate+ client seam. */
|
|
50527
50732
|
var plusFetch = async (url, init) => fetch(url, init);
|
|
50528
50733
|
var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
50529
50734
|
id = "model-studio";
|
|
50530
50735
|
modelsState = null;
|
|
50531
50736
|
availabilityState = null;
|
|
50737
|
+
/** modelId → the name a renamed registry row had before its first rename. */
|
|
50738
|
+
importedNamesState = null;
|
|
50532
50739
|
/** Lazily-built chunked-upload store (hub only) — see `upload/model-upload-store.ts`. */
|
|
50533
50740
|
uploadStore = null;
|
|
50534
50741
|
/**
|
|
@@ -50611,6 +50818,7 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50611
50818
|
const state = this.state(KEY_CUSTOM_MODELS, CustomModelsSchema, []);
|
|
50612
50819
|
this.modelsState = state;
|
|
50613
50820
|
this.availabilityState = this.state(KEY_AVAILABILITY, ModelAvailabilityMapSchema, {});
|
|
50821
|
+
this.importedNamesState = this.state(KEY_IMPORTED_NAMES, ImportedNamesSchema, {});
|
|
50614
50822
|
const rawNode = this.ctx.kernel?.localNodeId ?? "hub";
|
|
50615
50823
|
const isHub = (rawNode.includes("/") ? rawNode.split("/")[0] : rawNode) === "hub";
|
|
50616
50824
|
const pagesProvider = {
|
|
@@ -50644,7 +50852,11 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50644
50852
|
return result;
|
|
50645
50853
|
},
|
|
50646
50854
|
abortModelUpload: async (input) => (await this.getUploadStore()).abort(input),
|
|
50647
|
-
registerCustomModel: async (input) => this.registerCustomModel(input, {
|
|
50855
|
+
registerCustomModel: async (input) => this.registerCustomModel(input, {
|
|
50856
|
+
ensureEngines: true,
|
|
50857
|
+
nameOrigin: "operator"
|
|
50858
|
+
}),
|
|
50859
|
+
renameCustomModel: async (input) => this.renameCustomModel_(input),
|
|
50648
50860
|
ensureFormatsThenDistribute: async (input) => this.ensureFormatsThenDistribute_(input.modelId),
|
|
50649
50861
|
ensureModelFormats: async (input) => this.ensureModelFormats_(input.modelId, input.formats),
|
|
50650
50862
|
removeCustomModel: async (input) => this.removeCustomModel(input),
|
|
@@ -50796,6 +51008,35 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50796
51008
|
if (!this.modelsState) throw new Error("ModelStudioAddon: durable state not initialized");
|
|
50797
51009
|
return this.modelsState;
|
|
50798
51010
|
}
|
|
51011
|
+
get importedNames_() {
|
|
51012
|
+
if (!this.importedNamesState) throw new Error("ModelStudioAddon: imported-names state not initialized");
|
|
51013
|
+
return this.importedNamesState;
|
|
51014
|
+
}
|
|
51015
|
+
/**
|
|
51016
|
+
* Rename an imported registry row in place (`renameCustomModel` decides).
|
|
51017
|
+
* The id is untouched, so pins, availability and files are unaffected; the
|
|
51018
|
+
* pipeline's catalog view picks the new name up on its next registry read.
|
|
51019
|
+
*/
|
|
51020
|
+
async renameCustomModel_(input) {
|
|
51021
|
+
const names = await this.importedNames_.get();
|
|
51022
|
+
const outcome = {};
|
|
51023
|
+
await this.state_.update((prev) => {
|
|
51024
|
+
const renamed = renameCustomModel(prev, names, input.modelId, input.name);
|
|
51025
|
+
outcome.result = renamed;
|
|
51026
|
+
return renamed.list;
|
|
51027
|
+
});
|
|
51028
|
+
const result = outcome.result;
|
|
51029
|
+
if (result === void 0) throw new Error("renameCustomModel: registry update did not run");
|
|
51030
|
+
await this.importedNames_.set(result.importedNames);
|
|
51031
|
+
this.ctx.logger.info("Renamed custom model", { meta: {
|
|
51032
|
+
modelId: input.modelId,
|
|
51033
|
+
name: result.name
|
|
51034
|
+
} });
|
|
51035
|
+
return {
|
|
51036
|
+
modelId: input.modelId,
|
|
51037
|
+
name: result.name
|
|
51038
|
+
};
|
|
51039
|
+
}
|
|
50799
51040
|
get availability_() {
|
|
50800
51041
|
if (!this.availabilityState) throw new Error("ModelStudioAddon: availability state not initialized");
|
|
50801
51042
|
return this.availabilityState;
|
|
@@ -50917,6 +51158,7 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50917
51158
|
* `targetNodeId` lands the HF URL on that node via download-on-target.
|
|
50918
51159
|
*/
|
|
50919
51160
|
async importScryptedCatalogFromManifest(input) {
|
|
51161
|
+
const name = optionalImportName(input.name);
|
|
50920
51162
|
const entry = getScryptedManifestEntry(input.manifestId);
|
|
50921
51163
|
if (!entry) throw new Error(`importScryptedCatalogModel: unknown manifest id "${input.manifestId}"`);
|
|
50922
51164
|
let drift;
|
|
@@ -50936,8 +51178,15 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50936
51178
|
};
|
|
50937
51179
|
}
|
|
50938
51180
|
if (drift.status !== "ok") throw new Error(`importScryptedCatalogModel: entry "${entry.id}" is blocked by drift (${drift.status}${drift.details ? `: ${drift.details}` : ""})`);
|
|
50939
|
-
const
|
|
50940
|
-
|
|
51181
|
+
const built = buildScryptedRegistryDescriptor(entry);
|
|
51182
|
+
const descriptor = name !== void 0 ? {
|
|
51183
|
+
stepId: built.stepId,
|
|
51184
|
+
entry: {
|
|
51185
|
+
...built.entry,
|
|
51186
|
+
name
|
|
51187
|
+
}
|
|
51188
|
+
} : built;
|
|
51189
|
+
await this.registerCustomModel(descriptor, nameOriginOf(name));
|
|
50941
51190
|
if (input.targetNodeId !== void 0 && input.targetNodeId.length > 0) await this.distributeModel({
|
|
50942
51191
|
modelId: descriptor.entry.id,
|
|
50943
51192
|
nodeId: input.targetNodeId,
|
|
@@ -50959,11 +51208,12 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50959
51208
|
async importFrigateCatalogModel(input) {
|
|
50960
51209
|
const cat = FRIGATE_PUBLIC_CATALOG.find((c) => c.id === input.catalogId);
|
|
50961
51210
|
if (!cat) throw new Error(`importFrigateCatalogModel: unknown catalog id "${input.catalogId}"`);
|
|
51211
|
+
const name = optionalImportName(input.name);
|
|
50962
51212
|
const descriptor = buildFrigateCatalogDescriptor(input.catalogId, {
|
|
50963
51213
|
...input.modelId !== void 0 ? { modelId: input.modelId } : {},
|
|
50964
|
-
...
|
|
51214
|
+
...name !== void 0 ? { name } : {}
|
|
50965
51215
|
});
|
|
50966
|
-
await this.registerCustomModel(descriptor);
|
|
51216
|
+
await this.registerCustomModel(descriptor, nameOriginOf(name));
|
|
50967
51217
|
let bytes = Math.round(cat.sizeMB * 1e6);
|
|
50968
51218
|
if (input.targetNodeId !== void 0 && input.targetNodeId.length > 0) {
|
|
50969
51219
|
const landed = await this.distributeModel({
|
|
@@ -50994,6 +51244,7 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
50994
51244
|
*/
|
|
50995
51245
|
async importFrigatePlusModel(input) {
|
|
50996
51246
|
const modelId = frigatePlusRegistryId(input.plusModelId);
|
|
51247
|
+
const operatorName = optionalImportName(input.name);
|
|
50997
51248
|
const key = this.config.frigatePlusApiKey ?? "";
|
|
50998
51249
|
const { info, downloadUrl } = await requestPlusModelDownload(plusFetch, key, input.plusModelId);
|
|
50999
51250
|
const typeTraits = plusTypeTraits(info.type);
|
|
@@ -51018,12 +51269,15 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
51018
51269
|
const sha256 = await ModelStudioAddon.fileSha256(destPath);
|
|
51019
51270
|
const descriptor = plusInfoToDescriptor(info, {
|
|
51020
51271
|
modelId,
|
|
51021
|
-
name:
|
|
51272
|
+
name: operatorName ?? `Frigate+ ${info.type} (${input.plusModelId.slice(0, 8)})`,
|
|
51022
51273
|
filename,
|
|
51023
51274
|
sizeMB: Number((bytes / 1e6).toFixed(1)),
|
|
51024
51275
|
...input.format !== void 0 ? { format: input.format } : {}
|
|
51025
51276
|
});
|
|
51026
|
-
await this.registerCustomModel(descriptor, {
|
|
51277
|
+
await this.registerCustomModel(descriptor, {
|
|
51278
|
+
ensureEngines: false,
|
|
51279
|
+
...nameOriginOf(operatorName)
|
|
51280
|
+
});
|
|
51027
51281
|
await this.availability_.update((prev) => upsertAvailability(prev, modelId, "hub", {
|
|
51028
51282
|
format: traits.format,
|
|
51029
51283
|
sha256,
|
|
@@ -51056,7 +51310,7 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
51056
51310
|
async registerCustomModel(input, opts = {}) {
|
|
51057
51311
|
if (!input.stepId.trim()) throw new Error("registerCustomModel: stepId is required");
|
|
51058
51312
|
if (!input.entry.id.trim()) throw new Error("registerCustomModel: entry.id is required");
|
|
51059
|
-
await this.state_.update((prev) => upsertCustomModel(prev, input));
|
|
51313
|
+
await this.state_.update((prev) => upsertCustomModel(prev, input, opts.nameOrigin));
|
|
51060
51314
|
this.ctx.logger.info("Registered custom model", { meta: {
|
|
51061
51315
|
modelId: input.entry.id,
|
|
51062
51316
|
stepId: input.stepId
|
|
@@ -51313,6 +51567,7 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
51313
51567
|
removed = result.removed;
|
|
51314
51568
|
return result.next;
|
|
51315
51569
|
});
|
|
51570
|
+
await this.importedNames_.update((prev) => Object.fromEntries(Object.entries(prev).filter(([id]) => id !== input.modelId)));
|
|
51316
51571
|
this.ctx.logger.info("Removed custom model", { meta: {
|
|
51317
51572
|
modelId: input.modelId,
|
|
51318
51573
|
removed,
|