@axium/core 0.9.0 → 0.11.0

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/dist/access.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as z from 'zod';
1
2
  import type { User } from './user.js';
2
3
  export interface AccessControl {
3
4
  itemId: string;
@@ -6,13 +7,27 @@ export interface AccessControl {
6
7
  createdAt: Date;
7
8
  permission: Permission;
8
9
  }
9
- export declare enum Permission {
10
- None = 0,
11
- Read = 1,
12
- Comment = 2,
13
- Edit = 3,
14
- Manage = 5
15
- }
10
+ declare const _Permission: {
11
+ readonly None: 0;
12
+ readonly Read: 1;
13
+ readonly Comment: 2;
14
+ readonly Edit: 3;
15
+ readonly Manage: 5;
16
+ };
17
+ export declare const Permission: z.ZodEnum<{
18
+ readonly None: 0;
19
+ readonly Read: 1;
20
+ readonly Comment: 2;
21
+ readonly Edit: 3;
22
+ readonly Manage: 5;
23
+ }> & {
24
+ readonly None: 0;
25
+ readonly Read: 1;
26
+ readonly Comment: 2;
27
+ readonly Edit: 3;
28
+ readonly Manage: 5;
29
+ };
30
+ export type Permission = (typeof _Permission)[keyof typeof _Permission];
16
31
  export declare const permissionNames: {
17
32
  0: string;
18
33
  1: string;
@@ -25,4 +40,20 @@ export interface AccessControllable {
25
40
  publicPermission: Permission;
26
41
  acl?: AccessControl[];
27
42
  }
43
+ export declare const AccessMap: z.ZodRecord<z.ZodUnion<readonly [z.ZodUUID, z.ZodLiteral<"public">]>, z.ZodEnum<{
44
+ readonly None: 0;
45
+ readonly Read: 1;
46
+ readonly Comment: 2;
47
+ readonly Edit: 3;
48
+ readonly Manage: 5;
49
+ }> & {
50
+ readonly None: 0;
51
+ readonly Read: 1;
52
+ readonly Comment: 2;
53
+ readonly Edit: 3;
54
+ readonly Manage: 5;
55
+ }>;
56
+ export interface AccessMap extends z.infer<typeof AccessMap> {
57
+ }
28
58
  export declare function hasPermission(item: AccessControllable, userId: string | undefined, permission: Permission): boolean;
59
+ export {};
package/dist/access.js CHANGED
@@ -1,11 +1,12 @@
1
- export var Permission;
2
- (function (Permission) {
3
- Permission[Permission["None"] = 0] = "None";
4
- Permission[Permission["Read"] = 1] = "Read";
5
- Permission[Permission["Comment"] = 2] = "Comment";
6
- Permission[Permission["Edit"] = 3] = "Edit";
7
- Permission[Permission["Manage"] = 5] = "Manage";
8
- })(Permission || (Permission = {}));
1
+ import * as z from 'zod';
2
+ const _Permission = {
3
+ None: 0,
4
+ Read: 1,
5
+ Comment: 2,
6
+ Edit: 3,
7
+ Manage: 5,
8
+ };
9
+ export const Permission = Object.assign(z.enum(_Permission), _Permission);
9
10
  export const permissionNames = {
10
11
  [Permission.None]: 'No Permissions',
11
12
  [Permission.Read]: 'Reader',
@@ -13,6 +14,7 @@ export const permissionNames = {
13
14
  [Permission.Edit]: 'Editor',
14
15
  [Permission.Manage]: 'Manager',
15
16
  };
17
+ export const AccessMap = z.record(z.union([z.uuid(), z.literal('public')]), Permission);
16
18
  export function hasPermission(item, userId, permission) {
17
19
  if (item.publicPermission >= permission)
18
20
  return true;
package/dist/api.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types';
2
2
  import type z from 'zod';
3
- import type { AccessControl } from './access.js';
3
+ import type { AccessControl, AccessMap } from './access.js';
4
4
  import type { App } from './apps.js';
5
5
  import type { AuditEvent, AuditFilter, Severity } from './audit.js';
6
6
  import type { NewSessionResponse, Session, Verification } from './auth.js';
@@ -94,10 +94,8 @@ export interface $API {
94
94
  }];
95
95
  };
96
96
  'acl/:itemType/:itemId': {
97
- PUT: [{
98
- userId: string;
99
- permission: number;
100
- }, AccessControl];
97
+ GET: AccessControl[];
98
+ POST: [AccessMap, AccessControl[]];
101
99
  };
102
100
  'admin/summary': {
103
101
  GET: AdminSummary;
package/dist/io.d.ts CHANGED
@@ -15,7 +15,7 @@ export interface ProgressIO {
15
15
  progress(value: number, max: number, message?: any): void;
16
16
  done(): void;
17
17
  }
18
- export declare function useProgressIO(io: ProgressIO): void;
18
+ export declare function useProgress(io: ProgressIO): void;
19
19
  export declare let debug: (...args: any[]) => void;
20
20
  export declare let log: (...args: any[]) => void;
21
21
  export declare let info: (...args: any[]) => void;
package/dist/io.js CHANGED
@@ -18,7 +18,7 @@ export function _setDebugOutput(enabled) {
18
18
  export let start;
19
19
  export let progress;
20
20
  export let done;
21
- export function useProgressIO(io) {
21
+ export function useProgress(io) {
22
22
  start = io.start.bind(io);
23
23
  progress = io.progress.bind(io);
24
24
  done = io.done.bind(io);
package/dist/node/io.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as z from 'zod';
1
2
  export * from '../io.js';
2
3
  export declare function setCommandTimeout(value: number): void;
3
4
  /**
@@ -7,5 +8,10 @@ export declare function setCommandTimeout(value: number): void;
7
8
  export declare function run(message: string, command: string): Promise<string>;
8
9
  /** Yet another convenience function */
9
10
  export declare function exit(message: string | Error, code?: number): never;
10
- export declare function handleError(e: number | string | Error): void;
11
+ export declare function handleError(e: number | string | Error): never;
12
+ /**
13
+ *
14
+ * @param defaultValue Returned when the file can't be loaded. If omitted, loading errors will be thrown.
15
+ */
16
+ export declare function readJSON<S extends z.ZodType>(path: string, schema: S): z.infer<S>;
11
17
  export declare function writeJSON(path: string, data: any): void;
package/dist/node/io.js CHANGED
@@ -1,37 +1,174 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { exec } from 'node:child_process';
2
- import { writeFileSync } from 'node:fs';
54
+ import { writeFileSync, readFileSync } from 'node:fs';
3
55
  import { styleText } from 'node:util';
4
- import { _debugOutput, done, error, start, useOutput, useProgressIO } from '../io.js';
56
+ import * as io from '../io.js';
57
+ import * as z from 'zod';
5
58
  export * from '../io.js';
6
- useProgressIO({
59
+ let _currentOperation = null, _progress = null;
60
+ function handleProgress() {
61
+ if (!_currentOperation || !_progress)
62
+ return {
63
+ [Symbol.dispose]() {
64
+ if (!_progress)
65
+ _currentOperation = null;
66
+ },
67
+ };
68
+ process.stdout.clearLine(0);
69
+ process.stdout.cursorTo(0);
70
+ return {
71
+ [Symbol.dispose]() {
72
+ process.stdout.write(_currentOperation + '... ');
73
+ if (_progress)
74
+ io.progress(..._progress);
75
+ },
76
+ };
77
+ }
78
+ io.useProgress({
7
79
  start(message) {
8
- process.stdout.write(message + '... \x1b[s');
80
+ _currentOperation = message;
81
+ process.stdout.write(message + '... ');
9
82
  },
10
83
  /** @todo implement additional messaging */
11
84
  progress(value, max, message) {
12
- process.stdout.write(`\x1b[u\x1b[K${value.toString().padStart(max.toString().length)}/${max}`);
13
- if (value >= max)
85
+ _progress = [value, max];
86
+ value++;
87
+ process.stdout.clearLine(0);
88
+ process.stdout.cursorTo(0);
89
+ process.stdout.write(`${_currentOperation}... ${value.toString().padStart(max.toString().length)}/${max} ${message && value < max ? `(${message})` : ''}`);
90
+ if (value >= max) {
91
+ _currentOperation = null;
14
92
  console.log();
93
+ }
15
94
  },
16
95
  done() {
96
+ _currentOperation = null;
17
97
  console.log('done.');
18
98
  },
19
99
  });
20
- useOutput({
100
+ io.useOutput({
21
101
  error(message) {
22
- console.error(message.startsWith('\x1b') ? message : styleText('red', message));
102
+ const env_1 = { stack: [], error: void 0, hasError: false };
103
+ try {
104
+ const _ = __addDisposableResource(env_1, handleProgress(), false);
105
+ console.error(message.startsWith('\x1b') ? message : styleText('red', message));
106
+ }
107
+ catch (e_1) {
108
+ env_1.error = e_1;
109
+ env_1.hasError = true;
110
+ }
111
+ finally {
112
+ __disposeResources(env_1);
113
+ }
23
114
  },
24
115
  warn(message) {
25
- console.warn(message.startsWith('\x1b') ? message : styleText('yellow', message));
116
+ const env_2 = { stack: [], error: void 0, hasError: false };
117
+ try {
118
+ const _ = __addDisposableResource(env_2, handleProgress(), false);
119
+ console.warn(message.startsWith('\x1b') ? message : styleText('yellow', message));
120
+ }
121
+ catch (e_2) {
122
+ env_2.error = e_2;
123
+ env_2.hasError = true;
124
+ }
125
+ finally {
126
+ __disposeResources(env_2);
127
+ }
26
128
  },
27
129
  info(message) {
28
- console.info(message.startsWith('\x1b') ? message : styleText('blue', message));
130
+ const env_3 = { stack: [], error: void 0, hasError: false };
131
+ try {
132
+ const _ = __addDisposableResource(env_3, handleProgress(), false);
133
+ console.info(message.startsWith('\x1b') ? message : styleText('blue', message));
134
+ }
135
+ catch (e_3) {
136
+ env_3.error = e_3;
137
+ env_3.hasError = true;
138
+ }
139
+ finally {
140
+ __disposeResources(env_3);
141
+ }
29
142
  },
30
143
  log(message) {
31
- console.log(message);
144
+ const env_4 = { stack: [], error: void 0, hasError: false };
145
+ try {
146
+ const _ = __addDisposableResource(env_4, handleProgress(), false);
147
+ console.log(message);
148
+ }
149
+ catch (e_4) {
150
+ env_4.error = e_4;
151
+ env_4.hasError = true;
152
+ }
153
+ finally {
154
+ __disposeResources(env_4);
155
+ }
32
156
  },
33
157
  debug(message) {
34
- _debugOutput && console.debug(message.startsWith('\x1b') ? message : styleText('gray', message));
158
+ const env_5 = { stack: [], error: void 0, hasError: false };
159
+ try {
160
+ if (!io._debugOutput)
161
+ return;
162
+ const _ = __addDisposableResource(env_5, handleProgress(), false);
163
+ console.debug(message.startsWith('\x1b') ? message : styleText('gray', message));
164
+ }
165
+ catch (e_5) {
166
+ env_5.error = e_5;
167
+ env_5.hasError = true;
168
+ }
169
+ finally {
170
+ __disposeResources(env_5);
171
+ }
35
172
  },
36
173
  });
37
174
  let timeout = 1000;
@@ -45,7 +182,7 @@ export function setCommandTimeout(value) {
45
182
  export async function run(message, command) {
46
183
  let stderr;
47
184
  try {
48
- start(message);
185
+ io.start(message);
49
186
  const { promise, resolve, reject } = Promise.withResolvers();
50
187
  exec(command, { timeout }, (err, stdout, _stderr) => {
51
188
  stderr = _stderr.startsWith('ERROR:') ? _stderr.slice(6).trim() : _stderr;
@@ -55,7 +192,7 @@ export async function run(message, command) {
55
192
  resolve(stdout);
56
193
  });
57
194
  const value = await promise;
58
- done();
195
+ io.done();
59
196
  return value;
60
197
  }
61
198
  catch (error) {
@@ -70,7 +207,7 @@ export async function run(message, command) {
70
207
  export function exit(message, code = 1) {
71
208
  if (message instanceof Error)
72
209
  message = message.message;
73
- error(message);
210
+ io.error(message);
74
211
  process.exit(code);
75
212
  }
76
213
  export function handleError(e) {
@@ -79,6 +216,19 @@ export function handleError(e) {
79
216
  else
80
217
  exit(e);
81
218
  }
219
+ /**
220
+ *
221
+ * @param defaultValue Returned when the file can't be loaded. If omitted, loading errors will be thrown.
222
+ */
223
+ export function readJSON(path, schema) {
224
+ try {
225
+ const data = JSON.parse(readFileSync(path, 'utf-8'));
226
+ return schema.parse(data);
227
+ }
228
+ catch (e) {
229
+ throw e instanceof z.core.$ZodError ? z.prettifyError(e) : e instanceof Error ? e.message : e;
230
+ }
231
+ }
82
232
  export function writeJSON(path, data) {
83
233
  writeFileSync(path, JSON.stringify(data, null, 4).replaceAll(/^( {4})+/g, match => '\t'.repeat(match.length / 4)), 'utf-8');
84
234
  }
@@ -20,8 +20,14 @@ export function* pluginText(plugin) {
20
20
  }
21
21
  }
22
22
  function _locatePlugin(specifier, _loadedBy) {
23
- if (specifier[0] == '/' || specifier.startsWith('./') || specifier.startsWith('../')) {
24
- return resolve(dirname(_loadedBy), specifier);
23
+ if (specifier[0] == '/' || ['.', '..'].includes(specifier.split('/')[0])) {
24
+ const path = resolve(dirname(_loadedBy), specifier);
25
+ const stats = fs.statSync(path);
26
+ if (stats.isFile())
27
+ return path;
28
+ if (!stats.isDirectory())
29
+ throw new Error('Can not resolve plugin path: ' + path);
30
+ return join(path, 'package.json');
25
31
  }
26
32
  let packageDir = dirname(fileURLToPath(import.meta.resolve(specifier)));
27
33
  for (; !fs.existsSync(join(packageDir, 'package.json')); packageDir = dirname(packageDir))
@@ -31,6 +37,7 @@ function _locatePlugin(specifier, _loadedBy) {
31
37
  export async function loadPlugin(mode, specifier, _loadedBy, safeMode = false) {
32
38
  try {
33
39
  const path = _locatePlugin(specifier, _loadedBy);
40
+ io.debug(`Loading plugin at ${path} (from ${_loadedBy})`);
34
41
  let imported;
35
42
  try {
36
43
  imported = JSON.parse(fs.readFileSync(path, 'utf8'));
package/dist/user.d.ts CHANGED
@@ -20,8 +20,18 @@ export interface UserInternal extends User {
20
20
  tags: string[];
21
21
  }
22
22
  export declare const userPublicFields: ["id", "image", "name", "registeredAt", "roles"];
23
- type UserPublicField = (typeof userPublicFields)[number];
24
- export interface UserPublic extends Pick<User, UserPublicField> {
23
+ export declare const UserPublic: z.ZodObject<{
24
+ id: z.ZodUUID;
25
+ name: z.ZodString;
26
+ email: z.ZodOptional<z.ZodEmail>;
27
+ emailVerified: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodDate>>>;
28
+ image: z.ZodOptional<z.ZodNullable<z.ZodURL>>;
29
+ preferences: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
30
+ roles: z.ZodArray<z.ZodString>;
31
+ registeredAt: z.ZodCoercedDate<unknown>;
32
+ isAdmin: z.ZodOptional<z.ZodBoolean>;
33
+ }, z.core.$strip>;
34
+ export interface UserPublic extends z.infer<typeof UserPublic> {
25
35
  }
26
36
  export declare const userProtectedFields: ["email", "emailVerified", "preferences", "isAdmin"];
27
37
  export declare const UserChangeable: z.ZodObject<{
@@ -70,4 +80,3 @@ export declare const LogoutSessions: z.ZodObject<{
70
80
  id: z.ZodOptional<z.ZodArray<z.ZodUUID>>;
71
81
  confirm_all: z.ZodOptional<z.ZodBoolean>;
72
82
  }, z.core.$strip>;
73
- export {};
package/dist/user.js CHANGED
@@ -13,6 +13,9 @@ export const User = z.object({
13
13
  isAdmin: z.boolean(),
14
14
  });
15
15
  export const userPublicFields = ['id', 'image', 'name', 'registeredAt', 'roles'];
16
+ export const UserPublic = User.partial(Object.fromEntries(Object.keys(User.shape)
17
+ .filter((key) => !userPublicFields.includes(key))
18
+ .map(key => [key, true])));
16
19
  export const userProtectedFields = ['email', 'emailVerified', 'preferences', 'isAdmin'];
17
20
  export const UserChangeable = User.pick({
18
21
  name: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/core",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "funding": {
6
6
  "type": "individual",