Architecture
TableOfContents
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.
The principles of bags and recipes can be simply stated:
A very simple example of the recipe/bag model might be for a single user who maintains the following bags:
Those bags would be used with the following recipes:
All of this will work dynamically, so changes to the app bag will instantly ripple into the affected hosted wikis.
A more complex example might be for a teacher working with a group of students:
Those bags would be exposed through the following hosted wikis:
MultiWikiServer is a new development that drastically improves TiddlyWiki's capabilities when running as a server under Node.js. It brings TiddlyWiki up to par with common web-based tools like WordPress or MediaWiki by supporting multiple wikis and multiple users at the same time.
Planned features include:
MWS is currently under development at GitHub but it is already functional and usable.
These instructions require minimal knowledge of the terminal and require NodeJS to be installed.
npm init @tiddlywiki/mws@latest "new_folder_name"
cd "new_folder_name"
npm start
See Troubleshooting if you encounter any errors.
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.
tar -cf archive.tar my_folder
install
instead of init
. This pulls the latest version from NPM and installs it. npm install @tiddlywiki/mws@latest
npm start
GET /login
and POST /logout
[name, description]
[id, username]
SQLite is a very popular open source, embedded SQL database with some unusual characteristics. It has proved itself to be robust, fast and scalable, and has been widely adopted in a range of applications including web browsers, mobile devices, and embedded systems.
The "embedded" part means that developers access SQLite as a library of C functions that run as part of a larger application. This contrasts with more familiar database applications like Microsoft's SQL Server or Oracle that are accessed as network services.
MWS uses SQLite for the tiddler store and associated data. It brings many advantages:
TiddlyWiki 5 has always incorporated a database. Until MWS, that database has always been a custom tiddler database written in JavaScript. Over the years it has been enhanced and optimised with indexes and other database features that have given us reasonably decent performance for a range of common operations.
One particular misconception to avoid is the idea that SQLite replaces the folders of .tid
files that characterise the Node.js configuration of TiddlyWiki. Those files are generated by a separate sync operation. They are not the actual database itself. In the context of MWS, SQLite is a fast and efficient way to store tiddlers between requests. Regardless of how tiddlers are stored internally, MWS can still save .tid
files to the file system, just as TW5 does today.
SQLite is perfect for MWS because it doesn't require any extra setup. But MWS is not restricted to SQLite. It uses Prisma for the database access layer, which supports several other database engines, including MariaDB (the MySQL fork) and Postgres.
Our application has transitioned from a conventional username/password authentication system to a more robust Authentication and Authorization implementation. This new system supports multiple user accounts, roles, permissions, and a comprehensive access control list.
Conceptually, there are 6 access levels.
When you first launch the Multiwiki Server, it creates a default admin user. The username is admin
and the password is 1234
. To secure your installation you should change this immediately.
Access Control is implemented separately for both recipes and bags, but bags can in inherit the ACL of recipes they are added to.
If this were reversed, and users with explicit "read" access were forbidden from writing, it would significantly complicate roles.
Imagine a group of engineers working on several projects. Each project has people who are responsible for editing the documentation for everyone else. So everyone needs to be granted the read permission on all projects, but only a few people are granted the write permission on each project.
The easiest approach is to maintain one role which grants "read" access to all users, and then maintain additional roles to grant "write" access to the users responsible for each project.
If granting read access explicitly prevented a user from writing, we would need to create two roles for each project, one which which grants write access for the project, and another which grants read access to all other projects.
Every time a new project is added, all other projects would need to grant "read" access to that new "all projects but one" role on every single wiki for every single project in the entire organization.
Users can be administered through two interfaces:
Each user account contains the following essential components:
The MultiWikiServer HTTP API provides management and tiddler endpoints. It was based on the API of TiddlyWeb, first developed in 2008 by Chris Dent, but is more oriented around JSON and Typescript.
The design goals of the API are:
General points about the design:
This is more or less a reference on the design philosophy.
The server comprises several classes which handle various parts of the request path.
The Listener classes call the Router class with incoming requests. The Router class starts an async (Promise-based) code path with a catch handler protecting it.
There are two kinds of classes, routing and state.
Routing classes hold config state for that part of the request path. They are used to reach a specific objective. Examples include the Router and Authentication classes.
State classes hold information specific to each request. It may be used by any of the routing classes. The primary goal is usually to hide implementation details, or to pass information between routing classes. The StateObject class is the primary example, but modules may have their own state classes.
Both kinds of classes should check incoming information thoroughly and throw quickly if anything is wrong. The constructors of state classes are part of the request chain and may throw as well.
The request may be completed at any point in the request chain by throwing the STREAM_ENDED symbol. The catch all handler will ignore the symbol, but will send an error 500 if headers are not marked as sent at that point.
It is important that the entire request be awaited and eventually resolve or reject. A promise should never be left hanging. The Router class takes care of making sure every request has finished with some response, but if the promise never resolves or rejects, there is no way to do this.
Installation may fail with errors related to gyp
or prebuild
. These errors are caused by missing dependencies or incorrect versions of dependencies.
Note that in most cases, these errors occur because of the use of the npm module better-sqlite3. This module is mostly written in C, and thus requires compilation for the target platform. MWS supports switchable database engines, and also supports the use of the node-sqlite3-wasm module which is written in JavaScript and does not require compilation and so may avoid these errors. See Database Engines for more details of how to switch between engines.
The following steps may help resolve errors involving gyp
or prebuild
:
npm install -g npm@latest
npm cache clean --force
node_modules
folder in your project by running the following command in your terminal:
rm -rf node_modules
npm install
npm rebuild
gyp
and prebuild
dependencies. You can do this by running the following commands in your terminal:
npm install -g node-gyp
npm install -g prebuild
npm install
Once MWS is successfully installed, you can access it by visiting http://localhost:8080 in a browser on the same computer.
On first start, a default user is created with username admin
and password 1234
. However, also by default, the server is only accessible to browsers on the same machine.
If you intend to put an MWS installation on a public network like the Internet, the server will need to be secured with the following steps: