@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
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Whether declarations fit a package, and bindings fit declarations.
7
+ *
8
+ * {@link checkFiles} is the one check every deploy of declarations runs, on a
9
+ * local repository and in the cloud: each mapping's input exists, is an
10
+ * input, and is of its shape's type, compared exactly. {@link checkBindings}
11
+ * is what a bind runs. {@link readPackageInputs} reads a package's inputs
12
+ * from its objects, through a reader: the store's on a server, a local
13
+ * repository's on a machine.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+ import { type EastTypeValue } from '@elaraai/east';
18
+ import { type FilesBinding, type FilesManifest, type FilesProblem, type FilesShape } from '@elaraai/e3-cloud-types';
19
+ /** An input of a package. */
20
+ export interface PackageInput {
21
+ /** Its type */
22
+ readonly type: EastTypeValue;
23
+ /** Whether anything may write it: inputs are writable; task outputs and records are not */
24
+ readonly writable: boolean;
25
+ }
26
+ /** Reads an object of a package's repository by hash. */
27
+ export type ObjectReader = (hash: string) => Promise<Uint8Array>;
28
+ /** The type a shape's input holds. */
29
+ export declare function shapeType(shape: FilesShape): EastTypeValue;
30
+ /**
31
+ * Reads a package's inputs, `.inputs.<name>`, from its objects.
32
+ *
33
+ * @param read - Reads an object by hash
34
+ * @param packageHash - The package object's hash
35
+ * @returns Each input, by name
36
+ */
37
+ export declare function readPackageInputs(read: ObjectReader, packageHash: string): Promise<Map<string, PackageInput>>;
38
+ /**
39
+ * The problems of declarations against a package, none when they fit. Each
40
+ * mapping's input must be an input of the package, of its shape's type.
41
+ *
42
+ * @param manifest - The declarations
43
+ * @param inputs - The package's inputs ({@link readPackageInputs})
44
+ * @returns Every problem
45
+ */
46
+ export declare function checkFiles(manifest: FilesManifest, inputs: ReadonlyMap<string, PackageInput>): FilesProblem[];
47
+ /** Where a binding may point: for a deployed workspace, the sources the deployment grants. */
48
+ export interface BindingPolicy {
49
+ /** Whether the bindings are a local repository's, where `profile` and `latest` apply */
50
+ readonly local: boolean;
51
+ /** The buckets and prefixes the deployment grants, for a deployed workspace; any URL locally */
52
+ readonly granted?: readonly {
53
+ readonly bucket: string;
54
+ readonly prefixes: readonly string[];
55
+ }[];
56
+ }
57
+ /**
58
+ * The problems of bindings against declarations, none when they fit.
59
+ *
60
+ * @param manifest - The declarations
61
+ * @param bindings - The bindings
62
+ * @param policy - Where they may point
63
+ * @returns Every problem
64
+ */
65
+ export declare function checkBindings(manifest: FilesManifest, bindings: readonly FilesBinding[], policy: BindingPolicy): FilesProblem[];
66
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAoD,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAErG,OAAO,EAEL,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAC1E,MAAM,yBAAyB,CAAC;AAGjC,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,eAAe;IACf,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAIjE,sCAAsC;AACtC,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAU1D;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAWnH;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,YAAY,EAAE,CAgC7G;AAED,8FAA8F;AAC9F,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,gGAAgG;IAChG,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CACjG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,YAAY,EAAE,CAuB/H"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Whether declarations fit a package, and bindings fit declarations.
7
+ *
8
+ * {@link checkFiles} is the one check every deploy of declarations runs, on a
9
+ * local repository and in the cloud: each mapping's input exists, is an
10
+ * input, and is of its shape's type, compared exactly. {@link checkBindings}
11
+ * is what a bind runs. {@link readPackageInputs} reads a package's inputs
12
+ * from its objects, through a reader: the store's on a server, a local
13
+ * repository's on a machine.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+ import { EastTypeType, equalFor, toEastTypeValue, variant } from '@elaraai/east';
18
+ import { decodePackageObject } from '@elaraai/e3-types';
19
+ import { FilesFileType, FilesFolderType, FilesListingType, } from '@elaraai/e3-cloud-types';
20
+ import { includeProblem, keyProblem, parseBucketUrl, prefixProblem } from './paths.js';
21
+ const typesEqual = equalFor(EastTypeType);
22
+ /** The type a shape's input holds. */
23
+ export function shapeType(shape) {
24
+ switch (shape.type) {
25
+ case 'file':
26
+ case 'latest':
27
+ return toEastTypeValue(FilesFileType);
28
+ case 'folder':
29
+ return toEastTypeValue(FilesFolderType);
30
+ case 'listing':
31
+ return toEastTypeValue(FilesListingType);
32
+ }
33
+ }
34
+ /**
35
+ * Reads a package's inputs, `.inputs.<name>`, from its objects.
36
+ *
37
+ * @param read - Reads an object by hash
38
+ * @param packageHash - The package object's hash
39
+ * @returns Each input, by name
40
+ */
41
+ export async function readPackageInputs(read, packageHash) {
42
+ const pkg = decodePackageObject(await read(packageHash));
43
+ const inputs = new Map();
44
+ const root = pkg.data.structure;
45
+ if (root.type !== 'struct')
46
+ return inputs;
47
+ const tree = root.value.get('inputs');
48
+ if (tree === undefined || tree.type !== 'struct')
49
+ return inputs;
50
+ for (const [name, child] of tree.value) {
51
+ if (child.type === 'value')
52
+ inputs.set(name, { type: child.value.type, writable: child.value.writable });
53
+ }
54
+ return inputs;
55
+ }
56
+ /**
57
+ * The problems of declarations against a package, none when they fit. Each
58
+ * mapping's input must be an input of the package, of its shape's type.
59
+ *
60
+ * @param manifest - The declarations
61
+ * @param inputs - The package's inputs ({@link readPackageInputs})
62
+ * @returns Every problem
63
+ */
64
+ export function checkFiles(manifest, inputs) {
65
+ const problems = [];
66
+ const seen = new Set();
67
+ const sources = new Set(manifest.sources);
68
+ for (const mapping of manifest.mappings) {
69
+ const { input, shape } = mapping;
70
+ if (seen.has(input))
71
+ problems.push(variant('duplicate_input', { input }));
72
+ seen.add(input);
73
+ if (!sources.has(mapping.source))
74
+ problems.push(variant('source_unknown', { source: mapping.source }));
75
+ // What the declarations alone get wrong, as a declaration would have refused it
76
+ if (shape.type === 'file') {
77
+ const reason = keyProblem(shape.value.key);
78
+ if (reason !== null)
79
+ problems.push(variant('invalid_key', { input, key: shape.value.key, reason }));
80
+ }
81
+ else {
82
+ const reason = prefixProblem(shape.value.prefix);
83
+ if (reason !== null)
84
+ problems.push(variant('invalid_key', { input, key: shape.value.prefix, reason }));
85
+ if (shape.value.include.type === 'some') {
86
+ const include = includeProblem(shape.value.include.value);
87
+ if (include !== null)
88
+ problems.push(variant('invalid_include', { input, include: shape.value.include.value, reason: include }));
89
+ }
90
+ }
91
+ const expected = shapeType(shape);
92
+ const declared = inputs.get(input);
93
+ if (declared === undefined) {
94
+ problems.push(variant('input_missing', { input, expected }));
95
+ }
96
+ else if (!declared.writable) {
97
+ problems.push(variant('input_not_writable', { input }));
98
+ }
99
+ else if (!typesEqual(declared.type, expected)) {
100
+ problems.push(variant('input_type', { input, expected, actual: declared.type }));
101
+ }
102
+ }
103
+ return problems;
104
+ }
105
+ /**
106
+ * The problems of bindings against declarations, none when they fit.
107
+ *
108
+ * @param manifest - The declarations
109
+ * @param bindings - The bindings
110
+ * @param policy - Where they may point
111
+ * @returns Every problem
112
+ */
113
+ export function checkBindings(manifest, bindings, policy) {
114
+ const problems = [];
115
+ const sources = new Set(manifest.sources);
116
+ for (const binding of bindings) {
117
+ const { source, url } = binding;
118
+ if (!sources.has(source))
119
+ problems.push(variant('source_unknown', { source }));
120
+ const location = parseBucketUrl(url);
121
+ if ('problem' in location) {
122
+ problems.push(variant('invalid_url', { source, url, reason: location.problem }));
123
+ continue;
124
+ }
125
+ if (!policy.local) {
126
+ if (binding.profile.type === 'some')
127
+ problems.push(variant('local_only', { source, option: 'profile' }));
128
+ if (binding.latest.type === 'some')
129
+ problems.push(variant('local_only', { source, option: 'latest' }));
130
+ const granted = (policy.granted ?? []).some((grant) => grant.bucket === location.bucket && grant.prefixes.some((prefix) => location.prefix.startsWith(prefix)));
131
+ if (!granted)
132
+ problems.push(variant('not_granted', { source, url }));
133
+ }
134
+ if (binding.latest.type === 'some' && binding.latest.value < 1n) {
135
+ problems.push(variant('invalid_url', { source, url, reason: 'keeps fewer than one file (latest)' }));
136
+ }
137
+ }
138
+ return problems;
139
+ }
140
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
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`: a solution's inputs that come from files in a
7
+ * bucket.
8
+ *
9
+ * - `Files.source(name)`: a source, which each workspace binds to a bucket
10
+ * and a prefix; its `file`, `latest`, `folder` and `listing` declare the
11
+ * inputs its files fill, each an ordinary `e3.input`.
12
+ * - `Files.manifest(sources)`: the declarations `e3-cloud files deploy`
13
+ * deploys beside the package.
14
+ * - `checkFiles`, `checkBindings`, `readPackageInputs`: the checks a deploy
15
+ * and a bind run.
16
+ *
17
+ * A file arrives as it is, a `Blob`; the solution decodes it in East. The
18
+ * sync is `@elaraai/e3-cloud-files/sync`; the East types are
19
+ * `@elaraai/e3-cloud-types`'s `Files*`.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ export { Files, FilesSource, FilesDeclarationError, type FilesInput, type FilesSelection } from './authoring.js';
24
+ export { checkFiles, checkBindings, readPackageInputs, shapeType, type PackageInput, type ObjectReader, type BindingPolicy, } from './check.js';
25
+ export { globMatcher, parseBucketUrl, keyProblem, prefixProblem, includeProblem, type BucketLocation } from './paths.js';
26
+ export { FilesManifestType, FilesMappingType, FilesShapeType, FilesBindingType, FilesSyncReportType, FilesMappingReportType, FilesStatusType, FilesProblemType, FilesListingRowType, FilesFileType, FilesFolderType, FilesListingType, FILES_FILE_MAX_BYTES, FILES_FOLDER_ENTRY_MAX_BYTES, filesProblemText, type FilesManifest, type FilesMapping, type FilesShape, type FilesBinding, type FilesSyncReport, type FilesMappingReport, type FilesStatus, type FilesProblem, type FilesListingRow, } from '@elaraai/e3-cloud-types';
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjH,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,27 @@
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`: a solution's inputs that come from files in a
7
+ * bucket.
8
+ *
9
+ * - `Files.source(name)`: a source, which each workspace binds to a bucket
10
+ * and a prefix; its `file`, `latest`, `folder` and `listing` declare the
11
+ * inputs its files fill, each an ordinary `e3.input`.
12
+ * - `Files.manifest(sources)`: the declarations `e3-cloud files deploy`
13
+ * deploys beside the package.
14
+ * - `checkFiles`, `checkBindings`, `readPackageInputs`: the checks a deploy
15
+ * and a bind run.
16
+ *
17
+ * A file arrives as it is, a `Blob`; the solution decodes it in East. The
18
+ * sync is `@elaraai/e3-cloud-files/sync`; the East types are
19
+ * `@elaraai/e3-cloud-types`'s `Files*`.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ export { Files, FilesSource, FilesDeclarationError } from './authoring.js';
24
+ export { checkFiles, checkBindings, readPackageInputs, shapeType, } from './check.js';
25
+ export { globMatcher, parseBucketUrl, keyProblem, prefixProblem, includeProblem } from './paths.js';
26
+ export { FilesManifestType, FilesMappingType, FilesShapeType, FilesBindingType, FilesSyncReportType, FilesMappingReportType, FilesStatusType, FilesProblemType, FilesListingRowType, FilesFileType, FilesFolderType, FilesListingType, FILES_FILE_MAX_BYTES, FILES_FOLDER_ENTRY_MAX_BYTES, filesProblemText, } from '@elaraai/e3-cloud-types';
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAwC,MAAM,gBAAgB,CAAC;AACjH,OAAO,EACL,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,SAAS,GAIV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAuB,MAAM,YAAY,CAAC;AACzH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,GAUjB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The keys, prefixes and globs a mapping names, and the URLs a binding
7
+ * names: what makes each well-formed, and how a glob matches.
8
+ *
9
+ * A mapping's key or prefix is relative to where a workspace binds its
10
+ * source, so it never names a bucket and never begins with `/`. A prefix is
11
+ * a folder: empty for everything the binding holds, else ending with `/`.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /**
16
+ * Why a key cannot name one file, or `null` when it can.
17
+ *
18
+ * @param key - The key, relative to the binding
19
+ * @returns The reason, completing "'<key>' …"
20
+ */
21
+ export declare function keyProblem(key: string): string | null;
22
+ /**
23
+ * Why a prefix cannot name a folder, or `null` when it can.
24
+ *
25
+ * @param prefix - The prefix, relative to the binding: `''`, or ending with `/`
26
+ * @returns The reason, completing "'<prefix>' …"
27
+ */
28
+ export declare function prefixProblem(prefix: string): string | null;
29
+ /**
30
+ * Why a glob cannot select files, or `null` when it can.
31
+ *
32
+ * @param include - The glob, over paths relative to the prefix
33
+ * @returns The reason, completing "include '<include>' …"
34
+ */
35
+ export declare function includeProblem(include: string): string | null;
36
+ /**
37
+ * A glob's matcher over paths relative to a prefix: `*` matches within one
38
+ * segment of the path, `**` across segments, `?` one character but `/`, and
39
+ * every other character itself. No glob matches every path.
40
+ *
41
+ * @param include - The glob, or `null` for every path
42
+ * @returns Whether a path matches
43
+ */
44
+ export declare function globMatcher(include: string | null): (path: string) => boolean;
45
+ /** A binding's URL, read: its bucket, and the prefix under it, `''` or ending with `/`. */
46
+ export interface BucketLocation {
47
+ readonly bucket: string;
48
+ readonly prefix: string;
49
+ }
50
+ /**
51
+ * Reads a binding's URL, `s3://bucket/prefix/`.
52
+ *
53
+ * @param url - The URL
54
+ * @returns The bucket and the prefix, or the reason it is not one, completing "'<url>' …"
55
+ */
56
+ export declare function parseBucketUrl(url: string): BucketLocation | {
57
+ readonly problem: string;
58
+ };
59
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAwB7E;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAQzF"}
@@ -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
+ * The keys, prefixes and globs a mapping names, and the URLs a binding
7
+ * names: what makes each well-formed, and how a glob matches.
8
+ *
9
+ * A mapping's key or prefix is relative to where a workspace binds its
10
+ * source, so it never names a bucket and never begins with `/`. A prefix is
11
+ * a folder: empty for everything the binding holds, else ending with `/`.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /**
16
+ * Why a key cannot name one file, or `null` when it can.
17
+ *
18
+ * @param key - The key, relative to the binding
19
+ * @returns The reason, completing "'<key>' …"
20
+ */
21
+ export function keyProblem(key) {
22
+ if (key === '')
23
+ return 'is empty';
24
+ if (key.startsWith('/'))
25
+ return 'begins with /: a key is relative to where the workspace binds its source';
26
+ if (key.endsWith('/'))
27
+ return 'ends with /, which names a folder rather than a file';
28
+ return null;
29
+ }
30
+ /**
31
+ * Why a prefix cannot name a folder, or `null` when it can.
32
+ *
33
+ * @param prefix - The prefix, relative to the binding: `''`, or ending with `/`
34
+ * @returns The reason, completing "'<prefix>' …"
35
+ */
36
+ export function prefixProblem(prefix) {
37
+ if (prefix.startsWith('/'))
38
+ return 'begins with /: a prefix is relative to where the workspace binds its source';
39
+ if (prefix !== '' && !prefix.endsWith('/'))
40
+ return "doesn't end with /: a prefix names a folder";
41
+ return null;
42
+ }
43
+ /**
44
+ * Why a glob cannot select files, or `null` when it can.
45
+ *
46
+ * @param include - The glob, over paths relative to the prefix
47
+ * @returns The reason, completing "include '<include>' …"
48
+ */
49
+ export function includeProblem(include) {
50
+ if (include === '')
51
+ return 'is empty';
52
+ if (include.startsWith('/'))
53
+ return 'begins with /: it matches paths relative to the prefix';
54
+ if (/\*{3,}/.test(include))
55
+ return 'has three or more * in a row';
56
+ return null;
57
+ }
58
+ /**
59
+ * A glob's matcher over paths relative to a prefix: `*` matches within one
60
+ * segment of the path, `**` across segments, `?` one character but `/`, and
61
+ * every other character itself. No glob matches every path.
62
+ *
63
+ * @param include - The glob, or `null` for every path
64
+ * @returns Whether a path matches
65
+ */
66
+ export function globMatcher(include) {
67
+ if (include === null)
68
+ return () => true;
69
+ let pattern = '';
70
+ for (let i = 0; i < include.length; i++) {
71
+ const c = include[i];
72
+ if (c === '*' && include[i + 1] === '*') {
73
+ // `**/` matches zero or more whole segments; a bare `**`, anything
74
+ if (include[i + 2] === '/') {
75
+ pattern += '(?:.*/)?';
76
+ i += 2;
77
+ }
78
+ else {
79
+ pattern += '.*';
80
+ i += 1;
81
+ }
82
+ }
83
+ else if (c === '*') {
84
+ pattern += '[^/]*';
85
+ }
86
+ else if (c === '?') {
87
+ pattern += '[^/]';
88
+ }
89
+ else {
90
+ pattern += c.replace(/[.+^${}()|[\]\\]/g, '\\$&');
91
+ }
92
+ }
93
+ const regex = new RegExp(`^${pattern}$`, 'su');
94
+ return (path) => regex.test(path);
95
+ }
96
+ /**
97
+ * Reads a binding's URL, `s3://bucket/prefix/`.
98
+ *
99
+ * @param url - The URL
100
+ * @returns The bucket and the prefix, or the reason it is not one, completing "'<url>' …"
101
+ */
102
+ export function parseBucketUrl(url) {
103
+ const match = /^s3:\/\/([^/]+)(?:\/(.*))?$/su.exec(url);
104
+ if (match === null)
105
+ return { problem: 'is not an s3://bucket/prefix/ URL' };
106
+ const bucket = match[1];
107
+ if (!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/u.test(bucket))
108
+ return { problem: `names '${bucket}', which isn't a bucket's name` };
109
+ const prefix = match[2] ?? '';
110
+ if (prefix !== '' && !prefix.endsWith('/'))
111
+ return { problem: "doesn't end with /: a binding names a folder" };
112
+ return { bucket, prefix };
113
+ }
114
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
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/s3`: the sync's reader of a bucket (`s3://`), one
7
+ * bound source read through a client the caller makes. The CLI makes it with
8
+ * the developer's own profile, the platform with a session scoped to the
9
+ * binding's bucket and prefix; both read through this.
10
+ *
11
+ * A listing is the bucket's, a page of 1,000 keys at a time, in key order. An
12
+ * ETag is kept without the quotes the bucket wraps it in. A file is read
13
+ * whole: at most 1 GiB for a `file` or `latest` input, 64 MiB for a folder's
14
+ * file.
15
+ *
16
+ * Needs `@aws-sdk/client-s3`, which a solution's own code never imports: the
17
+ * CLI and the platform do.
18
+ *
19
+ * @packageDocumentation
20
+ */
21
+ import { type S3Client } from '@aws-sdk/client-s3';
22
+ import type { FilesReader } from '../sync/engine.js';
23
+ /** Where a binding's files are: a bucket, and the prefix every key is relative to. */
24
+ export interface S3Location {
25
+ readonly bucket: string;
26
+ /** `''`, or ending with `/` */
27
+ readonly prefix: string;
28
+ }
29
+ /**
30
+ * The reader of one bound source in its bucket.
31
+ *
32
+ * @param client - The client to read with: its credentials and region are the caller's
33
+ * @param location - The bucket, and the prefix the binding names
34
+ * @returns The reader: its keys relative to the prefix
35
+ */
36
+ export declare function s3FilesReader(client: S3Client, location: S3Location): FilesReader;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/s3/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAiF,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClI,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElE,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAYD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,WAAW,CAkCjF"}
@@ -0,0 +1,76 @@
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/s3`: the sync's reader of a bucket (`s3://`), one
7
+ * bound source read through a client the caller makes. The CLI makes it with
8
+ * the developer's own profile, the platform with a session scoped to the
9
+ * binding's bucket and prefix; both read through this.
10
+ *
11
+ * A listing is the bucket's, a page of 1,000 keys at a time, in key order. An
12
+ * ETag is kept without the quotes the bucket wraps it in. A file is read
13
+ * whole: at most 1 GiB for a `file` or `latest` input, 64 MiB for a folder's
14
+ * file.
15
+ *
16
+ * Needs `@aws-sdk/client-s3`, which a solution's own code never imports: the
17
+ * CLI and the platform do.
18
+ *
19
+ * @packageDocumentation
20
+ */
21
+ import { GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, S3ServiceException } from '@aws-sdk/client-s3';
22
+ /** An ETag without the quotes the bucket wraps it in. */
23
+ function bare(etag) {
24
+ return (etag ?? '').replace(/^"|"$/g, '');
25
+ }
26
+ /** Whether the bucket answered that there is no such key. */
27
+ function missing(err) {
28
+ return err instanceof S3ServiceException && (err.name === 'NotFound' || err.name === 'NoSuchKey' || err.$metadata.httpStatusCode === 404);
29
+ }
30
+ /**
31
+ * The reader of one bound source in its bucket.
32
+ *
33
+ * @param client - The client to read with: its credentials and region are the caller's
34
+ * @param location - The bucket, and the prefix the binding names
35
+ * @returns The reader: its keys relative to the prefix
36
+ */
37
+ export function s3FilesReader(client, location) {
38
+ const absolute = (key) => `${location.prefix}${key}`;
39
+ return {
40
+ async *list(prefix) {
41
+ let token;
42
+ do {
43
+ const page = await client.send(new ListObjectsV2Command({ Bucket: location.bucket, Prefix: absolute(prefix), ContinuationToken: token }));
44
+ for (const object of page.Contents ?? []) {
45
+ if (object.Key === undefined)
46
+ continue;
47
+ yield {
48
+ key: object.Key.slice(location.prefix.length),
49
+ size: object.Size ?? 0,
50
+ modified: object.LastModified ?? new Date(0),
51
+ etag: bare(object.ETag),
52
+ };
53
+ }
54
+ token = page.IsTruncated === true ? page.NextContinuationToken : undefined;
55
+ } while (token !== undefined);
56
+ },
57
+ async stat(key) {
58
+ try {
59
+ const head = await client.send(new HeadObjectCommand({ Bucket: location.bucket, Key: absolute(key) }));
60
+ return { key, size: head.ContentLength ?? 0, modified: head.LastModified ?? new Date(0), etag: bare(head.ETag) };
61
+ }
62
+ catch (err) {
63
+ if (missing(err))
64
+ return null;
65
+ throw err;
66
+ }
67
+ },
68
+ async read(key) {
69
+ const object = await client.send(new GetObjectCommand({ Bucket: location.bucket, Key: absolute(key) }));
70
+ if (object.Body === undefined)
71
+ throw new Error(`s3://${location.bucket}/${absolute(key)} answered no bytes`);
72
+ return object.Body.transformToByteArray();
73
+ },
74
+ };
75
+ }
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/s3/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { type StorageBackend } from '@elaraai/e3-core';
6
+ import type { FilesWriter } from '../sync/engine.js';
7
+ /**
8
+ * The sync's writer over an e3 store, for one workspace.
9
+ *
10
+ * @param storage - The store: a local repository's (`LocalStorage`) or the platform's
11
+ * @param repo - The repository: a local repository's path, or the platform's repository name
12
+ * @param ws - The workspace
13
+ * @returns The writer
14
+ */
15
+ export declare function storageWriter(storage: StorageBackend, repo: string, ws: string): FilesWriter;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AAgDpE;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CA+B5F"}