@camstack/addon-training 0.1.21 → 0.1.23

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.
Files changed (43) hide show
  1. package/dist/MaskShapeCanvas-BokARvOj.mjs +13806 -0
  2. package/dist/MotionZonesSettings-CwGjtvsX.mjs +310 -0
  3. package/dist/{PrivacyMaskSettings-Bo1S23wt.mjs → PrivacyMaskSettings-CM_WsrKB.mjs} +70 -45
  4. package/dist/{SceneMonitorEditor-DnQJ7Hx3.mjs → SceneMonitorEditor-B-sAJ--C.mjs} +311 -311
  5. package/dist/_stub.js +7372 -16803
  6. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DQi_LrZZ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DKblQaAP.mjs} +2 -2
  7. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ff7X-Xlf.mjs +26 -0
  8. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BSOdwqcC.mjs +26 -0
  9. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-B3rryujf.mjs +25 -0
  10. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-nL4MGFRP.mjs +26 -0
  11. package/dist/{_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-DeDbF7NI.mjs → _virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-BT_wL8s3.mjs} +1 -1
  12. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DDBEvLdo.mjs +26 -0
  13. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom__loadShare__.js-CK-LlgOt.mjs +26 -0
  14. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-gTIQrhKs.mjs +25 -0
  15. package/dist/{dist-BSYBh1ZO.mjs → dist-CVDWIKl7.mjs} +52 -2
  16. package/dist/{dist-BCLkrWJc.js → dist-DwF1P1v7.js} +87 -1
  17. package/dist/{hostInit-Bx2a8M7w.mjs → hostInit-Di0tDODX.mjs} +1 -1
  18. package/dist/index.js +8 -1
  19. package/dist/index.mjs +7 -0
  20. package/dist/orchestrator/training.addon.js +8 -1
  21. package/dist/orchestrator/training.addon.mjs +8 -1
  22. package/dist/{player-overlays-BR2_H0wZ.mjs → player-overlays-BFAqW2L1.mjs} +10 -32
  23. package/dist/providers/modal/training-modal.addon.js +196 -123
  24. package/dist/providers/modal/training-modal.addon.mjs +196 -123
  25. package/dist/remoteEntry.js +1 -1
  26. package/dist/{responsive-emJo3EdF.mjs → responsive-BBlQWFFi.mjs} +38 -42
  27. package/dist/{scene-monitor-copy-CcQxbRXa.mjs → scene-monitor-copy-D5mKGqt0.mjs} +4 -4
  28. package/dist/{square-CErp1WgN.mjs → square-D0FYSm8b.mjs} +4 -29
  29. package/dist/{trash-2-Drz0fMgI.mjs → trash-2-DdjGvgDw.mjs} +1 -1
  30. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-C-uqIKLg.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Dw400Y0a.mjs} +390 -399
  31. package/package.json +1 -1
  32. package/dist/MaskShapeCanvas-Kfg9dl6B.mjs +0 -686
  33. package/dist/MotionZonesSettings-DflIL9ss.mjs +0 -292
  34. package/dist/ReactKonva-DGuYUN0L.mjs +0 -5416
  35. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C7dks3FG.mjs +0 -26
  36. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DpjirGmB.mjs +0 -89
  37. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_client__loadShare__.js-CFCVuRAs.mjs +0 -58
  38. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.js-BkvDudqY.mjs +0 -62
  39. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DnrbBvrw.mjs +0 -34
  40. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom__loadShare__.js-DAZkHxxU.mjs +0 -45
  41. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CHqN9NLt.mjs +0 -34
  42. package/dist/grid-2x2-D9syAI6z.mjs +0 -21
  43. package/dist/lib-CVGFTwe0.mjs +0 -7770
@@ -1,4 +1,4 @@
1
- import { c as trainingProviderCapability, d as number, f as object, l as BaseAddon, m as string, p as record, u as boolean } from "../../dist-BSYBh1ZO.mjs";
1
+ import { _ as number, b as string, c as trainingProviderCapability, d as arrayItemFieldPath, f as globalSecretScope, g as boolean, h as toSecretFieldView, l as BaseAddon, m as isSecretMarker, p as isSecretClear, u as SECRET_CLEAR, v as object, y as record } from "../../dist-CVDWIKl7.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import path, { dirname, posix } from "node:path";
4
4
  import { createHash, createPrivateKey, createPublicKey, createSign, randomBytes, randomUUID } from "node:crypto";
