@platforma-sdk/block-tools 2.8.4 → 2.9.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/block-tools",
3
- "version": "2.8.4",
3
+ "version": "2.9.1",
4
4
  "description": "Utility to manipulate Platforma Blocks and Block Registry",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -32,14 +32,14 @@
32
32
  "undici": "~7.16.0",
33
33
  "yaml": "^2.8.0",
34
34
  "zod": "~3.25.76",
35
- "@milaboratories/pl-http": "1.2.4",
35
+ "@milaboratories/pl-model-backend": "1.3.4",
36
36
  "@milaboratories/pl-model-common": "1.42.0",
37
- "@milaboratories/pl-model-middle-layer": "1.21.0",
38
- "@milaboratories/pl-model-backend": "1.3.3",
39
- "@milaboratories/ts-helpers-oclif": "1.1.41",
37
+ "@milaboratories/pl-http": "1.2.4",
40
38
  "@milaboratories/resolve-helper": "1.1.3",
39
+ "@milaboratories/pl-model-middle-layer": "1.22.0",
41
40
  "@milaboratories/ts-helpers": "1.8.2",
42
- "@platforma-sdk/blocks-deps-updater": "2.2.0"
41
+ "@platforma-sdk/blocks-deps-updater": "2.2.0",
42
+ "@milaboratories/ts-helpers-oclif": "1.1.41"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@rollup/plugin-node-resolve": "^16.0.1",
@@ -56,8 +56,8 @@
56
56
  "vitest": "^4.1.3",
57
57
  "@milaboratories/build-configs": "2.0.0",
58
58
  "@milaboratories/oclif-index": "1.1.1",
59
- "@milaboratories/ts-configs": "1.2.3",
60
- "@milaboratories/ts-builder": "1.5.0"
59
+ "@milaboratories/ts-builder": "1.5.0",
60
+ "@milaboratories/ts-configs": "1.2.3"
61
61
  },
62
62
  "oclif": {
63
63
  "bin": "block-tools",
@@ -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 { BlockPackMetaDescription, BlockPackMetaEmbedAbsoluteBase64 } from "../v2/model/block_meta";
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 BlockPackMetaEmbedAbsoluteBase64.parseAsync(
33
- BlockPackMetaDescription(modulePath).parse(descriptionRaw.meta),
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));
@@ -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 { BlockPackDescriptionConsolidateToFolder } from "./model";
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 BlockPackDescriptionConsolidateToFolder runs, components.workflow.main
27
- // is always a {type: "relative", path: ...} reference into dst.
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
- await BlockPackDescriptionConsolidateToFolder(dst, files).parseAsync(description);
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 { z } from "zod";
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
- ContentAbsoluteBinaryLocal,
5
+ ContentAbsoluteFile,
12
6
  ContentAbsoluteFolder,
