dxfl 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +1 -0
- package/CHANGELOG.md +13 -0
- package/README.md +6 -2
- package/deuxfleurs.toml +23 -0
- package/deuxfleurs.toml~ +18 -0
- package/dist/deploy.js +5 -9
- package/dist/deploy_websiteconfig.js +108 -0
- package/dist/errors.js +7 -0
- package/dist/index.js +1 -1
- package/dist/website_config.js +45 -21
- package/npm-shrinkwrap.json +45 -27
- package/package.json +4 -2
- package/public/TinyCorePure64-15.0.iso +1 -0
- package/public/d/b +2 -0
- package/public/d/c +2 -0
- package/public/d/dd/bla +1 -0
- package/public/d/dd/foo.txt +1 -0
- package/public/def +2 -0
- package/public/error.html +1 -0
- package/public/index.html +1 -0
- package/public/index.html~ +1 -0
- package/public/rtj7uMG.mp4 +0 -0
- package/public/slt +1 -0
- package/public/test.html +0 -0
- package/public/toto.jpg +0 -0
- package/public/toto.txt +1 -0
- package/public/toto2.txt +1 -0
- package/dist/_empty.js +0 -64
- package/dist/tsconfig.tsbuildinfo +0 -1
package/.prettierignore
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# v0.7.0
|
|
2
|
+
|
|
3
|
+
- Improve behavior of redirections whose source path is a directory (path ending
|
|
4
|
+
with a `/`). They are now interpreted as redirecting from the index page of
|
|
5
|
+
that directory. For example, a redirect with `from = "foo/"` is now
|
|
6
|
+
interpreted as `from = "foo/index.html"` (assuming `index_page` in
|
|
7
|
+
`deuxfleurs.toml` is not defined to a custom value; otherwise `index.html` is
|
|
8
|
+
replaced by the value of `index_page`).
|
|
9
|
+
|
|
10
|
+
# v0.6.2
|
|
11
|
+
|
|
12
|
+
- `deploy`: Re-enable CORS configuration (disabled on v0.4.2)
|
|
13
|
+
|
|
1
14
|
# v0.6.1
|
|
2
15
|
|
|
3
16
|
- Dependencies bump
|
package/README.md
CHANGED
|
@@ -191,10 +191,13 @@ git clone https://git.deuxfleurs.fr/Deuxfleurs/dxfl
|
|
|
191
191
|
cd dxfl
|
|
192
192
|
npm install
|
|
193
193
|
# build and install the tool as the `dxfl` command
|
|
194
|
-
npm
|
|
194
|
+
npm run build
|
|
195
195
|
dxfl
|
|
196
196
|
# alternatively, run the tool from the sources directly
|
|
197
197
|
npx dxfl
|
|
198
|
+
# rebuild automatically on changes with:
|
|
199
|
+
npm run dev
|
|
200
|
+
|
|
198
201
|
```
|
|
199
202
|
|
|
200
203
|
### Code formatting
|
|
@@ -220,7 +223,8 @@ Then to publish a release:
|
|
|
220
223
|
vim CHANGELOG.md # update the version and its content in this file
|
|
221
224
|
vim package.json # update the version in this file
|
|
222
225
|
vim index.ts # update the version in this file
|
|
223
|
-
npm install # update the version in the lock file
|
|
226
|
+
npm install # update the version in the lock file and check security audit
|
|
227
|
+
npm shrinkwrap # make suuuure the lock file is up to date
|
|
224
228
|
npm run prettier # fix potential coding style problem
|
|
225
229
|
git commit -a -m 'set version 0.1.5' # commit your change
|
|
226
230
|
git push # send update
|
package/deuxfleurs.toml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
error_page = "error.html"
|
|
2
|
+
index_page = "myindex.html"
|
|
3
|
+
|
|
4
|
+
# [[redirects]]
|
|
5
|
+
# from = "TinyCorePure64-15.0.iso"
|
|
6
|
+
# to = "/bbc"
|
|
7
|
+
|
|
8
|
+
[[redirects]]
|
|
9
|
+
from = "/a"
|
|
10
|
+
to = "/def"
|
|
11
|
+
|
|
12
|
+
[[redirects]]
|
|
13
|
+
from = "/a/"
|
|
14
|
+
to = "/ghi"
|
|
15
|
+
|
|
16
|
+
[[cors]]
|
|
17
|
+
allowed_origins = "foo"
|
|
18
|
+
|
|
19
|
+
[[headers]]
|
|
20
|
+
for = ["**/*.txt"]
|
|
21
|
+
compress = "gzip"
|
|
22
|
+
[headers.values]
|
|
23
|
+
Cache-Control = "hello44"
|
package/deuxfleurs.toml~
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
error_page = "error.html"
|
|
2
|
+
|
|
3
|
+
# [[redirects]]
|
|
4
|
+
# from = "TinyCorePure64-15.0.iso"
|
|
5
|
+
# to = "/bbc"
|
|
6
|
+
|
|
7
|
+
[[redirects]]
|
|
8
|
+
from = "/a"
|
|
9
|
+
to = "/def"
|
|
10
|
+
|
|
11
|
+
[[cors]]
|
|
12
|
+
allowed_origins = "foo"
|
|
13
|
+
|
|
14
|
+
[[headers]]
|
|
15
|
+
for = ["**/*.txt"]
|
|
16
|
+
compress = "gzip"
|
|
17
|
+
[headers.values]
|
|
18
|
+
Cache-Control = "hello44"
|
package/dist/deploy.js
CHANGED
|
@@ -14,7 +14,7 @@ import { deleteBucketFile, deleteBucketFiles, getBucketCredentials, getBucket, g
|
|
|
14
14
|
import { ErrorMsg } from "./error.js";
|
|
15
15
|
import { fileContentType, supportedHeaders, } from "./headers.js";
|
|
16
16
|
import { confirmationPrompt, filterMap, formatBytesHuman, formatCount, getFileMd5, gzipFile, mapEq, mkTmpDir, sum, websiteIdBestEffort, } from "./utils.js";
|
|
17
|
-
import { evalHeadersRules, equalBucketRedirect, getBucketConfig, putBucketWebsiteConfig, readConfigFile, } from "./website_config.js";
|
|
17
|
+
import { evalHeadersRules, equalBucketRedirect, equalCorsRules, getBucketConfig, putBucketWebsiteConfig, putCorsRules, readConfigFile, } from "./website_config.js";
|
|
18
18
|
// Walks through the local directory at path `dir`, and for each file it contains, returns :
|
|
19
19
|
// - `localPath`: its path on the local filesystem (includes `dir`). On windows, this path
|
|
20
20
|
// will typically use `\` as separator.
|
|
@@ -263,11 +263,7 @@ function printPlan(plan, details) {
|
|
|
263
263
|
const oredirects_updated = plan.redirects.filter(r => r.action == "update");
|
|
264
264
|
const oredirects_deleted = plan.redirects.filter(r => r.action == "delete");
|
|
265
265
|
// check whether CORS rules changed
|
|
266
|
-
|
|
267
|
-
// plan.cors_rules.from,
|
|
268
|
-
// plan.cors_rules.to,
|
|
269
|
-
// );
|
|
270
|
-
const cors_changed = false;
|
|
266
|
+
const cors_changed = !equalCorsRules(plan.cors_rules.from, plan.cors_rules.to);
|
|
271
267
|
// print
|
|
272
268
|
if (details == "summary") {
|
|
273
269
|
const sizeRemote = sum([...plan.remoteFiles.values()].map(f => { var _a; return (_a = f.size) !== null && _a !== void 0 ? _a : 0; }));
|
|
@@ -407,9 +403,9 @@ function applyDeployPlan(bucket, plan) {
|
|
|
407
403
|
// Apply bucket redirects & global config
|
|
408
404
|
yield putBucketWebsiteConfig(bucket, plan.index_page.to, plan.error_page.to, plan.bucket_redirects.to);
|
|
409
405
|
// Apply CORS rules
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
406
|
+
if (!equalCorsRules(plan.cors_rules.from, plan.cors_rules.to)) {
|
|
407
|
+
yield putCorsRules(bucket, plan.cors_rules.to);
|
|
408
|
+
}
|
|
413
409
|
// Modify headers
|
|
414
410
|
yield PromisePool.for(plan.modifyHeaders)
|
|
415
411
|
.withConcurrency(50)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { PromisePool } from "@supercharge/promise-pool";
|
|
11
|
+
import { GetBucketWebsiteCommand, HeadObjectCommand, } from "@aws-sdk/client-s3";
|
|
12
|
+
export function getBucketWebsite(client, Bucket) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const cmd = new GetBucketWebsiteCommand({ Bucket });
|
|
16
|
+
const response = yield client.send(cmd);
|
|
17
|
+
if (response.RedirectAllRequestsTo) {
|
|
18
|
+
// NB: garage does not currently support RedirectAllRequestsTo so this should never happen
|
|
19
|
+
throw `remote website configuration: RedirectAllRequestsTo is specified; \
|
|
20
|
+
this is currently unsupported by dxfl`;
|
|
21
|
+
}
|
|
22
|
+
const index_page = (_a = response.ErrorDocument) === null || _a === void 0 ? void 0 : _a.Key;
|
|
23
|
+
const error_page = (_b = response.IndexDocument) === null || _b === void 0 ? void 0 : _b.Suffix;
|
|
24
|
+
let redirects = [];
|
|
25
|
+
if (response.RoutingRules) {
|
|
26
|
+
for (const rule of response.RoutingRules) {
|
|
27
|
+
// If no Condition is specified, then the redirect always applies, which is equivalent
|
|
28
|
+
// to matching on an empty prefix
|
|
29
|
+
let prefix = "";
|
|
30
|
+
let if_error = undefined;
|
|
31
|
+
if (rule.Condition) {
|
|
32
|
+
if (rule.Condition.HttpErrorCodeReturnedEquals) {
|
|
33
|
+
if (rule.Condition.HttpErrorCodeReturnedEquals == "404") {
|
|
34
|
+
if_error = 404;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// currently not supported by garage
|
|
38
|
+
throw `remote website configuration: 'if_error' specified with a different \
|
|
39
|
+
code than 404; this is currently unsupported by dxfl`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (rule.Condition.KeyPrefixEquals) {
|
|
43
|
+
prefix = rule.Condition.KeyPrefixEquals;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const hostname = rule.Redirect.HostName;
|
|
47
|
+
const code = rule.Redirect.HttpRedirectCode
|
|
48
|
+
? parseInt(rule.Redirect.HttpRedirectCode)
|
|
49
|
+
: undefined;
|
|
50
|
+
let protocol = undefined;
|
|
51
|
+
if (rule.Redirect.Protocol) {
|
|
52
|
+
if (rule.Redirect.Protocol == "http" ||
|
|
53
|
+
rule.Redirect.Protocol == "https") {
|
|
54
|
+
protocol = rule.Redirect.Protocol;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// currently not supported by garage
|
|
58
|
+
throw `remote website configuration: 'protocol' is neither http or https; \
|
|
59
|
+
this is currently unsupported by dxfl`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
let to;
|
|
63
|
+
if (rule.Redirect.ReplaceKeyPrefixWith) {
|
|
64
|
+
to = {
|
|
65
|
+
kind: "replace_prefix",
|
|
66
|
+
prefix: rule.Redirect.ReplaceKeyPrefixWith,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
else if (rule.Redirect.ReplaceKeyWith) {
|
|
70
|
+
to = { kind: "replace", target: rule.Redirect.ReplaceKeyWith };
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// not completely sure whether this is the correct behavior, but it should
|
|
74
|
+
// match garage's implementation
|
|
75
|
+
to = { kind: "replace", target: "" };
|
|
76
|
+
}
|
|
77
|
+
redirects.push({
|
|
78
|
+
kind: "bucket",
|
|
79
|
+
r: { prefix, if_error, hostname, code, protocol, to },
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { index_page, error_page, redirects };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// XXX
|
|
87
|
+
const MD5METAFIELD = "dfl-md5sum";
|
|
88
|
+
export function getBucketFilesDetails(client, Bucket, files) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
let res = new Map();
|
|
91
|
+
function doFile(file) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
var _a;
|
|
94
|
+
const resp = yield client.send(new HeadObjectCommand({ Bucket, Key: file }));
|
|
95
|
+
if (resp.$metadata.httpStatusCode != 200) {
|
|
96
|
+
// TODO: better error handling?
|
|
97
|
+
throw resp;
|
|
98
|
+
}
|
|
99
|
+
res.set(file, {
|
|
100
|
+
md5: (_a = resp.Metadata) === null || _a === void 0 ? void 0 : _a[MD5METAFIELD],
|
|
101
|
+
redirect: resp.WebsiteRedirectLocation,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
yield PromisePool.for(files).withConcurrency(50).process(doFile);
|
|
106
|
+
return res;
|
|
107
|
+
});
|
|
108
|
+
}
|
package/dist/errors.js
ADDED
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { deploy } from "./deploy.js";
|
|
|
6
6
|
import { empty } from "./empty.js";
|
|
7
7
|
import { list } from "./vhosts.js";
|
|
8
8
|
import { inspect } from "./inspect.js";
|
|
9
|
-
program.name("dxfl").description("Deuxfleurs CLI tool").version("0.
|
|
9
|
+
program.name("dxfl").description("Deuxfleurs CLI tool").version("0.7.0");
|
|
10
10
|
program
|
|
11
11
|
.command("login")
|
|
12
12
|
.description("Link your Deuxfleurs account with this tool.")
|
package/dist/website_config.js
CHANGED
|
@@ -13,7 +13,7 @@ import URI from "fast-uri";
|
|
|
13
13
|
import picomatch from "picomatch";
|
|
14
14
|
import { z as zod } from "zod";
|
|
15
15
|
import { fromError as zodError } from "zod-validation-error";
|
|
16
|
-
import { DeleteBucketCorsCommand, GetBucketWebsiteCommand, PutBucketWebsiteCommand, PutBucketCorsCommand, } from "@aws-sdk/client-s3";
|
|
16
|
+
import { DeleteBucketCorsCommand, GetBucketCorsCommand, GetBucketWebsiteCommand, PutBucketWebsiteCommand, PutBucketCorsCommand, S3ServiceException, } from "@aws-sdk/client-s3";
|
|
17
17
|
import { ErrorMsg, withErrorMsg, wrapS3Call } from "./error.js";
|
|
18
18
|
import { supportedHeaders } from "./headers.js";
|
|
19
19
|
import { getBucketFilesDetails } from "./bucket.js";
|
|
@@ -179,7 +179,7 @@ function unescape(s) {
|
|
|
179
179
|
}
|
|
180
180
|
function interpConfig(rawcfg) {
|
|
181
181
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
182
|
-
function interpRedirect(r) {
|
|
182
|
+
function interpRedirect(r, index_page) {
|
|
183
183
|
var _a, _b;
|
|
184
184
|
const rfrom = withErrorMsg(() => unescape(r.from), msg => `from: ${msg}`);
|
|
185
185
|
const rto = withErrorMsg(() => unescape(r.to), msg => `to: ${msg}`);
|
|
@@ -273,6 +273,14 @@ function interpConfig(rawcfg) {
|
|
|
273
273
|
if (from.startsWith("/")) {
|
|
274
274
|
from = from.substring(1);
|
|
275
275
|
}
|
|
276
|
+
// if 'from' ends with a /, consider that the user meant to refer to the index
|
|
277
|
+
// page of that directory, and add it for them. A redirection source that is a
|
|
278
|
+
// directory would otherwise be non-functional: a URL query to "foo/" will first
|
|
279
|
+
// turn it into a request to "foo/index.html", at which point the redirection would
|
|
280
|
+
// not apply.
|
|
281
|
+
if (from.endsWith("/")) {
|
|
282
|
+
from = from.concat(index_page);
|
|
283
|
+
}
|
|
276
284
|
// for the 'to' field, garage expects the target to start with 'http://', 'https://'
|
|
277
285
|
// or '/'. So if the 'to' field does not start with '/', add one...
|
|
278
286
|
let to = rto.s;
|
|
@@ -312,7 +320,7 @@ function interpConfig(rawcfg) {
|
|
|
312
320
|
};
|
|
313
321
|
for (const [i, raw] of ((_b = rawcfg.redirects) !== null && _b !== void 0 ? _b : []).entries()) {
|
|
314
322
|
// `i+1` is only used for display: start counting redirects from 1 instead of 0
|
|
315
|
-
const r = withErrorMsg(() => interpRedirect(raw), msg => `Redirect ${i + 1}: ${msg}`);
|
|
323
|
+
const r = withErrorMsg(() => interpRedirect(raw, index_page), msg => `Redirect ${i + 1}: ${msg}`);
|
|
316
324
|
if (r.kind == "bucket") {
|
|
317
325
|
cfg.bucket_redirects.push(r.r);
|
|
318
326
|
}
|
|
@@ -375,14 +383,12 @@ export function getBucketConfig(bucket, files) {
|
|
|
375
383
|
// - A Head command for each file in the bucket to collect object redirects.
|
|
376
384
|
// (This can become relatively slow for buckets with thousands of files,
|
|
377
385
|
// but I don't know of a better way.)
|
|
378
|
-
var _a, _b;
|
|
379
|
-
const [website, details] = yield Promise.all([
|
|
386
|
+
var _a, _b, _c, _d, _e, _f;
|
|
387
|
+
const [website, cors, details] = yield Promise.all([
|
|
380
388
|
// 204 "No Content" is returned when there is no existing website config
|
|
381
389
|
wrapS3Call(`read the bucket website config`, [200, 204], () => bucket.client.send(new GetBucketWebsiteCommand({ Bucket: bucket.name }))),
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
// bucket.client.send(new GetBucketCorsCommand({ Bucket: bucket.name })),
|
|
385
|
-
// ),
|
|
390
|
+
// 404 is returned when there are no existing CORS rules
|
|
391
|
+
wrapS3Call(`read the bucket CORS config`, [200, 404], () => getBucketCors(bucket)),
|
|
386
392
|
getBucketFilesDetails(bucket, files),
|
|
387
393
|
]);
|
|
388
394
|
// Collect object redirects
|
|
@@ -393,8 +399,7 @@ export function getBucketConfig(bucket, files) {
|
|
|
393
399
|
}
|
|
394
400
|
}
|
|
395
401
|
// Interpret bucket redirects
|
|
396
|
-
if (website.RedirectAllRequestsTo
|
|
397
|
-
"HostName" in website.RedirectAllRequestsTo) {
|
|
402
|
+
if (website.RedirectAllRequestsTo) {
|
|
398
403
|
// NB: garage does not currently support RedirectAllRequestsTo so this should never happen
|
|
399
404
|
throw new ErrorMsg(`remote website configuration: RedirectAllRequestsTo is specified; ` +
|
|
400
405
|
`this is currently unsupported by dxfl`);
|
|
@@ -468,16 +473,16 @@ export function getBucketConfig(bucket, files) {
|
|
|
468
473
|
}
|
|
469
474
|
// Interpret CORS rules
|
|
470
475
|
let cors_rules = [];
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
476
|
+
if (cors.CORSRules) {
|
|
477
|
+
for (const rule of cors.CORSRules) {
|
|
478
|
+
cors_rules.push({
|
|
479
|
+
allowed_origins: (_c = rule.AllowedOrigins) !== null && _c !== void 0 ? _c : [],
|
|
480
|
+
allowed_methods: (_d = rule.AllowedMethods) !== null && _d !== void 0 ? _d : [],
|
|
481
|
+
allowed_headers: (_e = rule.AllowedHeaders) !== null && _e !== void 0 ? _e : [],
|
|
482
|
+
expose_headers: (_f = rule.ExposeHeaders) !== null && _f !== void 0 ? _f : [],
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
481
486
|
// Interpret headers
|
|
482
487
|
let headers = new Map();
|
|
483
488
|
for (const [file, { headers: file_headers }] of details) {
|
|
@@ -493,6 +498,25 @@ export function getBucketConfig(bucket, files) {
|
|
|
493
498
|
};
|
|
494
499
|
});
|
|
495
500
|
}
|
|
501
|
+
function getBucketCors(bucket) {
|
|
502
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
503
|
+
var _a;
|
|
504
|
+
try {
|
|
505
|
+
return yield bucket.client.send(new GetBucketCorsCommand({ Bucket: bucket.name }));
|
|
506
|
+
}
|
|
507
|
+
catch (e) {
|
|
508
|
+
if (e instanceof S3ServiceException && ((_a = e.$response) === null || _a === void 0 ? void 0 : _a.statusCode) == 404) {
|
|
509
|
+
return {
|
|
510
|
+
CORSRules: [],
|
|
511
|
+
$metadata: e.$metadata,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
throw e;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
496
520
|
////////////// Applying a configuration to S3
|
|
497
521
|
// applies the bucket-wide part of the website configuration
|
|
498
522
|
export function putBucketWebsiteConfig(bucket, index_page, error_page, bucket_redirects) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dxfl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "dxfl",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.7.0",
|
|
10
10
|
"license": "EUPL-1.2",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@aws-sdk/client-s3": "^3.1014.0",
|
|
@@ -865,13 +865,14 @@
|
|
|
865
865
|
}
|
|
866
866
|
},
|
|
867
867
|
"node_modules/@aws-sdk/xml-builder": {
|
|
868
|
-
"version": "3.972.
|
|
869
|
-
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.
|
|
870
|
-
"integrity": "sha512-
|
|
868
|
+
"version": "3.972.21",
|
|
869
|
+
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.21.tgz",
|
|
870
|
+
"integrity": "sha512-qxNiHUtlrsjTeSlrPWiFkWps7uD6YB4eKzg7eLAFH8jbiHTlt0ePNlo2Xu+WlftP38JIcMaIX4jTUjOlE2ySWw==",
|
|
871
871
|
"license": "Apache-2.0",
|
|
872
872
|
"dependencies": {
|
|
873
|
-
"@
|
|
874
|
-
"
|
|
873
|
+
"@nodable/entities": "2.1.0",
|
|
874
|
+
"@smithy/types": "^4.14.1",
|
|
875
|
+
"fast-xml-parser": "5.7.2",
|
|
875
876
|
"tslib": "^2.6.2"
|
|
876
877
|
},
|
|
877
878
|
"engines": {
|
|
@@ -910,6 +911,18 @@
|
|
|
910
911
|
"commander": "~14.0.0"
|
|
911
912
|
}
|
|
912
913
|
},
|
|
914
|
+
"node_modules/@nodable/entities": {
|
|
915
|
+
"version": "2.1.0",
|
|
916
|
+
"resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz",
|
|
917
|
+
"integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==",
|
|
918
|
+
"funding": [
|
|
919
|
+
{
|
|
920
|
+
"type": "github",
|
|
921
|
+
"url": "https://github.com/sponsors/nodable"
|
|
922
|
+
}
|
|
923
|
+
],
|
|
924
|
+
"license": "MIT"
|
|
925
|
+
},
|
|
913
926
|
"node_modules/@smithy/abort-controller": {
|
|
914
927
|
"version": "4.2.12",
|
|
915
928
|
"resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.12.tgz",
|
|
@@ -1399,9 +1412,9 @@
|
|
|
1399
1412
|
}
|
|
1400
1413
|
},
|
|
1401
1414
|
"node_modules/@smithy/types": {
|
|
1402
|
-
"version": "4.
|
|
1403
|
-
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.
|
|
1404
|
-
"integrity": "sha512-
|
|
1415
|
+
"version": "4.14.1",
|
|
1416
|
+
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz",
|
|
1417
|
+
"integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==",
|
|
1405
1418
|
"license": "Apache-2.0",
|
|
1406
1419
|
"dependencies": {
|
|
1407
1420
|
"tslib": "^2.6.2"
|
|
@@ -1799,9 +1812,9 @@
|
|
|
1799
1812
|
"license": "BSD-3-Clause"
|
|
1800
1813
|
},
|
|
1801
1814
|
"node_modules/fast-xml-builder": {
|
|
1802
|
-
"version": "1.1.
|
|
1803
|
-
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.
|
|
1804
|
-
"integrity": "sha512-
|
|
1815
|
+
"version": "1.1.5",
|
|
1816
|
+
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz",
|
|
1817
|
+
"integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==",
|
|
1805
1818
|
"funding": [
|
|
1806
1819
|
{
|
|
1807
1820
|
"type": "github",
|
|
@@ -1814,9 +1827,9 @@
|
|
|
1814
1827
|
}
|
|
1815
1828
|
},
|
|
1816
1829
|
"node_modules/fast-xml-parser": {
|
|
1817
|
-
"version": "5.
|
|
1818
|
-
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.
|
|
1819
|
-
"integrity": "sha512-
|
|
1830
|
+
"version": "5.7.2",
|
|
1831
|
+
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.2.tgz",
|
|
1832
|
+
"integrity": "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==",
|
|
1820
1833
|
"funding": [
|
|
1821
1834
|
{
|
|
1822
1835
|
"type": "github",
|
|
@@ -1825,9 +1838,10 @@
|
|
|
1825
1838
|
],
|
|
1826
1839
|
"license": "MIT",
|
|
1827
1840
|
"dependencies": {
|
|
1828
|
-
"
|
|
1829
|
-
"
|
|
1830
|
-
"
|
|
1841
|
+
"@nodable/entities": "^2.1.0",
|
|
1842
|
+
"fast-xml-builder": "^1.1.5",
|
|
1843
|
+
"path-expression-matcher": "^1.5.0",
|
|
1844
|
+
"strnum": "^2.2.3"
|
|
1831
1845
|
},
|
|
1832
1846
|
"bin": {
|
|
1833
1847
|
"fxparser": "src/cli/cli.js"
|
|
@@ -1854,7 +1868,9 @@
|
|
|
1854
1868
|
"hasInstallScript": true,
|
|
1855
1869
|
"license": "MIT",
|
|
1856
1870
|
"optional": true,
|
|
1857
|
-
"os": [
|
|
1871
|
+
"os": [
|
|
1872
|
+
"darwin"
|
|
1873
|
+
],
|
|
1858
1874
|
"engines": {
|
|
1859
1875
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
1860
1876
|
}
|
|
@@ -1944,7 +1960,9 @@
|
|
|
1944
1960
|
"version": "4.1.0",
|
|
1945
1961
|
"resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz",
|
|
1946
1962
|
"integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==",
|
|
1947
|
-
"funding": [
|
|
1963
|
+
"funding": [
|
|
1964
|
+
"https://github.com/sponsors/broofa"
|
|
1965
|
+
],
|
|
1948
1966
|
"license": "MIT",
|
|
1949
1967
|
"bin": {
|
|
1950
1968
|
"mime": "bin/cli.js"
|
|
@@ -1992,9 +2010,9 @@
|
|
|
1992
2010
|
}
|
|
1993
2011
|
},
|
|
1994
2012
|
"node_modules/path-expression-matcher": {
|
|
1995
|
-
"version": "1.
|
|
1996
|
-
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.
|
|
1997
|
-
"integrity": "sha512-
|
|
2013
|
+
"version": "1.5.0",
|
|
2014
|
+
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz",
|
|
2015
|
+
"integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==",
|
|
1998
2016
|
"funding": [
|
|
1999
2017
|
{
|
|
2000
2018
|
"type": "github",
|
|
@@ -2118,9 +2136,9 @@
|
|
|
2118
2136
|
}
|
|
2119
2137
|
},
|
|
2120
2138
|
"node_modules/strnum": {
|
|
2121
|
-
"version": "2.2.
|
|
2122
|
-
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.
|
|
2123
|
-
"integrity": "sha512-
|
|
2139
|
+
"version": "2.2.3",
|
|
2140
|
+
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz",
|
|
2141
|
+
"integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==",
|
|
2124
2142
|
"funding": [
|
|
2125
2143
|
{
|
|
2126
2144
|
"type": "github",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dxfl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "EUPL-1.2",
|
|
6
6
|
"author": "Deuxfleurs Team <coucou@deuxfleurs.fr>",
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
"node": ">=20.0.0"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
+
"build": "npx tsc && npm link",
|
|
21
|
+
"dev": "npm link && npx onchange \"**/*.ts\" -- npx tsc",
|
|
20
22
|
"prepare": "npx tsc",
|
|
21
23
|
"prettier": "npx prettier . --write",
|
|
22
|
-
"prettier-watch": "npx
|
|
24
|
+
"prettier-watch": "npx onchange \"**/*\" -- npx prettier --write --ignore-unknown {{changed}}",
|
|
23
25
|
"prettier-check": "npx prettier . --check"
|
|
24
26
|
},
|
|
25
27
|
"dependencies": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
toto
|
package/public/d/b
ADDED
package/public/d/c
ADDED
package/public/d/dd/bla
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bla
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
test
|
package/public/def
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
oops, 404 error!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hello there! 花見 toto312
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hello there! 花見 toto2
|
|
Binary file
|
package/public/slt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abc
|
package/public/test.html
ADDED
|
File without changes
|
package/public/toto.jpg
ADDED
|
File without changes
|
package/public/toto.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abc defuieu
|
package/public/toto2.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abc
|
package/dist/_empty.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// // TODO: Refacto the codebase global before integrate this feature
|
|
2
|
-
export {};
|
|
3
|
-
// export async function empty(
|
|
4
|
-
// vhost: string,
|
|
5
|
-
// options: { dryRun: boolean | undefined },
|
|
6
|
-
// ) {
|
|
7
|
-
// const conf = await openApiConf();
|
|
8
|
-
// // Get website info from guichet (bucket name and keys)
|
|
9
|
-
// const api = new WebsiteApi(conf);
|
|
10
|
-
// let vhostInfo = await api.getWebsite({ vhost }).catch(err => {
|
|
11
|
-
// if (err.response.status == 404) {
|
|
12
|
-
// console.error(`Error: website '${vhost}' does not exist`);
|
|
13
|
-
// } else {
|
|
14
|
-
// console.error(err);
|
|
15
|
-
// }
|
|
16
|
-
// process.exit(1);
|
|
17
|
-
// });
|
|
18
|
-
// // List the files currently stored in the bucket
|
|
19
|
-
// // @FIXME this info could be returned by the guichet API
|
|
20
|
-
// const s3client = new S3Client({
|
|
21
|
-
// endpoint: "https://garage.deuxfleurs.fr",
|
|
22
|
-
// region: "garage",
|
|
23
|
-
// forcePathStyle: true,
|
|
24
|
-
// credentials: {
|
|
25
|
-
// accessKeyId: vhostInfo.accessKeyId!,
|
|
26
|
-
// secretAccessKey: vhostInfo.secretAccessKey!,
|
|
27
|
-
// },
|
|
28
|
-
// });
|
|
29
|
-
// const Bucket = vhostInfo.vhost!.name!;
|
|
30
|
-
// const filesToDelete = [...(await getBucketFiles(s3client, Bucket))].map(
|
|
31
|
-
// ([name, { size }]) => ({
|
|
32
|
-
// name,
|
|
33
|
-
// size,
|
|
34
|
-
// }),
|
|
35
|
-
// );
|
|
36
|
-
// for (const file of filesToDelete) {
|
|
37
|
-
// process.stdout.write(`Deleting ${file.name}\n`);
|
|
38
|
-
// }
|
|
39
|
-
// // If not in dry-run mode, send the delete command
|
|
40
|
-
// if (!options.dryRun) {
|
|
41
|
-
// const resp = await deleteFiles(s3client, Bucket, filesToDelete);
|
|
42
|
-
// if (resp && resp!.$metadata.httpStatusCode != 200) {
|
|
43
|
-
// // TODO: better error handling?
|
|
44
|
-
// console.error(resp);
|
|
45
|
-
// process.exit(1);
|
|
46
|
-
// }
|
|
47
|
-
// }
|
|
48
|
-
// // Display a summary
|
|
49
|
-
// function sum(a: number[]) {
|
|
50
|
-
// return a.reduce((x, y) => x + y, 0);
|
|
51
|
-
// }
|
|
52
|
-
// function formatFiles(n: number) {
|
|
53
|
-
// if (n == 1) {
|
|
54
|
-
// return `${n} file `;
|
|
55
|
-
// } else {
|
|
56
|
-
// return `${n} files`;
|
|
57
|
-
// }
|
|
58
|
-
// }
|
|
59
|
-
// const sizeDeleted = sum(filesToDelete.map(f => f.size ?? 0));
|
|
60
|
-
// process.stdout.write("\nSummary:\n");
|
|
61
|
-
// process.stdout.write(
|
|
62
|
-
// `${formatFiles(filesToDelete.length)} deleted (${formatBytes(sizeDeleted)})\n`,
|
|
63
|
-
// );
|
|
64
|
-
// }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["../auth.ts","../bucket.ts","../deploy.ts","../empty.ts","../error.ts","../guichet.ts","../headers.ts","../index.ts","../inspect.ts","../utils.ts","../vhosts.ts","../website_config.ts"],"version":"5.9.3"}
|