@tiddlywiki/mws 0.0.12 → 0.0.13

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 (65) hide show
  1. package/README.md +3 -1
  2. package/dist/server.d.ts +923 -0
  3. package/dist/server.js +1763 -1415
  4. package/dist/server.js.map +1 -1
  5. package/editions/mws-docs/tiddlers/$__StoryList.tid +3 -3
  6. package/editions/mws-docs/tiddlers/MWS and SQLite.md +11 -0
  7. package/editions/mws-docs/tiddlers/Request Server.md +20 -0
  8. package/editions/mws-docs/tiddlers/Request Server.md.meta +5 -0
  9. package/package.json +16 -10
  10. package/prisma/schema.prisma +1 -0
  11. package/react-user-mgmt/package-lock.json +76 -321
  12. package/react-user-mgmt/package.json +2 -5
  13. package/react-user-mgmt/public/chunk-YALWN5OT.js +2 -0
  14. package/react-user-mgmt/public/chunk-YALWN5OT.js.map +7 -0
  15. package/react-user-mgmt/public/esm-QKDFEP3B.js +3 -0
  16. package/react-user-mgmt/public/esm-QKDFEP3B.js.map +7 -0
  17. package/react-user-mgmt/public/index.html +1 -26
  18. package/react-user-mgmt/public/main.js +68 -109
  19. package/react-user-mgmt/public/main.js.map +4 -4
  20. package/react-user-mgmt/public/stats.css +597 -0
  21. package/react-user-mgmt/public/stats.html +59 -0
  22. package/react-user-mgmt/public/stats.js +2013 -0
  23. package/react-user-mgmt/public/stats.json +1 -0
  24. package/react-user-mgmt/public/stats.svg +4 -0
  25. package/react-user-mgmt/tsconfig.json +3 -0
  26. package/dist/server.cjs +0 -16677
  27. package/dist/server.cjs.map +0 -1
  28. package/src/StateObject.ts +0 -316
  29. package/src/commander.ts +0 -417
  30. package/src/commands/divider.ts +0 -20
  31. package/src/commands/index.ts +0 -24
  32. package/src/commands/mws-init-store.ts +0 -77
  33. package/src/commands/mws-listen.ts +0 -136
  34. package/src/commands/mws-load-archive.ts +0 -281
  35. package/src/commands/mws-load-plugin-bags.ts +0 -151
  36. package/src/commands/mws-load-tiddlers.ts +0 -37
  37. package/src/commands/mws-load-wiki-folder.ts +0 -124
  38. package/src/commands/mws-render-tiddlywiki5.ts +0 -55
  39. package/src/commands/mws-save-archive.ts +0 -111
  40. package/src/commands/mws-save-tiddler-text.ts +0 -33
  41. package/src/commands/tests-complete.ts +0 -21
  42. package/src/global.ts +0 -247
  43. package/src/routes/TiddlerStore.ts +0 -722
  44. package/src/routes/bag-file-server.ts +0 -340
  45. package/src/routes/cache.ts +0 -25
  46. package/src/routes/index.ts +0 -138
  47. package/src/routes/managers/index.ts +0 -17
  48. package/src/routes/managers/manager-recipes.ts +0 -438
  49. package/src/routes/managers/manager-users.ts +0 -201
  50. package/src/routes/managers/router-tiddlers.ts +0 -313
  51. package/src/routes/router.ts +0 -429
  52. package/src/routes/services/PasswordService.ts +0 -178
  53. package/src/routes/services/attachments.ts +0 -259
  54. package/src/routes/services/sessions.ts +0 -166
  55. package/src/routes/tw-test.ts +0 -65
  56. package/src/server.ts +0 -151
  57. package/src/setupDevServer.ts +0 -71
  58. package/src/streamer.ts +0 -430
  59. package/src/tiddlywiki.ts +0 -94
  60. package/src/utils/data-checks.ts +0 -172
  61. package/src/utils/index.ts +0 -4
  62. package/src/utils/rootRoute.ts +0 -237
  63. package/src/utils/utils.ts +0 -403
  64. package/src/utils/zodAssert.ts +0 -269
  65. /package/prisma/{migrations/notes.md → notes.md} +0 -0
