@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.
- package/README.md +3 -1
- package/dist/server.d.ts +923 -0
- package/dist/server.js +1763 -1415
- package/dist/server.js.map +1 -1
- package/editions/mws-docs/tiddlers/$__StoryList.tid +3 -3
- package/editions/mws-docs/tiddlers/MWS and SQLite.md +11 -0
- package/editions/mws-docs/tiddlers/Request Server.md +20 -0
- package/editions/mws-docs/tiddlers/Request Server.md.meta +5 -0
- package/package.json +16 -10
- package/prisma/schema.prisma +1 -0
- package/react-user-mgmt/package-lock.json +76 -321
- package/react-user-mgmt/package.json +2 -5
- package/react-user-mgmt/public/chunk-YALWN5OT.js +2 -0
- package/react-user-mgmt/public/chunk-YALWN5OT.js.map +7 -0
- package/react-user-mgmt/public/esm-QKDFEP3B.js +3 -0
- package/react-user-mgmt/public/esm-QKDFEP3B.js.map +7 -0
- package/react-user-mgmt/public/index.html +1 -26
- package/react-user-mgmt/public/main.js +68 -109
- package/react-user-mgmt/public/main.js.map +4 -4
- package/react-user-mgmt/public/stats.css +597 -0
- package/react-user-mgmt/public/stats.html +59 -0
- package/react-user-mgmt/public/stats.js +2013 -0
- package/react-user-mgmt/public/stats.json +1 -0
- package/react-user-mgmt/public/stats.svg +4 -0
- package/react-user-mgmt/tsconfig.json +3 -0
- package/dist/server.cjs +0 -16677
- package/dist/server.cjs.map +0 -1
- package/src/StateObject.ts +0 -316
- package/src/commander.ts +0 -417
- package/src/commands/divider.ts +0 -20
- package/src/commands/index.ts +0 -24
- package/src/commands/mws-init-store.ts +0 -77
- package/src/commands/mws-listen.ts +0 -136
- package/src/commands/mws-load-archive.ts +0 -281
- package/src/commands/mws-load-plugin-bags.ts +0 -151
- package/src/commands/mws-load-tiddlers.ts +0 -37
- package/src/commands/mws-load-wiki-folder.ts +0 -124
- package/src/commands/mws-render-tiddlywiki5.ts +0 -55
- package/src/commands/mws-save-archive.ts +0 -111
- package/src/commands/mws-save-tiddler-text.ts +0 -33
- package/src/commands/tests-complete.ts +0 -21
- package/src/global.ts +0 -247
- package/src/routes/TiddlerStore.ts +0 -722
- package/src/routes/bag-file-server.ts +0 -340
- package/src/routes/cache.ts +0 -25
- package/src/routes/index.ts +0 -138
- package/src/routes/managers/index.ts +0 -17
- package/src/routes/managers/manager-recipes.ts +0 -438
- package/src/routes/managers/manager-users.ts +0 -201
- package/src/routes/managers/router-tiddlers.ts +0 -313
- package/src/routes/router.ts +0 -429
- package/src/routes/services/PasswordService.ts +0 -178
- package/src/routes/services/attachments.ts +0 -259
- package/src/routes/services/sessions.ts +0 -166
- package/src/routes/tw-test.ts +0 -65
- package/src/server.ts +0 -151
- package/src/setupDevServer.ts +0 -71
- package/src/streamer.ts +0 -430
- package/src/tiddlywiki.ts +0 -94
- package/src/utils/data-checks.ts +0 -172
- package/src/utils/index.ts +0 -4
- package/src/utils/rootRoute.ts +0 -237
- package/src/utils/utils.ts +0 -403
- package/src/utils/zodAssert.ts +0 -269
- /package/prisma/{migrations/notes.md → notes.md} +0 -0
package/src/commander.ts
DELETED
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { SiteConfig } from "./routes/router";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
|
|
5
|
-
import { MWSConfig } from "./server";
|
|
6
|
-
import { Prisma, PrismaClient } from "@prisma/client";
|
|
7
|
-
import { createClient } from "@libsql/client";
|
|
8
|
-
import { PrismaLibSQL } from "@prisma/adapter-libsql";
|
|
9
|
-
import * as sessions from "./routes/services/sessions";
|
|
10
|
-
import * as attacher from "./routes/services/attachments";
|
|
11
|
-
import { PasswordService } from "./routes/services/PasswordService";
|
|
12
|
-
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
13
|
-
import { ITXClientDenyList } from "@prisma/client/runtime/library";
|
|
14
|
-
import { TiddlerFields, TW } from "tiddlywiki";
|
|
15
|
-
import { dist_resolve } from "./utils";
|
|
16
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
17
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
18
|
-
|
|
19
|
-
import { commands, mws_listen, divider } from "./commands";
|
|
20
|
-
|
|
21
|
-
export interface $TW {
|
|
22
|
-
utils: any;
|
|
23
|
-
wiki: any;
|
|
24
|
-
config: any;
|
|
25
|
-
boot: any;
|
|
26
|
-
loadTiddlersFromPath: any;
|
|
27
|
-
Tiddler: {
|
|
28
|
-
// TW5-typed for some reason just types this as a record of modules, which is incorrect
|
|
29
|
-
fieldModules: Record<string, {
|
|
30
|
-
name: string;
|
|
31
|
-
parse?: (value: any) => any;
|
|
32
|
-
stringify?: (value: any) => string;
|
|
33
|
-
}>;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface CommandInfo {
|
|
38
|
-
name: string;
|
|
39
|
-
/**
|
|
40
|
-
* @default false
|
|
41
|
-
*
|
|
42
|
-
* @description
|
|
43
|
-
*
|
|
44
|
-
* - Regardless of the value of `synchronous`, the execute method is always awaited.
|
|
45
|
-
* - Let `result` be any value thrown by the constructor or returned or thrown by the execute method.
|
|
46
|
-
* ```
|
|
47
|
-
* synchronous: false
|
|
48
|
-
* ```
|
|
49
|
-
* - `result` is awaited (if result is not then-able, this has no effect).
|
|
50
|
-
* - If `result` is truthy, the command is failed without waiting for the callback.
|
|
51
|
-
* - If `result` is falsy, the command waits for the callback result.
|
|
52
|
-
* - The callback value is NOT awaited.
|
|
53
|
-
* - if the callback value is truthy, the command is failed.
|
|
54
|
-
* - if the callback value is falsy, the command is completed.
|
|
55
|
-
* ```
|
|
56
|
-
* synchronous: true
|
|
57
|
-
* ```
|
|
58
|
-
* - `result` is awaited (if result is not then-able, this has no effect).
|
|
59
|
-
* - If `result` is truthy, the command is failed.
|
|
60
|
-
* - If `result` is falsy, the command is completed.
|
|
61
|
-
*
|
|
62
|
-
* - The callback is not available if `synchronous` is true.
|
|
63
|
-
*
|
|
64
|
-
*/
|
|
65
|
-
synchronous?: boolean;
|
|
66
|
-
namedParameterMode?: boolean;
|
|
67
|
-
mandatoryParameters?: string[];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// move the startup logic into a separate class
|
|
71
|
-
class StartupCommander {
|
|
72
|
-
|
|
73
|
-
constructor(
|
|
74
|
-
public config: MWSConfig,
|
|
75
|
-
public $tw: TW,
|
|
76
|
-
public PasswordService: PasswordService,
|
|
77
|
-
) {
|
|
78
|
-
|
|
79
|
-
// console.log(config.wikiPath);
|
|
80
|
-
// this is already resolved to the cwd.
|
|
81
|
-
this.wikiPath = config.wikiPath;
|
|
82
|
-
this.storePath = path.resolve(this.wikiPath, "store");
|
|
83
|
-
this.databasePath = path.resolve(this.storePath, "database.sqlite");
|
|
84
|
-
this.outputPath = path.resolve($tw.boot.wikiPath, $tw.config.wikiOutputSubDir);
|
|
85
|
-
this.cachePath = path.resolve(this.wikiPath, "cache");
|
|
86
|
-
|
|
87
|
-
if (!existsSync(this.storePath)) {
|
|
88
|
-
mkdirSync(this.storePath, { recursive: true });
|
|
89
|
-
this.setupRequired = true;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// using the libsql adapter because for some reason prisma was
|
|
93
|
-
// freezing when loading the system bag favicons.
|
|
94
|
-
// the libsql adapter has an additional advantage of letting us specify pragma
|
|
95
|
-
// and also gives us more control over connections.
|
|
96
|
-
|
|
97
|
-
this.libsql = createClient({ url: "file:" + this.databasePath });
|
|
98
|
-
// console.log(this.libsql.protocol, this.databasePath);
|
|
99
|
-
// this.libsql.execute("pragma synchronous=off");
|
|
100
|
-
this.engine = new PrismaClient({
|
|
101
|
-
log: ["info", "warn"],
|
|
102
|
-
adapter: new PrismaLibSQL(this.libsql),
|
|
103
|
-
// datasourceUrl: "file:" + this.databasePath
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
this.siteConfig = {
|
|
107
|
-
wikiPath: this.wikiPath,
|
|
108
|
-
allowAnonReads: !!config.config?.allowAnonReads,
|
|
109
|
-
allowAnonWrites: !!config.config?.allowAnonWrites,
|
|
110
|
-
allowUnreadableBags: !!config.config?.allowUnreadableBags,
|
|
111
|
-
attachmentsEnabled: !!config.config?.saveLargeTextToFileSystem,
|
|
112
|
-
attachmentSizeLimit: config.config?.saveLargeTextToFileSystem ?? 0,
|
|
113
|
-
enableBrowserCache: !!config.config?.enableBrowserCache,
|
|
114
|
-
enableGzip: !!config.config?.enableGzip,
|
|
115
|
-
contentTypeInfo: $tw.config.contentTypeInfo,
|
|
116
|
-
storePath: this.storePath,
|
|
117
|
-
saveLargeTextToFileSystem: undefined as never
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
this.SessionManager = config.SessionManager || sessions.SessionManager;
|
|
121
|
-
this.AttachmentService = config.AttachmentService || attacher.AttachmentService;
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async init() {
|
|
126
|
-
this.setupRequired = false;
|
|
127
|
-
|
|
128
|
-
if (process.env.RUN_OLD_MWS_DB_SETUP_FOR_TESTING) {
|
|
129
|
-
await this.libsql.executeMultiple(readFileSync(dist_resolve(
|
|
130
|
-
"../prisma/migrations/20250406213424_init/migration.sql"
|
|
131
|
-
), "utf8"));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const tables = await this.libsql.batch([{
|
|
135
|
-
sql: `SELECT tbl_name FROM sqlite_master WHERE type='table'`, args: [],
|
|
136
|
-
}]).then(e => e[0]?.rows as { tbl_name: string }[] | undefined);
|
|
137
|
-
|
|
138
|
-
const hasExisting = !!tables?.length;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const hasMigrationsTable = !!tables?.length && !!tables?.some((e) => e.tbl_name === "_prisma_migrations");
|
|
142
|
-
if (!hasMigrationsTable) await this.createMigrationsTable();
|
|
143
|
-
await this.checkMigrationsTable(hasExisting && !hasMigrationsTable);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const users = await this.engine.users.count();
|
|
147
|
-
if (!users) { this.setupRequired = true; }
|
|
148
|
-
}
|
|
149
|
-
async createMigrationsTable() {
|
|
150
|
-
await this.libsql.execute({
|
|
151
|
-
sql:
|
|
152
|
-
'CREATE TABLE "_prisma_migrations" (\n' +
|
|
153
|
-
' "id" TEXT PRIMARY KEY NOT NULL,\n' +
|
|
154
|
-
' "checksum" TEXT NOT NULL,\n' +
|
|
155
|
-
' "finished_at" DATETIME,\n' +
|
|
156
|
-
' "migration_name" TEXT NOT NULL,\n' +
|
|
157
|
-
' "logs" TEXT,\n' +
|
|
158
|
-
' "rolled_back_at" DATETIME,\n' +
|
|
159
|
-
' "started_at" DATETIME NOT NULL DEFAULT current_timestamp,\n' +
|
|
160
|
-
' "applied_steps_count" INTEGER UNSIGNED NOT NULL DEFAULT 0\n' +
|
|
161
|
-
')',
|
|
162
|
-
args: [],
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
async checkMigrationsTable(migrateExisting: boolean) {
|
|
166
|
-
|
|
167
|
-
const applied_migrations = new Set(
|
|
168
|
-
await this.libsql.batch([{
|
|
169
|
-
sql: `Select migration_name from _prisma_migrations`, args: []
|
|
170
|
-
}]).then(e => e[0]?.rows.map(e => e.migration_name))
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const migrations = await readdir(dist_resolve("../prisma/migrations"));
|
|
174
|
-
migrations.sort();
|
|
175
|
-
|
|
176
|
-
const new_migrations = migrations.filter(m => !applied_migrations.has(m) && m !== "migration_lock.toml");
|
|
177
|
-
if (!new_migrations.length) return;
|
|
178
|
-
|
|
179
|
-
function generateChecksum(fileContent: string) {
|
|
180
|
-
return createHash('sha256').update(fileContent).digest('hex');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
console.log("New migrations found", new_migrations);
|
|
184
|
-
|
|
185
|
-
for (const migration of new_migrations) {
|
|
186
|
-
const migration_path = dist_resolve(`../prisma/migrations/${migration}/migration.sql`);
|
|
187
|
-
if (!existsSync(migration_path)) continue;
|
|
188
|
-
|
|
189
|
-
const fileContent = await readFile(migration_path, 'utf-8');
|
|
190
|
-
// this is the hard-coded name of the first migration.
|
|
191
|
-
if (migrateExisting && migration === "20250406213424_init") {
|
|
192
|
-
console.log("Existing migration", migration, "is already applied");
|
|
193
|
-
} else {
|
|
194
|
-
console.log("Applying migration", migration);
|
|
195
|
-
await this.libsql.executeMultiple(fileContent);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
await this.libsql.execute({
|
|
199
|
-
sql: 'INSERT INTO _prisma_migrations (' +
|
|
200
|
-
'id, migration_name, checksum, finished_at, logs, rolled_back_at, started_at, applied_steps_count' +
|
|
201
|
-
') VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
|
202
|
-
args: [randomUUID(), migration, generateChecksum(fileContent), Date.now(), null, null, Date.now(), 1]
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
console.log("Migrations applied", new_migrations);
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
wikiPath: string;
|
|
210
|
-
storePath: string;
|
|
211
|
-
databasePath: string;
|
|
212
|
-
cachePath: string;
|
|
213
|
-
|
|
214
|
-
libsql;
|
|
215
|
-
engine: PrismaClient<Prisma.PrismaClientOptions, never, {
|
|
216
|
-
result: {
|
|
217
|
-
// this types every output field with PrismaField
|
|
218
|
-
[T in Uncapitalize<Prisma.ModelName>]: {
|
|
219
|
-
[K in keyof PrismaPayloadScalars<Capitalize<T>>]: () => {
|
|
220
|
-
compute: () => PrismaField<Capitalize<T>, K>
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
client: {},
|
|
225
|
-
model: {},
|
|
226
|
-
query: {},
|
|
227
|
-
}>;
|
|
228
|
-
|
|
229
|
-
$transaction<R>(
|
|
230
|
-
fn: (prisma: Omit<Commander["engine"], ITXClientDenyList>) => Promise<R>,
|
|
231
|
-
options?: {
|
|
232
|
-
maxWait?: number,
|
|
233
|
-
timeout?: number,
|
|
234
|
-
isolationLevel?: Prisma.TransactionIsolationLevel
|
|
235
|
-
}
|
|
236
|
-
): Promise<R> {
|
|
237
|
-
// $transaction doesn't have the client extensions types,
|
|
238
|
-
// but should have them available (were they not just types).
|
|
239
|
-
return this.engine.$transaction(fn as (prisma: any) => Promise<any>, options);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
siteConfig: SiteConfig;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
SessionManager: typeof sessions.SessionManager;
|
|
247
|
-
AttachmentService: typeof attacher.AttachmentService;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
/** Signals that database setup is required. May be set to false by any qualified setup command. */
|
|
252
|
-
setupRequired: boolean = true;
|
|
253
|
-
outputPath: string;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
Parse a sequence of commands
|
|
257
|
-
commandTokens: an array of command string tokens
|
|
258
|
-
wiki: reference to the wiki store object
|
|
259
|
-
streams: {output:, error:}, each of which has a write(string) method
|
|
260
|
-
callback: a callback invoked as callback(err) where err is null if there was no error
|
|
261
|
-
*/
|
|
262
|
-
export class Commander extends StartupCommander {
|
|
263
|
-
|
|
264
|
-
constructor(
|
|
265
|
-
config: MWSConfig,
|
|
266
|
-
$tw: TW,
|
|
267
|
-
PasswordService: PasswordService,
|
|
268
|
-
) {
|
|
269
|
-
super(config, $tw, PasswordService);
|
|
270
|
-
this.nextToken = 0;
|
|
271
|
-
this.verbose = false;
|
|
272
|
-
|
|
273
|
-
const { listeners, onListenersCreated } = config;
|
|
274
|
-
config.listeners = [];
|
|
275
|
-
config.onListenersCreated = undefined;
|
|
276
|
-
// there's nothing that can't be hacked in a Node process,
|
|
277
|
-
// but this just makes it a little bit harder for the listeners to be read.
|
|
278
|
-
// this can be replaced, but it only recieves the listeners via closure.
|
|
279
|
-
this.create_mws_listen = (params: string[]) => {
|
|
280
|
-
return new mws_listen.Command(params, this, listeners, onListenersCreated);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
create_mws_listen;
|
|
285
|
-
/**
|
|
286
|
-
* The promise of the current execution.
|
|
287
|
-
* It is created and returned by execute,
|
|
288
|
-
* but also accessible here.
|
|
289
|
-
*
|
|
290
|
-
* After the promise is resolved, it will
|
|
291
|
-
* be available until execute is called again.
|
|
292
|
-
*/
|
|
293
|
-
promise!: Promise<void>;
|
|
294
|
-
private callback!: (err?: any) => void;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
commandTokens!: string[];
|
|
298
|
-
nextToken
|
|
299
|
-
verbose
|
|
300
|
-
|
|
301
|
-
static initCommands(moduleType?: string) {
|
|
302
|
-
if (moduleType) throw new Error("moduleType is not implemented");
|
|
303
|
-
}
|
|
304
|
-
/*
|
|
305
|
-
Add a string of tokens to the command queue
|
|
306
|
-
*/
|
|
307
|
-
addCommandTokens(params: string[]) {
|
|
308
|
-
if (this.verbose) console.log("Commander addCommandTokens", params);
|
|
309
|
-
this.commandTokens.splice(this.nextToken, 0, ...params);
|
|
310
|
-
}
|
|
311
|
-
/*
|
|
312
|
-
Execute the sequence of commands and invoke a callback on completion
|
|
313
|
-
*/
|
|
314
|
-
execute(commandTokens: string[]) {
|
|
315
|
-
console.log("Commander", commandTokens);
|
|
316
|
-
this.commandTokens = commandTokens;
|
|
317
|
-
this.promise = new Promise<void>((resolve, reject) => {
|
|
318
|
-
this.callback = (err: any) => {
|
|
319
|
-
if (err) this.$tw.utils.error("Error: " + err);
|
|
320
|
-
err ? reject(err) : resolve();
|
|
321
|
-
};
|
|
322
|
-
});
|
|
323
|
-
this.executeNextCommand();
|
|
324
|
-
return this.promise;
|
|
325
|
-
}
|
|
326
|
-
/*
|
|
327
|
-
Execute the next command in the sequence
|
|
328
|
-
*/
|
|
329
|
-
executeNextCommand() {
|
|
330
|
-
|
|
331
|
-
// Invoke the callback if there are no more commands
|
|
332
|
-
if (this.nextToken >= this.commandTokens.length) {
|
|
333
|
-
this.callback(null);
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Get and check the command token
|
|
338
|
-
let commandName = this.commandTokens[this.nextToken++] as string;
|
|
339
|
-
if (commandName.slice(0, 2) !== "--") {
|
|
340
|
-
console.log(this.commandTokens);
|
|
341
|
-
this.callback("Missing command: " + commandName);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
commandName = commandName.slice(2); // Trim off the --
|
|
346
|
-
|
|
347
|
-
// Get the command info
|
|
348
|
-
var command = commands[commandName], c, err;
|
|
349
|
-
if (!command) {
|
|
350
|
-
this.callback("Unknown command: " + commandName);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Accumulate the parameters to the command
|
|
355
|
-
const nextCommand = this.commandTokens.findIndex((token, i) => i >= this.nextToken && token.startsWith("--"));
|
|
356
|
-
const params = this.commandTokens.slice(this.nextToken, nextCommand === -1 ? undefined : nextCommand);
|
|
357
|
-
this.nextToken = nextCommand === -1 ? this.commandTokens.length : nextCommand;
|
|
358
|
-
|
|
359
|
-
if (commandName !== divider.info.name)
|
|
360
|
-
console.log("Commander executing", commandName, params);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
// Parse named parameters if required
|
|
364
|
-
const paramsIfMandetory = !command.info.mandatoryParameters ? params :
|
|
365
|
-
this.extractNamedParameters(params, command.info.mandatoryParameters);
|
|
366
|
-
if (typeof params === "string") { this.callback(params); return; }
|
|
367
|
-
|
|
368
|
-
new Promise<any>(async (resolve) => {
|
|
369
|
-
const { Command, info } = command!;
|
|
370
|
-
try {
|
|
371
|
-
c = info.name === "mws-listen"
|
|
372
|
-
? this.create_mws_listen(paramsIfMandetory)
|
|
373
|
-
: new Command(paramsIfMandetory, this, info.synchronous ? undefined : resolve);
|
|
374
|
-
err = await c.execute();
|
|
375
|
-
if (err || info.synchronous) resolve(err);
|
|
376
|
-
} catch (e) {
|
|
377
|
-
resolve(e);
|
|
378
|
-
}
|
|
379
|
-
}).then((err: any) => {
|
|
380
|
-
if (err) {
|
|
381
|
-
console.log(err);
|
|
382
|
-
this.callback(err);
|
|
383
|
-
} else {
|
|
384
|
-
this.executeNextCommand();
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
/*
|
|
390
|
-
Given an array of parameter strings `params` in name=value format, and an array of mandatory parameter names in `mandatoryParameters`, returns a hashmap of values or a string if error
|
|
391
|
-
*/
|
|
392
|
-
extractNamedParameters(params: string[], mandatoryParameters?: string[]) {
|
|
393
|
-
mandatoryParameters = mandatoryParameters || [];
|
|
394
|
-
var errors: any[] = [], paramsByName = Object.create(null);
|
|
395
|
-
// Extract the parameters
|
|
396
|
-
each(params, function (param: string) {
|
|
397
|
-
var index = param.indexOf("=");
|
|
398
|
-
if (index < 1) {
|
|
399
|
-
errors.push("malformed named parameter: '" + param + "'");
|
|
400
|
-
}
|
|
401
|
-
paramsByName[param.slice(0, index)] = param.slice(index + 1).trim();
|
|
402
|
-
});
|
|
403
|
-
// Check the mandatory parameters are present
|
|
404
|
-
each(mandatoryParameters, function (mandatoryParameter: string) {
|
|
405
|
-
if (!hop(paramsByName, mandatoryParameter)) {
|
|
406
|
-
errors.push("missing mandatory parameter: '" + mandatoryParameter + "'");
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
// Return any errors
|
|
410
|
-
if (errors.length > 0) {
|
|
411
|
-
return errors.join(" and\n");
|
|
412
|
-
} else {
|
|
413
|
-
return paramsByName;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
package/src/commands/divider.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Commander, CommandInfo } from "../commander";
|
|
2
|
-
|
|
3
|
-
export const info: CommandInfo = {
|
|
4
|
-
name: "divider",
|
|
5
|
-
synchronous: true,
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export class Command {
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
public params: string[],
|
|
13
|
-
public commander: Commander,
|
|
14
|
-
) {
|
|
15
|
-
if (this.params.length) throw `${info.name}: No parameters allowed. This is a no-op command.`;
|
|
16
|
-
}
|
|
17
|
-
execute() {
|
|
18
|
-
// Do nothing
|
|
19
|
-
}
|
|
20
|
-
}
|
package/src/commands/index.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import * as mws_load_plugin_bags from "./mws-load-plugin-bags";
|
|
2
|
-
import * as mws_render_tiddler from "./mws-render-tiddlywiki5";
|
|
3
|
-
import * as mws_load_wiki_folder from "./mws-load-wiki-folder";
|
|
4
|
-
import * as mws_save_archive from "./mws-save-archive";
|
|
5
|
-
import * as mws_load_archive from "./mws-load-archive";
|
|
6
|
-
import * as mws_init_store from "./mws-init-store";
|
|
7
|
-
import * as mws_listen from "./mws-listen";
|
|
8
|
-
import * as divider from "./divider";
|
|
9
|
-
import * as tests_complete from "./tests-complete";
|
|
10
|
-
import { CommandInfo } from "../commander";
|
|
11
|
-
|
|
12
|
-
export { mws_listen, divider };
|
|
13
|
-
|
|
14
|
-
export const commands: Record<string, { info: CommandInfo, Command: any }> = {
|
|
15
|
-
[mws_load_plugin_bags.info.name]: mws_load_plugin_bags,
|
|
16
|
-
[mws_render_tiddler.info.name]: mws_render_tiddler,
|
|
17
|
-
[mws_load_wiki_folder.info.name]: mws_load_wiki_folder,
|
|
18
|
-
[mws_save_archive.info.name]: mws_save_archive,
|
|
19
|
-
[mws_load_archive.info.name]: mws_load_archive,
|
|
20
|
-
[mws_init_store.info.name]: mws_init_store,
|
|
21
|
-
[mws_listen.info.name]: mws_listen,
|
|
22
|
-
[divider.info.name]: divider,
|
|
23
|
-
[tests_complete.info.name]: tests_complete,
|
|
24
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
|
-
|
|
3
|
-
import { Commander, CommandInfo } from "../commander";
|
|
4
|
-
import { TiddlerStore } from "../routes/TiddlerStore";
|
|
5
|
-
import { readFileSync } from "node:fs";
|
|
6
|
-
import { dist_require_resolve, dist_resolve } from "../utils";
|
|
7
|
-
|
|
8
|
-
export const info: CommandInfo = {
|
|
9
|
-
name: "mws-init-store",
|
|
10
|
-
synchronous: true,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export class Command {
|
|
15
|
-
|
|
16
|
-
get $tw() { return this.commander.$tw; }
|
|
17
|
-
constructor(
|
|
18
|
-
public params: string[],
|
|
19
|
-
public commander: Commander,
|
|
20
|
-
public callback: (err?: any) => void
|
|
21
|
-
) {
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
async execute() {
|
|
25
|
-
|
|
26
|
-
if (!this.commander.setupRequired) return;
|
|
27
|
-
|
|
28
|
-
await this.commander.$transaction(async (prisma) => {
|
|
29
|
-
const userCount = await prisma.users.count();
|
|
30
|
-
|
|
31
|
-
if (!userCount) {
|
|
32
|
-
|
|
33
|
-
await prisma.roles.createMany({
|
|
34
|
-
data: [
|
|
35
|
-
{ role_id: 1, role_name: "ADMIN", description: "System Administrator" },
|
|
36
|
-
{ role_id: 2, role_name: "USER", description: "Basic User" },
|
|
37
|
-
]
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const user = await prisma.users.create({
|
|
41
|
-
data: { username: "admin", email: "", password: "", roles: { connect: { role_id: 1 } } },
|
|
42
|
-
select: { user_id: true }
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const password = await this.commander.PasswordService.PasswordCreation(user.user_id.toString(), "1234");
|
|
46
|
-
|
|
47
|
-
await prisma.users.update({
|
|
48
|
-
where: { user_id: user.user_id },
|
|
49
|
-
data: { password: password }
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
-
// should give us the path to boot.js
|
|
56
|
-
const tweditions = resolve(dist_require_resolve("tiddlywiki"), "../../editions");
|
|
57
|
-
this.commander.addCommandTokens([
|
|
58
|
-
"--mws-load-plugin-bags",
|
|
59
|
-
"--mws-load-wiki-folder", dist_resolve("../editions/mws-docs"),
|
|
60
|
-
"mws-docs", "MWS Documentation from https://mws.tiddlywiki.com",
|
|
61
|
-
"mws-docs", "MWS Documentation from https://mws.tiddlywiki.com",
|
|
62
|
-
"--mws-load-wiki-folder", resolve(tweditions, "tw5.com"),
|
|
63
|
-
"docs", "TiddlyWiki Documentation from https://tiddlywiki.com",
|
|
64
|
-
"docs", "TiddlyWiki Documentation from https://tiddlywiki.com",
|
|
65
|
-
"--mws-load-wiki-folder", resolve(tweditions, "dev"),
|
|
66
|
-
"dev", "TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev",
|
|
67
|
-
"dev-docs", "TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev",
|
|
68
|
-
"--mws-load-wiki-folder", resolve(tweditions, "tour"),
|
|
69
|
-
"tour", "TiddlyWiki Interactive Tour from https://tiddlywiki.com",
|
|
70
|
-
"tour", "TiddlyWiki Interactive Tour from https://tiddlywiki.com",
|
|
71
|
-
"--divider",
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
this.commander.setupRequired = false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { Commander, CommandInfo } from "../commander";
|
|
3
|
-
import { ok } from "assert";
|
|
4
|
-
import { existsSync, readFileSync } from "fs";
|
|
5
|
-
import { Server, IncomingMessage, ServerResponse, createServer } from "http";
|
|
6
|
-
import * as http2 from "node:http2";
|
|
7
|
-
import { Router } from "../routes/router";
|
|
8
|
-
import { MWSConfig } from "../server";
|
|
9
|
-
import { Streamer } from "../streamer";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export class ListenerBase {
|
|
13
|
-
constructor(
|
|
14
|
-
public server: http2.Http2SecureServer | Server,
|
|
15
|
-
public router: Router,
|
|
16
|
-
public bindInfo: string
|
|
17
|
-
) {
|
|
18
|
-
this.server.on("request", (
|
|
19
|
-
req: IncomingMessage | http2.Http2ServerRequest,
|
|
20
|
-
res: ServerResponse | http2.Http2ServerResponse
|
|
21
|
-
) => {
|
|
22
|
-
this.handleRequest(req, res);
|
|
23
|
-
});
|
|
24
|
-
this.server.on('error', (error: NodeJS.ErrnoException) => {
|
|
25
|
-
|
|
26
|
-
if (error.syscall !== 'listen') {
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// handle specific listen errors with friendly messages
|
|
31
|
-
switch (error.code) {
|
|
32
|
-
case 'EACCES':
|
|
33
|
-
console.error(bindInfo + ' requires elevated privileges');
|
|
34
|
-
process.exit();
|
|
35
|
-
break;
|
|
36
|
-
case 'EADDRINUSE':
|
|
37
|
-
console.error(bindInfo + ' is already in use');
|
|
38
|
-
process.exit();
|
|
39
|
-
break;
|
|
40
|
-
default:
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
this.server.on('listening', () => {
|
|
46
|
-
const address = this.server.address();
|
|
47
|
-
console.log(`Listening on`, address);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
handleRequest(
|
|
52
|
-
req: IncomingMessage | http2.Http2ServerRequest,
|
|
53
|
-
res: ServerResponse | http2.Http2ServerResponse
|
|
54
|
-
) {
|
|
55
|
-
const streamer = new Streamer(req, res, this.router);
|
|
56
|
-
this.router.handle(streamer).catch(streamer.catcher);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export class ListenerHTTPS extends ListenerBase {
|
|
61
|
-
constructor(router: Router, config: MWSConfig["listeners"][number]) {
|
|
62
|
-
const { port, host } = config;
|
|
63
|
-
if (port && typeof port !== "number") throw new Error("If specified, port must be a number");
|
|
64
|
-
const bindInfo = host ? `HTTPS ${host} ${port}` : `HTTPS ${port}`;
|
|
65
|
-
ok(config.key && existsSync(config.key), "Key file not found");
|
|
66
|
-
ok(config.cert && existsSync(config.cert), "Cert file not found");
|
|
67
|
-
const key = readFileSync(config.key);
|
|
68
|
-
const cert = readFileSync(config.cert);
|
|
69
|
-
super(http2.createSecureServer({ key, cert, allowHTTP1: true, }), router, bindInfo);
|
|
70
|
-
if (port) this.server.listen(port, host);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export class ListenerHTTP extends ListenerBase {
|
|
76
|
-
/** Create an http1 server */
|
|
77
|
-
constructor(router: Router, config: MWSConfig["listeners"][number]) {
|
|
78
|
-
const { port, host } = config;
|
|
79
|
-
if (port && typeof port !== "number") throw new Error("If specified, port must be a number");
|
|
80
|
-
const bindInfo = host ? `HTTP ${host} ${port}` : `HTTP ${port}`;
|
|
81
|
-
super(createServer(), router, bindInfo);
|
|
82
|
-
if (port) this.server.listen(port, host);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
export const info: CommandInfo = {
|
|
88
|
-
name: "mws-listen",
|
|
89
|
-
synchronous: true,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
export class Command {
|
|
94
|
-
execute;
|
|
95
|
-
get $tw() { return this.commander.$tw; }
|
|
96
|
-
constructor(
|
|
97
|
-
public params: string[],
|
|
98
|
-
public commander: Commander,
|
|
99
|
-
listenConfig: MWSConfig["listeners"],
|
|
100
|
-
onListenersCreated: MWSConfig["onListenersCreated"]
|
|
101
|
-
) {
|
|
102
|
-
if (this.params.length) throw `${info.name}: No parameters allowed. Please put listener options in the config file.`;
|
|
103
|
-
|
|
104
|
-
this.execute = async () => {
|
|
105
|
-
|
|
106
|
-
this.commander.addCommandTokens([
|
|
107
|
-
"--mws-render-tiddlywiki5",
|
|
108
|
-
"--divider",
|
|
109
|
-
]);
|
|
110
|
-
|
|
111
|
-
const router = await Router.makeRouter(
|
|
112
|
-
this.commander,
|
|
113
|
-
this.commander.config.enableDevServer,
|
|
114
|
-
).catch(e => {
|
|
115
|
-
console.log(e.stack);
|
|
116
|
-
throw "Router failed to load";
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const listeners = listenConfig.map(e => {
|
|
120
|
-
if (!e.key !== !e.cert) {
|
|
121
|
-
throw new Error("Both key and cert are required for HTTPS");
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const listener = e.key && e.cert
|
|
125
|
-
? new ListenerHTTPS(router, e)
|
|
126
|
-
: new ListenerHTTP(router, e);
|
|
127
|
-
|
|
128
|
-
return listener;
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
await onListenersCreated?.(listeners);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
}
|