@platforma-sdk/block-tools 2.8.3 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +28 -28
- package/dist/cli.mjs.map +1 -1
- package/dist/{config-CzNlwcwn.mjs → config-DpfTzcgG.mjs} +570 -506
- package/dist/config-DpfTzcgG.mjs.map +1 -0
- package/dist/config-xxVy3IQR.js +3 -0
- package/dist/config-xxVy3IQR.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +15 -15
- package/dist/v2/model/block_components.d.ts +25 -653
- package/dist/v2/model/block_description.d.ts +24 -16221
- package/dist/v2/model/block_meta.d.ts +28 -4351
- package/dist/v2/model/content_conversion.d.ts +6 -13
- package/dist/v2/registry/schema_public.d.ts +39028 -0
- package/package.json +7 -7
- package/src/cmd/build-meta.ts +3 -3
- package/src/v2/build_dist.ts +8 -5
- package/src/v2/model/block_components.ts +77 -28
- package/src/v2/model/block_description.ts +109 -50
- package/src/v2/model/block_meta.ts +109 -29
- package/src/v2/model/content_conversion.ts +26 -51
- package/src/v2/registry/registry.ts +11 -11
- package/src/v2/registry/registry_reader.ts +7 -5
- package/src/v2/registry/schema_public.ts +108 -111
- package/src/v2/source_package.ts +3 -7
- package/dist/config-C8wPuCgh.js +0 -3
- package/dist/config-C8wPuCgh.js.map +0 -1
- package/dist/config-CzNlwcwn.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/block-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Utility to manipulate Platforma Blocks and Block Registry",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"yaml": "^2.8.0",
|
|
34
34
|
"zod": "~3.25.76",
|
|
35
35
|
"@milaboratories/pl-http": "1.2.4",
|
|
36
|
-
"@milaboratories/pl-model-middle-layer": "1.20.0",
|
|
37
36
|
"@milaboratories/pl-model-common": "1.42.0",
|
|
38
|
-
"@milaboratories/resolve-helper": "1.1.3",
|
|
39
|
-
"@milaboratories/ts-helpers": "1.8.2",
|
|
40
37
|
"@milaboratories/pl-model-backend": "1.3.3",
|
|
38
|
+
"@milaboratories/resolve-helper": "1.1.3",
|
|
39
|
+
"@milaboratories/pl-model-middle-layer": "1.22.0",
|
|
40
|
+
"@milaboratories/ts-helpers-oclif": "1.1.41",
|
|
41
41
|
"@platforma-sdk/blocks-deps-updater": "2.2.0",
|
|
42
|
-
"@milaboratories/ts-helpers
|
|
42
|
+
"@milaboratories/ts-helpers": "1.8.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"vite": "^8.0.6",
|
|
55
55
|
"vite-plugin-dts": "^4.5.3",
|
|
56
56
|
"vitest": "^4.1.3",
|
|
57
|
-
"@milaboratories/ts-builder": "1.5.0",
|
|
58
|
-
"@milaboratories/oclif-index": "1.1.1",
|
|
59
57
|
"@milaboratories/build-configs": "2.0.0",
|
|
58
|
+
"@milaboratories/oclif-index": "1.1.1",
|
|
59
|
+
"@milaboratories/ts-builder": "1.5.0",
|
|
60
60
|
"@milaboratories/ts-configs": "1.2.3"
|
|
61
61
|
},
|
|
62
62
|
"oclif": {
|
package/src/cmd/build-meta.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Command, Flags } from "@oclif/core";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { loadPackDescriptionRaw } from "../v2";
|
|
5
|
-
import {
|
|
5
|
+
import { embedBlockPackMetaAbsoluteBase64, resolveBlockPackMeta } from "../v2/model/block_meta";
|
|
6
6
|
|
|
7
7
|
export default class BuildMeta extends Command {
|
|
8
8
|
static override description =
|
|
@@ -29,8 +29,8 @@ export default class BuildMeta extends Command {
|
|
|
29
29
|
const { flags } = await this.parse(BuildMeta);
|
|
30
30
|
const modulePath = path.resolve(flags.modulePath);
|
|
31
31
|
const descriptionRaw = await loadPackDescriptionRaw(modulePath);
|
|
32
|
-
const metaEmbedded = await
|
|
33
|
-
|
|
32
|
+
const metaEmbedded = await embedBlockPackMetaAbsoluteBase64(
|
|
33
|
+
await resolveBlockPackMeta(descriptionRaw.meta, modulePath),
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
await fs.promises.writeFile(path.resolve(flags.destination), JSON.stringify(metaEmbedded));
|
package/src/v2/build_dist.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
import { BlockPackManifest, BlockPackManifestFile } from "@milaboratories/pl-model-middle-layer";
|
|
6
6
|
import type { CompiledTemplateV3 } from "@milaboratories/pl-model-backend";
|
|
7
7
|
import type { BlockPackDescriptionAbsolute } from "./model";
|
|
8
|
-
import {
|
|
8
|
+
import { consolidateBlockPackDescription } from "./model";
|
|
9
9
|
import fsp from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { gunzipSync } from "node:zlib";
|
|
@@ -23,8 +23,8 @@ async function workflowRequiredCapabilities(
|
|
|
23
23
|
descriptionRelative: BlockPackDescriptionManifest,
|
|
24
24
|
dst: string,
|
|
25
25
|
): Promise<string[] | undefined> {
|
|
26
|
-
// After
|
|
27
|
-
//
|
|
26
|
+
// After consolidateBlockPackDescription runs, components.workflow.main is
|
|
27
|
+
// always a `{type: "relative", path: ...}` reference into `dst`.
|
|
28
28
|
const main = descriptionRelative.components.workflow.main;
|
|
29
29
|
const bytes = await fsp.readFile(path.resolve(dst, main.path));
|
|
30
30
|
|
|
@@ -47,8 +47,11 @@ export async function buildBlockPackDist(
|
|
|
47
47
|
): Promise<BlockPackManifest> {
|
|
48
48
|
await fsp.mkdir(dst, { recursive: true });
|
|
49
49
|
const files: string[] = [];
|
|
50
|
-
const descriptionRelative: BlockPackDescriptionManifest =
|
|
51
|
-
|
|
50
|
+
const descriptionRelative: BlockPackDescriptionManifest = await consolidateBlockPackDescription(
|
|
51
|
+
description,
|
|
52
|
+
dst,
|
|
53
|
+
files,
|
|
54
|
+
);
|
|
52
55
|
|
|
53
56
|
// Per-block capability detection: mirror the workflow's
|
|
54
57
|
// compile-time-computed `requiredCapabilities` onto the published
|
|
@@ -1,38 +1,87 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
ResolvedModuleFile,
|
|
4
|
-
ResolvedModuleFolder,
|
|
5
|
-
packFolderToRelativeTgz,
|
|
6
|
-
cpAbsoluteToRelative,
|
|
7
|
-
} from "./content_conversion";
|
|
8
|
-
import {
|
|
1
|
+
import type {
|
|
9
2
|
BlockComponents,
|
|
3
|
+
BlockComponentsDescriptionRaw,
|
|
10
4
|
BlockComponentsManifest,
|
|
11
|
-
|
|
5
|
+
ContentAbsoluteFile,
|
|
12
6
|
ContentAbsoluteFolder,
|
|
13
|
-
|
|
14
|
-
mapRemoteToAbsolute,
|
|
7
|
+
ContentAbsoluteUrl,
|
|
15
8
|
} from "@milaboratories/pl-model-middle-layer";
|
|
9
|
+
import { mapRemoteToAbsolute } from "@milaboratories/pl-model-middle-layer";
|
|
10
|
+
import {
|
|
11
|
+
cpAbsoluteToRelative,
|
|
12
|
+
packFolderToRelativeTgz,
|
|
13
|
+
resolveModuleFile,
|
|
14
|
+
resolveModuleFolder,
|
|
15
|
+
} from "./content_conversion";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolved BlockComponents — workflow main and model resolved to absolute
|
|
19
|
+
* file references, UI request resolved to its absolute folder.
|
|
20
|
+
*/
|
|
21
|
+
export type BlockComponentsDescription = BlockComponents<
|
|
22
|
+
ContentAbsoluteFile,
|
|
23
|
+
ContentAbsoluteFolder
|
|
24
|
+
>;
|
|
25
|
+
|
|
26
|
+
/** BlockComponents pointing at registry-served URLs. */
|
|
27
|
+
export type BlockComponentsAbsoluteUrl = BlockComponents<ContentAbsoluteUrl, ContentAbsoluteUrl>;
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Resolves block-components paths from `package.json` raw form against the
|
|
31
|
+
* module root. Workflow and model strings are resolved via node module
|
|
32
|
+
* resolution; the UI request resolves to a folder containing `index.html`.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveBlockComponents(
|
|
35
|
+
raw: BlockComponentsDescriptionRaw,
|
|
36
|
+
moduleRoot: string,
|
|
37
|
+
): BlockComponentsDescription {
|
|
38
|
+
return {
|
|
39
|
+
workflow: {
|
|
40
|
+
type: "workflow-v1",
|
|
41
|
+
main: resolveModuleFile(moduleRoot, raw.workflow.main),
|
|
42
|
+
},
|
|
43
|
+
model: resolveModuleFile(moduleRoot, raw.model),
|
|
44
|
+
ui: resolveModuleFolder(moduleRoot, raw.ui, ["index.html"]),
|
|
45
|
+
};
|
|
22
46
|
}
|
|
23
|
-
export type BlockComponentsDescription = z.infer<ReturnType<typeof BlockComponentsDescription>>;
|
|
24
47
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Copies file references for workflow and model into `dstFolder`, packs the
|
|
50
|
+
* UI folder into `ui.tgz`, returning the manifest form with relative paths.
|
|
51
|
+
*/
|
|
52
|
+
export async function consolidateBlockComponents(
|
|
53
|
+
description: BlockComponentsDescription,
|
|
54
|
+
dstFolder: string,
|
|
55
|
+
fileAccumulator?: string[],
|
|
56
|
+
): Promise<BlockComponentsManifest> {
|
|
57
|
+
const cpToRel = cpAbsoluteToRelative(dstFolder, fileAccumulator);
|
|
58
|
+
const packToTgz = packFolderToRelativeTgz(dstFolder, "ui.tgz", fileAccumulator);
|
|
59
|
+
return {
|
|
60
|
+
workflow: {
|
|
61
|
+
type: "workflow-v1",
|
|
62
|
+
main: await cpToRel(description.workflow.main),
|
|
63
|
+
},
|
|
64
|
+
model: await cpToRel(description.model),
|
|
65
|
+
ui: await packToTgz(description.ui),
|
|
66
|
+
};
|
|
30
67
|
}
|
|
31
68
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Maps a manifest with relative paths to one with absolute URLs against the
|
|
71
|
+
* given prefix. Used by the registry reader to point components at registry
|
|
72
|
+
* storage.
|
|
73
|
+
*/
|
|
74
|
+
export function blockComponentsManifestToAbsoluteUrl(
|
|
75
|
+
manifest: BlockComponentsManifest,
|
|
76
|
+
prefix: string,
|
|
77
|
+
): BlockComponentsAbsoluteUrl {
|
|
78
|
+
const toAbs = mapRemoteToAbsolute(prefix);
|
|
79
|
+
return {
|
|
80
|
+
workflow: {
|
|
81
|
+
type: "workflow-v1",
|
|
82
|
+
main: toAbs(manifest.workflow.main),
|
|
83
|
+
},
|
|
84
|
+
model: toAbs(manifest.model),
|
|
85
|
+
ui: toAbs(manifest.ui),
|
|
86
|
+
};
|
|
37
87
|
}
|
|
38
|
-
export type BlockComponentsAbsoluteUrl = z.infer<ReturnType<typeof BlockComponentsAbsoluteUrl>>;
|
|
@@ -1,63 +1,122 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
BlockComponents,
|
|
1
|
+
import type {
|
|
2
|
+
BlockPackDescription,
|
|
4
3
|
BlockPackDescriptionManifest,
|
|
5
|
-
|
|
6
|
-
ContentRelative,
|
|
7
|
-
ContentRelativeBinary,
|
|
8
|
-
ContentRelativeText,
|
|
9
|
-
CreateBlockPackDescriptionSchema,
|
|
4
|
+
BlockPackDescriptionRaw,
|
|
10
5
|
} from "@milaboratories/pl-model-middle-layer";
|
|
11
|
-
import {
|
|
12
|
-
import { BlockPackMetaConsolidate, BlockPackMetaDescription } from "./block_meta";
|
|
13
|
-
import type { z } from "zod";
|
|
14
|
-
import fsp from "node:fs/promises";
|
|
6
|
+
import { addPrefixToRelative } from "@milaboratories/pl-model-middle-layer";
|
|
15
7
|
import type { BlockConfigContainer } from "@milaboratories/pl-model-common";
|
|
16
8
|
import { extractConfigGeneric } from "@milaboratories/pl-model-common";
|
|
9
|
+
import fsp from "node:fs/promises";
|
|
10
|
+
import type { BlockComponentsDescription } from "./block_components";
|
|
11
|
+
import { consolidateBlockComponents, resolveBlockComponents } from "./block_components";
|
|
12
|
+
import type { BlockPackMetaDescription } from "./block_meta";
|
|
13
|
+
import { consolidateBlockPackMeta, resolveBlockPackMeta } from "./block_meta";
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
).transform(async (description, _ctx) => {
|
|
23
|
-
const cfg = extractConfigGeneric(
|
|
24
|
-
JSON.parse(
|
|
25
|
-
await fsp.readFile(description.components.model.file, "utf-8"),
|
|
26
|
-
) as BlockConfigContainer,
|
|
27
|
-
);
|
|
28
|
-
const featureFlags = cfg.featureFlags;
|
|
29
|
-
return {
|
|
30
|
-
...description,
|
|
31
|
-
featureFlags,
|
|
32
|
-
};
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
export type BlockPackDescriptionAbsolute = z.infer<
|
|
36
|
-
ReturnType<typeof ResolvedBlockPackDescriptionFromPackageJson>
|
|
15
|
+
/** Resolved block-pack description — components + meta point at absolute file paths. */
|
|
16
|
+
export type BlockPackDescriptionAbsolute = BlockPackDescription<
|
|
17
|
+
BlockComponentsDescription,
|
|
18
|
+
BlockPackMetaDescription
|
|
37
19
|
>;
|
|
38
20
|
|
|
39
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Resolves a raw `package.json`-form block-pack description against the
|
|
23
|
+
* module root: workflow/model/ui paths via node module resolution, text and
|
|
24
|
+
* binary fields in `meta` via `mapLocalToAbsolute`. Reads the resolved model
|
|
25
|
+
* file to extract feature flags from its `BlockConfigContainer`.
|
|
26
|
+
*/
|
|
27
|
+
export async function resolveBlockPackDescription(
|
|
28
|
+
raw: BlockPackDescriptionRaw,
|
|
29
|
+
root: string,
|
|
30
|
+
): Promise<BlockPackDescriptionAbsolute> {
|
|
31
|
+
const components = resolveBlockComponents(raw.components, root);
|
|
32
|
+
const meta = await resolveBlockPackMeta(raw.meta, root);
|
|
33
|
+
const cfg = extractConfigGeneric(
|
|
34
|
+
JSON.parse(await fsp.readFile(components.model.file, "utf-8")) as BlockConfigContainer,
|
|
35
|
+
);
|
|
36
|
+
return {
|
|
37
|
+
...raw,
|
|
38
|
+
components,
|
|
39
|
+
meta,
|
|
40
|
+
featureFlags: cfg.featureFlags,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Consolidates absolute references in components and meta into `dstFolder`
|
|
46
|
+
* (copying files and packing the UI as `ui.tgz`), returning the manifest
|
|
47
|
+
* form with relative paths.
|
|
48
|
+
*/
|
|
49
|
+
export async function consolidateBlockPackDescription(
|
|
50
|
+
description: BlockPackDescriptionAbsolute,
|
|
40
51
|
dstFolder: string,
|
|
41
52
|
fileAccumulator?: string[],
|
|
42
|
-
) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
): Promise<BlockPackDescriptionManifest> {
|
|
54
|
+
const components = await consolidateBlockComponents(
|
|
55
|
+
description.components,
|
|
56
|
+
dstFolder,
|
|
57
|
+
fileAccumulator,
|
|
58
|
+
);
|
|
59
|
+
const meta = await consolidateBlockPackMeta(description.meta, dstFolder, fileAccumulator);
|
|
60
|
+
return {
|
|
61
|
+
...description,
|
|
62
|
+
components,
|
|
63
|
+
meta,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Maps `components` and `meta` of a `BlockPackDescription` independently,
|
|
69
|
+
* preserving every other top-level field (including the `BlockPackId` and
|
|
70
|
+
* any passthrough siblings). Sync counterpart to the schema-driven async
|
|
71
|
+
* pipelines in `block_meta.ts`/`block_components.ts`; used by callers that
|
|
72
|
+
* need a synchronous transform (e.g. relative-path rewriting).
|
|
73
|
+
*/
|
|
74
|
+
function transformBlockPackDescription<Cin, Min, Cout, Mout>(
|
|
75
|
+
description: BlockPackDescription<Cin, Min>,
|
|
76
|
+
mapComponents: (components: Cin) => Cout,
|
|
77
|
+
mapMeta: (meta: Min) => Mout,
|
|
78
|
+
): BlockPackDescription<Cout, Mout> {
|
|
79
|
+
return {
|
|
80
|
+
...description,
|
|
81
|
+
components: mapComponents(description.components),
|
|
82
|
+
meta: mapMeta(description.meta),
|
|
83
|
+
};
|
|
47
84
|
}
|
|
48
85
|
|
|
49
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Prefixes every relative-path field in a manifest description with the
|
|
88
|
+
* given path prefix (components workflow/model/ui plus meta text/binary
|
|
89
|
+
* fields).
|
|
90
|
+
*/
|
|
91
|
+
export function addRelativePathPrefix(
|
|
92
|
+
manifest: BlockPackDescriptionManifest,
|
|
93
|
+
prefix: string,
|
|
94
|
+
): BlockPackDescriptionManifest {
|
|
50
95
|
const transformer = addPrefixToRelative(prefix);
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
|
|
96
|
+
return transformBlockPackDescription(
|
|
97
|
+
manifest,
|
|
98
|
+
(components) => ({
|
|
99
|
+
workflow: {
|
|
100
|
+
type: "workflow-v1",
|
|
101
|
+
main: transformer(components.workflow.main),
|
|
102
|
+
},
|
|
103
|
+
model: transformer(components.model),
|
|
104
|
+
ui: transformer(components.ui),
|
|
105
|
+
}),
|
|
106
|
+
(meta) => {
|
|
107
|
+
const { logo: orgLogo, ...orgRest } = meta.organization;
|
|
108
|
+
return {
|
|
109
|
+
...meta,
|
|
110
|
+
organization: {
|
|
111
|
+
...orgRest,
|
|
112
|
+
...(orgLogo !== undefined ? { logo: transformer(orgLogo) } : {}),
|
|
113
|
+
},
|
|
114
|
+
...(meta.longDescription !== undefined
|
|
115
|
+
? { longDescription: transformer(meta.longDescription) }
|
|
116
|
+
: {}),
|
|
117
|
+
...(meta.changelog !== undefined ? { changelog: transformer(meta.changelog) } : {}),
|
|
118
|
+
...(meta.logo !== undefined ? { logo: transformer(meta.logo) } : {}),
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
);
|
|
63
122
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
BlockPackMeta,
|
|
3
|
+
BlockPackMetaDescriptionRaw,
|
|
3
4
|
BlockPackMetaEmbeddedBase64,
|
|
4
5
|
BlockPackMetaEmbeddedBytes,
|
|
6
|
+
BlockPackMetaManifest,
|
|
5
7
|
ContentAbsoluteBinaryLocal,
|
|
6
8
|
ContentAbsoluteTextLocal,
|
|
7
|
-
ContentRelativeBinary,
|
|
8
|
-
ContentRelativeText,
|
|
9
|
-
DescriptionContentBinary,
|
|
10
|
-
DescriptionContentText,
|
|
11
9
|
} from "@milaboratories/pl-model-middle-layer";
|
|
12
10
|
import type { RelativeContentReader } from "./content_conversion";
|
|
13
11
|
import {
|
|
@@ -19,36 +17,118 @@ import {
|
|
|
19
17
|
relativeToContentString,
|
|
20
18
|
relativeToExplicitBytes,
|
|
21
19
|
} from "./content_conversion";
|
|
22
|
-
import type { z } from "zod";
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
/** Resolved BlockPackMeta — text/binary references mapped to absolute file refs. */
|
|
22
|
+
export type BlockPackMetaDescription = BlockPackMeta<
|
|
23
|
+
ContentAbsoluteTextLocal,
|
|
24
|
+
ContentAbsoluteBinaryLocal
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Applies independent transforms to BlockPackMeta's text-content and
|
|
29
|
+
* binary-content fields (`longDescription`, `changelog`, `logo`,
|
|
30
|
+
* `organization.logo`). All other fields, including unknown passthrough keys,
|
|
31
|
+
* pass through unchanged.
|
|
32
|
+
*
|
|
33
|
+
* Spread order matters: `...meta` first preserves every key (including
|
|
34
|
+
* passthrough); the conditional spreads at the end override the four
|
|
35
|
+
* transformed fields. Reading bottom-up: the per-field spreads win over
|
|
36
|
+
* the bulk spread.
|
|
37
|
+
*/
|
|
38
|
+
async function transformBlockPackMeta<LongStringIn, BinaryIn, LongStringOut, BinaryOut>(
|
|
39
|
+
meta: BlockPackMeta<LongStringIn, BinaryIn>,
|
|
40
|
+
mapText: (value: LongStringIn) => Promise<LongStringOut>,
|
|
41
|
+
mapBinary: (value: BinaryIn) => Promise<BinaryOut>,
|
|
42
|
+
): Promise<BlockPackMeta<LongStringOut, BinaryOut>> {
|
|
43
|
+
const { organization } = meta;
|
|
44
|
+
const { logo: orgLogo, ...orgRest } = organization;
|
|
45
|
+
const out = {
|
|
46
|
+
...meta,
|
|
47
|
+
organization: {
|
|
48
|
+
...orgRest,
|
|
49
|
+
...(orgLogo !== undefined ? { logo: await mapBinary(orgLogo) } : {}),
|
|
50
|
+
},
|
|
51
|
+
...(meta.longDescription !== undefined
|
|
52
|
+
? { longDescription: await mapText(meta.longDescription) }
|
|
53
|
+
: {}),
|
|
54
|
+
...(meta.changelog !== undefined ? { changelog: await mapText(meta.changelog) } : {}),
|
|
55
|
+
...(meta.logo !== undefined ? { logo: await mapBinary(meta.logo) } : {}),
|
|
56
|
+
};
|
|
57
|
+
return out as BlockPackMeta<LongStringOut, BinaryOut>;
|
|
29
58
|
}
|
|
30
|
-
export type BlockPackMetaDescription = z.infer<ReturnType<typeof BlockPackMetaDescription>>;
|
|
31
59
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Resolves text/binary references in raw BlockPackMeta (post-`package.json`
|
|
62
|
+
* normalization) to absolute file paths against the module root.
|
|
63
|
+
*/
|
|
64
|
+
export async function resolveBlockPackMeta(
|
|
65
|
+
raw: BlockPackMetaDescriptionRaw,
|
|
66
|
+
root: string,
|
|
67
|
+
): Promise<BlockPackMetaDescription> {
|
|
68
|
+
const toAbs = mapLocalToAbsolute(root);
|
|
69
|
+
return transformBlockPackMeta(
|
|
70
|
+
raw,
|
|
71
|
+
async (v) => toAbs(v),
|
|
72
|
+
async (v) => toAbs(v),
|
|
36
73
|
);
|
|
37
74
|
}
|
|
38
75
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Copies absolute text/binary file references into `dstFolder` and returns
|
|
78
|
+
* the manifest form with relative paths.
|
|
79
|
+
*/
|
|
80
|
+
export async function consolidateBlockPackMeta(
|
|
81
|
+
meta: BlockPackMetaDescription,
|
|
82
|
+
dstFolder: string,
|
|
83
|
+
fileAccumulator?: string[],
|
|
84
|
+
): Promise<BlockPackMetaManifest> {
|
|
85
|
+
const cpToRel = cpAbsoluteToRelative(dstFolder, fileAccumulator);
|
|
86
|
+
return transformBlockPackMeta(
|
|
87
|
+
meta,
|
|
88
|
+
async (v) => cpToRel(v),
|
|
89
|
+
async (v) => cpToRel(v),
|
|
90
|
+
) as Promise<BlockPackMetaManifest>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Reads absolute file references and embeds the content as in-line strings
|
|
95
|
+
* and base64-encoded binary blobs.
|
|
96
|
+
*/
|
|
97
|
+
export async function embedBlockPackMetaAbsoluteBase64(
|
|
98
|
+
meta: BlockPackMetaDescription,
|
|
99
|
+
): Promise<BlockPackMetaEmbeddedBase64> {
|
|
100
|
+
return transformBlockPackMeta(
|
|
101
|
+
meta,
|
|
102
|
+
absoluteToString(),
|
|
103
|
+
absoluteToBase64(),
|
|
104
|
+
) as Promise<BlockPackMetaEmbeddedBase64>;
|
|
105
|
+
}
|
|
43
106
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Reads absolute file references and embeds the content as in-line strings
|
|
109
|
+
* and raw byte arrays.
|
|
110
|
+
*/
|
|
111
|
+
export async function embedBlockPackMetaAbsoluteBytes(
|
|
112
|
+
meta: BlockPackMetaDescription,
|
|
113
|
+
): Promise<BlockPackMetaEmbeddedBytes> {
|
|
114
|
+
return transformBlockPackMeta(
|
|
115
|
+
meta,
|
|
116
|
+
absoluteToString(),
|
|
117
|
+
absoluteToBytes(),
|
|
118
|
+
) as Promise<BlockPackMetaEmbeddedBytes>;
|
|
119
|
+
}
|
|
48
120
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Reads relative-path references through the given content reader and embeds
|
|
123
|
+
* the content as in-line strings and raw byte arrays.
|
|
124
|
+
*/
|
|
125
|
+
export async function embedBlockPackMetaBytes(
|
|
126
|
+
manifest: BlockPackMetaManifest,
|
|
127
|
+
reader: RelativeContentReader,
|
|
128
|
+
): Promise<BlockPackMetaEmbeddedBytes> {
|
|
129
|
+
return transformBlockPackMeta(
|
|
130
|
+
manifest,
|
|
131
|
+
relativeToContentString(reader),
|
|
132
|
+
relativeToExplicitBytes(reader),
|
|
133
|
+
) as Promise<BlockPackMetaEmbeddedBytes>;
|
|
54
134
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import fsp from "node:fs/promises";
|
|
4
3
|
import * as mime from "mime-types";
|
|
@@ -33,60 +32,36 @@ type ContentCtxUrl = {
|
|
|
33
32
|
/** Describes a place relative to which any content references should be interpreted */
|
|
34
33
|
export type ContentCtx = ContentCtxFs | ContentCtxUrl;
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
function
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Zod type that resolves node module request into absolute content */
|
|
44
|
-
export function ResolvedModuleFile(moduleRoot: string) {
|
|
45
|
-
return z.string().transform<ContentAbsoluteFile>((request, ctx) => {
|
|
46
|
-
const result = tryResolve(moduleRoot, request);
|
|
47
|
-
if (result === undefined) {
|
|
48
|
-
ctx.addIssue({
|
|
49
|
-
code: z.ZodIssueCode.custom,
|
|
50
|
-
message: `Can't resolve ${request} against ${moduleRoot}`,
|
|
51
|
-
});
|
|
52
|
-
return z.NEVER;
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
type: "absolute-file",
|
|
56
|
-
file: result,
|
|
57
|
-
};
|
|
58
|
-
});
|
|
35
|
+
/** Resolves a node module request to an absolute file reference. */
|
|
36
|
+
export function resolveModuleFile(moduleRoot: string, request: string): ContentAbsoluteFile {
|
|
37
|
+
const result = tryResolve(moduleRoot, request);
|
|
38
|
+
if (result === undefined) throw new Error(`Can't resolve ${request} against ${moduleRoot}`);
|
|
39
|
+
return { type: "absolute-file", file: result };
|
|
59
40
|
}
|
|
60
41
|
|
|
61
42
|
/**
|
|
62
|
-
*
|
|
63
|
-
* given a list of expected index
|
|
64
|
-
|
|
65
|
-
export function
|
|
43
|
+
* Resolves a node module request for a folder to an absolute folder reference,
|
|
44
|
+
* given a list of expected index file names in that folder.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveModuleFolder(
|
|
66
47
|
moduleRoot: string,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
ctx.addIssue({
|
|
85
|
-
code: z.ZodIssueCode.custom,
|
|
86
|
-
message: `Can't resolve ${request} folder against ${moduleRoot}, no index file found (${indexFilesToLookFor.join(", ")})`,
|
|
87
|
-
});
|
|
88
|
-
return z.NEVER;
|
|
89
|
-
});
|
|
48
|
+
request: string,
|
|
49
|
+
indexFilesToLookFor: [string, ...string[]],
|
|
50
|
+
): ContentAbsoluteFolder {
|
|
51
|
+
const requestWithSlash = request.endsWith("/") ? request : `${request}/`;
|
|
52
|
+
for (const idxFile of indexFilesToLookFor) {
|
|
53
|
+
const result = tryResolve(moduleRoot, requestWithSlash + idxFile);
|
|
54
|
+
if (result === undefined) continue;
|
|
55
|
+
if (!result.endsWith(idxFile))
|
|
56
|
+
throw new Error(`Unexpected resolve result ${result} with index file ${idxFile}`);
|
|
57
|
+
return {
|
|
58
|
+
type: "absolute-folder",
|
|
59
|
+
folder: result.slice(0, result.length - idxFile.length),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Can't resolve ${request} folder against ${moduleRoot}, no index file found (${indexFilesToLookFor.join(", ")})`,
|
|
64
|
+
);
|
|
90
65
|
}
|
|
91
66
|
|
|
92
67
|
export function mapLocalToAbsolute(
|