@camstack/addon-training 0.1.22 → 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.
- package/dist/{MotionZonesSettings-DshSNzpp.mjs → MotionZonesSettings-CwGjtvsX.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-DDaIx7j5.mjs → PrivacyMaskSettings-CM_WsrKB.mjs} +4 -4
- package/dist/{SceneMonitorEditor-CuJ7xjyd.mjs → SceneMonitorEditor-B-sAJ--C.mjs} +3 -3
- package/dist/_stub.js +4974 -4879
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DJDgoXBt.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DKblQaAP.mjs} +2 -2
- package/dist/{_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D7T4QEtw.mjs → _virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ff7X-Xlf.mjs} +8 -8
- package/dist/{dist-DhCvklZW.mjs → dist-CVDWIKl7.mjs} +17 -4
- package/dist/{dist-Dd6EAdVX.js → dist-DwF1P1v7.js} +52 -3
- package/dist/{hostInit-DR-St7pA.mjs → hostInit-Di0tDODX.mjs} +1 -1
- package/dist/index.js +1 -1
- package/dist/orchestrator/training.addon.js +8 -1
- package/dist/orchestrator/training.addon.mjs +8 -1
- package/dist/{player-overlays-DUZMtmvk.mjs → player-overlays-BFAqW2L1.mjs} +1 -1
- package/dist/providers/modal/training-modal.addon.js +132 -38
- package/dist/providers/modal/training-modal.addon.mjs +132 -38
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-C7QsFtTb.mjs → responsive-BBlQWFFi.mjs} +1 -1
- package/dist/{scene-monitor-copy-BtffdnnW.mjs → scene-monitor-copy-D5mKGqt0.mjs} +1 -1
- package/dist/{square-e5Ytjod_.mjs → square-D0FYSm8b.mjs} +1 -1
- package/dist/{trash-2-Clte6zIF.mjs → trash-2-DdjGvgDw.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-dy7yMOdw.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Dw400Y0a.mjs} +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("../../dist-
|
|
2
|
+
const require_dist = require("../../dist-DwF1P1v7.js");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_dist.__toESM(node_path, 1);
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
@@ -11,14 +11,43 @@ let timers_promises = require("timers/promises");
|
|
|
11
11
|
let node_console = require("node:console");
|
|
12
12
|
let node_os = require("node:os");
|
|
13
13
|
let node_stream = require("node:stream");
|
|
14
|
-
//#region src/providers/modal/
|
|
14
|
+
//#region src/providers/modal/entry-secret-view.ts
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Build the {@link SecretFieldView} the Providers edit form needs for an
|
|
17
|
+
* entry's token secret.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* `readStoredGlobalKey` / `this.config` answer VALUES (D798), never markers —
|
|
20
|
+
* so `toSecretFieldView(plaintext)` alone yields an inline view (`$secret:
|
|
21
|
+
* null`) and `SecretFieldControl` cannot reveal. When the secret is set we
|
|
22
|
+
* prefer the deterministic keychain ref (`ctx.secrets.ref`) so the eye can
|
|
23
|
+
* call `keychain-admin.reveal` (D789).
|
|
21
24
|
*/
|
|
25
|
+
/** View for one entry row, or `null` when nothing is stored. */
|
|
26
|
+
function entryTokenSecretView(tokenSecret, secrets, entryId) {
|
|
27
|
+
if (require_dist.isSecretMarker(tokenSecret)) return require_dist.toSecretFieldView(tokenSecret);
|
|
28
|
+
const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
|
|
29
|
+
if (plain === "") return null;
|
|
30
|
+
if (secrets === void 0) return require_dist.toSecretFieldView(plain);
|
|
31
|
+
return {
|
|
32
|
+
$secret: secrets.ref(require_dist.globalSecretScope(), require_dist.arrayItemFieldPath("entries", entryId, "tokenSecret")),
|
|
33
|
+
v: 1,
|
|
34
|
+
set: true
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** View for the legacy flat `tokenSecret` (pre-multi-entry Default). */
|
|
38
|
+
function flatTokenSecretView(tokenSecret, secrets) {
|
|
39
|
+
if (require_dist.isSecretMarker(tokenSecret)) return require_dist.toSecretFieldView(tokenSecret);
|
|
40
|
+
const plain = typeof tokenSecret === "string" ? tokenSecret.trim() : "";
|
|
41
|
+
if (plain === "") return null;
|
|
42
|
+
if (secrets === void 0) return require_dist.toSecretFieldView(plain);
|
|
43
|
+
return {
|
|
44
|
+
$secret: secrets.ref(require_dist.globalSecretScope(), "tokenSecret"),
|
|
45
|
+
v: 1,
|
|
46
|
+
set: true
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/providers/modal/modal-entries.ts
|
|
22
51
|
var MODAL_TYPE_ID = "modal";
|
|
23
52
|
var DEFAULT_MODAL_ENTRY_NAME = "Default";
|
|
24
53
|
var MODAL_ICON_ASSET = "assets/training-modal/icon.svg";
|
|
@@ -29,22 +58,44 @@ var DEFAULT_GRACE = 24;
|
|
|
29
58
|
function legacyConfigured(config) {
|
|
30
59
|
return (config.tokenId ?? "").trim() !== "" || (config.tokenSecret ?? "").trim() !== "";
|
|
31
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Keychain / secretStatePaths may omit an empty `tokenSecret` from a stored
|
|
63
|
+
* row (writing `''` is KEEP, not "store empty"). Readers must never see
|
|
64
|
+
* `undefined` and then call `.trim()`.
|
|
65
|
+
*/
|
|
66
|
+
function secretAsString(value) {
|
|
67
|
+
return typeof value === "string" ? value : "";
|
|
68
|
+
}
|
|
69
|
+
function normalizeModalEntry(entry) {
|
|
70
|
+
return {
|
|
71
|
+
id: entry.id,
|
|
72
|
+
name: entry.name ?? "Default",
|
|
73
|
+
tokenId: entry.tokenId ?? "",
|
|
74
|
+
tokenSecret: secretAsString(entry.tokenSecret),
|
|
75
|
+
environment: entry.environment ?? "",
|
|
76
|
+
gpuType: entry.gpuType ?? DEFAULT_GPU,
|
|
77
|
+
region: entry.region ?? "",
|
|
78
|
+
costCapUsd: entry.costCapUsd ?? DEFAULT_COST,
|
|
79
|
+
maxRuntimeHours: entry.maxRuntimeHours ?? DEFAULT_HOURS,
|
|
80
|
+
failedDatasetGraceHours: entry.failedDatasetGraceHours ?? DEFAULT_GRACE
|
|
81
|
+
};
|
|
82
|
+
}
|
|
32
83
|
/** Entries the operator sees — synthesises Default from legacy flat fields. */
|
|
33
84
|
function effectiveModalEntries(config) {
|
|
34
|
-
if (config.entries.length > 0) return config.entries;
|
|
85
|
+
if (config.entries.length > 0) return config.entries.map((e) => normalizeModalEntry(e));
|
|
35
86
|
if (!legacyConfigured(config)) return [];
|
|
36
|
-
return [{
|
|
87
|
+
return [normalizeModalEntry({
|
|
37
88
|
id: "legacy-default",
|
|
38
89
|
name: DEFAULT_MODAL_ENTRY_NAME,
|
|
39
|
-
tokenId: config.tokenId
|
|
40
|
-
tokenSecret: config.tokenSecret
|
|
41
|
-
environment: config.environment
|
|
42
|
-
gpuType: config.gpuType
|
|
43
|
-
region: config.region
|
|
44
|
-
costCapUsd: config.costCapUsd
|
|
45
|
-
maxRuntimeHours: config.maxRuntimeHours
|
|
46
|
-
failedDatasetGraceHours: config.failedDatasetGraceHours
|
|
47
|
-
}];
|
|
90
|
+
tokenId: config.tokenId,
|
|
91
|
+
tokenSecret: config.tokenSecret,
|
|
92
|
+
environment: config.environment,
|
|
93
|
+
gpuType: config.gpuType,
|
|
94
|
+
region: config.region,
|
|
95
|
+
costCapUsd: config.costCapUsd,
|
|
96
|
+
maxRuntimeHours: config.maxRuntimeHours,
|
|
97
|
+
failedDatasetGraceHours: config.failedDatasetGraceHours
|
|
98
|
+
})];
|
|
48
99
|
}
|
|
49
100
|
function findModalEntry(config, entryId) {
|
|
50
101
|
return effectiveModalEntries(config).find((e) => e.id === entryId) ?? null;
|
|
@@ -381,7 +432,10 @@ var ModalTrainingProvider = class {
|
|
|
381
432
|
constructor(deps) {
|
|
382
433
|
this.deps = deps;
|
|
383
434
|
}
|
|
384
|
-
describe = async () =>
|
|
435
|
+
describe = async () => {
|
|
436
|
+
const views = await this.deps.secretViews();
|
|
437
|
+
return this.deps.listEntries().map((entry) => this.descriptorOf(entry, views.get(entry.id) ?? null));
|
|
438
|
+
};
|
|
385
439
|
describeTypes = async () => [{
|
|
386
440
|
typeId: MODAL_TYPE_ID,
|
|
387
441
|
label: "Modal",
|
|
@@ -397,10 +451,11 @@ var ModalTrainingProvider = class {
|
|
|
397
451
|
}));
|
|
398
452
|
createEntry = async (input) => this.deps.createEntry(input);
|
|
399
453
|
updateEntry = async (input) => {
|
|
454
|
+
const secret = input.tokenSecret === void 0 ? {} : require_dist.isSecretClear(input.tokenSecret) ? { clearTokenSecret: true } : input.tokenSecret === "" ? {} : { tokenSecret: input.tokenSecret };
|
|
400
455
|
await this.deps.updateEntry(input.entryId, {
|
|
401
456
|
name: input.name,
|
|
402
457
|
...input.tokenId !== void 0 ? { tokenId: input.tokenId } : {},
|
|
403
|
-
...
|
|
458
|
+
...secret,
|
|
404
459
|
...input.environment !== void 0 ? { environment: input.environment } : {},
|
|
405
460
|
...input.gpuType !== void 0 ? { gpuType: input.gpuType } : {},
|
|
406
461
|
...input.region !== void 0 ? { region: input.region } : {},
|
|
@@ -687,9 +742,12 @@ var ModalTrainingProvider = class {
|
|
|
687
742
|
}))];
|
|
688
743
|
};
|
|
689
744
|
entryConfigured(entry) {
|
|
690
|
-
|
|
745
|
+
const secret = typeof entry.tokenSecret === "string" ? entry.tokenSecret : "";
|
|
746
|
+
return (entry.tokenId ?? "").trim() !== "" && secret.trim() !== "";
|
|
691
747
|
}
|
|
692
|
-
descriptorOf(entry) {
|
|
748
|
+
descriptorOf(entry, tokenSecretView) {
|
|
749
|
+
const tokenId = entry.tokenId ?? "";
|
|
750
|
+
const environment = entry.environment ?? "";
|
|
693
751
|
return {
|
|
694
752
|
addonId: this.deps.addonId,
|
|
695
753
|
entryId: entry.id,
|
|
@@ -706,15 +764,16 @@ var ModalTrainingProvider = class {
|
|
|
706
764
|
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.",
|
|
707
765
|
configured: this.entryConfigured(entry),
|
|
708
766
|
defaults: {
|
|
709
|
-
gpuType: entry.gpuType,
|
|
710
|
-
region: entry.region,
|
|
711
|
-
costCapUsd: entry.costCapUsd,
|
|
712
|
-
maxRuntimeSec: Math.round(entry.maxRuntimeHours * 3600),
|
|
713
|
-
failedDatasetGraceHours: entry.failedDatasetGraceHours
|
|
767
|
+
gpuType: entry.gpuType ?? "L4",
|
|
768
|
+
region: entry.region ?? "",
|
|
769
|
+
costCapUsd: entry.costCapUsd ?? 5,
|
|
770
|
+
maxRuntimeSec: Math.round((entry.maxRuntimeHours ?? 4) * 3600),
|
|
771
|
+
failedDatasetGraceHours: entry.failedDatasetGraceHours ?? 24
|
|
714
772
|
},
|
|
715
|
-
tokenId
|
|
716
|
-
environment
|
|
717
|
-
hasTokenSecret:
|
|
773
|
+
tokenId,
|
|
774
|
+
environment,
|
|
775
|
+
hasTokenSecret: tokenSecretView !== null,
|
|
776
|
+
tokenSecretView
|
|
718
777
|
};
|
|
719
778
|
}
|
|
720
779
|
requireGateway(entryId) {
|
|
@@ -88588,9 +88647,15 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
|
|
|
88588
88647
|
}
|
|
88589
88648
|
async onInitialize() {
|
|
88590
88649
|
let next = this.config;
|
|
88591
|
-
|
|
88650
|
+
let migratedLegacy = false;
|
|
88651
|
+
if (next.entries.length === 0) {
|
|
88652
|
+
const migrated = migrateLegacyModalConfig(next, () => (0, node_crypto.randomUUID)());
|
|
88653
|
+
migratedLegacy = migrated !== next;
|
|
88654
|
+
next = migrated;
|
|
88655
|
+
}
|
|
88592
88656
|
next = ensureModalEntryIds(next, () => (0, node_crypto.randomUUID)());
|
|
88593
88657
|
if (next !== this.config) await this.updateGlobalSettings(next);
|
|
88658
|
+
if (migratedLegacy) await this.clearSecrets(["tokenSecret"]);
|
|
88594
88659
|
this.ledgerState = this.state(LEDGER_KEY, LedgerSchema, {});
|
|
88595
88660
|
const peer = this.ctx.peerBytes;
|
|
88596
88661
|
if (peer === void 0) throw new Error("training-modal needs the peer-bytes facility");
|
|
@@ -88606,17 +88671,27 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
|
|
|
88606
88671
|
return { entryId: result.entryId };
|
|
88607
88672
|
},
|
|
88608
88673
|
updateEntry: async (entryId, patch) => {
|
|
88609
|
-
const
|
|
88674
|
+
const { clearTokenSecret, ...rest } = patch;
|
|
88675
|
+
const result = updateModalEntry(this.config, entryId, rest);
|
|
88610
88676
|
if (!result.ok) throw new Error(`cannot update entry: ${result.reason}`);
|
|
88611
|
-
await this.updateGlobalSettings(
|
|
88677
|
+
if (clearTokenSecret === true) await this.updateGlobalSettings({
|
|
88678
|
+
...result.config,
|
|
88679
|
+
entries: result.config.entries.map((entry) => entry.id === entryId ? {
|
|
88680
|
+
...entry,
|
|
88681
|
+
tokenSecret: require_dist.SECRET_CLEAR
|
|
88682
|
+
} : entry)
|
|
88683
|
+
});
|
|
88684
|
+
else await this.updateGlobalSettings(result.config);
|
|
88612
88685
|
this.closeGateway(entryId);
|
|
88613
88686
|
},
|
|
88614
88687
|
deleteEntry: async (entryId) => {
|
|
88615
88688
|
const result = deleteModalEntry(this.config, entryId);
|
|
88616
88689
|
if (!result.ok) throw new Error(`cannot delete entry: ${result.reason}`);
|
|
88617
88690
|
await this.updateGlobalSettings(result.config);
|
|
88691
|
+
await this.clearSecrets(["tokenSecret"]);
|
|
88618
88692
|
this.closeGateway(entryId);
|
|
88619
88693
|
},
|
|
88694
|
+
secretViews: () => this.readEntrySecretViews(),
|
|
88620
88695
|
ledger: this.ledger(),
|
|
88621
88696
|
peer,
|
|
88622
88697
|
fetchText,
|
|
@@ -88625,7 +88700,10 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
|
|
|
88625
88700
|
});
|
|
88626
88701
|
this.ctx.logger.info("Modal training provider ready", { meta: {
|
|
88627
88702
|
entries: effectiveModalEntries(this.config).length,
|
|
88628
|
-
configured: effectiveModalEntries(this.config).some((e) =>
|
|
88703
|
+
configured: effectiveModalEntries(this.config).some((e) => {
|
|
88704
|
+
const secret = typeof e.tokenSecret === "string" ? e.tokenSecret : "";
|
|
88705
|
+
return (e.tokenId ?? "").trim() !== "" && secret.trim() !== "";
|
|
88706
|
+
})
|
|
88629
88707
|
} });
|
|
88630
88708
|
return { providers: [{
|
|
88631
88709
|
capability: require_dist.trainingProviderCapability,
|
|
@@ -88643,15 +88721,18 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
|
|
|
88643
88721
|
gatewayFor(entryId) {
|
|
88644
88722
|
const entry = findModalEntry(this.config, entryId);
|
|
88645
88723
|
if (entry === null) return null;
|
|
88646
|
-
|
|
88647
|
-
const
|
|
88724
|
+
const tokenId = (entry.tokenId ?? "").trim();
|
|
88725
|
+
const tokenSecret = (typeof entry.tokenSecret === "string" ? entry.tokenSecret : "").trim();
|
|
88726
|
+
if (tokenId === "" || tokenSecret === "") return null;
|
|
88727
|
+
const environment = (entry.environment ?? "").trim();
|
|
88728
|
+
const key = `${tokenId}\u0000${environment}`;
|
|
88648
88729
|
const cached = this.gateways.get(entryId);
|
|
88649
88730
|
if (cached !== void 0 && cached.key === key) return cached.gateway;
|
|
88650
88731
|
cached?.gateway.close();
|
|
88651
88732
|
const gateway = new ModalSdkGateway({
|
|
88652
|
-
tokenId
|
|
88653
|
-
tokenSecret
|
|
88654
|
-
environment
|
|
88733
|
+
tokenId,
|
|
88734
|
+
tokenSecret,
|
|
88735
|
+
environment
|
|
88655
88736
|
});
|
|
88656
88737
|
this.gateways.set(entryId, {
|
|
88657
88738
|
key,
|
|
@@ -88665,6 +88746,19 @@ var TrainingModalAddon = class extends require_dist.BaseAddon {
|
|
|
88665
88746
|
cached.gateway.close();
|
|
88666
88747
|
this.gateways.delete(entryId);
|
|
88667
88748
|
}
|
|
88749
|
+
/**
|
|
88750
|
+
* Keychain views for the Providers edit form. Addon-facing reads answer
|
|
88751
|
+
* VALUES (D798), so we cannot recover markers from `readStoredGlobalKey`.
|
|
88752
|
+
* When a secret is present on the resolved entry we emit the deterministic
|
|
88753
|
+
* keychain ref (`ctx.secrets.ref`) so `SecretFieldControl` can reveal.
|
|
88754
|
+
*/
|
|
88755
|
+
async readEntrySecretViews() {
|
|
88756
|
+
const map = /* @__PURE__ */ new Map();
|
|
88757
|
+
const secrets = this.ctx.secrets;
|
|
88758
|
+
for (const entry of effectiveModalEntries(this.config)) map.set(entry.id, entryTokenSecretView(entry.tokenSecret, secrets, entry.id));
|
|
88759
|
+
map.set("legacy-default", flatTokenSecretView(this.config.tokenSecret, secrets));
|
|
88760
|
+
return map;
|
|
88761
|
+
}
|
|
88668
88762
|
ledger() {
|
|
88669
88763
|
const state = () => {
|
|
88670
88764
|
if (this.ledgerState === null) throw new Error("training-modal ledger not initialised");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as trainingProviderCapability, d as
|
|
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/
|
|
42
|
+
//#region src/providers/modal/entry-secret-view.ts
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* Build the {@link SecretFieldView} the Providers edit form needs for an
|
|
45
|
+
* entry's token secret.
|
|
46
46
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
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
|
|
71
|
-
region: config.region
|
|
72
|
-
costCapUsd: config.costCapUsd
|
|
73
|
-
maxRuntimeHours: config.maxRuntimeHours
|
|
74
|
-
failedDatasetGraceHours: config.failedDatasetGraceHours
|
|
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;
|
|
@@ -409,7 +460,10 @@ var ModalTrainingProvider = class {
|
|
|
409
460
|
constructor(deps) {
|
|
410
461
|
this.deps = deps;
|
|
411
462
|
}
|
|
412
|
-
describe = async () =>
|
|
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
|
+
};
|
|
413
467
|
describeTypes = async () => [{
|
|
414
468
|
typeId: MODAL_TYPE_ID,
|
|
415
469
|
label: "Modal",
|
|
@@ -425,10 +479,11 @@ var ModalTrainingProvider = class {
|
|
|
425
479
|
}));
|
|
426
480
|
createEntry = async (input) => this.deps.createEntry(input);
|
|
427
481
|
updateEntry = async (input) => {
|
|
482
|
+
const secret = input.tokenSecret === void 0 ? {} : isSecretClear(input.tokenSecret) ? { clearTokenSecret: true } : input.tokenSecret === "" ? {} : { tokenSecret: input.tokenSecret };
|
|
428
483
|
await this.deps.updateEntry(input.entryId, {
|
|
429
484
|
name: input.name,
|
|
430
485
|
...input.tokenId !== void 0 ? { tokenId: input.tokenId } : {},
|
|
431
|
-
...
|
|
486
|
+
...secret,
|
|
432
487
|
...input.environment !== void 0 ? { environment: input.environment } : {},
|
|
433
488
|
...input.gpuType !== void 0 ? { gpuType: input.gpuType } : {},
|
|
434
489
|
...input.region !== void 0 ? { region: input.region } : {},
|
|
@@ -715,9 +770,12 @@ var ModalTrainingProvider = class {
|
|
|
715
770
|
}))];
|
|
716
771
|
};
|
|
717
772
|
entryConfigured(entry) {
|
|
718
|
-
|
|
773
|
+
const secret = typeof entry.tokenSecret === "string" ? entry.tokenSecret : "";
|
|
774
|
+
return (entry.tokenId ?? "").trim() !== "" && secret.trim() !== "";
|
|
719
775
|
}
|
|
720
|
-
descriptorOf(entry) {
|
|
776
|
+
descriptorOf(entry, tokenSecretView) {
|
|
777
|
+
const tokenId = entry.tokenId ?? "";
|
|
778
|
+
const environment = entry.environment ?? "";
|
|
721
779
|
return {
|
|
722
780
|
addonId: this.deps.addonId,
|
|
723
781
|
entryId: entry.id,
|
|
@@ -734,15 +792,16 @@ var ModalTrainingProvider = class {
|
|
|
734
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.",
|
|
735
793
|
configured: this.entryConfigured(entry),
|
|
736
794
|
defaults: {
|
|
737
|
-
gpuType: entry.gpuType,
|
|
738
|
-
region: entry.region,
|
|
739
|
-
costCapUsd: entry.costCapUsd,
|
|
740
|
-
maxRuntimeSec: Math.round(entry.maxRuntimeHours * 3600),
|
|
741
|
-
failedDatasetGraceHours: entry.failedDatasetGraceHours
|
|
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
|
|
742
800
|
},
|
|
743
|
-
tokenId
|
|
744
|
-
environment
|
|
745
|
-
hasTokenSecret:
|
|
801
|
+
tokenId,
|
|
802
|
+
environment,
|
|
803
|
+
hasTokenSecret: tokenSecretView !== null,
|
|
804
|
+
tokenSecretView
|
|
746
805
|
};
|
|
747
806
|
}
|
|
748
807
|
requireGateway(entryId) {
|
|
@@ -88616,9 +88675,15 @@ var TrainingModalAddon = class extends BaseAddon {
|
|
|
88616
88675
|
}
|
|
88617
88676
|
async onInitialize() {
|
|
88618
88677
|
let next = this.config;
|
|
88619
|
-
|
|
88678
|
+
let migratedLegacy = false;
|
|
88679
|
+
if (next.entries.length === 0) {
|
|
88680
|
+
const migrated = migrateLegacyModalConfig(next, () => randomUUID());
|
|
88681
|
+
migratedLegacy = migrated !== next;
|
|
88682
|
+
next = migrated;
|
|
88683
|
+
}
|
|
88620
88684
|
next = ensureModalEntryIds(next, () => randomUUID());
|
|
88621
88685
|
if (next !== this.config) await this.updateGlobalSettings(next);
|
|
88686
|
+
if (migratedLegacy) await this.clearSecrets(["tokenSecret"]);
|
|
88622
88687
|
this.ledgerState = this.state(LEDGER_KEY, LedgerSchema, {});
|
|
88623
88688
|
const peer = this.ctx.peerBytes;
|
|
88624
88689
|
if (peer === void 0) throw new Error("training-modal needs the peer-bytes facility");
|
|
@@ -88634,17 +88699,27 @@ var TrainingModalAddon = class extends BaseAddon {
|
|
|
88634
88699
|
return { entryId: result.entryId };
|
|
88635
88700
|
},
|
|
88636
88701
|
updateEntry: async (entryId, patch) => {
|
|
88637
|
-
const
|
|
88702
|
+
const { clearTokenSecret, ...rest } = patch;
|
|
88703
|
+
const result = updateModalEntry(this.config, entryId, rest);
|
|
88638
88704
|
if (!result.ok) throw new Error(`cannot update entry: ${result.reason}`);
|
|
88639
|
-
await this.updateGlobalSettings(
|
|
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);
|
|
88640
88713
|
this.closeGateway(entryId);
|
|
88641
88714
|
},
|
|
88642
88715
|
deleteEntry: async (entryId) => {
|
|
88643
88716
|
const result = deleteModalEntry(this.config, entryId);
|
|
88644
88717
|
if (!result.ok) throw new Error(`cannot delete entry: ${result.reason}`);
|
|
88645
88718
|
await this.updateGlobalSettings(result.config);
|
|
88719
|
+
await this.clearSecrets(["tokenSecret"]);
|
|
88646
88720
|
this.closeGateway(entryId);
|
|
88647
88721
|
},
|
|
88722
|
+
secretViews: () => this.readEntrySecretViews(),
|
|
88648
88723
|
ledger: this.ledger(),
|
|
88649
88724
|
peer,
|
|
88650
88725
|
fetchText,
|
|
@@ -88653,7 +88728,10 @@ var TrainingModalAddon = class extends BaseAddon {
|
|
|
88653
88728
|
});
|
|
88654
88729
|
this.ctx.logger.info("Modal training provider ready", { meta: {
|
|
88655
88730
|
entries: effectiveModalEntries(this.config).length,
|
|
88656
|
-
configured: effectiveModalEntries(this.config).some((e) =>
|
|
88731
|
+
configured: effectiveModalEntries(this.config).some((e) => {
|
|
88732
|
+
const secret = typeof e.tokenSecret === "string" ? e.tokenSecret : "";
|
|
88733
|
+
return (e.tokenId ?? "").trim() !== "" && secret.trim() !== "";
|
|
88734
|
+
})
|
|
88657
88735
|
} });
|
|
88658
88736
|
return { providers: [{
|
|
88659
88737
|
capability: trainingProviderCapability,
|
|
@@ -88671,15 +88749,18 @@ var TrainingModalAddon = class extends BaseAddon {
|
|
|
88671
88749
|
gatewayFor(entryId) {
|
|
88672
88750
|
const entry = findModalEntry(this.config, entryId);
|
|
88673
88751
|
if (entry === null) return null;
|
|
88674
|
-
|
|
88675
|
-
const
|
|
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}`;
|
|
88676
88757
|
const cached = this.gateways.get(entryId);
|
|
88677
88758
|
if (cached !== void 0 && cached.key === key) return cached.gateway;
|
|
88678
88759
|
cached?.gateway.close();
|
|
88679
88760
|
const gateway = new ModalSdkGateway({
|
|
88680
|
-
tokenId
|
|
88681
|
-
tokenSecret
|
|
88682
|
-
environment
|
|
88761
|
+
tokenId,
|
|
88762
|
+
tokenSecret,
|
|
88763
|
+
environment
|
|
88683
88764
|
});
|
|
88684
88765
|
this.gateways.set(entryId, {
|
|
88685
88766
|
key,
|
|
@@ -88693,6 +88774,19 @@ var TrainingModalAddon = class extends BaseAddon {
|
|
|
88693
88774
|
cached.gateway.close();
|
|
88694
88775
|
this.gateways.delete(entryId);
|
|
88695
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
|
+
}
|
|
88696
88790
|
ledger() {
|
|
88697
88791
|
const state = () => {
|
|
88698
88792
|
if (this.ledgerState === null) throw new Error("training-modal ledger not initialised");
|
package/dist/remoteEntry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as e, t } from "./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-
|
|
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,5 +1,5 @@
|
|
|
1
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 {
|
|
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
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
5
|
t();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
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-
|
|
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"
|
|
@@ -2753,7 +2753,7 @@ async function rr(e) {
|
|
|
2753
2753
|
}
|
|
2754
2754
|
}
|
|
2755
2755
|
async function ir() {
|
|
2756
|
-
return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-
|
|
2756
|
+
return tr ||= rr(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-DKblQaAP.mjs")).catch((e) => {
|
|
2757
2757
|
throw tr = void 0, e;
|
|
2758
2758
|
}), tr;
|
|
2759
2759
|
}
|
package/package.json
CHANGED