13
- ContentRelative,
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
- export function BlockComponentsDescription(moduleRoot: string) {
18
- return BlockComponents(
19
- ResolvedModuleFile(moduleRoot),
20
- ResolvedModuleFolder(moduleRoot, "index.html"),
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
- export function BlockComponentsConsolidate(dstFolder: string, fileAccumulator?: string[]) {
26
- return BlockComponents(
27
- ContentAbsoluteBinaryLocal.transform(cpAbsoluteToRelative(dstFolder, fileAccumulator)),
28
- ContentAbsoluteFolder.transform(packFolderToRelativeTgz(dstFolder, "ui.tgz", fileAccumulator)),
29
- ).pipe(BlockComponentsManifest);
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
- export function BlockComponentsAbsoluteUrl(prefix: string) {
33
- return BlockComponents(
34
- ContentRelative.transform(mapRemoteToAbsolute(prefix)),
35
- ContentRelative.transform(mapRemoteToAbsolute(prefix)),
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
- addPrefixToRelative,
3
- BlockComponents,
1
+ import type {
2
+ BlockPackDescription,
4
3
  BlockPackDescriptionManifest,
5
- BlockPackMeta,
6
- ContentRelative,
7
- ContentRelativeBinary,
8
- ContentRelativeText,
9
- CreateBlockPackDescriptionSchema,
4
+ BlockPackDescriptionRaw,
10
5
  } from "@milaboratories/pl-model-middle-layer";
11
- import { BlockComponentsConsolidate, BlockComponentsDescription } from "./block_components";
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
- export function ResolvedBlockPackDescriptionFromPackageJson(root: string) {
19
- return CreateBlockPackDescriptionSchema(
20
- BlockComponentsDescription(root),
21
- BlockPackMetaDescription(root),
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
- export function BlockPackDescriptionConsolidateToFolder(
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
- return CreateBlockPackDescriptionSchema(
44
- BlockComponentsConsolidate(dstFolder, fileAccumulator),
45
- BlockPackMetaConsolidate(dstFolder, fileAccumulator),
46
- ).pipe(BlockPackDescriptionManifest);
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
- export function BlockPackDescriptionManifestAddRelativePathPrefix(prefix: string) {
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 BlockPackDescriptionManifest.pipe(
52
- CreateBlockPackDescriptionSchema(
53
- BlockComponents(
54
- ContentRelative.transform(transformer),
55
- ContentRelative.transform(transformer),
56
- ),
57
- BlockPackMeta(
58
- ContentRelativeText.transform(transformer),
59
- ContentRelativeBinary.transform(transformer),
60
- ),
61
- ),
62
- ).pipe(BlockPackDescriptionManifest);
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
- export function BlockPackMetaDescription(root: string) {
25
- return BlockPackMeta(
26
- DescriptionContentText.transform(mapLocalToAbsolute(root)),
27
- DescriptionContentBinary.transform(mapLocalToAbsolute(root)),
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
- export function BlockPackMetaConsolidate(dstFolder: string, fileAccumulator?: string[]) {
33
- return BlockPackMeta(
34
- ContentAbsoluteTextLocal.transform(cpAbsoluteToRelative(dstFolder, fileAccumulator)),
35
- ContentAbsoluteBinaryLocal.transform(cpAbsoluteToRelative(dstFolder, fileAccumulator)),
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
- export const BlockPackMetaEmbedAbsoluteBase64 = BlockPackMeta(
40
- ContentAbsoluteTextLocal.transform(absoluteToString()),
41
- ContentAbsoluteBinaryLocal.transform(absoluteToBase64()),
42
- ).pipe(BlockPackMetaEmbeddedBase64);
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
- export const BlockPackMetaEmbedAbsoluteBytes = BlockPackMeta(
45
- ContentAbsoluteTextLocal.transform(absoluteToString()),
46
- ContentAbsoluteBinaryLocal.transform(absoluteToBytes()),
47
- ).pipe(BlockPackMetaEmbeddedBytes);
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
- export function BlockPackMetaEmbedBytes(reader: RelativeContentReader) {
50
- return BlockPackMeta(
51
- ContentRelativeText.transform(relativeToContentString(reader)),
52
- ContentRelativeBinary.transform(relativeToExplicitBytes(reader)),
53
- ).pipe(BlockPackMetaEmbeddedBytes);
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
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- utility function for future use
37
- function mustResolve(root: string, request: string): string {
38
- const res = tryResolve(root, request);
39
- if (res === undefined) throw new Error(`Can't resolve ${request} against ${root}`);
40
- return res;
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
- * Zod type that resolves node module request for folder into absolute folder,
63
- * given a list of expected index files in that folder
64
- * */
65
- export function ResolvedModuleFolder(
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
- ...indexFilesToLookFor: [string, ...string[]]
68
- ) {
69
- return z.string().transform<ContentAbsoluteFolder>((request, ctx) => {
70
- const requestWithSlash = request.endsWith("/") ? request : `${request}/`;
71
-
72
- for (const idxFile of indexFilesToLookFor) {
73
- const result = tryResolve(moduleRoot, requestWithSlash + idxFile);
74
- if (result !== undefined) {
75
- if (!result.endsWith(idxFile))
76
- throw new Error(`Unexpected resolve result ${result} with index file ${idxFile}`);
77
- return {
78
- type: "absolute-folder",
79
- folder: result.slice(0, result.length - idxFile.length),
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(