@zhuoyuezs/ml-platform 0.1.13 → 0.1.15
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/checksums.json
CHANGED
|
@@ -7,23 +7,23 @@
|
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"path": "runtime/business-client/package-lock.json",
|
|
10
|
-
"sha256": "sha256:
|
|
10
|
+
"sha256": "sha256:a966c6f4dd7a74efaec7ca14c41b0a72c42ab53d2360bc45cb680874e1669720",
|
|
11
11
|
"size_bytes": 381
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"path": "runtime/business-client/package.json",
|
|
15
|
-
"sha256": "sha256:
|
|
15
|
+
"sha256": "sha256:f2277bf940755b1237fb923e27596483341b2c3a93c16cd0113ce61c5496280a",
|
|
16
16
|
"size_bytes": 501
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"path": "runtime/business-client/src/catalog.js",
|
|
20
|
-
"sha256": "sha256:
|
|
21
|
-
"size_bytes":
|
|
20
|
+
"sha256": "sha256:8c636034f22f7fc70c018f7714923c23a641dd7f1b38f709e6feb3a0e773f105",
|
|
21
|
+
"size_bytes": 55999
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"path": "runtime/business-client/src/cli.js",
|
|
25
|
-
"sha256": "sha256:
|
|
26
|
-
"size_bytes":
|
|
25
|
+
"sha256": "sha256:4f135325b57725c614d266285013df799cdd9a2096d8fbe0a9e9608dae2bcdb7",
|
|
26
|
+
"size_bytes": 44947
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"path": "runtime/business-client/src/config.js",
|
package/package.json
CHANGED
package/release.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"entrypoint": "src/cli.js",
|
|
14
14
|
"name": "ml-platform",
|
|
15
15
|
"path": "runtime/business-client",
|
|
16
|
-
"sha256": "sha256:
|
|
17
|
-
"version": "0.7.
|
|
16
|
+
"sha256": "sha256:02dd0494eccb72dc5da160b65c7c17b266b4da9ce09a31122f434b553f8afbd0",
|
|
17
|
+
"version": "0.7.5"
|
|
18
18
|
},
|
|
19
19
|
"policy_sha256": "sha256:02fbde0134696b78c0c365d6e0b76c9814227208da5b2b3d4e5dbd82dc4a3606",
|
|
20
20
|
"public_schema_versions": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"ml_data_platform.feature_set/v1",
|
|
26
26
|
"ml_data_platform.dataset_manifest/v1"
|
|
27
27
|
],
|
|
28
|
-
"release_version": "0.1.
|
|
28
|
+
"release_version": "0.1.15",
|
|
29
29
|
"runtime_requirements": {
|
|
30
30
|
"node": ">=18",
|
|
31
31
|
"os": [
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"skills": {
|
|
38
38
|
"feature-management": {
|
|
39
39
|
"path": "skills/feature-management",
|
|
40
|
-
"requires_cli": ">=0.7.
|
|
41
|
-
"revision": "0.1.
|
|
40
|
+
"requires_cli": ">=0.7.5 <0.8.0",
|
|
41
|
+
"revision": "0.1.15",
|
|
42
42
|
"sha256": "sha256:182b6f2df4fe58c946e482dfaf416c7d5b78c6fde9c8c8d7293103246618cb4e"
|
|
43
43
|
},
|
|
44
44
|
"model-lifecycle-management": {
|
|
45
45
|
"path": "skills/model-lifecycle-management",
|
|
46
|
-
"requires_cli": ">=0.7.
|
|
47
|
-
"revision": "0.1.
|
|
46
|
+
"requires_cli": ">=0.7.5 <0.8.0",
|
|
47
|
+
"revision": "0.1.15",
|
|
48
48
|
"sha256": "sha256:61ba17f955b36d1c2e8329a10454d040ee7eca5afdb90ff0914d3f85b6e2d203"
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
-
"source_commit": "
|
|
51
|
+
"source_commit": "b91c349695595e23b0295ec48342b61cd5f80c8e"
|
|
52
52
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhuoyuezs/ml-platform-business-client",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@zhuoyuezs/ml-platform-business-client",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.5",
|
|
10
10
|
"license": "UNLICENSED",
|
|
11
11
|
"bin": {
|
|
12
12
|
"ml-platform": "src/cli.js"
|
|
@@ -167,7 +167,22 @@ function loadCatalog(directory) {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
async function fetchAll(client, endpoint, params = {}) { const rows = []; for (let offset = 0; ; offset += 500) { const response = await client.get(endpoint, { ...params, limit: 500, offset }); if (Array.isArray(response)) return response; const page = response.items; if (!Array.isArray(page)) throw new Error(`${endpoint} returned an invalid list response`); rows.push(...page); if (response.total == null || rows.length >= response.total || page.length < 500) return rows; } }
|
|
170
|
-
async function snapshot(client, targetProject) { const scope = { project: targetProject ?? "default" }; const [parameters, operators, features, featureSets, datasets] = await Promise.all([fetchAll(client, "/parameters", scope), fetchAll(client, "/operators", scope), fetchAll(client, "/features", scope), fetchAll(client, "/feature-sets", scope), fetchAll(client, "/datasets", { ...scope, include_deleted: true })]); return { parameters: new Map(parameters.map((x) => [key(x), x])), operators: new Map(operators.map((x) => [key(
|
|
170
|
+
async function snapshot(client, targetProject) { const scope = { project: targetProject ?? "default" }; const [parameters, operators, features, featureSets, datasets] = await Promise.all([fetchAll(client, "/parameters", scope), fetchAll(client, "/operators", scope), fetchAll(client, "/features", scope), fetchAll(client, "/feature-sets", scope), fetchAll(client, "/datasets", { ...scope, include_deleted: true })]); return { parameters: new Map(parameters.map((x) => [key(x), x])), operators: new Map(operators.map((x) => [key(x), x])), features: new Map(features.map((x) => [key(x), x])), feature_sets: new Map(featureSets.map((x) => [key(x), x])), datasets: new Map(datasets.filter((x) => !x.deleted_at).map((x) => [datasetKey(x), x])) }; }
|
|
171
|
+
|
|
172
|
+
async function hydrate(client, current, assets, endpoint, normalizer, keyFn = key, seen = new Set()) { for (const asset of assets) { const assetKey = keyFn(asset); if (current.has(assetKey) && !seen.has(assetKey)) { current.set(assetKey, normalizer(await client.get(endpoint(asset)))); seen.add(assetKey); } } }
|
|
173
|
+
async function hydrateCatalog(client, catalog, current) {
|
|
174
|
+
const hydrated = { parameters: new Set(), operators: new Set(), features: new Set(), feature_sets: new Set(), datasets: new Set() };
|
|
175
|
+
const resource = (prefix) => (asset) => `/${prefix}/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.name)}/${encodeURIComponent(asset.version)}`;
|
|
176
|
+
await hydrate(client, current.parameters, catalog.parameters, resource("parameters"), normalizeParameter, key, hydrated.parameters);
|
|
177
|
+
const operatorRefs = catalog.features.map((asset) => ({ project: asset.project, name: asset.operator, version: asset.operator_version }));
|
|
178
|
+
await hydrate(client, current.operators, [...catalog.operators.map((item) => item.spec), ...operatorRefs], resource("operators"), normalizeOperator, key, hydrated.operators);
|
|
179
|
+
const featureSetRefs = catalog.datasets.map((asset) => ({ project: asset.project, ...asset.feature_set }));
|
|
180
|
+
await hydrate(client, current.feature_sets, [...catalog.feature_sets, ...featureSetRefs], resource("feature-sets"), normalizeFeatureSet, key, hydrated.feature_sets);
|
|
181
|
+
await hydrate(client, current.datasets, catalog.datasets, (asset) => `/datasets/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.dataset_id)}/${encodeURIComponent(asset.dataset_version)}`, normalizeDataset, datasetKey, hydrated.datasets);
|
|
182
|
+
const declaredFeatureSets = new Map(catalog.feature_sets.map((asset) => [key(asset), asset]));
|
|
183
|
+
const featureRefs = catalog.datasets.flatMap((asset) => (declaredFeatureSets.get(referenceKey(asset.feature_set)) ?? current.feature_sets.get(referenceKey(asset.feature_set)) ?? { features: [] }).features.map((feature) => ({ project: asset.project, ...feature })));
|
|
184
|
+
await hydrate(client, current.features, [...catalog.features, ...featureRefs], resource("features"), normalizeFeature, key, hydrated.features);
|
|
185
|
+
}
|
|
171
186
|
|
|
172
187
|
function requiresPackage(spec) { return ["custom_python", "feature", "spark_udf"].includes(spec.type) && spec.code_artifact == null && !String(spec.package_uri ?? "").startsWith("pythonpath://"); }
|
|
173
188
|
function validateCatalog(catalog, current) {
|
|
@@ -198,16 +213,14 @@ function assertImmutable(label, assetKey, candidate, existing) { if (existing &&
|
|
|
198
213
|
function sha256File(file) { return `sha256:${crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex")}`; }
|
|
199
214
|
|
|
200
215
|
async function applyCatalog(catalog, client, dryRun, targetProject) {
|
|
201
|
-
validateCatalogProject(catalog, targetProject); const current = await snapshot(client, targetProject); validateCatalog(catalog, current); const groups = { parameters: catalog.parameters.length, operators: catalog.operators.length, features: catalog.features.length, feature_sets: catalog.feature_sets.length, datasets: catalog.datasets.length }; const summary = Object.fromEntries(Object.entries(groups).map(([name, count]) => [name, { declared: count, planned: 0, applied: 0, unchanged: 0 }]));
|
|
202
|
-
for (const asset of catalog.parameters) { const assetKey = key(asset); if (current.parameters.has(assetKey)) current.parameters.set(assetKey, normalizeParameter(await client.get(`/parameters/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.name)}/${encodeURIComponent(asset.version)}`))); }
|
|
203
|
-
for (const asset of catalog.features) { const assetKey = key(asset); if (current.features.has(assetKey)) current.features.set(assetKey, normalizeFeature(await client.get(`/features/${encodeURIComponent(asset.project)}/${encodeURIComponent(asset.name)}/${encodeURIComponent(asset.version)}`))); }
|
|
216
|
+
validateCatalogProject(catalog, targetProject); const current = await snapshot(client, targetProject); await hydrateCatalog(client, catalog, current); validateCatalog(catalog, current); const groups = { parameters: catalog.parameters.length, operators: catalog.operators.length, features: catalog.features.length, feature_sets: catalog.feature_sets.length, datasets: catalog.datasets.length }; const summary = Object.fromEntries(Object.entries(groups).map(([name, count]) => [name, { declared: count, planned: 0, applied: 0, unchanged: 0 }]));
|
|
204
217
|
for (const asset of catalog.parameters) assertImmutable("parameter", key(asset), asset, current.parameters.get(key(asset)));
|
|
205
218
|
for (const item of catalog.operators) { const existing = current.operators.get(key(item.spec)); if (!existing) continue; let candidate = item.spec; if (item.package_path) { if (existing.code_hash !== sha256File(item.package_path) || !existing.code_artifact) throw new Error(`operator version is immutable: ${key(item.spec)}; publish a new version`); candidate = normalizeOperator({ ...item.spec, code_hash: existing.code_artifact.sha256, package_uri: existing.code_artifact.uri, code_artifact: existing.code_artifact }); } assertImmutable("operator", key(item.spec), candidate, existing); }
|
|
206
219
|
const plain = async (assets, existing, label, endpoint, keyFn = key, params) => { for (const asset of assets) { const assetKey = keyFn(asset); assertImmutable(label, assetKey, asset, existing.get(assetKey)); if (existing.has(assetKey)) summary[label].unchanged += 1; else if (dryRun) summary[label].planned += 1; else { await client.post(endpoint, asset, params); summary[label].applied += 1; } } };
|
|
207
220
|
try {
|
|
208
221
|
await plain(catalog.parameters, current.parameters, "parameters", "/parameters");
|
|
209
222
|
for (const item of catalog.operators) { const assetKey = key(item.spec); if (current.operators.has(assetKey)) summary.operators.unchanged += 1; else if (dryRun) summary.operators.planned += 1; else { let candidate = item.spec; if (item.package_path) { const uploaded = await client.uploadOperatorPackage(item.spec.project, item.spec.name, item.spec.version, item.package_path); candidate = normalizeOperator({ ...item.spec, code_hash: uploaded.code_artifact.sha256, package_uri: uploaded.code_artifact.uri, code_artifact: uploaded.code_artifact }); } await client.post("/operators", candidate); summary.operators.applied += 1; } }
|
|
210
|
-
await plain(catalog.features, current.features, "features", "/features"); await plain(catalog.feature_sets, current.feature_sets, "feature_sets", "/feature-sets"); await plain(catalog.datasets, current.datasets, "datasets", "/datasets", datasetKey
|
|
223
|
+
await plain(catalog.features, current.features, "features", "/features"); await plain(catalog.feature_sets, current.feature_sets, "feature_sets", "/feature-sets"); await plain(catalog.datasets, current.datasets, "datasets", "/datasets", datasetKey);
|
|
211
224
|
} catch (error) { throw new Error(`catalog apply failed after progress=${JSON.stringify(canonical(summary))}: ${error.message}`); }
|
|
212
225
|
return { status: dryRun ? "validated" : "applied", profile: "server", catalog: { name: catalog.manifest.name, version: catalog.manifest.version, path: catalog.path }, summary };
|
|
213
226
|
}
|
|
@@ -405,8 +405,9 @@ async function runBusinessCli(argv) {
|
|
|
405
405
|
({ result, exitCode } = await submitBuild(api, manifest, build));
|
|
406
406
|
} else if (["add-dataset", "update-dataset"].includes(options.command)) {
|
|
407
407
|
const manifest = readDataset(positional(rest, "manifest JSON")); const force = boolean(rest, "--force"); const project = manifest.project || "default";
|
|
408
|
-
|
|
409
|
-
|
|
408
|
+
const params = force ? { force: true } : undefined;
|
|
409
|
+
if (options.command === "add-dataset") result = await client(options).post("/datasets", manifest, params);
|
|
410
|
+
else result = await client(options).put(`/datasets/${encodeURIComponent(project)}/${encodeURIComponent(manifest.dataset_id)}/${encodeURIComponent(manifest.dataset_version)}`, manifest, params);
|
|
410
411
|
} else if (options.command === "delete-dataset") {
|
|
411
412
|
const id = positional(rest, "dataset id"); const version = positional(rest, "dataset version"); const project = take(rest, "--project", "default");
|
|
412
413
|
result = await client(options).delete(`/datasets/${encodeURIComponent(project)}/${encodeURIComponent(id)}/${encodeURIComponent(version)}`);
|