@silvermoon-work/task-builder 0.0.0-stage → 0.1.0-canary-261109-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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 shazhou-ww
4
+ Copyright (c) 2026 silvermoon-work contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,251 @@
1
- # Temporary Holding Version
1
+ # @silvermoon-work/task-builder
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Build Task Bundles with esbuild from a read-only file tree into another read-only
4
+ file tree. No pguide command protocol, Gulp, Vinyl, CAR, network, publication, or
5
+ output-directory management is part of the transformation.
6
+
7
+ ## Transformation
8
+
9
+ ```ts
10
+ import {
11
+ buildTaskBundle,
12
+ type ReadonlyFileTree,
13
+ } from "@silvermoon-work/task-builder";
14
+
15
+ const output: ReadonlyFileTree = await buildTaskBundle(input, {
16
+ name: "Echo",
17
+ runtime: { minVersion: "22.13.0" },
18
+ source: {
19
+ entry: "src/main.ts",
20
+ contract: {
21
+ input: { type: "object", properties: { text: { type: "string" } } },
22
+ result: { type: "string" },
23
+ message: false,
24
+ },
25
+ mode: "explicit",
26
+ },
27
+ include: [{ from: "assets/**", to: "resources/" }],
28
+ binary: ["resources/images/**"],
29
+ signal,
30
+ });
31
+
32
+ const entries = await output.list("");
33
+ const resource = await output.read("resources/config.json", { signal });
34
+ ```
35
+
36
+ The input variable is a caller-supplied tree, not a host path:
37
+
38
+ ```ts
39
+ interface ReadonlyFileTree {
40
+ list(path: string, options?: { signal?: AbortSignal }): Promise<readonly {
41
+ name: string;
42
+ kind: "file" | "directory";
43
+ target?: string;
44
+ }[]>;
45
+ read(path: string, options?: {
46
+ signal?: AbortSignal;
47
+ }): Promise<ReadableStream<Uint8Array>>;
48
+ }
49
+ ```
50
+
51
+ `""` lists the root. Listings contain direct children, with names rather than
52
+ full paths. Logical paths use `/` on every OS; absolute paths, traversal,
53
+ backslashes, colons and control characters are rejected. Missing paths, wrong
54
+ file/directory kinds, invalid entries and input failures are explicit errors.
55
+ Every read must return a new stream of the same bytes. The caller must keep the
56
+ input version and its lifetime stable while using the output.
57
+ An optional `target` is a canonical path inside the same tree for an alias;
58
+ ordinary virtual trees need not provide it. The directory adapter supplies it
59
+ for confined links so package imports resolve from their real dependency
60
+ location, including pnpm's virtual store.
61
+
62
+ ## Streaming and ownership
63
+
64
+ The generated primary Schemas are `schemas/input.json`, `schemas/result.json`
65
+ and `schemas/message.json`; the manifest references those exact paths.
66
+ Additional contract Schemas use a name-to-Schema object, for example
67
+ `schemas: { user: UserSchema, address: AddressSchema }`, and become
68
+ `schemas/shared/user.json` and `schemas/shared/address.json`. Names must be
69
+ single portable file-name stems with no traversal, separators, reserved device
70
+ names, non-NFC spellings or case-insensitive collisions. Array declarations are
71
+ rejected rather than automatically numbered. Named Schemas are sorted by name
72
+ for deterministic output, independent of object insertion order.
73
+ Author-supplied `$id` and `$ref` values are preserved. Primary fallback IDs
74
+ remain unchanged; shared definitions without an `$id` receive
75
+ `https://task.invalid/schema/shared/<URI-encoded-name>`. References use Schema
76
+ identities, not object keys; missing references or conflicting identities fail.
77
+ Existing output directories are not renamed automatically; rebuild into a new
78
+ directory to obtain the new layout.
79
+
80
+ - Module source, package metadata and contracts are aggregated **per file**
81
+ because esbuild's `onLoad` requires complete bytes. Source reads and the module
82
+ graph have separate byte/file/path budgets; this is not a fully streaming JS
83
+ compiler.
84
+ - Building reads resource listings, but does not open resource contents.
85
+ `output.read()` itself does not open the input resource either: first demand
86
+ does. Resource chunks pass through with backpressure, without whole-resource
87
+ aggregation or a temporary snapshot. Normalization buffers at most an upstream
88
+ chunk plus its transformed bytes and UTF-8 decoder state. Input adapters should
89
+ emit reasonably sized chunks; the Node adapter uses 64 KiB.
90
+ - Text validates incremental UTF-8 and normalizes CRLF/lone CR to LF, including
91
+ CRLF and UTF-8 sequences split across chunks. BOM and all other bytes are
92
+ preserved. Explicit binary resource globs preserve bytes exactly.
93
+ - Cancel or abort of a resource stream cancels its upstream reader. Each read
94
+ has independent normalization and cancellation state. The build signal applies
95
+ only to construction; output reads use their own signal.
96
+ - Generated Worker, manifest and Schema bytes are owned by the output. Readers
97
+ receive copies. Resources retain a reference to the input, not a byte snapshot;
98
+ changing or closing the input changes or breaks subsequent reads.
99
+ - Manifest, path collisions, Schema closure and generated bytes are validated
100
+ before build returns. Resource UTF-8, input failures and byte capacities can
101
+ fail later during reading, including at EOF. **A returned tree is not proof
102
+ that all resource bytes have been validated.** Consume every file to EOF before
103
+ treating it as a distributable Bundle. Partial reads do not validate the tail.
104
+ - Resource capacity accounting tracks the maximum observed normalized length per
105
+ logical file across reads, so repeated/concurrent reads do not double-count.
106
+ Protocol defaults remain 64 MiB per file/total, 256 files and 512 paths.
107
+
108
+ ## Modules and contracts
109
+
110
+ An esbuild namespace confines module loading to the input tree. `enhanced-resolve`
111
+ uses a tree-backed filesystem for relative imports, extension resolution,
112
+ `.js` to `.ts` aliases, `node_modules`, package exports/imports and Node
113
+ import/require conditions. Only Node builtins remain external. Missing
114
+ dependencies never fall back to the builder's own node_modules.
115
+
116
+ Dependencies must be present in the input tree. There is no install, network
117
+ resolver, automatic tsconfig discovery, tsconfig path mapping, arbitrary asset
118
+ loader or externally supplied esbuild plugin in this first implementation.
119
+ Compilation targets Node 22 CommonJS and rejects non-static import/require calls.
120
+ The build host must use Node >=22.13; execution runtime eligibility belongs to
121
+ the Engine.
122
+
123
+ `source.mode` defaults to `explicit`: the entry calls the SDK's `runTask`
124
+ itself. `callback` wraps a lazily imported callback; `exportName` defaults to
125
+ `default` and is only accepted in that mode. `source.sdk` defaults to
126
+ `@silvermoon-work/task-sdk` for callback wrappers and can explicitly select an
127
+ SDK already present in the tree. The SDK has not been migrated into this
128
+ repository; existing projects can supply `@potential-guide/task-sdk`.
129
+ Recognized SDK `binding.js`/`binding.ts` modules are replaced with the resolved
130
+ Bundle declaration without evaluating the Worker or author callback.
131
+
132
+ `source.contract` accepts an object, a tree-relative JSON file, or a trusted
133
+ TS/JS module default-exporting `{ input, result, message, schemas? }`. Objects
134
+ can contain plain JSON Schema or supported TypeBox 0.34.52 schemas; transforms
135
+ and unsupported metadata/format semantics are rejected. Code contracts require
136
+ `allowContractExecution: true`. They are compiled using the same tree resolver,
137
+ then **executed as trusted Node code, not in a sandbox**. Builtins and global
138
+ APIs can have side effects; a read-only tree is not an execution security boundary.
139
+ Their `__filename`, `__dirname` and `import.meta.url` are logical `task-tree:///`
140
+ locations, not host source paths. Use JSON contracts for non-executing builds.
141
+
142
+ For example, a JSON contract can share one definition between input and result:
143
+
144
+ ```json
145
+ {
146
+ "input": {
147
+ "type": "object",
148
+ "properties": {
149
+ "user": { "$ref": "https://example.invalid/schemas/user" }
150
+ }
151
+ },
152
+ "result": { "$ref": "https://example.invalid/schemas/user" },
153
+ "message": false,
154
+ "schemas": {
155
+ "user": {
156
+ "$id": "https://example.invalid/schemas/user",
157
+ "type": "object",
158
+ "properties": { "name": { "type": "string" } }
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ Text contracts reject duplicate JSON/YAML keys during strict parsing, including
165
+ escaped JSON keys with the same decoded spelling. JS/TS objects can overwrite
166
+ duplicate keys before evaluation returns; that information cannot be recovered
167
+ by the builder. Case-insensitive name collisions are still checked after
168
+ evaluation. The build YAML and final `task.yaml` protocol structure do not change;
169
+ the latter only lists the newly named files in `include`.
170
+
171
+ ## Standalone CLI
172
+
173
+ The Node adapter is deliberately separate:
174
+
175
+ ```ts
176
+ import { directoryTree, writeDirectory } from "@silvermoon-work/task-builder/node";
177
+
178
+ const input = await directoryTree(projectDirectory);
179
+ const output = await buildTaskBundle(input, options);
180
+ await writeDirectory(output, newOutputDirectory);
181
+ ```
182
+
183
+ The directory adapter is a live view, not an atomic snapshot under concurrent
184
+ filesystem changes. It follows links only to regular files/directories within
185
+ the chosen root, allowing confined pnpm dependency links. It rejects escaping
186
+ links and special files; this is not an OS sandbox.
187
+
188
+ Create `task.build.yaml`:
189
+
190
+ ```yaml
191
+ name: Echo
192
+ runtime:
193
+ minVersion: "22.13.0"
194
+ source:
195
+ entry: src/main.ts
196
+ contract: src/contract.json
197
+ mode: explicit
198
+ include:
199
+ - from: assets/**
200
+ to: resources/
201
+ outDirectory: dist
202
+ binary: []
203
+ ```
204
+
205
+ All source paths and include globs are relative to this file; include destinations
206
+ and binary globs refer to final Bundle paths. Include rules skip dot entries and
207
+ node_modules, must match a file, and cannot overlap or traverse the output.
208
+ The existing author `$schema` URI is accepted when explicitly supplied; it is
209
+ not rewritten. Unknown configuration fields are rejected.
210
+
211
+ ```sh
212
+ task-builder task.build.yaml --root <project-directory>
213
+ # Trusted TypeBox module contract:
214
+ task-builder task.build.yaml --root <project-directory> --trusted-contract
215
+ ```
216
+
217
+ In this repository, after building the package:
218
+
219
+ ```sh
220
+ pnpm --filter @silvermoon-work/task-builder build
221
+ node packages/task-builder/dist/cli.js task.build.yaml --root <project-directory>
222
+ ```
223
+
224
+ The CLI streams files sequentially into a **new** output directory and returns
225
+ JSON `{ directory, files }` only after every stream completes. The output's
226
+ parent must already exist and be canonical. Existing output is never replaced;
227
+ on failure, only newly created files/directories are removed. Build interruption
228
+ aborts active I/O. There is no init, watch, CAR generation or publication.
229
+
230
+ Try the included [Echo task](./examples/echo/task.build.yaml) from the repository
231
+ root after installation and build:
232
+
233
+ ```sh
234
+ node packages/task-builder/dist/cli.js packages/task-builder/examples/echo/task.build.yaml
235
+ ```
236
+
237
+ The root includes the installed dependency tree, so this example can bundle the
238
+ published SDK used by the repository's tests. The generated directory is
239
+ `packages/task-builder/examples/echo/dist`. It contains a real SDK Worker meant
240
+ to be started by a Task Engine, not executed directly as a standalone script.
241
+
242
+ ## Validation
243
+
244
+ ```sh
245
+ pnpm --filter @silvermoon-work/task-builder... build
246
+ pnpm --filter @silvermoon-work/task-builder test
247
+ pnpm check
248
+ ```
249
+
250
+ The contract conversion and SDK binding behavior were extracted from
251
+ potential-guide's MIT-licensed author tooling; its license notice is retained.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import { resolve, sep } from "node:path";
3
+ import { buildTaskBundle, readTaskBuild } from "./index.js";
4
+ import { directoryTree, writeDirectory } from "./node.js";
5
+ const help = `Usage: task-builder <task.build.yaml> [--root <directory>] [--trusted-contract]
6
+
7
+ Build a Task Bundle into the build file's outDirectory (must not exist).
8
+ Paths in the build file are relative to that file inside --root (default: cwd).
9
+ Resources are streamed to disk; no CAR, upload, or pguide command protocol.
10
+ Code contracts are executed only with --trusted-contract; JSON contracts need no flag.
11
+ `;
12
+ async function main(argv) {
13
+ if (argv.includes("--help") || argv.includes("-h")) {
14
+ process.stdout.write(help);
15
+ return;
16
+ }
17
+ let root = process.cwd();
18
+ let file;
19
+ let trusted = false;
20
+ for (let index = 0; index < argv.length; index++) {
21
+ const arg = argv[index];
22
+ if (arg === "--root") {
23
+ const value = argv[++index];
24
+ if (!value || value.startsWith("--"))
25
+ throw new Error("--root requires a directory.");
26
+ root = resolve(value);
27
+ }
28
+ else if (arg === "--trusted-contract")
29
+ trusted = true;
30
+ else if (arg.startsWith("-") || file !== undefined)
31
+ throw new Error(help);
32
+ else
33
+ file = arg;
34
+ }
35
+ if (!file)
36
+ throw new Error(help);
37
+ const controller = new AbortController();
38
+ const interrupt = () => controller.abort(new Error("Build interrupted."));
39
+ process.once("SIGINT", interrupt);
40
+ process.once("SIGTERM", interrupt);
41
+ try {
42
+ const input = await directoryTree(root);
43
+ const definition = await readTaskBuild(input, file.split(sep).join("/"), {
44
+ signal: controller.signal,
45
+ allowContractExecution: trusted,
46
+ });
47
+ const tree = await buildTaskBundle(input, definition.options);
48
+ const directory = resolve(root, ...definition.outDirectory.split("/"));
49
+ const files = await writeDirectory(tree, directory, { signal: controller.signal });
50
+ process.stdout.write(`${JSON.stringify({ directory, files })}\n`);
51
+ }
52
+ finally {
53
+ process.removeListener("SIGINT", interrupt);
54
+ process.removeListener("SIGTERM", interrupt);
55
+ }
56
+ }
57
+ void main(process.argv.slice(2)).catch((error) => {
58
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
59
+ process.exitCode = 1;
60
+ });
61
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type JsonObject } from "@silvermoon-work/task-protocol";
2
+ export declare function toTaskSchema(value: unknown): unknown;
3
+ export declare function contractSchemas(value: unknown): {
4
+ path: string;
5
+ document: JsonObject;
6
+ }[];
7
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAuCzF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAqDpD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAA;CAAE,EAAE,CAyDxF"}
@@ -0,0 +1,146 @@
1
+ import { Kind, OptionalKind, ReadonlyKind } from "@sinclair/typebox";
2
+ import { isTaskBundlePath, json } from "@silvermoon-work/task-protocol";
3
+ const kinds = new Set([
4
+ "Object",
5
+ "String",
6
+ "Number",
7
+ "Integer",
8
+ "Boolean",
9
+ "Null",
10
+ "Literal",
11
+ "Array",
12
+ "Tuple",
13
+ "Union",
14
+ "Intersect",
15
+ "Record",
16
+ "Ref",
17
+ "Never",
18
+ ]);
19
+ const maps = new Set([
20
+ "properties",
21
+ "patternProperties",
22
+ "$defs",
23
+ "definitions",
24
+ "dependentSchemas",
25
+ ]);
26
+ const singles = new Set([
27
+ "items",
28
+ "additionalProperties",
29
+ "unevaluatedProperties",
30
+ "propertyNames",
31
+ "contains",
32
+ "not",
33
+ "if",
34
+ "then",
35
+ "else",
36
+ "unevaluatedItems",
37
+ ]);
38
+ const arrays = new Set(["anyOf", "allOf", "oneOf", "prefixItems"]);
39
+ export function toTaskSchema(value) {
40
+ let nodes = 0;
41
+ function visit(value, schema, depth) {
42
+ if (++nodes > 16_384 || depth > 64)
43
+ throw new Error("Contract Schema budget exceeded.");
44
+ if (value === null || typeof value !== "object") {
45
+ if (["function", "symbol", "undefined", "bigint"].includes(typeof value))
46
+ throw new Error("Contract must contain only JSON semantics.");
47
+ return value;
48
+ }
49
+ if (Array.isArray(value))
50
+ return value.map((child) => visit(child, schema, depth + 1));
51
+ const node = value;
52
+ for (const symbol of Object.getOwnPropertySymbols(node))
53
+ if (![Kind, OptionalKind, ReadonlyKind, Symbol.for("TypeBox.Hint")].includes(symbol))
54
+ throw new Error("Unsupported TypeBox metadata or transform.");
55
+ if (node[Kind] !== undefined && !kinds.has(String(node[Kind])))
56
+ throw new Error(`Unsupported TypeBox kind: ${String(node[Kind])}.`);
57
+ if (schema &&
58
+ ["format", "contentEncoding", "contentMediaType", "contentSchema"].some((key) => Object.hasOwn(node, key)))
59
+ throw new Error("Engine does not enforce format or content annotations.");
60
+ if (schema &&
61
+ node[Kind] === "Tuple" &&
62
+ node.additionalItems !== undefined &&
63
+ node.additionalItems !== false)
64
+ throw new Error("Unsupported TypeBox Tuple additionalItems override.");
65
+ const output = {};
66
+ for (const [key, child] of Object.entries(node)) {
67
+ if (schema && node[Kind] === "Tuple" && (key === "items" || key === "additionalItems"))
68
+ continue;
69
+ let result;
70
+ if (schema && maps.has(key)) {
71
+ if (!child || typeof child !== "object" || Array.isArray(child))
72
+ throw new Error("Invalid Schema map.");
73
+ result = Object.fromEntries(Object.entries(child).map(([name, entry]) => [name, visit(entry, true, depth + 1)]));
74
+ }
75
+ else
76
+ result = visit(child, schema && (singles.has(key) || arrays.has(key)), depth + 1);
77
+ Object.defineProperty(output, key, { value: result, enumerable: true });
78
+ }
79
+ if (schema && node[Kind] === "Tuple") {
80
+ const items = visit(node.items ?? [], true, depth + 1);
81
+ if (!Array.isArray(items))
82
+ throw new Error("Invalid TypeBox Tuple items.");
83
+ if (items.length)
84
+ output.prefixItems = items;
85
+ output.items = false;
86
+ }
87
+ return output;
88
+ }
89
+ return visit(value, true, 0);
90
+ }
91
+ export function contractSchemas(value) {
92
+ if (!value ||
93
+ typeof value !== "object" ||
94
+ Array.isArray(value) ||
95
+ !("input" in value) ||
96
+ !("result" in value) ||
97
+ !("message" in value) ||
98
+ Object.keys(value).some((key) => !["input", "result", "message", "schemas"].includes(key)))
99
+ throw new Error("Contract must contain { input, result, message, schemas? }.");
100
+ const schemas = "schemas" in value ? value.schemas : {};
101
+ if (!schemas || typeof schemas !== "object" || Array.isArray(schemas))
102
+ throw new Error("Contract schemas must be a name-to-Schema object, not an array.");
103
+ const shared = Object.entries(schemas).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
104
+ const names = new Set();
105
+ for (const [name] of shared) {
106
+ if (!name ||
107
+ name.includes("/") ||
108
+ !isTaskBundlePath(name) ||
109
+ !isTaskBundlePath(`schemas/shared/${name}.json`) ||
110
+ names.has(name.toLowerCase()))
111
+ throw new Error(`Shared Schema names must be unique portable file names: ${name}`);
112
+ names.add(name.toLowerCase());
113
+ }
114
+ const entries = [
115
+ { path: "schemas/input.json", identity: "0", schema: value.input },
116
+ { path: "schemas/result.json", identity: "1", schema: value.result },
117
+ { path: "schemas/message.json", identity: "2", schema: value.message },
118
+ ...shared.map(([name, schema]) => ({
119
+ path: `schemas/shared/${name}.json`,
120
+ identity: `shared/${encodeURIComponent(name)}`,
121
+ schema,
122
+ })),
123
+ ];
124
+ return entries.map(({ path, identity, schema }, index) => {
125
+ const normalized = json(toTaskSchema(schema));
126
+ const id = `https://task.invalid/schema/${identity}`;
127
+ if (typeof normalized === "boolean") {
128
+ if (!index)
129
+ throw new Error("Task input Schema must be an object.");
130
+ return {
131
+ path,
132
+ document: { $id: id, ...(normalized ? {} : { not: {} }) },
133
+ };
134
+ }
135
+ if (!normalized || typeof normalized !== "object" || Array.isArray(normalized))
136
+ throw new Error("Contract Schema must be an object or boolean.");
137
+ return {
138
+ path,
139
+ document: {
140
+ ...normalized,
141
+ $id: normalized.$id ?? id,
142
+ },
143
+ };
144
+ });
145
+ }
146
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAmB,MAAM,gCAAgC,CAAC;AAEzF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,SAAS;IACT,MAAM;IACN,SAAS;IACT,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;IACX,QAAQ;IACR,KAAK;IACL,OAAO;CACR,CAAC,CAAC;AACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;IACnB,YAAY;IACZ,mBAAmB;IACnB,OAAO;IACP,aAAa;IACb,kBAAkB;CACnB,CAAC,CAAC;AACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC;IACtB,OAAO;IACP,sBAAsB;IACtB,uBAAuB;IACvB,eAAe;IACf,UAAU;IACV,KAAK;IACL,IAAI;IACJ,MAAM;IACN,MAAM;IACN,kBAAkB;CACnB,CAAC,CAAC;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;AAEnE,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,SAAS,KAAK,CAAC,KAAc,EAAE,MAAe,EAAE,KAAa;QAC3D,IAAI,EAAE,KAAK,GAAG,MAAM,IAAI,KAAK,GAAG,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACxF,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChD,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC;gBACtE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QACvF,MAAM,IAAI,GAAG,KAAqC,CAAC;QACnD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC;YACrD,IAAI,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAClF,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAClE,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACtE,IACE,MAAM;YACN,CAAC,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9E,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CACzB;YAED,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,IACE,MAAM;YACN,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO;YACtB,IAAI,CAAC,eAAe,KAAK,SAAS;YAClC,IAAI,CAAC,eAAe,KAAK,KAAK;YAE9B,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,iBAAiB,CAAC;gBACpF,SAAS;YACX,IAAI,MAAe,CAAC;YACpB,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;oBAC7D,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACzC,MAAM,GAAG,MAAM,CAAC,WAAW,CACzB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CACpF,CAAC;YACJ,CAAC;;gBAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACzF,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAC3E,IAAI,KAAK,CAAC,MAAM;gBAAE,MAAM,CAAC,WAAW,GAAG,KAAK,CAAC;YAC7C,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACvB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IACE,CAAC,KAAK;QACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC;QACnB,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC;QACpB,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAE1F,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;QAC5B,IACE,CAAC,IAAI;YACL,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAClB,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACvB,CAAC,gBAAgB,CAAC,kBAAkB,IAAI,OAAO,CAAC;YAChD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAE7B,MAAM,IAAI,KAAK,CAAC,2DAA2D,IAAI,EAAE,CAAC,CAAC;QACrF,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,OAAO,GAAG;QACd,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE;QAClE,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE;QACpE,EAAE,IAAI,EAAE,sBAAsB,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE;QACtE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,kBAAkB,IAAI,OAAO;YACnC,QAAQ,EAAE,UAAU,kBAAkB,CAAC,IAAI,CAAC,EAAE;YAC9C,MAAM;SACP,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE;QACvD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9C,MAAM,EAAE,GAAG,+BAA+B,QAAQ,EAAE,CAAC;QACrD,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YACpE,OAAO;gBACL,IAAI;gBACJ,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE;aAC1D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,OAAO;YACL,IAAI;YACJ,QAAQ,EAAE;gBACR,GAAG,UAAU;gBACb,GAAG,EAAE,UAAU,CAAC,GAAG,IAAI,EAAE;aAC1B;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ResolvedTaskBundle } from "@silvermoon-work/task-protocol";
2
+ import { type ReadonlyFileTree, type ReadOptions } from "./tree.js";
3
+ export interface CompileOptions extends ReadOptions {
4
+ readonly fileBytes: number;
5
+ readonly sourceBytes: number;
6
+ readonly sourceFiles: number;
7
+ readonly traversalPaths: number;
8
+ readonly binding?: ResolvedTaskBundle;
9
+ readonly callbackExport?: string;
10
+ readonly sdk?: string;
11
+ }
12
+ export declare function compileTree(tree: ReadonlyFileTree, entry: string, options: CompileOptions): Promise<Uint8Array>;
13
+ export declare function evaluateContract(bytes: Uint8Array): unknown;
14
+ //# sourceMappingURL=esbuild.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"esbuild.d.ts","sourceRoot":"","sources":["../src/esbuild.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAkC,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAiCpG,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC,CA0NrB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAkB3D"}