@tiddlywiki/mws 0.1.9 → 0.1.12

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.
Files changed (57) hide show
  1. package/README.md +22 -22
  2. package/dist/metafile-esm.json +1 -1
  3. package/dist/mws.js +43 -50
  4. package/dist/mws.js.map +1 -1
  5. package/editions/mws-docs/tiddlers/$__StoryList.tid +5 -2
  6. package/editions/mws-docs/tiddlers/$__config_RelinkOnRename.tid +6 -0
  7. package/editions/mws-docs/tiddlers/2025-05-06 - syncer design.md +5 -1
  8. package/editions/mws-docs/tiddlers/2025-05-06 - syncer design.md.meta +1 -1
  9. package/editions/mws-docs/tiddlers/Bag.md +1 -0
  10. package/editions/mws-docs/tiddlers/Bag.md.meta +4 -0
  11. package/editions/mws-docs/tiddlers/Bags and Recipes Complex Example.md +11 -0
  12. package/editions/mws-docs/tiddlers/Bags and Recipes Complex Example.md.meta +4 -0
  13. package/editions/mws-docs/tiddlers/Bags and Recipes Model.md +14 -0
  14. package/editions/mws-docs/tiddlers/Bags and Recipes Model.md.meta +4 -0
  15. package/editions/mws-docs/tiddlers/Bags and Recipes Simple Example.md +13 -0
  16. package/editions/mws-docs/tiddlers/Bags and Recipes Simple Example.md.meta +4 -0
  17. package/editions/mws-docs/tiddlers/Code Layout.md +94 -0
  18. package/editions/mws-docs/tiddlers/Code Layout.md.meta +5 -0
  19. package/editions/mws-docs/tiddlers/Entity Access Control.md +1 -0
  20. package/editions/mws-docs/tiddlers/Entity Access Control.md.meta +5 -0
  21. package/editions/mws-docs/tiddlers/Entity Owner.md +3 -0
  22. package/editions/mws-docs/tiddlers/Entity Owner.md.meta +4 -0
  23. package/editions/mws-docs/tiddlers/Entity Permissions.md +7 -0
  24. package/editions/mws-docs/tiddlers/Entity Permissions.md.meta +4 -0
  25. package/editions/mws-docs/tiddlers/Entity.md +3 -0
  26. package/editions/mws-docs/tiddlers/Entity.md.meta +5 -0
  27. package/editions/mws-docs/tiddlers/HelloThere.tid +2 -2
  28. package/editions/mws-docs/tiddlers/Installation.md +31 -0
  29. package/editions/mws-docs/tiddlers/Installation.md.meta +5 -0
  30. package/editions/mws-docs/tiddlers/MWS Architecture_1.md +2 -0
  31. package/editions/mws-docs/tiddlers/{MWS Architecture.tid → MWS Architecture_1.md.meta } +2 -4
  32. package/editions/mws-docs/tiddlers/Recipe Bag Priority.md +5 -0
  33. package/editions/mws-docs/tiddlers/Recipe Bag Priority.md.meta +4 -0
  34. package/editions/mws-docs/tiddlers/Recipe.tid +6 -0
  35. package/editions/mws-docs/tiddlers/Security.md +7 -7
  36. package/editions/mws-docs/tiddlers/Security.md.meta +1 -1
  37. package/editions/mws-docs/tiddlers/Server Routes.md +54 -0
  38. package/editions/mws-docs/tiddlers/Server Routes.md.meta +5 -0
  39. package/editions/mws-docs/tiddlers/Site Admin.md +3 -0
  40. package/editions/mws-docs/tiddlers/Site Admin.md.meta +4 -0
  41. package/editions/mws-docs/tiddlers/Wiki.md +2 -0
  42. package/editions/mws-docs/tiddlers/Wiki.md.meta +4 -0
  43. package/editions/mws-docs/tiddlers/system/$__palettes_MUI_styles.css +1 -1
  44. package/editions/mws-docs/tiddlers/system/$__palettes_MUI_styles.css.meta +1 -1
  45. package/mws.run.mjs +2 -2
  46. package/package.json +1 -1
  47. package/plugins/client/src/multiwikiclientadaptor.ts +16 -9
  48. package/plugins/client/tiddlers/syncer/multiwikiclientadaptor.js +9 -10
  49. package/plugins/client/tiddlers/syncer/syncer.js +3 -3
  50. package/public/react-admin/main.js +10 -10
  51. package/public/react-admin/main.js.map +3 -3
  52. package/public/react-admin/stats.json +1 -1
  53. package/scripts.mjs +4 -5
  54. package/editions/mws-docs/tiddlers/Bags and Recipes.tid +0 -41
  55. package/editions/mws-docs/tiddlers/Installation.tid +0 -32
  56. package/prisma/test.sqlite +0 -0
  57. package/prisma/test.sqlite-journal +0 -0
