@toa.io/extensions.storages 1.0.0-alpha.34 → 1.0.0-alpha.340
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/package.json +43 -18
- package/readme.md +127 -47
- package/transpiled/Aspect.d.ts +8 -4
- package/transpiled/Aspect.js +12 -14
- package/transpiled/Aspect.js.map +1 -1
- package/transpiled/Entry.d.ts +14 -11
- package/transpiled/Entry.js +1 -2
- package/transpiled/Factory.d.ts +10 -2
- package/transpiled/Factory.js +52 -32
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Provider.d.ts +23 -19
- package/transpiled/Provider.js +18 -32
- package/transpiled/Provider.js.map +1 -1
- package/transpiled/Scanner.d.ts +10 -4
- package/transpiled/Scanner.js +38 -26
- package/transpiled/Scanner.js.map +1 -1
- package/transpiled/Secrets.d.ts +5 -0
- package/transpiled/Secrets.js +2 -0
- package/transpiled/Secrets.js.map +1 -0
- package/transpiled/Storage.d.ts +35 -22
- package/transpiled/Storage.js +95 -141
- package/transpiled/Storage.js.map +1 -1
- package/transpiled/errors.d.ts +15 -0
- package/transpiled/errors.js +12 -0
- package/transpiled/errors.js.map +1 -0
- package/transpiled/index.d.ts +4 -4
- package/transpiled/index.js +1 -9
- package/transpiled/index.js.map +1 -1
- package/transpiled/measurements.d.ts +3 -0
- package/transpiled/measurements.js +23 -0
- package/transpiled/measurements.js.map +1 -0
- package/transpiled/providers/Cloudinary.d.ts +55 -0
- package/transpiled/providers/Cloudinary.js +232 -0
- package/transpiled/providers/Cloudinary.js.map +1 -0
- package/transpiled/providers/Declaration.d.ts +9 -5
- package/transpiled/providers/Declaration.js +1 -2
- package/transpiled/providers/FileSystem.d.ts +16 -11
- package/transpiled/providers/FileSystem.js +64 -43
- package/transpiled/providers/FileSystem.js.map +1 -1
- package/transpiled/providers/S3.d.ts +18 -18
- package/transpiled/providers/S3.js +87 -122
- package/transpiled/providers/S3.js.map +1 -1
- package/transpiled/providers/Spaces.d.ts +12 -0
- package/transpiled/providers/Spaces.js +13 -0
- package/transpiled/providers/Spaces.js.map +1 -0
- package/transpiled/providers/Temporary.d.ts +2 -3
- package/transpiled/providers/Temporary.js +7 -11
- package/transpiled/providers/Temporary.js.map +1 -1
- package/transpiled/providers/Test.d.ts +4 -4
- package/transpiled/providers/Test.js +6 -12
- package/transpiled/providers/Test.js.map +1 -1
- package/transpiled/providers/index.d.ts +23 -11
- package/transpiled/providers/index.js +30 -14
- package/transpiled/providers/index.js.map +1 -1
- package/transpiled/providers/index.types.d.ts +5 -0
- package/transpiled/providers/index.types.js +2 -0
- package/transpiled/providers/index.types.js.map +1 -0
- package/transpiled/test/util.d.ts +113 -6
- package/transpiled/test/util.js +68 -15
- package/transpiled/test/util.js.map +1 -1
- package/schemas/annotation.cos.yaml +0 -10
- package/schemas/fs.cos.yaml +0 -9
- package/schemas/mem.cos.yaml +0 -6
- package/schemas/s3.cos.yaml +0 -16
- package/schemas/test.cos.yaml +0 -8
- package/schemas/tmp.cos.yaml +0 -9
- package/source/Annotation.ts +0 -39
- package/source/Aspect.ts +0 -25
- package/source/Entry.ts +0 -14
- package/source/Factory.ts +0 -68
- package/source/Provider.ts +0 -37
- package/source/Scanner.ts +0 -153
- package/source/Storage.test.ts +0 -472
- package/source/Storage.ts +0 -235
- package/source/deployment.ts +0 -57
- package/source/index.ts +0 -5
- package/source/manifest.ts +0 -8
- package/source/providers/Declaration.ts +0 -10
- package/source/providers/FileSystem.test.ts +0 -5
- package/source/providers/FileSystem.ts +0 -63
- package/source/providers/Memory.ts +0 -55
- package/source/providers/S3.test.ts +0 -134
- package/source/providers/S3.ts +0 -196
- package/source/providers/Temporary.ts +0 -16
- package/source/providers/Test.ts +0 -13
- package/source/providers/index.test.ts +0 -136
- package/source/providers/index.ts +0 -16
- package/source/providers/readme.md +0 -25
- package/source/schemas.test.ts +0 -58
- package/source/schemas.ts +0 -15
- package/source/test/.env.example +0 -1
- package/source/test/albert.jpg +0 -0
- package/source/test/empty.txt +0 -0
- package/source/test/lenna.ascii +0 -64
- package/source/test/lenna.png +0 -0
- package/source/test/sample.avi +0 -0
- package/source/test/sample.avif +0 -0
- package/source/test/sample.gif +0 -0
- package/source/test/sample.heic +0 -0
- package/source/test/sample.jpeg +0 -0
- package/source/test/sample.jxl +0 -0
- package/source/test/sample.svg +0 -4
- package/source/test/sample.wav +0 -0
- package/source/test/sample.webp +0 -0
- package/source/test/util.ts +0 -45
- package/transpiled/Annotation.d.ts +0 -3
- package/transpiled/Annotation.js +0 -57
- package/transpiled/Annotation.js.map +0 -1
- package/transpiled/deployment.d.ts +0 -5
- package/transpiled/deployment.js +0 -68
- package/transpiled/deployment.js.map +0 -1
- package/transpiled/manifest.d.ts +0 -1
- package/transpiled/manifest.js +0 -9
- package/transpiled/manifest.js.map +0 -1
- package/transpiled/providers/Memory.d.ts +0 -15
- package/transpiled/providers/Memory.js +0 -72
- package/transpiled/providers/Memory.js.map +0 -1
- package/transpiled/schemas.d.ts +0 -9
- package/transpiled/schemas.js +0 -14
- package/transpiled/schemas.js.map +0 -1
- package/transpiled/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.json +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.storages",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.340",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Toa Storages",
|
|
5
6
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
7
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -16,27 +17,51 @@
|
|
|
16
17
|
"publishConfig": {
|
|
17
18
|
"access": "public"
|
|
18
19
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
20
|
+
"files": [
|
|
21
|
+
"transpiled",
|
|
22
|
+
"readme.md",
|
|
23
|
+
"!**/tsconfig.tsbuildinfo",
|
|
24
|
+
"!**/*.test.*",
|
|
25
|
+
"!**/.env*"
|
|
26
|
+
],
|
|
23
27
|
"scripts": {
|
|
24
|
-
"test": "
|
|
28
|
+
"test": "echo \"Error: run tests from root\" && exit 1",
|
|
25
29
|
"transpile": "npx tsc"
|
|
26
30
|
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@aws-sdk/client-s3": "3.1156.0",
|
|
33
|
+
"@aws-sdk/lib-storage": "3.1156.0",
|
|
34
|
+
"@aws-sdk/s3-request-presigner": "3.1156.0",
|
|
35
|
+
"cloudinary": "2.11.0",
|
|
36
|
+
"dotenv": "18.0.9"
|
|
37
|
+
},
|
|
27
38
|
"peerDependencies": {
|
|
28
|
-
"
|
|
39
|
+
"@aws-sdk/client-s3": "3.1156.0",
|
|
40
|
+
"@aws-sdk/lib-storage": "3.1156.0",
|
|
41
|
+
"@aws-sdk/s3-request-presigner": "3.1156.0",
|
|
42
|
+
"cloudinary": "2.11.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"@aws-sdk/client-s3": {
|
|
46
|
+
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"@aws-sdk/lib-storage": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"@aws-sdk/s3-request-presigner": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"cloudinary": {
|
|
55
|
+
"optional": true
|
|
56
|
+
}
|
|
29
57
|
},
|
|
30
58
|
"dependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@toa.io/
|
|
34
|
-
"@toa.io/
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"smithy-node-native-fetch": "1.0.6"
|
|
40
|
-
},
|
|
41
|
-
"gitHead": "caf71c04ebd589ff54a25f533b975484aaf9a254"
|
|
59
|
+
"@toa.io/core": "1.0.0-alpha.333",
|
|
60
|
+
"@toa.io/definitions": "1.0.0-alpha.340",
|
|
61
|
+
"@toa.io/generic": "1.0.0-alpha.332",
|
|
62
|
+
"@toa.io/schemas": "1.0.0-alpha.332",
|
|
63
|
+
"negotiator": "1.1.0",
|
|
64
|
+
"openspan": "1.0.0-alpha.330"
|
|
65
|
+
},
|
|
66
|
+
"gitHead": "1871346ef431050d23bd8e91f2b920cea1aeb749"
|
|
42
67
|
}
|
package/readme.md
CHANGED
|
@@ -2,19 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
Shared BLOB storage.
|
|
4
4
|
|
|
5
|
+
## Installing a provider
|
|
6
|
+
|
|
7
|
+
A provider's SDK is not installed with this extension: `s3` and `spaces` need
|
|
8
|
+
`@aws-sdk/client-s3`, `@aws-sdk/lib-storage` and `@aws-sdk/s3-request-presigner`, `cloudinary`
|
|
9
|
+
needs `cloudinary`, and `fs`, `tmp` and `test` need nothing. A deploy installs what the components
|
|
10
|
+
of each composition declare, so an image carries the SDK of a provider it uses and no other, and a
|
|
11
|
+
process makes the storages its components declare — every one, for a component that names none.
|
|
12
|
+
|
|
13
|
+
A workspace installs the same set itself, once, and again when a storage is added:
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
$ toa npm -p application
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Without it a composition fails to start, naming the package and version it wants.
|
|
20
|
+
|
|
5
21
|
## Entry
|
|
6
22
|
|
|
7
23
|
BLOBs are stored with the meta-information object (Entry) having the following properties:
|
|
8
24
|
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
12
|
-
- `created
|
|
13
|
-
- `
|
|
14
|
-
- `name` - unique name
|
|
15
|
-
- `size` - size in bytes
|
|
16
|
-
- `type` - variant MIME type
|
|
17
|
-
- `meta` - object with application-specific information, empty by default
|
|
25
|
+
- `size`: size in bytes
|
|
26
|
+
- `type`: MIME type
|
|
27
|
+
- `checksum`: content checksum
|
|
28
|
+
- `created`: creation timestamp (ISO 8601)
|
|
29
|
+
- `attributes`: `Record<string, string>` with application-specific information, empty by default
|
|
18
30
|
|
|
19
31
|
### Example
|
|
20
32
|
|
|
@@ -22,12 +34,7 @@ BLOBs are stored with the meta-information object (Entry) having the following p
|
|
|
22
34
|
id: eecd837c
|
|
23
35
|
type: image/jpeg
|
|
24
36
|
created: 1698004822358
|
|
25
|
-
|
|
26
|
-
- name: thumbnail.jpeg
|
|
27
|
-
type: image/jpeg
|
|
28
|
-
- name: thumbnail.webp
|
|
29
|
-
type: image/webp
|
|
30
|
-
meta:
|
|
37
|
+
attributes:
|
|
31
38
|
face: true
|
|
32
39
|
nudity: false
|
|
33
40
|
```
|
|
@@ -38,8 +45,8 @@ The Storages extension provides `storages` aspect,
|
|
|
38
45
|
containing named Storage instances, according to the annotation.
|
|
39
46
|
|
|
40
47
|
```javascript
|
|
41
|
-
async function effect
|
|
42
|
-
await context.storages.photos.
|
|
48
|
+
async function effect(_, context) {
|
|
49
|
+
await context.storages.photos.get('/path/to/b4f577e0.thumbnail.jpeg')
|
|
43
50
|
}
|
|
44
51
|
```
|
|
45
52
|
|
|
@@ -47,13 +54,15 @@ async function effect (_, context) {
|
|
|
47
54
|
|
|
48
55
|
> `Maybe<T> = T | Error`
|
|
49
56
|
|
|
57
|
+
An error has a `code`, and an operation that returns it refuses with that code.
|
|
58
|
+
|
|
50
59
|
#### `async put(path: string, stream: Readable, options?: Options): Maybe<Entry>`
|
|
51
60
|
|
|
52
|
-
```
|
|
61
|
+
```ts
|
|
53
62
|
interface Options {
|
|
54
63
|
claim?: string
|
|
55
64
|
accept?: string
|
|
56
|
-
|
|
65
|
+
attributes?: Record<string, string>
|
|
57
66
|
}
|
|
58
67
|
```
|
|
59
68
|
|
|
@@ -75,13 +84,13 @@ are: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `image/heic`, `image/
|
|
|
75
84
|
|
|
76
85
|
See [source](source/Scanner.ts).
|
|
77
86
|
|
|
78
|
-
#### `async
|
|
87
|
+
#### `async head(path: string): Maybe<Entry>`
|
|
79
88
|
|
|
80
89
|
Get an entry.
|
|
81
90
|
|
|
82
91
|
If the entry does not exist, a `NOT_FOUND` error is returned.
|
|
83
92
|
|
|
84
|
-
#### `async
|
|
93
|
+
#### `async get(path: string): Maybe<Readable>`
|
|
85
94
|
|
|
86
95
|
Fetch the BLOB specified by `path`. If the path does not exist, a `NOT_FOUND` error is returned.
|
|
87
96
|
|
|
@@ -91,6 +100,15 @@ Fetch the BLOB specified by `path`. If the path does not exist, a `NOT_FOUND` er
|
|
|
91
100
|
- `/path/to/eecd837c` - fetch the BLOB by path
|
|
92
101
|
- `/path/to/eecd837c.thumbnail.jpeg` - fetch the `thumbnail.jpeg` variant of the BLOB
|
|
93
102
|
|
|
103
|
+
#### `async url(path: string, options?: { expires?: number }): Maybe<string>`
|
|
104
|
+
|
|
105
|
+
Where the file is read straight from the provider, by whoever is given the address and with no
|
|
106
|
+
credentials of their own. `s3` and `spaces` sign it for `expires` seconds — an hour by default, a
|
|
107
|
+
week at most — and serve the file as the type it was stored as; `cloudinary` gives where it
|
|
108
|
+
delivers the file, or a variant of it by extension, unsigned and without asking whether the file
|
|
109
|
+
is there. `NOT_FOUND` is a file an `s3` or `spaces` storage does not have; `NO_URL` is a storage
|
|
110
|
+
that serves no address of its own: `fs`, `tmp` and `test`.
|
|
111
|
+
|
|
94
112
|
#### `async delete(path: string): Maybe<void>`
|
|
95
113
|
|
|
96
114
|
Delete the entry specified by `path`.
|
|
@@ -110,18 +128,6 @@ await storage.move('/path/to/eecd837c', './sub/eecd837c')
|
|
|
110
128
|
await storage.move('/path/to/eecd837c', './sub/')
|
|
111
129
|
```
|
|
112
130
|
|
|
113
|
-
#### `async entries(path: string): Entry[]`
|
|
114
|
-
|
|
115
|
-
Get a list of entries under the `path`.
|
|
116
|
-
|
|
117
|
-
#### `async diversify(path: string, name: string, stream: Readable): Maybe<void>`
|
|
118
|
-
|
|
119
|
-
Add or replace a `name` variant of the entry specified by `path`.
|
|
120
|
-
|
|
121
|
-
#### `async annotate(path: string, key: string, value: any): Maybe<void>`
|
|
122
|
-
|
|
123
|
-
Set a `key` property in the `meta` of the entry specified by `path`.
|
|
124
|
-
|
|
125
131
|
## Providers
|
|
126
132
|
|
|
127
133
|
Storage uses underlying providers to store BLOBs and entries.
|
|
@@ -152,40 +158,114 @@ and [`toa env`](/runtime/cli/readme.md#env)
|
|
|
152
158
|
for local environment.
|
|
153
159
|
`endpoint` parameter is optional.
|
|
154
160
|
|
|
155
|
-
###
|
|
161
|
+
### DigitalOcean Spaces
|
|
156
162
|
|
|
157
163
|
Annotation format is:
|
|
158
164
|
|
|
159
165
|
```yaml
|
|
160
166
|
storages:
|
|
161
|
-
photos
|
|
162
|
-
provider:
|
|
163
|
-
|
|
167
|
+
photos:
|
|
168
|
+
provider: spaces
|
|
169
|
+
space: my-space
|
|
170
|
+
region: fra1
|
|
164
171
|
```
|
|
165
172
|
|
|
166
|
-
|
|
173
|
+
`region` is the datacenter slug, the endpoint is derived from it.
|
|
167
174
|
|
|
168
|
-
|
|
175
|
+
Secrets `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY` are required.
|
|
176
|
+
Keys are created in the DigitalOcean control panel,
|
|
177
|
+
under Spaces Object Storage, on the Access Keys tab.
|
|
178
|
+
|
|
179
|
+
### Cloudinary
|
|
180
|
+
|
|
181
|
+
[Cloudinary](https://cloudinary.com) provider is used to store and transform media files.
|
|
182
|
+
|
|
183
|
+
Objects stored in the Cloudinary storage can be requested with transformations,
|
|
184
|
+
using dot-separated path extensions: `/path/to/eecd837c.{extension}.{extension}`.
|
|
185
|
+
|
|
186
|
+
Transformation is defined by the `extension` property, which is a regular expression with named
|
|
187
|
+
groups.
|
|
188
|
+
The named groups are used to replace the placeholders in the `transform` object.
|
|
189
|
+
|
|
190
|
+
`transform` object is an element of
|
|
191
|
+
the [Cloudinary `transformation` array](https://cloudinary.com/documentation/node_image_manipulation#apply_common_image_transformations).
|
|
192
|
+
|
|
193
|
+
> - `zoom` should be specified as integer [0–100].
|
|
194
|
+
> - `format` value `jpeg` is converted to `jpg`.
|
|
195
|
+
> - `^` and `$` are added to the regular expression automatically, unless they are already present.
|
|
169
196
|
|
|
170
197
|
Annotation format is:
|
|
171
198
|
|
|
172
199
|
```yaml
|
|
173
200
|
storages:
|
|
174
|
-
|
|
175
|
-
provider:
|
|
176
|
-
|
|
201
|
+
media:
|
|
202
|
+
provider: cloudinary
|
|
203
|
+
environment: my-cloud
|
|
204
|
+
type: image # image or video
|
|
205
|
+
prefix: my-app
|
|
206
|
+
transformations:
|
|
207
|
+
- extension: (?<width>\d*)x(?<height>\d*)(z(?<zoom>\d*))?
|
|
208
|
+
transformation:
|
|
209
|
+
width: <width>
|
|
210
|
+
height: <height>
|
|
211
|
+
zoom: <zoom>
|
|
212
|
+
crop: thumb
|
|
213
|
+
gravity: face
|
|
214
|
+
optional: true
|
|
215
|
+
- extension: (?<format>jpeg|webp)
|
|
216
|
+
transformation:
|
|
217
|
+
fetch_format: <format>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Path extensions must be specified in the same order as in the annotation.
|
|
221
|
+
|
|
222
|
+
For the example above:
|
|
223
|
+
|
|
224
|
+
- `/path/to/eecd837c.100x100.jpeg`: matches
|
|
225
|
+
- `/path/to/eecd837c.jpeg.100x100`: does not match
|
|
226
|
+
|
|
227
|
+
If a path extension is not matched,
|
|
228
|
+
or if at least one of the transformations is not matched (unless it is `optional`),
|
|
229
|
+
then an error is returned.
|
|
230
|
+
|
|
231
|
+
Secrets:
|
|
232
|
+
|
|
233
|
+
- `API_KEY`
|
|
234
|
+
- `API_SECRET`
|
|
235
|
+
|
|
236
|
+
### Filesystem
|
|
237
|
+
|
|
238
|
+
Annotation format is:
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
storages:
|
|
242
|
+
photos:
|
|
243
|
+
provider: fs
|
|
244
|
+
path: /var/my-photos
|
|
177
245
|
```
|
|
178
246
|
|
|
179
|
-
|
|
247
|
+
[Kubernetes PVC](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) can be mounted to
|
|
248
|
+
the storage:
|
|
180
249
|
|
|
181
|
-
|
|
250
|
+
```yaml
|
|
251
|
+
storages:
|
|
252
|
+
photos:
|
|
253
|
+
provider: fs
|
|
254
|
+
path: /var/my-photos
|
|
255
|
+
claim: photos-pvc
|
|
256
|
+
```
|
|
182
257
|
|
|
183
|
-
|
|
258
|
+
### Temporary
|
|
259
|
+
|
|
260
|
+
Filesystem using OS temporary directory.
|
|
261
|
+
|
|
262
|
+
Annotation format is:
|
|
184
263
|
|
|
185
264
|
```yaml
|
|
186
265
|
storages:
|
|
187
266
|
photos@dev:
|
|
188
|
-
provider:
|
|
267
|
+
provider: tmp
|
|
268
|
+
directory: my-app-tmp
|
|
189
269
|
```
|
|
190
270
|
|
|
191
271
|
## Deduplication
|
|
@@ -196,7 +276,7 @@ Variants, on the other hand, are not deduplicated across different entries.
|
|
|
196
276
|
|
|
197
277
|
Underlying directory structure:
|
|
198
278
|
|
|
199
|
-
```
|
|
279
|
+
```text
|
|
200
280
|
/temp
|
|
201
281
|
c28f4dfd # random id
|
|
202
282
|
/blobs
|
package/transpiled/Aspect.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { Connector
|
|
2
|
-
import
|
|
1
|
+
import { Connector } from '@toa.io/core';
|
|
2
|
+
import type { extensions } from '@toa.io/core/types';
|
|
3
|
+
import { type Storage, type Storages } from './Storage.ts';
|
|
3
4
|
export declare class Aspect extends Connector implements extensions.Aspect {
|
|
4
5
|
readonly name = "storages";
|
|
5
|
-
private readonly
|
|
6
|
-
|
|
6
|
+
private readonly create;
|
|
7
|
+
private storages;
|
|
8
|
+
/** The storages are made as the aspect connects: their providers load then, not before. */
|
|
9
|
+
constructor(create: () => Promise<Storages>);
|
|
10
|
+
protected open(): Promise<void>;
|
|
7
11
|
invoke(name: string, method: keyof Storage, ...args: unknown[]): unknown;
|
|
8
12
|
}
|
package/transpiled/Aspect.js
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Aspect = void 0;
|
|
7
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
8
|
-
const core_1 = require("@toa.io/core");
|
|
9
|
-
class Aspect extends core_1.Connector {
|
|
1
|
+
import { Connector } from '@toa.io/core';
|
|
2
|
+
export class Aspect extends Connector {
|
|
10
3
|
name = 'storages';
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
create;
|
|
5
|
+
storages = {};
|
|
6
|
+
/** The storages are made as the aspect connects: their providers load then, not before. */
|
|
7
|
+
constructor(create) {
|
|
13
8
|
super();
|
|
14
|
-
this.
|
|
9
|
+
this.create = create;
|
|
10
|
+
}
|
|
11
|
+
async open() {
|
|
12
|
+
this.storages = await this.create();
|
|
15
13
|
}
|
|
16
14
|
invoke(name, method, ...args) {
|
|
17
15
|
const storage = this.storages[name];
|
|
18
|
-
|
|
16
|
+
if (storage === undefined)
|
|
17
|
+
throw new Error(`Storage '${name}' is not defined`);
|
|
19
18
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
20
19
|
// @ts-expect-error
|
|
21
20
|
return storage[method](...args);
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
|
-
exports.Aspect = Aspect;
|
|
25
23
|
//# sourceMappingURL=Aspect.js.map
|
package/transpiled/Aspect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Aspect.js","sourceRoot":"","sources":["../source/Aspect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Aspect.js","sourceRoot":"","sources":["../source/Aspect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAIxC,MAAM,OAAO,MAAO,SAAQ,SAAS;IACnB,IAAI,GAAG,UAAU,CAAA;IAEhB,MAAM,CAAyB;IACxC,QAAQ,GAAa,EAAE,CAAA;IAE/B,2FAA2F;IAC3F,YAAmB,MAA+B;QAChD,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAEkB,KAAK,CAAC,IAAI;QAC3B,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;IACrC,CAAC;IAEM,MAAM,CAAC,IAAY,EAAE,MAAqB,EAAE,GAAG,IAAe;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAEnC,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,kBAAkB,CAAC,CAAA;QAE9E,6DAA6D;QAC7D,mBAAmB;QACnB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACjC,CAAC;CACF"}
|
package/transpiled/Entry.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
export type Entry = {
|
|
2
3
|
id: string;
|
|
3
|
-
|
|
4
|
+
} & Metadata;
|
|
5
|
+
export type Stream = {
|
|
6
|
+
stream: Readable;
|
|
7
|
+
} & Metadata;
|
|
8
|
+
export interface Metadata {
|
|
4
9
|
type: string;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
size: number | null;
|
|
11
|
+
checksum: string;
|
|
12
|
+
created: string;
|
|
13
|
+
attributes: Attributes;
|
|
14
|
+
range?: string;
|
|
15
|
+
partial?: boolean;
|
|
8
16
|
}
|
|
9
|
-
|
|
10
|
-
name: string;
|
|
11
|
-
size: number;
|
|
12
|
-
type: string;
|
|
13
|
-
}
|
|
14
|
-
export {};
|
|
17
|
+
export type Attributes = Record<string, string>;
|
package/transpiled/Entry.js
CHANGED
package/transpiled/Factory.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import { Aspect } from './Aspect';
|
|
1
|
+
import { Aspect } from './Aspect.ts';
|
|
2
2
|
export declare class Factory {
|
|
3
3
|
private readonly annotation;
|
|
4
|
+
/** The storages made so far, by name: one for the process, whichever component declares it. */
|
|
5
|
+
private readonly made;
|
|
4
6
|
constructor();
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The storages of a component: those it declares, and every storage there is where it names
|
|
9
|
+
* none (`storages: ~`). A deploy installs the SDKs of the providers a composition's components
|
|
10
|
+
* declare and no other, so a storage nobody in the process declares is not made: its provider
|
|
11
|
+
* may not be there.
|
|
12
|
+
*/
|
|
13
|
+
aspect(_: unknown, declaration?: string[] | null): Aspect;
|
|
6
14
|
private createStorages;
|
|
7
15
|
private createStorage;
|
|
8
16
|
private resolveSecrets;
|
package/transpiled/Factory.js
CHANGED
|
@@ -1,53 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const generic_1 = require("@toa.io/generic");
|
|
9
|
-
const providers_1 = require("./providers");
|
|
10
|
-
const Storage_1 = require("./Storage");
|
|
11
|
-
const Aspect_1 = require("./Aspect");
|
|
12
|
-
const deployment_1 = require("./deployment");
|
|
13
|
-
const Annotation_1 = require("./Annotation");
|
|
14
|
-
class Factory {
|
|
1
|
+
import { console } from 'openspan';
|
|
2
|
+
import { provider as load } from './providers/index.js';
|
|
3
|
+
import { Storage } from './Storage.js';
|
|
4
|
+
import { Aspect } from './Aspect.js';
|
|
5
|
+
import { ENV_PREFIX, validateAnnotation } from '@toa.io/definitions/extensions.storages';
|
|
6
|
+
import { environment } from '@toa.io/generic';
|
|
7
|
+
export class Factory {
|
|
15
8
|
annotation;
|
|
9
|
+
/** The storages made so far, by name: one for the process, whichever component declares it. */
|
|
10
|
+
made = new Map();
|
|
16
11
|
constructor() {
|
|
17
|
-
const env =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
const env = environment.get(ENV_PREFIX);
|
|
13
|
+
if (env === undefined)
|
|
14
|
+
throw new Error(`${ENV_PREFIX} is not defined`);
|
|
15
|
+
this.annotation = JSON.parse(env);
|
|
16
|
+
validateAnnotation(this.annotation);
|
|
21
17
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The storages of a component: those it declares, and every storage there is where it names
|
|
20
|
+
* none (`storages: ~`). A deploy installs the SDKs of the providers a composition's components
|
|
21
|
+
* declare and no other, so a storage nobody in the process declares is not made: its provider
|
|
22
|
+
* may not be there.
|
|
23
|
+
*/
|
|
24
|
+
aspect(_, declaration) {
|
|
25
|
+
const names = declaration === undefined || declaration === null || declaration.length === 0
|
|
26
|
+
? Object.keys(this.annotation)
|
|
27
|
+
: declaration;
|
|
28
|
+
return new Aspect(() => this.createStorages(names));
|
|
25
29
|
}
|
|
26
|
-
createStorages() {
|
|
30
|
+
async createStorages(names) {
|
|
27
31
|
const storages = {};
|
|
28
|
-
for (const
|
|
29
|
-
|
|
32
|
+
for (const name of names) {
|
|
33
|
+
const declaration = this.annotation[name];
|
|
34
|
+
// one the annotation does not declare is refused as it is used (`Aspect.invoke`)
|
|
35
|
+
if (declaration === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
let storage = this.made.get(name);
|
|
38
|
+
if (storage === undefined) {
|
|
39
|
+
// the annotation is validated above, so a declaration is its provider's
|
|
40
|
+
storage = this.createStorage(name, declaration);
|
|
41
|
+
this.made.set(name, storage);
|
|
42
|
+
}
|
|
43
|
+
storages[name] = await storage;
|
|
44
|
+
}
|
|
30
45
|
return storages;
|
|
31
46
|
}
|
|
32
|
-
createStorage(name, declaration) {
|
|
33
|
-
const { provider:
|
|
34
|
-
const Provider =
|
|
47
|
+
async createStorage(name, declaration) {
|
|
48
|
+
const { provider: id, ...options } = declaration;
|
|
49
|
+
const Provider = await load(id);
|
|
35
50
|
const secrets = this.resolveSecrets(name, Provider);
|
|
36
51
|
const provider = new Provider(options, secrets);
|
|
37
|
-
|
|
52
|
+
console.debug('Storage created', {
|
|
53
|
+
name,
|
|
54
|
+
provider: id,
|
|
55
|
+
...(provider.root === undefined ? undefined : { root: provider.root })
|
|
56
|
+
});
|
|
57
|
+
return new Storage(provider, { name, provider: id });
|
|
38
58
|
}
|
|
39
59
|
resolveSecrets(storageName, Class) {
|
|
40
60
|
if (Class.SECRETS === undefined)
|
|
41
61
|
return {};
|
|
42
62
|
const secrets = {};
|
|
43
63
|
for (const secret of Class.SECRETS) {
|
|
44
|
-
const variable = `${
|
|
45
|
-
const value =
|
|
46
|
-
|
|
64
|
+
const variable = `${ENV_PREFIX}_${storageName}_${secret.name}`.toUpperCase();
|
|
65
|
+
const value = environment.get(variable);
|
|
66
|
+
if (secret.optional !== true && value === undefined)
|
|
67
|
+
throw new Error(`'${variable}' is not defined`);
|
|
47
68
|
secrets[secret.name] = value;
|
|
48
69
|
}
|
|
49
70
|
return secrets;
|
|
50
71
|
}
|
|
51
72
|
}
|
|
52
|
-
exports.Factory = Factory;
|
|
53
73
|
//# sourceMappingURL=Factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Factory.js","sourceRoot":"","sources":["../source/Factory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Factory.js","sourceRoot":"","sources":["../source/Factory.ts"],"names":[],"mappings":"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"}
|
package/transpiled/Provider.d.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readonly
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
abstract
|
|
12
|
-
abstract
|
|
13
|
-
abstract
|
|
1
|
+
import type { Metadata, Stream } from './Entry.ts';
|
|
2
|
+
import type { Readable } from 'node:stream';
|
|
3
|
+
import type { Maybe } from '@toa.io/core/types';
|
|
4
|
+
import type { Secret, Secrets } from './Secrets.ts';
|
|
5
|
+
export declare abstract class Provider<Options = unknown> {
|
|
6
|
+
static readonly SECRETS?: readonly Secret[];
|
|
7
|
+
readonly root?: string;
|
|
8
|
+
readonly options: Options;
|
|
9
|
+
protected constructor(options: Options, secrets?: Secrets);
|
|
10
|
+
abstract get(path: string, options?: unknown): Promise<Maybe<Stream>>;
|
|
11
|
+
abstract head(path: string): Promise<Maybe<Metadata>>;
|
|
12
|
+
abstract put(path: string, stream: Readable): Promise<void>;
|
|
13
|
+
abstract commit(path: string, metadata: Metadata): Promise<void>;
|
|
14
14
|
abstract delete(path: string): Promise<void>;
|
|
15
|
-
abstract move(from: string, to: string): Promise<void
|
|
16
|
-
|
|
15
|
+
abstract move(from: string, to: string): Promise<Maybe<void>>;
|
|
16
|
+
/**
|
|
17
|
+
* Where whoever is given it reads the file straight from the provider, with no credentials of
|
|
18
|
+
* their own, for `expires` seconds where the address is signed. A provider that serves no
|
|
19
|
+
* address of its own answers `NO_URL`.
|
|
20
|
+
*/
|
|
21
|
+
url(_path: string, _expires: number): Promise<Maybe<string>>;
|
|
17
22
|
}
|
|
18
|
-
export interface
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
new (options: any, secrets?: ProviderSecrets): Provider;
|
|
23
|
+
export interface Constructor<Options = any> {
|
|
24
|
+
SECRETS?: readonly Secret[];
|
|
25
|
+
new (options: Options, secrets?: Secrets): Provider<Options>;
|
|
22
26
|
}
|