@elaraai/e3-core 0.0.1-beta.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.
Files changed (55) hide show
  1. package/LICENSE.md +50 -0
  2. package/README.md +76 -0
  3. package/dist/src/dataflow.d.ts +96 -0
  4. package/dist/src/dataflow.d.ts.map +1 -0
  5. package/dist/src/dataflow.js +433 -0
  6. package/dist/src/dataflow.js.map +1 -0
  7. package/dist/src/errors.d.ts +87 -0
  8. package/dist/src/errors.d.ts.map +1 -0
  9. package/dist/src/errors.js +178 -0
  10. package/dist/src/errors.js.map +1 -0
  11. package/dist/src/executions.d.ts +163 -0
  12. package/dist/src/executions.d.ts.map +1 -0
  13. package/dist/src/executions.js +535 -0
  14. package/dist/src/executions.js.map +1 -0
  15. package/dist/src/formats.d.ts +38 -0
  16. package/dist/src/formats.d.ts.map +1 -0
  17. package/dist/src/formats.js +115 -0
  18. package/dist/src/formats.js.map +1 -0
  19. package/dist/src/gc.d.ts +54 -0
  20. package/dist/src/gc.d.ts.map +1 -0
  21. package/dist/src/gc.js +232 -0
  22. package/dist/src/gc.js.map +1 -0
  23. package/dist/src/index.d.ts +23 -0
  24. package/dist/src/index.d.ts.map +1 -0
  25. package/dist/src/index.js +68 -0
  26. package/dist/src/index.js.map +1 -0
  27. package/dist/src/objects.d.ts +62 -0
  28. package/dist/src/objects.d.ts.map +1 -0
  29. package/dist/src/objects.js +245 -0
  30. package/dist/src/objects.js.map +1 -0
  31. package/dist/src/packages.d.ts +85 -0
  32. package/dist/src/packages.d.ts.map +1 -0
  33. package/dist/src/packages.js +355 -0
  34. package/dist/src/packages.js.map +1 -0
  35. package/dist/src/repository.d.ts +38 -0
  36. package/dist/src/repository.d.ts.map +1 -0
  37. package/dist/src/repository.js +103 -0
  38. package/dist/src/repository.js.map +1 -0
  39. package/dist/src/tasks.d.ts +63 -0
  40. package/dist/src/tasks.d.ts.map +1 -0
  41. package/dist/src/tasks.js +145 -0
  42. package/dist/src/tasks.js.map +1 -0
  43. package/dist/src/test-helpers.d.ts +44 -0
  44. package/dist/src/test-helpers.d.ts.map +1 -0
  45. package/dist/src/test-helpers.js +141 -0
  46. package/dist/src/test-helpers.js.map +1 -0
  47. package/dist/src/trees.d.ts +156 -0
  48. package/dist/src/trees.d.ts.map +1 -0
  49. package/dist/src/trees.js +607 -0
  50. package/dist/src/trees.js.map +1 -0
  51. package/dist/src/workspaces.d.ts +116 -0
  52. package/dist/src/workspaces.d.ts.map +1 -0
  53. package/dist/src/workspaces.js +356 -0
  54. package/dist/src/workspaces.js.map +1 -0
  55. package/package.json +50 -0
@@ -0,0 +1,145 @@
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
+ * Task operations for e3 repositories.
7
+ *
8
+ * Tasks are computations with input/output dataset paths. They are stored
9
+ * as TaskObjects in the object store and referenced by packages via their hash.
10
+ *
11
+ * This module provides APIs to:
12
+ * - List tasks in packages and workspaces
13
+ * - Get task details (runner, inputs, output paths)
14
+ */
15
+ import { decodeBeast2For } from '@elaraai/east';
16
+ import { PackageObjectType, TaskObjectType, WorkspaceStateType, } from '@elaraai/e3-types';
17
+ import { objectRead } from './objects.js';
18
+ import { packageRead } from './packages.js';
19
+ import { TaskNotFoundError, WorkspaceNotFoundError, WorkspaceNotDeployedError, isNotFoundError, } from './errors.js';
20
+ import * as fs from 'fs/promises';
21
+ import * as path from 'path';
22
+ // =============================================================================
23
+ // Package Task Operations
24
+ // =============================================================================
25
+ /**
26
+ * List task names in a package.
27
+ *
28
+ * @param repoPath - Path to .e3 repository
29
+ * @param name - Package name
30
+ * @param version - Package version
31
+ * @returns Array of task names
32
+ * @throws If package not found
33
+ */
34
+ export async function packageListTasks(repoPath, name, version) {
35
+ const pkg = await packageRead(repoPath, name, version);
36
+ return Array.from(pkg.tasks.keys());
37
+ }
38
+ /**
39
+ * Get task details from a package.
40
+ *
41
+ * @param repoPath - Path to .e3 repository
42
+ * @param name - Package name
43
+ * @param version - Package version
44
+ * @param taskName - Name of the task
45
+ * @returns The TaskObject containing runner, inputs, and output
46
+ * @throws {PackageNotFoundError} If package not found
47
+ * @throws {TaskNotFoundError} If task not found in package
48
+ */
49
+ export async function packageGetTask(repoPath, name, version, taskName) {
50
+ const pkg = await packageRead(repoPath, name, version);
51
+ const taskHash = pkg.tasks.get(taskName);
52
+ if (!taskHash) {
53
+ throw new TaskNotFoundError(taskName);
54
+ }
55
+ const taskData = await objectRead(repoPath, taskHash);
56
+ const decoder = decodeBeast2For(TaskObjectType);
57
+ return decoder(Buffer.from(taskData));
58
+ }
59
+ // =============================================================================
60
+ // Workspace Task Operations
61
+ // =============================================================================
62
+ /**
63
+ * Read workspace state from file.
64
+ * @throws {WorkspaceNotFoundError} If workspace doesn't exist
65
+ * @throws {WorkspaceNotDeployedError} If workspace exists but not deployed
66
+ */
67
+ async function readWorkspaceState(repoPath, ws) {
68
+ const stateFile = path.join(repoPath, 'workspaces', `${ws}.beast2`);
69
+ try {
70
+ const data = await fs.readFile(stateFile);
71
+ if (data.length === 0) {
72
+ throw new WorkspaceNotDeployedError(ws);
73
+ }
74
+ const decoder = decodeBeast2For(WorkspaceStateType);
75
+ return decoder(data);
76
+ }
77
+ catch (err) {
78
+ if (err instanceof WorkspaceNotDeployedError)
79
+ throw err;
80
+ if (isNotFoundError(err)) {
81
+ throw new WorkspaceNotFoundError(ws);
82
+ }
83
+ throw err;
84
+ }
85
+ }
86
+ /**
87
+ * Get the deployed package object for a workspace.
88
+ */
89
+ async function getWorkspacePackageObject(repoPath, ws) {
90
+ const state = await readWorkspaceState(repoPath, ws);
91
+ const pkgData = await objectRead(repoPath, state.packageHash);
92
+ const decoder = decodeBeast2For(PackageObjectType);
93
+ return decoder(Buffer.from(pkgData));
94
+ }
95
+ /**
96
+ * List task names in a workspace.
97
+ *
98
+ * Tasks are defined by the deployed package.
99
+ *
100
+ * @param repoPath - Path to .e3 repository
101
+ * @param ws - Workspace name
102
+ * @returns Array of task names
103
+ * @throws If workspace not found or not deployed
104
+ */
105
+ export async function workspaceListTasks(repoPath, ws) {
106
+ const pkg = await getWorkspacePackageObject(repoPath, ws);
107
+ return Array.from(pkg.tasks.keys());
108
+ }
109
+ /**
110
+ * Get task hash from a workspace.
111
+ *
112
+ * @param repoPath - Path to .e3 repository
113
+ * @param ws - Workspace name
114
+ * @param taskName - Name of the task
115
+ * @returns The hash of the TaskObject
116
+ * @throws {WorkspaceNotFoundError} If workspace not found
117
+ * @throws {WorkspaceNotDeployedError} If workspace not deployed
118
+ * @throws {TaskNotFoundError} If task not found
119
+ */
120
+ export async function workspaceGetTaskHash(repoPath, ws, taskName) {
121
+ const pkg = await getWorkspacePackageObject(repoPath, ws);
122
+ const taskHash = pkg.tasks.get(taskName);
123
+ if (!taskHash) {
124
+ throw new TaskNotFoundError(taskName);
125
+ }
126
+ return taskHash;
127
+ }
128
+ /**
129
+ * Get task details from a workspace.
130
+ *
131
+ * Tasks are defined by the deployed package.
132
+ *
133
+ * @param repoPath - Path to .e3 repository
134
+ * @param ws - Workspace name
135
+ * @param taskName - Name of the task
136
+ * @returns The TaskObject containing runner, inputs, and output
137
+ * @throws If workspace not deployed or task not found
138
+ */
139
+ export async function workspaceGetTask(repoPath, ws, taskName) {
140
+ const taskHash = await workspaceGetTaskHash(repoPath, ws, taskName);
141
+ const taskData = await objectRead(repoPath, taskHash);
142
+ const decoder = decodeBeast2For(TaskObjectType);
143
+ return decoder(Buffer.from(taskData));
144
+ }
145
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/tasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
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
+ * Creates a temporary directory for testing
7
+ * @returns Path to temporary directory
8
+ */
9
+ export declare function createTempDir(): string;
10
+ /**
11
+ * Removes a temporary directory and all its contents
12
+ * @param dir Path to directory to remove
13
+ */
14
+ export declare function removeTempDir(dir: string): void;
15
+ /**
16
+ * Creates a temporary e3 repository for testing
17
+ * @returns Path to .e3 directory
18
+ */
19
+ export declare function createTestRepo(): string;
20
+ /**
21
+ * Remove a test repository (removes parent directory)
22
+ * @param e3Dir Path to .e3 directory
23
+ */
24
+ export declare function removeTestRepo(e3Dir: string): void;
25
+ /**
26
+ * Read all entries from a zip file
27
+ * @param zipPath Path to zip file
28
+ * @returns Map of entry path to content buffer
29
+ */
30
+ export declare function readZipEntries(zipPath: string): Promise<Map<string, Buffer>>;
31
+ /**
32
+ * Compare two zip files for content equality.
33
+ * Returns true if both zips have the same entries with the same content.
34
+ * Does not compare timestamps or other metadata.
35
+ *
36
+ * @param zipPath1 Path to first zip file
37
+ * @param zipPath2 Path to second zip file
38
+ * @returns Object with equal flag and optional diff info
39
+ */
40
+ export declare function zipEqual(zipPath1: string, zipPath2: string): Promise<{
41
+ equal: boolean;
42
+ diff?: string;
43
+ }>;
44
+ //# sourceMappingURL=test-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../../src/test-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE/C;AAOD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CASvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CASlD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgClF;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoC5C"}
@@ -0,0 +1,141 @@
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
+ * Test helpers for e3-core
7
+ * Provides utilities for setting up and tearing down test repositories
8
+ */
9
+ import { mkdtempSync, rmSync } from 'node:fs';
10
+ import { tmpdir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import yauzl from 'yauzl';
13
+ import { repoInit } from './repository.js';
14
+ /**
15
+ * Creates a temporary directory for testing
16
+ * @returns Path to temporary directory
17
+ */
18
+ export function createTempDir() {
19
+ return mkdtempSync(join(tmpdir(), 'e3-test-'));
20
+ }
21
+ /**
22
+ * Removes a temporary directory and all its contents
23
+ * @param dir Path to directory to remove
24
+ */
25
+ export function removeTempDir(dir) {
26
+ rmSync(dir, { recursive: true, force: true });
27
+ }
28
+ /**
29
+ * Track parent directories for cleanup
30
+ */
31
+ const parentDirs = new Map();
32
+ /**
33
+ * Creates a temporary e3 repository for testing
34
+ * @returns Path to .e3 directory
35
+ */
36
+ export function createTestRepo() {
37
+ const dir = createTempDir();
38
+ const result = repoInit(dir);
39
+ if (!result.success) {
40
+ throw new Error(`Failed to create test repository: ${result.error?.message}`);
41
+ }
42
+ // Track parent directory for cleanup
43
+ parentDirs.set(result.e3Dir, dir);
44
+ return result.e3Dir;
45
+ }
46
+ /**
47
+ * Remove a test repository (removes parent directory)
48
+ * @param e3Dir Path to .e3 directory
49
+ */
50
+ export function removeTestRepo(e3Dir) {
51
+ const parentDir = parentDirs.get(e3Dir);
52
+ if (parentDir) {
53
+ removeTempDir(parentDir);
54
+ parentDirs.delete(e3Dir);
55
+ }
56
+ else {
57
+ // Fallback: remove the .e3 directory itself
58
+ removeTempDir(e3Dir);
59
+ }
60
+ }
61
+ /**
62
+ * Read all entries from a zip file
63
+ * @param zipPath Path to zip file
64
+ * @returns Map of entry path to content buffer
65
+ */
66
+ export async function readZipEntries(zipPath) {
67
+ return new Promise((resolve, reject) => {
68
+ yauzl.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
69
+ if (err)
70
+ return reject(err);
71
+ if (!zipfile)
72
+ return reject(new Error('No zipfile'));
73
+ const entries = new Map();
74
+ zipfile.readEntry();
75
+ zipfile.on('entry', (entry) => {
76
+ if (/\/$/.test(entry.fileName)) {
77
+ // Directory entry, skip
78
+ zipfile.readEntry();
79
+ }
80
+ else {
81
+ zipfile.openReadStream(entry, (err, readStream) => {
82
+ if (err)
83
+ return reject(err);
84
+ if (!readStream)
85
+ return reject(new Error('No read stream'));
86
+ const chunks = [];
87
+ readStream.on('data', (chunk) => chunks.push(chunk));
88
+ readStream.on('end', () => {
89
+ entries.set(entry.fileName, Buffer.concat(chunks));
90
+ zipfile.readEntry();
91
+ });
92
+ });
93
+ }
94
+ });
95
+ zipfile.on('end', () => resolve(entries));
96
+ zipfile.on('error', reject);
97
+ });
98
+ });
99
+ }
100
+ /**
101
+ * Compare two zip files for content equality.
102
+ * Returns true if both zips have the same entries with the same content.
103
+ * Does not compare timestamps or other metadata.
104
+ *
105
+ * @param zipPath1 Path to first zip file
106
+ * @param zipPath2 Path to second zip file
107
+ * @returns Object with equal flag and optional diff info
108
+ */
109
+ export async function zipEqual(zipPath1, zipPath2) {
110
+ const entries1 = await readZipEntries(zipPath1);
111
+ const entries2 = await readZipEntries(zipPath2);
112
+ // Check for missing entries
113
+ const keys1 = Array.from(entries1.keys()).sort();
114
+ const keys2 = Array.from(entries2.keys()).sort();
115
+ if (keys1.length !== keys2.length) {
116
+ return {
117
+ equal: false,
118
+ diff: `Entry count differs: ${keys1.length} vs ${keys2.length}`,
119
+ };
120
+ }
121
+ for (let i = 0; i < keys1.length; i++) {
122
+ if (keys1[i] !== keys2[i]) {
123
+ return {
124
+ equal: false,
125
+ diff: `Entry paths differ at index ${i}: ${keys1[i]} vs ${keys2[i]}`,
126
+ };
127
+ }
128
+ }
129
+ // Check content equality
130
+ for (const [path, data1] of entries1) {
131
+ const data2 = entries2.get(path);
132
+ if (!data1.equals(data2)) {
133
+ return {
134
+ equal: false,
135
+ diff: `Content differs at ${path}: ${data1.length} bytes vs ${data2.length} bytes`,
136
+ };
137
+ }
138
+ }
139
+ return { equal: true };
140
+ }
141
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/test-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,156 @@
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
+ * Low-level tree and dataset operations for e3 repositories.
7
+ *
8
+ * Trees are persistent data structures with structural sharing (like git trees).
9
+ * Each tree node contains DataRefs pointing to either other trees or dataset values.
10
+ *
11
+ * Tree operations require a Structure parameter which describes the shape of the
12
+ * tree node. This enables proper encoding/decoding with the correct StructType
13
+ * and supports future tree types (array, variant, etc.).
14
+ *
15
+ * Low-level operations work with hashes directly (by-hash).
16
+ * High-level operations traverse paths from a root (by-path).
17
+ */
18
+ import { type EastType, type EastTypeValue } from '@elaraai/east';
19
+ import { type DataRef, type Structure, type TreePath } from '@elaraai/e3-types';
20
+ /**
21
+ * A tree object: mapping of field names to data references.
22
+ *
23
+ * This is a plain object (not a Map) because tree objects are encoded as
24
+ * StructTypes with known field names derived from the Structure.
25
+ */
26
+ export type TreeObject = Record<string, DataRef>;
27
+ /**
28
+ * Read and decode a tree object from the object store.
29
+ *
30
+ * @param repoPath - Path to .e3 repository
31
+ * @param hash - Hash of the tree object
32
+ * @param structure - The structure describing this tree node's shape
33
+ * @returns The decoded tree object (field name -> DataRef)
34
+ * @throws If object not found, structure is not a tree, or decoding fails
35
+ */
36
+ export declare function treeRead(repoPath: string, hash: string, structure: Structure): Promise<TreeObject>;
37
+ /**
38
+ * Encode and write a tree object to the object store.
39
+ *
40
+ * @param repoPath - Path to .e3 repository
41
+ * @param fields - Object mapping field names to DataRefs
42
+ * @param structure - The structure describing this tree node's shape
43
+ * @returns Hash of the written tree object
44
+ * @throws If structure is not a tree or encoding fails
45
+ */
46
+ export declare function treeWrite(repoPath: string, fields: TreeObject, structure: Structure): Promise<string>;
47
+ /**
48
+ * Read and decode a dataset value from the object store.
49
+ *
50
+ * The .beast2 format includes type information in the header, so values
51
+ * can be decoded without knowing the schema in advance.
52
+ *
53
+ * @param repoPath - Path to .e3 repository
54
+ * @param hash - Hash of the dataset value
55
+ * @returns The decoded value and its type
56
+ * @throws If object not found or not a valid beast2 object
57
+ */
58
+ export declare function datasetRead(repoPath: string, hash: string): Promise<{
59
+ type: EastType;
60
+ value: unknown;
61
+ }>;
62
+ /**
63
+ * Encode and write a dataset value to the object store.
64
+ *
65
+ * @param repoPath - Path to .e3 repository
66
+ * @param value - The value to encode
67
+ * @param type - The East type for encoding (EastType or EastTypeValue)
68
+ * @returns Hash of the written dataset value
69
+ */
70
+ export declare function datasetWrite(repoPath: string, value: unknown, type: EastType | EastTypeValue): Promise<string>;
71
+ /**
72
+ * List field names at a tree path within a package's data tree.
73
+ *
74
+ * @param repoPath - Path to .e3 repository
75
+ * @param name - Package name
76
+ * @param version - Package version
77
+ * @param path - Path to the tree node
78
+ * @returns Array of field names at the path
79
+ * @throws If package not found, path invalid, or path points to a dataset
80
+ */
81
+ export declare function packageListTree(repoPath: string, name: string, version: string, path: TreePath): Promise<string[]>;
82
+ /**
83
+ * Read and decode a dataset value at a path within a package's data tree.
84
+ *
85
+ * @param repoPath - Path to .e3 repository
86
+ * @param name - Package name
87
+ * @param version - Package version
88
+ * @param path - Path to the dataset
89
+ * @returns The decoded dataset value
90
+ * @throws If package not found, path invalid, or path points to a tree
91
+ */
92
+ export declare function packageGetDataset(repoPath: string, name: string, version: string, path: TreePath): Promise<unknown>;
93
+ /**
94
+ * Update a dataset at a path within a workspace.
95
+ *
96
+ * This creates new tree objects along the path with structural sharing,
97
+ * then atomically updates the workspace root.
98
+ *
99
+ * @param repoPath - Path to .e3 repository
100
+ * @param ws - Workspace name
101
+ * @param treePath - Path to the dataset
102
+ * @param value - The new value to write
103
+ * @param type - The East type for encoding the value (EastType or EastTypeValue)
104
+ * @throws If workspace not deployed, path invalid, or path points to a tree
105
+ */
106
+ export declare function workspaceSetDataset(repoPath: string, ws: string, treePath: TreePath, value: unknown, type: EastType | EastTypeValue): Promise<void>;
107
+ /**
108
+ * List field names at a tree path within a workspace's data tree.
109
+ *
110
+ * @param repoPath - Path to .e3 repository
111
+ * @param ws - Workspace name
112
+ * @param path - Path to the tree node
113
+ * @returns Array of field names at the path
114
+ * @throws If workspace not deployed, path invalid, or path points to a dataset
115
+ */
116
+ export declare function workspaceListTree(repoPath: string, ws: string, treePath: TreePath): Promise<string[]>;
117
+ /**
118
+ * Read and decode a dataset value at a path within a workspace's data tree.
119
+ *
120
+ * @param repoPath - Path to .e3 repository
121
+ * @param ws - Workspace name
122
+ * @param path - Path to the dataset
123
+ * @returns The decoded dataset value
124
+ * @throws If workspace not deployed, path invalid, or path points to a tree
125
+ */
126
+ export declare function workspaceGetDataset(repoPath: string, ws: string, treePath: TreePath): Promise<unknown>;
127
+ /**
128
+ * Get the hash of a dataset at a path within a workspace's data tree.
129
+ *
130
+ * Unlike workspaceGetDataset which decodes the value, this returns the raw
131
+ * hash reference. Useful for dataflow execution which operates on hashes.
132
+ *
133
+ * @param repoPath - Path to .e3 repository
134
+ * @param ws - Workspace name
135
+ * @param treePath - Path to the dataset
136
+ * @returns Object with ref type and hash (null for unassigned/null refs)
137
+ * @throws If workspace not deployed, path invalid, or path points to a tree
138
+ */
139
+ export declare function workspaceGetDatasetHash(repoPath: string, ws: string, treePath: TreePath): Promise<{
140
+ refType: DataRef['type'];
141
+ hash: string | null;
142
+ }>;
143
+ /**
144
+ * Set a dataset at a path within a workspace using a pre-computed hash.
145
+ *
146
+ * Unlike workspaceSetDataset which encodes a value, this takes a hash
147
+ * directly. Useful for dataflow execution which already has the output hash.
148
+ *
149
+ * @param repoPath - Path to .e3 repository
150
+ * @param ws - Workspace name
151
+ * @param treePath - Path to the dataset
152
+ * @param valueHash - Hash of the dataset value already in the object store
153
+ * @throws If workspace not deployed, path invalid, or path points to a tree
154
+ */
155
+ export declare function workspaceSetDatasetByHash(repoPath: string, ws: string, treePath: TreePath, valueHash: string): Promise<void>;
156
+ //# sourceMappingURL=trees.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trees.d.ts","sourceRoot":"","sources":["../../src/trees.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAKL,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAsD,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAuB,MAAM,mBAAmB,CAAC;AAYzJ;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyBjD;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,UAAU,CAAC,CAKrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAI7C;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,QAAQ,GAAG,aAAa,GAC7B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAyFD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CAiCnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,OAAO,CAAC,CAoClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,QAAQ,GAAG,aAAa,GAC7B,OAAO,CAAC,IAAI,CAAC,CAiHf;AA2ED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CA8BnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,CAAC,CAiClB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA2B5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA2Gf"}