@filelayer/core 0.3.0 → 0.4.1
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/CHANGELOG.md +196 -3
- package/NOTICE +11 -8
- package/README.md +30 -5
- package/dist/db.d.ts +4 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +86 -2
- package/dist/db.js.map +1 -1
- package/package.json +8 -2
- package/src/db.ts +93 -2
- package/test/s3-live.test.ts +17 -29
package/CHANGELOG.md
CHANGED
|
@@ -21,9 +21,74 @@ embarrassing. A changelog that only records features is a marketing document.
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## [Unreleased]
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
## [Unreleased]
|
|
25
|
+
|
|
26
|
+
Two things: **packaging** — the published tarball now has no runtime
|
|
27
|
+
dependencies at all — and **group grant subjects** (RFC-001), a breaking schema
|
|
28
|
+
change with an additive API whose migration is `MIGRATIONS.md` Entry 2.
|
|
29
|
+
|
|
30
|
+
### Changed — packaging
|
|
31
|
+
|
|
32
|
+
- **`@electric-sql/pglite` is no longer a runtime dependency.** It was the only
|
|
33
|
+
one, and it should never have been one: it is an embedded WebAssembly
|
|
34
|
+
PostgreSQL, and a library whose entire premise is "run it against your own
|
|
35
|
+
Postgres" has no business putting a second Postgres into every production
|
|
36
|
+
`node_modules`. It is used by exactly two functions — `createTestDb()` and the
|
|
37
|
+
`Filelayer.quickstart()` built on it — and both are development helpers.
|
|
38
|
+
- It is now a **`devDependency`** (the suite needs it) *and* an **optional
|
|
39
|
+
peer dependency** (`peerDependenciesMeta.optional: true`). A consumer who
|
|
40
|
+
wants `createTestDb()` is told what to install and at which version range; a
|
|
41
|
+
consumer who does not gets no install warning and no WASM blob.
|
|
42
|
+
- **Installing `@filelayer/core` now installs one package.** Asserted from
|
|
43
|
+
inside the installed copy by the release gate and by the packaging job, so
|
|
44
|
+
a runtime dependency cannot be reintroduced without a red build.
|
|
45
|
+
- **Nothing about the public API changed.** `createTestDb`, `SCHEMA_PATH` and
|
|
46
|
+
`loadSchemaSql` are exported exactly as before, and production code — a
|
|
47
|
+
`pg.Pool` (or anything satisfying `Queryable`) passed to `new Filelayer()` —
|
|
48
|
+
never touches the removed dependency. If you use `quickstart()` or
|
|
49
|
+
`createTestDb()`, add
|
|
50
|
+
`npm install --save-dev "@electric-sql/pglite@^0.3.11"`.
|
|
51
|
+
- **`createTestDb()` without PGlite installed now explains itself.** It used to
|
|
52
|
+
surface Node's raw `ERR_MODULE_NOT_FOUND` from inside `dist/`, naming a
|
|
53
|
+
package the caller never asked for. It now throws an error that names
|
|
54
|
+
`@electric-sql/pglite`, gives the exact install command, says why the package
|
|
55
|
+
is optional, and points at the production alternative (`pg.Pool` plus
|
|
56
|
+
`psql -f node_modules/@filelayer/core/schema.sql`). The original resolution
|
|
57
|
+
error is preserved as `cause`. A resolution failure *inside* PGlite — a broken
|
|
58
|
+
install rather than a missing one — is passed through untouched.
|
|
59
|
+
- **The release gate now runs the whole lifecycle twice, in both shapes.** Once
|
|
60
|
+
in the shape a production consumer installs — the packed tarball and nothing
|
|
61
|
+
else, no embedded database on disk, driven against a real PostgreSQL server
|
|
62
|
+
through `pg` — and once through `Filelayer.quickstart()` after explicitly
|
|
63
|
+
installing the optional peer dependency. The assertions are written once and
|
|
64
|
+
run in both. It also asserts that a missing optional peer produces no install
|
|
65
|
+
warning, and that `createTestDb()`'s error names the package and the command.
|
|
66
|
+
|
|
67
|
+
### Added — testing
|
|
68
|
+
|
|
69
|
+
- **The live S3/R2 suite now runs in CI.** `test/s3-live.test.ts` has always
|
|
70
|
+
skipped itself without credentials; it now has a job that runs it when the
|
|
71
|
+
repository secrets are present. This is the code path every download goes
|
|
72
|
+
through, and a local harness that verifies signatures cannot speak for TLS,
|
|
73
|
+
real IAM evaluation, R2's divergences from S3, read-after-write visibility or
|
|
74
|
+
the error codes a real store returns.
|
|
75
|
+
- **A fork does not go red.** Secrets are unavailable to pull requests from
|
|
76
|
+
forks, so the job decides for itself whether it has credentials and skips
|
|
77
|
+
the work if not.
|
|
78
|
+
- **The skip is visible.** It is written to the job summary and raised as a
|
|
79
|
+
workflow notice, naming the missing secrets. A green tick that ran nothing
|
|
80
|
+
is worse than an honest "skipped: no credentials", because the two look
|
|
81
|
+
identical. The converse is checked too: credentials present and the suite
|
|
82
|
+
skipping itself anyway is a **failure**, not a pass.
|
|
83
|
+
- **`docs/LIVE-S3-TESTS.md`** is the single place the bucket, the minimal R2
|
|
84
|
+
token / IAM policy and the exact secret names are specified. The test file
|
|
85
|
+
header used to restate them and now points at it.
|
|
86
|
+
- The multipart test (~11 MB of uploads) runs on a nightly schedule and on
|
|
87
|
+
manual dispatch, rather than on every push.
|
|
88
|
+
- Fixed while wiring the above: an *empty* `FILELAYER_TEST_S3_PREFIX` — what a
|
|
89
|
+
workflow hands you for an unset repository variable — was taken as a real
|
|
90
|
+
value by `??`, rooting every test key at `/` instead of under the prefix the
|
|
91
|
+
cleanup deletes.
|
|
27
92
|
|
|
28
93
|
### Fixed
|
|
29
94
|
|
|
@@ -103,6 +168,134 @@ Breaking schema change, additive API. Migration: `MIGRATIONS.md` Entry 2.
|
|
|
103
168
|
|
|
104
169
|
---
|
|
105
170
|
|
|
171
|
+
## [0.4.1] — 2026-09-06
|
|
172
|
+
|
|
173
|
+
A single defect, in the first command a new user runs. Nothing else changed: no
|
|
174
|
+
API change, no schema change, no behaviour change. If you already have a working
|
|
175
|
+
install, this release does nothing for you.
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
|
|
179
|
+
- **The documented command for installing PGlite could not resolve against the
|
|
180
|
+
peer range this package declares.** `0.4.0` declares
|
|
181
|
+
`peerDependencies: { "@electric-sql/pglite": "^0.3.11" }`, as an optional peer.
|
|
182
|
+
The install command in the `createTestDb()` error message, in `README.md`, in
|
|
183
|
+
`docs/QUICKSTART.md`, in `llms.txt` and in the changelog entry above carried no
|
|
184
|
+
version at all. PGlite's `latest` on npm is `0.5.8`, outside `^0.3.11`, so
|
|
185
|
+
following our own written instructions could put a version on disk that the
|
|
186
|
+
declared range does not admit — and npm then refuses the whole tree:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
npm error Could not resolve dependency:
|
|
190
|
+
npm error peerOptional @electric-sql/pglite@"^0.3.11" from @filelayer/core@0.4.0
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
It is deterministic for anyone whose project already has PGlite, or who asks
|
|
194
|
+
for a specific version, and it is a hard stop about sixty seconds in. Every
|
|
195
|
+
install command in this repository is now version-explicit:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm install --save-dev "@electric-sql/pglite@^0.3.11"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The quotes are for the shell, not for npm — `^` is a glob operator under `zsh`
|
|
202
|
+
with `extendedglob` and an escape character in `cmd.exe`, and a command that
|
|
203
|
+
breaks in a common shell is the same defect wearing a different hat.
|
|
204
|
+
|
|
205
|
+
### Not changed, deliberately
|
|
206
|
+
|
|
207
|
+
- **The peer range is still `^0.3.11`. PGlite 0.5.x is not supported.** Before
|
|
208
|
+
choosing between widening the range and fixing the instructions, the full
|
|
209
|
+
suite was run against `0.5.8`. It does not pass. `tsc --noEmit` is clean and
|
|
210
|
+
every assertion that executes passes, but seven test files are killed by the
|
|
211
|
+
operating system and the run aborts after 92 of 313 tests. Reproduced in
|
|
212
|
+
isolation with 3.6 GB free, so it is not a plain out-of-memory: one suite runs
|
|
213
|
+
20 of 21 subtests green and is then killed. Against `0.3.16` the identical
|
|
214
|
+
suite is 313 of 313.
|
|
215
|
+
|
|
216
|
+
We have not diagnosed it further, because the supported range is the decision
|
|
217
|
+
in front of us and the cause is upstream. What we will not do is widen the
|
|
218
|
+
range to whatever npm installs by default and describe an untested
|
|
219
|
+
configuration as supported. When 0.5.x passes, the range moves and this entry
|
|
220
|
+
gets a successor.
|
|
221
|
+
|
|
222
|
+
### Added
|
|
223
|
+
|
|
224
|
+
- **`tools/check-install-commands.mjs`, wired into `npm run verify`.** It reads
|
|
225
|
+
every tracked file and fails the build if an install command names a
|
|
226
|
+
version-constrained package without a version constraint, or pins one to a
|
|
227
|
+
range that is not the range `packages/core/package.json` declares. The
|
|
228
|
+
comparison is semver intervals rather than string equality and runs in both
|
|
229
|
+
directions, so widening the peer range without updating the documentation
|
|
230
|
+
fails, and so does the reverse. No network and no install: it is a check on
|
|
231
|
+
what we wrote, evaluated against what we declared.
|
|
232
|
+
|
|
233
|
+
It carries a negative control that runs on every invocation, before the real
|
|
234
|
+
scan: fourteen commands whose correct classification is known — including the
|
|
235
|
+
exact unversioned command `0.4.0` shipped, in each of the five forms it was
|
|
236
|
+
written in — plus seven pieces of text that must *not* be read as install
|
|
237
|
+
commands. If the detector misclassifies any of them the check exits `2` and
|
|
238
|
+
says the detector is broken rather than reporting a clean repository. A
|
|
239
|
+
checker that has never rejected anything is a green tick of unknown value.
|
|
240
|
+
|
|
241
|
+
### Changed
|
|
242
|
+
|
|
243
|
+
- **The release gate now runs the documented command instead of its own.**
|
|
244
|
+
`tools/verify-release.mjs` reads the install command out of `README.md` at run
|
|
245
|
+
time and executes that string in its empty consumer directory. It used to
|
|
246
|
+
write its own equivalent, which is why a green gate and a broken instruction
|
|
247
|
+
could coexist for a whole release: the gate was testing a command no user
|
|
248
|
+
would ever type.
|
|
249
|
+
- **The gate also installs in the other order.** Phases 1 and 2 install the
|
|
250
|
+
package first and PGlite second, and in that order npm can rescue a bad
|
|
251
|
+
instruction by quietly walking `latest` back into the peer range — which is
|
|
252
|
+
precisely how `0.4.0`'s command passed. A new phase does it the other way
|
|
253
|
+
round, in a second directory that has never contained anything: the documented
|
|
254
|
+
command first, then `@filelayer/core` on top. There is nothing left to rescue
|
|
255
|
+
there, so the resolution failure is either real or absent. It asserts, too,
|
|
256
|
+
that the version actually installed satisfies the declared range, because an
|
|
257
|
+
install that succeeds by giving the reader something other than what they
|
|
258
|
+
asked for is still a broken instruction.
|
|
259
|
+
- `README.md`, `docs/QUICKSTART.md` and the `createTestDb()` error message now
|
|
260
|
+
state the supported range in words as well as in the command: the 0.3.x line
|
|
261
|
+
is supported, 0.5.x is not, and the reason is that the suite does not pass
|
|
262
|
+
against it.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## [0.4.0] — 2026-09-06
|
|
267
|
+
|
|
268
|
+
### Changed
|
|
269
|
+
|
|
270
|
+
- **`@electric-sql/pglite` is no longer a runtime dependency.** It is now a
|
|
271
|
+
dev dependency and an *optional* peer. The published package declares zero
|
|
272
|
+
runtime dependencies. A library whose premise is "run it against your own
|
|
273
|
+
Postgres" should not install an embedded WASM Postgres into every production
|
|
274
|
+
deployment; it did, and that was wrong.
|
|
275
|
+
`createTestDb()` and `Filelayer.quickstart()` still need it, and now say so
|
|
276
|
+
with an actionable message instead of a module-resolution error. If you use
|
|
277
|
+
either in tests, add
|
|
278
|
+
`npm install --save-dev "@electric-sql/pglite@^0.3.11"`. Nothing
|
|
279
|
+
else changes; production code paths never imported it.
|
|
280
|
+
|
|
281
|
+
*(The command in this entry originally omitted the version constraint. That
|
|
282
|
+
omission is the defect fixed in 0.4.1, and the command has been corrected here
|
|
283
|
+
so that nobody reading the history copies the broken one.)*
|
|
284
|
+
|
|
285
|
+
### Added
|
|
286
|
+
|
|
287
|
+
- A CI job that exercises the S3/R2 storage adapter against live object storage
|
|
288
|
+
when credentials are configured, and states plainly in the build summary when
|
|
289
|
+
they are not. See `docs/LIVE-S3-TESTS.md`.
|
|
290
|
+
- `TRUST.md` — the current state of this project in numbers, including the ones
|
|
291
|
+
that are zero, and what would change them.
|
|
292
|
+
|
|
293
|
+
### Fixed
|
|
294
|
+
|
|
295
|
+
- `FILELAYER_TEST_S3_PREFIX` used `??` rather than `||`, so the empty string CI
|
|
296
|
+
supplies for an unset variable became a real value and rooted test objects at
|
|
297
|
+
the bucket root instead of under the prefix cleanup deletes.
|
|
298
|
+
|
|
106
299
|
## [0.3.0] — 2026-09-05
|
|
107
300
|
|
|
108
301
|
The release that makes the package installable, and the one that closes the
|
package/NOTICE
CHANGED
|
@@ -16,20 +16,23 @@ and anyone reviewing this distribution's licence obligations. It is
|
|
|
16
16
|
NOT a required attribution notice under Apache-2.0 section 4(d), and
|
|
17
17
|
redistributors of Filelayer do not inherit an obligation to reproduce it.
|
|
18
18
|
|
|
19
|
-
Filelayer has
|
|
19
|
+
Filelayer has NO runtime dependencies. Installing @filelayer/core installs
|
|
20
|
+
@filelayer/core and nothing else. One third-party package is used, and only
|
|
21
|
+
outside production:
|
|
20
22
|
|
|
21
23
|
@electric-sql/pglite
|
|
22
24
|
PostgreSQL compiled to WebAssembly, used for the embedded database in
|
|
23
|
-
`Filelayer.quickstart()` and in the test suite.
|
|
25
|
+
`Filelayer.quickstart()`, in `createTestDb()` and in the test suite.
|
|
24
26
|
Licensed under the Apache License, Version 2.0.
|
|
25
27
|
https://github.com/electric-sql/pglite
|
|
26
28
|
|
|
27
|
-
It is declared as a
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
It is declared as a devDependency and as an OPTIONAL peer dependency, so a
|
|
30
|
+
consumer who does not call those two helpers never installs it. When it is
|
|
31
|
+
installed it comes from the registry. No part of it is vendored into,
|
|
32
|
+
copied into, or redistributed inside this repository or the published
|
|
33
|
+
tarball, so this distribution is not a Derivative Work of it. It ships no
|
|
34
|
+
NOTICE file of its own, so Apache-2.0 section 4(d) imposes no propagation
|
|
35
|
+
requirement even where a redistributor bundles it.
|
|
33
36
|
|
|
34
37
|
No other third-party code is vendored, copied or embedded in this
|
|
35
38
|
distribution. The comparison implementations under `benchmark/` are original
|
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
resolve on their own with no edit here. The licence badge is live now. -->
|
|
13
13
|
|
|
14
14
|
> ## ⚠️ Alpha — developer preview. Not production software.
|
|
15
|
+
|
|
16
|
+
> **[Should you depend on this?](https://github.com/filelayer/filelayer/blob/main/TRUST.md)** — the real numbers, including the ones
|
|
17
|
+
> that are zero, and exactly what would change them.
|
|
15
18
|
>
|
|
16
19
|
> We would rather you trust us later for good reasons than trust us now for bad
|
|
17
20
|
> ones, so here is the honest state of this project.
|
|
@@ -184,6 +187,26 @@ declarations in `dist/`; the TypeScript source and the full test suite are in
|
|
|
184
187
|
the tarball as well, so every claim on this page is inspectable from what you
|
|
185
188
|
installed.
|
|
186
189
|
|
|
190
|
+
**That install has zero runtime dependencies.** Filelayer talks to *your*
|
|
191
|
+
Postgres and *your* bucket, so it ships neither. The throwaway instance below is
|
|
192
|
+
the one exception: `quickstart()` runs on an embedded WebAssembly Postgres,
|
|
193
|
+
declared as an *optional peer dependency* so that it never lands in a production
|
|
194
|
+
`node_modules`. Add it if you want the throwaway instance, and skip it
|
|
195
|
+
otherwise — `createTestDb()` will tell you, by name, if you need it:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm install --save-dev "@electric-sql/pglite@^0.3.11"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Install PGlite with that version constraint.** Filelayer supports the
|
|
202
|
+
**0.3.x** line, which is what `peerDependencies` declares and what the suite runs
|
|
203
|
+
against. **0.5.x is not supported**: we ran the full suite against 0.5.8 and it
|
|
204
|
+
does not pass, so the range has not been widened. PGlite's `latest` on npm is a
|
|
205
|
+
0.5.x release, so omitting the constraint can install a version outside the
|
|
206
|
+
supported range — and npm then refuses the whole tree with `ERESOLVE`. The quotes
|
|
207
|
+
are for your shell, not for npm: `^` is a glob operator under `zsh` with
|
|
208
|
+
`extendedglob` and an escape character in `cmd.exe`.
|
|
209
|
+
|
|
187
210
|
```ts
|
|
188
211
|
import { Filelayer } from '@filelayer/core';
|
|
189
212
|
|
|
@@ -278,11 +301,13 @@ tarball, so the grant travels with the artifact rather than only with the
|
|
|
278
301
|
repository. There are no per-file licence headers — the grant is carried by
|
|
279
302
|
`LICENSE`, `NOTICE` and the `license` field of every `package.json`.
|
|
280
303
|
|
|
281
|
-
**Dependencies.** Filelayer has
|
|
282
|
-
[`@electric-sql/pglite`](https://github.com/electric-sql/pglite)
|
|
283
|
-
Apache-2.0
|
|
284
|
-
`
|
|
285
|
-
|
|
304
|
+
**Dependencies.** Filelayer has **no runtime dependencies**. Its one third-party
|
|
305
|
+
package, [`@electric-sql/pglite`](https://github.com/electric-sql/pglite)
|
|
306
|
+
(Apache-2.0), is a `devDependency` and an *optional peer dependency*: the test
|
|
307
|
+
suite and `quickstart()` run on it, and a production install does not contain
|
|
308
|
+
it. It is installed from the registry rather than vendored, ships no `NOTICE`
|
|
309
|
+
file of its own, and is recorded in ours for convenience. No third-party code is
|
|
310
|
+
copied or embedded anywhere in this repository.
|
|
286
311
|
|
|
287
312
|
## Contributing, security and conduct
|
|
288
313
|
|
package/dist/db.d.ts
CHANGED
|
@@ -135,6 +135,10 @@ export declare function loadSchemaSql(): Promise<string>;
|
|
|
135
135
|
* real enums, real arrays, real rules, real transactional semantics. The one
|
|
136
136
|
* thing it is NOT is multi-process, which matters for exactly one test; see
|
|
137
137
|
* test/security.test.ts, "atomic download cap", for what that weakens.
|
|
138
|
+
*
|
|
139
|
+
* REQUIRES the optional peer dependency `@electric-sql/pglite`. Production code
|
|
140
|
+
* does not need it: hand `new Filelayer(...)` your own `pg.Pool`, or anything
|
|
141
|
+
* else that satisfies `Queryable`, and this function is never reached.
|
|
138
142
|
*/
|
|
139
143
|
export declare function createTestDb(): Promise<{
|
|
140
144
|
db: Queryable & {
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAMH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC;;;;OAIG;IACH,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACpE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,EAAG,SAAQ,SAAS;IACnC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC;IAC7B,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChD;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,SAAS,GAAG,EAAE,IAAI,EAAE,CAE5C;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBACZ,KAAK,EAAE,OAAO;CAK3B;AAoBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,SAAS,EACb,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAqCZ;AA6CD,eAAO,MAAM,WAAW,QAAiC,CAAC;AAE1D,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAErD;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAMH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC;;;;OAIG;IACH,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACpE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,EAAG,SAAQ,SAAS;IACnC,QAAQ,CAAC,aAAa,EAAE,IAAI,CAAC;IAC7B,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChD;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,SAAS,GAAG,EAAE,IAAI,EAAE,CAE5C;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBACZ,KAAK,EAAE,OAAO;CAK3B;AAoBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,SAAS,EACb,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAqCZ;AA6CD,eAAO,MAAM,WAAW,QAAiC,CAAC;AAE1D,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAErD;AAiDD;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAC5C,EAAE,EAAE,SAAS,GAAG;QAAE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAC3C,GAAG,EAAE,OAAO,CAAC;CACd,CAAC,CAMD"}
|
package/dist/db.js
CHANGED
|
@@ -198,6 +198,51 @@ export const SCHEMA_PATH = join(HERE, '..', 'schema.sql');
|
|
|
198
198
|
export async function loadSchemaSql() {
|
|
199
199
|
return readFile(SCHEMA_PATH, 'utf8');
|
|
200
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* The one package this library needs and deliberately does not depend on.
|
|
203
|
+
*
|
|
204
|
+
* PGlite is an embedded WASM build of PostgreSQL. It is what `createTestDb()`
|
|
205
|
+
* and `Filelayer.quickstart()` run on, and it is superb for that -- but a
|
|
206
|
+
* library whose premise is "point it at YOUR Postgres" has no business putting
|
|
207
|
+
* a second Postgres into every production `node_modules`. So it is declared as
|
|
208
|
+
* an OPTIONAL PEER DEPENDENCY: named, version-ranged and discoverable, but not
|
|
209
|
+
* installed for anyone who never calls the two helpers that use it.
|
|
210
|
+
*
|
|
211
|
+
* The cost of that choice is this constant and the `catch` below. Without them
|
|
212
|
+
* the failure mode for a consumer who calls `createTestDb()` is a raw
|
|
213
|
+
* ERR_MODULE_NOT_FOUND naming a package they never asked for, from a stack
|
|
214
|
+
* inside our `dist`, and no indication that installing one thing fixes it.
|
|
215
|
+
*/
|
|
216
|
+
const PGLITE = '@electric-sql/pglite';
|
|
217
|
+
/**
|
|
218
|
+
* The install command a caller is handed, spelled out in full.
|
|
219
|
+
*
|
|
220
|
+
* The version constraint is not decoration. PGlite's `latest` on npm is a 0.5.x
|
|
221
|
+
* release and this package declares `peerDependencies` of `^0.3.11`, so an
|
|
222
|
+
* install with no constraint on it can land a version outside the declared
|
|
223
|
+
* range -- at which point npm refuses the whole tree with ERESOLVE and the
|
|
224
|
+
* developer is stuck one minute in, having typed what we told them to type.
|
|
225
|
+
* That happened; it is the defect 0.4.1 fixes.
|
|
226
|
+
*
|
|
227
|
+
* The range is a literal rather than a template so that
|
|
228
|
+
* `tools/check-install-commands.mjs` can read it out of this file and fail the
|
|
229
|
+
* build if it ever stops matching `peerDependencies` in package.json. The two
|
|
230
|
+
* are the same fact written in two places, and the check is what keeps them
|
|
231
|
+
* one fact.
|
|
232
|
+
*
|
|
233
|
+
* The quotes are for the shell, not for npm: `^` is a glob operator under zsh
|
|
234
|
+
* with `extendedglob`, and an escape character in cmd.exe.
|
|
235
|
+
*/
|
|
236
|
+
const PGLITE_INSTALL = 'npm install --save-dev "@electric-sql/pglite@^0.3.11"';
|
|
237
|
+
/** True when `err` is Node refusing to resolve `spec`, and not some other failure. */
|
|
238
|
+
function isModuleNotFound(err, spec) {
|
|
239
|
+
const code = err?.code;
|
|
240
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND')
|
|
241
|
+
return false;
|
|
242
|
+
// A resolution failure *inside* pglite itself is a broken install, not a
|
|
243
|
+
// missing one, and must not be reported as "run npm install".
|
|
244
|
+
return String(err.message ?? '').includes(spec);
|
|
245
|
+
}
|
|
201
246
|
/**
|
|
202
247
|
* Create an in-process Postgres (PGlite) with the Filelayer schema applied.
|
|
203
248
|
*
|
|
@@ -205,13 +250,52 @@ export async function loadSchemaSql() {
|
|
|
205
250
|
* real enums, real arrays, real rules, real transactional semantics. The one
|
|
206
251
|
* thing it is NOT is multi-process, which matters for exactly one test; see
|
|
207
252
|
* test/security.test.ts, "atomic download cap", for what that weakens.
|
|
253
|
+
*
|
|
254
|
+
* REQUIRES the optional peer dependency `@electric-sql/pglite`. Production code
|
|
255
|
+
* does not need it: hand `new Filelayer(...)` your own `pg.Pool`, or anything
|
|
256
|
+
* else that satisfies `Queryable`, and this function is never reached.
|
|
208
257
|
*/
|
|
209
258
|
export async function createTestDb() {
|
|
210
|
-
const { PGlite } = await
|
|
211
|
-
const { pgcrypto } = await import('@electric-sql/pglite/contrib/pgcrypto');
|
|
259
|
+
const { PGlite, pgcrypto } = await importPglite();
|
|
212
260
|
const pg = await PGlite.create({ extensions: { pgcrypto } });
|
|
213
261
|
const sql = await loadSchemaSql();
|
|
214
262
|
await pg.exec(sql);
|
|
215
263
|
return { db: pg, raw: pg };
|
|
216
264
|
}
|
|
265
|
+
async function importPglite() {
|
|
266
|
+
try {
|
|
267
|
+
const [mod, contrib] = await Promise.all([
|
|
268
|
+
import('@electric-sql/pglite'),
|
|
269
|
+
import('@electric-sql/pglite/contrib/pgcrypto'),
|
|
270
|
+
]);
|
|
271
|
+
return { PGlite: mod.PGlite, pgcrypto: contrib.pgcrypto };
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
if (!isModuleNotFound(err, PGLITE))
|
|
275
|
+
throw err;
|
|
276
|
+
throw new Error(`createTestDb() needs "${PGLITE}", which is not installed.\n` +
|
|
277
|
+
`\n` +
|
|
278
|
+
` ${PGLITE_INSTALL}\n` +
|
|
279
|
+
`\n` +
|
|
280
|
+
`The version is part of the command. @filelayer/core supports the 0.3.x line\n` +
|
|
281
|
+
`of ${PGLITE}; 0.5.x is not supported, because the test suite does\n` +
|
|
282
|
+
`not pass against it. Installing without the constraint can resolve to a\n` +
|
|
283
|
+
`version outside the supported range, and npm then refuses the install with\n` +
|
|
284
|
+
`ERESOLVE rather than giving you a working tree.\n` +
|
|
285
|
+
`\n` +
|
|
286
|
+
`It is an OPTIONAL peer dependency of @filelayer/core, on purpose: it is an\n` +
|
|
287
|
+
`embedded WASM PostgreSQL used by createTestDb() and Filelayer.quickstart()\n` +
|
|
288
|
+
`for tests and local development, and shipping it to production installs of\n` +
|
|
289
|
+
`a library that talks to your own Postgres would be wrong.\n` +
|
|
290
|
+
`\n` +
|
|
291
|
+
`In production, do not call this. Pass your own database instead:\n` +
|
|
292
|
+
`\n` +
|
|
293
|
+
` import { Pool } from 'pg';\n` +
|
|
294
|
+
` new Filelayer(new Pool({ connectionString: process.env.DATABASE_URL }), storage, opts)\n` +
|
|
295
|
+
`\n` +
|
|
296
|
+
`and apply the schema once with:\n` +
|
|
297
|
+
`\n` +
|
|
298
|
+
` psql "$DATABASE_URL" -f node_modules/@filelayer/core/schema.sql\n`, { cause: err });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
217
301
|
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@filelayer/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Multi-tenant file authorization and lifecycle for Postgres: one decision point for public and private files, revocable URLs, delegated share links and a hash-chained audit trail.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -67,10 +67,16 @@
|
|
|
67
67
|
"typecheck": "tsc --noEmit",
|
|
68
68
|
"verify": "npm run typecheck && npm test && npm run build"
|
|
69
69
|
},
|
|
70
|
-
"
|
|
70
|
+
"peerDependencies": {
|
|
71
71
|
"@electric-sql/pglite": "^0.3.11"
|
|
72
72
|
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"@electric-sql/pglite": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
73
78
|
"devDependencies": {
|
|
79
|
+
"@electric-sql/pglite": "^0.3.11",
|
|
74
80
|
"typescript": "^5.7.0",
|
|
75
81
|
"@types/node": "^22.10.0"
|
|
76
82
|
}
|
package/src/db.ts
CHANGED
|
@@ -250,6 +250,53 @@ export async function loadSchemaSql(): Promise<string> {
|
|
|
250
250
|
return readFile(SCHEMA_PATH, 'utf8');
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The one package this library needs and deliberately does not depend on.
|
|
255
|
+
*
|
|
256
|
+
* PGlite is an embedded WASM build of PostgreSQL. It is what `createTestDb()`
|
|
257
|
+
* and `Filelayer.quickstart()` run on, and it is superb for that -- but a
|
|
258
|
+
* library whose premise is "point it at YOUR Postgres" has no business putting
|
|
259
|
+
* a second Postgres into every production `node_modules`. So it is declared as
|
|
260
|
+
* an OPTIONAL PEER DEPENDENCY: named, version-ranged and discoverable, but not
|
|
261
|
+
* installed for anyone who never calls the two helpers that use it.
|
|
262
|
+
*
|
|
263
|
+
* The cost of that choice is this constant and the `catch` below. Without them
|
|
264
|
+
* the failure mode for a consumer who calls `createTestDb()` is a raw
|
|
265
|
+
* ERR_MODULE_NOT_FOUND naming a package they never asked for, from a stack
|
|
266
|
+
* inside our `dist`, and no indication that installing one thing fixes it.
|
|
267
|
+
*/
|
|
268
|
+
const PGLITE = '@electric-sql/pglite';
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The install command a caller is handed, spelled out in full.
|
|
272
|
+
*
|
|
273
|
+
* The version constraint is not decoration. PGlite's `latest` on npm is a 0.5.x
|
|
274
|
+
* release and this package declares `peerDependencies` of `^0.3.11`, so an
|
|
275
|
+
* install with no constraint on it can land a version outside the declared
|
|
276
|
+
* range -- at which point npm refuses the whole tree with ERESOLVE and the
|
|
277
|
+
* developer is stuck one minute in, having typed what we told them to type.
|
|
278
|
+
* That happened; it is the defect 0.4.1 fixes.
|
|
279
|
+
*
|
|
280
|
+
* The range is a literal rather than a template so that
|
|
281
|
+
* `tools/check-install-commands.mjs` can read it out of this file and fail the
|
|
282
|
+
* build if it ever stops matching `peerDependencies` in package.json. The two
|
|
283
|
+
* are the same fact written in two places, and the check is what keeps them
|
|
284
|
+
* one fact.
|
|
285
|
+
*
|
|
286
|
+
* The quotes are for the shell, not for npm: `^` is a glob operator under zsh
|
|
287
|
+
* with `extendedglob`, and an escape character in cmd.exe.
|
|
288
|
+
*/
|
|
289
|
+
const PGLITE_INSTALL = 'npm install --save-dev "@electric-sql/pglite@^0.3.11"';
|
|
290
|
+
|
|
291
|
+
/** True when `err` is Node refusing to resolve `spec`, and not some other failure. */
|
|
292
|
+
function isModuleNotFound(err: unknown, spec: string): boolean {
|
|
293
|
+
const code = (err as { code?: unknown } | null)?.code;
|
|
294
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') return false;
|
|
295
|
+
// A resolution failure *inside* pglite itself is a broken install, not a
|
|
296
|
+
// missing one, and must not be reported as "run npm install".
|
|
297
|
+
return String((err as Error).message ?? '').includes(spec);
|
|
298
|
+
}
|
|
299
|
+
|
|
253
300
|
/**
|
|
254
301
|
* Create an in-process Postgres (PGlite) with the Filelayer schema applied.
|
|
255
302
|
*
|
|
@@ -257,15 +304,59 @@ export async function loadSchemaSql(): Promise<string> {
|
|
|
257
304
|
* real enums, real arrays, real rules, real transactional semantics. The one
|
|
258
305
|
* thing it is NOT is multi-process, which matters for exactly one test; see
|
|
259
306
|
* test/security.test.ts, "atomic download cap", for what that weakens.
|
|
307
|
+
*
|
|
308
|
+
* REQUIRES the optional peer dependency `@electric-sql/pglite`. Production code
|
|
309
|
+
* does not need it: hand `new Filelayer(...)` your own `pg.Pool`, or anything
|
|
310
|
+
* else that satisfies `Queryable`, and this function is never reached.
|
|
260
311
|
*/
|
|
261
312
|
export async function createTestDb(): Promise<{
|
|
262
313
|
db: Queryable & { close(): Promise<void> };
|
|
263
314
|
raw: unknown;
|
|
264
315
|
}> {
|
|
265
|
-
const { PGlite } = await
|
|
266
|
-
const { pgcrypto } = await import('@electric-sql/pglite/contrib/pgcrypto');
|
|
316
|
+
const { PGlite, pgcrypto } = await importPglite();
|
|
267
317
|
const pg = await PGlite.create({ extensions: { pgcrypto } });
|
|
268
318
|
const sql = await loadSchemaSql();
|
|
269
319
|
await pg.exec(sql);
|
|
270
320
|
return { db: pg as unknown as Queryable & { close(): Promise<void> }, raw: pg };
|
|
271
321
|
}
|
|
322
|
+
|
|
323
|
+
async function importPglite(): Promise<{
|
|
324
|
+
PGlite: typeof import('@electric-sql/pglite').PGlite;
|
|
325
|
+
pgcrypto: typeof import('@electric-sql/pglite/contrib/pgcrypto').pgcrypto;
|
|
326
|
+
}> {
|
|
327
|
+
try {
|
|
328
|
+
const [mod, contrib] = await Promise.all([
|
|
329
|
+
import('@electric-sql/pglite'),
|
|
330
|
+
import('@electric-sql/pglite/contrib/pgcrypto'),
|
|
331
|
+
]);
|
|
332
|
+
return { PGlite: mod.PGlite, pgcrypto: contrib.pgcrypto };
|
|
333
|
+
} catch (err) {
|
|
334
|
+
if (!isModuleNotFound(err, PGLITE)) throw err;
|
|
335
|
+
throw new Error(
|
|
336
|
+
`createTestDb() needs "${PGLITE}", which is not installed.\n` +
|
|
337
|
+
`\n` +
|
|
338
|
+
` ${PGLITE_INSTALL}\n` +
|
|
339
|
+
`\n` +
|
|
340
|
+
`The version is part of the command. @filelayer/core supports the 0.3.x line\n` +
|
|
341
|
+
`of ${PGLITE}; 0.5.x is not supported, because the test suite does\n` +
|
|
342
|
+
`not pass against it. Installing without the constraint can resolve to a\n` +
|
|
343
|
+
`version outside the supported range, and npm then refuses the install with\n` +
|
|
344
|
+
`ERESOLVE rather than giving you a working tree.\n` +
|
|
345
|
+
`\n` +
|
|
346
|
+
`It is an OPTIONAL peer dependency of @filelayer/core, on purpose: it is an\n` +
|
|
347
|
+
`embedded WASM PostgreSQL used by createTestDb() and Filelayer.quickstart()\n` +
|
|
348
|
+
`for tests and local development, and shipping it to production installs of\n` +
|
|
349
|
+
`a library that talks to your own Postgres would be wrong.\n` +
|
|
350
|
+
`\n` +
|
|
351
|
+
`In production, do not call this. Pass your own database instead:\n` +
|
|
352
|
+
`\n` +
|
|
353
|
+
` import { Pool } from 'pg';\n` +
|
|
354
|
+
` new Filelayer(new Pool({ connectionString: process.env.DATABASE_URL }), storage, opts)\n` +
|
|
355
|
+
`\n` +
|
|
356
|
+
`and apply the schema once with:\n` +
|
|
357
|
+
`\n` +
|
|
358
|
+
` psql "$DATABASE_URL" -f node_modules/@filelayer/core/schema.sql\n`,
|
|
359
|
+
{ cause: err },
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
package/test/s3-live.test.ts
CHANGED
|
@@ -10,36 +10,21 @@
|
|
|
10
10
|
* WHAT A MAINTAINER MUST SET
|
|
11
11
|
* -----------------------------------------------------------------------------
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* The bucket, the token permissions and the exact secret names are specified in
|
|
14
|
+
* ONE place -- `docs/LIVE-S3-TESTS.md` -- and this file deliberately does not
|
|
15
|
+
* restate them. Two copies of a setup procedure drift, and the copy that drifts
|
|
16
|
+
* is the one nobody followed most recently.
|
|
14
17
|
*
|
|
15
|
-
*
|
|
16
|
-
* or https://s3.<region>.amazonaws.com
|
|
17
|
-
* FILELAYER_TEST_S3_BUCKET a bucket that may be written to and
|
|
18
|
-
* emptied. USE A DEDICATED TEST BUCKET.
|
|
19
|
-
* FILELAYER_TEST_S3_REGION 'auto' for R2, the real region for AWS
|
|
20
|
-
* FILELAYER_TEST_S3_ACCESS_KEY_ID
|
|
21
|
-
* FILELAYER_TEST_S3_SECRET_ACCESS_KEY
|
|
18
|
+
* What this file reads, and nothing more:
|
|
22
19
|
*
|
|
23
|
-
*
|
|
20
|
+
* REQUIRED, all five or the suite skips:
|
|
21
|
+
* FILELAYER_TEST_S3_ENDPOINT, FILELAYER_TEST_S3_BUCKET,
|
|
22
|
+
* FILELAYER_TEST_S3_REGION, FILELAYER_TEST_S3_ACCESS_KEY_ID,
|
|
23
|
+
* FILELAYER_TEST_S3_SECRET_ACCESS_KEY
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* Defaults to path-style, which is what
|
|
29
|
-
* R2 requires.
|
|
30
|
-
* FILELAYER_TEST_S3_PREFIX key prefix. Defaults to
|
|
31
|
-
* 'filelayer-ci/'. Everything the suite
|
|
32
|
-
* writes lives under it and is deleted
|
|
33
|
-
* afterwards.
|
|
34
|
-
* FILELAYER_TEST_S3_MULTIPART '1' to run the multipart test, which
|
|
35
|
-
* uploads ~11 MB. Off by default so the
|
|
36
|
-
* suite stays cheap on every push;
|
|
37
|
-
* turn it ON in the nightly job.
|
|
38
|
-
*
|
|
39
|
-
* IAM PERMISSIONS REQUIRED on the bucket:
|
|
40
|
-
* s3:PutObject, s3:GetObject, s3:DeleteObject, s3:ListBucket,
|
|
41
|
-
* s3:AbortMultipartUpload (multipart cleanup),
|
|
42
|
-
* s3:ListBucketMultipartUploads (only if you enable the multipart test)
|
|
25
|
+
* OPTIONAL:
|
|
26
|
+
* FILELAYER_TEST_S3_SESSION_TOKEN, FILELAYER_TEST_S3_PATH_STYLE,
|
|
27
|
+
* FILELAYER_TEST_S3_PREFIX, FILELAYER_TEST_S3_MULTIPART
|
|
43
28
|
*
|
|
44
29
|
* -----------------------------------------------------------------------------
|
|
45
30
|
* WHY THIS FILE EXISTS EVEN THOUGH test/storage.test.ts PASSES
|
|
@@ -75,9 +60,12 @@ const missing = REQUIRED.filter((k) => !env[k]);
|
|
|
75
60
|
const enabled = missing.length === 0;
|
|
76
61
|
const skip = enabled
|
|
77
62
|
? false
|
|
78
|
-
: `live S3 credentials not present (missing: ${missing.join(', ')}); see
|
|
63
|
+
: `live S3 credentials not present (missing: ${missing.join(', ')}); see docs/LIVE-S3-TESTS.md`;
|
|
79
64
|
|
|
80
|
-
|
|
65
|
+
// `||`, not `??`: a workflow that forwards an unset repository variable hands
|
|
66
|
+
// us the EMPTY STRING, and `'' ?? default` is `''` -- which would root every
|
|
67
|
+
// test key at '/' instead of under the prefix that gets cleaned up.
|
|
68
|
+
const PREFIX = (env['FILELAYER_TEST_S3_PREFIX'] || 'filelayer-ci/').replace(/\/*$/, '/');
|
|
81
69
|
const RUN = `${PREFIX}${Date.now()}-${Math.random().toString(36).slice(2, 8)}/`;
|
|
82
70
|
const MULTIPART = env['FILELAYER_TEST_S3_MULTIPART'] === '1';
|
|
83
71
|
|