@@ -1,71 +0,0 @@
1
-
2
- import { request } from "http";
3
- import { resolve } from "path";
4
- import { StateObject } from "./StateObject";
5
- import { dist_resolve } from "./utils";
6
-
7
-
8
-
9
- export async function setupDevServer<T extends StateObject>(enableDevServer: string | undefined) {
10
-
11
- if (!enableDevServer) {
12
- return async function sendProdServer(state: T) {
13
-
14
- const rootdir = dist_resolve('../react-user-mgmt/public');
15
- // use sendFile directly instead of having the dev server send it
16
- return state.sendFile(200, {}, {
17
- root: rootdir,
18
- reqpath: state.url === "/" ? "/index.html" : state.url,
19
- on404: () => state.sendFile(200, {}, { reqpath: "/index.html", root: rootdir, })
20
- });
21
- };
22
- } else {
23
- const esbuild = await import("esbuild");
24
-
25
- const rootdir = resolve(enableDevServer, 'react-user-mgmt');
26
-
27
- let ctx = await esbuild.context({
28
- entryPoints: [resolve(rootdir, 'src/main.tsx')],
29
- bundle: true,
30
- target: 'es2020',
31
- platform: 'browser',
32
- jsx: 'automatic',
33
- outdir: resolve(rootdir, 'public'),
34
- minify: true,
35
- sourcemap: true,
36
- });
37
-
38
- const { port } = await ctx.serve({
39
- servedir: resolve(rootdir, 'public'),
40
- fallback: resolve(rootdir, 'public/index.html'),
41
- });
42
-
43
- return async function sendDevServer(state: T) {
44
- const proxyRes = await new Promise<import("http").IncomingMessage>((resolve, reject) => {
45
- const headers = { ...state.headers };
46
- delete headers[":method"];
47
- delete headers[":path"];
48
- delete headers[":authority"];
49
- delete headers[":scheme"];
50
- headers.host = "localhost";
51
- const proxyReq = request({
52
- hostname: "localhost",
53
- port: port,
54
- path: state.url,
55
- method: state.method,
56
- headers,
57
- }, resolve);
58
- state.reader.pipe(proxyReq, { end: true });
59
- });
60
-
61
- const { statusCode, headers } = proxyRes;
62
- if (statusCode === 404 || !statusCode) {
63
- proxyRes.resume();
64
- return state.sendEmpty(404, { 'Content-Type': 'text/html' });
65
- } else {
66
- return state.sendStream(statusCode as number, headers, proxyRes);
67
- }
68
-
69
- };
70
- }
71
- }
package/src/streamer.ts DELETED
@@ -1,430 +0,0 @@
1
- import "./global";
2
- import * as http2 from 'node:http2';
3
- import send from 'send';
4
- import { Readable } from 'stream';
5
- import { IncomingMessage, ServerResponse, IncomingHttpHeaders as NodeIncomingHeaders, OutgoingHttpHeaders } from 'node:http';
6
- import { is } from './utils';
7
- import { createReadStream } from 'node:fs';
8
- import { Writable } from 'node:stream';
9
-
10
- declare module 'node:net' {
11
- interface Socket {
12
- // this comment gets prepended to the other comment for this property, thus the hanging sentance.
13
- /** Not defined on net.Socket instances.
14
- *
15
- * On tls.Socket instances, */
16
- encrypted?: boolean;
17
- }
18
- }
19
-
20
-
21
- export interface IncomingHttpHeaders extends NodeIncomingHeaders {
22
- "accept-encoding"?: string;
23
- }
24
-
25
- export const SYMBOL_IGNORE_ERROR: unique symbol = Symbol("IGNORE_ERROR");
26
- export const STREAM_ENDED: unique symbol = Symbol("STREAM_ENDED");
27
-
28
-
29
- export type StreamerChunk = { data: string, encoding: NodeJS.BufferEncoding } | NodeJS.ReadableStream | Readable | Buffer;
30
-
31
- /**
32
- * The HTTP2 shims used in the request handler are only used for HTTP2 requests.
33
- * The NodeJS HTTP2 server actually calls the HTTP1 parser for all HTTP1 requests.
34
- */
35
- export class Streamer {
36
- host: string;
37
- method: AllowedMethod;
38
- urlInfo: URL;
39
- url: string;
40
- headers: IncomingHttpHeaders;
41
- isSecure: boolean;
42
- cookies: Record<string, string | undefined>;
43
- constructor(
44
- private req: IncomingMessage | http2.Http2ServerRequest,
45
- private res: ServerResponse | http2.Http2ServerResponse,
46
- private router: Router
47
- ) {
48
-
49
- this.headers = req.headers;
50
- this.url = req.url as string;
51
- if (is<http2.Http2ServerRequest>(req, req.httpVersionMajor > 1)) {
52
- this.req.headers.host = req.headers[":authority"];
53
- }
54
-
55
- if (!req.headers.host) throw new Error("This should never happen");
56
- if (!req.method) throw new Error("This should never happen");
57
- if (!req.url?.startsWith("/")) throw new Error("This should never happen");
58
- //https://httpwg.org/specs/rfc9110.html#status.501
59
- if (!is<AllowedMethod>(req.method, AllowedMethods.includes(req.method as any)))
60
- throw this.sendString(501, {}, "Method not supported", "utf8");
61
- this.host = req.headers.host;
62
- this.method = req.method;
63
- this.isSecure = !!req.socket.encrypted;
64
- this.urlInfo = new URL(`https://${req.headers.host}${req.url}`);
65
-
66
- this.cookies = this.parseCookieString(req.headers.cookie || "");
67
- }
68
-
69
-
70
- // RIP Push Stream. it was a great idea.
71
- async pushStream(path: string) {
72
- return new Promise<Streamer>((resolve, reject) => {
73
- const req2: http2.Http2ServerRequest = this.req as any;
74
- if (!req2.stream || !req2.stream.pushAllowed) return reject();
75
- req2.stream.write
76
- const newRawHeaders = this.req.rawHeaders.slice();
77
- for (let i = 0; i < newRawHeaders.length; i += 2) {
78
- if (newRawHeaders[i] === ":method") newRawHeaders[i + 1] = "GET";
79
- if (newRawHeaders[i] === ":path") newRawHeaders[i + 1] = path;
80
- }
81
- req2.stream.pushStream({ ":method": "GET", ":path": path }, (err, pushStream, headers) => {
82
- if (err) return reject(err);
83
- const preq = new http2.Http2ServerRequest(pushStream, req2.headers, {}, newRawHeaders);
84
- const pres = new http2.Http2ServerResponse(pushStream);
85
- const pushStreamer = new Streamer(preq, pres, this.router);
86
- resolve(pushStreamer);
87
- });
88
- }).then(async streamer => {
89
- await this.router.handle(streamer);
90
- return streamer;
91
- }, (err) => { if (err) throw err; });
92
- }
93
-
94
-
95
- parseCookieString(cookieString: string) {
96
- const cookies: any = {};
97
- if (typeof cookieString !== 'string') throw new Error('cookieString must be a string');
98
- cookieString.split(';').forEach(cookie => {
99
- const parts = cookie.split('=');
100
- if (parts.length >= 2) {
101
- const key = parts[0]!.trim();
102
- const value = parts.slice(1).join('=').trim();
103
- cookies[key] = decodeURIComponent(value);
104
- }
105
- });
106
- return cookies;
107
- }
108
-
109
- get reader(): Readable { return this.req; }
110
- get writer(): Writable {
111
- // don't overwrite it here if it's already set because this could just be for sending the body.
112
- if (!this.headersSent && !this.headersSentBy)
113
- this.headersSentBy = new Error("Possible culprit was given access to the response object here.");
114
- return this.res;
115
- }
116
-
117
- throw(statusCode: number) {
118
- this.sendEmpty(statusCode);
119
- throw SYMBOL_IGNORE_ERROR;
120
- }
121
-
122
- catcher = (error: unknown) => {
123
- if (error === SYMBOL_IGNORE_ERROR) return;
124
- if (error === STREAM_ENDED) return;
125
- const tag = this.urlInfo.href;
126
- console.error(tag, error);
127
- if (!this.headersSent)
128
- this.sendEmpty(500, { "x-reason": "Internal Server Error (catcher)" });
129
- }
130
-
131
- checkHeadersSentBy(setError: boolean) {
132
- if (this.headersSent && this.headersSentBy) {
133
- console.log(this.headersSentBy);
134
- console.log(new Error("This is the second attempt to send headers. Was it supposed to happen?"));
135
- }
136
- else if (this.res.headersSent) console.log("Headers were sent by an unknown source.");
137
- // queue up the error in case there is a second attempt.
138
- else this.headersSentBy = new Error("You appear to be sending headers more than once. The first attempt was here. Does it need to throw or return?")
139
- }
140
-
141
-
142
-
143
- toHeadersMap(headers: { [x: string]: string | string[] | number | undefined }) {
144
- return new Map(Object.entries(headers).map(([k, v]) =>
145
- [k.toLowerCase(), Array.isArray(v) ? v : v === undefined ? [] : [v.toString()]]
146
- ));
147
- }
148
-
149
- readBody = () => new Promise<Buffer>((resolve: (chunk: Buffer) => void) => {
150
- const chunks: Buffer[] = [];
151
-
152
- this.reader.on('data', chunk => chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
153
- this.reader.on('end', () => resolve(Buffer.concat(chunks)));
154
- });
155
-
156
- sendEmpty(status: number, headers: OutgoingHttpHeaders = {}): typeof STREAM_ENDED {
157
- if (process.env.DEBUG?.split(",").includes("send")) {
158
- console.error("sendEmpty", status, headers);
159
- }
160
- this.checkHeadersSentBy(true);
161
- this.res.writeHead(status, headers);
162
- this.res.end();
163
- return STREAM_ENDED;
164
- }
165
-
166
- sendString(status: number, headers: OutgoingHttpHeaders, data: string, encoding: NodeJS.BufferEncoding): typeof STREAM_ENDED {
167
- if (process.env.DEBUG?.split(",").includes("send")) {
168
- console.error("sendString", status, headers);
169
- }
170
- this.checkHeadersSentBy(true);
171
- headers['content-length'] = Buffer.byteLength(data, encoding);
172
- this.res.writeHead(status, headers);
173
-
174
- if (this.method === "HEAD")
175
- this.res.end();
176
- else
177
- this.res.end(data, encoding);
178
-
179
- return STREAM_ENDED;
180
- }
181
-
182
- sendBuffer(status: number, headers: OutgoingHttpHeaders, data: Buffer): typeof STREAM_ENDED {
183
- if (process.env.DEBUG?.split(",").includes("send")) {
184
- console.error("sendBuffer", status, headers);
185
- }
186
- this.checkHeadersSentBy(true);
187
- headers['content-length'] = data.length;
188
- this.res.writeHead(status, headers);
189
- if (this.method === "HEAD")
190
- this.res.end();
191
- else
192
- this.res.end(data);
193
- return STREAM_ENDED;
194
- }
195
- /** If this is a HEAD request, the stream will be ignored AND LEFT OPEN. */
196
- sendStream(status: number, headers: OutgoingHttpHeaders, stream: Readable): typeof STREAM_ENDED {
197
- if (process.env.DEBUG?.split(",").includes("send")) {
198
- console.error("sendStream", status, headers);
199
- }
200
- this.checkHeadersSentBy(true);
201
- this.res.writeHead(status, headers);
202
- if (this.method === "HEAD")
203
- this.res.end();
204
- else
205
- stream.pipe(this.res);
206
- return STREAM_ENDED;
207
- }
208
- // I'm not sure if there's a use case for this
209
- private sendFD(status: number, headers: OutgoingHttpHeaders, options: {
210
- fd: number;
211
- offset?: number;
212
- length?: number;
213
- }): typeof STREAM_ENDED {
214
- this.checkHeadersSentBy(true);
215
- this.res.writeHead(status, headers);
216
- const { fd, offset, length } = options;
217
- const stream = createReadStream("", {
218
- fd,
219
- start: offset,
220
- end: length && length - 1,
221
- autoClose: false,
222
- });
223
- stream.pipe(this.res);
224
- return STREAM_ENDED;
225
- }
226
- /**
227
- * Sends a file with the appropriate cache headers, using the `send` npm module.
228
- *
229
- * Think of it like a static file server where you are serving files from a directory.
230
- *
231
- * @param options.root The directory to serve files from.
232
- * @param options.reqpath The path to the file relative to the `root` directory.
233
- * @param options.offset The offset in bytes to start reading the file from.
234
- * @param options.length The number of bytes to read from the file.
235
- * @param options.index "index.html" by default, to disable this set false or
236
- * to supply a new index pass a string or an array in preferred order.
237
- *
238
- * If an index.html file is not found, `send` will NOT generate a directory listing.
239
- *
240
- * The `send` method will automatically set the `Content-Type` header based on the file extension.
241
- *
242
- * If the file is not found, the `send` method will automatically send a 404 response.
243
- *
244
-
245
- * @returns STREAM_ENDED
246
- */
247
- sendFile(status: number, headers: OutgoingHttpHeaders, options: {
248
- root: string;
249
- reqpath: string;
250
- offset?: number;
251
- length?: number;
252
- index?: string | boolean | string[] | undefined,
253
- on404?: () => Promise<typeof STREAM_ENDED>;
254
- onDir?: () => Promise<typeof STREAM_ENDED>;
255
- }) {
256
-
257
- // the headers and status have to be set on the response object before piping the stream
258
- this.res.statusCode = status;
259
- this.toHeadersMap(headers).forEach((v, k) => { this.res.appendHeader(k, v); });
260
-
261
- const { root, reqpath, offset, length } = options;
262
-
263
- if (process.env.DEBUG?.split(",").includes("send")) {
264
- console.error("sendFile", root, reqpath, status, headers);
265
- }
266
-
267
- const stream = send(this.req, reqpath, {
268
- dotfiles: "ignore",
269
- index: false,
270
- root,
271
- start: offset,
272
- end: length && length - 1,
273
- });
274
- return new Promise<typeof STREAM_ENDED>((resolve, reject) => {
275
-
276
- stream.on("error", (err) => Promise.resolve().then(async (): Promise<typeof STREAM_ENDED> => {
277
- if (err === 404 || err?.statusCode === 404) {
278
- return (await options.on404?.()) ?? this.sendEmpty(404);
279
- } else {
280
- console.log(err);
281
- throw this.sendEmpty(500);
282
- }
283
- }).then(resolve, reject));
284
-
285
- stream.on("directory", () => Promise.resolve().then(async (): Promise<typeof STREAM_ENDED> => {
286
- return (await options.onDir?.())
287
- ?? this.sendEmpty(404, { "x-reason": "Directory listing not allowed" })
288
- }).then(resolve, reject));
289
-
290
- stream.on("end", () => {
291
- resolve(STREAM_ENDED);
292
- })
293
-
294
- this.checkHeadersSentBy(true);
295
- stream.pipe(this.res);
296
- });
297
- }
298
-
299
- setCookie(name: string, value: string, options: {
300
- domain?: string;
301
- path?: string;
302
- expires?: Date;
303
- maxAge?: number;
304
- secure?: boolean;
305
- httpOnly?: boolean;
306
- sameSite?: "Strict" | "Lax" | "None";
307
- }) {
308
- var cookie = `${name}=${encodeURIComponent(value)}`;
309
- if (options.domain) cookie += `; Domain=${options.domain}`;
310
- if (options.path) cookie += `; Path=${options.path}`;
311
- if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
312
- if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;
313
- if (options.secure) cookie += `; Secure`;
314
- if (options.httpOnly) cookie += `; HttpOnly`;
315
- if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
316
- this.appendHeader("Set-Cookie", cookie);
317
- }
318
-
319
- appendHeader(name: string, value: string): void {
320
- const current = this.res.getHeader(name);
321
- this.res.setHeader(name,
322
- current
323
- ? Array.isArray(current)
324
- ? [...current as string[], value]
325
- : [current as string, value]
326
- : value
327
- );
328
- }
329
-
330
- setHeader(name: string, value: string): void {
331
- this.res.setHeader(name, value);
332
- }
333
- writeHead(status: number, headers: OutgoingHttpHeaders = {}): void {
334
- if (process.env.DEBUG?.split(",").includes("send")) {
335
- console.error("writeHead", status, headers);
336
- }
337
- this.checkHeadersSentBy(true);
338
- this.res.writeHead(status, headers);
339
- }
340
- write(chunk: Buffer | string, encoding?: NodeJS.BufferEncoding): void {
341
- // Between http1 and http2, the types are slightly different, but the runtime effect seems to be the same.
342
- encoding ? (this.res as ServerResponse).write(chunk, encoding) : (this.res as ServerResponse).write(chunk)
343
- }
344
- end(): typeof STREAM_ENDED {
345
- this.res.end();
346
- return STREAM_ENDED;
347
- }
348
-
349
- get headersSent() {
350
- return this.res.headersSent;
351
- }
352
-
353
- headersSentBy: Error | undefined;
354
- }
355
-
356
- export class StreamerState {
357
-
358
- readBody
359
- sendEmpty
360
- sendString
361
- sendBuffer
362
- sendStream
363
- sendFile
364
- setCookie
365
- /**
366
- *
367
- * Sets a single header value. If the header already exists in the to-be-sent
368
- * headers, its value will be replaced. Use an array of strings to send multiple
369
- * headers with the same name
370
- *
371
- * When headers have been set with `response.setHeader()`, they will be merged
372
- * with any headers passed to `response.writeHead()`, with the headers passed
373
- * to `response.writeHead()` given precedence.
374
- *
375
- */
376
- setHeader
377
- writeHead
378
- write
379
- end
380
-
381
- /** sends a status and plain text string body */
382
- sendSimple(status: number, msg: string): typeof STREAM_ENDED {
383
- return this.sendString(status, {
384
- "content-type": "text/plain"
385
- }, msg, "utf8");
386
- }
387
- /** Stringify the value (unconditionally) and send it with content-type `application/json` */
388
- sendJSON<T>(status: number, obj: T): typeof STREAM_ENDED {
389
- return this.sendString(status, {
390
- "content-type": "application/json"
391
- }, JSON.stringify(obj), "utf8");
392
- }
393
-
394
-
395
- STREAM_ENDED: typeof STREAM_ENDED = STREAM_ENDED;
396
-
397
- constructor(private streamer: Streamer) {
398
- this.readBody = this.streamer.readBody.bind(this.streamer);
399
- this.sendEmpty = this.streamer.sendEmpty.bind(this.streamer);
400
- this.sendString = this.streamer.sendString.bind(this.streamer);
401
- this.sendBuffer = this.streamer.sendBuffer.bind(this.streamer);
402
- this.sendStream = this.streamer.sendStream.bind(this.streamer);
403
- this.sendFile = this.streamer.sendFile.bind(this.streamer);
404
- this.setHeader = this.streamer.setHeader.bind(this.streamer);
405
- this.writeHead = this.streamer.writeHead.bind(this.streamer);
406
- this.write = this.streamer.write.bind(this.streamer);
407
- this.end = this.streamer.end.bind(this.streamer);
408
- this.setCookie = this.streamer.setCookie.bind(this.streamer);
409
-
410
- }
411
-
412
-
413
- get url() { return this.streamer.url; }
414
- get method(): AllowedMethod { return this.streamer.method; }
415
- get headers() { return this.streamer.headers; }
416
- get host() { return this.streamer.host; }
417
- get urlInfo() { return this.streamer.urlInfo; }
418
- get headersSent() { return this.streamer.headersSent; }
419
-
420
- get reader() { return this.streamer.reader; }
421
-
422
- /** Currently this is based on whether the socket is secure, so a proxy will cause problems. */
423
- get isSecure() { return this.streamer.isSecure; }
424
- get cookies() { return this.streamer.cookies; }
425
-
426
- }
427
-
428
-
429
- import { AllowedMethod, AllowedMethods, Router } from './routes/router';
430
-
package/src/tiddlywiki.ts DELETED
@@ -1,94 +0,0 @@
1
- import { TiddlyWiki, TWBoot, TWBootBrowser, TWBootNode } from "tiddlywiki";
2
- import { } from "tiddlywiki/boot/bootprefix";
3
- import { $TW } from "./commander";
4
- import { resolve } from "node:path";
5
- import { dist_resolve, is } from "./utils";
6
- import { ok } from "node:assert";
7
-
8
- declare module "tiddlywiki" {
9
- interface TWUtils {
10
- eachAsync: (array: any[], callback: (item: any, index: number) => Promise<void>) => Promise<void>;
11
- }
12
- interface TWBoot {
13
-
14
- }
15
- }
16
-
17
- export async function bootTiddlyWiki(wikiPath: string) {
18
-
19
- const $tw = TiddlyWiki()
20
-
21
- $tw.utils.eachAsync = eachAsync;
22
-
23
- $tw.boot.boot = async (callback) => {
24
- // Initialise crypto object
25
- $tw.crypto = new $tw.utils.Crypto();
26
- // Initialise password prompter
27
- if ($tw.browser && !$tw.node) {
28
- $tw.passwordPrompt = new $tw.utils.PasswordPrompt();
29
- }
30
- // Preload any encrypted tiddlers
31
- await new Promise<void>(resolve =>
32
- $tw.boot.decryptEncryptedTiddlers(resolve)
33
- );
34
-
35
- // $tw.boot.startup();
36
- await new Promise<void>(callback => {
37
- const options = { callback };
38
- $tw.boot.initStartup(options);
39
- $tw.boot.loadStartup(options);
40
- $tw.boot.execStartup(options);
41
- });
42
-
43
- callback?.();
44
-
45
- };
46
-
47
- // creating a new tiddler with the same title as a shadow tiddler
48
- // prevents the shadow tiddler from defining modules
49
-
50
- $tw.preloadTiddler({ title: "$:/core/modules/commander.js" })
51
- $tw.modules.define("$:/core/modules/commander.js", "global", {
52
- Commander: { initCommands: function () { } },
53
- });
54
-
55
- // disable the default commander. We'll use our own version of it.
56
- $tw.preloadTiddler({ title: "$:/core/modules/startup/commands.js" })
57
- $tw.modules.define("$:/core/modules/startup/commands.js", "startup", {
58
- name: "commands",
59
- platforms: ["node"],
60
- after: ["story"],
61
- synchronous: true,
62
- startup: () => { },
63
- });
64
-
65
-
66
-
67
- $tw.preloadTiddler({ title: "$:/plugins/tiddlywiki/multiwikiserver/startup.js" })
68
- $tw.modules.define("$:/plugins/tiddlywiki/multiwikiserver/startup.js", "startup", {
69
- name: "multiwikiserver",
70
- platforms: ["node"],
71
- after: ["load-modules"],
72
- before: ["story", "commands"],
73
- synchronous: true,
74
- startup: () => { },
75
- });
76
-
77
- // tiddlywiki [+<pluginname> | ++<pluginpath>] [<wikipath>] ...[--command ...args]
78
- $tw.boot.argv = [
79
- "++" + dist_resolve("../plugins/client"),
80
- "+plugins/tiddlywiki/tiddlyweb",
81
- "+themes/tiddlywiki/vanilla",
82
- "+themes/tiddlywiki/snowwhite",
83
- wikiPath,
84
- ];
85
-
86
- // use callback to match the type signature
87
- await new Promise<void>(resolve => $tw.boot.boot(resolve));
88
-
89
- // this makes sure boot followed the node path
90
- ok(!$tw.boot.tasks.readBrowserTiddlers);
91
-
92
- return $tw;
93
-
94
- }