@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,172 +0,0 @@
1
- import { Prisma } from "@prisma/client";
2
- import { truthy } from "./utils";
3
- import { ok } from "node:assert";
4
-
5
-
6
- export class DataChecks {
7
- allowAnonReads;
8
- allowAnonWrites;
9
- constructor(options: { allowAnonReads?: boolean, allowAnonWrites?: boolean }) {
10
- this.allowAnonReads = options.allowAnonReads;
11
- this.allowAnonWrites = options.allowAnonWrites;
12
- }
13
-
14
- okTiddlerFields(tiddlerFields: Record<string, any>) {
15
- ok(tiddlerFields.title, 'title must not be empty');
16
- Object.entries(tiddlerFields).forEach(([key, value]) => {
17
- if (typeof value === "undefined" || value === null) return;
18
- ok(typeof value === "string", `tiddler fields must be a string, ${key} is ${typeof value}`);
19
- });
20
- }
21
-
22
- okBagName(bagName: PrismaField<"Bags", "bag_name">) {
23
- ok(typeof bagName === "string", 'bagName must be a string');
24
- ok(bagName, 'bagName must not be empty');
25
- }
26
-
27
- okRecipeName(recipeName: PrismaField<"Recipes", "recipe_name">) {
28
- ok(typeof recipeName === "string", 'recipeName must be a string');
29
- ok(recipeName, 'recipeName must not be empty');
30
- }
31
-
32
- okUserID(userID: PrismaField<"Users", "user_id">) {
33
- ok(typeof userID === "number", 'userID must be a number');
34
- ok(userID > 0, 'userID must be greater than zero');
35
- }
36
-
37
- okTiddlerTitle(tiddlerTitle: string): asserts tiddlerTitle is PrismaField<"Tiddlers", "title"> {
38
- ok(typeof tiddlerTitle === "string", 'tiddler title must be a string');
39
- ok(tiddlerTitle, 'tiddler title must not be empty');
40
- }
41
-
42
- okEntityType(entityType: EntityType) {
43
- ok(entityType === "bag" || entityType === "recipe", "Invalid entity type: " + entityType);
44
- }
45
-
46
- okEntityName(entityName: EntityName<EntityType>) {
47
- ok(typeof entityName === "string", 'entityName must be a string');
48
- ok(entityName, 'entityName must not be empty');
49
- }
50
-
51
- okSessionID(sessionID: string): asserts sessionID is PrismaField<"Sessions", "session_id"> {
52
- ok(typeof sessionID === "string", 'sessionID must be a string');
53
- ok(sessionID, 'sessionID must not be empty');
54
- }
55
-
56
- isPermissionName = <T extends string>(e: T): e is T & ACLPermissionName => {
57
- const test = e as ACLPermissionName;
58
- switch (test) {
59
- case "ADMIN":
60
- case "READ":
61
- case "WRITE":
62
- return true;
63
- default: {
64
- const _: never = test;
65
- return false;
66
- }
67
- }
68
- }
69
-
70
- permissions: { [K in ACLPermissionName]: K } = { READ: "READ", WRITE: "WRITE", ADMIN: "ADMIN", };
71
-
72
- isEntityType = (x: any): x is "recipe" | "bag" => ["recipe", "bag"].includes(x);
73
-
74
- entityTypes: { [K in EntityType]: K } = { recipe: "recipe", bag: "bag" };
75
-
76
- /** If the user isn't logged in, user_id is 0. */
77
- getBagWhereACL({ recipe_id, permission, user_id, role_ids }: {
78
- /** Recipe ID can be provided as an extra restriction */
79
- recipe_id?: number,
80
- permission: ACLPermissionName,
81
- user_id: number,
82
- role_ids: number[],
83
- }) {
84
-
85
- const OR = this.getWhereACL({ permission, user_id, role_ids });
86
-
87
- return ([
88
- // all system bags are allowed to be read by any user
89
- permission === "READ" && { is_plugin: true },
90
- ...OR,
91
- // admin permission doesn't get inherited
92
- permission === "ADMIN" ? undefined : {
93
- recipe_bags: {
94
- some: {
95
- // check if we're in position 0 (for write) or any position (for read)
96
- position: permission === "WRITE" ? 0 : undefined,
97
- // of a recipe that the user has this permission on
98
- recipe: { OR },
99
- // if the connection was created with admin permissions
100
- with_acl: true,
101
- // for the specific recipe, if provided
102
- recipe_id,
103
- }
104
- }
105
- }
106
- ] satisfies (Prisma.BagsWhereInput | undefined | null | false)[]).filter(truthy)
107
-
108
- }
109
- getWhereACL({ permission, user_id, role_ids }: {
110
- permission: ACLPermissionName,
111
- user_id?: number,
112
- role_ids?: number[],
113
- }) {
114
- const { allowAnonReads, allowAnonWrites } = this;
115
- const anonRead = allowAnonReads && permission === "READ";
116
- const anonWrite = allowAnonWrites && permission === "WRITE";
117
- const allowAnon = anonRead || anonWrite;
118
- const allperms = ["READ", "WRITE", "ADMIN"] as const;
119
- const index = allperms.indexOf(permission);
120
- if (index === -1) throw new Error("Invalid permission");
121
- const checkPerms = allperms.slice(index);
122
-
123
- return ([
124
- // allow unowned for any user (conditional for anon reads)
125
- (user_id || allowAnon) && { acl: { none: {} }, owner_id: null },
126
- // allow owner for user
127
- user_id && { owner_id: user_id },
128
- // allow acl for user
129
- user_id && role_ids?.length && {
130
- acl: {
131
- some: {
132
- permission: { in: checkPerms },
133
- role_id: { in: role_ids },
134
- }
135
- }
136
- },
137
- user_id && role_ids?.length && {
138
- acl: {
139
- some: {
140
- permission: { in: checkPerms },
141
- role_id: { in: role_ids },
142
- }
143
- }
144
- },
145
-
146
- ] satisfies (Prisma.RecipesWhereInput | Prisma.BagsWhereInput | undefined | null | false | 0)[]
147
- ).filter(truthy)
148
- }
149
-
150
-
151
-
152
- }
153
-
154
-
155
-
156
- /**
157
- ## assumptions about prisma that should be tested
158
-
159
- ```
160
- return await this.engine.acl.findMany({
161
- where: {
162
- entity_name: entityName,
163
- entity_type: entityType,
164
- // if permission_name is undefined, will prisma
165
- // include records without a permission connection?
166
- // ChatGPT 03-mini-high doesn't think so.
167
- permission: { permission_name }
168
- },
169
- });
170
- ```
171
- */
172
- declare let _dataChecks: any;
@@ -1,4 +0,0 @@
1
- export * from "./utils";
2
- export * from "./rootRoute";
3
- export * from "./data-checks";
4
- export * from "./zodAssert";
@@ -1,237 +0,0 @@
1
- import { AuthStateRouteACL, StateObject } from "../StateObject";
2
- import * as z from "zod";
3
- import { AllowedMethod, BodyFormat } from "../routes/router";
4
-
5
-
6
- export interface RouteOptAny extends RouteOptBase<BodyFormat, AllowedMethod[], string[]> { }
7
-
8
- export interface Route extends RouteDef<ParentTuple, string[]> { }
9
-
10
- export interface rootRoute extends RouteDef<[
11
- undefined,
12
- AllowedMethod[],
13
- StateObject<BodyFormat, AllowedMethod>,
14
- [[]]
15
- ], []> { }
16
-
17
- export interface RouteMatch {
18
- route: Route;
19
- params: (string | undefined)[];
20
- remainingPath: string;
21
- }
22
-
23
- type DetermineRouteOptions<
24
- P extends ParentTuple, PA extends string[]
25
- > = P extends [BodyFormat, AllowedMethod[], any, any]
26
- ?
27
- RouteOptBase<P[0], P[1], PA> & { bodyFormat?: undefined; }
28
- :
29
- P extends [undefined, AllowedMethod[], any, any]
30
- ?
31
- | { [K in BodyFormat]: RouteOptBase<K, P[1], PA> & { bodyFormat: K; }; }[BodyFormat]
32
- | RouteOptBase<BodyFormat, P[1], PA> & { bodyFormat?: undefined; }
33
- : never;
34
-
35
- type ParentTuple = [BodyFormat | undefined, AllowedMethod[], any, string[][]];
36
-
37
- interface RouteOptBase<B extends BodyFormat, M extends AllowedMethod[], PA extends string[]> {
38
-
39
- /**
40
- * Regex to test the pathname on. It must start with `^`. If this is a child route,
41
- * it will be tested against the remaining portion of the parent route.
42
- */
43
- path: RegExp;
44
- pathParams?: PA;
45
- /** The uppercase method names to match this route */
46
- method: M;
47
- /**
48
- * The highest bodyformat in the chain always takes precedent. Type-wise, only one is allowed,
49
- * but at runtime the first one found is the one used.
50
- *
51
- * Note that bodyFormat is completely ignored for GET and HEAD requests.
52
- */
53
- bodyFormat?: B;
54
- /** If this route is the last one matched, it will NOT be called, and a 404 will be returned. */
55
- denyFinal?: boolean;
56
- }
57
-
58
- export interface RouteDef<P extends ParentTuple, PA extends string[]> extends RouteOptBase<P[0] & {}, P[1], PA> {
59
-
60
- /**
61
- * If this route's handler sends headers, the matched child route will not be called.
62
- */
63
- handler: (state: StateObject<P[0] extends undefined ? BodyFormat : (P[0] & {}), P[1][number], [...P[3], [...PA]], unknown>) => Promise<P[2]>
64
-
65
- /**
66
- * ### ROUTING
67
- *
68
- * @param route The route definition.
69
- *
70
- * If the parent route sends headers, or returns the STREAM_ENDED symbol,
71
- * this route will not be called.
72
- *
73
- * Inner routes are matched on the remaining portion of the parent route
74
- * using `pathname.slice(match[0].length)`. If the parent route entirely
75
- * matches the pathname, this route will be matched on "/".
76
- *
77
- * If the body format is "stream", "buffer", "ignore" or not yet defined at this level in the tree,
78
- * then zod cannot be used.
79
- *
80
- * Note that GET and HEAD are always bodyFormat: "ignore", regardless of what is set here.
81
- */
82
- defineRoute: <R, PA extends string[],
83
- // T extends DetermineRouteOptions<P, [...PA]>
84
- T extends (P extends [BodyFormat, AllowedMethod[], any, any]
85
- ?
86
- RouteOptBase<P[0], P[1], [...PA]> & { bodyFormat?: undefined; }
87
- :
88
- P extends [undefined, AllowedMethod[], any, any]
89
- ?
90
- | { [K in BodyFormat]: RouteOptBase<K, P[1], [...PA]> & { bodyFormat: K; }; }[BodyFormat]
91
- | RouteOptBase<BodyFormat, P[1], [...PA]> & { bodyFormat?: undefined; }
92
- : never)
93
- > (
94
- route: T,
95
- handler: (
96
- /**
97
- * The state object for this route.
98
- *
99
- * If the route only specifies "GET" and/or "HEAD", then the bodyFormat can only be "ignore"
100
- *
101
- * Otherwise, the bodyFormat is determined by the first parent route that specifies it.
102
- *
103
- * The state object is wrapped in a proxy which throws if methods return a promise that
104
- * doesn't get awaited before the next property access. It only enforces the first layer
105
- * of properties, so if you have a nested object, you will need to wrap it in a proxy as well.
106
- *
107
- * store and store.sql will probably also be wrapped in this proxy.
108
- */
109
- state: StateObject<
110
- // if the route only specifies "GET" and/or "HEAD", then the bodyFormat can only be "ignore"
111
- (Exclude<T["method"][number], "GET" | "HEAD"> extends never ? never : (
112
- // parent route specified bodyFormat?
113
- P[0] extends BodyFormat ? P[0] :
114
- // this route specified bodyFormat?
115
- T["bodyFormat"] extends BodyFormat ? T["bodyFormat"] :
116
- // otherwise it could be anything
117
- BodyFormat
118
- )) | (
119
- // GET and HEAD requests imply "ignore"
120
- T["method"][number] extends "GET" | "HEAD" ? "ignore" : never
121
- ),
122
- // HTTP method
123
- T["method"][number],
124
- // possible placeholder for declaring routes
125
- getPA<P, T>,
126
- // infer zod, if set for this route
127
- unknown
128
- >) => Promise<R>
129
- ) =>
130
- P[0] extends BodyFormat ? RouteDef<[P[0], T["method"], R, P[3]], [...PA]> :
131
- T["bodyFormat"] extends BodyFormat ? RouteDef<[T["bodyFormat"], T["method"], R, P[3]], [...PA]> :
132
- RouteDef<[undefined, T["method"], R, P[3]], [...PA]>
133
-
134
- $o?: P;
135
- }
136
-
137
- type getPA<P extends ParentTuple, T extends DetermineRouteOptions<P, any>> =
138
- [...P[3], ...T["pathParams"] extends string[] ? [T["pathParams"]] : []];
139
- function test<T extends z.ZodTypeAny>(schema: { schema: T }): T {
140
- return schema.schema;
141
- }
142
- const test1 = test({ schema: z.object({ test: z.string() }) })
143
- type t1 = typeof test1;
144
- type t2 = z.infer<t1>;
145
-
146
-
147
-
148
- /** This doesn't need to run, it's just to test types */
149
- function testroute(root: rootRoute) {
150
-
151
- const test1 = root.defineRoute({
152
- path: /^test/,
153
- method: ["GET", "POST"],
154
- bodyFormat: undefined,
155
- }, async state => {
156
- const test: BodyFormat = state.bodyFormat;
157
- });
158
-
159
- const test2_2 = test1.defineRoute({
160
- path: /^test/,
161
- bodyFormat: "www-form-urlencoded",
162
- method: ["POST"],
163
- }, async state => {
164
- // zod: z.object({ test: z.string() }),
165
-
166
-
167
- });
168
-
169
- const test2 = test1.defineRoute({
170
- path: /^test/,
171
- bodyFormat: "string",
172
- method: ["GET"],
173
- zod: z.string(),
174
- // handler: ,
175
- }, async (state) => {
176
- //@ts-expect-error because we didn't include "string"
177
- const test: Exclude<BodyFormat, "ignore"> = state.bodyFormat;
178
- // no error here if bodyFormat is correctly typed
179
- const test2: "ignore" = state.bodyFormat
180
- // @ts-expect-error because it should be "string"
181
- state.isBodyFormat("buffer");
182
- // this should never be an error unless something is really messed up
183
- state.isBodyFormat("ignore");
184
- });
185
-
186
- const test3 = test2.defineRoute({
187
- path: /^test/,
188
- method: ["GET"],
189
- // // @ts-expect-error because it's already been defined by the parent
190
- // bodyFormat: "buffer",
191
- zod: z.string(),
192
- }, async (state) => {
193
- //@ts-expect-error because we didn't include "string"
194
- const test: Exclude<BodyFormat, "ignore"> = state.bodyFormat;
195
- // no error here if bodyFormat is correctly typed
196
- const test2: "ignore" = state.bodyFormat
197
- // @ts-expect-error because it should be "string"
198
- state.isBodyFormat("buffer");
199
- // this should never be an error unless something is really messed up
200
- state.isBodyFormat("ignore");
201
- })
202
-
203
- const test2post = test1.defineRoute({
204
- path: /^test/,
205
- bodyFormat: "string",
206
- method: ["POST"],
207
- zod: z.string(),
208
- // handler: ,
209
- }, async (state) => {
210
- // @ts-expect-error because we didn't include "string"
211
- const test: Exclude<BodyFormat, "string"> = state.bodyFormat;
212
- // no error here if bodyFormat is correctly typed
213
- const test2: "string" = state.bodyFormat
214
- // @ts-expect-error because it should be "string"
215
- state.isBodyFormat("buffer");
216
- // this should never be an error unless something is really messed up
217
- state.isBodyFormat("string");
218
- });
219
-
220
- const test3post = test2post.defineRoute({
221
- path: /^test/,
222
- method: ["POST"],
223
- // // @ts-expect-error because it's already been defined by the parent
224
- // bodyFormat: "buffer",
225
- zod: z.string(),
226
- }, async (state) => {
227
- // @ts-expect-error because we didn't include "string"
228
- const test: Exclude<BodyFormat, "string"> = state.bodyFormat;
229
- // no error here if bodyFormat is correctly typed
230
- const test2: "string" = state.bodyFormat
231
- // @ts-expect-error because it should be "string"
232
- state.isBodyFormat("buffer");
233
- // this should never be an error unless something is really messed up
234
- state.isBodyFormat("string");
235
- })
236
- }
237
-