@elaraai/e3-cloud-files 0.0.0-stage → 1.0.91-alpha.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 (51) hide show
  1. package/LICENSE.md +54 -0
  2. package/README.md +227 -2
  3. package/dist/src/authoring.d.ts +114 -0
  4. package/dist/src/authoring.d.ts.map +1 -0
  5. package/dist/src/authoring.js +178 -0
  6. package/dist/src/authoring.js.map +1 -0
  7. package/dist/src/check/index.d.ts +15 -0
  8. package/dist/src/check/index.d.ts.map +1 -0
  9. package/dist/src/check/index.js +15 -0
  10. package/dist/src/check/index.js.map +1 -0
  11. package/dist/src/check.d.ts +66 -0
  12. package/dist/src/check.d.ts.map +1 -0
  13. package/dist/src/check.js +140 -0
  14. package/dist/src/check.js.map +1 -0
  15. package/dist/src/index.d.ts +27 -0
  16. package/dist/src/index.d.ts.map +1 -0
  17. package/dist/src/index.js +27 -0
  18. package/dist/src/index.js.map +1 -0
  19. package/dist/src/paths.d.ts +59 -0
  20. package/dist/src/paths.d.ts.map +1 -0
  21. package/dist/src/paths.js +114 -0
  22. package/dist/src/paths.js.map +1 -0
  23. package/dist/src/s3/index.d.ts +37 -0
  24. package/dist/src/s3/index.d.ts.map +1 -0
  25. package/dist/src/s3/index.js +76 -0
  26. package/dist/src/s3/index.js.map +1 -0
  27. package/dist/src/storage/index.d.ts +16 -0
  28. package/dist/src/storage/index.d.ts.map +1 -0
  29. package/dist/src/storage/index.js +117 -0
  30. package/dist/src/storage/index.js.map +1 -0
  31. package/dist/src/sync/engine.d.ts +136 -0
  32. package/dist/src/sync/engine.d.ts.map +1 -0
  33. package/dist/src/sync/engine.js +345 -0
  34. package/dist/src/sync/engine.js.map +1 -0
  35. package/dist/src/sync/index.d.ts +15 -0
  36. package/dist/src/sync/index.d.ts.map +1 -0
  37. package/dist/src/sync/index.js +15 -0
  38. package/dist/src/sync/index.js.map +1 -0
  39. package/dist/src/sync/memory.d.ts +65 -0
  40. package/dist/src/sync/memory.d.ts.map +1 -0
  41. package/dist/src/sync/memory.js +127 -0
  42. package/dist/src/sync/memory.js.map +1 -0
  43. package/dist/test/decode.examples.d.ts +33 -0
  44. package/dist/test/decode.examples.d.ts.map +1 -0
  45. package/dist/test/decode.examples.js +103 -0
  46. package/dist/test/decode.examples.js.map +1 -0
  47. package/dist/test/orders.examples.d.ts +88 -0
  48. package/dist/test/orders.examples.d.ts.map +1 -0
  49. package/dist/test/orders.examples.js +71 -0
  50. package/dist/test/orders.examples.js.map +1 -0
  51. package/package.json +76 -3