@@ -1,2 +1,5 @@
1
- list: HelloThere Installation Usage Reference
2
- title: $:/StoryList
1
+ created: 20250901000936475
2
+ list: [[Server Routes]]
3
+ modified: 20250901003004551
4
+ title: $:/StoryList
5
+ type: text/vnd.tiddlywiki
@@ -0,0 +1,6 @@
1
+ created: 20250717212338113
2
+ modified: 20250717212338113
3
+ title: $:/config/RelinkOnRename
4
+ type: text/vnd.tiddlywiki
5
+
6
+ yes
@@ -12,4 +12,8 @@ There also isn't a good way to move tiddlers between levels. Admins will need to
12
12
 
13
13
  I'm not good at wikitext, but I can provide the endpoints for all of these operations as well as the client-side adapters and actions to use them.
14
14
 
15
- -- Arlen22
15
+ -- Arlen22
16
+
17
+ ## Update 2025-07-09
18
+
19
+ I've come up with a solution for this and opened a PR on GitHub [#9117](https://github.com/TiddlyWiki/TiddlyWiki5/pull/9117). I've also included the changes in the client plugin so MWS wikis can make use of them already. This is temporary and only allowed because the current version of MWS is still considered experimental.
@@ -1,5 +1,5 @@
1
1
  created: 20250507031006573
2
- modified: 20250624130310879
2
+ modified: 20250709174613734
3
3
  tags: Notes Roadmap
4
4
  title: 2025-05-06 - syncer design
5
5
  type: text/markdown
