@elaraai/e3-cloud-files 0.0.0-stage → 1.0.92
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 +54 -0
- package/README.md +286 -2
- package/dist/src/authoring.d.ts +114 -0
- package/dist/src/authoring.d.ts.map +1 -0
- package/dist/src/authoring.js +178 -0
- package/dist/src/authoring.js.map +1 -0
- package/dist/src/check/index.d.ts +15 -0
- package/dist/src/check/index.d.ts.map +1 -0
- package/dist/src/check/index.js +15 -0
- package/dist/src/check/index.js.map +1 -0
- package/dist/src/check.d.ts +66 -0
- package/dist/src/check.d.ts.map +1 -0
- package/dist/src/check.js +140 -0
- package/dist/src/check.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +27 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/paths.d.ts +70 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +205 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/s3/index.d.ts +44 -0
- package/dist/src/s3/index.d.ts.map +1 -0
- package/dist/src/s3/index.js +138 -0
- package/dist/src/s3/index.js.map +1 -0
- package/dist/src/storage/index.d.ts +16 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +120 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/sync/engine.d.ts +191 -0
- package/dist/src/sync/engine.d.ts.map +1 -0
- package/dist/src/sync/engine.js +481 -0
- package/dist/src/sync/engine.js.map +1 -0
- package/dist/src/sync/index.d.ts +15 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +15 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/memory.d.ts +75 -0
- package/dist/src/sync/memory.d.ts.map +1 -0
- package/dist/src/sync/memory.js +155 -0
- package/dist/src/sync/memory.js.map +1 -0
- package/dist/test/decode.examples.d.ts +33 -0
- package/dist/test/decode.examples.d.ts.map +1 -0
- package/dist/test/decode.examples.js +103 -0
- package/dist/test/decode.examples.js.map +1 -0
- package/dist/test/orders.examples.d.ts +88 -0
- package/dist/test/orders.examples.d.ts.map +1 -0
- package/dist/test/orders.examples.js +71 -0
- package/dist/test/orders.examples.js.map +1 -0
- package/package.json +76 -3
|
@@ -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"}
|
|
@@ -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,70 @@
|
|
|
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
|
+
* folder of the path, `**` across folders, `?` one character but `/`,
|
|
39
|
+
* `[abc]`, `[a-z]` and `[!abc]` one character of a set but `/`, and
|
|
40
|
+
* `{csv,json}` any of its alternatives, each a glob itself. Every other
|
|
41
|
+
* character matches itself. No glob matches every path.
|
|
42
|
+
*
|
|
43
|
+
* @param include - The glob, or `null` for every path
|
|
44
|
+
* @returns Whether a path matches
|
|
45
|
+
* @throws {Error} When the glob is malformed ({@link includeProblem} says how)
|
|
46
|
+
*/
|
|
47
|
+
export declare function globMatcher(include: string | null): (path: string) => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a glob matches only paths in the prefix's own folder, never in one
|
|
50
|
+
* under it: a listing of that folder alone holds every file it can match.
|
|
51
|
+
*
|
|
52
|
+
* @param include - The glob, or `null` for every path
|
|
53
|
+
* @returns Whether it names no `/` and no `**`
|
|
54
|
+
*/
|
|
55
|
+
export declare function matchesTopFolderOnly(include: string | null): boolean;
|
|
56
|
+
/** A binding's URL, read: its bucket, and the prefix under it, `''` or ending with `/`. */
|
|
57
|
+
export interface BucketLocation {
|
|
58
|
+
readonly bucket: string;
|
|
59
|
+
readonly prefix: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reads a binding's URL, `s3://bucket/prefix/`.
|
|
63
|
+
*
|
|
64
|
+
* @param url - The URL
|
|
65
|
+
* @returns The bucket and the prefix, or the reason it is not one, completing "'<url>' …"
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseBucketUrl(url: string): BucketLocation | {
|
|
68
|
+
readonly problem: string;
|
|
69
|
+
};
|
|
70
|
+
//# 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;AAsFD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEpE;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,205 @@
|
|
|
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
|
+
/** Why a glob is malformed, completing "include '<include>' …". */
|
|
44
|
+
class GlobError extends Error {
|
|
45
|
+
}
|
|
46
|
+
/** A literal character, as a regular expression matches it. */
|
|
47
|
+
function literal(c) {
|
|
48
|
+
return c.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A `[…]` class at `glob[at.i]`, as a regular expression: one character of a
|
|
52
|
+
* segment, never `/`. `[!…]` and `[^…]` match any character but those named;
|
|
53
|
+
* a `]` first in the class is one of its characters; `a-z` is a range.
|
|
54
|
+
*/
|
|
55
|
+
function characterClass(glob, at) {
|
|
56
|
+
let i = at.i + 1;
|
|
57
|
+
let negate = false;
|
|
58
|
+
if (glob[i] === '!' || glob[i] === '^') {
|
|
59
|
+
negate = true;
|
|
60
|
+
i += 1;
|
|
61
|
+
}
|
|
62
|
+
let body = '';
|
|
63
|
+
for (let first = true;; first = false, i += 1) {
|
|
64
|
+
const c = glob[i];
|
|
65
|
+
if (c === undefined)
|
|
66
|
+
throw new GlobError('has a [ it never closes');
|
|
67
|
+
if (c === ']' && !first)
|
|
68
|
+
break;
|
|
69
|
+
if (c === '/')
|
|
70
|
+
throw new GlobError('has a / in a [...] class, which matches one character within a folder');
|
|
71
|
+
body += c === '\\' || c === ']' || c === '[' || c === '^' ? `\\${c}` : c;
|
|
72
|
+
}
|
|
73
|
+
at.i = i + 1;
|
|
74
|
+
return negate ? `[^/${body}]` : `[${body}]`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A glob's pattern from `glob[at.i]`, as a regular expression, up to its end,
|
|
78
|
+
* or, inside braces, up to the `,` or `}` that ends an alternative.
|
|
79
|
+
*/
|
|
80
|
+
function translate(glob, at, inBraces) {
|
|
81
|
+
let pattern = '';
|
|
82
|
+
while (at.i < glob.length) {
|
|
83
|
+
const c = glob[at.i];
|
|
84
|
+
if (inBraces && (c === ',' || c === '}'))
|
|
85
|
+
return pattern;
|
|
86
|
+
if (c === '*' && glob[at.i + 1] === '*') {
|
|
87
|
+
// `**/` matches zero or more whole folders; a bare `**`, anything
|
|
88
|
+
if (glob[at.i + 2] === '/') {
|
|
89
|
+
pattern += '(?:.*/)?';
|
|
90
|
+
at.i += 3;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
pattern += '.*';
|
|
94
|
+
at.i += 2;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (c === '*') {
|
|
98
|
+
pattern += '[^/]*';
|
|
99
|
+
at.i += 1;
|
|
100
|
+
}
|
|
101
|
+
else if (c === '?') {
|
|
102
|
+
pattern += '[^/]';
|
|
103
|
+
at.i += 1;
|
|
104
|
+
}
|
|
105
|
+
else if (c === '[') {
|
|
106
|
+
pattern += characterClass(glob, at);
|
|
107
|
+
}
|
|
108
|
+
else if (c === '{') {
|
|
109
|
+
at.i += 1;
|
|
110
|
+
const alternatives = [];
|
|
111
|
+
for (;;) {
|
|
112
|
+
alternatives.push(translate(glob, at, true));
|
|
113
|
+
const end = glob[at.i];
|
|
114
|
+
if (end === undefined)
|
|
115
|
+
throw new GlobError('has a { it never closes');
|
|
116
|
+
at.i += 1;
|
|
117
|
+
if (end === '}')
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
pattern += `(?:${alternatives.join('|')})`;
|
|
121
|
+
}
|
|
122
|
+
else if (c === '}') {
|
|
123
|
+
throw new GlobError('has a } with no { before it');
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
pattern += literal(c);
|
|
127
|
+
at.i += 1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return pattern;
|
|
131
|
+
}
|
|
132
|
+
/** A glob, as the regular expression its matcher tests paths with. */
|
|
133
|
+
function globRegex(include) {
|
|
134
|
+
return new RegExp(`^${translate(include, { i: 0 }, false)}$`, 'su');
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Why a glob cannot select files, or `null` when it can.
|
|
138
|
+
*
|
|
139
|
+
* @param include - The glob, over paths relative to the prefix
|
|
140
|
+
* @returns The reason, completing "include '<include>' …"
|
|
141
|
+
*/
|
|
142
|
+
export function includeProblem(include) {
|
|
143
|
+
if (include === '')
|
|
144
|
+
return 'is empty';
|
|
145
|
+
if (include.startsWith('/'))
|
|
146
|
+
return 'begins with /: it matches paths relative to the prefix';
|
|
147
|
+
if (/\*{3,}/.test(include))
|
|
148
|
+
return 'has three or more * in a row';
|
|
149
|
+
try {
|
|
150
|
+
globRegex(include);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
if (err instanceof GlobError)
|
|
154
|
+
return err.message;
|
|
155
|
+
// A class whose range runs backwards (`[z-a]`) is no pattern at all
|
|
156
|
+
return 'has a [...] class no character can match';
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* A glob's matcher over paths relative to a prefix: `*` matches within one
|
|
162
|
+
* folder of the path, `**` across folders, `?` one character but `/`,
|
|
163
|
+
* `[abc]`, `[a-z]` and `[!abc]` one character of a set but `/`, and
|
|
164
|
+
* `{csv,json}` any of its alternatives, each a glob itself. Every other
|
|
165
|
+
* character matches itself. No glob matches every path.
|
|
166
|
+
*
|
|
167
|
+
* @param include - The glob, or `null` for every path
|
|
168
|
+
* @returns Whether a path matches
|
|
169
|
+
* @throws {Error} When the glob is malformed ({@link includeProblem} says how)
|
|
170
|
+
*/
|
|
171
|
+
export function globMatcher(include) {
|
|
172
|
+
if (include === null)
|
|
173
|
+
return () => true;
|
|
174
|
+
const regex = globRegex(include);
|
|
175
|
+
return (path) => regex.test(path);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Whether a glob matches only paths in the prefix's own folder, never in one
|
|
179
|
+
* under it: a listing of that folder alone holds every file it can match.
|
|
180
|
+
*
|
|
181
|
+
* @param include - The glob, or `null` for every path
|
|
182
|
+
* @returns Whether it names no `/` and no `**`
|
|
183
|
+
*/
|
|
184
|
+
export function matchesTopFolderOnly(include) {
|
|
185
|
+
return include !== null && !include.includes('/') && !include.includes('**');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Reads a binding's URL, `s3://bucket/prefix/`.
|
|
189
|
+
*
|
|
190
|
+
* @param url - The URL
|
|
191
|
+
* @returns The bucket and the prefix, or the reason it is not one, completing "'<url>' …"
|
|
192
|
+
*/
|
|
193
|
+
export function parseBucketUrl(url) {
|
|
194
|
+
const match = /^s3:\/\/([^/]+)(?:\/(.*))?$/su.exec(url);
|
|
195
|
+
if (match === null)
|
|
196
|
+
return { problem: 'is not an s3://bucket/prefix/ URL' };
|
|
197
|
+
const bucket = match[1];
|
|
198
|
+
if (!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/u.test(bucket))
|
|
199
|
+
return { problem: `names '${bucket}', which isn't a bucket's name` };
|
|
200
|
+
const prefix = match[2] ?? '';
|
|
201
|
+
if (prefix !== '' && !prefix.endsWith('/'))
|
|
202
|
+
return { problem: "doesn't end with /: a binding names a folder" };
|
|
203
|
+
return { bucket, prefix };
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,UAAU,CAAC;IAClC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,0EAA0E,CAAC;IAC3G,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,sDAAsD,CAAC;IACrF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,6EAA6E,CAAC;IACjH,IAAI,MAAM,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,6CAA6C,CAAC;IACjG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mEAAmE;AACnE,MAAM,SAAU,SAAQ,KAAK;CAAG;AAEhC,+DAA+D;AAC/D,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,EAAiB;IACrD,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QACvC,MAAM,GAAG,IAAI,CAAC;QACd,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,IAAI,KAAK,GAAG,IAAI,GAAI,KAAK,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,SAAS;YAAE,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC,CAAC;QACpE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK;YAAE,MAAM;QAC/B,IAAI,CAAC,KAAK,GAAG;YAAE,MAAM,IAAI,SAAS,CAAC,uEAAuE,CAAC,CAAC;QAC5G,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACb,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,EAAiB,EAAE,QAAiB;IACnE,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,OAAO,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC;QACtB,IAAI,QAAQ,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACxC,kEAAkE;YAClE,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC3B,OAAO,IAAI,UAAU,CAAC;gBACtB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,IAAI,CAAC;gBAChB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACZ,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,IAAI,OAAO,CAAC;YACnB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACZ,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,IAAI,MAAM,CAAC;YAClB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACZ,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,IAAI,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACV,MAAM,YAAY,GAAa,EAAE,CAAC;YAClC,SAAS,CAAC;gBACR,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,GAAG,KAAK,SAAS;oBAAE,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC,CAAC;gBACtE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;gBACV,IAAI,GAAG,KAAK,GAAG;oBAAE,MAAM;YACzB,CAAC;YACD,OAAO,IAAI,MAAM,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAC7C,CAAC;aAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACrB,MAAM,IAAI,SAAS,CAAC,6BAA6B,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;YACtB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sEAAsE;AACtE,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,IAAI,MAAM,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,UAAU,CAAC;IACtC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,wDAAwD,CAAC;IAC7F,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,8BAA8B,CAAC;IAClE,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS;YAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACjD,oEAAoE;QACpE,OAAO,0CAA0C,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,OAAsB;IAChD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IACxC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IACzD,OAAO,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/E,CAAC;AAQD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,+BAA+B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IACzB,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,UAAU,MAAM,gCAAgC,EAAE,CAAC;IAC9H,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,MAAM,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;IAC/G,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
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;
|
|
12
|
+
* of a prefix's own folder alone (a delimiter), when the sync asks. An ETag is
|
|
13
|
+
* kept without the quotes the bucket wraps it in. One file's listing is a
|
|
14
|
+
* listing of its key alone, not a HEAD: a session that may list only under
|
|
15
|
+
* its binding's prefix is answered 403 for a HEAD of a key that isn't there,
|
|
16
|
+
* not 404. Credentials that may read the file but list nothing are asked by
|
|
17
|
+
* a HEAD instead, a 404 its absence. A file is read whole, at the version its listing gave (`If-Match`
|
|
18
|
+
* its ETag): at most 1 GiB for a `file` or `latest` input, 64 MiB for a
|
|
19
|
+
* folder's file. A file changed, archived, gone or closed to the reader since
|
|
20
|
+
* it was listed is refused (`FilesUnreadableError`), the sync going on with
|
|
21
|
+
* the rest; any other refusal is thrown.
|
|
22
|
+
*
|
|
23
|
+
* Needs `@aws-sdk/client-s3`, which a solution's own code never imports: the
|
|
24
|
+
* CLI and the platform do.
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
import { type S3Client } from '@aws-sdk/client-s3';
|
|
29
|
+
import { type FilesReader } from '../sync/engine.js';
|
|
30
|
+
/** Where a binding's files are: a bucket, and the prefix every key is relative to. */
|
|
31
|
+
export interface S3Location {
|
|
32
|
+
readonly bucket: string;
|
|
33
|
+
/** `''`, or ending with `/` */
|
|
34
|
+
readonly prefix: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The reader of one bound source in its bucket.
|
|
38
|
+
*
|
|
39
|
+
* @param client - The client to read with: its credentials and region are the caller's
|
|
40
|
+
* @param location - The bucket, and the prefix the binding names
|
|
41
|
+
* @returns The reader: its keys relative to the prefix
|
|
42
|
+
*/
|
|
43
|
+
export declare function s3FilesReader(client: S3Client, location: S3Location): FilesReader;
|
|
44
|
+
//# 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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAiF,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClI,OAAO,EAA0C,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE7F,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgCD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,WAAW,CAgEjF"}
|