package/LICENSE.md ADDED
@@ -0,0 +1,54 @@
1
+ # Business Source License 1.1
2
+
3
+ Copyright (c) 2025 Elara AI Pty Ltd
4
+
5
+ ## License
6
+
7
+ **Licensor:** Elara AI Pty Ltd
8
+
9
+ **Licensed Work:** @elaraai/e3-cloud-files
10
+
11
+ **Change Date:** Four years from the date of each release
12
+
13
+ **Change License:** AGPL-3.0
14
+
15
+ ## Terms
16
+
17
+ The Licensed Work is provided under the terms of the Business Source License 1.1 as detailed below.
18
+
19
+ ### Grant of Rights
20
+
21
+ The Licensor grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work.
22
+
23
+ ### Production Use Limitation
24
+
25
+ **"Production Use"** means any use by or on behalf of a for-profit entity, other than for evaluation, testing, or development purposes.
26
+
27
+ Production Use requires a separate commercial license from the Licensor.
28
+
29
+ ### Change Date
30
+
31
+ On the Change Date (four years after each release), the Licensed Work will be made available under the Change License (AGPL-3.0).
32
+
33
+ ### No Warranty
34
+
35
+ THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. THE LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
36
+
37
+ ### Package-Specific Licenses
38
+
39
+ Individual packages within this repository may have different licensing terms. See the LICENSE.md file in each package directory for details.
40
+
41
+ ## Commercial Licensing
42
+
43
+ To obtain a commercial license for Production Use, contact:
44
+
45
+ **Email:** support@elara.ai
46
+ **Website:** https://elaraai.com
47
+
48
+ ## Governing Law
49
+
50
+ This license is governed by the laws of New South Wales, Australia.
51
+
52
+ ---
53
+
54
+ *Elara AI Pty Ltd*
package/README.md CHANGED
@@ -1,3 +1,228 @@
1
- # Temporary Holding Version
1
+ # @elaraai/e3-cloud-files
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
+ Files for e3 cloud: a solution's inputs that come from files in a bucket
4
+ (`s3://bucket/prefix/`).
5
+ The solution says in its code which inputs a bucket's files fill. Each
6
+ workspace says where the files are. `e3-cloud files sync` brings in what
7
+ changed, the same way on a local repository and on a deployed workspace.
8
+
9
+ - **Your data stays in the bucket.** Locally, a sync reads the bucket with
10
+ your own cloud credentials. The bytes land only in the local e3 repository,
11
+ never in your project.
12
+ - **A file arrives as it is**, a `Blob`. A task decodes it in East: as East's
13
+ JSON, as CSV, or as text.
14
+ - **Nothing polls.** A sync runs when someone asks for it, and reads only the
15
+ files that changed since the last one.
16
+
17
+ Its version is the @elaraai lockstep it is built against: install the one of
18
+ the same version as your east and e3.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npm install @elaraai/e3-cloud-files@<your e3's version>
24
+ ```
25
+
26
+ Its peers are the same lockstep's `@elaraai/east` and `@elaraai/e3`. The
27
+ `e3-cloud` CLI (`@elaraai/e3-cloud-cli`) deploys and syncs.
28
+
29
+ ## Declaring the files
30
+
31
+ A **source** is a place files come from, named in your code. Each workspace
32
+ binds it to a bucket and prefix. Its shapes declare the inputs its files
33
+ fill:
34
+
35
+ ```ts
36
+ // src/files.ts
37
+ import { Files } from '@elaraai/e3-cloud-files';
38
+
39
+ /** Where the partners' files are: each workspace binds it to a bucket and prefix. */
40
+ export const upload = Files.source('upload');
41
+
42
+ /** One file: today's exchange rates. */
43
+ export const rates = upload.file('rates', { key: 'rates.json' });
44
+ /** The newest stock snapshot: named by date, so the greatest key is the latest. */
45
+ export const stock = upload.latest('stock', { prefix: 'stock/', include: '*.json' });
46
+ /** Every order file, keyed by its name. */
47
+ export const orders = upload.folder('orders', { prefix: 'orders/', include: '*.json' });
48
+ /** The order files' sizes, times and ETags, without their bytes. */
49
+ export const orderFiles = upload.listing('order_files', { prefix: 'orders/', include: '*.json' });
50
+
51
+ export default Files.manifest([upload]);
52
+ ```
53
+
54
+ | Shape | Selects | The input's type | Largest file |
55
+ |---|---|---|---|
56
+ | `file(input, { key })` | One key | `Blob` | 1 GiB |
57
+ | `latest(input, { prefix, include? })` | The greatest key under the prefix that matches | `Blob` | 1 GiB |
58
+ | `folder(input, { prefix, include? })` | Every key under the prefix that matches, by its path under the prefix | `Dict<String, Blob>` | 64 MiB each |
59
+ | `listing(input, { prefix, include? })` | The same keys' size, time and ETag, without their bytes | `Dict<String, Struct{size, modified, etag}>` | none |
60
+
61
+ - **Each shape returns an ordinary `e3.input`.** It has no default, so it
62
+ stays unassigned until a sync sets it. A task takes it like any input, and
63
+ a task that needs it waits until the first sync, as with any unassigned
64
+ input.
65
+ - **Keys and prefixes are relative to the binding.** The code never names a
66
+ bucket. A prefix is `''` (everything the binding holds) or ends with `/`.
67
+ - **`include` is a glob** over each file's path under the prefix: `*` matches
68
+ within one folder, `**` across folders, `?` one character. `*.json` takes
69
+ only the prefix's own files; `**/*.json` takes its subfolders' too, their
70
+ paths naming the subfolder (`2026/10/a.json`).
71
+ - **Mistakes are refused as they are declared** (`FilesDeclarationError`, one
72
+ line per problem): a name e3 refuses, a key that isn't relative, a glob
73
+ that can't match, and in `Files.manifest` two sources of one name or two
74
+ shapes filling one input.
75
+
76
+ ## Decoding in a task
77
+
78
+ A task decodes what arrives. The package is a package, as always:
79
+
80
+ ```ts
81
+ // src/package.ts
82
+ import { East, ArrayType, BlobType, FloatType, StringType, StructType } from '@elaraai/east';
83
+ import e3 from '@elaraai/e3';
84
+ import { FilesFolderType } from '@elaraai/e3-cloud-files';
85
+ import { rates, orders } from './files.js';
86
+
87
+ const Rate = StructType({ currency: StringType, rate: FloatType });
88
+ const Order = StructType({ id: StringType, sku: StringType, currency: StringType, amount: FloatType });
89
+
90
+ const decodeRates = East.function([BlobType], ArrayType(Rate), (_$, file) =>
91
+ file.decodeUtf8().parseJson(ArrayType(Rate)));
92
+
93
+ const decodeOrders = East.function([FilesFolderType], ArrayType(Order), (_$, files) =>
94
+ files.flattenToArray((_$, file) => file.decodeUtf8().parseJson(ArrayType(Order))));
95
+
96
+ export const rateTable = e3.task('rate_table', [rates], decodeRates, { runner });
97
+ export const allOrders = e3.task('all_orders', [orders], decodeOrders, { runner });
98
+
99
+ export default e3.package('orders', '1.0.0', rateTable, allOrders);
100
+ ```
101
+
102
+ - **CSV:** `file.decodeCsv(Row, { delimiter: ',' })`, the header naming the
103
+ struct's fields.
104
+ - **Text:** `file.decodeUtf8().split('\n')`.
105
+ - **A folder** is in its paths' order. `flattenToArray` joins its files'
106
+ rows; its key is each file's path, if a row should say where it came from.
107
+ - **A listing** lets a task choose files by name, size or time without
108
+ reading them.
109
+
110
+ The plugin's example index holds one example of each (search
111
+ `e3-cloud-files`).
112
+
113
+ ## Deploying and syncing
114
+
115
+ The package deploys as always. The declarations deploy beside it, are checked
116
+ against it, and each source is bound:
117
+
118
+ ```bash
119
+ e3 workspace deploy ./repo dev --from-source src/package.ts
120
+ e3-cloud files deploy ./repo dev src/files.ts
121
+ e3-cloud files bind ./repo dev upload s3://partner-drop/orders-team/ --profile partner --latest 30
122
+ e3-cloud files sync ./repo dev
123
+ e3 start ./repo dev
124
+ ```
125
+
126
+ - **`<repo>` is a local repository's path or a repository URL**
127
+ (`https://e3.example.com/repos/acme`). The commands are the same for both.
128
+ - **`files deploy`** runs the module (its default export is
129
+ `Files.manifest(...)`) and checks the declarations against the package the
130
+ workspace runs. Each mapping's input must be in the package, writable, and
131
+ exactly its shape's type. `--dry-run` checks and keeps nothing.
132
+ - **`files bind`** says where a source's files are for this workspace:
133
+ `s3://bucket/prefix/`. `--region` gives the bucket's region when it isn't
134
+ your configured one. On a local repository only: `--profile` names the
135
+ profile to read with (one of `~/.aws/config`'s), and `--latest n` takes
136
+ only each folder's n greatest keys, which caps what comes down to your
137
+ machine.
138
+ - **`files sync`** lists each source and compares every file with what its
139
+ input took last, by ETag and size. It reads only what is new or changed,
140
+ writes only the inputs whose files changed, and says what it did per input.
141
+ `--input` syncs only those inputs; `--dry-run` lists what a sync would take
142
+ and takes nothing. A sync doesn't run the dataflow: `e3 start` does, and the
143
+ sync prints the command when anything changed.
144
+ - **`files status`** shows the declarations, where each source is bound, and
145
+ the last sync.
146
+
147
+ A sync is safe to repeat and to stop. Each input is remembered only once it
148
+ is written, so a sync that stops part way takes the rest next time.
149
+
150
+ ### What a sync takes again whole
151
+
152
+ A sync trusts what an input took last only while the input still holds the
153
+ value the sync wrote. It takes an input's files again whole when:
154
+
155
+ - a deploy reset the input, or someone set it by hand. A package deploy resets
156
+ inputs unless told to keep them: `e3 workspace deploy … --inputs
157
+ keep-edited` keeps synced inputs while their type is unchanged;
158
+ - the input's declaration changed (`files deploy` says which);
159
+ - its source was bound somewhere else (`files bind` says which).
160
+
161
+ ### Large folders
162
+
163
+ A folder is stored as e3 stores any large collection, in pieces each holding
164
+ the files between two keys. A sync that changes a few files rewrites only the
165
+ pieces holding them, and carries every other piece over unread.
166
+
167
+ A folder's new and changed files are taken in batches of at most 256 MiB:
168
+ each batch is read, written into the folder and remembered before the next
169
+ is read. So a sync holds one batch of files and the pieces it changes,
170
+ however large the folder; the first sync of 6 GB of files holds 256 MiB at a
171
+ time, and a sync stopped part way takes the rest next time.
172
+
173
+ A `file` or `latest` input is held whole while it is written: a 1 GiB file
174
+ needs some 3 GiB of memory.
175
+
176
+ ### On a local repository
177
+
178
+ The repository keeps each workspace's Files in
179
+ `<repo>/.e3-cloud/files/<workspace>.json`: the declarations, the bindings,
180
+ what each input took last, and the last sync's report. It belongs to the
181
+ repository, never to the project. Removing the repository removes it, along
182
+ with every byte the syncs took in.
183
+
184
+ A sync reads with the binding's `--profile`, else the SDK's usual chain
185
+ (`AWS_PROFILE`, the environment, SSO). An expired SSO login says which source
186
+ and profile it was: `aws sso login --profile <name>` renews it.
187
+
188
+ ## The checks
189
+
190
+ `@elaraai/e3-cloud-files/check` holds the checks without the authoring:
191
+
192
+ - `checkFiles(manifest, inputs)`: the declarations against a package's inputs
193
+ (`readPackageInputs(read, packageHash)` reads them from its objects);
194
+ - `checkBindings(manifest, bindings, policy)`: bindings against the
195
+ declarations, and in the cloud against the sources the deployment grants.
196
+
197
+ Both answer `FilesProblem` values (from `@elaraai/e3-cloud-types`), each
198
+ rendered as one line by `filesProblemText`.
199
+
200
+ ## The East types
201
+
202
+ In `@elaraai/e3-cloud-types`, re-exported here:
203
+
204
+ - `FilesManifestType`: the sources' names, and each mapping's input, source
205
+ and shape (`FilesShapeType`: `file`, `latest`, `folder`, `listing`).
206
+ - `FilesBindingType`: a source's URL, region, and, locally, profile and
207
+ `latest`.
208
+ - `FilesSyncReportType`: per input, the files new, changed, removed,
209
+ unchanged and refused, the bytes taken in, and whether it was written.
210
+ - `FilesStatusType`, `FilesProblemType`.
211
+ - The inputs' types: `FilesFileType` (`Blob`), `FilesFolderType`
212
+ (`Dict<String, Blob>`), `FilesListingType`.
213
+
214
+ ## Entries
215
+
216
+ | Entry | Holds |
217
+ |---|---|
218
+ | `@elaraai/e3-cloud-files` | Authoring: `Files.source`, the shapes, `Files.manifest`, and the types |
219
+ | `@elaraai/e3-cloud-files/check` | The checks, without the authoring |
220
+ | `@elaraai/e3-cloud-files/sync` | The sync (`syncFiles`) over what reads, writes and remembers, and those three in memory for tests |
221
+ | `@elaraai/e3-cloud-files/storage` | The sync's writer over an e3 store (needs `@elaraai/e3-core`) |
222
+ | `@elaraai/e3-cloud-files/s3` | The sync's reader of a bucket (needs `@aws-sdk/client-s3`) |
223
+ | `@elaraai/e3-cloud-files/examples/*` | The worked example (`orders`) and the decoding examples (`decode`) |
224
+
225
+ ## License
226
+
227
+ [BSL 1.1](./LICENSE.md). Production use needs a commercial license from Elara
228
+ AI Pty Ltd. Each release becomes AGPL-3.0 four years after it is released.
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Declaring which inputs come from files.
7
+ *
8
+ * ```ts
9
+ * export const upload = Files.source('upload');
10
+ * export const rates = upload.file('rates', { key: 'rates.json' });
11
+ * export const stock = upload.latest('stock', { prefix: 'stock/' });
12
+ * export const orders = upload.folder('orders', { prefix: 'orders/', include: '*.json' });
13
+ * export default Files.manifest([upload]);
14
+ * ```
15
+ *
16
+ * Each declaration is an ordinary `e3.input` with no default, so the package
17
+ * is plain e3 and tasks take these inputs as any other. A sync fills them;
18
+ * until the first, they are unassigned. What each source's files fill is the
19
+ * {@link Files.manifest}, which `e3-cloud files deploy` deploys beside the
20
+ * package.
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ import e3 from '@elaraai/e3';
25
+ import { type EastType } from '@elaraai/east';
26
+ import { FilesFileType, FilesFolderType, FilesListingType, type FilesManifest, type FilesMapping, type FilesProblem } from '@elaraai/e3-cloud-types';
27
+ /** The input a declaration makes: an `e3.input` of its shape's type, with no default. */
28
+ export type FilesInput<Name extends string, T extends EastType> = ReturnType<typeof e3.input<Name, T>>;
29
+ /** The selection of `latest`, `folder` and `listing`: a prefix, and a glob over the paths under it. */
30
+ export interface FilesSelection {
31
+ /** The folder, relative to where the workspace binds the source: `''` for all of it, else ending with `/` */
32
+ readonly prefix: string;
33
+ /** A glob over paths relative to the prefix: `*` within a segment, `**` across segments, `?` one character */
34
+ readonly include?: string;
35
+ }
36
+ /** Thrown when declarations are not well-formed, naming every problem. */
37
+ export declare class FilesDeclarationError extends Error {
38
+ /** Every problem */
39
+ readonly problems: readonly FilesProblem[];
40
+ constructor(problems: readonly FilesProblem[]);
41
+ }
42
+ /**
43
+ * A source of files: a name each workspace binds to a bucket and a prefix,
44
+ * and the inputs its files fill.
45
+ */
46
+ export declare class FilesSource {
47
+ #private;
48
+ /** The source's name */
49
+ readonly name: string;
50
+ /** @internal Use {@link Files.source}. */
51
+ constructor(name: string);
52
+ /** The inputs this source fills, in the order they were declared. */
53
+ get mappings(): readonly FilesMapping[];
54
+ /**
55
+ * One file, as a `Blob`: the input `.inputs.<input>`.
56
+ *
57
+ * @param input - The input's name
58
+ * @param spec - `key`: the file, relative to where the workspace binds the source
59
+ * @returns The input, for tasks to take
60
+ */
61
+ file<Name extends string>(input: Name, spec: {
62
+ readonly key: string;
63
+ }): FilesInput<Name, typeof FilesFileType>;
64
+ /**
65
+ * The newest file under a prefix, as a `Blob`: the greatest key that matches
66
+ * `include`, so files named by their time pick the latest.
67
+ *
68
+ * @param input - The input's name
69
+ * @param spec - The prefix, and a glob over the paths under it
70
+ * @returns The input, for tasks to take
71
+ */
72
+ latest<Name extends string>(input: Name, spec: FilesSelection): FilesInput<Name, typeof FilesFileType>;
73
+ /**
74
+ * Every file under a prefix that matches `include`, as a
75
+ * `Dict<String, Blob>` keyed by each file's path relative to the prefix.
76
+ *
77
+ * @param input - The input's name
78
+ * @param spec - The prefix, and a glob over the paths under it
79
+ * @returns The input, for tasks to take
80
+ */
81
+ folder<Name extends string>(input: Name, spec: FilesSelection): FilesInput<Name, typeof FilesFolderType>;
82
+ /**
83
+ * The files under a prefix that match `include`, without their bytes: each
84
+ * one's size, time and ETag, keyed by its path relative to the prefix, so a
85
+ * task can pick files by name or time.
86
+ *
87
+ * @param input - The input's name
88
+ * @param spec - The prefix, and a glob over the paths under it
89
+ * @returns The input, for tasks to take
90
+ */
91
+ listing<Name extends string>(input: Name, spec: FilesSelection): FilesInput<Name, typeof FilesListingType>;
92
+ }
93
+ /** Declaring files. */
94
+ export declare const Files: {
95
+ /**
96
+ * A source of files, which each workspace binds to a bucket and a prefix.
97
+ *
98
+ * @param name - Its name, unique among a solution's sources
99
+ * @returns The source, whose methods declare the inputs it fills
100
+ * @throws {FilesDeclarationError} When the name is one e3 refuses
101
+ */
102
+ source(name: string): FilesSource;
103
+ /**
104
+ * The declarations `e3-cloud files deploy` deploys: the sources, and the
105
+ * inputs their files fill.
106
+ *
107
+ * @param sources - Every source
108
+ * @returns The manifest, an East value of `FilesManifestType`
109
+ * @throws {FilesDeclarationError} When two sources share a name, or two
110
+ * mappings fill one input
111
+ */
112
+ manifest(sources: readonly FilesSource[]): FilesManifest;
113
+ };
114
+ //# sourceMappingURL=authoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../../src/authoring.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,EACL,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAEhD,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EACzD,MAAM,yBAAyB,CAAC;AAGjC,yFAAyF;AACzF,MAAM,MAAM,UAAU,CAAC,IAAI,SAAS,MAAM,EAAE,CAAC,SAAS,QAAQ,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAEvG,uGAAuG;AACvG,MAAM,WAAW,cAAc;IAC7B,6GAA6G;IAC7G,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8GAA8G;IAC9G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,0EAA0E;AAC1E,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,oBAAoB;IACpB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;gBAE/B,QAAQ,EAAE,SAAS,YAAY,EAAE;CAK9C;AA8BD;;;GAGG;AACH,qBAAa,WAAW;;IACtB,wBAAwB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,0CAA0C;gBAC9B,IAAI,EAAE,MAAM;IAKxB,qEAAqE;IACrE,IAAI,QAAQ,IAAI,SAAS,YAAY,EAAE,CAEtC;IASD;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,aAAa,CAAC;IAM9G;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,aAAa,CAAC;IAItG;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,eAAe,CAAC;IAIxG;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,gBAAgB,CAAC;CAG3G;AAED,uBAAuB;AACvB,eAAO,MAAM,KAAK;IAChB;;;;;;OAMG;iBACU,MAAM,GAAG,WAAW;IAIjC;;;;;;;;OAQG;sBACe,SAAS,WAAW,EAAE,GAAG,aAAa;CAmBzD,CAAC"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Declaring which inputs come from files.
7
+ *
8
+ * ```ts
9
+ * export const upload = Files.source('upload');
10
+ * export const rates = upload.file('rates', { key: 'rates.json' });
11
+ * export const stock = upload.latest('stock', { prefix: 'stock/' });
12
+ * export const orders = upload.folder('orders', { prefix: 'orders/', include: '*.json' });
13
+ * export default Files.manifest([upload]);
14
+ * ```
15
+ *
16
+ * Each declaration is an ordinary `e3.input` with no default, so the package
17
+ * is plain e3 and tasks take these inputs as any other. A sync fills them;
18
+ * until the first, they are unassigned. What each source's files fill is the
19
+ * {@link Files.manifest}, which `e3-cloud files deploy` deploys beside the
20
+ * package.
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+ import e3 from '@elaraai/e3';
25
+ import { none, some, variant } from '@elaraai/east';
26
+ import { nameProblem } from '@elaraai/e3-types';
27
+ import { FilesFileType, FilesFolderType, FilesListingType, filesProblemText, } from '@elaraai/e3-cloud-types';
28
+ import { includeProblem, keyProblem, prefixProblem } from './paths.js';
29
+ /** Thrown when declarations are not well-formed, naming every problem. */
30
+ export class FilesDeclarationError extends Error {
31
+ /** Every problem */
32
+ problems;
33
+ constructor(problems) {
34
+ super(`The files declarations are not well-formed:\n${problems.map((p) => ` - ${filesProblemText(p)}`).join('\n')}`);
35
+ this.name = 'FilesDeclarationError';
36
+ this.problems = problems;
37
+ }
38
+ }
39
+ /** Throws a declaration's problems, if it has any. */
40
+ function refuse(problems) {
41
+ if (problems.length > 0)
42
+ throw new FilesDeclarationError(problems);
43
+ }
44
+ /** A name's problem, as e3 names a dataset's path segment. */
45
+ function nameProblems(kind, name) {
46
+ const reason = nameProblem('workspace', name);
47
+ return reason === null ? [] : [variant('invalid_name', { kind, name, reason })];
48
+ }
49
+ /** A selection's problems. */
50
+ function selectionProblems(input, selection) {
51
+ const problems = [];
52
+ const prefix = prefixProblem(selection.prefix);
53
+ if (prefix !== null)
54
+ problems.push(variant('invalid_key', { input, key: selection.prefix, reason: prefix }));
55
+ if (selection.include !== undefined) {
56
+ const include = includeProblem(selection.include);
57
+ if (include !== null)
58
+ problems.push(variant('invalid_include', { input, include: selection.include, reason: include }));
59
+ }
60
+ return problems;
61
+ }
62
+ /** A selection's shape fields. */
63
+ function selected(selection) {
64
+ return { prefix: selection.prefix, include: selection.include === undefined ? none : some(selection.include) };
65
+ }
66
+ /**
67
+ * A source of files: a name each workspace binds to a bucket and a prefix,
68
+ * and the inputs its files fill.
69
+ */
70
+ export class FilesSource {
71
+ /** The source's name */
72
+ name;
73
+ #mappings = [];
74
+ /** @internal Use {@link Files.source}. */
75
+ constructor(name) {
76
+ refuse(nameProblems('source', name));
77
+ this.name = name;
78
+ }
79
+ /** The inputs this source fills, in the order they were declared. */
80
+ get mappings() {
81
+ return this.#mappings;
82
+ }
83
+ /** Records a mapping and makes its input. */
84
+ #declare(input, type, shape, problems) {
85
+ refuse([...nameProblems('input', input), ...problems]);
86
+ this.#mappings.push({ input, source: this.name, shape });
87
+ return e3.input(input, type);
88
+ }
89
+ /**
90
+ * One file, as a `Blob`: the input `.inputs.<input>`.
91
+ *
92
+ * @param input - The input's name
93
+ * @param spec - `key`: the file, relative to where the workspace binds the source
94
+ * @returns The input, for tasks to take
95
+ */
96
+ file(input, spec) {
97
+ const reason = keyProblem(spec.key);
98
+ const problems = reason === null ? [] : [variant('invalid_key', { input, key: spec.key, reason })];
99
+ return this.#declare(input, FilesFileType, variant('file', { key: spec.key }), problems);
100
+ }
101
+ /**
102
+ * The newest file under a prefix, as a `Blob`: the greatest key that matches
103
+ * `include`, so files named by their time pick the latest.
104
+ *
105
+ * @param input - The input's name
106
+ * @param spec - The prefix, and a glob over the paths under it
107
+ * @returns The input, for tasks to take
108
+ */
109
+ latest(input, spec) {
110
+ return this.#declare(input, FilesFileType, variant('latest', selected(spec)), selectionProblems(input, spec));
111
+ }
112
+ /**
113
+ * Every file under a prefix that matches `include`, as a
114
+ * `Dict<String, Blob>` keyed by each file's path relative to the prefix.
115
+ *
116
+ * @param input - The input's name
117
+ * @param spec - The prefix, and a glob over the paths under it
118
+ * @returns The input, for tasks to take
119
+ */
120
+ folder(input, spec) {
121
+ return this.#declare(input, FilesFolderType, variant('folder', selected(spec)), selectionProblems(input, spec));
122
+ }
123
+ /**
124
+ * The files under a prefix that match `include`, without their bytes: each
125
+ * one's size, time and ETag, keyed by its path relative to the prefix, so a
126
+ * task can pick files by name or time.
127
+ *
128
+ * @param input - The input's name
129
+ * @param spec - The prefix, and a glob over the paths under it
130
+ * @returns The input, for tasks to take
131
+ */
132
+ listing(input, spec) {
133
+ return this.#declare(input, FilesListingType, variant('listing', selected(spec)), selectionProblems(input, spec));
134
+ }
135
+ }
136
+ /** Declaring files. */
137
+ export const Files = {
138
+ /**
139
+ * A source of files, which each workspace binds to a bucket and a prefix.
140
+ *
141
+ * @param name - Its name, unique among a solution's sources
142
+ * @returns The source, whose methods declare the inputs it fills
143
+ * @throws {FilesDeclarationError} When the name is one e3 refuses
144
+ */
145
+ source(name) {
146
+ return new FilesSource(name);
147
+ },
148
+ /**
149
+ * The declarations `e3-cloud files deploy` deploys: the sources, and the
150
+ * inputs their files fill.
151
+ *
152
+ * @param sources - Every source
153
+ * @returns The manifest, an East value of `FilesManifestType`
154
+ * @throws {FilesDeclarationError} When two sources share a name, or two
155
+ * mappings fill one input
156
+ */
157
+ manifest(sources) {
158
+ const problems = [];
159
+ const names = new Set();
160
+ const inputs = new Set();
161
+ const mappings = [];
162
+ for (const source of sources) {
163
+ if (names.has(source.name)) {
164
+ problems.push(variant('invalid_name', { kind: 'source', name: source.name, reason: 'is declared twice' }));
165
+ }
166
+ names.add(source.name);
167
+ for (const mapping of source.mappings) {
168
+ if (inputs.has(mapping.input))
169
+ problems.push(variant('duplicate_input', { input: mapping.input }));
170
+ inputs.add(mapping.input);
171
+ mappings.push(mapping);
172
+ }
173
+ }
174
+ refuse(problems);
175
+ return { sources: [...names], mappings };
176
+ },
177
+ };
178
+ //# sourceMappingURL=authoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring.js","sourceRoot":"","sources":["../../src/authoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * `@elaraai/e3-cloud-files/check`: the checks a deploy of declarations and a
7
+ * bind run, and the keys, prefixes, globs and URLs they hold to, without the
8
+ * authoring (which needs `@elaraai/e3`): what the CLI and the platform
9
+ * import.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ export { checkFiles, checkBindings, readPackageInputs, shapeType, type PackageInput, type ObjectReader, type BindingPolicy, } from '../check.js';
14
+ export { globMatcher, parseBucketUrl, keyProblem, prefixProblem, includeProblem, type BucketLocation } from '../paths.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/check/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * `@elaraai/e3-cloud-files/check`: the checks a deploy of declarations and a
7
+ * bind run, and the keys, prefixes, globs and URLs they hold to, without the
8
+ * authoring (which needs `@elaraai/e3`): what the CLI and the platform
9
+ * import.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ export { checkFiles, checkBindings, readPackageInputs, shapeType, } from '../check.js';
14
+ export { globMatcher, parseBucketUrl, keyProblem, prefixProblem, includeProblem } from '../paths.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/check/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;GAOG;AAEH,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,SAAS,GAIV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC"}