@@ -39,14 +39,43 @@ var __copyProps = (to, from, except, desc) => {
39
39
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
41
41
  //#endregion
42
- //#region src/providers/modal/modal-entries.ts
42
+ //#region src/providers/modal/entry-secret-view.ts
43
43
  /**
44
- * Modal provider entries — one credentials + defaults row per operator
45
- * account. Pure helpers so the store is unit-tested without BaseAddon.
44
+ * Build the {@link SecretFieldView} the Providers edit form needs for an
45
+ * entry's token secret.
46
46
  *
47
- * A pre-multi-entry config (flat tokenId/tokenSecret on the addon) migrates
48
- * to a single entry named {@link DEFAULT_MODAL_ENTRY_NAME}.
47
+ * `readStoredGlobalKey` / `this.config` answer VALUES (D798), never markers —
48
+ * so `toSecretFieldView(plaintext)` alone yields an inline view (`$secret:
49
+ * null`) and `SecretFieldControl` cannot reveal. When the secret is set we
50
+ * prefer the deterministic keychain ref (`ctx.secrets.ref`) so the eye can
51
+ * call `keychain-admin.reveal` (D789).
49
52
  */
53
+ /** View for one entry row, or `null` when nothing is stored. */
54
+ function entryTokenSecretView(tokenSecret, secrets, entryId) {
55
+ if (isSecretMarker(tokenSecret)) return toSecretFieldView(tokenSecret);
56
+ const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
57
+ if (plain === "") return null;
58
+ if (secrets === void 0) return toSecretFieldView(plain);
59
+ return {
60
+ $secret: secrets.ref(globalSecretScope(), arrayItemFieldPath("entries", entryId, "tokenSecret")),
61
+ v: 1,
62
+ set: true
63
+ };
64
+ }
65
+ /** View for the legacy flat `tokenSecret` (pre-multi-entry Default). */
66
+ function flatTokenSecretView(tokenSecret, secrets) {
67
+ if (isSecretMarker(tokenSecret)) return toSecretFieldView(tokenSecret);
68
+ const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
69
+ if (plain === "") return null;
70
+ if (secrets === void 0) return toSecretFieldView(plain);
71
+ return {
72
+ $secret: secrets.ref(globalSecretScope(), "tokenSecret"),
73
+ v: 1,
74
+ set: true
75
+ };
76
+ }
77
+ //#endregion
78
+ //#region src/providers/modal/modal-entries.ts
50
79
  var MODAL_TYPE_ID = "modal";
51
80
  var DEFAULT_MODAL_ENTRY_NAME = "Default";
52
81
  var MODAL_ICON_ASSET = "assets/training-modal/icon.svg";
@@ -57,22 +86,44 @@ var DEFAULT_GRACE = 24;
57
86
  function legacyConfigured(config) {
58
87
  return (config.tokenId ?? "").trim() !== "" || (config.tokenSecret ?? "").trim() !== "";
59
88
  }
89
+ /**
90
+ * Keychain / secretStatePaths may omit an empty `tokenSecret` from a stored
91
+ * row (writing `''` is KEEP, not "store empty"). Readers must never see
92
+ * `undefined` and then call `.trim()`.
93
+ */
94
+ function secretAsString(value) {
95
+ return typeof value === "string" ? value : "";
96
+ }
97
+ function normalizeModalEntry(entry) {
98
+ return {
99
+ id: entry.id,
100
+ name: entry.name ?? "Default",
101
+ tokenId: entry.tokenId ?? "",
102
+ tokenSecret: secretAsString(entry.tokenSecret),
103
+ environment: entry.environment ?? "",
104
+ gpuType: entry.gpuType ?? DEFAULT_GPU,
105
+ region: entry.region ?? "",
106
+ costCapUsd: entry.costCapUsd ?? DEFAULT_COST,
107
+ maxRuntimeHours: entry.maxRuntimeHours ?? DEFAULT_HOURS,
108
+ failedDatasetGraceHours: entry.failedDatasetGraceHours ?? DEFAULT_GRACE
109
+ };
110
+ }
60
111
  /** Entries the operator sees — synthesises Default from legacy flat fields. */
61
112
  function effectiveModalEntries(config) {
62
- if (config.entries.length > 0) return config.entries;
113
+ if (config.entries.length > 0) return config.entries.map((e) => normalizeModalEntry(e));
63
114
  if (!legacyConfigured(config)) return [];
64
- return [{
115
+ return [normalizeModalEntry({
65
116
  id: "legacy-default",
66
117
  name: DEFAULT_MODAL_ENTRY_NAME,
67
- tokenId: config.tokenId ?? "",
68
- tokenSecret: config.tokenSecret ?? "",
69
- environment: config.environment ?? "",
70
- gpuType: config.gpuType ?? DEFAULT_GPU,
71
- region: config.region ?? "",
72
- costCapUsd: config.costCapUsd ?? DEFAULT_COST,
73
- maxRuntimeHours: config.maxRuntimeHours ?? DEFAULT_HOURS,
74
- failedDatasetGraceHours: config.failedDatasetGraceHours ?? DEFAULT_GRACE
75
- }];
118
+ tokenId: config.tokenId,
119
+ tokenSecret: config.tokenSecret,
120
+ environment: config.environment,
121
+ gpuType: config.gpuType,
122
+ region: config.region,
123
+ costCapUsd: config.costCapUsd,
124
+ maxRuntimeHours: config.maxRuntimeHours,
125
+ failedDatasetGraceHours: config.failedDatasetGraceHours
126
+ })];
76
127
  }
77
128
  function findModalEntry(config, entryId) {
78
129
  return effectiveModalEntries(config).find((e) => e.id === entryId) ?? null;
@@ -156,6 +207,43 @@ function deleteModalEntry(config, entryId) {
156
207
  }
157
208
  };
158
209
  }