@@ -0,0 +1 @@
1
+ A bag is an [[Entity]] that stores tiddlers.
@@ -0,0 +1,4 @@
1
+ created: 20250717034520360
2
+ modified: 20250717035423554
3
+ title: Bag
4
+ type: text/markdown
@@ -0,0 +1,11 @@
1
+ A more complex example might be for a teacher working with a group of students:
2
+
3
+ - **student-{name}** bag for each students work
4
+ - **teacher-course** bag for the coursework, editable by the teacher
5
+ - **teacher-tools** bag for custom tools used by the teacher
6
+
7
+ Those bags would be exposed through the following hosted wikis:
8
+
9
+ - **student-{name}** hosted wiki for each students work, including the coursework material
10
+ - **teacher-course** hosted wiki for the coursework, editable by the teacher
11
+ - **teacher** hosted wiki for the teacher, bringing together all the bags, giving them an overview of all the students work
@@ -0,0 +1,4 @@
1
+ created: 20250718011700377
2
+ modified: 20250718031126481
3
+ title: Bags and Recipes Complex Example
4
+ type: text/markdown
@@ -0,0 +1,14 @@
1
+ The bags and recipes model is a reference architecture for how tiddlers can be shared between multiple wikis. It was first introduced by TiddlyWeb in 2008.
2
+
3
+ The principles of bags and recipes can be simply stated:
4
+
5
+ 1. Tiddlers are stored in named "bags"
6
+ 2. Bags have access controls that determines which users can read or write to them
7
+ 3. Recipes are named lists of bags, ordered from lowest priority to highest
8
+ 4. The tiddlers within a recipe are accumulated in turn from each bag in the recipe in order of increasing priority. Thus, if there are multiple tiddlers with the same title in different bags then the one from the highest priority bag will be used as the recipe tiddler
9
+ 5. Wikis are composed by splicing the tiddlers from the corresponding recipe into the standard TW5 HTML template
10
+
11
+ [[Bags and Recipes Simple Example]]
12
+
13
+ [[Bags and Recipes Complex Example]]
14
+
@@ -0,0 +1,4 @@
1
+ created: 20240309135835396
2
+ modified: 20250718012016047
3
+ title: Bags and Recipes Model
4
+ type: text/markdown
@@ -0,0 +1,13 @@
1
+ A very simple example of the recipe/bag model might be for a single user who maintains the following bags:
2
+
3
+ - **recipes** - tiddlers related to cooking recipes
4
+ - **work** - tiddlers related to work
5
+ - **app** - common tiddlers for customising TiddlyWiki
6
+
7
+ Those bags would be used with the following recipes:
8
+
9
+ - **recipes** --> recipes, app - wiki for working with recipes, with common custom components
10
+ - **work** --> work, app - wiki for working with work, with common custom components
11
+ - **app** --> app - wiki for maintaining custom components
12
+
13
+ All of this will work dynamically, so changes to the app bag will instantly ripple into the affected hosted wikis.
@@ -0,0 +1,4 @@
1
+ created: 20250718011135237
2
+ modified: 20250718031933624
3
+ title: Bags and Recipes Simple Example
4
+ type: text/markdown
@@ -0,0 +1,94 @@
1
+
2
+ The MWS repo is divided into separate projects in the `packages` folder. The entry point is in `packages/mws/src/index.ts`. The entry point imports the `server`, `commander`, and `events` projects.
3
+
4
+ The entire server uses Promises and async functions for pretty much everything. Synchronous file system calls should be avoided as much as possible.
5
+
6
+ The `events` project is the foundation of MWS. It contains an `EventEmitter` instance that everything else subscribes to.
7
+
8
+ Events are emitted asyncly. Event listeners are awaited with `Promise.all`, and rejections throw back to the event emit call. This is intentional because it is the heart of the entire server, not just a public event bus, and errors shouldn't be ignored. Errors that come from things like attempting to send SSE events to other clients, however, should not be thrown because they aren't relevent to the source of the event.
9
+
10
+ There should be no singleton references other than the event emitter and event handlers should be as pure as possible, so that in theory it would be possible to run multiple completely separate MWS servers in the same process.
11
+
12
+ The `commander` project handles the CLI parsing code. It exports a default function which MWS calls to execute the CLI. Commander emits several events during execution, which MWS hooks into to scaffold the rest of the server.
13
+
14
+ It also exports the base class for commands to inherit from, and because it instantiates the commands, commands should not specify their own constructor. Additional instance properties may be added to commands in the `cli.execute.before` event.
15
+
16
+ The `server` project handles all web related stuff, but in an MWS-agnostic way. It only requires the `events` project, so it could be used as the foundation for unrelated webservers. Its internal API is directly inspired by the TiddlyWiki server API, with routing and centralized handling of the request body.
17
+
18
+ The `mws` project is the application layer of MWS and ties everything else together. It defines all the commands and web server routes and handles the database connection.
19
+
20
+ The `react-admin` package is the Admin UI. It's based on react, and is built automatically when the dev server is enabled. You can find the server route in `packages/mws/src/services/setupDevServer.ts`
21
+
22
+ ## Events
23
+
24
+ If this all sounds a bit confusing, here are the events that are emitted on a normal startup.
25
+
26
+ - `zod.make` - Emitted by `server` to extend the zod global.
27
+ - `cli.register` - Emitted by `commander` to register commands.
28
+ - `cli.commander` - Emitted by `commander` after routes are registered, but before help is printed.
29
+ - `cli.execute.before` - Emitted by `commander` right before the command is executed. This allows adding properties to the command instance for use later in the application.
30
+
31
+ These next ones are attachment points for further extension of MWS. They are emitted in the main `cli.execute.before` listener that MWS attaches.
32
+
33
+ - `mws.cache.init.before`
34
+ - `mws.cache.init.after`
35
+ - `mws.adapter.init.before`
36
+ - `mws.adapter.init.after`
37
+ - `mws.config.init.before`
38
+ - `mws.config.init.after`
39
+
40
+ Next, these are emitted by the listen command, either by `mws` or by `server`.
41
+
42
+ - `listen.router.init`
43
+ - `mws.router.init`
44
+ - `mws.routes.important`
45
+ - `mws.routes`
46
+ - `mws.routes.fallback`
47
+
48
+ And finally the event emitted after the command ends.
49
+
50
+ - `cli.execute.after`
51
+
52
+ ## Event nesting
53
+
54
+ Some of them are nested. For instance, if I log the event name when it is emitted, and then how long it took when it completes, this is the output (indented for clarity).
55
+
56
+ ```
57
+ zod.make
58
+ zod.make: 0.123ms
59
+
60
+ cli.register
61
+ cli.register: 0.088ms
62
+
63
+ cli.commander
64
+ cli.commander: 0.019ms
65
+
66
+ cli.execute.before
67
+ mws.cache.init.before
68
+ mws.cache.init.before: 0.014ms
69
+ mws.cache.init.after
70
+ mws.cache.init.after: 0.013ms
71
+ mws.adapter.init.before
72
+ mws.adapter.init.before: 0.007ms
73
+ mws.adapter.init.after
74
+ mws.adapter.init.after: 0.006ms
75
+ mws.config.init.before
76
+ mws.config.init.before: 0.008ms
77
+ mws.config.init.after
78
+ mws.config.init.after: 0.009ms
79
+ cli.execute.before: 1.171s
80
+
81
+ listen.router.init
82
+ mws.router.init
83
+ mws.router.init: 0.012ms
84
+ mws.routes.important
85
+ mws.routes.important: 0.006ms
86
+ mws.routes
87
+ mws.routes: 2.754ms
88
+ mws.routes.fallback
89
+ mws.routes.fallback: 0.054ms
90
+ listen.router.init: 4.002ms
91
+
92
+ cli.execute.after
93
+ cli.execute.after: 0.015ms
94
+ ```
@@ -0,0 +1,5 @@
1
+ created: 20250710211718128
2
+ modified: 20250710211749763
3
+ tags: Architecture
4
+ title: Code Layout
5
+ type: text/markdown
@@ -0,0 +1 @@
1
+ Each [[Entity]] has a list of roles and the [[permissions|Entity Permissions]] they have on that entity.
@@ -0,0 +1,5 @@
1
+ created: 20250713025613925
2
+ modified: 20250714124428825
3
+ tags: Reference
4
+ title: Entity Access Control
5
+ type: text/markdown
@@ -0,0 +1,3 @@
1
+ When a user creates an [[Entity]], they can optionally become the owner of the entity. Owners have full [[permission|Entity Permissions]] over the entity. There can only be one or no owner of an entity.
2
+
3
+ Entity owners can not transfer ownership to another user. Only [[site admins|Site Admin]] can change ownership.
@@ -0,0 +1,4 @@
1
+ created: 20250713030055363
2
+ modified: 20250714125005911
3
+ title: Entity Owner
4
+ type: text/markdown
@@ -0,0 +1,7 @@
1
+ There are 3 levels of permissions that can be assigned on the [[Entity Access Control]] list.
2
+
3
+ - **ADMIN** - Update the [[Entity Access Control]] list for this entity. Also granted WRITE and READ.
4
+ - **WRITE** - Create, update, and delete tiddlers. Also granted READ.
5
+ - **READ** - List and read tiddlers.
6
+
7
+ The [[Entity Owner]] and the [[site admins|Site Admin]] have full permissions over the [[entity]].
@@ -0,0 +1,4 @@
1
+ created: 20250713025717567
2
+ modified: 20250718013201161
3
+ title: Entity Permissions
4
+ type: text/markdown
@@ -0,0 +1,3 @@
1
+ An entity is a [[Bag]] or a [[Recipe]].
2
+
3
+ Configuring what certain roles can do to entities is done with [[Entity Access Control]].
@@ -0,0 +1,5 @@
1
+ created: 20250713025508951
2
+ modified: 20250717212511382
3
+ tags:
4
+ title: Entity
5
+ type: text/markdown
@@ -1,5 +1,5 @@
1
1
  created: 20250417170314382
