@tiddlywiki/mws 0.0.18 → 0.0.20

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/dist/server.js CHANGED
@@ -15,10 +15,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
15
15
  if (typeof require !== "undefined") return require.apply(this, arguments);
16
16
  throw Error('Dynamic require of "' + x + '" is not supported');
17
17
  });
18
- var __glob = (map) => (path5) => {
19
- var fn = map[path5];
18
+ var __glob = (map) => (path6) => {
19
+ var fn = map[path6];
20
20
  if (fn) return fn();
21
- throw new Error("Module not found in bundle: " + path5);
21
+ throw new Error("Module not found in bundle: " + path6);
22
22
  };
23
23
  var __esm = (fn, res) => function __init() {
24
24
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -152,8 +152,8 @@ var init_global = __esm({
152
152
  });
153
153
  };
154
154
  __Result = class __Result {
155
- constructor(ok8, error, value) {
156
- this.ok = ok8;
155
+ constructor(ok7, error, value) {
156
+ this.ok = ok7;
157
157
  this.error = error;
158
158
  this.value = value;
159
159
  }
@@ -195,7 +195,7 @@ var require_depd = __commonJS({
195
195
  "node_modules/depd/index.js"(exports, module2) {
196
196
  "use strict";
197
197
  init_esm_shims();
198
- var relative = __require("path").relative;
198
+ var relative2 = __require("path").relative;
199
199
  module2.exports = depd;
200
200
  var basePath = process.cwd();
201
201
  function containsNamespace(str, namespace) {
@@ -401,7 +401,7 @@ var require_depd = __commonJS({
401
401
  }
402
402
  __name(formatColor, "formatColor");
403
403
  function formatLocation(callSite) {
404
- return relative(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
404
+ return relative2(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
405
405
  }
406
406
  __name(formatLocation, "formatLocation");
407
407
  function getStack() {
@@ -1786,14 +1786,14 @@ var require_etag = __commonJS({
1786
1786
  "use strict";
1787
1787
  init_esm_shims();
1788
1788
  module2.exports = etag;
1789
- var crypto = __require("crypto");
1789
+ var crypto2 = __require("crypto");
1790
1790
  var Stats = __require("fs").Stats;
1791
1791
  var toString = Object.prototype.toString;
1792
1792
  function entitytag(entity) {
1793
1793
  if (entity.length === 0) {
1794
1794
  return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
1795
1795
  }
1796
- var hash = crypto.createHash("sha1").update(entity, "utf8").digest("base64").substring(0, 27);
1796
+ var hash = crypto2.createHash("sha1").update(entity, "utf8").digest("base64").substring(0, 27);
1797
1797
  var len = typeof entity === "string" ? Buffer.byteLength(entity, "utf8") : entity.length;
1798
1798
  return '"' + len.toString(16) + "-" + hash + '"';
1799
1799
  }
@@ -10497,11 +10497,11 @@ var require_mime_types = __commonJS({
10497
10497
  return exts[0];
10498
10498
  }
10499
10499
  __name(extension, "extension");
10500
- function lookup(path5) {
10501
- if (!path5 || typeof path5 !== "string") {
10500
+ function lookup(path6) {
10501
+ if (!path6 || typeof path6 !== "string") {
10502
10502
  return false;
10503
10503
  }
10504
- var extension2 = extname("x." + path5).toLowerCase().substr(1);
10504
+ var extension2 = extname("x." + path6).toLowerCase().substr(1);
10505
10505
  if (!extension2) {
10506
10506
  return false;
10507
10507
  }
@@ -10812,33 +10812,33 @@ var require_send = __commonJS({
10812
10812
  var escapeHtml = require_escape_html();
10813
10813
  var etag = require_etag();
10814
10814
  var fresh = require_fresh();
10815
- var fs3 = __require("fs");
10815
+ var fs4 = __require("fs");
10816
10816
  var mime = require_mime_types();
10817
10817
  var ms = require_ms();
10818
10818
  var onFinished = require_on_finished();
10819
10819
  var parseRange = require_range_parser();
10820
- var path5 = __require("path");
10820
+ var path6 = __require("path");
10821
10821
  var statuses = require_statuses();
10822
10822
  var Stream = __require("stream");
10823
10823
  var util = __require("util");
10824
- var extname = path5.extname;
10825
- var join3 = path5.join;
10826
- var normalize = path5.normalize;
10827
- var resolve13 = path5.resolve;
10828
- var sep2 = path5.sep;
10824
+ var extname = path6.extname;
10825
+ var join4 = path6.join;
10826
+ var normalize2 = path6.normalize;
10827
+ var resolve13 = path6.resolve;
10828
+ var sep2 = path6.sep;
10829
10829
  var BYTES_RANGE_REGEXP = /^ *bytes=/;
10830
10830
  var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
10831
10831
  var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
10832
10832
  module2.exports = send2;
10833
- function send2(req, path6, options) {
10834
- return new SendStream(req, path6, options);
10833
+ function send2(req, path7, options) {
10834
+ return new SendStream(req, path7, options);
10835
10835
  }
10836
10836
  __name(send2, "send");
10837
- function SendStream(req, path6, options) {
10837
+ function SendStream(req, path7, options) {
10838
10838
  Stream.call(this);
10839
10839
  var opts = options || {};
10840
10840
  this.options = opts;
10841
- this.path = path6;
10841
+ this.path = path7;
10842
10842
  this.req = req;
10843
10843
  this._acceptRanges = opts.acceptRanges !== void 0 ? Boolean(opts.acceptRanges) : true;
10844
10844
  this._cacheControl = opts.cacheControl !== void 0 ? Boolean(opts.cacheControl) : true;
@@ -10953,10 +10953,10 @@ var require_send = __commonJS({
10953
10953
  var lastModified = this.res.getHeader("Last-Modified");
10954
10954
  return parseHttpDate(lastModified) <= parseHttpDate(ifRange);
10955
10955
  }, "isRangeFresh");
10956
- SendStream.prototype.redirect = /* @__PURE__ */ __name(function redirect(path6) {
10956
+ SendStream.prototype.redirect = /* @__PURE__ */ __name(function redirect(path7) {
10957
10957
  var res = this.res;
10958
10958
  if (hasListeners(this, "directory")) {
10959
- this.emit("directory", res, path6);
10959
+ this.emit("directory", res, path7);
10960
10960
  return;
10961
10961
  }
10962
10962
  if (this.hasTrailingSlash()) {
@@ -10976,38 +10976,38 @@ var require_send = __commonJS({
10976
10976
  SendStream.prototype.pipe = /* @__PURE__ */ __name(function pipe(res) {
10977
10977
  var root = this._root;
10978
10978
  this.res = res;
10979
- var path6 = decode(this.path);
10980
- if (path6 === -1) {
10979
+ var path7 = decode(this.path);
10980
+ if (path7 === -1) {
10981
10981
  this.error(400);
10982
10982
  return res;
10983
10983
  }
10984
- if (~path6.indexOf("\0")) {
10984
+ if (~path7.indexOf("\0")) {
10985
10985
  this.error(400);
10986
10986
  return res;
10987
10987
  }
10988
10988
  var parts;
10989
10989
  if (root !== null) {
10990
- if (path6) {
10991
- path6 = normalize("." + sep2 + path6);
10990
+ if (path7) {
10991
+ path7 = normalize2("." + sep2 + path7);
10992
10992
  }
10993
- if (UP_PATH_REGEXP.test(path6)) {
10994
- debug('malicious path "%s"', path6);
10993
+ if (UP_PATH_REGEXP.test(path7)) {
10994
+ debug('malicious path "%s"', path7);
10995
10995
  this.error(403);
10996
10996
  return res;
10997
10997
  }
10998
- parts = path6.split(sep2);
10999
- path6 = normalize(join3(root, path6));
10998
+ parts = path7.split(sep2);
10999
+ path7 = normalize2(join4(root, path7));
11000
11000
  } else {
11001
- if (UP_PATH_REGEXP.test(path6)) {
11002
- debug('malicious path "%s"', path6);
11001
+ if (UP_PATH_REGEXP.test(path7)) {
11002
+ debug('malicious path "%s"', path7);
11003
11003
  this.error(403);
11004
11004
  return res;
11005
11005
  }
11006
- parts = normalize(path6).split(sep2);
11007
- path6 = resolve13(path6);
11006
+ parts = normalize2(path7).split(sep2);
11007
+ path7 = resolve13(path7);
11008
11008
  }
11009
11009
  if (containsDotFile(parts)) {
11010
- debug('%s dotfile "%s"', this._dotfiles, path6);
11010
+ debug('%s dotfile "%s"', this._dotfiles, path7);
11011
11011
  switch (this._dotfiles) {
11012
11012
  case "allow":
11013
11013
  break;
@@ -11021,13 +11021,13 @@ var require_send = __commonJS({
11021
11021
  }
11022
11022
  }
11023
11023
  if (this._index.length && this.hasTrailingSlash()) {
11024
- this.sendIndex(path6);
11024
+ this.sendIndex(path7);
11025
11025
  return res;
11026
11026
  }
11027
- this.sendFile(path6);
11027
+ this.sendFile(path7);
11028
11028
  return res;
11029
11029
  }, "pipe");
11030
- SendStream.prototype.send = /* @__PURE__ */ __name(function send3(path6, stat) {
11030
+ SendStream.prototype.send = /* @__PURE__ */ __name(function send3(path7, stat) {
11031
11031
  var len = stat.size;
11032
11032
  var options = this.options;
11033
11033
  var opts = {};
@@ -11039,9 +11039,9 @@ var require_send = __commonJS({
11039
11039
  this.headersAlreadySent();
11040
11040
  return;
11041
11041
  }
11042
- debug('pipe "%s"', path6);
11043
- this.setHeader(path6, stat);
11044
- this.type(path6);
11042
+ debug('pipe "%s"', path7);
11043
+ this.setHeader(path7, stat);
11044
+ this.type(path7);
11045
11045
  if (this.isConditionalGET()) {
11046
11046
  if (this.isPreconditionFailure()) {
11047
11047
  this.error(412);
@@ -11090,30 +11090,30 @@ var require_send = __commonJS({
11090
11090
  res.end();
11091
11091
  return;
11092
11092
  }
11093
- this.stream(path6, opts);
11093
+ this.stream(path7, opts);
11094
11094
  }, "send");
11095
- SendStream.prototype.sendFile = /* @__PURE__ */ __name(function sendFile(path6) {
11095
+ SendStream.prototype.sendFile = /* @__PURE__ */ __name(function sendFile(path7) {
11096
11096
  var i = 0;
11097
11097
  var self = this;
11098
- debug('stat "%s"', path6);
11099
- fs3.stat(path6, /* @__PURE__ */ __name(function onstat(err, stat) {
11100
- var pathEndsWithSep = path6[path6.length - 1] === sep2;
11101
- if (err && err.code === "ENOENT" && !extname(path6) && !pathEndsWithSep) {
11098
+ debug('stat "%s"', path7);
11099
+ fs4.stat(path7, /* @__PURE__ */ __name(function onstat(err, stat) {
11100
+ var pathEndsWithSep = path7[path7.length - 1] === sep2;
11101
+ if (err && err.code === "ENOENT" && !extname(path7) && !pathEndsWithSep) {
11102
11102
  return next(err);
11103
11103
  }
11104
11104
  if (err) return self.onStatError(err);
11105
- if (stat.isDirectory()) return self.redirect(path6);
11105
+ if (stat.isDirectory()) return self.redirect(path7);
11106
11106
  if (pathEndsWithSep) return self.error(404);
11107
- self.emit("file", path6, stat);
11108
- self.send(path6, stat);
11107
+ self.emit("file", path7, stat);
11108
+ self.send(path7, stat);
11109
11109
  }, "onstat"));
11110
11110
  function next(err) {
11111
11111
  if (self._extensions.length <= i) {
11112
11112
  return err ? self.onStatError(err) : self.error(404);
11113
11113
  }
11114
- var p = path6 + "." + self._extensions[i++];
11114
+ var p = path7 + "." + self._extensions[i++];
11115
11115
  debug('stat "%s"', p);
11116
- fs3.stat(p, function(err2, stat) {
11116
+ fs4.stat(p, function(err2, stat) {
11117
11117
  if (err2) return next(err2);
11118
11118
  if (stat.isDirectory()) return next();
11119
11119
  self.emit("file", p, stat);
@@ -11122,7 +11122,7 @@ var require_send = __commonJS({
11122
11122
  }
11123
11123
  __name(next, "next");
11124
11124
  }, "sendFile");
11125
- SendStream.prototype.sendIndex = /* @__PURE__ */ __name(function sendIndex(path6) {
11125
+ SendStream.prototype.sendIndex = /* @__PURE__ */ __name(function sendIndex(path7) {
11126
11126
  var i = -1;
11127
11127
  var self = this;
11128
11128
  function next(err) {
@@ -11130,9 +11130,9 @@ var require_send = __commonJS({
11130
11130
  if (err) return self.onStatError(err);
11131
11131
  return self.error(404);
11132
11132
  }
11133
- var p = join3(path6, self._index[i]);
11133
+ var p = join4(path7, self._index[i]);
11134
11134
  debug('stat "%s"', p);
11135
- fs3.stat(p, function(err2, stat) {
11135
+ fs4.stat(p, function(err2, stat) {
11136
11136
  if (err2) return next(err2);
11137
11137
  if (stat.isDirectory()) return next();
11138
11138
  self.emit("file", p, stat);
@@ -11142,10 +11142,10 @@ var require_send = __commonJS({
11142
11142
  __name(next, "next");
11143
11143
  next();
11144
11144
  }, "sendIndex");
11145
- SendStream.prototype.stream = /* @__PURE__ */ __name(function stream(path6, options) {
11145
+ SendStream.prototype.stream = /* @__PURE__ */ __name(function stream(path7, options) {
11146
11146
  var self = this;
11147
11147
  var res = this.res;
11148
- var stream2 = fs3.createReadStream(path6, options);
11148
+ var stream2 = fs4.createReadStream(path7, options);
11149
11149
  this.emit("stream", stream2);
11150
11150
  stream2.pipe(res);
11151
11151
  function cleanup() {
@@ -11161,17 +11161,17 @@ var require_send = __commonJS({
11161
11161
  self.emit("end");
11162
11162
  }, "onend"));
11163
11163
  }, "stream");
11164
- SendStream.prototype.type = /* @__PURE__ */ __name(function type(path6) {
11164
+ SendStream.prototype.type = /* @__PURE__ */ __name(function type(path7) {
11165
11165
  var res = this.res;
11166
11166
  if (res.getHeader("Content-Type")) return;
11167
- var ext = extname(path6);
11167
+ var ext = extname(path7);
11168
11168
  var type2 = mime.contentType(ext) || "application/octet-stream";
11169
11169
  debug("content-type %s", type2);
11170
11170
  res.setHeader("Content-Type", type2);
11171
11171
  }, "type");
11172
- SendStream.prototype.setHeader = /* @__PURE__ */ __name(function setHeader(path6, stat) {
11172
+ SendStream.prototype.setHeader = /* @__PURE__ */ __name(function setHeader(path7, stat) {
11173
11173
  var res = this.res;
11174
- this.emit("headers", res, path6, stat);
11174
+ this.emit("headers", res, path7, stat);
11175
11175
  if (this._acceptRanges && !res.getHeader("Accept-Ranges")) {
11176
11176
  debug("accept ranges");
11177
11177
  res.setHeader("Accept-Ranges", "bytes");
@@ -11236,9 +11236,9 @@ var require_send = __commonJS({
11236
11236
  return err instanceof Error ? createError(status, err, { expose: false }) : createError(status, err);
11237
11237
  }
11238
11238
  __name(createHttpError, "createHttpError");
11239
- function decode(path6) {
11239
+ function decode(path7) {
11240
11240
  try {
11241
- return decodeURIComponent(path6);
11241
+ return decodeURIComponent(path7);
11242
11242
  } catch (err) {
11243
11243
  return -1;
11244
11244
  }
@@ -14257,7 +14257,7 @@ var init_bag_file_server = __esm({
14257
14257
  if (!recipe_name) {
14258
14258
  return state.sendEmpty(404);
14259
14259
  }
14260
- const bagTiddlers = await this.prisma.recipe_bags.findMany({
14260
+ const bags = await this.prisma.recipe_bags.findMany({
14261
14261
  where: { recipe: { recipe_name } },
14262
14262
  select: {
14263
14263
  position: true,
@@ -14265,36 +14265,28 @@ var init_bag_file_server = __esm({
14265
14265
  select: {
14266
14266
  bag_id: true,
14267
14267
  bag_name: true,
14268
- is_plugin: true,
14269
- tiddlers: {
14270
- select: {
14271
- title: true,
14272
- tiddler_id: true,
14273
- is_deleted: true,
14274
- attachment_hash: true,
14275
- fields: true
14276
- },
14277
- where: {
14278
- is_deleted: false
14279
- }
14280
- }
14268
+ is_plugin: true
14281
14269
  }
14282
14270
  }
14283
14271
  }
14284
14272
  });
14285
- bagTiddlers.sort((a, b) => a.position - b.position);
14286
- const recipeTiddlers = Array.from(new Map(bagTiddlers.flatMap(
14287
- (bag) => bag.bag.tiddlers.map((tiddler) => [tiddler.title, { bag: bag.bag, tiddler }])
14288
- )).values());
14273
+ const lastTiddlerId = await this.prisma.tiddlers.aggregate({
14274
+ _max: { tiddler_id: true },
14275
+ where: { bag_id: { in: bags.map((e) => e.bag.bag_id) } }
14276
+ });
14289
14277
  const template = readFileSync(resolve2(this.state.config.wikiPath, "tiddlywiki5.html"), "utf8");
14290
14278
  const hash = createHash2("md5");
14291
14279
  hash.update(template);
14292
- hash.update(recipeTiddlers.map((e) => e.tiddler.tiddler_id).join("|"));
14280
+ hash.update(bags.map((e) => e.bag.bag_name).join(","));
14281
+ hash.update(`${lastTiddlerId._max.tiddler_id}`);
14293
14282
  const contentDigest = hash.digest("hex");
14283
+ if ('"' + contentDigest + '"' === state.headers["if-none-match"])
14284
+ return state.sendEmpty(304, { "x-reason": "if-none-match" });
14294
14285
  state.writeHead(200, {
14295
14286
  "Content-Type": "text/html",
14296
14287
  "Etag": '"' + contentDigest + '"',
14297
- "Cache-Control": "max-age=0, must-revalidate"
14288
+ // TODO: WHY IS THIS DISABLED???
14289
+ "Cache-Control": "max-age=1000, must-revalidate"
14298
14290
  });
14299
14291
  if (state.method === "HEAD") return state.end();
14300
14292
  var marker = `<script class="tiddlywiki-tiddler-store" type="application/json">[`, markerPos = template.indexOf(marker);
@@ -14306,7 +14298,88 @@ var init_bag_file_server = __esm({
14306
14298
  state.write(",\n");
14307
14299
  }
14308
14300
  __name(writeTiddler, "writeTiddler");
14309
- state.write(template.substring(0, markerPos + marker.length));
14301
+ state.write(template.substring(0, markerPos));
14302
+ if (state.config.enablePluginCache) {
14303
+ const preloadMarkup = `
14304
+ ${"<"}script>
14305
+ window.$tw = window.$tw || Object.create(null);
14306
+ $tw.preloadTiddlers = $tw.preloadTiddlers || [];
14307
+ $tw.preloadTiddler = function(fields) {
14308
+ $tw.preloadTiddlers.push(fields);
14309
+ };
14310
+ ${"</"}script>
14311
+ `;
14312
+ state.write(preloadMarkup);
14313
+ const pluginMarkup = /* @__PURE__ */ __name((plugin, hash2) => `
14314
+ <script
14315
+ src="${state.config.pathPrefix}/$cache/${plugin}/plugin.js"
14316
+ integrity="${hash2}"
14317
+ crossorigin="anonymous"></script>
14318
+ `, "pluginMarkup");
14319
+ const plugins = [...(/* @__PURE__ */ new Set([
14320
+ "$:/core",
14321
+ "$:/plugins/tiddlywiki/multiwikiclient",
14322
+ "$:/plugins/tiddlywiki/tiddlyweb",
14323
+ "$:/themes/tiddlywiki/snowwhite",
14324
+ "$:/themes/tiddlywiki/vanilla",
14325
+ ...bags.map((e) => e.bag.bag_name)
14326
+ ])).values()].filter((e) => state.tiddlerCache.tiddlerFiles.has(e)).map((e) => pluginMarkup(
14327
+ state.tiddlerCache.tiddlerFiles.get(e),
14328
+ state.tiddlerCache.tiddlerHashes.get(e)
14329
+ ));
14330
+ state.write(plugins.join("\n"));
14331
+ }
14332
+ state.write(marker);
14333
+ const bagOrder = new Map(bags.map((e) => [e.bag.bag_id, e.position]));
14334
+ const bagIDs = bags.filter((e) => !state.tiddlerCache.tiddlerFiles.has(e.bag.bag_name)).map((e) => e.bag.bag_id);
14335
+ await this.serveStoreTiddlers(bagIDs, bagOrder, writeTiddler);
14336
+ writeTiddler({
14337
+ title: "$:/config/multiwikiclient/recipe",
14338
+ text: recipe_name
14339
+ });
14340
+ writeTiddler({
14341
+ title: "$:/state/multiwikiclient/recipe/last_tiddler_id",
14342
+ text: (lastTiddlerId._max.tiddler_id ?? 0).toString()
14343
+ });
14344
+ writeTiddler({
14345
+ title: "$:/config/multiwikiclient/host",
14346
+ text: "$protocol$//$host$" + this.state.config.pathPrefix + "/"
14347
+ });
14348
+ state.write(template.substring(markerPos + marker.length));
14349
+ return state.end();
14350
+ }
14351
+ async serveStoreTiddlers(bagKeys, bagOrder, writeTiddler) {
14352
+ const bagTiddlers = await this.prisma.bags.findMany({
14353
+ where: { bag_id: { in: bagKeys } },
14354
+ select: {
14355
+ bag_id: true,
14356
+ bag_name: true,
14357
+ is_plugin: true,
14358
+ description: true,
14359
+ owner_id: true,
14360
+ tiddlers: {
14361
+ select: {
14362
+ title: true,
14363
+ tiddler_id: true,
14364
+ is_deleted: true,
14365
+ attachment_hash: true,
14366
+ fields: true
14367
+ },
14368
+ where: {
14369
+ is_deleted: false
14370
+ }
14371
+ }
14372
+ }
14373
+ });
14374
+ if (!bagTiddlers.every((e) => bagOrder.has(e.bag_id))) {
14375
+ console.log(bagTiddlers.map((e) => e.bag_id));
14376
+ console.log(bagOrder);
14377
+ throw new Error("Bags missing from bag order");
14378
+ }
14379
+ bagTiddlers.sort((a, b) => bagOrder.get(b.bag_id) - bagOrder.get(a.bag_id));
14380
+ const recipeTiddlers = Array.from(new Map(bagTiddlers.flatMap(
14381
+ (bag) => bag.tiddlers.map((tiddler) => [tiddler.title, { bag, tiddler }])
14382
+ )).values());
14310
14383
  const bagInfo = {}, revisionInfo = {};
14311
14384
  for (const recipeTiddlerInfo of recipeTiddlers) {
14312
14385
  const { title, tiddler_id, attachment_hash, fields } = recipeTiddlerInfo.tiddler;
@@ -14335,21 +14408,6 @@ var init_bag_file_server = __esm({
14335
14408
  text: JSON.stringify(revisionInfo),
14336
14409
  type: "application/json"
14337
14410
  });
14338
- writeTiddler({
14339
- title: "$:/config/multiwikiclient/recipe",
14340
- text: recipe_name
14341
- });
14342
- const lastTiddlerId = await this.prisma.tiddlers.aggregate({ _max: { tiddler_id: true } });
14343
- writeTiddler({
14344
- title: "$:/state/multiwikiclient/recipe/last_tiddler_id",
14345
- text: (lastTiddlerId._max.tiddler_id ?? 0).toString()
14346
- });
14347
- writeTiddler({
14348
- title: "$:/config/multiwikiclient/host",
14349
- text: "$protocol$//$host$" + this.state.config.pathPrefix + "/"
14350
- });
14351
- state.write(template.substring(markerPos + marker.length));
14352
- return state.end();
14353
14411
  }
14354
14412
  };
14355
14413
  __name(_TiddlerServer, "TiddlerServer");
@@ -14616,26 +14674,27 @@ var init_router_tiddlers = __esm({
14616
14674
  }
14617
14675
  });
14618
14676
 
14619
- // src/routes/tw-test.ts
14677
+ // src/routes/tw-routes.ts
14620
14678
  import { TiddlyWiki } from "tiddlywiki";
14621
14679
  function DocsRoute(parent, config) {
14622
14680
  const wikiRouter = new TWRouter(config);
14681
+ console.log("The mws-docs tiddlywiki is being served at " + config.pathPrefix + "/mws-docs");
14623
14682
  parent.defineRoute({
14624
14683
  method: ["OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE"],
14625
14684
  bodyFormat: "stream",
14626
- path: /^\/mws(\/|$)/,
14685
+ path: /^\/mwsp-docs(\/|$)/,
14627
14686
  pathParams: []
14628
14687
  }, async (state) => {
14629
- if (state.urlInfo.pathname === "/mws") throw state.redirect("/mws/");
14688
+ if (state.urlInfo.pathname === "/mws-docs") throw state.redirect("/mws-docs/");
14630
14689
  const { req, res } = state.streamer;
14631
- if (req.url === "/mws") req.url = "/mws/";
14690
+ if (req.url === "/mws-docs") req.url = "/mws-docs/";
14632
14691
  wikiRouter.twserver.requestHandler(req, res, {});
14633
14692
  return new Promise((r, c) => res.on("finish", r).on("error", c));
14634
14693
  });
14635
14694
  }
14636
14695
  var _TWRouter, TWRouter;
14637
- var init_tw_test = __esm({
14638
- "src/routes/tw-test.ts"() {
14696
+ var init_tw_routes = __esm({
14697
+ "src/routes/tw-routes.ts"() {
14639
14698
  "use strict";
14640
14699
  init_esm_shims();
14641
14700
  __name(DocsRoute, "DocsRoute");
@@ -14712,7 +14771,6 @@ async function RootRoute(root, config) {
14712
14771
  return state.sendJSON(200, await fn.call(table, state.data.arg));
14713
14772
  });
14714
14773
  });
14715
- await importEsbuild(root);
14716
14774
  }
14717
14775
  async function importEsbuild(root) {
14718
14776
  root.defineRoute({
@@ -14748,7 +14806,7 @@ var init_routes = __esm({
14748
14806
  init_utils2();
14749
14807
  init_managers();
14750
14808
  init_router_tiddlers();
14751
- init_tw_test();
14809
+ init_tw_routes();
14752
14810
  init_();
14753
14811
  __name(RootRoute, "RootRoute");
14754
14812
  __name(importEsbuild, "importEsbuild");
@@ -14932,18 +14990,77 @@ var init_setupDevServer = __esm({
14932
14990
  });
14933
14991
 
14934
14992
  // src/routes/cache.ts
14935
- import { ok as ok4 } from "assert";
14936
- async function startupCache(commander2) {
14993
+ import * as fs2 from "fs";
14994
+ import * as path3 from "path";
14995
+ import * as crypto from "crypto";
14996
+ async function startupCache(rootRoute2, commander2) {
14937
14997
  const $tw2 = commander2.$tw;
14938
- const bootTiddlers = $tw2.loadTiddlersFromPath($tw2.boot.bootPath).flatMap((file) => file.tiddlers);
14939
- const coreTiddler = $tw2.loadPluginFolder($tw2.boot.corePath);
14940
- ok4(coreTiddler);
14941
- const tiddlerMemoryCache = new Map([
14942
- ...bootTiddlers.map((e) => e.title && [e.title, JSON.stringify(e)]).filter(truthy),
14943
- [coreTiddler.title, JSON.stringify(coreTiddler)]
14998
+ console.log(commander2.siteConfig.enablePluginCache);
14999
+ const { tiddlerFiles, tiddlerHashes } = commander2.siteConfig.enablePluginCache ? await importTW5(path3.join($tw2.boot.corePath, ".."), commander2.cachePath, "client", $tw2) : { tiddlerFiles: /* @__PURE__ */ new Map(), tiddlerHashes: /* @__PURE__ */ new Map() };
15000
+ rootRoute2.defineRoute({
15001
+ method: ["GET", "HEAD"],
15002
+ path: /^\/\$cache\/(.*)\/plugin\.js$/,
15003
+ bodyFormat: "ignore",
15004
+ pathParams: ["plugin"]
15005
+ }, async (state) => {
15006
+ ZodAssert.pathParams(state, (z5) => ({
15007
+ plugin: z5.string()
15008
+ }));
15009
+ return state.sendFile(200, {}, {
15010
+ root: commander2.cachePath,
15011
+ reqpath: state.pathParams.plugin + "/plugin.js"
15012
+ });
15013
+ });
15014
+ return { tiddlerFiles, tiddlerHashes };
15015
+ }
15016
+ async function importTW5(twFolder, cacheFolder, type, $tw2) {
15017
+ const readLevel = /* @__PURE__ */ __name((d) => {
15018
+ return fs2.readdirSync(path3.join(twFolder, d)).filter((e) => !$tw2.boot.excludeRegExp.test(e)).map((e) => path3.join(d, e));
15019
+ }, "readLevel");
15020
+ const plugins = [
15021
+ ...[
15022
+ ...[
15023
+ "plugins",
15024
+ "themes"
15025
+ ].flatMap(readLevel),
15026
+ "languages"
15027
+ ].flatMap(readLevel),
15028
+ "core"
15029
+ ].map((e) => {
15030
+ const oldPath = path3.join(twFolder, e);
15031
+ const relativePluginPath = path3.normalize(path3.relative(twFolder, oldPath));
15032
+ return [oldPath, relativePluginPath];
15033
+ });
15034
+ plugins.push([
15035
+ dist_resolve("../plugins/client"),
15036
+ "plugins/mws/client"
14944
15037
  ]);
14945
- const tiddlerFileCache = /* @__PURE__ */ new Map();
14946
- return { tiddlerFileCache, tiddlerMemoryCache };
15038
+ const hashes = {};
15039
+ const tiddlerFiles = /* @__PURE__ */ new Map();
15040
+ const tiddlerHashes = /* @__PURE__ */ new Map();
15041
+ plugins.forEach(([oldPath, relativePluginPath]) => {
15042
+ const plugin = $tw2.loadPluginFolder(oldPath);
15043
+ const newPath = path3.join(cacheFolder, relativePluginPath);
15044
+ fs2.mkdirSync(newPath, { recursive: true });
15045
+ if (plugin && plugin.title) {
15046
+ plugin.text = JSON.stringify(JSON.parse(plugin.text));
15047
+ if (type === "server") {
15048
+ plugin.tiddlers = JSON.parse(plugin.text).tiddlers;
15049
+ delete plugin.text;
15050
+ fs2.writeFileSync(path3.join(newPath, "plugin.info"), JSON.stringify(plugin));
15051
+ } else if (type === "client") {
15052
+ let js = Buffer.from(`$tw.preloadTiddler(${JSON.stringify(plugin)});`, "utf8");
15053
+ let hash = crypto.createHash("sha384").update(js).digest("base64");
15054
+ fs2.writeFileSync(path3.join(newPath, "plugin.js"), js);
15055
+ tiddlerFiles.set(plugin.title, relativePluginPath);
15056
+ tiddlerHashes.set(plugin.title, "sha384-" + hash);
15057
+ }
15058
+ } else {
15059
+ console.log("Info: No plugin found at", oldPath);
15060
+ }
15061
+ });
15062
+ fs2.writeFileSync(path3.join(cacheFolder, "hashes.json"), JSON.stringify(hashes, null, 2));
15063
+ return { tiddlerFiles, tiddlerHashes };
14947
15064
  }
14948
15065
  var init_cache = __esm({
14949
15066
  "src/routes/cache.ts"() {
@@ -14951,6 +15068,7 @@ var init_cache = __esm({
14951
15068
  init_esm_shims();
14952
15069
  init_utils2();
14953
15070
  __name(startupCache, "startupCache");
15071
+ __name(importTW5, "importTW5");
14954
15072
  }
14955
15073
  });
14956
15074
 
@@ -14971,10 +15089,10 @@ function defineRoute(parent, route, handler) {
14971
15089
  route.handler = handler;
14972
15090
  return route;
14973
15091
  }
14974
- function zodRoute(method, path5, zodPathParams, bodyFormat, zodRequest, inner) {
15092
+ function zodRoute(method, path6, zodPathParams, bodyFormat, zodRequest, inner) {
14975
15093
  return {
14976
15094
  method,
14977
- path: path5,
15095
+ path: path6,
14978
15096
  bodyFormat,
14979
15097
  inner,
14980
15098
  zodRequest,
@@ -15045,21 +15163,22 @@ var init_router = __esm({
15045
15163
  });
15046
15164
  await commander2.SessionManager.defineRoutes(rootRoute2);
15047
15165
  await RootRoute(rootRoute2, commander2.siteConfig);
15048
- const cache = await startupCache(commander2);
15166
+ const cache = await startupCache(rootRoute2, commander2);
15167
+ await importEsbuild(rootRoute2);
15049
15168
  return new _Router(rootRoute2, commander2, cache);
15050
15169
  }
15051
15170
  get pathPrefix() {
15052
15171
  return this.siteConfig.pathPrefix;
15053
15172
  }
15054
15173
  handleIncomingRequest(req, res) {
15055
- const [ok8, err, streamer] = function() {
15174
+ const [ok7, err, streamer] = function() {
15056
15175
  try {
15057
15176
  return [true, void 0, new Streamer(req, res, this)];
15058
15177
  } catch (e) {
15059
15178
  return [false, e, void 0];
15060
15179
  }
15061
15180
  }.call(this);
15062
- if (!ok8) {
15181
+ if (!ok7) {
15063
15182
  if (err === STREAM_ENDED) return;
15064
15183
  res.writeHead(500, { "x-reason": "handle incoming request" }).end();
15065
15184
  throw err;
@@ -15178,11 +15297,11 @@ var init_router = __esm({
15178
15297
  registerZodRoutes = /* @__PURE__ */ __name((root, router, keys) => {
15179
15298
  keys.forEach((key) => {
15180
15299
  const route = router[key];
15181
- const { method, path: path5, bodyFormat, zodPathParams, zodRequest, inner } = route;
15182
- const pathParams = path5.split("/").filter((e) => e.startsWith(":")).map((e) => e.substring(1));
15183
- if (!path5.startsWith("/")) throw new Error(`Path ${path5} must start with a forward slash`);
15300
+ const { method, path: path6, bodyFormat, zodPathParams, zodRequest, inner } = route;
15301
+ const pathParams = path6.split("/").filter((e) => e.startsWith(":")).map((e) => e.substring(1));
15302
+ if (!path6.startsWith("/")) throw new Error(`Path ${path6} must start with a forward slash`);
15184
15303
  if (key.startsWith(":")) throw new Error(`Key ${key} must not start with a colon`);
15185
- const pathregex = "^" + path5.split("/").map(
15304
+ const pathregex = "^" + path6.split("/").map(
15186
15305
  (e) => e === "$key" ? key : e.startsWith(":") ? "([^/]+)" : e
15187
15306
  ).join("\\/") + "$";
15188
15307
  root.defineRoute({
@@ -15230,7 +15349,7 @@ var init_router = __esm({
15230
15349
 
15231
15350
  // src/tiddlywiki.ts
15232
15351
  import { TiddlyWiki as TiddlyWiki2 } from "tiddlywiki";
15233
- import { ok as ok5 } from "node:assert";
15352
+ import { ok as ok4 } from "node:assert";
15234
15353
  async function bootTiddlyWiki(wikiPath) {
15235
15354
  const $tw2 = TiddlyWiki2();
15236
15355
  $tw2.utils.eachAsync = eachAsync;
@@ -15274,7 +15393,7 @@ async function bootTiddlyWiki(wikiPath) {
15274
15393
  // this should be inert
15275
15394
  ];
15276
15395
  await new Promise((resolve13) => $tw2.boot.boot(resolve13));
15277
- ok5(!$tw2.boot.tasks.readBrowserTiddlers);
15396
+ ok4(!$tw2.boot.tasks.readBrowserTiddlers);
15278
15397
  return $tw2;
15279
15398
  }
15280
15399
  var init_tiddlywiki = __esm({
@@ -15287,13 +15406,13 @@ var init_tiddlywiki = __esm({
15287
15406
  });
15288
15407
 
15289
15408
  // src/services/sessions.ts
15290
- import { createHash as createHash4, randomBytes } from "node:crypto";
15291
- function zodSession(path5, zodRequest, inner) {
15409
+ import { createHash as createHash5, randomBytes } from "node:crypto";
15410
+ function zodSession(path6, zodRequest, inner) {
15292
15411
  return {
15293
- ...zodRoute(["POST"], path5, (z5) => ({}), "json", zodRequest, async (state) => {
15412
+ ...zodRoute(["POST"], path6, (z5) => ({}), "json", zodRequest, async (state) => {
15294
15413
  return state.$transaction(async (prisma) => await inner(state, prisma));
15295
15414
  }),
15296
- path: path5
15415
+ path: path6
15297
15416
  };
15298
15417
  }
15299
15418
  async function createSession(prisma, user_id, session_key) {
@@ -15308,7 +15427,7 @@ async function createSession(prisma, user_id, session_key) {
15308
15427
  }).then(({ session_id: session_id2 }) => session_id2);
15309
15428
  }
15310
15429
  function assertSignature({ session_id, signature, session_key }) {
15311
- const hash = createHash4("sha256").update(session_key + session_id).digest("base64");
15430
+ const hash = createHash5("sha256").update(session_key + session_id).digest("base64");
15312
15431
  if (hash !== signature) throw "Invalid session signature.";
15313
15432
  }
15314
15433
  var SessionKeyMap, _SessionManager, SessionManager;
@@ -15432,8 +15551,8 @@ var init_sessions = __esm({
15432
15551
  });
15433
15552
 
15434
15553
  // src/services/attachments.ts
15435
- import * as path3 from "path";
15436
- import * as fs2 from "fs";
15554
+ import * as path4 from "path";
15555
+ import * as fs3 from "fs";
15437
15556
  var import_sjcl2, $tw, _AttachmentService, AttachmentService;
15438
15557
  var init_attachments = __esm({
15439
15558
  "src/services/attachments.ts"() {
@@ -15532,15 +15651,15 @@ var init_attachments = __esm({
15532
15651
  async saveAttachment(options) {
15533
15652
  const contentHash = import_sjcl2.default.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(options.text)).slice(0, 64).toString();
15534
15653
  const contentTypeInfo = this.config.contentTypeInfo[options.type] || this.config.contentTypeInfo["application/octet-stream"];
15535
- const attachmentPath = path3.resolve(this.config.storePath, "files", contentHash);
15654
+ const attachmentPath = path4.resolve(this.config.storePath, "files", contentHash);
15536
15655
  createDirectory(attachmentPath);
15537
15656
  const dataFilename = "data" + contentTypeInfo.extension;
15538
- fs2.writeFileSync(path3.resolve(attachmentPath, dataFilename), options.text, contentTypeInfo.encoding);
15539
- this.writeMetaFile(fs2, path3, attachmentPath, options, contentHash, dataFilename);
15657
+ fs3.writeFileSync(path4.resolve(attachmentPath, dataFilename), options.text, contentTypeInfo.encoding);
15658
+ this.writeMetaFile(fs3, path4, attachmentPath, options, contentHash, dataFilename);
15540
15659
  return contentHash;
15541
15660
  }
15542
- writeMetaFile(fs3, path5, attachmentPath, options, contentHash, dataFilename) {
15543
- fs3.writeFileSync(path5.resolve(attachmentPath, "meta.json"), JSON.stringify({
15661
+ writeMetaFile(fs4, path6, attachmentPath, options, contentHash, dataFilename) {
15662
+ fs4.writeFileSync(path6.resolve(attachmentPath, "meta.json"), JSON.stringify({
15544
15663
  _canonical_uri: options._canonical_uri,
15545
15664
  created: (/* @__PURE__ */ new Date()).toISOString(),
15546
15665
  modified: (/* @__PURE__ */ new Date()).toISOString(),
@@ -15554,11 +15673,11 @@ var init_attachments = __esm({
15554
15673
  */
15555
15674
  async adoptAttachment({ incomingFilepath, type, hash, _canonical_uri }) {
15556
15675
  const contentTypeInfo = this.config.contentTypeInfo[type] || this.config.contentTypeInfo["application/octet-stream"];
15557
- const attachmentPath = path3.resolve(this.config.storePath, "files", hash);
15676
+ const attachmentPath = path4.resolve(this.config.storePath, "files", hash);
15558
15677
  createDirectory(attachmentPath);
15559
- const dataFilename = "data" + contentTypeInfo.extension, dataFilepath = path3.resolve(attachmentPath, dataFilename);
15560
- fs2.renameSync(incomingFilepath, dataFilepath);
15561
- fs2.writeFileSync(path3.resolve(attachmentPath, "meta.json"), JSON.stringify({
15678
+ const dataFilename = "data" + contentTypeInfo.extension, dataFilepath = path4.resolve(attachmentPath, dataFilename);
15679
+ fs3.renameSync(incomingFilepath, dataFilepath);
15680
+ fs3.writeFileSync(path4.resolve(attachmentPath, "meta.json"), JSON.stringify({
15562
15681
  _canonical_uri,
15563
15682
  created: (/* @__PURE__ */ new Date()).toISOString(),
15564
15683
  modified: (/* @__PURE__ */ new Date()).toISOString(),
@@ -15575,15 +15694,15 @@ var init_attachments = __esm({
15575
15694
  */
15576
15695
  async getAttachmentStream(content_hash) {
15577
15696
  if (!this.isValidAttachmentName(content_hash)) return null;
15578
- const attachmentPath = path3.resolve(this.config.storePath, "files", content_hash);
15579
- const metaJsonPath = path3.resolve(attachmentPath, "meta.json");
15580
- if (!fs2.existsSync(metaJsonPath) || !fs2.statSync(metaJsonPath).isFile()) return null;
15581
- const meta = tryParseJSON(fs2.readFileSync(metaJsonPath, "utf8"));
15697
+ const attachmentPath = path4.resolve(this.config.storePath, "files", content_hash);
15698
+ const metaJsonPath = path4.resolve(attachmentPath, "meta.json");
15699
+ if (!fs3.existsSync(metaJsonPath) || !fs3.statSync(metaJsonPath).isFile()) return null;
15700
+ const meta = tryParseJSON(fs3.readFileSync(metaJsonPath, "utf8"));
15582
15701
  if (!meta) return null;
15583
- const dataFilepath = path3.resolve(attachmentPath, meta.filename);
15584
- if (!fs2.existsSync(dataFilepath) || !fs2.statSync(dataFilepath).isFile()) return null;
15702
+ const dataFilepath = path4.resolve(attachmentPath, meta.filename);
15703
+ if (!fs3.existsSync(dataFilepath) || !fs3.statSync(dataFilepath).isFile()) return null;
15585
15704
  return {
15586
- stream: fs2.createReadStream(dataFilepath),
15705
+ stream: fs3.createReadStream(dataFilepath),
15587
15706
  type: meta.type
15588
15707
  };
15589
15708
  }
@@ -15592,20 +15711,20 @@ var init_attachments = __esm({
15592
15711
  Returns the size in bytes, or null if the file doesn't exist.
15593
15712
  */
15594
15713
  async getAttachmentFileSize(content_hash) {
15595
- const attachmentPath = path3.resolve(this.config.storePath, "files", content_hash);
15596
- const metaJsonPath = path3.resolve(attachmentPath, "meta.json");
15597
- if (!(fs2.existsSync(metaJsonPath) && fs2.statSync(metaJsonPath).isFile())) return null;
15598
- const meta = tryParseJSON(fs2.readFileSync(metaJsonPath, "utf8"));
15714
+ const attachmentPath = path4.resolve(this.config.storePath, "files", content_hash);
15715
+ const metaJsonPath = path4.resolve(attachmentPath, "meta.json");
15716
+ if (!(fs3.existsSync(metaJsonPath) && fs3.statSync(metaJsonPath).isFile())) return null;
15717
+ const meta = tryParseJSON(fs3.readFileSync(metaJsonPath, "utf8"));
15599
15718
  if (!meta) return null;
15600
- const dataFilepath = path3.resolve(attachmentPath, meta.filename);
15601
- if (!(fs2.existsSync(dataFilepath) && fs2.statSync(dataFilepath).isFile())) return null;
15602
- return fs2.statSync(dataFilepath).size;
15719
+ const dataFilepath = path4.resolve(attachmentPath, meta.filename);
15720
+ if (!(fs3.existsSync(dataFilepath) && fs3.statSync(dataFilepath).isFile())) return null;
15721
+ return fs3.statSync(dataFilepath).size;
15603
15722
  }
15604
15723
  async getAttachmentMetadata(content_hash) {
15605
- const attachmentPath = path3.resolve(this.config.storePath, "files", content_hash);
15606
- const metaJsonPath = path3.resolve(attachmentPath, "meta.json");
15607
- if (!fs2.existsSync(metaJsonPath)) return null;
15608
- return JSON.parse(fs2.readFileSync(metaJsonPath, "utf8"));
15724
+ const attachmentPath = path4.resolve(this.config.storePath, "files", content_hash);
15725
+ const metaJsonPath = path4.resolve(attachmentPath, "meta.json");
15726
+ if (!fs3.existsSync(metaJsonPath)) return null;
15727
+ return JSON.parse(fs3.readFileSync(metaJsonPath, "utf8"));
15609
15728
  }
15610
15729
  };
15611
15730
  __name(_AttachmentService, "AttachmentService");
@@ -16761,8 +16880,8 @@ var require_command = __commonJS({
16761
16880
  init_esm_shims();
16762
16881
  var EventEmitter = __require("node:events").EventEmitter;
16763
16882
  var childProcess = __require("node:child_process");
16764
- var path5 = __require("node:path");
16765
- var fs3 = __require("node:fs");
16883
+ var path6 = __require("node:path");
16884
+ var fs4 = __require("node:fs");
16766
16885
  var process2 = __require("node:process");
16767
16886
  var { Argument: Argument2, humanReadableArgName } = require_argument();
16768
16887
  var { CommanderError: CommanderError2 } = require_error();
@@ -17743,7 +17862,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
17743
17862
  * @param {string} subcommandName
17744
17863
  */
17745
17864
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
17746
- if (fs3.existsSync(executableFile)) return;
17865
+ if (fs4.existsSync(executableFile)) return;
17747
17866
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
17748
17867
  const executableMissing = `'${executableFile}' does not exist
17749
17868
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -17761,11 +17880,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
17761
17880
  let launchWithNode = false;
17762
17881
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
17763
17882
  function findFile(baseDir, baseName) {
17764
- const localBin = path5.resolve(baseDir, baseName);
17765
- if (fs3.existsSync(localBin)) return localBin;
17766
- if (sourceExt.includes(path5.extname(baseName))) return void 0;
17883
+ const localBin = path6.resolve(baseDir, baseName);
17884
+ if (fs4.existsSync(localBin)) return localBin;
17885
+ if (sourceExt.includes(path6.extname(baseName))) return void 0;
17767
17886
  const foundExt = sourceExt.find(
17768
- (ext) => fs3.existsSync(`${localBin}${ext}`)
17887
+ (ext) => fs4.existsSync(`${localBin}${ext}`)
17769
17888
  );
17770
17889
  if (foundExt) return `${localBin}${foundExt}`;
17771
17890
  return void 0;
@@ -17778,21 +17897,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
17778
17897
  if (this._scriptPath) {
17779
17898
  let resolvedScriptPath;
17780
17899
  try {
17781
- resolvedScriptPath = fs3.realpathSync(this._scriptPath);
17900
+ resolvedScriptPath = fs4.realpathSync(this._scriptPath);
17782
17901
  } catch {
17783
17902
  resolvedScriptPath = this._scriptPath;
17784
17903
  }
17785
- executableDir = path5.resolve(
17786
- path5.dirname(resolvedScriptPath),
17904
+ executableDir = path6.resolve(
17905
+ path6.dirname(resolvedScriptPath),
17787
17906
  executableDir
17788
17907
  );
17789
17908
  }
17790
17909
  if (executableDir) {
17791
17910
  let localFile = findFile(executableDir, executableFile);
17792
17911
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
17793
- const legacyName = path5.basename(
17912
+ const legacyName = path6.basename(
17794
17913
  this._scriptPath,
17795
- path5.extname(this._scriptPath)
17914
+ path6.extname(this._scriptPath)
17796
17915
  );
17797
17916
  if (legacyName !== this._name) {
17798
17917
  localFile = findFile(
@@ -17803,7 +17922,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
17803
17922
  }
17804
17923
  executableFile = localFile || executableFile;
17805
17924
  }
17806
- launchWithNode = sourceExt.includes(path5.extname(executableFile));
17925
+ launchWithNode = sourceExt.includes(path6.extname(executableFile));
17807
17926
  let proc;
17808
17927
  if (process2.platform !== "win32") {
17809
17928
  if (launchWithNode) {
@@ -18651,7 +18770,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
18651
18770
  * @return {Command}
18652
18771
  */
18653
18772
  nameFromFilename(filename) {
18654
- this._name = path5.basename(filename, path5.extname(filename));
18773
+ this._name = path6.basename(filename, path6.extname(filename));
18655
18774
  return this;
18656
18775
  }
18657
18776
  /**
@@ -18665,9 +18784,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
18665
18784
  * @param {string} [path]
18666
18785
  * @return {(string|null|Command)}
18667
18786
  */
18668
- executableDir(path6) {
18669
- if (path6 === void 0) return this._executableDir;
18670
- this._executableDir = path6;
18787
+ executableDir(path7) {
18788
+ if (path7 === void 0) return this._executableDir;
18789
+ this._executableDir = path7;
18671
18790
  return this;
18672
18791
  }
18673
18792
  /**
@@ -19082,12 +19201,12 @@ __export(render_tiddlywiki5_exports, {
19082
19201
  info: () => info2
19083
19202
  });
19084
19203
  import { resolve as resolve6 } from "node:path";
19085
- var writeFileSync3, info2, _Command2, Command3;
19204
+ var writeFileSync4, info2, _Command2, Command3;
19086
19205
  var init_render_tiddlywiki5 = __esm({
19087
19206
  "src/commands/render-tiddlywiki5.ts"() {
19088
19207
  "use strict";
19089
19208
  init_esm_shims();
19090
- ({ writeFileSync: writeFileSync3 } = __require("fs"));
19209
+ ({ writeFileSync: writeFileSync4 } = __require("fs"));
19091
19210
  info2 = {
19092
19211
  name: "render-tiddlywiki5",
19093
19212
  description: "Render the TiddlyWiki5 HTML file",
@@ -19103,12 +19222,13 @@ var init_render_tiddlywiki5 = __esm({
19103
19222
  async execute() {
19104
19223
  const result = this.commander.$tw.wiki.renderTiddler("text/plain", "$:/core/templates/tiddlywiki5.html", {
19105
19224
  variables: {
19106
- saveTiddlerFilter: `
19107
- $:/boot/boot.css
19108
- $:/boot/boot.js
19109
- $:/boot/bootprefix.js
19225
+ // the boot and library tiddlers get rendered into the page
19226
+ // this list gets saved in the store array
19227
+ // we have to render at least one tiddler
19228
+ saveTiddlerFilter: this.commander.siteConfig.enablePluginCache ? `
19229
+ $:/temp/nothing
19230
+ ` : `
19110
19231
  $:/core
19111
- $:/library/sjcl.js
19112
19232
  $:/plugins/tiddlywiki/tiddlyweb
19113
19233
  $:/plugins/tiddlywiki/multiwikiclient
19114
19234
  $:/themes/tiddlywiki/snowwhite
@@ -19117,7 +19237,7 @@ var init_render_tiddlywiki5 = __esm({
19117
19237
  }
19118
19238
  });
19119
19239
  const filepath = resolve6(this.commander.wikiPath, "tiddlywiki5.html");
19120
- writeFileSync3(filepath, result);
19240
+ writeFileSync4(filepath, result);
19121
19241
  }
19122
19242
  };
19123
19243
  __name(_Command2, "Command");
@@ -19136,11 +19256,11 @@ function makePluginBagName(type, publisher, name) {
19136
19256
  return "$:/" + type + "/" + (publisher ? publisher + "/" : "") + name;
19137
19257
  }
19138
19258
  function loadWikiFolder({ $tw: $tw2, store, ...options }) {
19139
- const path5 = __require("path"), fs3 = __require("fs");
19140
- const wikiInfoPath = path5.resolve(options.wikiPath, $tw2.config.wikiInfo);
19259
+ const path6 = __require("path"), fs4 = __require("fs");
19260
+ const wikiInfoPath = path6.resolve(options.wikiPath, $tw2.config.wikiInfo);
19141
19261
  let wikiInfo;
19142
- if (fs3.existsSync(wikiInfoPath)) {
19143
- wikiInfo = $tw2.utils.parseJSONSafe(fs3.readFileSync(wikiInfoPath, "utf8"), function() {
19262
+ if (fs4.existsSync(wikiInfoPath)) {
19263
+ wikiInfo = $tw2.utils.parseJSONSafe(fs4.readFileSync(wikiInfoPath, "utf8"), function() {
19144
19264
  return null;
19145
19265
  });
19146
19266
  }
@@ -19167,7 +19287,7 @@ function loadWikiFolder({ $tw: $tw2, store, ...options }) {
19167
19287
  with_acl: true
19168
19288
  });
19169
19289
  recipeList.reverse();
19170
- const tiddler_files_path = path5.resolve(options.wikiPath, $tw2.config.wikiTiddlersSubDir);
19290
+ const tiddler_files_path = path6.resolve(options.wikiPath, $tw2.config.wikiTiddlersSubDir);
19171
19291
  const tiddlersFromPath = $tw2.loadTiddlersFromPath(
19172
19292
  resolve7($tw2.boot.corePath, $tw2.config.editionsPath, tiddler_files_path)
19173
19293
  );
@@ -19349,7 +19469,7 @@ __export(load_archive_exports, {
19349
19469
  Command: () => Command6,
19350
19470
  info: () => info5
19351
19471
  });
19352
- import { join as join2, resolve as resolve9 } from "path";
19472
+ import { join as join3, resolve as resolve9 } from "path";
19353
19473
  import * as _fsp2 from "fs/promises";
19354
19474
  import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
19355
19475
  import { existsSync as existsSync3 } from "fs";
@@ -19454,7 +19574,7 @@ var init_load_archive = __esm({
19454
19574
  });
19455
19575
  }
19456
19576
  async restoreBag(folder, prisma) {
19457
- const bagInfo = JSON.parse(await fsp2.readFile(join2(folder, "meta.json"), "utf8"));
19577
+ const bagInfo = JSON.parse(await fsp2.readFile(join3(folder, "meta.json"), "utf8"));
19458
19578
  await prisma.bags.create({
19459
19579
  data: {
19460
19580
  bag_id: bagInfo.bag_id,
@@ -19465,10 +19585,10 @@ var init_load_archive = __esm({
19465
19585
  acl: { createMany: { data: bagInfo.acl } }
19466
19586
  }
19467
19587
  });
19468
- const tiddlerFiles = await fsp2.readdir(join2(folder, "tiddlers"));
19588
+ const tiddlerFiles = await fsp2.readdir(join3(folder, "tiddlers"));
19469
19589
  const tiddlers = await Promise.all(tiddlerFiles.map(async (tiddlerFilename) => {
19470
19590
  if (!tiddlerFilename.endsWith(".json")) return;
19471
- const value = await fsp2.readFile(join2(folder, "tiddlers", tiddlerFilename), "utf8");
19591
+ const value = await fsp2.readFile(join3(folder, "tiddlers", tiddlerFilename), "utf8");
19472
19592
  return JSON.parse(value);
19473
19593
  }));
19474
19594
  await prisma.tiddlers.createMany({
@@ -19552,7 +19672,7 @@ var init_load_archive = __esm({
19552
19672
  });
19553
19673
  }
19554
19674
  async restoreBag(folder, prisma) {
19555
- const bagInfo = JSON.parse(await fsp2.readFile(join2(folder, "meta.json"), "utf8"));
19675
+ const bagInfo = JSON.parse(await fsp2.readFile(join3(folder, "meta.json"), "utf8"));
19556
19676
  await prisma.bags.create({
19557
19677
  data: {
19558
19678
  bag_id: bagInfo.bag_id,
@@ -19563,10 +19683,10 @@ var init_load_archive = __esm({
19563
19683
  acl: { createMany: { data: bagInfo.acl } }
19564
19684
  }
19565
19685
  });
19566
- const tiddlerFiles = await fsp2.readdir(join2(folder, "tiddlers"));
19686
+ const tiddlerFiles = await fsp2.readdir(join3(folder, "tiddlers"));
19567
19687
  const tiddlers = await Promise.all(tiddlerFiles.map(async (tiddlerFilename) => {
19568
19688
  if (!tiddlerFilename.endsWith(".json")) return;
19569
- const value = await fsp2.readFile(join2(folder, "tiddlers", tiddlerFilename), "utf8");
19689
+ const value = await fsp2.readFile(join3(folder, "tiddlers", tiddlerFilename), "utf8");
19570
19690
  return JSON.parse(value);
19571
19691
  }));
19572
19692
  await prisma.tiddlers.createMany({
@@ -19688,7 +19808,7 @@ __export(listen_exports, {
19688
19808
  ListenerHTTPS: () => ListenerHTTPS,
19689
19809
  info: () => info7
19690
19810
  });
19691
- import { ok as ok6 } from "assert";
19811
+ import { ok as ok5 } from "assert";
19692
19812
  import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
19693
19813
  import { createServer } from "http";
19694
19814
  import * as http2 from "node:http2";
@@ -19745,8 +19865,8 @@ var init_listen = __esm({
19745
19865
  const { port, host } = config;
19746
19866
  if (port && typeof port !== "number") throw new Error("If specified, port must be a number");
19747
19867
  const bindInfo = host ? `HTTPS ${host} ${port}` : `HTTPS ${port}`;
19748
- ok6(config.key && existsSync4(config.key), "Key file not found");
19749
- ok6(config.cert && existsSync4(config.cert), "Cert file not found");
19868
+ ok5(config.key && existsSync4(config.key), "Key file not found");
19869
+ ok5(config.cert && existsSync4(config.cert), "Cert file not found");
19750
19870
  const key = readFileSync3(config.key);
19751
19871
  const cert = readFileSync3(config.cert);
19752
19872
  super(http2.createSecureServer({ key, cert, allowHTTP1: true }), router, bindInfo);
@@ -19970,7 +20090,7 @@ var init_commands = __esm({
19970
20090
  // src/db/sqlite-adapter.ts
19971
20091
  import { PrismaBetterSQLite3 } from "@prisma/adapter-better-sqlite3";
19972
20092
  import { readdir, readFile as readFile2 } from "fs/promises";
19973
- import { createHash as createHash5, randomUUID } from "crypto";
20093
+ import { createHash as createHash6, randomUUID } from "crypto";
19974
20094
  import { existsSync as existsSync5 } from "fs";
19975
20095
  var _SqliteAdapter, SqliteAdapter;
19976
20096
  var init_sqlite_adapter = __esm({
@@ -20019,7 +20139,7 @@ var init_sqlite_adapter = __esm({
20019
20139
  const new_migrations = migrations.filter((m) => !applied_migrations.has(m) && m !== "migration_lock.toml");
20020
20140
  if (!new_migrations.length) return;
20021
20141
  function generateChecksum(fileContent) {
20022
- return createHash5("sha256").update(fileContent).digest("hex");
20142
+ return createHash6("sha256").update(fileContent).digest("hex");
20023
20143
  }
20024
20144
  __name(generateChecksum, "generateChecksum");
20025
20145
  console.log("New migrations found", new_migrations);
@@ -20049,10 +20169,10 @@ var init_sqlite_adapter = __esm({
20049
20169
  });
20050
20170
 
20051
20171
  // src/commander.ts
20052
- import * as path4 from "node:path";
20172
+ import * as path5 from "node:path";
20053
20173
  import { PrismaClient as PrismaClient2 } from "@prisma/client";
20054
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4 } from "node:fs";
20055
- import { ok as ok7 } from "node:assert";
20174
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4 } from "node:fs";
20175
+ import { ok as ok6 } from "node:assert";
20056
20176
  var _StartupCommander, StartupCommander, _Commander, Commander;
20057
20177
  var init_commander = __esm({
20058
20178
  "src/commander.ts"() {
@@ -20073,16 +20193,16 @@ var init_commander = __esm({
20073
20193
  this.setupRequired = true;
20074
20194
  this.fieldModules = $tw2.Tiddler.fieldModules;
20075
20195
  if (config.config?.pathPrefix) {
20076
- ok7(config.config.pathPrefix.startsWith("/"), "pathPrefix must start with a slash");
20077
- ok7(!config.config.pathPrefix.endsWith("/"), "pathPrefix must not end with a slash");
20196
+ ok6(config.config.pathPrefix.startsWith("/"), "pathPrefix must start with a slash");
20197
+ ok6(!config.config.pathPrefix.endsWith("/"), "pathPrefix must not end with a slash");
20078
20198
  }
20079
20199
  this.wikiPath = config.wikiPath;
20080
- this.storePath = path4.resolve(this.wikiPath, "store");
20081
- this.databasePath = path4.resolve(this.storePath, "database.sqlite");
20082
- this.outputPath = path4.resolve($tw2.boot.wikiPath, $tw2.config.wikiOutputSubDir);
20083
- this.cachePath = path4.resolve(this.wikiPath, "cache");
20200
+ this.storePath = path5.resolve(this.wikiPath, "store");
20201
+ this.databasePath = path5.resolve(this.storePath, "database.sqlite");
20202
+ this.outputPath = path5.resolve($tw2.boot.wikiPath, $tw2.config.wikiOutputSubDir);
20203
+ this.cachePath = path5.resolve(this.wikiPath, "cache");
20084
20204
  if (!existsSync6(this.storePath)) {
20085
- mkdirSync2(this.storePath, { recursive: true });
20205
+ mkdirSync3(this.storePath, { recursive: true });
20086
20206
  this.setupRequired = true;
20087
20207
  }
20088
20208
  this.siteConfig = {
@@ -20097,7 +20217,8 @@ var init_commander = __esm({
20097
20217
  contentTypeInfo: $tw2.config.contentTypeInfo,
20098
20218
  storePath: this.storePath,
20099
20219
  pathPrefix: config.config?.pathPrefix ?? "",
20100
- saveLargeTextToFileSystem: void 0
20220
+ saveLargeTextToFileSystem: void 0,
20221
+ enablePluginCache: config.config?.enablePluginCache ?? false
20101
20222
  };
20102
20223
  this.SessionManager = config.SessionManager || SessionManager;
20103
20224
  this.AttachmentService = config.AttachmentService || AttachmentService;
@@ -20364,7 +20485,7 @@ var init_PasswordService = __esm({
20364
20485
 
20365
20486
  // src/server.ts
20366
20487
  import * as opaque2 from "@serenity-kit/opaque";
20367
- import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
20488
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
20368
20489
  import { resolve as resolve12 } from "node:path";
20369
20490
  async function startServer(config) {
20370
20491
  await opaque2.ready;
@@ -20372,7 +20493,7 @@ async function startServer(config) {
20372
20493
  throw new Error("passwordMasterKeyFile must be a string or number");
20373
20494
  }
20374
20495
  if (typeof config.passwordMasterKeyFile === "string" && config.passwordMasterKeyFile && !existsSync7(config.passwordMasterKeyFile)) {
20375
- writeFileSync4(config.passwordMasterKeyFile, opaque2.server.createSetup());
20496
+ writeFileSync5(config.passwordMasterKeyFile, opaque2.server.createSetup());
20376
20497
  console.log("Password master key created at", config.passwordMasterKeyFile);
20377
20498
  }
20378
20499
  const passwordMasterKey = readFileSync5(config.passwordMasterKeyFile, "utf8").trim();