@tiddlywiki/mws 0.0.20 → 0.0.21

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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # MultiWikiServer
2
2
 
3
+ **This is not ready for primetime. Do not use it to protect feelings or intellectual property.**
4
+
5
+ *You really shouldn't be using it to store anything important yet. It is still in the VERY early stages of development and we don't even have proper tests verifying the security mechanisms yet. So please try it out, kick the tires, import your multi-gigabyte wikis and play around with it, but don't actually store anything you want to keep. We'll hopefully get there soon, but even the database schema itself is still in flux as we figure out what the best layout is for all the stuff we have planned.*
6
+
3
7
  Multiple users, multiple wikis for TiddlyWiki.
4
8
 
5
9
  - Bag & Recipe system for storing tiddlers.
package/dist/server.d.ts CHANGED
@@ -228,6 +228,10 @@ declare class StartupCommander {
228
228
  $tw: TW;
229
229
  PasswordService: PasswordService;
230
230
  fieldModules: Record<string, TiddlerFieldModule>;
231
+ versions: {
232
+ tiddlywiki: any;
233
+ mws: string;
234
+ };
231
235
  constructor(config: MWSConfig, $tw: TW, PasswordService: PasswordService);
232
236
  init(): Promise<void>;
233
237
  wikiPath: string;
@@ -333,6 +337,7 @@ declare class StateObject<B extends BodyFormat = BodyFormat, M extends AllowedMe
333
337
  private engine;
334
338
  config: SiteConfig;
335
339
  PasswordService: PasswordService;
340
+ get pathPrefix(): string;
336
341
  constructor(streamer: Streamer,
337
342
  /** The array of Route tree nodes the request matched. */
338
343
  routePath: RouteMatch[],
@@ -798,6 +803,10 @@ declare class Router {
798
803
  engine: Commander["engine"];
799
804
  private SessionManager;
800
805
  PasswordService: Commander["PasswordService"];
806
+ versions: {
807
+ tiddlywiki: any;
808
+ mws: string;
809
+ };
801
810
  fieldModules: Commander["$tw"]["Tiddler"]["fieldModules"];
802
811
  AttachmentService: Commander["AttachmentService"];
803
812
  constructor(rootRoute: rootRoute$1, commander: Commander, tiddlerCache: CacheState);
package/dist/server.js CHANGED
@@ -1621,7 +1621,7 @@ var require_destroy = __commonJS({
1621
1621
  "node_modules/destroy/index.js"(exports, module2) {
1622
1622
  "use strict";
1623
1623
  init_esm_shims();
1624
- var EventEmitter = __require("events").EventEmitter;
1624
+ var EventEmitter2 = __require("events").EventEmitter;
1625
1625
  var ReadStream = __require("fs").ReadStream;
1626
1626
  var Stream = __require("stream");
1627
1627
  var Zlib = __require("zlib");
@@ -1688,7 +1688,7 @@ var require_destroy = __commonJS({
1688
1688
  }
1689
1689
  __name(hasDestroy, "hasDestroy");
1690
1690
  function isEventEmitter(val) {
1691
- return val instanceof EventEmitter;
1691
+ return val instanceof EventEmitter2;
1692
1692
  }
1693
1693
  __name(isEventEmitter, "isEventEmitter");
1694
1694
  function isFsReadStream(stream) {
@@ -11569,7 +11569,8 @@ var init_data_checks = __esm({
11569
11569
  init_esm_shims();
11570
11570
  init_utils();
11571
11571
  _DataChecks = class _DataChecks {
11572
- constructor(options) {
11572
+ constructor(config) {
11573
+ this.config = config;
11573
11574
  this.isPermissionName = /* @__PURE__ */ __name((e) => {
11574
11575
  const test2 = e;
11575
11576
  switch (test2) {
@@ -11586,8 +11587,6 @@ var init_data_checks = __esm({
11586
11587
  this.permissions = { READ: "READ", WRITE: "WRITE", ADMIN: "ADMIN" };
11587
11588
  this.isEntityType = /* @__PURE__ */ __name((x) => ["recipe", "bag"].includes(x), "isEntityType");
11588
11589
  this.entityTypes = { recipe: "recipe", bag: "bag" };
11589
- this.allowAnonReads = options.allowAnonReads;
11590
- this.allowAnonWrites = options.allowAnonWrites;
11591
11590
  }
11592
11591
  okTiddlerFields(tiddlerFields) {
11593
11592
  ok2(tiddlerFields.title, "title must not be empty");
@@ -11648,17 +11647,11 @@ var init_data_checks = __esm({
11648
11647
  ].filter(truthy);
11649
11648
  }
11650
11649
  getWhereACL({ permission, user_id, role_ids }) {
11651
- const { allowAnonReads, allowAnonWrites } = this;
11652
- const anonRead = allowAnonReads && permission === "READ";
11653
- const anonWrite = allowAnonWrites && permission === "WRITE";
11654
- const allowAnon = anonRead || anonWrite;
11655
11650
  const allperms = ["READ", "WRITE", "ADMIN"];
11656
11651
  const index = allperms.indexOf(permission);
11657
11652
  if (index === -1) throw new Error("Invalid permission");
11658
11653
  const checkPerms = allperms.slice(index);
11659
11654
  return [
11660
- // allow unowned for any user (conditional for anon reads)
11661
- (user_id || allowAnon) && { acl: { none: {} }, owner_id: null },
11662
11655
  // allow owner for user
11663
11656
  user_id && { owner_id: { equals: user_id, not: null } },
11664
11657
  // allow acl for user
@@ -11669,7 +11662,9 @@ var init_data_checks = __esm({
11669
11662
  role_id: { in: role_ids }
11670
11663
  }
11671
11664
  }
11672
- }
11665
+ },
11666
+ { owner_id: { equals: null, not: null } }
11667
+ // dud to make sure that at least one condition exists
11673
11668
  ].filter(truthy);
11674
11669
  }
11675
11670
  };
@@ -11814,8 +11809,9 @@ var init_streamer = __esm({
11814
11809
  if (error === STREAM_ENDED) return;
11815
11810
  const tag = this.urlInfo.href;
11816
11811
  console.error(tag, error);
11817
- if (!this.headersSent)
11812
+ if (!this.headersSent) {
11818
11813
  this.sendEmpty(500, { "x-reason": "Internal Server Error (catcher)" });
11814
+ }
11819
11815
  }, "catcher");
11820
11816
  this.readBody = /* @__PURE__ */ __name(() => new Promise((resolve13) => {
11821
11817
  const chunks = [];
@@ -12178,6 +12174,9 @@ var init_StateObject = __esm({
12178
12174
  get method() {
12179
12175
  return super.method;
12180
12176
  }
12177
+ get pathPrefix() {
12178
+ return this.config.pathPrefix;
12179
+ }
12181
12180
  okUser() {
12182
12181
  if (!this.user.isLoggedIn) throw "User not authenticated";
12183
12182
  }
@@ -12406,8 +12405,8 @@ var init_manager_recipes = __esm({
12406
12405
  where: isAdmin ? void 0 : {
12407
12406
  OR: [
12408
12407
  { recipe_bags: { every: { bag: { OR } } } },
12409
- { owner_id: { equals: user_id, not: null } }
12410
- ]
12408
+ user_id && { owner_id: { equals: user_id, not: null } }
12409
+ ].filter((e) => e)
12411
12410
  }
12412
12411
  });
12413
12412
  const userListUser = !isAdmin && await prisma.users.findMany({
@@ -12428,7 +12427,8 @@ var init_manager_recipes = __esm({
12428
12427
  username,
12429
12428
  isLoggedIn: state.user.isLoggedIn,
12430
12429
  allowAnonReads: state.config.allowAnonReads,
12431
- allowAnonWrites: state.config.allowAnonWrites
12430
+ allowAnonWrites: state.config.allowAnonWrites,
12431
+ versions: state.router.versions
12432
12432
  };
12433
12433
  });
12434
12434
  this.recipe_create = zodManage((z5) => z5.object({
@@ -12585,8 +12585,7 @@ var init_manager_recipes = __esm({
12585
12585
  });
12586
12586
  return null;
12587
12587
  });
12588
- const { allowAnonReads, allowAnonWrites } = config;
12589
- this.checks = new DataChecks({ allowAnonReads, allowAnonWrites });
12588
+ this.checks = new DataChecks(config);
12590
12589
  }
12591
12590
  static defineRoutes(root, config) {
12592
12591
  registerZodRoutes(root, new _RecipeManager(config), Object.keys(RecipeKeyMap));
@@ -13190,13 +13189,15 @@ var init_TiddlerStore = __esm({
13190
13189
  recipe_bags: {
13191
13190
  // we're saving to the top most bag
13192
13191
  where: { position: 0 },
13193
- select: { bag: { select: { bag_id: true, bag_name: true } } }
13192
+ select: { bag: { select: { bag_id: true, bag_name: true, is_plugin: true } } }
13194
13193
  }
13195
13194
  }
13196
13195
  });
13197
13196
  if (!recipe) throw new UserError("Recipe not found");
13198
13197
  const bag_name = recipe.recipe_bags[0]?.bag.bag_name;
13199
13198
  if (!bag_name) throw new UserError("Recipe has no bag at position 0");
13199
+ if (recipe.recipe_bags[0]?.bag.is_plugin)
13200
+ throw new UserError("Saving to plugin bags is not currently supported. Please use a normal bag. This error occurs if a plugin bag is at the top of the recipe.\n");
13200
13201
  var { tiddler_id } = await this.saveBagTiddlerFields(tiddlerFields, bag_name, attachment_hash);
13201
13202
  return { tiddler_id, bag_name };
13202
13203
  }
@@ -14676,58 +14677,62 @@ var init_router_tiddlers = __esm({
14676
14677
 
14677
14678
  // src/routes/tw-routes.ts
14678
14679
  import { TiddlyWiki } from "tiddlywiki";
14679
- function DocsRoute(parent, config) {
14680
- const wikiRouter = new TWRouter(config);
14681
- console.log("The mws-docs tiddlywiki is being served at " + config.pathPrefix + "/mws-docs");
14682
- parent.defineRoute({
14680
+ import { basename } from "path";
14681
+ import EventEmitter from "events";
14682
+ function DocsRoute(rootRoute2, mountPath, singleFile) {
14683
+ const $tw2 = TiddlyWiki();
14684
+ const last = basename(mountPath);
14685
+ $tw2.preloadTiddler({
14686
+ title: "$:/config/tiddlyweb/host",
14687
+ // if the page url doesn't end with a slash, we have to include the basename here
14688
+ text: singleFile ? last + "/" : ""
14689
+ });
14690
+ $tw2.boot.argv = [
14691
+ "+plugins/tiddlywiki/tiddlyweb",
14692
+ "+plugins/tiddlywiki/filesystem",
14693
+ // relative to the cwd
14694
+ "./editions/mws-docs"
14695
+ ];
14696
+ const hooks = new EventEmitter();
14697
+ $tw2.boot.boot(() => {
14698
+ const Server2 = $tw2.modules.execute("$:/core/modules/server/server.js", "tw-test.ts").Server;
14699
+ const twserver = new Server2({
14700
+ wiki: $tw2.wiki,
14701
+ variables: {
14702
+ // path prefix gets set per-request
14703
+ "path-prefix": "",
14704
+ "root-tiddler": "$:/core/save/all"
14705
+ },
14706
+ routes: []
14707
+ });
14708
+ $tw2.hooks.invokeHook("th-server-command-post-start", twserver, null, "mws");
14709
+ hooks.on("req", (req, res, pathPrefix) => {
14710
+ twserver.requestHandler(req, res, { pathPrefix });
14711
+ });
14712
+ });
14713
+ rootRoute2.defineRoute({
14683
14714
  method: ["OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE"],
14684
14715
  bodyFormat: "stream",
14685
- path: /^\/mwsp-docs(\/|$)/,
14716
+ path: new RegExp("^" + mountPath + "(/|$)"),
14686
14717
  pathParams: []
14687
14718
  }, async (state) => {
14688
- if (state.urlInfo.pathname === "/mws-docs") throw state.redirect("/mws-docs/");
14719
+ if (singleFile && state.urlInfo.pathname === mountPath + "/")
14720
+ throw state.redirect(mountPath);
14721
+ if (!singleFile && state.urlInfo.pathname === mountPath)
14722
+ throw state.redirect(mountPath + "/");
14689
14723
  const { req, res } = state.streamer;
14690
- if (req.url === "/mws-docs") req.url = "/mws-docs/";
14691
- wikiRouter.twserver.requestHandler(req, res, {});
14692
- return new Promise((r, c) => res.on("finish", r).on("error", c));
14724
+ if (req.url === state.pathPrefix + mountPath)
14725
+ req.url = state.pathPrefix + mountPath + "/";
14726
+ const prom = new Promise((r, c) => res.on("finish", r).on("error", c));
14727
+ hooks.emit("req", req, res, state.pathPrefix + mountPath);
14728
+ return prom;
14693
14729
  });
14694
14730
  }
14695
- var _TWRouter, TWRouter;
14696
14731
  var init_tw_routes = __esm({
14697
14732
  "src/routes/tw-routes.ts"() {
14698
14733
  "use strict";
14699
14734
  init_esm_shims();
14700
14735
  __name(DocsRoute, "DocsRoute");
14701
- _TWRouter = class _TWRouter {
14702
- constructor(config) {
14703
- this.config = config;
14704
- this.$tw = TiddlyWiki();
14705
- this.$tw.boot.argv = [
14706
- "+plugins/tiddlywiki/tiddlyweb",
14707
- "+plugins/tiddlywiki/filesystem",
14708
- "./editions/mws-docs"
14709
- ];
14710
- this.$tw.preloadTiddler({
14711
- text: "$protocol$//$host$" + this.config.pathPrefix + "/mws/",
14712
- title: "$:/config/tiddlyweb/host"
14713
- });
14714
- this.$tw.boot.boot(() => {
14715
- const Server2 = this.$tw.modules.execute("$:/core/modules/server/server.js", "tw-test.ts").Server;
14716
- this.twserver = new Server2({
14717
- wiki: this.$tw.wiki,
14718
- variables: {
14719
- // do not use a trailing slash
14720
- "path-prefix": this.config.pathPrefix + "/mws",
14721
- "root-tiddler": "$:/core/save/all"
14722
- },
14723
- routes: []
14724
- });
14725
- this.$tw.hooks.invokeHook("th-server-command-post-start", this.twserver, null, "mws");
14726
- });
14727
- }
14728
- };
14729
- __name(_TWRouter, "TWRouter");
14730
- TWRouter = _TWRouter;
14731
14736
  }
14732
14737
  });
14733
14738
 
@@ -14747,7 +14752,7 @@ var init_ = __esm({
14747
14752
  // src/routes/index.ts
14748
14753
  import { Prisma } from "@prisma/client";
14749
14754
  async function RootRoute(root, config) {
14750
- if (process.env.ENABLE_DOCS_ROUTE) DocsRoute(root, config);
14755
+ if (process.env.ENABLE_DOCS_ROUTE) DocsRoute(root, "/mws-docs", false);
14751
14756
  TiddlerRouter.defineRoutes(root);
14752
14757
  ManagerRoutes(root, config);
14753
14758
  if (process.env.ENABLE_UNSAFE_PRISMA_ROUTE)
@@ -14995,7 +15000,6 @@ import * as path3 from "path";
14995
15000
  import * as crypto from "crypto";
14996
15001
  async function startupCache(rootRoute2, commander2) {
14997
15002
  const $tw2 = commander2.$tw;
14998
- console.log(commander2.siteConfig.enablePluginCache);
14999
15003
  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
15004
  rootRoute2.defineRoute({
15001
15005
  method: ["GET", "HEAD"],
@@ -15151,6 +15155,7 @@ var init_router = __esm({
15151
15155
  this.PasswordService = commander2.PasswordService;
15152
15156
  this.fieldModules = commander2.$tw.Tiddler.fieldModules;
15153
15157
  this.AttachmentService = commander2.AttachmentService;
15158
+ this.versions = commander2.versions;
15154
15159
  }
15155
15160
  static async makeRouter(commander2, enableDevServer) {
15156
15161
  const sendDevServer = await setupDevServer(enableDevServer, commander2.siteConfig.pathPrefix);
@@ -15332,8 +15337,10 @@ var init_router = __esm({
15332
15337
  if (error === STREAM_ENDED) {
15333
15338
  return error;
15334
15339
  } else if (typeof error === "string") {
15340
+ console.log(error);
15335
15341
  return state.sendString(400, { "x-reason": "zod-handler" }, error, "utf8");
15336
15342
  } else if (error instanceof Error && error.name === "UserError") {
15343
+ console.log(error.stack);
15337
15344
  return state.sendString(400, { "x-reason": "user-error" }, error.message, "utf8");
15338
15345
  } else {
15339
15346
  throw error;
@@ -16878,7 +16885,7 @@ var require_command = __commonJS({
16878
16885
  "node_modules/commander/lib/command.js"(exports) {
16879
16886
  "use strict";
16880
16887
  init_esm_shims();
16881
- var EventEmitter = __require("node:events").EventEmitter;
16888
+ var EventEmitter2 = __require("node:events").EventEmitter;
16882
16889
  var childProcess = __require("node:child_process");
16883
16890
  var path6 = __require("node:path");
16884
16891
  var fs4 = __require("node:fs");
@@ -16888,7 +16895,7 @@ var require_command = __commonJS({
16888
16895
  var { Help: Help2, stripColor } = require_help();
16889
16896
  var { Option: Option2, DualOptions } = require_option();
16890
16897
  var { suggestSimilar } = require_suggestSimilar();
16891
- var _Command12 = class _Command12 extends EventEmitter {
16898
+ var _Command12 = class _Command12 extends EventEmitter2 {
16892
16899
  /**
16893
16900
  * Initialize a new `Command`.
16894
16901
  *
@@ -20134,6 +20141,23 @@ var init_sqlite_adapter = __esm({
20134
20141
  argTypes: []
20135
20142
  }).then((e) => e.rows.map((e2) => e2[0]))
20136
20143
  );
20144
+ if (applied_migrations.size && !applied_migrations.has("20250406213424_init")) {
20145
+ console.log("Unknown migrations have been found in the database.");
20146
+ console.log("There is no way to guarentee the integrity of the database under these conditions.");
20147
+ console.log("The only way I know of that you could be seeing this message is if you installed this verion of MWS in a project either from the PR branch or from a newer version of MWS.");
20148
+ console.log("Please revert back to the version you had installed before.");
20149
+ console.log("The sqlite database can be opened manually with any third-party SQLite tool to retrieve your data. If you do this, make sure you keep all the files in the store folder together, as they are all an integral part of your sqlite database and deleting any of them manually is very likely to cause data loss.");
20150
+ process.exit();
20151
+ } else {
20152
+ console.log([
20153
+ "=======================================================================================",
20154
+ "This version of MWS is no longer supported. It is an alpha version",
20155
+ "and you shouldn't be using it in production anyway. Please export any",
20156
+ "wikis you want to keep by opening them and downloading them as single-file",
20157
+ "wikis by clicking on the cloud status icon and then 'save snapshot for offline use'.",
20158
+ "======================================================================================="
20159
+ ].join("\n"));
20160
+ }
20137
20161
  const migrations = await readdir(dist_resolve("../prisma/migrations"));
20138
20162
  migrations.sort();
20139
20163
  const new_migrations = migrations.filter((m) => !applied_migrations.has(m) && m !== "migration_lock.toml");
@@ -20168,6 +20192,78 @@ var init_sqlite_adapter = __esm({
20168
20192
  }
20169
20193
  });
20170
20194
 
20195
+ // package.json
20196
+ var package_default;
20197
+ var init_package = __esm({
20198
+ "package.json"() {
20199
+ package_default = {
20200
+ name: "@tiddlywiki/mws",
20201
+ description: "TiddlyWiki Multiple Wiki Server",
20202
+ private: false,
20203
+ version: "0.0.21",
20204
+ type: "module",
20205
+ exports: {
20206
+ types: "./src/server.ts",
20207
+ require: "./dist/server.cjs",
20208
+ import: "./dist/server.js"
20209
+ },
20210
+ files: [
20211
+ "dist",
20212
+ "prisma",
20213
+ "react-user-mgmt",
20214
+ "tiddlywiki-types",
20215
+ "editions/mws-docs",
20216
+ "plugins/client",
20217
+ "scripts.mjs"
20218
+ ],
20219
+ engines: {
20220
+ node: ">=18"
20221
+ },
20222
+ scripts: {
20223
+ docs: "node scripts.mjs docs",
20224
+ start: "node scripts.mjs start",
20225
+ certs: "(cd runtime-config && bash localhost_certs.sh)",
20226
+ tsc: "tsc -p tsconfig.json --skipLibCheck",
20227
+ build: "npm run tsc && tsup && node mws.dev.mjs --client-build",
20228
+ "install-android": `GYP_DEFINES="android_ndk_path=''" npm install`,
20229
+ postinstall: "node scripts.mjs prisma:generate",
20230
+ env: "env",
20231
+ "test:pack": "(git clean -dfx tests && npm pack --pack-destination tests && cd tests && npm install && npm install ./tiddlywiki-mws-$npm_package_version.tgz --no-save && npm test)",
20232
+ test: "(git clean -dfx tests && cd tests && npm install .. --no-save && npm test)",
20233
+ fulltest: "mv node_modules node_modules_old; npm run test:pack; mv node_modules_old node_modules",
20234
+ prepublishOnly: "npm run build"
20235
+ },
20236
+ dependencies: {
20237
+ "@prisma/adapter-better-sqlite3": "6.7.0-dev.48",
20238
+ "@prisma/client": "6.6.0",
20239
+ "@serenity-kit/opaque": "^0.8.4",
20240
+ "@types/mime-types": "^2.1.4",
20241
+ "@types/node": "^22.13.1",
20242
+ "@types/send": "^0.17.4",
20243
+ "@types/sjcl": "^1.0.34",
20244
+ "@types/tiddlywiki": "file:tiddlywiki-types",
20245
+ prisma: "6.6.0",
20246
+ "source-map-support": "^0.5.21",
20247
+ zod: "^3.24.2"
20248
+ },
20249
+ devDependencies: {
20250
+ commander: "^13.1.0",
20251
+ esbuild: "0.25.2",
20252
+ "mime-types": "^2.1.35",
20253
+ send: "^1.1.0",
20254
+ sjcl: "^1.0.8",
20255
+ tiddlywiki: "^5.1.22",
20256
+ tsup: "^8.4.0",
20257
+ typescript: "^5.7.3",
20258
+ uuid: "^11.1.0"
20259
+ },
20260
+ peerDependencies: {
20261
+ tiddlywiki: "^5.1.22"
20262
+ }
20263
+ };
20264
+ }
20265
+ });
20266
+
20171
20267
  // src/commander.ts
20172
20268
  import * as path5 from "node:path";
20173
20269
  import { PrismaClient as PrismaClient2 } from "@prisma/client";
@@ -20184,6 +20280,7 @@ var init_commander = __esm({
20184
20280
  init_esm();
20185
20281
  init_commands();
20186
20282
  init_sqlite_adapter();
20283
+ init_package();
20187
20284
  _StartupCommander = class _StartupCommander {
20188
20285
  constructor(config, $tw2, PasswordService) {
20189
20286
  this.config = config;
@@ -20224,6 +20321,10 @@ var init_commander = __esm({
20224
20321
  this.AttachmentService = config.AttachmentService || AttachmentService;
20225
20322
  this.adapter = new SqliteAdapter(this.databasePath);
20226
20323
  this.engine = new PrismaClient2({ log: ["info", "warn"], adapter: this.adapter.adapter });
20324
+ this.versions = {
20325
+ tiddlywiki: $tw2.packageInfo.version,
20326
+ mws: package_default.version
20327
+ };
20227
20328
  }
20228
20329
  async init() {
20229
20330
  await this.adapter.init();
@@ -20231,6 +20332,19 @@ var init_commander = __esm({
20231
20332
  const users = await this.engine.users.count();
20232
20333
  if (!users) {
20233
20334
  this.setupRequired = true;
20335
+ } else {
20336
+ const checkBags = await this.engine.bags.findMany({
20337
+ where: { bag_name: { startsWith: "$:/" } },
20338
+ select: { bag_name: true, tiddlers: { select: { title: true } } }
20339
+ });
20340
+ checkBags.forEach((e) => {
20341
+ e.tiddlers.forEach((f) => {
20342
+ if (f.title !== e.bag_name) {
20343
+ if (e.bag_name === "$:/plugins/tiddlywiki/codemirror-fullscreen-editing" && f.title === "$:/plugins/tiddlywiki/codemirror-fullscreen") return;
20344
+ console.log(`The bag ${e.bag_name} has a tiddler ${f.title}, in the future this will be unsupported. This can occur if the top bag in a recipe is one of the system bags (starting with $:/)`);
20345
+ }
20346
+ });
20347
+ });
20234
20348
  }
20235
20349
  }
20236
20350
  $transaction(fn, options) {