@tiddlywiki/mws 0.0.16 → 0.0.18
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 +22 -33
- package/dist/server.d.ts +15 -9
- package/dist/server.js +119 -61
- package/dist/server.js.map +1 -1
- package/editions/mws-docs/tiddlers/$__StoryList.tid +1 -3
- package/editions/mws-docs/tiddlers/2025-02-18 - User Management.md +56 -0
- package/editions/mws-docs/tiddlers/2025-02-18 - User Management.md.meta +5 -0
- package/editions/mws-docs/tiddlers/2025-04-03 - Phases of Development.md +64 -0
- package/editions/mws-docs/tiddlers/2025-04-03 - Phases of Development.md.meta +5 -0
- package/editions/mws-docs/tiddlers/2025-04-13 - Plugins.md +18 -0
- package/editions/mws-docs/tiddlers/2025-04-13 - Plugins.md.meta +5 -0
- package/editions/mws-docs/tiddlers/2025-05-04.md +13 -0
- package/editions/mws-docs/tiddlers/2025-05-04.md.meta +5 -0
- package/editions/mws-docs/tiddlers/2025-05-06.md +19 -0
- package/editions/mws-docs/tiddlers/2025-05-06.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Checklists and Features.md +15 -0
- package/editions/mws-docs/tiddlers/Checklists and Features.md.meta +5 -0
- package/editions/mws-docs/tiddlers/MWS Architecture.md +15 -0
- package/editions/mws-docs/tiddlers/MWS Architecture.md.meta +5 -0
- package/editions/mws-docs/tiddlers/Notes.tid +5 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Dark +173 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Dark.meta +6 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Light +172 -0
- package/editions/mws-docs/tiddlers/system/$__palettes_MUI-Light.meta +6 -0
- package/package.json +9 -21
- package/plugins/client/tiddlers/readme.tid +0 -3
- package/react-user-mgmt/public/main.js +32 -32
- package/react-user-mgmt/public/main.js.map +4 -4
- package/react-user-mgmt/public/stats.json +1 -1
- package/scripts.mjs +34 -0
- package/.env-cmdrc +0 -5
package/README.md
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
# MultiWikiServer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Multiple users, multiple wikis for TiddlyWiki.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Bag & Recipe system for storing tiddlers.
|
|
6
|
+
- User and Role management with ACL.
|
|
7
|
+
- Multiple database engines supported, using Prisma.
|
|
8
|
+
- Third-party OAuth and password-based login.
|
|
9
|
+
|
|
10
|
+
## Flexible and Extendible
|
|
11
|
+
|
|
12
|
+
- Plugins can add routes and hooks.
|
|
13
|
+
- Abstractions everywhere, allowing flexibility.
|
|
14
|
+
- The source code is fully typed and easy to navigate.
|
|
15
|
+
- Admin endpoints can also be called from the CLI.
|
|
16
|
+
|
|
17
|
+
Most of these features are still in development.
|
|
18
|
+
|
|
19
|
+
**Do not use it to protect feelings or intellectual property.**
|
|
20
|
+
|
|
21
|
+
## How to run
|
|
6
22
|
|
|
7
23
|
The init command creates a new folder and installs what you need to get started.
|
|
8
24
|
|
|
@@ -36,42 +52,15 @@ If there are any database changes, MWS should pick them up and apply them. The c
|
|
|
36
52
|
If you want to work on the project,
|
|
37
53
|
|
|
38
54
|
- `git clone https://github.com/TiddlyWiki/MultiWikiServer`
|
|
55
|
+
- `cd MultiWikiServer`
|
|
39
56
|
- `npm install` or `npm run install-android`
|
|
40
57
|
- `cd react-user-mgmt`
|
|
41
58
|
- `npm install`
|
|
42
59
|
- `cd ..`
|
|
43
|
-
- `npm run certs` - if you want https
|
|
60
|
+
- `npm run certs` - if you want https (unix only)
|
|
44
61
|
- `npm start` - this runs the build and test every time, but it's pretty fast
|
|
45
62
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### The Server
|
|
49
|
-
|
|
50
|
-
- Supports HTTP and HTTPS listeners. All requests are funneled into one stack.
|
|
51
|
-
- Uses abstractions and state objects to make the server as flexible as possible.
|
|
52
|
-
- Supports overriding classes to implement custom handling of various features.
|
|
53
|
-
- All of the features from the old MWS branch have been converted to the new system.
|
|
54
|
-
|
|
55
|
-
### The Store
|
|
56
|
-
|
|
57
|
-
- Written using Prisma and entirely promise-based.
|
|
58
|
-
- Swapping to a different database engine should be a breeze. For sqlite it uses the libsql adapter, which also allows connections to libsql servers.
|
|
59
|
-
- The tiddler text attachment system, which stores some tiddler bodies on the file system, is promise-based and can be modified to store files in the cloud.
|
|
60
|
-
|
|
61
|
-
### The Features
|
|
62
|
-
|
|
63
|
-
- Bag & Recipe system for storing tiddlers.
|
|
64
|
-
- User and Role management with ACL.
|
|
65
|
-
- Attachment system for storing binary tiddlers on the file system.
|
|
66
|
-
- Various import and export commands (currently still in development).
|
|
67
|
-
- Customization of these features should be quite easy as they are fairly self-contained. The TypeScript code is fully typed and easy to navigate.
|
|
68
|
-
|
|
69
|
-
### Planned (hopefully) for the future
|
|
70
|
-
|
|
71
|
-
- AuthJS or a similar integration that supports third-party OAuth (you can already write your own).
|
|
72
|
-
- Compiling filters to SQL to optimize memory on both the client and server.
|
|
73
|
-
- Support for other database and storage systems. Most likely MariaDB and Postgres.
|
|
74
|
-
- Additional recipe strategies with features like prefixed bags and namespaces.
|
|
75
|
-
- Server rendering of pages, for a more wikipedia-like experience.
|
|
63
|
+
The development wiki will be active at http://localhost:8080/dev
|
|
76
64
|
|
|
65
|
+
You can change the listeners as explained in the mws.dev.mjs file.
|
|
77
66
|
|
package/dist/server.d.ts
CHANGED
|
@@ -5,13 +5,13 @@ import { PassThrough, Writable } from 'node:stream';
|
|
|
5
5
|
import * as z from 'zod';
|
|
6
6
|
import { z as z$1, ZodEffects } from 'zod';
|
|
7
7
|
import { PrismaClient, Prisma } from '@prisma/client';
|
|
8
|
-
import { ITXClientDenyList, Types } from '@prisma/client/runtime/library';
|
|
9
8
|
import * as fs from 'fs';
|
|
10
9
|
import * as tiddlywiki from 'tiddlywiki';
|
|
11
|
-
import { TW } from 'tiddlywiki';
|
|
12
|
-
import
|
|
10
|
+
import { TW, TiddlerFieldModule } from 'tiddlywiki';
|
|
11
|
+
import { ITXClientDenyList, Types } from '@prisma/client/runtime/library';
|
|
13
12
|
import * as commander from 'commander';
|
|
14
13
|
import { SqlMigrationAwareDriverAdapterFactory, SqlDriverAdapter } from '@prisma/driver-adapter-utils';
|
|
14
|
+
import * as http2 from 'node:http2';
|
|
15
15
|
import * as http2$1 from 'http2';
|
|
16
16
|
import { OutgoingHttpHeaders, IncomingHttpHeaders as IncomingHttpHeaders$1, IncomingMessage as IncomingMessage$1, ServerResponse as ServerResponse$1 } from 'node:http';
|
|
17
17
|
|
|
@@ -227,6 +227,7 @@ declare class StartupCommander {
|
|
|
227
227
|
config: MWSConfig;
|
|
228
228
|
$tw: TW;
|
|
229
229
|
PasswordService: PasswordService;
|
|
230
|
+
fieldModules: Record<string, TiddlerFieldModule>;
|
|
230
231
|
constructor(config: MWSConfig, $tw: TW, PasswordService: PasswordService);
|
|
231
232
|
init(): Promise<void>;
|
|
232
233
|
wikiPath: string;
|
|
@@ -298,7 +299,7 @@ declare class StateObject<B extends BodyFormat = BodyFormat, M extends AllowedMe
|
|
|
298
299
|
/** The bodyformat that ended up taking precedence. This should be correctly typed. */
|
|
299
300
|
bodyFormat: B;
|
|
300
301
|
user: AuthUser;
|
|
301
|
-
|
|
302
|
+
router: Router;
|
|
302
303
|
tiddlerCache: Router["tiddlerCache"];
|
|
303
304
|
z: typeof z;
|
|
304
305
|
STREAM_ENDED: typeof STREAM_ENDED;
|
|
@@ -336,7 +337,7 @@ declare class StateObject<B extends BodyFormat = BodyFormat, M extends AllowedMe
|
|
|
336
337
|
/** The array of Route tree nodes the request matched. */
|
|
337
338
|
routePath: RouteMatch[],
|
|
338
339
|
/** The bodyformat that ended up taking precedence. This should be correctly typed. */
|
|
339
|
-
bodyFormat: B, user: AuthUser,
|
|
340
|
+
bodyFormat: B, user: AuthUser, router: Router, tiddlerCache: Router["tiddlerCache"]);
|
|
340
341
|
okUser(): void;
|
|
341
342
|
okAdmin(): void;
|
|
342
343
|
$transaction: <T>(fn: (prisma: PrismaTxnClient) => Promise<T>) => Promise<T>;
|
|
@@ -784,15 +785,18 @@ declare const BodyFormats: readonly ["stream", "string", "json", "buffer", "www-
|
|
|
784
785
|
type BodyFormat = typeof BodyFormats[number];
|
|
785
786
|
declare class Router {
|
|
786
787
|
private rootRoute;
|
|
787
|
-
private commander;
|
|
788
788
|
private tiddlerCache;
|
|
789
789
|
static makeRouter(commander: Commander, enableDevServer: boolean): Promise<Router>;
|
|
790
|
-
pathPrefix: string;
|
|
791
790
|
enableBrowserCache: boolean;
|
|
792
791
|
enableGzip: boolean;
|
|
793
792
|
csrfDisable: boolean;
|
|
793
|
+
siteConfig: SiteConfig;
|
|
794
|
+
get pathPrefix(): string;
|
|
794
795
|
engine: Commander["engine"];
|
|
795
796
|
private SessionManager;
|
|
797
|
+
PasswordService: Commander["PasswordService"];
|
|
798
|
+
fieldModules: Commander["$tw"]["Tiddler"]["fieldModules"];
|
|
799
|
+
AttachmentService: Commander["AttachmentService"];
|
|
796
800
|
constructor(rootRoute: rootRoute$1, commander: Commander, tiddlerCache: CacheState);
|
|
797
801
|
handleIncomingRequest(req: http.IncomingMessage | http2$1.Http2ServerRequest, res: http.ServerResponse | http2$1.Http2ServerResponse): void;
|
|
798
802
|
handle(streamer: Streamer): Promise<void | typeof STREAM_ENDED>;
|
|
@@ -890,8 +894,10 @@ interface SiteConfig extends MWSConfigConfig {
|
|
|
890
894
|
storePath: string;
|
|
891
895
|
/**
|
|
892
896
|
* The path prefix is a essentially folder mount point.
|
|
893
|
-
*
|
|
894
|
-
*
|
|
897
|
+
*
|
|
898
|
+
* It starts with a slash, and ends without a slash (`"/dev"`).
|
|
899
|
+
*
|
|
900
|
+
* If there is not a prefix, it is an empty string (`""`).
|
|
895
901
|
*/
|
|
896
902
|
pathPrefix: string;
|
|
897
903
|
}
|
package/dist/server.js
CHANGED
|
@@ -11660,16 +11660,8 @@ var init_data_checks = __esm({
|
|
|
11660
11660
|
// allow unowned for any user (conditional for anon reads)
|
|
11661
11661
|
(user_id || allowAnon) && { acl: { none: {} }, owner_id: null },
|
|
11662
11662
|
// allow owner for user
|
|
11663
|
-
user_id && { owner_id: user_id },
|
|
11663
|
+
user_id && { owner_id: { equals: user_id, not: null } },
|
|
11664
11664
|
// allow acl for user
|
|
11665
|
-
user_id && role_ids?.length && {
|
|
11666
|
-
acl: {
|
|
11667
|
-
some: {
|
|
11668
|
-
permission: { in: checkPerms },
|
|
11669
|
-
role_id: { in: role_ids }
|
|
11670
|
-
}
|
|
11671
|
-
}
|
|
11672
|
-
},
|
|
11673
11665
|
user_id && role_ids?.length && {
|
|
11674
11666
|
acl: {
|
|
11675
11667
|
some: {
|
|
@@ -11857,9 +11849,6 @@ var init_streamer = __esm({
|
|
|
11857
11849
|
this.isSecure = !!req.socket.encrypted;
|
|
11858
11850
|
this.urlInfo = new URL(`https://${this.headers.host}${this.url}`);
|
|
11859
11851
|
this.cookies = this.parseCookieString(req.headers.cookie || "");
|
|
11860
|
-
if (this.cookies.getAll("session").length > 1) {
|
|
11861
|
-
console.warn("Multiple session cookies found. This is very likely to cause problems. This may happen after changing the path prefix.");
|
|
11862
|
-
}
|
|
11863
11852
|
}
|
|
11864
11853
|
// RIP Push Stream. it was a great idea.
|
|
11865
11854
|
// async pushStream(path: string) {
|
|
@@ -12154,12 +12143,12 @@ var init_StateObject = __esm({
|
|
|
12154
12143
|
init_streamer();
|
|
12155
12144
|
init_utils2();
|
|
12156
12145
|
_StateObject = class _StateObject extends StreamerState {
|
|
12157
|
-
constructor(streamer, routePath, bodyFormat, user,
|
|
12146
|
+
constructor(streamer, routePath, bodyFormat, user, router, tiddlerCache) {
|
|
12158
12147
|
super(streamer);
|
|
12159
12148
|
this.routePath = routePath;
|
|
12160
12149
|
this.bodyFormat = bodyFormat;
|
|
12161
12150
|
this.user = user;
|
|
12162
|
-
this.
|
|
12151
|
+
this.router = router;
|
|
12163
12152
|
this.tiddlerCache = tiddlerCache;
|
|
12164
12153
|
this.z = z3;
|
|
12165
12154
|
this.STREAM_ENDED = STREAM_ENDED;
|
|
@@ -12170,9 +12159,9 @@ var init_StateObject = __esm({
|
|
|
12170
12159
|
this.$transaction = /* @__PURE__ */ __name(async (fn) => {
|
|
12171
12160
|
return await this.engine.$transaction((prisma) => fn(prisma));
|
|
12172
12161
|
}, "$transaction");
|
|
12173
|
-
this.engine =
|
|
12174
|
-
this.config =
|
|
12175
|
-
this.PasswordService =
|
|
12162
|
+
this.engine = router.engine;
|
|
12163
|
+
this.config = router.siteConfig;
|
|
12164
|
+
this.PasswordService = router.PasswordService;
|
|
12176
12165
|
this.readMultipartData = readMultipartData.bind(this);
|
|
12177
12166
|
this.sendResponse = sendResponse.bind(void 0, this.config, this);
|
|
12178
12167
|
this.pathParams = Object.fromEntries(routePath.map(
|
|
@@ -12222,7 +12211,7 @@ var init_StateObject = __esm({
|
|
|
12222
12211
|
* - **308 Permanent Redirect:** The resource has permanently moved; the client should use the new URL in future requests.
|
|
12223
12212
|
*/
|
|
12224
12213
|
redirect(location, pushLocation) {
|
|
12225
|
-
return this.sendEmpty(302, { "Location": location });
|
|
12214
|
+
return this.sendEmpty(302, { "Location": this.config.pathPrefix + location });
|
|
12226
12215
|
}
|
|
12227
12216
|
sendSSE(retryMilliseconds) {
|
|
12228
12217
|
if (retryMilliseconds !== void 0) {
|
|
@@ -12414,7 +12403,12 @@ var init_manager_recipes = __esm({
|
|
|
12414
12403
|
}
|
|
12415
12404
|
}
|
|
12416
12405
|
},
|
|
12417
|
-
where: isAdmin ? void 0 : {
|
|
12406
|
+
where: isAdmin ? void 0 : {
|
|
12407
|
+
OR: [
|
|
12408
|
+
{ recipe_bags: { every: { bag: { OR } } } },
|
|
12409
|
+
{ owner_id: { equals: user_id, not: null } }
|
|
12410
|
+
]
|
|
12411
|
+
}
|
|
12418
12412
|
});
|
|
12419
12413
|
const userListUser = !isAdmin && await prisma.users.findMany({
|
|
12420
12414
|
select: { user_id: true, username: true }
|
|
@@ -12601,7 +12595,7 @@ var init_manager_recipes = __esm({
|
|
|
12601
12595
|
const existing = await prisma.recipes.findUnique({ where: { recipe_name } });
|
|
12602
12596
|
this.assertCreateOrUpdate({ user, type: "recipe", isCreate, owner_id, existing });
|
|
12603
12597
|
const { isAdmin, user_id } = user;
|
|
12604
|
-
const OR = this.checks.getWhereACL({ permission: "ADMIN", user_id });
|
|
12598
|
+
const OR = isAdmin ? void 0 : this.checks.getWhereACL({ permission: "ADMIN", user_id });
|
|
12605
12599
|
const bags = new Map(
|
|
12606
12600
|
await prisma.bags.findMany({
|
|
12607
12601
|
where: { bag_name: { in: bag_names.map((e) => e.bag_name) } }
|
|
@@ -12609,14 +12603,12 @@ var init_manager_recipes = __esm({
|
|
|
12609
12603
|
);
|
|
12610
12604
|
const missing = bag_names.filter((e) => !bags.has(e.bag_name));
|
|
12611
12605
|
if (missing.length) throw "Some bags not found: " + JSON.stringify(missing);
|
|
12612
|
-
const bagsAcl = new Map(
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
}).then((bags2) => bags2.map((bag) => [bag.bag_name, bag]))
|
|
12616
|
-
);
|
|
12606
|
+
const bagsAcl = new Map((await prisma.bags.findMany({
|
|
12607
|
+
where: { bag_name: { in: bag_names.map((e) => e.bag_name) }, OR }
|
|
12608
|
+
})).map((bag) => [bag.bag_name, bag]));
|
|
12617
12609
|
const createBags = bag_names.map((bag, position) => ({
|
|
12618
12610
|
bag_id: bags.get(bag.bag_name).bag_id,
|
|
12619
|
-
with_acl: bagsAcl
|
|
12611
|
+
with_acl: bagsAcl.has(bag.bag_name) && bag.with_acl,
|
|
12620
12612
|
position
|
|
12621
12613
|
}));
|
|
12622
12614
|
if (existing) {
|
|
@@ -12914,13 +12906,20 @@ var init_TiddlerStore = __esm({
|
|
|
12914
12906
|
init_esm_shims();
|
|
12915
12907
|
init_utils2();
|
|
12916
12908
|
_TiddlerStore = class _TiddlerStore {
|
|
12917
|
-
constructor(
|
|
12918
|
-
this.
|
|
12909
|
+
constructor(fieldModules, attachService, siteConfig, prisma) {
|
|
12910
|
+
this.fieldModules = fieldModules;
|
|
12911
|
+
this.attachService = attachService;
|
|
12912
|
+
this.siteConfig = siteConfig;
|
|
12919
12913
|
this.prisma = prisma;
|
|
12920
|
-
this.
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12914
|
+
this.storePath = this.siteConfig.storePath;
|
|
12915
|
+
}
|
|
12916
|
+
static fromCommander(commander2, prisma) {
|
|
12917
|
+
return new _TiddlerStore(
|
|
12918
|
+
commander2.$tw.Tiddler.fieldModules,
|
|
12919
|
+
new commander2.AttachmentService(commander2.siteConfig, prisma),
|
|
12920
|
+
commander2.siteConfig,
|
|
12921
|
+
prisma
|
|
12922
|
+
);
|
|
12924
12923
|
}
|
|
12925
12924
|
/*
|
|
12926
12925
|
Returns null if a bag/recipe name is valid, or a string error message if not
|
|
@@ -13170,7 +13169,7 @@ var init_TiddlerStore = __esm({
|
|
|
13170
13169
|
const stream = new Readable();
|
|
13171
13170
|
stream._read = () => {
|
|
13172
13171
|
const type = tiddlerInfo.tiddler.type || "text/plain";
|
|
13173
|
-
stream.push(tiddlerInfo.tiddler.text || "", (this.
|
|
13172
|
+
stream.push(tiddlerInfo.tiddler.text || "", (this.siteConfig.contentTypeInfo[type] || { encoding: "utf8" }).encoding);
|
|
13174
13173
|
stream.push(null);
|
|
13175
13174
|
};
|
|
13176
13175
|
return {
|
|
@@ -14093,7 +14092,13 @@ var init_bag_file_server = __esm({
|
|
|
14093
14092
|
import_sjcl = __toESM(require_sjcl(), 1);
|
|
14094
14093
|
_TiddlerServer = class _TiddlerServer extends TiddlerStore {
|
|
14095
14094
|
constructor(state, prisma) {
|
|
14096
|
-
|
|
14095
|
+
const router = state.router;
|
|
14096
|
+
super(
|
|
14097
|
+
router.fieldModules,
|
|
14098
|
+
new router.AttachmentService(router.siteConfig, prisma),
|
|
14099
|
+
router.siteConfig,
|
|
14100
|
+
prisma
|
|
14101
|
+
);
|
|
14097
14102
|
this.state = state;
|
|
14098
14103
|
}
|
|
14099
14104
|
toTiddlyWebJson(info12) {
|
|
@@ -14611,6 +14616,62 @@ var init_router_tiddlers = __esm({
|
|
|
14611
14616
|
}
|
|
14612
14617
|
});
|
|
14613
14618
|
|
|
14619
|
+
// src/routes/tw-test.ts
|
|
14620
|
+
import { TiddlyWiki } from "tiddlywiki";
|
|
14621
|
+
function DocsRoute(parent, config) {
|
|
14622
|
+
const wikiRouter = new TWRouter(config);
|
|
14623
|
+
parent.defineRoute({
|
|
14624
|
+
method: ["OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE"],
|
|
14625
|
+
bodyFormat: "stream",
|
|
14626
|
+
path: /^\/mws(\/|$)/,
|
|
14627
|
+
pathParams: []
|
|
14628
|
+
}, async (state) => {
|
|
14629
|
+
if (state.urlInfo.pathname === "/mws") throw state.redirect("/mws/");
|
|
14630
|
+
const { req, res } = state.streamer;
|
|
14631
|
+
if (req.url === "/mws") req.url = "/mws/";
|
|
14632
|
+
wikiRouter.twserver.requestHandler(req, res, {});
|
|
14633
|
+
return new Promise((r, c) => res.on("finish", r).on("error", c));
|
|
14634
|
+
});
|
|
14635
|
+
}
|
|
14636
|
+
var _TWRouter, TWRouter;
|
|
14637
|
+
var init_tw_test = __esm({
|
|
14638
|
+
"src/routes/tw-test.ts"() {
|
|
14639
|
+
"use strict";
|
|
14640
|
+
init_esm_shims();
|
|
14641
|
+
__name(DocsRoute, "DocsRoute");
|
|
14642
|
+
_TWRouter = class _TWRouter {
|
|
14643
|
+
constructor(config) {
|
|
14644
|
+
this.config = config;
|
|
14645
|
+
this.$tw = TiddlyWiki();
|
|
14646
|
+
this.$tw.boot.argv = [
|
|
14647
|
+
"+plugins/tiddlywiki/tiddlyweb",
|
|
14648
|
+
"+plugins/tiddlywiki/filesystem",
|
|
14649
|
+
"./editions/mws-docs"
|
|
14650
|
+
];
|
|
14651
|
+
this.$tw.preloadTiddler({
|
|
14652
|
+
text: "$protocol$//$host$" + this.config.pathPrefix + "/mws/",
|
|
14653
|
+
title: "$:/config/tiddlyweb/host"
|
|
14654
|
+
});
|
|
14655
|
+
this.$tw.boot.boot(() => {
|
|
14656
|
+
const Server2 = this.$tw.modules.execute("$:/core/modules/server/server.js", "tw-test.ts").Server;
|
|
14657
|
+
this.twserver = new Server2({
|
|
14658
|
+
wiki: this.$tw.wiki,
|
|
14659
|
+
variables: {
|
|
14660
|
+
// do not use a trailing slash
|
|
14661
|
+
"path-prefix": this.config.pathPrefix + "/mws",
|
|
14662
|
+
"root-tiddler": "$:/core/save/all"
|
|
14663
|
+
},
|
|
14664
|
+
routes: []
|
|
14665
|
+
});
|
|
14666
|
+
this.$tw.hooks.invokeHook("th-server-command-post-start", this.twserver, null, "mws");
|
|
14667
|
+
});
|
|
14668
|
+
}
|
|
14669
|
+
};
|
|
14670
|
+
__name(_TWRouter, "TWRouter");
|
|
14671
|
+
TWRouter = _TWRouter;
|
|
14672
|
+
}
|
|
14673
|
+
});
|
|
14674
|
+
|
|
14614
14675
|
// import("./**/*/**/*") in src/routes/index.ts
|
|
14615
14676
|
var globImport;
|
|
14616
14677
|
var init_ = __esm({
|
|
@@ -14627,9 +14688,10 @@ var init_ = __esm({
|
|
|
14627
14688
|
// src/routes/index.ts
|
|
14628
14689
|
import { Prisma } from "@prisma/client";
|
|
14629
14690
|
async function RootRoute(root, config) {
|
|
14691
|
+
if (process.env.ENABLE_DOCS_ROUTE) DocsRoute(root, config);
|
|
14630
14692
|
TiddlerRouter.defineRoutes(root);
|
|
14631
14693
|
ManagerRoutes(root, config);
|
|
14632
|
-
if (
|
|
14694
|
+
if (process.env.ENABLE_UNSAFE_PRISMA_ROUTE)
|
|
14633
14695
|
root.defineRoute({
|
|
14634
14696
|
method: ["POST"],
|
|
14635
14697
|
path: /^\/prisma$/,
|
|
@@ -14686,6 +14748,7 @@ var init_routes = __esm({
|
|
|
14686
14748
|
init_utils2();
|
|
14687
14749
|
init_managers();
|
|
14688
14750
|
init_router_tiddlers();
|
|
14751
|
+
init_tw_test();
|
|
14689
14752
|
init_();
|
|
14690
14753
|
__name(RootRoute, "RootRoute");
|
|
14691
14754
|
__name(importEsbuild, "importEsbuild");
|
|
@@ -14960,15 +15023,16 @@ var init_router = __esm({
|
|
|
14960
15023
|
_Router = class _Router {
|
|
14961
15024
|
constructor(rootRoute2, commander2, tiddlerCache) {
|
|
14962
15025
|
this.rootRoute = rootRoute2;
|
|
14963
|
-
this.commander = commander2;
|
|
14964
15026
|
this.tiddlerCache = tiddlerCache;
|
|
14965
|
-
this.pathPrefix = "";
|
|
14966
15027
|
this.enableBrowserCache = true;
|
|
14967
15028
|
this.enableGzip = false;
|
|
14968
15029
|
this.csrfDisable = false;
|
|
14969
15030
|
this.engine = commander2.engine;
|
|
14970
15031
|
this.SessionManager = commander2.SessionManager;
|
|
14971
|
-
this.
|
|
15032
|
+
this.siteConfig = commander2.siteConfig;
|
|
15033
|
+
this.PasswordService = commander2.PasswordService;
|
|
15034
|
+
this.fieldModules = commander2.$tw.Tiddler.fieldModules;
|
|
15035
|
+
this.AttachmentService = commander2.AttachmentService;
|
|
14972
15036
|
}
|
|
14973
15037
|
static async makeRouter(commander2, enableDevServer) {
|
|
14974
15038
|
const sendDevServer = await setupDevServer(enableDevServer, commander2.siteConfig.pathPrefix);
|
|
@@ -14984,6 +15048,9 @@ var init_router = __esm({
|
|
|
14984
15048
|
const cache = await startupCache(commander2);
|
|
14985
15049
|
return new _Router(rootRoute2, commander2, cache);
|
|
14986
15050
|
}
|
|
15051
|
+
get pathPrefix() {
|
|
15052
|
+
return this.siteConfig.pathPrefix;
|
|
15053
|
+
}
|
|
14987
15054
|
handleIncomingRequest(req, res) {
|
|
14988
15055
|
const [ok8, err, streamer] = function() {
|
|
14989
15056
|
try {
|
|
@@ -15019,7 +15086,7 @@ var init_router = __esm({
|
|
|
15019
15086
|
routePath,
|
|
15020
15087
|
bodyFormat,
|
|
15021
15088
|
authUser,
|
|
15022
|
-
this
|
|
15089
|
+
this,
|
|
15023
15090
|
this.tiddlerCache
|
|
15024
15091
|
)
|
|
15025
15092
|
);
|
|
@@ -15162,10 +15229,10 @@ var init_router = __esm({
|
|
|
15162
15229
|
});
|
|
15163
15230
|
|
|
15164
15231
|
// src/tiddlywiki.ts
|
|
15165
|
-
import { TiddlyWiki } from "tiddlywiki";
|
|
15232
|
+
import { TiddlyWiki as TiddlyWiki2 } from "tiddlywiki";
|
|
15166
15233
|
import { ok as ok5 } from "node:assert";
|
|
15167
15234
|
async function bootTiddlyWiki(wikiPath) {
|
|
15168
|
-
const $tw2 =
|
|
15235
|
+
const $tw2 = TiddlyWiki2();
|
|
15169
15236
|
$tw2.utils.eachAsync = eachAsync;
|
|
15170
15237
|
$tw2.boot.boot = async (callback) => {
|
|
15171
15238
|
$tw2.crypto = new $tw2.utils.Crypto();
|
|
@@ -15197,22 +15264,14 @@ async function bootTiddlyWiki(wikiPath) {
|
|
|
15197
15264
|
startup: /* @__PURE__ */ __name(() => {
|
|
15198
15265
|
}, "startup")
|
|
15199
15266
|
});
|
|
15200
|
-
$tw2.preloadTiddler({ title: "$:/plugins/tiddlywiki/multiwikiserver/startup.js" });
|
|
15201
|
-
$tw2.modules.define("$:/plugins/tiddlywiki/multiwikiserver/startup.js", "startup", {
|
|
15202
|
-
name: "multiwikiserver",
|
|
15203
|
-
platforms: ["node"],
|
|
15204
|
-
after: ["load-modules"],
|
|
15205
|
-
before: ["story", "commands"],
|
|
15206
|
-
synchronous: true,
|
|
15207
|
-
startup: /* @__PURE__ */ __name(() => {
|
|
15208
|
-
}, "startup")
|
|
15209
|
-
});
|
|
15210
15267
|
$tw2.boot.argv = [
|
|
15211
15268
|
"++" + dist_resolve("../plugins/client"),
|
|
15212
15269
|
"+plugins/tiddlywiki/tiddlyweb",
|
|
15270
|
+
// these are sane defaults, these should be in the recipe
|
|
15213
15271
|
"+themes/tiddlywiki/vanilla",
|
|
15214
15272
|
"+themes/tiddlywiki/snowwhite",
|
|
15215
15273
|
wikiPath
|
|
15274
|
+
// this should be inert
|
|
15216
15275
|
];
|
|
15217
15276
|
await new Promise((resolve13) => $tw2.boot.boot(resolve13));
|
|
15218
15277
|
ok5(!$tw2.boot.tasks.readBrowserTiddlers);
|
|
@@ -15342,17 +15401,17 @@ var init_sessions = __esm({
|
|
|
15342
15401
|
registerZodRoutes(root, new _SessionManager(), Object.keys(SessionKeyMap));
|
|
15343
15402
|
}
|
|
15344
15403
|
static async parseIncomingRequest(streamer, router) {
|
|
15345
|
-
const sessionId = streamer.cookies.
|
|
15346
|
-
const session = sessionId && await router.engine.sessions.
|
|
15347
|
-
where: { session_id: sessionId },
|
|
15348
|
-
select: { user: { select: { user_id: true, username: true, roles: { select: { role_id: true } } } } }
|
|
15404
|
+
const sessionId = streamer.cookies.getAll("session");
|
|
15405
|
+
const session = sessionId && await router.engine.sessions.findFirst({
|
|
15406
|
+
where: { session_id: { in: sessionId } },
|
|
15407
|
+
select: { session_id: true, user: { select: { user_id: true, username: true, roles: { select: { role_id: true } } } } }
|
|
15349
15408
|
});
|
|
15350
15409
|
if (sessionId && session) return {
|
|
15351
15410
|
user_id: session.user.user_id,
|
|
15352
15411
|
username: session.user.username,
|
|
15353
15412
|
isAdmin: session.user.roles.some((e) => e.role_id === 1),
|
|
15354
15413
|
role_ids: session.user.roles.map((e) => e.role_id),
|
|
15355
|
-
sessionId,
|
|
15414
|
+
sessionId: session.session_id,
|
|
15356
15415
|
isLoggedIn: true
|
|
15357
15416
|
};
|
|
15358
15417
|
else return {
|
|
@@ -19004,7 +19063,7 @@ var init_load_plugin_bags = __esm({
|
|
|
19004
19063
|
console.time(`${info.name} complete`);
|
|
19005
19064
|
await loadPluginBags(
|
|
19006
19065
|
this.$tw,
|
|
19007
|
-
|
|
19066
|
+
TiddlerStore.fromCommander(this.commander, this.commander.engine),
|
|
19008
19067
|
this.commander.engine
|
|
19009
19068
|
);
|
|
19010
19069
|
console.timeEnd(`${info.name} complete`);
|
|
@@ -19160,7 +19219,7 @@ var init_load_wiki_folder = __esm({
|
|
|
19160
19219
|
bagDescription: this.params[2],
|
|
19161
19220
|
recipeName: this.params[3],
|
|
19162
19221
|
recipeDescription: this.params[4],
|
|
19163
|
-
store:
|
|
19222
|
+
store: TiddlerStore.fromCommander(this.commander, this.commander.engine),
|
|
19164
19223
|
$tw: this.commander.$tw
|
|
19165
19224
|
}));
|
|
19166
19225
|
console.log(info3.name, "complete:", this.params[0]);
|
|
@@ -19213,7 +19272,7 @@ var init_save_archive = __esm({
|
|
|
19213
19272
|
async execute() {
|
|
19214
19273
|
if (this.params.length < 1) throw "Missing pathname";
|
|
19215
19274
|
await this.commander.$transaction(async (prisma) => {
|
|
19216
|
-
this.store =
|
|
19275
|
+
this.store = TiddlerStore.fromCommander(this.commander, prisma);
|
|
19217
19276
|
await this.saveArchive();
|
|
19218
19277
|
this.store = void 0;
|
|
19219
19278
|
});
|
|
@@ -20012,6 +20071,7 @@ var init_commander = __esm({
|
|
|
20012
20071
|
this.PasswordService = PasswordService;
|
|
20013
20072
|
/** Signals that database setup is required. May be set to false by any qualified setup command. */
|
|
20014
20073
|
this.setupRequired = true;
|
|
20074
|
+
this.fieldModules = $tw2.Tiddler.fieldModules;
|
|
20015
20075
|
if (config.config?.pathPrefix) {
|
|
20016
20076
|
ok7(config.config.pathPrefix.startsWith("/"), "pathPrefix must start with a slash");
|
|
20017
20077
|
ok7(!config.config.pathPrefix.endsWith("/"), "pathPrefix must not end with a slash");
|
|
@@ -20067,7 +20127,6 @@ var init_commander = __esm({
|
|
|
20067
20127
|
config.listeners = [];
|
|
20068
20128
|
config.onListenersCreated = void 0;
|
|
20069
20129
|
this.create_mws_listen = (params) => {
|
|
20070
|
-
console.log(listeners);
|
|
20071
20130
|
return new listen_exports.Command(params, this, listeners, onListenersCreated);
|
|
20072
20131
|
};
|
|
20073
20132
|
}
|
|
@@ -20168,7 +20227,6 @@ var init_commander = __esm({
|
|
|
20168
20227
|
this.callback(params);
|
|
20169
20228
|
return;
|
|
20170
20229
|
}
|
|
20171
|
-
console.log(params);
|
|
20172
20230
|
new Promise(async (resolve13) => {
|
|
20173
20231
|
const { Command: Command13, info: info12 } = command;
|
|
20174
20232
|
try {
|