miqro 7.2.9 → 7.3.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.
@@ -7,6 +7,7 @@ interface MiqroJSON {
7
7
  browser?: string | boolean;
8
8
  logFile?: string | boolean;
9
9
  editor?: boolean;
10
+ etag?: boolean;
10
11
  https?: boolean;
11
12
  serverOptions?: ServerOptions;
12
13
  httpsRedirect?: number;
@@ -23,6 +24,7 @@ export interface Arguments {
23
24
  inflateFlat?: boolean;
24
25
  name?: string;
25
26
  noBuild?: boolean;
27
+ etag?: boolean;
26
28
  noMinify?: boolean;
27
29
  browser?: string | boolean;
28
30
  logFile?: string | boolean;
@@ -16,6 +16,7 @@ const MiqroJSONSchema = {
16
16
  type: "object",
17
17
  properties: {
18
18
  name: "string?",
19
+ etag: "boolean?",
19
20
  services: "string[]?",
20
21
  noBuild: "boolean?",
21
22
  noMinify: "boolean?",
@@ -53,6 +54,7 @@ export function parseArguments() {
53
54
  const args = cluster.isPrimary ? process.argv.slice(2, process.argv.length) : process.argv.slice(3, process.argv.length);
54
55
  const flags = {
55
56
  inflateFlat: null,
57
+ etag: null,
56
58
  inflateOnlyAssets: null,
57
59
  inflateParallel: null,
58
60
  httpsRedirect: null,
@@ -182,6 +184,22 @@ export function parseArguments() {
182
184
  }
183
185
  flags.install = true;
184
186
  continue;
187
+ case "--disable-etag":
188
+ if (flags.etag !== null) {
189
+ console.error("bad arguments.");
190
+ console.error(usage);
191
+ process.exit(EXIT_CODES.BAD_ARGUMENTS);
192
+ }
193
+ flags.etag = false;
194
+ continue;
195
+ case "--enable-etag":
196
+ if (flags.etag !== null) {
197
+ console.error("bad arguments.");
198
+ console.error(usage);
199
+ process.exit(EXIT_CODES.BAD_ARGUMENTS);
200
+ }
201
+ flags.etag = true;
202
+ continue;
185
203
  case "--watch":
186
204
  if (flags.watch !== null) {
187
205
  console.error("bad arguments.");
@@ -542,6 +560,11 @@ export function parseArguments() {
542
560
  flags.https = miqroRC.https;
543
561
  }
544
562
  }
563
+ if (flags.etag === null) {
564
+ if (miqroRC.etag !== undefined) {
565
+ flags.etag = miqroRC.etag;
566
+ }
567
+ }
545
568
  if (flags.httpsRedirect === null) {
546
569
  if (miqroRC.httpsRedirect && flags.https) {
547
570
  /*console.log("reading key from " + String(miqroRC.serverOptions?.key));
@@ -692,6 +715,7 @@ export function parseArguments() {
692
715
  process.exit(EXIT_CODES.BAD_ARGUMENTS);
693
716
  }
694
717
  return {
718
+ etag: flags.etag !== null ? flags.etag : true,
695
719
  inflateFlat: flags.inflateFlat === null ? false : flags.inflateFlat,
696
720
  inflateOnlyAssets: flags.inflateOnlyAssets === null ? undefined : flags.inflateOnlyAssets,
697
721
  noMinify: flags.noMinify === null ? false : flags.noMinify,
@@ -1,3 +1,3 @@
1
1
  export declare const BIN_NAME = "miqro";
2
2
  export declare const usage = "usage: miqro [...FLAGS] --service app/\n\n==examples==\n\nmiqro --watch --service front/\nPORT=8181 miqro --service api/ --service front/\nmiqro --test --service front/\nmiqro --inflate --service front/\nmiqro --generate-doc --generate-doc-out API.md --service front/\nCLUSTER_COUNT=10 miqro-cluster --service api/";
3
- export declare const help = "\n==flags==\n\n-v, --version\n\toutputs the version number\n-h, --help\n\toutputs this page.\n--watch\n\tuse to auto reload the server when files change.\n--hot-reload\n\tenables the hot-reload functionality use with --watch.\n--test\n\trun the tests for a service.\n--migrate-up\n\tmigrations up.\n--migrate-down\n\tmigrations down.\n--inflate\n\tinflates the application into a directory using esbuild.\n--inflate-dir\n\tto set the output directory of the --inflate command. default value is inflated/.\n--editor\n\truns the application with a built-in editor.\n--generate-doc\n\tgenerates a documentation for the api endpoints of the service.\n--generate-doc-out\n\tthe output file for the generated documentation. default value is API.md.\n--generate-doc-type\n\tthe format of the generated documentation. it can be JSON or MD. default value is MD.\n--generate-doc-all\n\toutputs all the server routes in the documentation output.\n--compile\n\tinflates the application and tries to create a NODE SEA binary.\n--no-build\n\tdisables calling esbuild during imports in runtime. Notice that to use jsx you will need to run tsc or esbuild on your jsx files to transpile them to js.\n--no-minify\n\tdisables calling minifing min.js files.\n--inflate-only-assets\n\tinflates ONLY the application assets. must be used with --inflate.\n--inflate-flat\n\tinflates files into the inflate-dir directly.\n--inflate-sea\n\tinflates the application with sea compilation scripts.\n--install-tsconfig\n\tcreates a tsconfig.json configured to use with --install-types.\n--install-miqrojson\n\tcreates a default miqro.json file.\n--install\n\tcreates a node_modules folder from binary cache (only available in sea binary).\n--disable-miqrojson\n\tdisables the load of miqro.json file.\n--log-file\n\toverrides the default log file from LOG_FILE.\n--browser\n\toverrides the default browser from BROWSER.\n--config\n\toverrides the default miqro.json path.\n--port\n\toverrides the default port from PORT.\n--name\n\toverrides the default name of the server.\n--https\n\tserves the server in https instead of http\n--https-key\n\tpoint to a server.key file for https.\n--https-cert\n\tpoint to a server.cert file for https.\n--https-redirect\n\tserves an aditional http server that redirects to https. it needs a port number.\n--inflate-parallel\n\tsets the max parallel esbuild instances. defaults to 1.\n\n==environment variables==\n\nPORT\n\toverride the default 8080 port.\nBROWSER\n\toverride the default browser. change to none to disable.\".\nLOG_FILE\n\toverride the default ./server.log file\nDB\n\tenable the server.db features\nDB_STORAGE\n\toverride the default local db location ./db.sqlite3\nDB_DIALECT\n\toverride the default node:sqlite\nDB_CONNECTION\n\toverride the default connection url\nCLEAR_JSX_CACHE\n\tset to 1 or 0 to enable or disable the clearing of the esbuild cache defaults to 1.\nJSX_TMP\n\tset custom location of esbuild builds defaults to /tmp/jsx_tmp.\n";
3
+ export declare const help = "\n==flags==\n\n-v, --version\n\toutputs the version number\n-h, --help\n\toutputs this page.\n--disable-etag\n\tuse to disable etag generation by default. each route can still enable this.\n--enable-etag\n\tuse to enable etag generation by default. each route can still disable this. ( by default etag is enabled )\n--watch\n\tuse to auto reload the server when files change.\n--hot-reload\n\tenables the hot-reload functionality use with --watch.\n--test\n\trun the tests for a service.\n--migrate-up\n\tmigrations up.\n--migrate-down\n\tmigrations down.\n--inflate\n\tinflates the application into a directory using esbuild.\n--inflate-dir\n\tto set the output directory of the --inflate command. default value is inflated/.\n--editor\n\truns the application with a built-in editor.\n--generate-doc\n\tgenerates a documentation for the api endpoints of the service.\n--generate-doc-out\n\tthe output file for the generated documentation. default value is API.md.\n--generate-doc-type\n\tthe format of the generated documentation. it can be JSON or MD. default value is MD.\n--generate-doc-all\n\toutputs all the server routes in the documentation output.\n--compile\n\tinflates the application and tries to create a NODE SEA binary.\n--no-build\n\tdisables calling esbuild during imports in runtime. Notice that to use jsx you will need to run tsc or esbuild on your jsx files to transpile them to js.\n--no-minify\n\tdisables calling minifing min.js files.\n--inflate-only-assets\n\tinflates ONLY the application assets. must be used with --inflate.\n--inflate-flat\n\tinflates files into the inflate-dir directly.\n--inflate-sea\n\tinflates the application with sea compilation scripts.\n--install-tsconfig\n\tcreates a tsconfig.json configured to use with --install-types.\n--install-miqrojson\n\tcreates a default miqro.json file.\n--install\n\tcreates a node_modules folder from binary cache (only available in sea binary).\n--disable-miqrojson\n\tdisables the load of miqro.json file.\n--log-file\n\toverrides the default log file from LOG_FILE.\n--browser\n\toverrides the default browser from BROWSER.\n--config\n\toverrides the default miqro.json path.\n--port\n\toverrides the default port from PORT.\n--name\n\toverrides the default name of the server.\n--https\n\tserves the server in https instead of http\n--https-key\n\tpoint to a server.key file for https.\n--https-cert\n\tpoint to a server.cert file for https.\n--https-redirect\n\tserves an aditional http server that redirects to https. it needs a port number.\n--inflate-parallel\n\tsets the max parallel esbuild instances. defaults to 1.\n\n==environment variables==\n\nPORT\n\toverride the default 8080 port.\nBROWSER\n\toverride the default browser. change to none to disable.\".\nLOG_FILE\n\toverride the default ./server.log file\nDB\n\tenable the server.db features\nDB_STORAGE\n\toverride the default local db location ./db.sqlite3\nDB_DIALECT\n\toverride the default node:sqlite\nDB_CONNECTION\n\toverride the default connection url\nCLEAR_JSX_CACHE\n\tset to 1 or 0 to enable or disable the clearing of the esbuild cache defaults to 1.\nJSX_TMP\n\tset custom location of esbuild builds defaults to /tmp/jsx_tmp.\n";
@@ -15,6 +15,8 @@ export const help = `
15
15
 
16
16
  -v, --version\n\toutputs the version number
17
17
  -h, --help\n\toutputs this page.
18
+ --disable-etag\n\tuse to disable etag generation by default. each route can still enable this.
19
+ --enable-etag\n\tuse to enable etag generation by default. each route can still disable this. ( by default etag is enabled )
18
20
  --watch\n\tuse to auto reload the server when files change.
19
21
  --hot-reload\n\tenables the hot-reload functionality use with --watch.
20
22
  --test\n\trun the tests for a service.
@@ -17,7 +17,7 @@ export async function encryptJWT(payload, secret, options) {
17
17
  .setIssuer(options?.iss ? options?.iss : 'urn:example:issuer')
18
18
  .setAudience(options?.aud ? options?.aud : 'urn:example:audience')
19
19
  .setExpirationTime(options?.exp ? options?.exp : '2h');
20
- return await en.encrypt(secret, options?.options);
20
+ return en.encrypt(secret, options?.options);
21
21
  }
22
22
  /**
23
23
  * decrypts a JWT token with jose
@@ -27,7 +27,7 @@ export async function encryptJWT(payload, secret, options) {
27
27
  * @returns
28
28
  */
29
29
  export async function decryptJWT(jwt, secret, options) {
30
- return await joseJWTDecrypt(jwt, secret, options);
30
+ return joseJWTDecrypt(jwt, secret, options);
31
31
  }
32
32
  /**
33
33
  * verify a JWT token with jose
@@ -37,7 +37,7 @@ export async function decryptJWT(jwt, secret, options) {
37
37
  * @returns
38
38
  */
39
39
  export async function verifyJWT(jwt, secret, options) {
40
- return await jwtVerify(jwt, secret, options);
40
+ return jwtVerify(jwt, secret, options);
41
41
  }
42
42
  /**
43
43
  * creates a signed JWT with jose
@@ -86,7 +86,7 @@ async function createStaticRoute(inflateJSXOptions, service, logger, router, dir
86
86
  }
87
87
  // router.use(assertGlobalTampered);
88
88
  router.get(path, async function (_req, res) {
89
- await new Promise((resolve, reject) => {
89
+ return new Promise((resolve, reject) => {
90
90
  try {
91
91
  readFile(file.filePath, async (err, body) => {
92
92
  if (err) {
@@ -94,14 +94,13 @@ async function createStaticRoute(inflateJSXOptions, service, logger, router, dir
94
94
  }
95
95
  else {
96
96
  try {
97
- await res.asyncEnd({
97
+ resolve({
98
98
  status: 200,
99
99
  headers: {
100
100
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
101
101
  },
102
102
  body
103
103
  });
104
- resolve();
105
104
  }
106
105
  catch (e) {
107
106
  reject(e);
@@ -113,6 +112,10 @@ async function createStaticRoute(inflateJSXOptions, service, logger, router, dir
113
112
  reject(e);
114
113
  }
115
114
  });
115
+ }, {
116
+ response: {
117
+ etag: true
118
+ }
116
119
  });
117
120
  resolve();
118
121
  }
@@ -250,13 +253,13 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
250
253
  // router.use(assertGlobalTampered);
251
254
  router.use(async function (req, res) {
252
255
  const JSON = await getJSON(req, res, newURL(req.path), module.apiOptions?.basePath, module.default);
253
- return res.asyncEnd({
256
+ return {
254
257
  status: 200,
255
258
  headers: {
256
259
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
257
260
  },
258
261
  body: JSON
259
- });
262
+ };
260
263
  }, r.path, r.method, r.options);
261
264
  }
262
265
  return resolve();
@@ -310,13 +313,13 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
310
313
  router.use(async function (req, res) {
311
314
  const toRender = typeof module.default === "function" ? module.default(req, res) : module.default;
312
315
  const HTML = await getHTML(hotreload, req, res, newURL(req.path), module.apiOptions?.basePath, await toRender);
313
- return res.asyncEnd({
316
+ return {
314
317
  status: 200,
315
318
  headers: {
316
319
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
317
320
  },
318
321
  body: HTML
319
- });
322
+ };
320
323
  }, r.path, r.method, r.options);
321
324
  }
322
325
  return resolve();
@@ -364,13 +367,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
364
367
  }
365
368
  // router.use(assertGlobalTampered);
366
369
  router.get(path, async function (req, res) {
367
- return res.asyncEnd({
370
+ return {
368
371
  status: 200,
369
372
  headers: {
370
373
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
371
374
  },
372
375
  body: code
373
- });
376
+ };
377
+ }, {
378
+ response: {
379
+ etag: true
380
+ }
374
381
  });
375
382
  return resolve();
376
383
  }
@@ -413,13 +420,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
413
420
  }
414
421
  // router.use(assertGlobalTampered);
415
422
  router.get(path, async function (_req, res) {
416
- res.asyncEnd({
423
+ return {
417
424
  status: 200,
418
425
  headers: {
419
426
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
420
427
  },
421
428
  body: code
422
- });
429
+ };
430
+ }, {
431
+ response: {
432
+ etag: true
433
+ }
423
434
  });
424
435
  return resolve();
425
436
  }
@@ -472,13 +483,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
472
483
  }
473
484
  // router.use(assertGlobalTampered);
474
485
  router.get(path, async function (_req, res) {
475
- res.asyncEnd({
486
+ return {
476
487
  status: 200,
477
488
  headers: {
478
489
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
479
490
  },
480
491
  body: code
481
- });
492
+ };
493
+ }, {
494
+ response: {
495
+ etag: true
496
+ }
482
497
  });
483
498
  return resolve();
484
499
  }
@@ -529,13 +544,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
529
544
  }
530
545
  // router.use(assertGlobalTampered);
531
546
  router.get(path, async function (_req, res) {
532
- res.asyncEnd({
547
+ return {
533
548
  status: 200,
534
549
  headers: {
535
550
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
536
551
  },
537
552
  body: code
538
- });
553
+ };
554
+ }, {
555
+ response: {
556
+ etag: true
557
+ }
539
558
  });
540
559
  return resolve();
541
560
  }
@@ -16,6 +16,7 @@ async function main(args) {
16
16
  else {
17
17
  const app = new Miqro({
18
18
  editor: args.editor,
19
+ etag: args.etag,
19
20
  name: args.name ? args.name : undefined,
20
21
  port: args.test ? TEST_SOCKET : args.port,
21
22
  services: args.services,
@@ -24,6 +24,7 @@ export interface MiqroOptions extends ImportJSXFileOptions {
24
24
  hotreload?: boolean;
25
25
  watch?: boolean;
26
26
  serverOptions?: ServerOptions<any, any>;
27
+ etag?: boolean;
27
28
  https?: boolean;
28
29
  httpRedirect?: number;
29
30
  noMinify?: boolean;
@@ -47,6 +47,7 @@ export class Miqro {
47
47
  constructor(options) {
48
48
  this.options = {
49
49
  noMinify: false,
50
+ etag: true,
50
51
  editor: false,
51
52
  name: "server",
52
53
  noBuild: false,
@@ -374,6 +375,7 @@ export class Miqro {
374
375
  this.logger?.error(e);
375
376
  }
376
377
  },
378
+ etag: this.options?.etag ?? true,
377
379
  loggerFactory: this.loggerProvider.requestLoggerFactory,
378
380
  serverOptions: this.options?.serverOptions,
379
381
  https: this.options?.https
@@ -19,7 +19,9 @@ export function getRoutes(prePath, defaultPath, apiOptions) {
19
19
  parser: apiOptions?.parser,
20
20
  policy: apiOptions?.policy,
21
21
  request: apiOptions?.request,
22
- response: apiOptions?.response,
22
+ response: apiOptions?.response ?? {
23
+ etag: true
24
+ },
23
25
  session: apiOptions?.session
24
26
  },
25
27
  inflatePath: defaultInflatePath,
@@ -42,7 +44,9 @@ export function getRoutes(prePath, defaultPath, apiOptions) {
42
44
  parser: apiOptions?.parser,
43
45
  policy: apiOptions?.policy,
44
46
  request: apiOptions?.request,
45
- response: apiOptions?.response,
47
+ response: apiOptions?.response ?? {
48
+ etag: true
49
+ },
46
50
  session: apiOptions?.session
47
51
  },
48
52
  inflatePath: p !== "/" ? join(prePath, p) : defaultInflatePath,
package/build/lib.cjs CHANGED
@@ -1013,31 +1013,37 @@ function ResultParser(options, parser4) {
1013
1013
  }
1014
1014
  };
1015
1015
  }
1016
- async function ResponseHandler(req, res) {
1017
- req.logger.trace("results [%o]", req.results);
1018
- if (!req.results || req.results.length === 0) {
1019
- throw new Error(`no response to send. Is your handler returning a value differente than boolean 'true|false' ?`);
1020
- } else {
1021
- const lastResult = req.results[req.results.length - 1];
1022
- req.logger.debug("response [%o]", lastResult);
1023
- if (lastResult !== void 0) {
1024
- const headers = lastResult.headers;
1025
- const body = lastResult.body;
1026
- const status = lastResult.status;
1027
- const noContentType = headers && !headers["Content-Type"] || !headers;
1028
- if (noContentType) {
1029
- await res.json(body, headers, status);
1016
+ function ResponseHandler(options) {
1017
+ const isEtagEnabled = options?.etag !== void 0;
1018
+ return async function ResponseHandler2(req, res) {
1019
+ req.logger.trace("results [%o]", req.results);
1020
+ if (!req.results || req.results.length === 0) {
1021
+ throw new Error(`no response to send. Is your handler returning a value differente than boolean 'true|false' ?`);
1022
+ } else {
1023
+ const lastResult = req.results[req.results.length - 1];
1024
+ req.logger.debug("response [%o]", lastResult);
1025
+ if (lastResult !== void 0) {
1026
+ let headers = lastResult.headers;
1027
+ const body = lastResult.body;
1028
+ const status = lastResult.status;
1029
+ const noContentType = headers && !headers["Content-Type"] || !headers;
1030
+ if (options?.etag !== void 0) {
1031
+ res.setETag(options?.etag);
1032
+ }
1033
+ if (noContentType) {
1034
+ await res.json(body, headers, status);
1035
+ } else {
1036
+ await res.asyncEnd({
1037
+ body,
1038
+ headers,
1039
+ status
1040
+ });
1041
+ }
1030
1042
  } else {
1031
- await res.asyncEnd({
1032
- body,
1033
- headers,
1034
- status
1035
- });
1043
+ throw new Error(`no response to send. Is your handler returning a value different than boolean 'true|false' ?`);
1036
1044
  }
1037
- } else {
1038
- throw new Error(`no response to send. Is your handler returning a value different than boolean 'true|false' ?`);
1039
1045
  }
1040
- }
1046
+ };
1041
1047
  }
1042
1048
  function parsePart(req, part, value, args, mode, parser4) {
1043
1049
  for (let i = 0; i < args.length; i++) {
@@ -1349,6 +1355,9 @@ function isMinimalRouter(obj) {
1349
1355
  function defineRoute(route) {
1350
1356
  return route;
1351
1357
  }
1358
+ function defaultETag({ body }) {
1359
+ return body ? `"${(0, import_node_crypto.createHash)("sha1").update(body instanceof Buffer ? body : typeof body === "object" ? JSON.stringify(body) : String(body)).digest("hex").slice(0, 16)}"` : null;
1360
+ }
1352
1361
  function pathPartTokenize(token) {
1353
1362
  const isWild = token.value[0] === ":";
1354
1363
  const optional = token.value[token.value.length - 1] === "?";
@@ -1452,12 +1461,12 @@ function parseSearchParams(search) {
1452
1461
  });
1453
1462
  return query;
1454
1463
  }
1455
- var import_cookie2, import_crypto, import_http, LoggerErrorEvent, GroupPolicySchema, SessionHandlerOptionsOptionsSchema, SessionHandlerOptionsSchema, OptionalSchema, OptionalSchemaWithBoolean, OptionalParserModeSchema, RouteOptionsSchema, RouterHandlerOptionsSchema, HandlerWithOptionsSchema, MinimalRouterSchema, APIRouteSchema, Request, Response, splitPath;
1464
+ var import_cookie2, import_node_crypto, import_node_http, LoggerErrorEvent, GroupPolicySchema, SessionHandlerOptionsOptionsSchema, SessionHandlerOptionsSchema, OptionalSchema, OptionalSchemaWithBoolean, OptionalParserModeSchema, RouteOptionsSchema, RouterHandlerOptionsSchema, HandlerWithOptionsSchema, MinimalRouterSchema, APIRouteSchema, Request, Response, splitPath;
1456
1465
  var init_types = __esm({
1457
1466
  "node_modules/@miqro/core/build/types.js"() {
1458
1467
  import_cookie2 = __toESM(require_dist(), 1);
1459
- import_crypto = require("crypto");
1460
- import_http = require("http");
1468
+ import_node_crypto = require("node:crypto");
1469
+ import_node_http = require("node:http");
1461
1470
  init_session();
1462
1471
  LoggerErrorEvent = class extends Event {
1463
1472
  constructor(event, init) {
@@ -1548,6 +1557,7 @@ var init_types = __esm({
1548
1557
  response: {
1549
1558
  type: "object?|boolean?",
1550
1559
  properties: {
1560
+ etag: "boolean?|function?",
1551
1561
  status: "number[]!?",
1552
1562
  headers: OptionalSchema,
1553
1563
  headersMode: OptionalParserModeSchema,
@@ -1624,7 +1634,7 @@ var init_types = __esm({
1624
1634
  init: "function?"
1625
1635
  }
1626
1636
  };
1627
- Request = class extends import_http.IncomingMessage {
1637
+ Request = class extends import_node_http.IncomingMessage {
1628
1638
  constructor(socket) {
1629
1639
  super(socket);
1630
1640
  this.logger = console;
@@ -1636,7 +1646,7 @@ var init_types = __esm({
1636
1646
  this.params = /* @__PURE__ */ Object.create(null);
1637
1647
  this.results = [];
1638
1648
  this.startMS = Date.now();
1639
- this.uuid = (0, import_crypto.randomUUID)();
1649
+ this.uuid = (0, import_node_crypto.randomUUID)();
1640
1650
  let vURL;
1641
1651
  Object.defineProperty(this, "url", {
1642
1652
  get: () => {
@@ -1680,12 +1690,16 @@ var init_types = __esm({
1680
1690
  });
1681
1691
  }
1682
1692
  };
1683
- Response = class _Response extends import_http.ServerResponse {
1693
+ Response = class _Response extends import_node_http.ServerResponse {
1684
1694
  //logger: Logger;
1685
1695
  constructor(req) {
1686
1696
  super(req);
1697
+ this.useETag = false;
1687
1698
  this.removeHeader("Date");
1688
1699
  }
1700
+ setETag(useETag) {
1701
+ this.useETag = useETag;
1702
+ }
1689
1703
  async redirect(url, headers, status) {
1690
1704
  return this.asyncEnd({
1691
1705
  status: status !== void 0 ? status : 302,
@@ -1778,18 +1792,35 @@ var init_types = __esm({
1778
1792
  if (this.headersSent) {
1779
1793
  return Promise.reject(new Error("already ended"));
1780
1794
  }
1781
- return new Promise((resolve24, reject) => {
1795
+ return new Promise(async (resolve24, reject) => {
1782
1796
  try {
1783
1797
  if (this.headersSent) {
1784
1798
  reject(new Error("already ended"));
1799
+ return;
1785
1800
  } else {
1786
1801
  const body = args ? args.body : void 0;
1802
+ const nBody = body !== void 0 ? body instanceof Buffer ? body : String(body) : null;
1787
1803
  if (args !== void 0) {
1788
1804
  const { status, headers } = args;
1789
1805
  const nStatus = status !== void 0 ? parseInt(String(status), 10) : 200;
1790
1806
  if (isNaN(nStatus)) {
1791
1807
  reject(new Error("status not a number!"));
1808
+ return;
1792
1809
  } else {
1810
+ if (this.useETag) {
1811
+ const incomingETag = this.req.headers["if-none-match"];
1812
+ const etag = typeof this.useETag === "function" ? await this.useETag(args) : defaultETag({ body: nBody });
1813
+ if (incomingETag && etag && etag === incomingETag && nStatus >= 200 && nStatus < 300) {
1814
+ this.statusCode = 304;
1815
+ this.setHeader("ETag", etag);
1816
+ this.end(() => {
1817
+ resolve24();
1818
+ });
1819
+ return;
1820
+ } else if (etag) {
1821
+ this.setHeader("ETag", etag);
1822
+ }
1823
+ }
1793
1824
  this.statusCode = nStatus;
1794
1825
  if (headers) {
1795
1826
  const keys = Object.keys(headers);
@@ -1805,7 +1836,6 @@ var init_types = __esm({
1805
1836
  }
1806
1837
  }
1807
1838
  this.setHeader("connection", "close");
1808
- const nBody = body !== void 0 ? body instanceof Buffer ? body : String(body) : null;
1809
1839
  this.end(nBody, () => {
1810
1840
  resolve24();
1811
1841
  });
@@ -2262,6 +2292,9 @@ var init_router = __esm({
2262
2292
  const loggerFactory = this.config && this.config.loggerFactory ? this.config.loggerFactory : routerDefaultLoggerFactory;
2263
2293
  this.listener = async (req, res) => {
2264
2294
  req.logger = loggerFactory(req.uuid, req);
2295
+ if (this.config?.etag !== void 0) {
2296
+ res.setETag(this.config?.etag);
2297
+ }
2265
2298
  req.logger.trace(`request received`);
2266
2299
  await this.run(req, res);
2267
2300
  };
@@ -2416,7 +2449,11 @@ ${tab}${tab}${methodData.description}` : ""}`;
2416
2449
  }
2417
2450
  handlers = handlers.concat(routeHandlers);
2418
2451
  if (this.options && this.options.response && !this.isRouter) {
2419
- const responseMiddleware = typeof this.options.response === "boolean" ? [ResponseHandler] : this.options.response.middleware ? this.options.response.middleware instanceof Array ? this.options.response.middleware : [this.options.response.middleware] : [ResponseHandler];
2452
+ const responseMiddleware = typeof this.options.response === "boolean" ? [ResponseHandler({
2453
+ etag: true
2454
+ })] : this.options.response.middleware ? this.options.response.middleware instanceof Array ? this.options.response.middleware : [this.options.response.middleware] : [ResponseHandler({
2455
+ etag: this.options?.response?.etag !== void 0 ? this.options?.response?.etag : true
2456
+ })];
2420
2457
  if (typeof this.options.response !== "boolean") {
2421
2458
  handlers.push(ResultParser(this.options.response, this.options.parser));
2422
2459
  }
@@ -2518,14 +2555,14 @@ ${tab}${tab}${methodData.description}` : ""}`;
2518
2555
  });
2519
2556
 
2520
2557
  // node_modules/@miqro/core/build/app.js
2521
- var import_http2, import_https, import_crypto2, App;
2558
+ var import_http, import_https, import_crypto, App;
2522
2559
  var init_app = __esm({
2523
2560
  "node_modules/@miqro/core/build/app.js"() {
2524
- import_http2 = require("http");
2561
+ import_http = require("http");
2525
2562
  import_https = require("https");
2526
2563
  init_router();
2527
2564
  init_common();
2528
- import_crypto2 = require("crypto");
2565
+ import_crypto = require("crypto");
2529
2566
  App = class extends Router2 {
2530
2567
  constructor(config) {
2531
2568
  super(config);
@@ -2544,6 +2581,9 @@ var init_app = __esm({
2544
2581
  const logger = loggerFactory(req.uuid, req);
2545
2582
  try {
2546
2583
  req.logger = logger;
2584
+ if (this.config?.etag !== void 0) {
2585
+ res.setETag(this.config?.etag);
2586
+ }
2547
2587
  try {
2548
2588
  req.logger.trace(`request received for [%s]`, req.path);
2549
2589
  if (this.shouldCloseConnection) {
@@ -2581,10 +2621,10 @@ var init_app = __esm({
2581
2621
  console.error(loggerError);
2582
2622
  }
2583
2623
  };
2584
- const createS = config && config.https ? import_https.createServer : import_http2.createServer;
2624
+ const createS = config && config.https ? import_https.createServer : import_http.createServer;
2585
2625
  this.httpServer = createS(this.serverOptions, this.listener);
2586
2626
  this.httpServer.on("connection", (conn) => {
2587
- const key = (0, import_crypto2.randomUUID)();
2627
+ const key = (0, import_crypto.randomUUID)();
2588
2628
  this.connections[key] = conn;
2589
2629
  conn.on("close", () => {
2590
2630
  delete this.connections[key];
@@ -2670,7 +2710,7 @@ var init_app = __esm({
2670
2710
 
2671
2711
  // node_modules/@miqro/core/build/websocket.js
2672
2712
  function createUpgradeHeaders(acceptKey, extraHeaders) {
2673
- const acceptValue = (0, import_crypto3.createHash)("sha1").update(acceptKey + GUID, "binary").digest("base64");
2713
+ const acceptValue = (0, import_crypto2.createHash)("sha1").update(acceptKey + GUID, "binary").digest("base64");
2674
2714
  let extra = extraHeaders && extraHeaders.length > 0 ? `\r
2675
2715
  ${extraHeaders.map((h) => `${h.name}: ${h.value}`).join("\r\n")}` : "";
2676
2716
  return `HTTP/1.1 101 Switching Protocols\r
@@ -2746,10 +2786,10 @@ function createFrame(payload) {
2746
2786
  buffer.write(payload, payloadBytesOffset);
2747
2787
  return buffer;
2748
2788
  }
2749
- var import_crypto3, WebSocketServer, PING, OPCODES, GUID, DEFAULT_MAX_FRAME_SIZE;
2789
+ var import_crypto2, WebSocketServer, PING, OPCODES, GUID, DEFAULT_MAX_FRAME_SIZE;
2750
2790
  var init_websocket = __esm({
2751
2791
  "node_modules/@miqro/core/build/websocket.js"() {
2752
- import_crypto3 = require("crypto");
2792
+ import_crypto2 = require("crypto");
2753
2793
  WebSocketServer = class {
2754
2794
  constructor(options) {
2755
2795
  this.options = options;
@@ -2825,7 +2865,7 @@ var init_websocket = __esm({
2825
2865
  return;
2826
2866
  } else {
2827
2867
  const validateRet = this.options.validate ? await this.options.validate(req) : true;
2828
- const uuid = typeof validateRet === "boolean" ? validateRet ? (0, import_crypto3.randomUUID)() : null : typeof validateRet === "object" ? validateRet.uuid : validateRet ? (0, import_crypto3.randomUUID)() : null;
2868
+ const uuid = typeof validateRet === "boolean" ? validateRet ? (0, import_crypto2.randomUUID)() : null : typeof validateRet === "object" ? validateRet.uuid : validateRet ? (0, import_crypto2.randomUUID)() : null;
2829
2869
  const extraHeaders = typeof validateRet === "object" ? validateRet.headers : void 0;
2830
2870
  if (!uuid) {
2831
2871
  req.logger.debug("validating failed with result [%s]", validateRet);
@@ -9052,7 +9092,7 @@ var DEFAULT_BUILD_DIR = (0, import_os.tmpdir)();
9052
9092
 
9053
9093
  // src/common/jsx.ts
9054
9094
  var import_node_path6 = require("node:path");
9055
- var import_node_crypto3 = require("node:crypto");
9095
+ var import_node_crypto4 = require("node:crypto");
9056
9096
  init_lib();
9057
9097
  init_lib3();
9058
9098
  var import_node_process3 = require("node:process");
@@ -9066,7 +9106,7 @@ var import_node_sea = require("node:sea");
9066
9106
  var import_node_path3 = require("node:path");
9067
9107
 
9068
9108
  // src/common/checksum.ts
9069
- var import_node_crypto = require("node:crypto");
9109
+ var import_node_crypto2 = require("node:crypto");
9070
9110
  var import_node_fs2 = require("node:fs");
9071
9111
  async function calculateChecksum(filePath) {
9072
9112
  return calculateChecksumFromStream((0, import_node_fs2.createReadStream)(filePath));
@@ -9074,7 +9114,7 @@ async function calculateChecksum(filePath) {
9074
9114
  async function calculateChecksumFromStream(input) {
9075
9115
  return new Promise((resolve24, reject) => {
9076
9116
  try {
9077
- const hash = (0, import_node_crypto.createHash)("sha256");
9117
+ const hash = (0, import_node_crypto2.createHash)("sha256");
9078
9118
  input.on("readable", () => {
9079
9119
  const data = input.read();
9080
9120
  if (data)
@@ -9094,7 +9134,7 @@ async function calculateChecksumFromStream(input) {
9094
9134
  async function calculateChecksumFromBuffer(buffer) {
9095
9135
  return new Promise((resolve24, reject) => {
9096
9136
  try {
9097
- const hash = (0, import_node_crypto.createHash)("sha256");
9137
+ const hash = (0, import_node_crypto2.createHash)("sha256");
9098
9138
  hash.update(buffer);
9099
9139
  resolve24(hash.digest("hex").toString());
9100
9140
  } catch (e) {
@@ -9298,13 +9338,13 @@ async function initAsset(logger, path, buffer, executable, checksum, logInstalla
9298
9338
 
9299
9339
  // src/common/paths.ts
9300
9340
  init_lib3();
9301
- var import_node_crypto2 = require("node:crypto");
9341
+ var import_node_crypto3 = require("node:crypto");
9302
9342
  var import_node_fs5 = require("node:fs");
9303
9343
  var import_node_os = require("node:os");
9304
9344
  var import_node_path4 = require("node:path");
9305
9345
  var import_node_process2 = require("node:process");
9306
9346
  var JSX_TMP_DIR = checkEnvVariable(`JSX_TMP`, (0, import_node_path4.resolve)((0, import_node_os.tmpdir)(), "jsx_tmp"));
9307
- var TEST_SOCKET = (0, import_node_path4.resolve)(JSX_TMP_DIR, `test.${(0, import_node_crypto2.randomUUID)()}.sock`);
9347
+ var TEST_SOCKET = (0, import_node_path4.resolve)(JSX_TMP_DIR, `test.${(0, import_node_crypto3.randomUUID)()}.sock`);
9308
9348
  function getServicePath(service) {
9309
9349
  return (0, import_node_path4.resolve)((0, import_node_process2.cwd)(), service);
9310
9350
  }
@@ -9461,7 +9501,7 @@ function JSXTemplate(inFile, useExport = true) {
9461
9501
  return `${useExport ? `export * from "${inFile}";import * as lib from "${inFile}";export default lib.default;` : `import * as lib from "${inFile}"`}`;
9462
9502
  }
9463
9503
  async function inflateJSX(inFile, options) {
9464
- const tmpBuildDir = (0, import_node_path6.resolve)(JSX_TMP_DIR, String(process.pid), "build", Date.now() + "-" + (0, import_node_crypto3.randomUUID)());
9504
+ const tmpBuildDir = (0, import_node_path6.resolve)(JSX_TMP_DIR, String(process.pid), "build", Date.now() + "-" + (0, import_node_crypto4.randomUUID)());
9465
9505
  const inFileTmp = (0, import_node_path6.resolve)(tmpBuildDir, (0, import_node_path6.basename)(inFile) + ".mjs");
9466
9506
  const logger = options.logger;
9467
9507
  try {
@@ -9792,7 +9832,7 @@ async function importJSXFile(inFile, options, logger) {
9792
9832
  platform: "node",
9793
9833
  logger
9794
9834
  });
9795
- const tmpBuildDir = (0, import_node_path6.resolve)(JSX_TMP_DIR, String(process.pid), "import", Date.now() + "-" + (0, import_node_crypto3.randomUUID)());
9835
+ const tmpBuildDir = (0, import_node_path6.resolve)(JSX_TMP_DIR, String(process.pid), "import", Date.now() + "-" + (0, import_node_crypto4.randomUUID)());
9796
9836
  const inFileTmp = (0, import_node_path6.resolve)(tmpBuildDir, (0, import_node_path6.basename)(inFile) + ".cjs");
9797
9837
  await mkdirASync(tmpBuildDir, {
9798
9838
  recursive: true
@@ -12632,7 +12672,9 @@ function getRoutes(prePath, defaultPath, apiOptions) {
12632
12672
  parser: apiOptions?.parser,
12633
12673
  policy: apiOptions?.policy,
12634
12674
  request: apiOptions?.request,
12635
- response: apiOptions?.response,
12675
+ response: apiOptions?.response ?? {
12676
+ etag: true
12677
+ },
12636
12678
  session: apiOptions?.session
12637
12679
  },
12638
12680
  inflatePath: defaultInflatePath,
@@ -12654,7 +12696,9 @@ function getRoutes(prePath, defaultPath, apiOptions) {
12654
12696
  parser: apiOptions?.parser,
12655
12697
  policy: apiOptions?.policy,
12656
12698
  request: apiOptions?.request,
12657
- response: apiOptions?.response,
12699
+ response: apiOptions?.response ?? {
12700
+ etag: true
12701
+ },
12658
12702
  session: apiOptions?.session
12659
12703
  },
12660
12704
  inflatePath: p !== "/" ? (0, import_node_path9.join)(prePath, p) : defaultInflatePath,
@@ -12842,21 +12886,20 @@ async function createStaticRoute(inflateJSXOptions, service, logger, router, dir
12842
12886
  }
12843
12887
  }
12844
12888
  router.get(path, async function(_req, res) {
12845
- await new Promise((resolve25, reject2) => {
12889
+ return new Promise((resolve25, reject2) => {
12846
12890
  try {
12847
12891
  (0, import_node_fs11.readFile)(file.filePath, async (err, body) => {
12848
12892
  if (err) {
12849
12893
  reject2(err);
12850
12894
  } else {
12851
12895
  try {
12852
- await res.asyncEnd({
12896
+ resolve25({
12853
12897
  status: 200,
12854
12898
  headers: {
12855
12899
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
12856
12900
  },
12857
12901
  body
12858
12902
  });
12859
- resolve25();
12860
12903
  } catch (e) {
12861
12904
  reject2(e);
12862
12905
  }
@@ -12866,6 +12909,10 @@ async function createStaticRoute(inflateJSXOptions, service, logger, router, dir
12866
12909
  reject2(e);
12867
12910
  }
12868
12911
  });
12912
+ }, {
12913
+ response: {
12914
+ etag: true
12915
+ }
12869
12916
  });
12870
12917
  resolve24();
12871
12918
  } catch (e) {
@@ -12987,13 +13034,13 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
12987
13034
  }
12988
13035
  router.use(async function(req, res) {
12989
13036
  const JSON2 = await getJSON(req, res, newURL2(req.path), module2.apiOptions?.basePath, module2.default);
12990
- return res.asyncEnd({
13037
+ return {
12991
13038
  status: 200,
12992
13039
  headers: {
12993
13040
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
12994
13041
  },
12995
13042
  body: JSON2
12996
- });
13043
+ };
12997
13044
  }, r.path, r.method, r.options);
12998
13045
  }
12999
13046
  return resolve24();
@@ -13044,13 +13091,13 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
13044
13091
  router.use(async function(req, res) {
13045
13092
  const toRender = typeof module2.default === "function" ? module2.default(req, res) : module2.default;
13046
13093
  const HTML = await getHTML(hotreload, req, res, newURL2(req.path), module2.apiOptions?.basePath, await toRender);
13047
- return res.asyncEnd({
13094
+ return {
13048
13095
  status: 200,
13049
13096
  headers: {
13050
13097
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
13051
13098
  },
13052
13099
  body: HTML
13053
- });
13100
+ };
13054
13101
  }, r.path, r.method, r.options);
13055
13102
  }
13056
13103
  return resolve24();
@@ -13096,13 +13143,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
13096
13143
  }
13097
13144
  }
13098
13145
  router.get(path, async function(req, res) {
13099
- return res.asyncEnd({
13146
+ return {
13100
13147
  status: 200,
13101
13148
  headers: {
13102
13149
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
13103
13150
  },
13104
13151
  body: code
13105
- });
13152
+ };
13153
+ }, {
13154
+ response: {
13155
+ etag: true
13156
+ }
13106
13157
  });
13107
13158
  return resolve24();
13108
13159
  }
@@ -13144,13 +13195,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
13144
13195
  }
13145
13196
  }
13146
13197
  router.get(path, async function(_req, res) {
13147
- res.asyncEnd({
13198
+ return {
13148
13199
  status: 200,
13149
13200
  headers: {
13150
13201
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
13151
13202
  },
13152
13203
  body: code
13153
- });
13204
+ };
13205
+ }, {
13206
+ response: {
13207
+ etag: true
13208
+ }
13154
13209
  });
13155
13210
  return resolve24();
13156
13211
  }
@@ -13202,13 +13257,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
13202
13257
  }
13203
13258
  }
13204
13259
  router.get(path, async function(_req, res) {
13205
- res.asyncEnd({
13260
+ return {
13206
13261
  status: 200,
13207
13262
  headers: {
13208
13263
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
13209
13264
  },
13210
13265
  body: code
13211
- });
13266
+ };
13267
+ }, {
13268
+ response: {
13269
+ etag: true
13270
+ }
13212
13271
  });
13213
13272
  return resolve24();
13214
13273
  }
@@ -13252,13 +13311,17 @@ async function createRouterFromDirectory(importOptions, inflateJSXOptions, serve
13252
13311
  }
13253
13312
  }
13254
13313
  router.get(path, async function(_req, res) {
13255
- res.asyncEnd({
13314
+ return {
13256
13315
  status: 200,
13257
13316
  headers: {
13258
13317
  ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
13259
13318
  },
13260
13319
  body: code
13261
- });
13320
+ };
13321
+ }, {
13322
+ response: {
13323
+ etag: true
13324
+ }
13262
13325
  });
13263
13326
  return resolve24();
13264
13327
  }
@@ -14055,7 +14118,7 @@ init_constants();
14055
14118
  init_constants();
14056
14119
 
14057
14120
  // editor/auth.ts
14058
- var import_node_crypto4 = require("node:crypto");
14121
+ var import_node_crypto5 = require("node:crypto");
14059
14122
  var ADMIN_EDITOR_AUTH_KEY = "$$ADMIN_EDITOR_AUTH_KEY$$";
14060
14123
  var ADMIN_EDITOR_AUTH_QUERY = "key";
14061
14124
  var ADMIN_EDITOR_AUTH_COOKIE = ADMIN_EDITOR_AUTH_KEY;
@@ -14074,7 +14137,7 @@ var auth_default = {
14074
14137
  const queryToken = args.req.query[ADMIN_EDITOR_AUTH_QUERY];
14075
14138
  const cookieToken = args.req.cookies[ADMIN_EDITOR_AUTH_COOKIE];
14076
14139
  if (queryToken) {
14077
- if (typeof queryToken === "string" && (0, import_node_crypto4.timingSafeEqual)(Buffer.from(queryToken), Buffer.from(KEY))) {
14140
+ if (typeof queryToken === "string" && (0, import_node_crypto5.timingSafeEqual)(Buffer.from(queryToken), Buffer.from(KEY))) {
14078
14141
  args.res.setCookie(ADMIN_EDITOR_AUTH_COOKIE, KEY, {
14079
14142
  expires: new Date(Date.now() + 1e3 * 60 * 60 * 24 * 31 * 12 * 500),
14080
14143
  httpOnly: true,
@@ -14109,7 +14172,7 @@ var ws_default = {
14109
14172
  };
14110
14173
 
14111
14174
  // editor/server.ts
14112
- var import_node_crypto5 = require("node:crypto");
14175
+ var import_node_crypto6 = require("node:crypto");
14113
14176
  init_constants();
14114
14177
  var import_node_fs17 = require("node:fs");
14115
14178
  var import_node_path18 = require("node:path");
@@ -14124,7 +14187,7 @@ var server_default = {
14124
14187
  serverInterface.logger.warn("loading static ADMIN_KEY from [%s]", (0, import_node_path18.relative)(process.cwd(), adminKEYPath));
14125
14188
  cache2.set(ADMIN_EDITOR_AUTH_KEY, (0, import_node_fs17.readFileSync)(adminKEYPath).toString().trim());
14126
14189
  } else {
14127
- cache2.set(ADMIN_EDITOR_AUTH_KEY, (0, import_node_crypto5.randomUUID)());
14190
+ cache2.set(ADMIN_EDITOR_AUTH_KEY, (0, import_node_crypto6.randomUUID)());
14128
14191
  }
14129
14192
  }
14130
14193
  }
@@ -17048,13 +17111,13 @@ async function encryptJWT(payload, secret, options) {
17048
17111
  alg: options?.alg ? options?.alg : "dir",
17049
17112
  enc: options?.enc ? options?.enc : "A128CBC-HS256"
17050
17113
  }).setIssuedAt(options?.iat).setIssuer(options?.iss ? options?.iss : "urn:example:issuer").setAudience(options?.aud ? options?.aud : "urn:example:audience").setExpirationTime(options?.exp ? options?.exp : "2h");
17051
- return await en.encrypt(secret, options?.options);
17114
+ return en.encrypt(secret, options?.options);
17052
17115
  }
17053
17116
  async function decryptJWT(jwt2, secret, options) {
17054
- return await jwtDecrypt(jwt2, secret, options);
17117
+ return jwtDecrypt(jwt2, secret, options);
17055
17118
  }
17056
17119
  async function verifyJWT(jwt2, secret, options) {
17057
- return await jwtVerify(jwt2, secret, options);
17120
+ return jwtVerify(jwt2, secret, options);
17058
17121
  }
17059
17122
  async function signJWT(payload, secret, options) {
17060
17123
  const sign2 = new SignJWT(payload).setProtectedHeader({
@@ -17070,9 +17133,9 @@ function decodeJWT(jwt2) {
17070
17133
  }
17071
17134
 
17072
17135
  // src/services/utils/jwt.ts
17073
- var import_node_crypto6 = require("node:crypto");
17136
+ var import_node_crypto7 = require("node:crypto");
17074
17137
  var jwt = {
17075
- createSecretKey: import_node_crypto6.createSecretKey,
17138
+ createSecretKey: import_node_crypto7.createSecretKey,
17076
17139
  decode(jwt2) {
17077
17140
  return decodeJWT(jwt2);
17078
17141
  },
@@ -17208,6 +17271,7 @@ var MiqroJSONSchema = {
17208
17271
  type: "object",
17209
17272
  properties: {
17210
17273
  name: "string?",
17274
+ etag: "boolean?",
17211
17275
  services: "string[]?",
17212
17276
  noBuild: "boolean?",
17213
17277
  noMinify: "boolean?",
@@ -17346,6 +17410,7 @@ var Miqro = class _Miqro {
17346
17410
  constructor(options) {
17347
17411
  this.options = {
17348
17412
  noMinify: false,
17413
+ etag: true,
17349
17414
  editor: false,
17350
17415
  name: "server",
17351
17416
  noBuild: false,
@@ -17637,6 +17702,7 @@ var Miqro = class _Miqro {
17637
17702
  this.logger?.error(e);
17638
17703
  }
17639
17704
  },
17705
+ etag: this.options?.etag ?? true,
17640
17706
  loggerFactory: this.loggerProvider.requestLoggerFactory,
17641
17707
  serverOptions: this.options?.serverOptions,
17642
17708
  https: this.options?.https
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miqro",
3
- "version": "7.2.9",
3
+ "version": "7.3.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "build/esm/src/lib.js",
@@ -11,12 +11,12 @@
11
11
  "pretest": "npm run build",
12
12
  "test": "BROWSER=none node --enable-source-maps --test test/cases/*.test.js",
13
13
  "coverage": "BROWSER=none node --enable-source-maps --experimental-test-coverage --test test/cases/*.test.js",
14
- "prepare": "npm run build",
14
+ "prepare2": "npm run build",
15
15
  "release:package": "sh sea/release-tar.sh",
16
16
  "prerelease:package": "npm run compile",
17
17
  "prebuild": "rm -Rf build/;",
18
18
  "build": "tsc",
19
- "postbuild": "npm run postbuild:lib && npm run postbuild:sh && npm run postbuild:assets && npm run postbuild:editor && npm run postbuild:editor-assets && npm run postbuild:versiontag",
19
+ "postbuild": "npm run postbuild:lib && npm run postbuild:editor && npm run postbuild:editor-assets && npm run postbuild:versiontag",
20
20
  "postbuild:versiontag": "node sea/version.tag.js",
21
21
  "postbuild:editor-assets": "cp sea/editor-assets/style.css build/style.css",
22
22
  "postbuild:editor": "esbuild --external:node:process --external:node:path --bundle --loader:.js=jsx --jsx-factory=jsx.createElement --jsx-fragment=jsx.Fragment sea/editor-assets/editor.bundle.in.mjs --outfile=build/editor.bundle.js",
@@ -41,10 +41,10 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "postject": "1.0.0-alpha.6",
44
- "@miqro/core": "^5.0.20",
44
+ "@miqro/core": "^5.1.0",
45
45
  "@miqro/jsx": "^1.0.2",
46
46
  "@miqro/jsx-dom": "^1.0.6",
47
- "@miqro/jsx-node": "^1.0.7",
47
+ "@miqro/jsx-node": "^1.0.8",
48
48
  "@miqro/parser": "^2.0.6",
49
49
  "@miqro/query": "^0.0.8",
50
50
  "@miqro/runner": "^2.0.3",
@@ -1 +0,0 @@
1
- IyEvdXNyL2Jpbi9lbnYgc2gKCnJtIC1SZiBiaW47Cm1rZGlyIC1wIGJpbi87CgpzaCAuL2luc3RhbGwtbm9kZWpzLnNoCgpOT0RFX0JJTj0ic2ggc2VhL25vZGUuc2giClNJR05fUkVNT1ZFX0JJTj0ic2ggc2VhL3NpZ24tcmVtb3ZlLnNoIgpTSUdOX0FERF9CSU49InNoIHNlYS9zaWduLWFkZC5zaCIKUE9TVEpFQ1RfQklOPSIke05PREVfQklOfSAuLi9ub2RlX21vZHVsZXMvcG9zdGplY3QvZGlzdC9jbGkuanMiCkVTQlVJTERfQklOPSJzZWEvZXNidWlsZCIKCiMkRVNCVUlMRF9CSU4gc2VhL2FwcC5janMgLS1idW5kbGUgLS1wbGF0Zm9ybT1ub2RlIC0tZXh0ZXJuYWw6c3FsaXRlMyAtLWV4dGVybmFsOnBnIC0tZXh0ZXJuYWw6ZXNidWlsZCAtLW91dGZpbGU9c2VhL2FwcC5idW5kbGUuY2pzCgokTk9ERV9CSU4gLS1leHBlcmltZW50YWwtc2VhLWNvbmZpZyBzZWEvY29uZmlnLmpzb24KClRBUkdFVF9CSU5fTkFNRT0iYXBwIgoKVEFSR0VUX0xJTlVYX1g2ND0iYmluL2xpbnV4LXg2NC8ke1RBUkdFVF9CSU5fTkFNRX0iClRBUkdFVF9MSU5VWF9BUk02ND0iYmluL2xpbnV4LWFybTY0LyR7VEFSR0VUX0JJTl9OQU1FfSIKClRBUkdFVF9EQVJXSU5fQVJNNjQ9ImJpbi9kYXJ3aW4tYXJtNjQvJHtUQVJHRVRfQklOX05BTUV9IgpUQVJHRVRfREFSV0lOX1g2ND0iYmluL2Rhcndpbi14NjQvJHtUQVJHRVRfQklOX05BTUV9IgoKI1RBUkdFVF9XSU5fWDY0PSJiaW4vd2luLXg2NC8ke1RBUkdFVF9CSU5fTkFNRX0uZXhlIgojVEFSR0VUX1dJTl9BUk02ND0iYmluL3dpbi1hcm02NC8ke1RBUkdFVF9CSU5fTkFNRX0uZXhlIgoKbWtkaXIgLXAgYmluL2xpbnV4LXg2NApta2RpciAtcCBiaW4vbGludXgtYXJtNjQKCm1rZGlyIC1wIGJpbi9kYXJ3aW4teDY0Cm1rZGlyIC1wIGJpbi9kYXJ3aW4tYXJtNjQKCiNta2RpciAtcCBiaW4vd2luLXg2NAojbWtkaXIgLXAgYmluL3dpbi1hcm02NAoKY3Agc2VhL2RlcHMvbm9kZWpzL2Rhcndpbi9hcm02NC9ub2RlICIke1RBUkdFVF9EQVJXSU5fQVJNNjR9IgpjcCBzZWEvZGVwcy9ub2RlanMvZGFyd2luL3g2NC9ub2RlICIke1RBUkdFVF9EQVJXSU5fWDY0fSIKCmNwIHNlYS9kZXBzL25vZGVqcy9saW51eC94NjQvbm9kZSAiJHtUQVJHRVRfTElOVVhfWDY0fSIKY3Agc2VhL2RlcHMvbm9kZWpzL2xpbnV4L2FybTY0L25vZGUgIiR7VEFSR0VUX0xJTlVYX0FSTTY0fSIKCiNjcCBzZWEvZGVwcy9ub2RlanMvd2luL3g2NC9ub2RlLmV4ZSAiJHtUQVJHRVRfV0lOX1g2NH0iCiNjcCBzZWEvZGVwcy9ub2RlanMvd2luL3g2NC9ub2RlLmV4ZSAiJHtUQVJHRVRfV0lOX0FSTTY0fSIKCiRTSUdOX1JFTU9WRV9CSU4gIiR7VEFSR0VUX0RBUldJTl9BUk02NH0iCiRTSUdOX1JFTU9WRV9CSU4gIiR7VEFSR0VUX0RBUldJTl9YNjR9IgoKY2htb2QgK3cgIiR7VEFSR0VUX0xJTlVYX0FSTTY0fSIKY2htb2QgK3cgIiR7VEFSR0VUX0xJTlVYX1g2NH0iCgpjaG1vZCArdyAiJHtUQVJHRVRfREFSV0lOX0FSTTY0fSIKY2htb2QgK3cgIiR7VEFSR0VUX0RBUldJTl9YNjR9IgoKI2NobW9kICt3ICIke1RBUkdFVF9XSU5fWDY0fSIKI2NobW9kICt3ICIke1RBUkdFVF9XSU5fQVJNNjR9IgoKQkxPQj0ic2VhL2FwcC5idW5kbGUuYmxvYiIKCmNwIHNlYS9ydW4uc2ggYmluL2FwcC5zaApjaG1vZCAreCBiaW4vYXBwLnNoCgokUE9TVEpFQ1RfQklOICIke1RBUkdFVF9EQVJXSU5fQVJNNjR9IiBOT0RFX1NFQV9CTE9CICR7QkxPQn0gLS1zZW50aW5lbC1mdXNlIE5PREVfU0VBX0ZVU0VfZmNlNjgwYWIyY2M0NjdiNmUwNzJiOGI1ZGYxOTk2YjIgLS1tYWNoby1zZWdtZW50LW5hbWUgTk9ERV9TRUEKJFNJR05fQUREX0JJTiAiJHtUQVJHRVRfREFSV0lOX0FSTTY0fSIKJFBPU1RKRUNUX0JJTiAiJHtUQVJHRVRfREFSV0lOX1g2NH0iIE5PREVfU0VBX0JMT0IgJHtCTE9CfSAtLXNlbnRpbmVsLWZ1c2UgTk9ERV9TRUFfRlVTRV9mY2U2ODBhYjJjYzQ2N2I2ZTA3MmI4YjVkZjE5OTZiMiAtLW1hY2hvLXNlZ21lbnQtbmFtZSBOT0RFX1NFQQokU0lHTl9BRERfQklOICIke1RBUkdFVF9EQVJXSU5fWDY0fSIKCiRQT1NUSkVDVF9CSU4gIiR7VEFSR0VUX0xJTlVYX0FSTTY0fSIgTk9ERV9TRUFfQkxPQiAke0JMT0J9IC0tc2VudGluZWwtZnVzZSBOT0RFX1NFQV9GVVNFX2ZjZTY4MGFiMmNjNDY3YjZlMDcyYjhiNWRmMTk5NmIyCiRQT1NUSkVDVF9CSU4gIiR7VEFSR0VUX0xJTlVYX1g2NH0iIE5PREVfU0VBX0JMT0IgJHtCTE9CfSAtLXNlbnRpbmVsLWZ1c2UgTk9ERV9TRUFfRlVTRV9mY2U2ODBhYjJjYzQ2N2I2ZTA3MmI4YjVkZjE5OTZiMgoKIyRQT1NUSkVDVF9CSU4gIiR7VEFSR0VUX1dJTl9YNjR9IiBOT0RFX1NFQV9CTE9CICR7QkxPQn0gLS1zZW50aW5lbC1mdXNlIE5PREVfU0VBX0ZVU0VfZmNlNjgwYWIyY2M0NjdiNmUwNzJiOGI1ZGYxOTk2YjIKIyRQT1NUSkVDVF9CSU4gIiR7VEFSR0VUX1dJTl9BUk02NH0iIE5PREVfU0VBX0JMT0IgJHtCTE9CfSAtLXNlbnRpbmVsLWZ1c2UgTk9ERV9TRUFfRlVTRV9mY2U2ODBhYjJjYzQ2N2I2ZTA3MmI4YjVkZjE5OTZiMgo=