2
- modified: 20250612222324438
2
+ modified: 20250717214743442
3
3
  tags: TableOfContents
4
4
  title: HelloThere
5
5
  type: text/vnd.tiddlywiki
@@ -11,7 +11,7 @@ type: text/vnd.tiddlywiki
11
11
 
12
12
  Planned features include:
13
13
 
14
- * Hosting multiple wikis at once, using the [[Bags and Recipes]] mechanism for sharing data between them
14
+ * Hosting multiple wikis at once, using the [[Bags and Recipes Model]] for sharing data between them
15
15
  * Full support for SQLite, as well as MariaDB/MySQL, Postgres, and Microsoft SQL Server
16
16
  * Robust built-in synchronisation handlers for syncing data to the filesystem
17
17
  * Flexible authentication and authorisation options
@@ -0,0 +1,31 @@
1
+ These instructions require minimal knowledge of the terminal and require NodeJS to be installed.
2
+
3
+ - Open a terminal window and set the current directory to the folder you want to create the project folder in.
4
+ - The init command creates the project folder and installs the required dependencies and config files. You can change the name to whatever you like.
5
+ <<.copy-code-to-clipboard """npm init @tiddlywiki/mws@latest "new_folder_name" """>>
6
+ - Set the current directory to the project folder that was just created:
7
+ <<.copy-code-to-clipboard """cd "new_folder_name" """>>
8
+ - Initialize the database
9
+ <<.copy-code-to-clipboard "npx mws init-store">>
10
+ - Start MWS:
11
+ <<.copy-code-to-clipboard "npx mws listen --listener">>
12
+ - Visit [[http://localhost:8080/]] in a browser on the same computer.
13
+ - When you have finished using MWS, stop the server with <kbd>ctrl-C</kbd>
14
+
15
+ See [[Troubleshooting]] if you encounter any errors.
16
+
17
+ ### Updating MWS
18
+
19
+ To update your copy of MWS in the future with newer changes will require re-downloading the code, taking care not to lose any changes you might have made.
20
+
21
+ - Make a backup: Copy or zip your project folder to a safe backup folder. <<.copy-code-to-clipboard """tar -cf archive.tar "new_folder_name" """>>
22
+ - Get the latest version. Notice that the second word is `install` instead of `init`. This pulls the latest version from NPM and installs it. <<.copy-code-to-clipboard "npm install @tiddlywiki/mws@latest --save-exact">>
23
+ - Run MWS. On startup, MWS checks the database schema and updates it automatically if there are changes. Normally this works just fine, but it can fail, which is why it's important to save a backup first.
24
+
25
+ ### Git repo
26
+
27
+ It is recommended to save a history of your project configuration using git,
28
+
29
+ - On Windows you can use [[GitHub Desktop|https://github.com/apps/desktop]].
30
+ - On Linux, git is usually preinstalled or available via the default package manager for your distro.
31
+
@@ -0,0 +1,5 @@
1
+ created: 20241105133737778
2
+ modified: 20250714123715061
3
+ tags: TableOfContents
4
+ title: Installation
5
+ type: text/markdown
@@ -1,7 +1,5 @@
1
1
  created: 20250612170433199
2
- modified: 20250612170434896
2
+ modified: 20250710211738963
3
3
  tags: TableOfContents
4
4
  title: Architecture
5
- type: text/vnd.tiddlywiki
6
-
7
- <<toc>>
5
+ type: text/markdown
@@ -0,0 +1,5 @@
1
+ A [[Recipe]] orders its [[bags|Bag]] by priority.
2
+
3
+ If there are tiddlers with duplicate names in different bags, the tiddler from the bag that is higher in the priority list is used as the recipe tiddler.
4
+
5
+ New tiddlers are added to the bag at top of the list.
@@ -0,0 +1,4 @@
1
+ created: 20250717213602278
2
+ modified: 20250718012651305
3
+ title: Recipe Bag Priority
4
+ type: text/markdown
@@ -0,0 +1,6 @@
1
+ created: 20250717212608133
2
+ modified: 20250717213112789
3
+ title: Recipe
4
+ type: text/vnd.tiddlywiki
5
+
6
+ A recipe is an [[Entity]] that stores a list of bags by [[priority|Recipe Bag Priority]].
@@ -11,17 +11,17 @@ The primary use cases for MWS are
11
11
 
12
12
  While these are the goals of MWS, it is still in early development, so none of these security restraints have actually been put in place yet. This is a work in progress, and the direction we're headed.
13
13
 
14
- ## Potential weaknesses
15
-
16
- - **Not using HTTPS**
17
- - **Oracles** that leak information through observable side-effects, such as network traffic, without directly revealing the contents.
18
- - **Multi-user**: Users with write access can modify bags to gain access to other tiddlers in a different recipe that are supposed to be private.
19
-
20
14
  ## Don't add untrusted bags to your recipe.
21
15
 
22
16
  Generally speaking, wiki text is quite powerful, almost as powerful as JavaScript. Button clicks can run widget actions, which can read and change any tiddler in the current recipe. Any user could easily cause TiddlyWiki to write tiddlers to other bags via actions.
23
17
 
24
- A possible protection from this is using the referrer header to restrict edits to from a wiki to only follow the rules for the recipe that is open. In other words, if you have a recipe open, code in that page cannot use your credentials to somehow write to unrelated bags.
18
+ A user can also modify a bag they have write access to so that when a different user loads that bag in their own recipe it gives the first user access to tiddlers that the second user would consider private. This flaw is almost inherent to the idea of bags and recipes and cannot be avoided.
19
+
20
+ ## Potential weaknesses
21
+
22
+ - **Not using HTTPS** is always the number one weakness. If you're on an open WIFI network, your session info can be read by anyone within 100 meters.
23
+ - **Oracles** that leak information through observable side-effects, such as network traffic, without directly revealing the contents.
24
+ - **Multi-user**: Users with write access can modify bags to gain access to other tiddlers in a different recipe that are supposed to be private.
25
25
 
26
26
  ## Protection strategies
27
27
 
@@ -1,5 +1,5 @@
1
1
  created: 20250522181107057
2
- modified: 20250612224336089
2
+ modified: 20250709133857831
3
3
  tags: TableOfContents
4
4
  title: Security
5
5
  type: text/markdown
@@ -0,0 +1,54 @@
1
+ The routing for the server uses the same concept of routes as the TiddlyWiki core server, but significantly enhanced with TypeScript types and request helpers and primitives, including request validation.
2
+
3
+ ## Server Routing
4
+
5
+ Routes are registered as a tree. The router starts at the root node and works its way down, using the regex and method of each route to check if the request matches. Once it finds a match, it recursively checks the children of those matches.
6
+
7
+ - The request method is "narrowed". Parent routes restrict the methods their child routes can accept.
8
+
9
+ Once the full route is determined, it handles the request body based on the options of the matched route, then it calls each handler, starting with the root handler, and continuing down.
10
+
11
+ - The request body format is determined by the parent routes, and child routes cannot change the body format if a parent route sets it.
12
+
13
+ In the example below, if the request matches child 2a, the router calls the root handler, then the child 2 handler, then the child 2a handler.
14
+
15
+ ---
16
+
17
+ [root]
18
+
19
+ - child 1
20
+ - child 1a
21
+ - child 2
22
+ - child 2a
23
+ - child 2b
24
+
25
+ ---
26
+
27
+ ## Server Route Definition
28
+
29
+ The type definitions for this interface contains comments with more details. Please see that for more info.
30
+
31
+ - **path**: A regular expression (must start with `^` to match the start of the path)
32
+ - **pathParams**: Keys for the Regex match params. The object is added to the request state.
33
+ - **method**: Array of methods supported by this route.
34
+ - **bodyFormat**: The desired body format for this route. Ignored if the parent also specifies a body format.
35
+ - **denyFinal**: Parent routes can set this so the request is rejected if no child routes are matched.
36
+ - **securityChecks**: additional security checks for the server to perform.
37
+ - **requestedWithHeader**: requires a custom `X-Requested-With` header to be set to one of the valid values (`fetch`, `XMLHttpRequest`, `TiddlyWiki`) in order to prevent form and `no-cors` requests.
38
+
39
+ ## Request Validation
40
+
41
+ The `zodRoute` helper function implements validation checks and additional typing for the request object. See the comments and types in the `zodRoute` file for further information.
42
+
43
+ The zod options accept a function which returns a zod schema (or a hashmap of keys to zod schemas).
44
+
45
+ - **zodPathParams**: the path params object
46
+ - **zodQueryParams**: the query params object
47
+ - **zodRequestBody**: the request body
48
+ - The **path** is a string instead of a regex. The path is split on the `/` and names starting with a colon become path params.
49
+ - The **method**, **body format**, and **security checks** are same as above.
50
+ - **registerError**: An error instance to capture a stack trace in case it's needed for any reason. Note that in most runtimes the performance penalty is incurred when the stack trace is read, not when the error instance is created.
51
+
52
+
53
+
54
+
@@ -0,0 +1,5 @@
1
+ created: 20250831152841666
2
+ modified: 20250901003034562
3
+ tags: Architecture Developers
4
+ title: Server Routes
5
+ type: text/markdown
@@ -0,0 +1,3 @@
1
+ The "Site Admin" is a role created by MWS. It can do everything on the site.
2
+
3
+ It is distinct from the [[admin permission|Entity Permissions]] on entities.
@@ -0,0 +1,4 @@
1
+ created: 20250714125009642
2
+ modified: 20250718005750287
3
+ title: Site Admin
4
+ type: text/markdown
@@ -0,0 +1,2 @@
1
+ Wikis are the user interfaces for [[recipes|Recipe]], and are available at &lt;host&gt;/wiki/&lt;recipe&gt;.
2
+ TiddlyWiki 5 is the default wiki for new recipes.
@@ -0,0 +1,4 @@
1
+ created: 20250718020459001
2
+ modified: 20250718022736895
3
+ title: Wiki
4
+ type: text/markdown
@@ -145,7 +145,7 @@ type: text/css
145
145
  /* --------------------------------------------------------------------- */
146
146
  /* Typography */
147
147
  /* --------------------------------------------------------------------- */
148
- --foreground: var(--color-grey-900);
148
+ --foreground: var(--color-grey-800);
149
149
  /* text.primary */
150
150
  --muted-foreground: var(--color-grey-700);
151
151
  /* text.secondary */
@@ -1,6 +1,6 @@
1
1
  created: 20250513234032612
2
2
  description: Colors reflecting the MWS admin UI, responsive to system settings.
3
- modified: 20250613012927316
3
+ modified: 20250901002906435
4
4
  tags: $:/tags/Stylesheet
5
5
  title: $:/palettes/MUI/styles
6
6
  type: text/css
package/mws.run.mjs CHANGED
@@ -19,7 +19,7 @@ if(!pkg?.dependencies?.["@tiddlywiki/mws"] || pkg.name !== "@tiddlywiki/mws-inst
19
19
  process.exit(1);
20
20
  }
21
21
 
22
- import(`${cwd}/node_modules/@tiddlywiki/mws/dist/mws.js`).then(mws => mws.default()).catch(console.error);
22
+ import(`file://${cwd}/node_modules/@tiddlywiki/mws/dist/mws.js`).then(mws => mws.default()).catch(console.error);
23
23
 
24
24
  function tryParseJSON(file) {
25
25
  try {
@@ -27,4 +27,4 @@ function tryParseJSON(file) {
27
27
  } catch(e) {
28
28
  return undefined;
29
29
  }
30
- }
30
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tiddlywiki/mws",
3
3
  "description": "TiddlyWiki Multiple Wiki Server",
4
4
  "private": false,
5
- "version": "0.1.9",
5
+ "version": "0.1.12",
6
6
  "bin": {
7
7
  "mws": "./mws.run.mjs"
8
8
  },
@@ -124,6 +124,8 @@ interface SyncAdaptor<AD> {
124
124
 
125
125
  isReady?(): boolean;
126
126
 
127
+ registerSyncer?(syncer: Syncer<AD>): void;
128
+
127
129
  getStatus?(
128
130
  cb: ServerStatusCallback
129
131
  ): void;
@@ -190,6 +192,7 @@ interface SyncAdaptor<AD> {
190
192
  displayLoginPrompt?(syncer: Syncer<AD>): void;
191
193
  login?(username: string, password: string, cb: (err: any) => void): void;
192
194
  logout?(cb: (err: any) => void): any;
195
+
193
196
  }
194
197
  interface SyncerTiddlerInfo<AD> {
195
198
  /** this comes from the wiki changeCount record */
@@ -249,7 +252,7 @@ class MultiWikiClientAdaptor implements SyncAdaptor<MWSAdaptorInfo> {
249
252
  private serverUpdateConnectionStatus!: string;
250
253
  private isDevMode: boolean;
251
254
  private useGzipStream: boolean;
252
- private triggerPoll: (() => void) | null = null;
255
+ private syncer: Syncer<MWSAdaptorInfo> | null = null;
253
256
 
254
257
  name = "multiwikiclient";
255
258
  private supportsLazyLoading = true;
@@ -283,15 +286,21 @@ class MultiWikiClientAdaptor implements SyncAdaptor<MWSAdaptorInfo> {
283
286
  setLoggerSaveBuffer(loggerForSaving: Logger) {
284
287
  this.logger.setSaveBuffer(loggerForSaving);
285
288
  }
289
+
286
290
  isReady() {
287
291
  return true;
288
292
  }
289
- subscribe(callback: () => void) {
290
- // TODO: not working at the moment for some reason
291
- console.log("Subscribing to server updates");
292
- this.triggerPoll = callback;
293
- this.connectRecipeEvents();
293
+
294
+ registerSyncer(syncer: Syncer<MWSAdaptorInfo>): void {
295
+ this.syncer = syncer;
296
+ if (this.useServerSentEvents)
297
+ this.connectRecipeEvents();
298
+ }
299
+
300
+ triggerPoll() {
301
+ this.syncer?.syncFromServer();
294
302
  }
303
+
295
304
  private getHost() {
296
305
  var text = this.wiki.getTiddlerText(CONFIG_HOST_TIDDLER, DEFAULT_HOST_TIDDLER), substitutions = [
297
306
  { name: "protocol", value: document.location.protocol },
@@ -540,9 +549,7 @@ class MultiWikiClientAdaptor implements SyncAdaptor<MWSAdaptorInfo> {
540
549
  // this.syncer && this.syncer.enqueueLoadTiddler(title);
541
550
  // }
542
551
  }
543
- private get syncer() {
544
- if ($tw.syncadaptor === this) return $tw.syncer as Syncer<MWSAdaptorInfo>;
545
- }
552
+
546
553
  async loadTiddlers(options: {
547
554
  syncer: Syncer<MWSAdaptorInfo>;
548
555
  titles: string[];
@@ -31,7 +31,7 @@ var CONFIG_HOST_TIDDLER = "$:/config/multiwikiclient/host", DEFAULT_HOST_TIDDLER
31
31
  var SERVER_NOT_CONNECTED = "NOT CONNECTED", SERVER_CONNECTING_SSE = "CONNECTING SSE", SERVER_CONNECTED_SSE = "CONNECTED SSE", SERVER_POLLING = "SERVER POLLING";
32
32
  class MultiWikiClientAdaptor {
33
33
  constructor(options) {
34
- this.triggerPoll = null;
34
+ this.syncer = null;
35
35
  this.name = "multiwikiclient";
36
36
  this.supportsLazyLoading = true;
37
37
  this.error = null;
@@ -66,11 +66,14 @@ class MultiWikiClientAdaptor {
66
66
  isReady() {
67
67
  return true;
68
68
  }
69
- subscribe(callback) {
70
- // TODO: not working at the moment for some reason
71
- console.log("Subscribing to server updates");
72
- this.triggerPoll = callback;
73
- this.connectRecipeEvents();
69
+ registerSyncer(syncer) {
70
+ this.syncer = syncer;
71
+ if (this.useServerSentEvents)
72
+ this.connectRecipeEvents();
73
+ }
74
+ triggerPoll() {
75
+ var _a;
76
+ (_a = this.syncer) === null || _a === void 0 ? void 0 : _a.syncFromServer();
74
77
  }
75
78
  getHost() {
76
79
  var text = this.wiki.getTiddlerText(CONFIG_HOST_TIDDLER, DEFAULT_HOST_TIDDLER), substitutions = [
@@ -295,10 +298,6 @@ class MultiWikiClientAdaptor {
295
298
  // this.syncer && this.syncer.enqueueLoadTiddler(title);
296
299
  // }
297
300
  }
298
- get syncer() {
299
- if ($tw.syncadaptor === this)
300
- return $tw.syncer;
301
- }
302
301
  loadTiddlers(options) {
303
302
  return __awaiter(this, void 0, void 0, function* () {
304
303
  const { syncer, titles, onNext, onDone, onError } = options;
@@ -139,9 +139,9 @@ function Syncer(options) {
139
139
  self.handleLazyLoadEvent(title);
140
140
  });
141
141
  }
142
- if(this.syncadaptor.subscribe) this.syncadaptor.subscribe(function(){
143
- self.syncFromServer();
144
- });
142
+
143
+ if(this.syncadaptor.registerSyncer)
144
+ this.syncadaptor.registerSyncer(this);
145
145
 
146
146
  // Get the login status
147
147
  this.getStatus(function(err,isLoggedIn) {