210
+ function updateModalEntry(config, entryId, patch) {
211
+ const current = [...effectiveModalEntries(config)];
212
+ const index = current.findIndex((e) => e.id === entryId);
213
+ if (index < 0) return {
214
+ ok: false,
215
+ reason: "unknown-entry"
216
+ };
217
+ const prev = current[index];
218
+ const secret = patch.tokenSecret !== void 0 && patch.tokenSecret !== "" ? patch.tokenSecret : prev.tokenSecret;
219
+ current[index] = {
220
+ id: prev.id,
221
+ name: patch.name !== void 0 ? patch.name : prev.name,
222
+ tokenId: patch.tokenId !== void 0 ? patch.tokenId : prev.tokenId,
223
+ tokenSecret: secret,
224
+ environment: patch.environment !== void 0 ? patch.environment : prev.environment,
225
+ gpuType: patch.gpuType !== void 0 ? patch.gpuType : prev.gpuType,
226
+ region: patch.region !== void 0 ? patch.region : prev.region,
227
+ costCapUsd: patch.costCapUsd !== void 0 ? patch.costCapUsd : prev.costCapUsd,
228
+ maxRuntimeHours: patch.maxRuntimeHours !== void 0 ? patch.maxRuntimeHours : prev.maxRuntimeHours,
229
+ failedDatasetGraceHours: patch.failedDatasetGraceHours !== void 0 ? patch.failedDatasetGraceHours : prev.failedDatasetGraceHours
230
+ };
231
+ return {
232
+ ok: true,
233
+ entryId,
234
+ config: {
235
+ entries: current,
236
+ tokenId: "",
237
+ tokenSecret: "",
238
+ environment: config.environment ?? "",
239
+ gpuType: config.gpuType ?? DEFAULT_GPU,
240
+ region: config.region ?? "",
241
+ costCapUsd: config.costCapUsd ?? DEFAULT_COST,
242
+ maxRuntimeHours: config.maxRuntimeHours ?? DEFAULT_HOURS,
243
+ failedDatasetGraceHours: config.failedDatasetGraceHours ?? DEFAULT_GRACE
244
+ }
245
+ };
246
+ }
159
247
  /**
160
248
  * Mint a stable id for every persisted entry that lacks one. Operator-typed
161
249
  * empty ids (legacy settings UI) must never stay empty — createEntry always
@@ -372,7 +460,10 @@ var ModalTrainingProvider = class {
372
460
  constructor(deps) {
373
461
  this.deps = deps;
374
462
  }
375
- describe = async () => this.deps.listEntries().map((entry) => this.descriptorOf(entry));
463
+ describe = async () => {
464
+ const views = await this.deps.secretViews();
465
+ return this.deps.listEntries().map((entry) => this.descriptorOf(entry, views.get(entry.id) ?? null));
466
+ };
376
467
  describeTypes = async () => [{
377
468
  typeId: MODAL_TYPE_ID,
378
469
  label: "Modal",
@@ -387,6 +478,21 @@ var ModalTrainingProvider = class {
387
478
  configured: this.entryConfigured(entry)
388
479
  }));
389
480
  createEntry = async (input) => this.deps.createEntry(input);
481
+ updateEntry = async (input) => {
482
+ const secret = input.tokenSecret === void 0 ? {} : isSecretClear(input.tokenSecret) ? { clearTokenSecret: true } : input.tokenSecret === "" ? {} : { tokenSecret: input.tokenSecret };
483
+ await this.deps.updateEntry(input.entryId, {
484
+ name: input.name,
485
+ ...input.tokenId !== void 0 ? { tokenId: input.tokenId } : {},
486
+ ...secret,
487
+ ...input.environment !== void 0 ? { environment: input.environment } : {},
488
+ ...input.gpuType !== void 0 ? { gpuType: input.gpuType } : {},
489
+ ...input.region !== void 0 ? { region: input.region } : {},
490
+ ...input.costCapUsd !== void 0 ? { costCapUsd: input.costCapUsd } : {},
491
+ ...input.maxRuntimeSec !== void 0 ? { maxRuntimeHours: input.maxRuntimeSec / 3600 } : {},
492
+ ...input.failedDatasetGraceHours !== void 0 ? { failedDatasetGraceHours: input.failedDatasetGraceHours } : {}
493
+ });
494
+ return { ok: true };
495
+ };
390
496
  deleteEntry = async (input) => {
391
497
  await this.deps.deleteEntry(input.entryId);
392
498
  return { ok: true };
@@ -664,9 +770,12 @@ var ModalTrainingProvider = class {
664
770
  }))];
665
771
  };
666
772
  entryConfigured(entry) {
667
- return entry.tokenId.trim() !== "" && entry.tokenSecret.trim() !== "";
773
+ const secret = typeof entry.tokenSecret === "string" ? entry.tokenSecret : "";
774
+ return (entry.tokenId ?? "").trim() !== "" && secret.trim() !== "";
668
775
  }
669
- descriptorOf(entry) {
776
+ descriptorOf(entry, tokenSecretView) {
777
+ const tokenId = entry.tokenId ?? "";
778
+ const environment = entry.environment ?? "";
670
779
  return {
671
780
  addonId: this.deps.addonId,
672
781
  entryId: entry.id,
@@ -683,12 +792,16 @@ var ModalTrainingProvider = class {
683
792
  dataResidencyNote: "Modal keeps the frames on a Volume of your workspace for the length of the job; the training container sees them only while it runs.",
684
793
  configured: this.entryConfigured(entry),
685
794
  defaults: {
686
- gpuType: entry.gpuType,
687
- region: entry.region,
688
- costCapUsd: entry.costCapUsd,
689
- maxRuntimeSec: Math.round(entry.maxRuntimeHours * 3600),
690
- failedDatasetGraceHours: entry.failedDatasetGraceHours
691
- }
795
+ gpuType: entry.gpuType ?? "L4",
796
+ region: entry.region ?? "",
797
+ costCapUsd: entry.costCapUsd ?? 5,
798
+ maxRuntimeSec: Math.round((entry.maxRuntimeHours ?? 4) * 3600),
799
+ failedDatasetGraceHours: entry.failedDatasetGraceHours ?? 24
800
+ },
801
+ tokenId,
802
+ environment,
803
+ hasTokenSecret: tokenSecretView !== null,
804
+ tokenSecretView
692
805
  };
693
806
  }
694
807
  requireGateway(entryId) {
@@ -88541,6 +88654,12 @@ async function fetchText(url) {
88541
88654
  var TrainingModalAddon = class extends BaseAddon {
88542
88655
  ledgerState = null;
88543
88656
  gateways = /* @__PURE__ */ new Map();
