@axium/server 0.16.3 → 0.17.1
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/build/client/_app/immutable/chunks/{DDMLQWfm.js → 7xl0ELIE.js} +1 -1
- package/build/client/_app/immutable/chunks/7xl0ELIE.js.br +0 -0
- package/build/client/_app/immutable/chunks/7xl0ELIE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BRAdhDz6.js +31 -0
- package/build/client/_app/immutable/chunks/BRAdhDz6.js.br +0 -0
- package/build/client/_app/immutable/chunks/BRAdhDz6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BfcZAjMn.js → CX0J-op4.js} +1 -1
- package/build/client/_app/immutable/chunks/CX0J-op4.js.br +0 -0
- package/build/client/_app/immutable/chunks/CX0J-op4.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{C_sHKpBE.js → DJ_KxCMV.js} +1 -1
- package/build/client/_app/immutable/chunks/DJ_KxCMV.js.br +0 -0
- package/build/client/_app/immutable/chunks/DJ_KxCMV.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.DQs_wJeB.js → app.CQmekYJh.js} +2 -2
- package/build/client/_app/immutable/entry/app.CQmekYJh.js.br +0 -0
- package/build/client/_app/immutable/entry/app.CQmekYJh.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.Dx36W5a3.js +1 -0
- package/build/client/_app/immutable/entry/start.Dx36W5a3.js.br +2 -0
- package/build/client/_app/immutable/entry/start.Dx36W5a3.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.D2ng5LTp.js → 1.DYxkhS_I.js} +1 -1
- package/build/client/_app/immutable/nodes/1.DYxkhS_I.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.DYxkhS_I.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{3.DfNZyDBl.js → 3.Cki5Gkis.js} +1 -1
- package/build/client/_app/immutable/nodes/3.Cki5Gkis.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.Cki5Gkis.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{4.CFJZfOMs.js → 4.BKg_Gu-0.js} +1 -1
- package/build/client/_app/immutable/nodes/4.BKg_Gu-0.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.BKg_Gu-0.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.5undPhf2.js +1 -0
- package/build/client/_app/immutable/nodes/5.5undPhf2.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.5undPhf2.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{6.CqeNzAMh.js → 6.BzQIq2vx.js} +1 -1
- package/build/client/_app/immutable/nodes/6.BzQIq2vx.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.BzQIq2vx.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{1-CNB-iEOC.js → 1-DzEYA6on.js} +2 -2
- package/build/server/chunks/{1-CNB-iEOC.js.map → 1-DzEYA6on.js.map} +1 -1
- package/build/server/chunks/{3-D7xQwEuP.js → 3-Ks9jlNYv.js} +3 -3
- package/build/server/chunks/{3-D7xQwEuP.js.map → 3-Ks9jlNYv.js.map} +1 -1
- package/build/server/chunks/{4-CTLWwpj1.js → 4-CmDUmYYc.js} +3 -3
- package/build/server/chunks/{4-CTLWwpj1.js.map → 4-CmDUmYYc.js.map} +1 -1
- package/build/server/chunks/{5-uP-phnWG.js → 5-BbXAiLZP.js} +3 -3
- package/build/server/chunks/{5-uP-phnWG.js.map → 5-BbXAiLZP.js.map} +1 -1
- package/build/server/chunks/{6-C9P6O1MT.js → 6-CyHZCnEe.js} +3 -3
- package/build/server/chunks/{6-C9P6O1MT.js.map → 6-CyHZCnEe.js.map} +1 -1
- package/build/server/chunks/{Logout-CDjCRZpb.js → Logout-CkwmxNTt.js} +2 -2
- package/build/server/chunks/{Logout-CDjCRZpb.js.map → Logout-CkwmxNTt.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-oktZpRPO.js → _page.svelte-CVJoQAAB.js} +2 -2
- package/build/server/chunks/{_page.svelte-oktZpRPO.js.map → _page.svelte-CVJoQAAB.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-CohtrGLZ.js → _page.svelte-D3kXcWlK.js} +2 -2
- package/build/server/chunks/{_page.svelte-CohtrGLZ.js.map → _page.svelte-D3kXcWlK.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-D5xsy8Qm.js → _page.svelte-DPdvFuWg.js} +3 -3
- package/build/server/chunks/{_page.svelte-D5xsy8Qm.js.map → _page.svelte-DPdvFuWg.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-C07GMDXE.js → _page.svelte-whmO3TtB.js} +3 -3
- package/build/server/chunks/{_page.svelte-C07GMDXE.js.map → _page.svelte-whmO3TtB.js.map} +1 -1
- package/build/server/chunks/{user-CvsWrOQL.js → user-DW-tjDe0.js} +16 -1
- package/build/server/chunks/{user-CvsWrOQL.js.map → user-DW-tjDe0.js.map} +1 -1
- package/build/server/index.js +1 -1
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +6 -6
- package/build/server/manifest.js.map +1 -1
- package/dist/acl.d.ts +54 -0
- package/dist/acl.js +63 -0
- package/dist/api/acl.d.ts +1 -0
- package/dist/api/acl.js +21 -0
- package/dist/api/users.js +16 -12
- package/dist/auth.js +1 -0
- package/dist/cli.js +13 -7
- package/dist/database.d.ts +53 -7
- package/dist/database.js +146 -41
- package/dist/plugins.d.ts +5 -5
- package/dist/routes.d.ts +3 -0
- package/dist/routes.js +3 -0
- package/package.json +1 -1
- package/web/lib/AccessControl.svelte +37 -0
- package/web/lib/AccessControlDialog.svelte +12 -0
- package/build/client/_app/immutable/chunks/BfcZAjMn.js.br +0 -0
- package/build/client/_app/immutable/chunks/BfcZAjMn.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C_sHKpBE.js.br +0 -0
- package/build/client/_app/immutable/chunks/C_sHKpBE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DDMLQWfm.js.br +0 -0
- package/build/client/_app/immutable/chunks/DDMLQWfm.js.gz +0 -0
- package/build/client/_app/immutable/chunks/znOOCAZb.js +0 -31
- package/build/client/_app/immutable/chunks/znOOCAZb.js.br +0 -0
- package/build/client/_app/immutable/chunks/znOOCAZb.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.DQs_wJeB.js.br +0 -0
- package/build/client/_app/immutable/entry/app.DQs_wJeB.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.B5yg2sIq.js +0 -1
- package/build/client/_app/immutable/entry/start.B5yg2sIq.js.br +0 -2
- package/build/client/_app/immutable/entry/start.B5yg2sIq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.D2ng5LTp.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.D2ng5LTp.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DfNZyDBl.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DfNZyDBl.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.CFJZfOMs.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.CFJZfOMs.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.xLFJGflh.js +0 -1
- package/build/client/_app/immutable/nodes/5.xLFJGflh.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.xLFJGflh.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.CqeNzAMh.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.CqeNzAMh.js.gz +0 -0
package/dist/database.js
CHANGED
|
@@ -77,11 +77,12 @@ export function connect() {
|
|
|
77
77
|
return database;
|
|
78
78
|
}
|
|
79
79
|
// Helpers
|
|
80
|
-
export async function count(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.select(
|
|
84
|
-
|
|
80
|
+
export async function count(...tables) {
|
|
81
|
+
return await database
|
|
82
|
+
.selectFrom(tables)
|
|
83
|
+
.select(() => tables.map(t => database.fn.countAll(t).as(t)))
|
|
84
|
+
.$castTo()
|
|
85
|
+
.executeTakeFirstOrThrow();
|
|
85
86
|
}
|
|
86
87
|
/**
|
|
87
88
|
* Select the user with the id from the userId column of a table, placing it in the `user` property.
|
|
@@ -92,16 +93,9 @@ export function userFromId(eb) {
|
|
|
92
93
|
.$castTo()
|
|
93
94
|
.as('user');
|
|
94
95
|
}
|
|
95
|
-
export async function
|
|
96
|
-
return {
|
|
97
|
-
users: await count('users'),
|
|
98
|
-
passkeys: await count('passkeys'),
|
|
99
|
-
sessions: await count('sessions'),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
export async function statusText() {
|
|
96
|
+
export async function statText() {
|
|
103
97
|
try {
|
|
104
|
-
const stats = await
|
|
98
|
+
const stats = await count('users', 'passkeys', 'sessions');
|
|
105
99
|
return `${stats.users} users, ${stats.passkeys} passkeys, ${stats.sessions} sessions`;
|
|
106
100
|
}
|
|
107
101
|
catch (error) {
|
|
@@ -152,6 +146,13 @@ const throwUnlessRows = (text) => {
|
|
|
152
146
|
throw 'missing.';
|
|
153
147
|
return text;
|
|
154
148
|
};
|
|
149
|
+
export async function createIndex(table, column, mod) {
|
|
150
|
+
io.start(`Creating index for ${table}.${column}`);
|
|
151
|
+
let query = database.schema.createIndex(`${table}_${column}_index`).on(table).column(column);
|
|
152
|
+
if (mod)
|
|
153
|
+
query = mod(query);
|
|
154
|
+
await query.execute().then(io.done).catch(warnExists);
|
|
155
|
+
}
|
|
155
156
|
export async function init(opt) {
|
|
156
157
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
157
158
|
try {
|
|
@@ -195,7 +196,16 @@ export async function init(opt) {
|
|
|
195
196
|
})
|
|
196
197
|
.catch(io.warn);
|
|
197
198
|
await _sql('SELECT pg_reload_conf()', 'Reloading configuration');
|
|
199
|
+
io.start('Connecting to database');
|
|
198
200
|
const db = __addDisposableResource(env_1, connect(), true);
|
|
201
|
+
io.done();
|
|
202
|
+
function maybeCheck(table) {
|
|
203
|
+
return (e) => {
|
|
204
|
+
warnExists(e);
|
|
205
|
+
if (opt.check)
|
|
206
|
+
return checkTableTypes(table, expectedTypes[table], opt);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
199
209
|
io.start('Creating table users');
|
|
200
210
|
await db.schema
|
|
201
211
|
.createTable('users')
|
|
@@ -211,7 +221,7 @@ export async function init(opt) {
|
|
|
211
221
|
.addColumn('registeredAt', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
|
|
212
222
|
.execute()
|
|
213
223
|
.then(io.done)
|
|
214
|
-
.catch(
|
|
224
|
+
.catch(maybeCheck('users'));
|
|
215
225
|
io.start('Creating table sessions');
|
|
216
226
|
await db.schema
|
|
217
227
|
.createTable('sessions')
|
|
@@ -223,9 +233,8 @@ export async function init(opt) {
|
|
|
223
233
|
.addColumn('elevated', 'boolean', col => col.notNull())
|
|
224
234
|
.execute()
|
|
225
235
|
.then(io.done)
|
|
226
|
-
.catch(
|
|
227
|
-
|
|
228
|
-
await db.schema.createIndex('sessions_userId_index').on('sessions').column('userId').execute().then(io.done).catch(warnExists);
|
|
236
|
+
.catch(maybeCheck('sessions'));
|
|
237
|
+
await createIndex('sessions', 'id');
|
|
229
238
|
io.start('Creating table verifications');
|
|
230
239
|
await db.schema
|
|
231
240
|
.createTable('verifications')
|
|
@@ -235,14 +244,14 @@ export async function init(opt) {
|
|
|
235
244
|
.addColumn('role', 'text', col => col.notNull())
|
|
236
245
|
.execute()
|
|
237
246
|
.then(io.done)
|
|
238
|
-
.catch(
|
|
247
|
+
.catch(maybeCheck('verifications'));
|
|
239
248
|
io.start('Creating table passkeys');
|
|
240
249
|
await db.schema
|
|
241
250
|
.createTable('passkeys')
|
|
242
251
|
.addColumn('id', 'text', col => col.primaryKey().notNull())
|
|
243
252
|
.addColumn('name', 'text')
|
|
244
253
|
.addColumn('createdAt', 'timestamptz', col => col.notNull().defaultTo(sql `now()`))
|
|
245
|
-
.addColumn('userId', 'uuid', col => col.notNull().references('users.id').onDelete('cascade').
|
|
254
|
+
.addColumn('userId', 'uuid', col => col.notNull().references('users.id').onDelete('cascade').notNull())
|
|
246
255
|
.addColumn('publicKey', 'bytea', col => col.notNull())
|
|
247
256
|
.addColumn('counter', 'integer', col => col.notNull())
|
|
248
257
|
.addColumn('deviceType', 'text', col => col.notNull())
|
|
@@ -250,14 +259,15 @@ export async function init(opt) {
|
|
|
250
259
|
.addColumn('transports', sql `text[]`)
|
|
251
260
|
.execute()
|
|
252
261
|
.then(io.done)
|
|
253
|
-
.catch(
|
|
254
|
-
|
|
255
|
-
|
|
262
|
+
.catch(maybeCheck('passkeys'));
|
|
263
|
+
await createIndex('passkeys', 'userId');
|
|
264
|
+
io.start('Creating schema acl');
|
|
265
|
+
await db.schema.createSchema('acl').execute().then(io.done).catch(warnExists);
|
|
256
266
|
for (const plugin of plugins) {
|
|
257
267
|
if (!plugin.hooks.db_init)
|
|
258
268
|
continue;
|
|
259
269
|
io.plugin(plugin.name);
|
|
260
|
-
await plugin.hooks.db_init(opt
|
|
270
|
+
await plugin.hooks.db_init(opt);
|
|
261
271
|
}
|
|
262
272
|
}
|
|
263
273
|
catch (e_1) {
|
|
@@ -270,6 +280,90 @@ export async function init(opt) {
|
|
|
270
280
|
await result_1;
|
|
271
281
|
}
|
|
272
282
|
}
|
|
283
|
+
export const expectedTypes = {
|
|
284
|
+
users: {
|
|
285
|
+
email: { type: 'text', required: true },
|
|
286
|
+
emailVerified: { type: 'timestamptz' },
|
|
287
|
+
id: { type: 'uuid', required: true, hasDefault: true },
|
|
288
|
+
image: { type: 'text' },
|
|
289
|
+
isAdmin: { type: 'bool', required: true, hasDefault: true },
|
|
290
|
+
name: { type: 'text' },
|
|
291
|
+
preferences: { type: 'jsonb', required: true, hasDefault: true },
|
|
292
|
+
registeredAt: { type: 'timestamptz', required: true, hasDefault: true },
|
|
293
|
+
roles: { type: '_text', required: true, hasDefault: true },
|
|
294
|
+
tags: { type: '_text', required: true, hasDefault: true },
|
|
295
|
+
},
|
|
296
|
+
verifications: {
|
|
297
|
+
userId: { type: 'uuid', required: true },
|
|
298
|
+
token: { type: 'text', required: true },
|
|
299
|
+
expires: { type: 'timestamptz', required: true },
|
|
300
|
+
role: { type: 'text', required: true },
|
|
301
|
+
},
|
|
302
|
+
passkeys: {
|
|
303
|
+
id: { type: 'text', required: true },
|
|
304
|
+
name: { type: 'text' },
|
|
305
|
+
createdAt: { type: 'timestamptz', required: true, hasDefault: true },
|
|
306
|
+
userId: { type: 'uuid', required: true },
|
|
307
|
+
publicKey: { type: 'bytea', required: true },
|
|
308
|
+
counter: { type: 'int4', required: true },
|
|
309
|
+
deviceType: { type: 'text', required: true },
|
|
310
|
+
backedUp: { type: 'bool', required: true },
|
|
311
|
+
transports: { type: '_text' },
|
|
312
|
+
},
|
|
313
|
+
sessions: {
|
|
314
|
+
id: { type: 'uuid', required: true, hasDefault: true },
|
|
315
|
+
userId: { type: 'uuid', required: true },
|
|
316
|
+
created: { type: 'timestamptz', required: true },
|
|
317
|
+
token: { type: 'text', required: true },
|
|
318
|
+
expires: { type: 'timestamptz', required: true },
|
|
319
|
+
elevated: { type: 'bool', required: true },
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* Checks that a table has the expected column types, nullability, and default values.
|
|
324
|
+
*/
|
|
325
|
+
export async function checkTableTypes(tableName, types, opt) {
|
|
326
|
+
io.start(`Checking for table ${tableName}`);
|
|
327
|
+
const dbTables = opt._metadata || (await database.introspection.getTables());
|
|
328
|
+
const table = dbTables.find(t => t.name === tableName);
|
|
329
|
+
if (!table)
|
|
330
|
+
throw 'missing.';
|
|
331
|
+
io.done();
|
|
332
|
+
const columns = Object.fromEntries(table.columns.map(c => [c.name, c]));
|
|
333
|
+
for (const [key, { type, required = false, hasDefault = false }] of Object.entries(types)) {
|
|
334
|
+
io.start(`Checking column ${tableName}.${key}`);
|
|
335
|
+
const col = columns[key];
|
|
336
|
+
if (!col)
|
|
337
|
+
throw 'missing.';
|
|
338
|
+
try {
|
|
339
|
+
if (col.dataType != type)
|
|
340
|
+
throw `incorrect type "${col.dataType}", expected ${type}`;
|
|
341
|
+
if (col.isNullable != !required)
|
|
342
|
+
throw required ? 'nullable' : 'not nullable';
|
|
343
|
+
if (col.hasDefaultValue != hasDefault)
|
|
344
|
+
throw hasDefault ? 'missing default' : 'has default';
|
|
345
|
+
io.done();
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
if (opt.strict)
|
|
349
|
+
throw e;
|
|
350
|
+
io.warn(e);
|
|
351
|
+
}
|
|
352
|
+
delete columns[key];
|
|
353
|
+
}
|
|
354
|
+
if (!opt.extra)
|
|
355
|
+
return;
|
|
356
|
+
io.start('Checking for extra columns in ' + tableName);
|
|
357
|
+
const unchecked = Object.keys(columns)
|
|
358
|
+
.map(c => `${tableName}.${c}`)
|
|
359
|
+
.join(', ');
|
|
360
|
+
if (!unchecked.length)
|
|
361
|
+
io.done();
|
|
362
|
+
else if (opt.strict)
|
|
363
|
+
throw unchecked;
|
|
364
|
+
else
|
|
365
|
+
io.warn(unchecked);
|
|
366
|
+
}
|
|
273
367
|
export async function check(opt) {
|
|
274
368
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
275
369
|
try {
|
|
@@ -280,18 +374,22 @@ export async function check(opt) {
|
|
|
280
374
|
io.start('Connecting to database');
|
|
281
375
|
const db = __addDisposableResource(env_2, connect(), true);
|
|
282
376
|
io.done();
|
|
283
|
-
io.start('
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
377
|
+
io.start('Getting table metadata');
|
|
378
|
+
opt._metadata = await db.introspection.getTables();
|
|
379
|
+
const tables = Object.fromEntries(opt._metadata.map(t => [t.name, t]));
|
|
380
|
+
io.done();
|
|
381
|
+
for (const table of Object.keys(expectedTypes)) {
|
|
382
|
+
await checkTableTypes(table, expectedTypes[table], opt);
|
|
383
|
+
delete tables[table];
|
|
384
|
+
}
|
|
385
|
+
io.start('Checking for extra tables');
|
|
386
|
+
const unchecked = Object.keys(tables).join(', ');
|
|
387
|
+
if (!unchecked.length)
|
|
388
|
+
io.done();
|
|
389
|
+
else if (opt.strict)
|
|
390
|
+
throw unchecked;
|
|
391
|
+
else
|
|
392
|
+
io.warn(unchecked);
|
|
295
393
|
}
|
|
296
394
|
catch (e_2) {
|
|
297
395
|
env_2.error = e_2;
|
|
@@ -314,7 +412,7 @@ export async function clean(opt) {
|
|
|
314
412
|
if (!plugin.hooks.clean)
|
|
315
413
|
continue;
|
|
316
414
|
io.plugin(plugin.name);
|
|
317
|
-
await plugin.hooks.clean(opt
|
|
415
|
+
await plugin.hooks.clean(opt);
|
|
318
416
|
}
|
|
319
417
|
}
|
|
320
418
|
/**
|
|
@@ -323,12 +421,12 @@ export async function clean(opt) {
|
|
|
323
421
|
export async function uninstall(opt) {
|
|
324
422
|
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
325
423
|
try {
|
|
326
|
-
const
|
|
424
|
+
const _ = __addDisposableResource(env_3, connect(), true);
|
|
327
425
|
for (const plugin of plugins) {
|
|
328
426
|
if (!plugin.hooks.remove)
|
|
329
427
|
continue;
|
|
330
428
|
io.plugin(plugin.name);
|
|
331
|
-
await plugin.hooks.remove(opt
|
|
429
|
+
await plugin.hooks.remove(opt);
|
|
332
430
|
}
|
|
333
431
|
await _sql('DROP DATABASE axium', 'Dropping database');
|
|
334
432
|
await _sql('REVOKE ALL PRIVILEGES ON SCHEMA public FROM axium', 'Revoking schema privileges');
|
|
@@ -365,13 +463,20 @@ export async function wipe(opt) {
|
|
|
365
463
|
if (!plugin.hooks.db_wipe)
|
|
366
464
|
continue;
|
|
367
465
|
io.plugin(plugin.name);
|
|
368
|
-
await plugin.hooks.db_wipe(opt
|
|
466
|
+
await plugin.hooks.db_wipe(opt);
|
|
369
467
|
}
|
|
370
468
|
for (const table of ['users', 'passkeys', 'sessions', 'verifications']) {
|
|
371
|
-
io.start(`
|
|
469
|
+
io.start(`Wiping ${table}`);
|
|
372
470
|
await db.deleteFrom(table).execute();
|
|
373
471
|
io.done();
|
|
374
472
|
}
|
|
473
|
+
for (const table of await database.introspection.getTables()) {
|
|
474
|
+
if (!table.name.startsWith('acl.'))
|
|
475
|
+
continue;
|
|
476
|
+
const name = table.name;
|
|
477
|
+
io.debug(`Wiping ${name}`);
|
|
478
|
+
await db.deleteFrom(name).execute();
|
|
479
|
+
}
|
|
375
480
|
}
|
|
376
481
|
export async function rotatePassword() {
|
|
377
482
|
io.start('Generating new password');
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
-
import type {
|
|
2
|
+
import type { InitOptions, OpOptions } from './database.js';
|
|
3
3
|
export declare const PluginMetadata: z.ZodObject<{
|
|
4
4
|
name: z.ZodString;
|
|
5
5
|
version: z.ZodString;
|
|
@@ -21,12 +21,12 @@ interface PluginInternal extends Plugin {
|
|
|
21
21
|
hooks: Hooks;
|
|
22
22
|
}
|
|
23
23
|
export interface Hooks {
|
|
24
|
-
db_init?: (opt: InitOptions
|
|
24
|
+
db_init?: (opt: InitOptions) => void | Promise<void>;
|
|
25
25
|
remove?: (opt: {
|
|
26
26
|
force?: boolean;
|
|
27
|
-
}
|
|
28
|
-
db_wipe?: (opt: OpOptions
|
|
29
|
-
clean?: (opt: Partial<OpOptions
|
|
27
|
+
}) => void | Promise<void>;
|
|
28
|
+
db_wipe?: (opt: OpOptions) => void | Promise<void>;
|
|
29
|
+
clean?: (opt: Partial<OpOptions>) => void | Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
export declare const plugins: Set<PluginInternal>;
|
|
32
32
|
export declare function resolvePlugin(search: string): PluginInternal | undefined;
|
package/dist/routes.d.ts
CHANGED
|
@@ -42,6 +42,9 @@ export type Route = ServerRoute | WebRoute;
|
|
|
42
42
|
* @internal
|
|
43
43
|
*/
|
|
44
44
|
export declare const routes: Map<string, Route>;
|
|
45
|
+
/**
|
|
46
|
+
* @category Plugin API
|
|
47
|
+
*/
|
|
45
48
|
export declare function addRoute(opt: RouteOptions): void;
|
|
46
49
|
/**
|
|
47
50
|
* Resolve a request URL into a route.
|
package/dist/routes.js
CHANGED
|
@@ -6,6 +6,9 @@ import { _unique } from './state.js';
|
|
|
6
6
|
* @internal
|
|
7
7
|
*/
|
|
8
8
|
export const routes = _unique('routes', new Map());
|
|
9
|
+
/**
|
|
10
|
+
* @category Plugin API
|
|
11
|
+
*/
|
|
9
12
|
export function addRoute(opt) {
|
|
10
13
|
const route = { ...opt, server: !('page' in opt) };
|
|
11
14
|
if (!route.path.startsWith('/')) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import UserCard from './UserCard.svelte';
|
|
3
|
+
import type { Permission, AccessControl } from '@axium/core/access';
|
|
4
|
+
import { permissionNames } from '@axium/core/access';
|
|
5
|
+
import type { Entries } from 'utilium';
|
|
6
|
+
|
|
7
|
+
const { control, editable }: { control: AccessControl; editable: boolean } = $props();
|
|
8
|
+
|
|
9
|
+
const perm = $derived(permissionNames[control.permission as Permission]);
|
|
10
|
+
|
|
11
|
+
const permEntries = Object.entries(permissionNames) as any as Entries<typeof permissionNames>;
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div class="AccessControl">
|
|
15
|
+
{#if !control.user}<i>Unknown</i>
|
|
16
|
+
{:else}
|
|
17
|
+
<UserCard user={control.user} />
|
|
18
|
+
{#if editable}
|
|
19
|
+
<input type="hidden" name="userId" value={control.user.id} />
|
|
20
|
+
<select name="permission">
|
|
21
|
+
{#each permEntries as [key, name]}
|
|
22
|
+
<option value={key} selected={key == control.permission}>{name}</option>
|
|
23
|
+
{/each}
|
|
24
|
+
</select>
|
|
25
|
+
{:else}
|
|
26
|
+
<span>{perm}</span>
|
|
27
|
+
{/if}
|
|
28
|
+
{/if}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.AccessControl {
|
|
33
|
+
display: flex;
|
|
34
|
+
gap: 1em;
|
|
35
|
+
padding: 1em 2em;
|
|
36
|
+
}
|
|
37
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import FormDialog from './FormDialog.svelte';
|
|
3
|
+
import AccessControl from './AccessControl.svelte';
|
|
4
|
+
|
|
5
|
+
let { item, editable } = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<FormDialog submitText="Save">
|
|
9
|
+
{#each item.acl as control}
|
|
10
|
+
<AccessControl {control} {editable} />
|
|
11
|
+
{/each}
|
|
12
|
+
</FormDialog>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|