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 CHANGED
@@ -1,3 +1,4 @@
1
1
  # Ignore artifacts:
2
2
  dist
3
3
  node_modules
4
+ npm-shrinkwrap.json
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 link
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
@@ -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"
@@ -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
- // const cors_changed = !equalCorsRules(
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
- // if (!equalCorsRules(plan.cors_rules.from, plan.cors_rules.to)) {
411
- // await putCorsRules(bucket, plan.cors_rules.to);
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
@@ -0,0 +1,7 @@
1
+ import { err } from "neverthrow";
2
+ export function errMsg(msg) {
3
+ return err({ kind: "msg", msg });
4
+ }
5
+ export function errS3(resp) {
6
+ return err({ kind: "s3", resp: resp.$metadata });
7
+ }
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.6.1");
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.")
@@ -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
- // 204 "No Content" is returned when there are no existing CORS rules
383
- // wrapS3Call(`read the bucket CORS config`, [200, 204], () =>
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
- // if (cors.CORSRules) {
472
- // for (const rule of cors.CORSRules) {
473
- // cors_rules.push({
474
- // allowed_origins: rule.AllowedOrigins ?? [],
475
- // allowed_methods: rule.AllowedMethods ?? [],
476
- // allowed_headers: rule.AllowedHeaders ?? [],
477
- // expose_headers: rule.ExposeHeaders ?? [],
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) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "dxfl",
3
- "version": "0.6.1",
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.6.1",
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.15",
869
- "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.15.tgz",
870
- "integrity": "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA==",
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
- "@smithy/types": "^4.13.1",
874
- "fast-xml-parser": "5.5.8",
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.13.1",
1403
- "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz",
1404
- "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==",
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.4",
1803
- "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
1804
- "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
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.5.8",
1818
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz",
1819
- "integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==",
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
- "fast-xml-builder": "^1.1.4",
1829
- "path-expression-matcher": "^1.2.0",
1830
- "strnum": "^2.2.0"
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": ["darwin"],
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": ["https://github.com/sponsors/broofa"],
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.2.0",
1996
- "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
1997
- "integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==",
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.1",
2122
- "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.1.tgz",
2123
- "integrity": "sha512-BwRvNd5/QoAtyW1na1y1LsJGQNvRlkde6Q/ipqqEaivoMdV+B1OMOTVdwR+N/cwVUcIt9PYyHmV8HyexCZSupg==",
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.6.1",
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 -y onchange \"**/*\" -- npx prettier --write --ignore-unknown {{changed}}",
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
@@ -0,0 +1,2 @@
1
+ b
2
+ foo
package/public/d/c ADDED
@@ -0,0 +1,2 @@
1
+ c
2
+ foo
@@ -0,0 +1 @@
1
+ bla
@@ -0,0 +1 @@
1
+ test
package/public/def ADDED
@@ -0,0 +1,2 @@
1
+ abc
2
+ abc
@@ -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
File without changes
File without changes
@@ -0,0 +1 @@
1
+ abc defuieu
@@ -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"}