@elaraai/e3 0.0.1-alpha.2

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.md ADDED
@@ -0,0 +1,31 @@
1
+ Copyright (c) 2025 Elara AI Pty Ltd
2
+
3
+ # Dual License
4
+
5
+ This software is available under two licenses. You may choose which license applies to your use:
6
+
7
+ ## Option 1: AGPL-3.0 (Open Source)
8
+
9
+ You may use, modify, and distribute this software under the terms of the GNU Affero General Public License v3.0.
10
+
11
+ This requires that if you use this software in a network service, you must make your complete source code available under AGPL-3.0.
12
+
13
+ Full text: https://www.gnu.org/licenses/agpl-3.0.html
14
+
15
+ ## Option 2: Commercial License
16
+
17
+ If you wish to use this software without the source code disclosure requirements of AGPL-3.0, you must obtain a commercial license from Elara AI Pty Ltd.
18
+
19
+ Contact: support@elara.ai
20
+
21
+ ## Contributions
22
+
23
+ Contributions are welcome. By submitting a pull request, you agree to license your contribution under both AGPL-3.0 and our commercial license terms.
24
+
25
+ ## Governing Law
26
+
27
+ This license is governed by the laws of New South Wales, Australia.
28
+
29
+ ---
30
+
31
+ *Elara AI Pty Ltd*
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @elaraai/e3
2
+
3
+ SDK for authoring e3 packages.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @elaraai/e3
9
+ ```
10
+
11
+ ## Example
12
+
13
+ ```typescript
14
+ import e3 from '@elaraai/e3';
15
+ import { StringType, East } from '@elaraai/east';
16
+
17
+ // Define input datasets with default values
18
+ const input_name = e3.input('name', StringType, 'World');
19
+ const input_prefix = e3.input('prefix', StringType, 'Hello');
20
+
21
+ // Define a task that combines inputs
22
+ const greet = e3.task(
23
+ 'greet',
24
+ [input_prefix, input_name],
25
+ East.function(
26
+ [StringType, StringType],
27
+ StringType,
28
+ ($, prefix, name) => East.str`${prefix}, ${name}!`
29
+ )
30
+ );
31
+
32
+ // Chain tasks - output of one feeds into the next
33
+ const shout = e3.task(
34
+ 'shout',
35
+ [greet.output], // reads from previous task's output
36
+ East.function(
37
+ [StringType],
38
+ StringType,
39
+ ($, greeting) => greeting.upperCase()
40
+ )
41
+ );
42
+
43
+ // Create and export the package
44
+ const pkg = e3.package('greeting-pkg', '1.0.0', shout);
45
+ await e3.export(pkg, 'dist/greeting-pkg-1.0.0.zip');
46
+ ```
47
+
48
+ This creates a package with:
49
+ - `.inputs.name` - String input (default: "World")
50
+ - `.inputs.prefix` - String input (default: "Hello")
51
+ - `.tasks.greet` - Combines inputs into greeting
52
+ - `.tasks.shout` - Transforms greeting to uppercase
53
+
54
+ ## API
55
+
56
+ - `e3.input(name, type, default)` - Define an input dataset
57
+ - `e3.task(name, inputs, fn)` - Define a task with East function
58
+ - `e3.package(name, version, task)` - Create a package (dependencies collected automatically)
59
+ - `e3.export(pkg, path)` - Export package to zip file
60
+
61
+
62
+ ## License
63
+
64
+ Dual AGPL-3.0 / Commercial. See [LICENSE.md](./LICENSE.md).
65
+
66
+ ### Ecosystem
67
+
68
+ - **[East Node](https://github.com/elaraai/east-node)**: Node.js platform functions for I/O, databases, and system operations. Connect East programs to filesystems, SQL/NoSQL databases, cloud storage, and network services.
69
+ - [@elaraai/east-node-std](https://www.npmjs.com/package/@elaraai/east-node-std): Filesystem, console, HTTP fetch, crypto, random distributions, timestamps
70
+ - [@elaraai/east-node-io](https://www.npmjs.com/package/@elaraai/east-node-io): SQLite, PostgreSQL, MySQL, MongoDB, S3, FTP, SFTP
71
+ - [@elaraai/east-node-cli](https://www.npmjs.com/package/@elaraai/east-node-cli): CLI for running East IR programs in Node.js
72
+
73
+ - **[East Python](https://github.com/elaraai/east-py)**: Python runtime and platform functions for data science and machine learning. Execute East programs with access to optimization solvers, gradient boosting, neural networks, and model explainability.
74
+ - [@elaraai/east-py-datascience](https://www.npmjs.com/package/@elaraai/east-py-datascience): TypeScript types for optimization, gradient boosting, neural networks, explainability
75
+
76
+ - **[East UI](https://github.com/elaraai/east-ui)**: East types and expressions for building dashboards and interactive layouts. Define UIs as data structures that render consistently across React, web, and other environments.
77
+ - [@elaraai/east-ui](https://www.npmjs.com/package/@elaraai/east-ui): 50+ typed UI components for layouts, forms, charts, tables, dialogs
78
+ - [@elaraai/east-ui-components](https://www.npmjs.com/package/@elaraai/east-ui-components): React renderer with Chakra UI styling
79
+
80
+ - **[e3 - East Execution Engine](https://github.com/elaraai/e3)**: Durable execution engine for running East pipelines at scale. Features Git-like content-addressable storage, automatic memoization, task queuing, and real-time monitoring.
81
+ - [@elaraai/e3](https://www.npmjs.com/package/@elaraai/e3): SDK for authoring e3 packages with typed tasks and pipelines
82
+ - [@elaraai/e3-core](https://www.npmjs.com/package/@elaraai/e3-core): Git-like object store, task queue, result caching
83
+ - [@elaraai/e3-types](https://www.npmjs.com/package/@elaraai/e3-types): Shared type definitions for e3 packages
84
+ - [@elaraai/e3-cli](https://www.npmjs.com/package/@elaraai/e3-cli): `e3 init`, `e3 run`, `e3 logs` commands for managing and monitoring tasks
85
+ - [@elaraai/e3-api-client](https://www.npmjs.com/package/@elaraai/e3-api-client): HTTP client for remote e3 servers
86
+ - [@elaraai/e3-api-server](https://www.npmjs.com/package/@elaraai/e3-api-server): REST API server for e3 repositories
87
+
88
+ ## Links
89
+
90
+ - [East Language](https://github.com/elaraai/east)
91
+ - [East Python Runtime](https://github.com/elaraai/east-py)
92
+ - [Elara AI](https://elaraai.com/)
93
+ - [Issues](https://github.com/elaraai/e3/issues)
94
+ - support@elara.ai
95
+
96
+ ## About Elara
97
+
98
+ East is developed by [Elara AI Pty Ltd](https://elaraai.com/), an AI-powered platform that creates economic digital twins of businesses that optimize performance. Elara combines business objectives, decisions and data to help organizations make data-driven decisions across operations, purchasing, sales and customer engagement, and project and investment planning. East powers the computational layer of Elara solutions, enabling the expression of complex business logic and data in a simple, type-safe and portable language.
99
+
100
+ ---
101
+
102
+ *Developed by [Elara AI Pty Ltd](https://elaraai.com/)*
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import yazl from 'yazl';
6
+ import type { PackageDef } from './types.js';
7
+ /**
8
+ * Exports a package to a .zip bundle.
9
+ *
10
+ * The bundle can be imported into an e3 repository using `e3 package import`.
11
+ * It contains all objects needed for the package, plus a ref at
12
+ * `packages/<name>/<version>` pointing to the package object.
13
+ *
14
+ * @param pkg - The package to export
15
+ * @param outputPath - Path to write the .zip file
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * await e3.export(pkg, './my-package-1.0.0.zip');
20
+ * ```
21
+ */
22
+ export declare function export_(pkg: PackageDef<Record<string, unknown>>, outputPath: string): Promise<void>;
23
+ /**
24
+ * Adds an object to the zip file at the content-addressed path.
25
+ *
26
+ * @param zipfile - The zip file to add to
27
+ * @param data - The serialized object data (.beast2 format)
28
+ * @returns The SHA256 hash of the data (used as the object ID)
29
+ */
30
+ export declare function addObject(zipfile: yazl.ZipFile, data: Buffer): string;
31
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,OAAO,IAAI,MAAM,MAAM,CAAC;AAIxB,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AAEH,wBAAsB,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkNzG;AAOD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrE"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Export functionality for e3 packages.
7
+ *
8
+ * Exports a package definition to a .zip bundle that can be imported
9
+ * into an e3 repository. The bundle is a valid subset of an e3 repository:
10
+ * - `packages/<name>/<version>` - ref to package object hash
11
+ * - `objects/<ab>/<cdef...>.beast2` - content-addressed objects
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import { createHash } from 'node:crypto';
15
+ import yazl from 'yazl';
16
+ import { variant, encodeBeast2For, StructType, printIdentifier, SortedMap, toEastTypeValue, IRType } from '@elaraai/east';
17
+ import { DataRefType, PackageObjectType, TaskObjectType } from '@elaraai/e3-types';
18
+ /**
19
+ * Exports a package to a .zip bundle.
20
+ *
21
+ * The bundle can be imported into an e3 repository using `e3 package import`.
22
+ * It contains all objects needed for the package, plus a ref at
23
+ * `packages/<name>/<version>` pointing to the package object.
24
+ *
25
+ * @param pkg - The package to export
26
+ * @param outputPath - Path to write the .zip file
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * await e3.export(pkg, './my-package-1.0.0.zip');
31
+ * ```
32
+ */
33
+ // Named export_ to avoid conflict with reserved word
34
+ export async function export_(pkg, outputPath) {
35
+ const partialPath = `${outputPath}.partial`;
36
+ // Create zip file
37
+ const zipfile = new yazl.ZipFile();
38
+ // Initialize empty package object that we'll populate as we iterate
39
+ const tasks = new SortedMap(); // name -> task object hash
40
+ const refs = new Map(); // path -> data ref (variant of dataset or tree object hash)
41
+ const trees = new Map(); // path -> struct of paths
42
+ const structures = new Map(); // path -> structure (parallel to trees)
43
+ // Create root tree and structure as first entries
44
+ trees.set('', variant('struct', {}));
45
+ structures.set('', variant('struct', new SortedMap()));
46
+ // Iterate over package contents and write each object
47
+ // Contents are topologically sorted, so dependencies come before dependents
48
+ for (const item of pkg.contents) {
49
+ if (item.kind === "datatree") {
50
+ // Trees are accumulated in memory and written after
51
+ // Get parent tree
52
+ const parentPath = item.path.slice(0, -1).map(segment => {
53
+ if (segment.type !== 'field') {
54
+ throw new Error(`Unsupported tree path segment type in path ${item.path}: ${segment.type}`);
55
+ }
56
+ return `.${printIdentifier(segment.value)}`;
57
+ }).join('');
58
+ const parentTree = trees.get(parentPath);
59
+ if (!parentTree) {
60
+ throw new Error(`Missing parent tree at path: ${parentPath}`);
61
+ }
62
+ if (parentTree.type !== 'struct') {
63
+ throw new Error(`Parent tree at path ${parentPath} is not a struct: ${parentTree.type}`);
64
+ }
65
+ // Add this tree as a child of the parent
66
+ const segment = item.path[item.path.length - 1];
67
+ if (segment.type !== 'field') {
68
+ throw new Error(`Unsupported tree path segment type in path ${item.path}: ${segment.type}`);
69
+ }
70
+ const name = segment.value;
71
+ const path = `${parentPath}.${printIdentifier(name)}`;
72
+ parentTree.value[name] = path;
73
+ trees.set(path, variant('struct', {}));
74
+ // Update structure: add nested struct to parent
75
+ const parentStructure = structures.get(parentPath);
76
+ if (!parentStructure || parentStructure.type !== 'struct') {
77
+ throw new Error(`Missing or invalid parent structure at path: ${parentPath}`);
78
+ }
79
+ const childStructure = variant('struct', new SortedMap());
80
+ parentStructure.value.set(name, childStructure);
81
+ structures.set(path, childStructure);
82
+ }
83
+ else if (item.kind === "dataset") {
84
+ // Datasets are serialized and written immediately
85
+ // Get parent tree
86
+ const parentPath = item.path.slice(0, -1).map(segment => {
87
+ if (segment.type !== 'field') {
88
+ throw new Error(`Unsupported tree path segment type in path ${item.path}: ${segment.type}`);
89
+ }
90
+ return `.${printIdentifier(segment.value)}`;
91
+ }).join('');
92
+ const parentTree = trees.get(parentPath);
93
+ if (!parentTree) {
94
+ throw new Error(`Missing parent tree at path: ${parentPath}`);
95
+ }
96
+ if (parentTree.type !== 'struct') {
97
+ throw new Error(`Parent tree at path ${parentPath} is not a struct: ${parentTree.type}`);
98
+ }
99
+ // Add this dataset as a child of the parent
100
+ const segment = item.path[item.path.length - 1];
101
+ if (segment.type !== 'field') {
102
+ throw new Error(`Unsupported tree path segment type in path ${item.path}: ${segment.type}`);
103
+ }
104
+ const name = segment.value;
105
+ const path = `${parentPath}.${printIdentifier(name)}`;
106
+ parentTree.value[name] = path;
107
+ // Serialize default value (if present) and record DataRef
108
+ let dataRef;
109
+ if (item.default !== undefined) {
110
+ const valueEncoder = encodeBeast2For(item.type);
111
+ const valueData = valueEncoder(item.default);
112
+ const valueHash = addObject(zipfile, Buffer.from(valueData));
113
+ dataRef = variant('value', valueHash);
114
+ }
115
+ else {
116
+ dataRef = variant('unassigned', null);
117
+ }
118
+ refs.set(path, dataRef);
119
+ // Update structure: add value type to parent
120
+ const parentStructure = structures.get(parentPath);
121
+ if (!parentStructure || parentStructure.type !== 'struct') {
122
+ throw new Error(`Missing or invalid parent structure at path: ${parentPath}`);
123
+ }
124
+ const typeValue = toEastTypeValue(item.type);
125
+ parentStructure.value.set(name, variant('value', typeValue));
126
+ }
127
+ else if (item.kind === "task") {
128
+ // Tasks are serialized and written immediately
129
+ // Build input paths from the task definition
130
+ // Note: e3.task() includes function_ir in inputs, e3.customTask() does not
131
+ const inputPaths = item.inputs.map(input => input.path);
132
+ // Serialize command IR
133
+ const commandIrEncoder = encodeBeast2For(IRType);
134
+ const commandIrData = commandIrEncoder(item.command);
135
+ const commandIrHash = addObject(zipfile, Buffer.from(commandIrData));
136
+ // Build TaskObject
137
+ const taskObject = {
138
+ commandIr: commandIrHash,
139
+ inputs: inputPaths,
140
+ output: item.output.path,
141
+ };
142
+ // Serialize and add to zip
143
+ const taskEncoder = encodeBeast2For(TaskObjectType);
144
+ const taskData = taskEncoder(taskObject);
145
+ const taskHash = addObject(zipfile, Buffer.from(taskData));
146
+ // Add to package tasks map
147
+ tasks.set(item.name, taskHash);
148
+ }
149
+ else {
150
+ throw new Error(`Unknown package item kind: ${item.kind}`);
151
+ }
152
+ }
153
+ // Now we traverse the trees in reverse order to build and write tree objects, finishing with root.
154
+ const treePaths = Array.from(trees.keys()).reverse();
155
+ for (const treePath of treePaths) {
156
+ const tree = trees.get(treePath);
157
+ if (tree.type === 'struct') {
158
+ // Build tree object with DataRef fields
159
+ const treeObject = {};
160
+ for (const [fieldName, childPath] of Object.entries(tree.value).sort(([name1], [name2]) => name1 < name2 ? -1 : 1)) {
161
+ const childRef = refs.get(childPath);
162
+ if (!childRef) {
163
+ throw new Error(`Missing hash for tree child at path: ${childPath}`);
164
+ }
165
+ treeObject[fieldName] = childRef;
166
+ }
167
+ // Serialize and write tree object
168
+ // TODO: I wonder if this is better as a dictionary, like the structure?
169
+ const TreeType = StructType(Object.fromEntries(Object.keys(treeObject).map((fieldName) => [fieldName, DataRefType])));
170
+ const treeEncoder = encodeBeast2For(TreeType);
171
+ const treeData = treeEncoder(treeObject);
172
+ const treeHash = addObject(zipfile, Buffer.from(treeData));
173
+ // Record DataRef for this tree
174
+ const treeRef = variant('tree', treeHash);
175
+ refs.set(treePath, treeRef);
176
+ }
177
+ else {
178
+ throw new Error(`Unsupported tree type at path ${treePath}: ${tree.type}`);
179
+ }
180
+ }
181
+ // Get the root tree and structure
182
+ const rootTreeRef = refs.get('');
183
+ if (!rootTreeRef) {
184
+ throw new Error('Missing root tree object');
185
+ }
186
+ if (rootTreeRef.type !== 'tree') {
187
+ throw new Error(`Root tree ref is not a tree: ${rootTreeRef.type}`);
188
+ }
189
+ const rootStructure = structures.get('');
190
+ if (!rootStructure) {
191
+ throw new Error('Missing root structure');
192
+ }
193
+ // Build and write the package object
194
+ const packageObject = {
195
+ tasks,
196
+ data: {
197
+ structure: rootStructure,
198
+ value: rootTreeRef.value,
199
+ },
200
+ };
201
+ const packageObjectEncoder = encodeBeast2For(PackageObjectType);
202
+ const packageObjectData = packageObjectEncoder(packageObject);
203
+ const packageHash = addObject(zipfile, Buffer.from(packageObjectData));
204
+ // Write the package ref at packages/<name>/<version>
205
+ const refPath = `packages/${pkg.name}/${pkg.version}`;
206
+ zipfile.addBuffer(Buffer.from(packageHash + '\n'), refPath, { mtime: DETERMINISTIC_MTIME });
207
+ // Finalize and write zip to disk
208
+ await new Promise((resolve, reject) => {
209
+ const writeStream = fs.createWriteStream(partialPath);
210
+ zipfile.outputStream.pipe(writeStream);
211
+ zipfile.outputStream.on('error', reject);
212
+ writeStream.on('error', reject);
213
+ writeStream.on('close', resolve);
214
+ zipfile.end();
215
+ });
216
+ // Atomic rename to final path
217
+ await fs.promises.rename(partialPath, outputPath);
218
+ }
219
+ /**
220
+ * Fixed mtime for deterministic zip output (Unix epoch)
221
+ */
222
+ const DETERMINISTIC_MTIME = new Date(0);
223
+ /**
224
+ * Adds an object to the zip file at the content-addressed path.
225
+ *
226
+ * @param zipfile - The zip file to add to
227
+ * @param data - The serialized object data (.beast2 format)
228
+ * @returns The SHA256 hash of the data (used as the object ID)
229
+ */
230
+ export function addObject(zipfile, data) {
231
+ const hash = createHash('sha256').update(data).digest('hex');
232
+ const path = `objects/${hash.slice(0, 2)}/${hash.slice(2)}.beast2`;
233
+ zipfile.addBuffer(data, path, { mtime: DETERMINISTIC_MTIME });
234
+ return hash;
235
+ }
236
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=export.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.spec.d.ts","sourceRoot":"","sources":["../../src/export.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import { describe, it, before, after } from 'node:test';
6
+ import * as assert from 'node:assert';
7
+ import * as fs from 'node:fs';
8
+ import * as os from 'node:os';
9
+ import * as path from 'node:path';
10
+ import yazl from 'yazl';
11
+ import yauzl from 'yauzl';
12
+ import { StringType, decodeBeast2For } from '@elaraai/east';
13
+ import { PackageObjectType } from '@elaraai/e3-types';
14
+ import { addObject, export_ } from './export.js';
15
+ import { package_ } from './package.js';
16
+ import { input } from './input.js';
17
+ describe('addObject', () => {
18
+ it('returns correct SHA256 hash for empty buffer', () => {
19
+ const zipfile = new yazl.ZipFile();
20
+ const data = Buffer.from('');
21
+ const hash = addObject(zipfile, data);
22
+ // SHA256 of empty string
23
+ assert.strictEqual(hash, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
24
+ });
25
+ it('returns correct SHA256 hash for known input', () => {
26
+ const zipfile = new yazl.ZipFile();
27
+ const data = Buffer.from('hello');
28
+ const hash = addObject(zipfile, data);
29
+ // SHA256 of "hello"
30
+ assert.strictEqual(hash, '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
31
+ });
32
+ it('adds object at correct path in zip', () => {
33
+ const zipfile = new yazl.ZipFile();
34
+ const data = Buffer.from('hello');
35
+ const hash = addObject(zipfile, data);
36
+ // Verify the path format: objects/xx/yyyy...beast2
37
+ const expectedPath = `objects/${hash.slice(0, 2)}/${hash.slice(2)}.beast2`;
38
+ assert.strictEqual(expectedPath, 'objects/2c/f24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824.beast2');
39
+ });
40
+ it('returns consistent hash for same input', () => {
41
+ const zipfile1 = new yazl.ZipFile();
42
+ const zipfile2 = new yazl.ZipFile();
43
+ const data = Buffer.from('test data');
44
+ const hash1 = addObject(zipfile1, data);
45
+ const hash2 = addObject(zipfile2, data);
46
+ assert.strictEqual(hash1, hash2);
47
+ });
48
+ it('returns different hash for different input', () => {
49
+ const zipfile = new yazl.ZipFile();
50
+ const data1 = Buffer.from('hello');
51
+ const data2 = Buffer.from('world');
52
+ const hash1 = addObject(zipfile, data1);
53
+ const hash2 = addObject(zipfile, data2);
54
+ assert.notStrictEqual(hash1, hash2);
55
+ });
56
+ });
57
+ /**
58
+ * Helper to read a zip file and return entries as a map of path -> buffer
59
+ */
60
+ async function readZip(zipPath) {
61
+ return new Promise((resolve, reject) => {
62
+ yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
63
+ if (err)
64
+ return reject(err);
65
+ if (!zipfile)
66
+ return reject(new Error('No zipfile'));
67
+ const entries = new Map();
68
+ zipfile.readEntry();
69
+ zipfile.on('entry', (entry) => {
70
+ if (/\/$/.test(entry.fileName)) {
71
+ // Directory entry, skip
72
+ zipfile.readEntry();
73
+ }
74
+ else {
75
+ zipfile.openReadStream(entry, (err, readStream) => {
76
+ if (err)
77
+ return reject(err);
78
+ if (!readStream)
79
+ return reject(new Error('No read stream'));
80
+ const chunks = [];
81
+ readStream.on('data', (chunk) => chunks.push(chunk));
82
+ readStream.on('end', () => {
83
+ entries.set(entry.fileName, Buffer.concat(chunks));
84
+ zipfile.readEntry();
85
+ });
86
+ });
87
+ }
88
+ });
89
+ zipfile.on('end', () => resolve(entries));
90
+ zipfile.on('error', reject);
91
+ });
92
+ });
93
+ }
94
+ describe('export_', () => {
95
+ let tempDir;
96
+ before(async () => {
97
+ tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'e3-export-test-'));
98
+ });
99
+ after(async () => {
100
+ await fs.promises.rm(tempDir, { recursive: true });
101
+ });
102
+ it('exports empty package', async () => {
103
+ const pkg = package_('empty-pkg', '1.0.0');
104
+ const zipPath = path.join(tempDir, 'empty.zip');
105
+ await export_(pkg, zipPath);
106
+ // Verify zip exists
107
+ const stat = await fs.promises.stat(zipPath);
108
+ assert.ok(stat.isFile());
109
+ // Read zip contents
110
+ const entries = await readZip(zipPath);
111
+ // Should have package ref
112
+ assert.ok(entries.has('packages/empty-pkg/1.0.0'));
113
+ // Package ref should contain a hash
114
+ const refContent = entries.get('packages/empty-pkg/1.0.0').toString().trim();
115
+ assert.match(refContent, /^[a-f0-9]{64}$/);
116
+ // Should have at least the package object and root tree
117
+ const objectEntries = Array.from(entries.keys()).filter(k => k.startsWith('objects/'));
118
+ assert.ok(objectEntries.length >= 2, `Expected at least 2 objects, got ${objectEntries.length}`);
119
+ // Decode and verify package object
120
+ const packageObjectPath = `objects/${refContent.slice(0, 2)}/${refContent.slice(2)}.beast2`;
121
+ assert.ok(entries.has(packageObjectPath), `Missing package object at ${packageObjectPath}`);
122
+ const packageObjectData = entries.get(packageObjectPath);
123
+ const decoder = decodeBeast2For(PackageObjectType);
124
+ const packageObject = decoder(packageObjectData);
125
+ // Empty package should have no tasks
126
+ assert.strictEqual(packageObject.tasks.size, 0);
127
+ // Structure should be an empty struct
128
+ assert.strictEqual(packageObject.data.structure.type, 'struct');
129
+ assert.strictEqual(packageObject.data.structure.value.size, 0);
130
+ });
131
+ it('exports package with input dataset', async () => {
132
+ const myInput = input('greeting', StringType, 'hello');
133
+ const pkg = package_('input-pkg', '1.0.0', myInput);
134
+ const zipPath = path.join(tempDir, 'input.zip');
135
+ await export_(pkg, zipPath);
136
+ // Read zip contents
137
+ const entries = await readZip(zipPath);
138
+ // Get package object
139
+ const refContent = entries.get('packages/input-pkg/1.0.0').toString().trim();
140
+ const packageObjectPath = `objects/${refContent.slice(0, 2)}/${refContent.slice(2)}.beast2`;
141
+ const packageObjectData = entries.get(packageObjectPath);
142
+ const decoder = decodeBeast2For(PackageObjectType);
143
+ const packageObject = decoder(packageObjectData);
144
+ // Should have no tasks (input only)
145
+ assert.strictEqual(packageObject.tasks.size, 0);
146
+ // Structure should have inputs.greeting as a value
147
+ assert.strictEqual(packageObject.data.structure.type, 'struct');
148
+ const inputs = packageObject.data.structure.value.get('inputs');
149
+ assert.ok(inputs, 'Missing inputs in structure');
150
+ assert.strictEqual(inputs.type, 'struct');
151
+ const greeting = inputs.value.get('greeting');
152
+ assert.ok(greeting, 'Missing greeting in inputs structure');
153
+ assert.strictEqual(greeting.type, 'value');
154
+ // The value should be a String type
155
+ assert.strictEqual(greeting.value.type, 'String');
156
+ });
157
+ it('produces identical output for same package', async () => {
158
+ const myInput = input('name', StringType, 'world');
159
+ const pkg = package_('deterministic', '1.0.0', myInput);
160
+ const zipPath1 = path.join(tempDir, 'deterministic1.zip');
161
+ const zipPath2 = path.join(tempDir, 'deterministic2.zip');
162
+ await export_(pkg, zipPath1);
163
+ await export_(pkg, zipPath2);
164
+ // Read both zips
165
+ const entries1 = await readZip(zipPath1);
166
+ const entries2 = await readZip(zipPath2);
167
+ // Should have same entries
168
+ assert.deepStrictEqual(Array.from(entries1.keys()).sort(), Array.from(entries2.keys()).sort());
169
+ // Each entry should have identical content
170
+ for (const [path, data1] of entries1) {
171
+ const data2 = entries2.get(path);
172
+ assert.ok(data1.equals(data2), `Content mismatch at ${path}`);
173
+ }
174
+ });
175
+ });
176
+ //# sourceMappingURL=export.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.spec.js","sourceRoot":"","sources":["../../src/export.spec.ts"],"names":[],"mappings":"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"}