88657
+ /**
88658
+ * Entry secrets live on `entries[id].tokenSecret` (and legacy flat
88659
+ * `tokenSecret`). Declared here — not via an editable-array form — so the
88660
+ * Training → Providers page is the only UI that edits entries.
88661
+ */
88662
+ secretStatePaths = ["entries[id].tokenSecret", "tokenSecret"];
88544
88663
  constructor() {
88545
88664
  super({
88546
88665
  entries: [],
@@ -88556,9 +88675,15 @@ var TrainingModalAddon = class extends BaseAddon {
88556
88675
  }
88557
88676
  async onInitialize() {
88558
88677
  let next = this.config;
88559
- if (next.entries.length === 0) next = migrateLegacyModalConfig(next, () => randomUUID());
88678
+ let migratedLegacy = false;
88679
+ if (next.entries.length === 0) {
88680
+ const migrated = migrateLegacyModalConfig(next, () => randomUUID());
88681
+ migratedLegacy = migrated !== next;
88682
+ next = migrated;
88683
+ }
88560
88684
  next = ensureModalEntryIds(next, () => randomUUID());
88561
88685
  if (next !== this.config) await this.updateGlobalSettings(next);
88686
+ if (migratedLegacy) await this.clearSecrets(["tokenSecret"]);
88562
88687
  this.ledgerState = this.state(LEDGER_KEY, LedgerSchema, {});
88563
88688
  const peer = this.ctx.peerBytes;
88564
88689
  if (peer === void 0) throw new Error("training-modal needs the peer-bytes facility");
@@ -88573,12 +88698,28 @@ var TrainingModalAddon = class extends BaseAddon {
88573
88698
  await this.updateGlobalSettings(result.config);
88574
88699
  return { entryId: result.entryId };
88575
88700
  },
88701
+ updateEntry: async (entryId, patch) => {
88702
+ const { clearTokenSecret, ...rest } = patch;
88703
+ const result = updateModalEntry(this.config, entryId, rest);
88704
+ if (!result.ok) throw new Error(`cannot update entry: ${result.reason}`);
88705
+ if (clearTokenSecret === true) await this.updateGlobalSettings({
88706
+ ...result.config,
88707
+ entries: result.config.entries.map((entry) => entry.id === entryId ? {
88708
+ ...entry,
88709
+ tokenSecret: SECRET_CLEAR
88710
+ } : entry)
88711
+ });
88712
+ else await this.updateGlobalSettings(result.config);
88713
+ this.closeGateway(entryId);
88714
+ },
88576
88715
  deleteEntry: async (entryId) => {
88577
88716
  const result = deleteModalEntry(this.config, entryId);
88578
88717
  if (!result.ok) throw new Error(`cannot delete entry: ${result.reason}`);
88579
88718
  await this.updateGlobalSettings(result.config);
88719
+ await this.clearSecrets(["tokenSecret"]);
88580
88720
  this.closeGateway(entryId);
88581
88721
  },
88722
+ secretViews: () => this.readEntrySecretViews(),
88582
88723
  ledger: this.ledger(),
88583
88724
  peer,
88584
88725
  fetchText,
@@ -88587,7 +88728,10 @@ var TrainingModalAddon = class extends BaseAddon {
88587
88728
  });
88588
88729
  this.ctx.logger.info("Modal training provider ready", { meta: {
88589
88730
  entries: effectiveModalEntries(this.config).length,
88590
- configured: effectiveModalEntries(this.config).some((e) => e.tokenId.trim() !== "" && e.tokenSecret.trim() !== "")
88731
+ configured: effectiveModalEntries(this.config).some((e) => {
88732
+ const secret = typeof e.tokenSecret === "string" ? e.tokenSecret : "";
88733
+ return (e.tokenId ?? "").trim() !== "" && secret.trim() !== "";
88734
+ })
88591
88735
  } });
88592
88736
  return { providers: [{
88593
88737
  capability: trainingProviderCapability,
@@ -88605,15 +88749,18 @@ var TrainingModalAddon = class extends BaseAddon {
88605
88749
  gatewayFor(entryId) {
88606
88750
  const entry = findModalEntry(this.config, entryId);
88607
88751
  if (entry === null) return null;
88608
- if (entry.tokenId.trim() === "" || entry.tokenSecret.trim() === "") return null;
88609
- const key = `${entry.tokenId}\u0000${entry.environment}`;
88752
+ const tokenId = (entry.tokenId ?? "").trim();
88753
+ const tokenSecret = (typeof entry.tokenSecret === "string" ? entry.tokenSecret : "").trim();
88754
+ if (tokenId === "" || tokenSecret === "") return null;
88755
+ const environment = (entry.environment ?? "").trim();
88756
+ const key = `${tokenId}\u0000${environment}`;
88610
88757
  const cached = this.gateways.get(entryId);
88611
88758
  if (cached !== void 0 && cached.key === key) return cached.gateway;
88612
88759
  cached?.gateway.close();
88613
88760
  const gateway = new ModalSdkGateway({
88614
- tokenId: entry.tokenId.trim(),
88615
- tokenSecret: entry.tokenSecret.trim(),
88616
- environment: entry.environment.trim()
88761
+ tokenId,
88762
+ tokenSecret,
88763
+ environment
88617
88764
  });
88618
88765
  this.gateways.set(entryId, {
88619
88766
  key,
@@ -88627,6 +88774,19 @@ var TrainingModalAddon = class extends BaseAddon {
88627
88774
  cached.gateway.close();
88628
88775
  this.gateways.delete(entryId);
88629
88776
  }
88777
+ /**
88778
+ * Keychain views for the Providers edit form. Addon-facing reads answer
88779
+ * VALUES (D798), so we cannot recover markers from `readStoredGlobalKey`.
88780
+ * When a secret is present on the resolved entry we emit the deterministic
88781
+ * keychain ref (`ctx.secrets.ref`) so `SecretFieldControl` can reveal.
88782
+ */
88783
+ async readEntrySecretViews() {
88784
+ const map = /* @__PURE__ */ new Map();
88785
+ const secrets = this.ctx.secrets;
88786
+ for (const entry of effectiveModalEntries(this.config)) map.set(entry.id, entryTokenSecretView(entry.tokenSecret, secrets, entry.id));
88787
+ map.set("legacy-default", flatTokenSecretView(this.config.tokenSecret, secrets));
88788
+ return map;
88789
+ }
88630
88790
  ledger() {
88631
88791
  const state = () => {
88632
88792
  if (this.ledgerState === null) throw new Error("training-modal ledger not initialised");
@@ -88651,97 +88811,10 @@ var TrainingModalAddon = class extends BaseAddon {
88651
88811
  }
88652
88812
  globalSettingsSchema() {
88653
88813
  return this.schema({ sections: [{
88654
- id: "entries",
88814
+ id: "providers",
88655
88815
  title: "Modal accounts",
88656
- description: "Each entry is one Modal workspace token. Create entries from the Training → Providers tab; edit credentials here. Secrets stay in the CamStack keychain.",
88657
- fields: [{
88658
- type: "editable-array",
88659
- key: "entries",
88660
- label: "Entries",
88661
- itemIdKey: "id",
88662
- /** Create only via trainingProvider.createEntry (auto id). */
88663
- maxRows: 0,
88664
- emptyMessage: "No Modal entries yet — add one from Training → Providers.",
88665
- rowTitleTemplate: "{name}",
88666
- defaultItem: {
88667
- id: "",
88668
- name: "Default",
88669
- tokenId: "",
88670
- tokenSecret: "",
88671
- environment: "",
88672
- gpuType: "L4",
88673
- region: "",
88674
- costCapUsd: 5,
88675
- maxRuntimeHours: 4,
88676
- failedDatasetGraceHours: 24
88677
- },
88678
- itemFields: [
88679
- {
88680
- type: "text",
88681
- key: "name",
88682
- label: "Name"
88683
- },
88684
- {
88685
- type: "text",
88686
- key: "tokenId",
88687
- label: "Token id",
88688
- placeholder: "ak-…"
88689
- },
88690
- {
88691
- type: "password",
88692
- key: "tokenSecret",
88693
- label: "Token secret",
88694
- showToggle: true
88695
- },
88696
- {
88697
- type: "text",
88698
- key: "environment",
88699
- label: "Environment",
88700
- description: "Leave empty for the workspace default."
88701
- },
88702
- {
88703
- type: "select",
88704
- key: "gpuType",
88705
- label: "GPU",
88706
- options: MODAL_GPUS.map((g) => ({
88707
- value: g.id,
88708
- label: `${g.label} — $${g.usdPerHour.toFixed(2)}/h`
88709
- }))
88710
- },
88711
- {
88712
- type: "select",
88713
- key: "region",
88714
- label: "Region",
88715
- options: MODAL_REGIONS.map((r) => ({
88716
- value: r.id,
88717
- label: r.label
88718
- }))
88719
- },
88720
- {
88721
- type: "number",
88722
- key: "costCapUsd",
88723
- label: "Cost cap per job (USD)",
88724
- min: .5,
88725
- step: .5
88726
- },
88727
- {
88728
- type: "number",
88729
- key: "maxRuntimeHours",
88730
- label: "Maximum runtime (hours)",
88731
- min: .5,
88732
- max: 24,
88733
- step: .5
88734
- },
88735
- {
88736
- type: "number",
88737
- key: "failedDatasetGraceHours",
88738
- label: "Keep a failed job’s dataset (hours)",
88739
- min: 0,
88740
- max: 168,
88741
- step: 1
88742
- }
88743
- ]
88744
- }]
88816
+ description: "Create and edit Modal workspace entries under Training → Providers. Credentials stay in the CamStack keychain.",
88817
+ fields: []
88745
88818
  }] });
88746
88819
  }
88747
88820
  };
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-C-uqIKLg.mjs";
1
+ import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Dw400Y0a.mjs";
2
2
  export { t as get, e as init };
@@ -1,8 +1,8 @@
1
- import { S as e, _ as t, c as n, l as r, m as i, n as a, r as o, t as s, u as c, v as l } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-DeDbF7NI.mjs";
2
- import { h as u } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-C7dks3FG.mjs";
3
- import "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DnrbBvrw.mjs";
1
+ import { _ as e, b as t, c as n, g as r, l as i, m as a, n as o, r as s, t as c, u as l } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-BT_wL8s3.mjs";
2
+ import { a as u } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ff7X-Xlf.mjs";
3
+ import "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DDBEvLdo.mjs";
4
4
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
5
- e();
5
+ t();
6
6
  var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), f = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), p = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), m = (e) => {
7
7
  let t = p(e);
8
8
  return t.charAt(0).toUpperCase() + t.slice(1);
@@ -19,7 +19,7 @@ var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
19
19
  }, g = (e) => {
20
20
  for (let t in e) if (t.startsWith("aria-") || t === "role" || t === "title") return !0;
21
21
  return !1;
22
- }, _ = o(({ color: e = "currentColor", size: t = 24, strokeWidth: n = 2, absoluteStrokeWidth: r, className: i = "", children: o, iconNode: s, ...c }, l) => a("svg", {
22
+ }, _ = s(({ color: e = "currentColor", size: t = 24, strokeWidth: n = 2, absoluteStrokeWidth: r, className: i = "", children: a, iconNode: s, ...c }, l) => o("svg", {
23
23
  ref: l,
24
24
  ...h,
25
25
  width: t,
@@ -27,14 +27,14 @@ var d = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) =
27
27
  stroke: e,
28
28
  strokeWidth: r ? Number(n) * 24 / Number(t) : n,
29
29
  className: d("lucide", i),
30
- ...!o && !g(c) && { "aria-hidden": "true" },
30
+ ...!a && !g(c) && { "aria-hidden": "true" },
31
31
  ...c
32
- }, [...s.map(([e, t]) => a(e, t)), ...Array.isArray(o) ? o : [o]]));
32
+ }, [...s.map(([e, t]) => o(e, t)), ...Array.isArray(a) ? a : [a]]));
33
33
  //#endregion
34
34
  //#region ../../node_modules/lucide-react/dist/esm/createLucideIcon.js
35
- e();
35
+ t();
36
36
  var v = (e, t) => {
37
- let n = o(({ className: n, ...r }, i) => a(_, {
37
+ let n = s(({ className: n, ...r }, i) => o(_, {
38
38
  ref: i,
39
39
  iconNode: t,
40
40
  className: d(`lucide-${f(m(e))}`, `lucide-${e}`, n),
@@ -44,69 +44,65 @@ var v = (e, t) => {
44
44
  };
45
45
  //#endregion
46
46
  //#region ../ui-library/src/lib/shared-context.ts
47
- e();
47
+ t();
48
48
  function y(e, t) {
49
- if (typeof globalThis > "u") return s(t);
49
+ if (typeof globalThis > "u") return c(t);
50
50
  let n = globalThis.__camstackSharedContexts, r = n ?? /* @__PURE__ */ new Map();
51
51
  n || (globalThis.__camstackSharedContexts = r);
52
52
  let i = r.get(e);
53
53
  if (i) return i;
54
- let a = s(t);
54
+ let a = c(t);
55
55
  return r.set(e, a), a;
56
56
  }
57
57
  //#endregion
58
58
  //#region ../ui-library/src/contexts/system-context.tsx
59
- e();
59
+ t();
60
60
  var b = y("camstack:system", null);
61
61
  function x() {
62
- let e = r(b);
62
+ let e = i(b);
63
63
  if (!e) throw Error("useSystem(): no <SystemProvider> in tree");
64
64
  return e;
65
65
  }
66
66
  //#endregion
67
67
  //#region ../ui-library/src/hooks/use-device-proxy.ts
68
- e();
68
+ t();
69
69
  var S = "capability.binding-changed";
70
- function C(e, n) {
71
- let [r, a] = t(null);
72
- return c(() => {
73
- if (n === null) {
74
- a(null);
70
+ function C(e, t) {
71
+ let [n, i] = r(null);
72
+ return l(() => {
73
+ if (t === null) {
74
+ i(null);
75
75
  return;
76
76
  }
77
- let t = !1, r = async () => {
77
+ let n = !1, r = async () => {
78
78
  try {
79
- let r = await e.deviceManager.getBindings.query({ deviceId: n });
80
- t || a(r);
79
+ let r = await e.deviceManager.getBindings.query({ deviceId: t });
80
+ n || i(r);
81
81
  } catch {
82
- t || a((e) => e);
82
+ n || i((e) => e);
83
83
  }
84
84
  };
85
85
  r();
86
- let i = e.live?.onEvent.subscribe({ category: S }, { onData: (e) => {
87
- let t = e.data?.source;
88
- if (!t) {
86
+ let a = e.live?.onEvent.subscribe({ category: S }, { onData: (e) => {
87
+ let n = e.data?.source;
88
+ if (!n) {
89
89
  r();
90
90
  return;
91
91
  }
92
- t.type === "device" && t.id === n && r();
92
+ n.type === "device" && n.id === t && r();
93
93
  } });
94
94
  return () => {
95
- t = !0, i?.unsubscribe();
95
+ n = !0, a?.unsubscribe();
96
96
  };
97
- }, [e, n]), i(() => r ? u(e, r) : null, [e, r]);
97
+ }, [e, t]), a(() => n ? u(e, n) : null, [e, n]);
98
98
  }
99
- function w(e) {
100
- let t = n((t) => e ? e.subscribe(() => t()) : () => void 0, [e]), r = n(() => e?.value, [e]);
101
- return l(t, r, r);
102
- }
103
- function T(e, t, n) {
104
- let r = C(e, t);
105
- return w(r ? n(r.state) : void 0);
99
+ function w(t) {
100
+ let r = n((e) => t ? t.subscribe(() => e()) : () => void 0, [t]), i = n(() => t?.value, [t]);
101
+ return e(r, i, i);
106
102
  }
107
103
  //#endregion
108
104
  //#region ../ui-library/src/lib/cap-error.ts
109
- function E(e) {
105
+ function T(e) {
110
106
  if (typeof e != "object" || !e) return null;
111
107
  let t = Reflect.get(e, "data");
112
108
  if (typeof t == "object" && t) {
@@ -115,12 +111,12 @@ function E(e) {
115
111
  }
116
112
  return null;
117
113
  }
118
- function D(e) {
119
- let t = E(e);
114
+ function E(e) {
115
+ let t = T(e);
120
116
  return t === null ? (e instanceof Error ? e.message : String(e)).includes("provider not available") : t === "no-provider" || t === "node-offline";
121
117
  }
122
118
  //#endregion
123
119
  //#region ../ui-library/src/lib/responsive.ts
124
- var O = "rounded-lg border border-border bg-surface overflow-hidden", k = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2", A = "p-2 sm:p-3 lg:p-4", j = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4", M = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center", N = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2", P = "flex w-full min-w-0 items-center gap-1 sm:flex-1", F = "min-w-0 break-all text-xs text-foreground sm:truncate", I = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider", L = "text-[10px] text-foreground-subtle", R = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors", z = "border-primary/50 bg-primary/15 text-primary", B = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
120
+ var D = "rounded-lg border border-border bg-surface overflow-hidden", O = "border-b border-border px-3 sm:px-4 py-1.5 sm:py-2", k = "p-2 sm:p-3 lg:p-4", A = "grid grid-cols-2 sm:grid-cols-2 lg:grid-cols-4", j = "flex min-w-0 flex-col gap-0.5 py-1.5 sm:flex-row sm:items-center", M = "min-w-0 text-[11px] leading-tight text-foreground-subtle sm:w-32 sm:shrink-0 sm:pr-2", N = "flex w-full min-w-0 items-center gap-1 sm:flex-1", P = "min-w-0 break-all text-xs text-foreground sm:truncate", F = "text-[10px] sm:text-[11px] font-semibold text-foreground uppercase tracking-wider", I = "text-[10px] text-foreground-subtle", L = "inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors", R = "border-primary/50 bg-primary/15 text-primary", z = "border-border bg-surface text-foreground-subtle hover:bg-surface-hover";
125
121
  //#endregion
126
- export { w as _, A as a, v as b, M as c, F as d, L as f, T as g, C as h, j as i, N as l, D as m, R as n, O as o, I as p, B as r, k as s, z as t, P as u, x as v, y };
122
+ export { x as _, k as a, j as c, P as d, I as f, w as g, C as h, A as i, M as l, E as m, L as n, D as o, F as p, z as r, O as s, R as t, N as u, y as v, v as y };
@@ -1,5 +1,5 @@
1
- import { S as e, _ as t, c as n, m as r } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-DeDbF7NI.mjs";
2
- import { b as i } from "./responsive-emJo3EdF.mjs";
1
+ import { b as e, c as t, g as n, m as r } from "./_virtual_mf___mfe_internal__addon_training_page__loadShare__react__loadShare__.js-BT_wL8s3.mjs";
2
+ import { y as i } from "./responsive-BBlQWFFi.mjs";
3
3
  var a = i("camera", [["path", {
4
4
  d: "M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",
5
5
  key: "18u6gg"
@@ -89,7 +89,7 @@ function g(e) {
89
89
  //#region ../ui-library/src/hooks/use-device-snapshot.ts
90
90
  var _ = "/addon/snapshot/media";
91
91
  function v(e, i = {}) {
92
- let { width: a, baseUrl: o } = i, [s, c] = t(0);
92
+ let { width: a, baseUrl: o } = i, [s, c] = n(0);
93
93
  return {
94
94
  src: r(() => {
95
95
  if (e === null || e <= 0) return null;
@@ -104,7 +104,7 @@ function v(e, i = {}) {
104
104
  s
105
105
  ]),
106
106
  loading: !1,
107
- refresh: n(() => {
107
+ refresh: t(() => {
108
108
  c((e) => e + 1);
109
109
  }, [])
110
110
  };