@axium/core 0.11.0 → 0.12.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/dist/access.d.ts CHANGED
@@ -2,58 +2,16 @@ import * as z from 'zod';
2
2
  import type { User } from './user.js';
3
3
  export interface AccessControl {
4
4
  itemId: string;
5
- userId: string;
5
+ userId?: string | null;
6
+ role?: string | null;
6
7
  user?: User;
7
8
  createdAt: Date;
8
- permission: Permission;
9
9
  }
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];
31
- export declare const permissionNames: {
32
- 0: string;
33
- 1: string;
34
- 2: string;
35
- 3: string;
36
- 5: string;
37
- };
10
+ export declare function pickPermissions<T extends AccessControl & object>(ac: T): Omit<T, 'itemId' | 'userId' | 'role' | 'user' | 'createdAt'>;
38
11
  export interface AccessControllable {
39
12
  userId: string;
40
- publicPermission: Permission;
41
13
  acl?: AccessControl[];
42
14
  }
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
- }>;
15
+ export declare const AccessMap: z.ZodRecord<z.ZodUnion<readonly [z.ZodUUID, z.ZodTemplateLiteral<`@${string}`>, z.ZodTemplateLiteral<`#${string}`>, z.ZodLiteral<"public">]>, z.ZodAny>;
56
16
  export interface AccessMap extends z.infer<typeof AccessMap> {
57
17
  }
58
- export declare function hasPermission(item: AccessControllable, userId: string | undefined, permission: Permission): boolean;
59
- export {};
package/dist/access.js CHANGED
@@ -1,29 +1,6 @@
1
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);
10
- export const permissionNames = {
11
- [Permission.None]: 'No Permissions',
12
- [Permission.Read]: 'Reader',
13
- [Permission.Comment]: 'Commenter',
14
- [Permission.Edit]: 'Editor',
15
- [Permission.Manage]: 'Manager',
16
- };
17
- export const AccessMap = z.record(z.union([z.uuid(), z.literal('public')]), Permission);
18
- export function hasPermission(item, userId, permission) {
19
- if (item.publicPermission >= permission)
20
- return true;
21
- if (!userId)
22
- return false;
23
- if (item.userId == userId)
24
- return true;
25
- const entry = item.acl?.find(entry => entry.userId == userId);
26
- if (!entry)
27
- return false;
28
- return entry.permission >= permission;
2
+ import { omit } from 'utilium';
3
+ export function pickPermissions(ac) {
4
+ return omit(ac, ['itemId', 'userId', 'role', 'user', 'createdAt']);
29
5
  }
6
+ export const AccessMap = z.record(z.union([z.uuid(), z.templateLiteral(['@', z.string()]), z.templateLiteral(['#', z.string()]), z.literal('public')]), z.any());
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@ export * from './api.js';
3
3
  export * from './apps.js';
4
4
  export * from './audit.js';
5
5
  export * from './auth.js';
6
+ export * from './format.js';
6
7
  export * as icons from './icons.js';
8
+ export * from './parse.js';
7
9
  export * from './passkeys.js';
8
10
  export * from './plugins.js';
9
11
  export * from './preferences.js';
package/dist/index.js CHANGED
@@ -3,7 +3,9 @@ export * from './api.js';
3
3
  export * from './apps.js';
4
4
  export * from './audit.js';
5
5
  export * from './auth.js';
6
+ export * from './format.js';
6
7
  export * as icons from './icons.js';
8
+ export * from './parse.js';
7
9
  export * from './passkeys.js';
8
10
  export * from './plugins.js';
9
11
  export * from './preferences.js';
package/dist/node/io.js CHANGED
@@ -89,20 +89,32 @@ io.useProgress({
89
89
  process.stdout.write(`${_currentOperation}... ${value.toString().padStart(max.toString().length)}/${max} ${message && value < max ? `(${message})` : ''}`);
90
90
  if (value >= max) {
91
91
  _currentOperation = null;
92
+ _progress = null;
92
93
  console.log();
93
94
  }
94
95
  },
95
96
  done() {
96
97
  _currentOperation = null;
98
+ _progress = null;
97
99
  console.log('done.');
98
100
  },
99
101
  });
102
+ function* maybeStyle(style, parts) {
103
+ for (const part of parts) {
104
+ if (typeof part != 'string')
105
+ yield part;
106
+ else if (part.startsWith('\x1b'))
107
+ yield part;
108
+ else
109
+ yield styleText(style, part);
110
+ }
111
+ }
100
112
  io.useOutput({
101
- error(message) {
113
+ error(...message) {
102
114
  const env_1 = { stack: [], error: void 0, hasError: false };
103
115
  try {
104
116
  const _ = __addDisposableResource(env_1, handleProgress(), false);
105
- console.error(message.startsWith('\x1b') ? message : styleText('red', message));
117
+ console.error(...maybeStyle('red', message));
106
118
  }
107
119
  catch (e_1) {
108
120
  env_1.error = e_1;
@@ -112,11 +124,11 @@ io.useOutput({
112
124
  __disposeResources(env_1);
113
125
  }
114
126
  },
115
- warn(message) {
127
+ warn(...message) {
116
128
  const env_2 = { stack: [], error: void 0, hasError: false };
117
129
  try {
118
130
  const _ = __addDisposableResource(env_2, handleProgress(), false);
119
- console.warn(message.startsWith('\x1b') ? message : styleText('yellow', message));
131
+ console.warn(...maybeStyle('yellow', message));
120
132
  }
121
133
  catch (e_2) {
122
134
  env_2.error = e_2;
@@ -126,11 +138,11 @@ io.useOutput({
126
138
  __disposeResources(env_2);
127
139
  }
128
140
  },
129
- info(message) {
141
+ info(...message) {
130
142
  const env_3 = { stack: [], error: void 0, hasError: false };
131
143
  try {
132
144
  const _ = __addDisposableResource(env_3, handleProgress(), false);
133
- console.info(message.startsWith('\x1b') ? message : styleText('blue', message));
145
+ console.info(...maybeStyle('blue', message));
134
146
  }
135
147
  catch (e_3) {
136
148
  env_3.error = e_3;
@@ -140,11 +152,11 @@ io.useOutput({
140
152
  __disposeResources(env_3);
141
153
  }
142
154
  },
143
- log(message) {
155
+ log(...message) {
144
156
  const env_4 = { stack: [], error: void 0, hasError: false };
145
157
  try {
146
158
  const _ = __addDisposableResource(env_4, handleProgress(), false);
147
- console.log(message);
159
+ console.log(...message);
148
160
  }
149
161
  catch (e_4) {
150
162
  env_4.error = e_4;
@@ -154,13 +166,13 @@ io.useOutput({
154
166
  __disposeResources(env_4);
155
167
  }
156
168
  },
157
- debug(message) {
169
+ debug(...message) {
158
170
  const env_5 = { stack: [], error: void 0, hasError: false };
159
171
  try {
160
172
  if (!io._debugOutput)
161
173
  return;
162
174
  const _ = __addDisposableResource(env_5, handleProgress(), false);
163
- console.debug(message.startsWith('\x1b') ? message : styleText('gray', message));
175
+ console.debug(...maybeStyle('gray', message));
164
176
  }
165
177
  catch (e_5) {
166
178
  env_5.error = e_5;
@@ -1,3 +1,3 @@
1
1
  import { type PluginInternal } from '@axium/core/plugins';
2
2
  export declare function pluginText(plugin: PluginInternal): Generator<string>;
3
- export declare function loadPlugin<const T extends 'client' | 'server'>(mode: T, specifier: string, _loadedBy: string, safeMode?: boolean): Promise<void>;
3
+ export declare function loadPlugin<const T extends 'client' | 'server'>(mode: T, specifier: string, _loadedBy: string, safeMode?: boolean): Promise<PluginInternal | void>;
@@ -53,15 +53,20 @@ export async function loadPlugin(mode, specifier, _loadedBy, safeMode = false) {
53
53
  if (!plugin[mode])
54
54
  throw `Plugin does not support running ${mode}-side`;
55
55
  if (!safeMode) {
56
- if (plugin.cli)
57
- await import(resolve(plugin.dirname, plugin.cli));
56
+ if (plugin[mode].cli)
57
+ await import(resolve(plugin.dirname, plugin[mode].cli));
58
58
  if (mode == 'client') {
59
59
  if (plugin.client.hooks)
60
60
  Object.assign(plugin, { _client: await import(resolve(plugin.dirname, plugin.client.hooks)) });
61
61
  }
62
62
  if (mode == 'server') {
63
- if (plugin.server.hooks)
64
- Object.assign(plugin, { _hooks: await import(resolve(plugin.dirname, plugin.server.hooks)) });
63
+ const cfg = plugin.server;
64
+ if (cfg.hooks)
65
+ Object.assign(plugin, { _hooks: await import(resolve(plugin.dirname, cfg.hooks)) });
66
+ if (cfg.db) {
67
+ const dbSchema = await import(resolve(plugin.dirname, cfg.db), { with: { type: 'json' } });
68
+ Object.assign(plugin, { _db: dbSchema.default });
69
+ }
65
70
  }
66
71
  }
67
72
  Object.freeze(plugin);
@@ -77,6 +82,7 @@ export async function loadPlugin(mode, specifier, _loadedBy, safeMode = false) {
77
82
  }
78
83
  plugins.set(plugin.name, plugin);
79
84
  io.debug(`Loaded plugin: ${plugin.name} ${plugin.version}`);
85
+ return plugin;
80
86
  }
81
87
  catch (e) {
82
88
  io.warn(`Failed to load plugin from ${specifier}: ${e ? (e instanceof Error ? e.message : e.toString()) : e}`);
@@ -0,0 +1 @@
1
+ export declare function parseByteSize(input: string): number | null;
package/dist/parse.js ADDED
@@ -0,0 +1,19 @@
1
+ const byteSizePattern = /^(?<size>\d+(?:\.\d+)?)\s*(?<unit>\w*)$/i;
2
+ const units = ['', 'K', 'M', 'G', 'T', 'P', 'E'];
3
+ export function parseByteSize(input) {
4
+ const match = byteSizePattern.exec(input.trim());
5
+ if (!match)
6
+ return null;
7
+ const size = parseFloat(match.groups.size);
8
+ if (!Number.isFinite(size))
9
+ return null;
10
+ let unit = match.groups.unit.toUpperCase();
11
+ if (unit.at(-1) == 'B')
12
+ unit = unit.slice(0, -1);
13
+ if (unit.at(-1) == 'I')
14
+ unit = unit.slice(0, -1);
15
+ const unitIndex = units.indexOf(unit);
16
+ if (unitIndex === -1)
17
+ return null;
18
+ return Math.round(size * Math.pow(1024, unitIndex));
19
+ }
package/dist/plugins.d.ts CHANGED
@@ -12,26 +12,32 @@ export declare const Plugin: z.ZodObject<{
12
12
  client: z.ZodOptional<z.ZodObject<{
13
13
  cli: z.ZodOptional<z.ZodString>;
14
14
  hooks: z.ZodOptional<z.ZodString>;
15
+ integrations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
15
16
  }, z.core.$strip>>;
16
17
  server: z.ZodOptional<z.ZodObject<{
18
+ cli: z.ZodOptional<z.ZodString>;
17
19
  hooks: z.ZodOptional<z.ZodString>;
20
+ integrations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
18
21
  http_handler: z.ZodOptional<z.ZodString>;
19
22
  routes: z.ZodOptional<z.ZodString>;
20
- cli: z.ZodOptional<z.ZodString>;
23
+ db: z.ZodOptional<z.ZodString>;
21
24
  }, z.core.$strip>>;
22
25
  }, z.core.$loose>;
23
26
  export type Plugin = z.infer<typeof Plugin>;
24
- export interface PluginInternal extends Plugin {
25
- readonly path: string;
26
- readonly dirname: string;
27
- readonly specifier: string;
28
- readonly _loadedBy: string;
29
- readonly cli?: string;
27
+ export interface PluginInfo {
28
+ path: string;
29
+ dirname: string;
30
+ specifier: string;
31
+ _loadedBy: string;
32
+ cli?: string;
30
33
  /** @internal */
31
- readonly _hooks?: ServerHooks;
34
+ _hooks?: ServerHooks;
32
35
  /** @internal */
33
- readonly _client?: ClientHooks;
34
- readonly isServer: boolean;
36
+ _client?: ClientHooks;
37
+ isServer: boolean;
38
+ _db?: any;
39
+ }
40
+ export interface PluginInternal extends Plugin, Readonly<PluginInfo> {
35
41
  }
36
42
  export declare const plugins: Map<string, PluginInternal>;
37
43
  /**
@@ -40,9 +46,7 @@ export declare const plugins: Map<string, PluginInternal>;
40
46
  export declare function _findPlugin(search: string): PluginInternal;
41
47
  export declare const PluginServerHooks: z.ZodObject<{
42
48
  statusText: z.ZodOptional<z.ZodCustom<z.core.$InferInnerFunctionTypeAsync<z.ZodTuple<readonly [], null>, z.ZodString>, z.core.$InferInnerFunctionTypeAsync<z.ZodTuple<readonly [], null>, z.ZodString>>>;
43
- db_init: z.ZodOptional<z.ZodCustom<(...args: any[]) => any, (...args: any[]) => any>>;
44
49
  remove: z.ZodOptional<z.ZodCustom<(...args: any[]) => any, (...args: any[]) => any>>;
45
- db_wipe: z.ZodOptional<z.ZodCustom<(...args: any[]) => any, (...args: any[]) => any>>;
46
50
  clean: z.ZodOptional<z.ZodCustom<(...args: any[]) => any, (...args: any[]) => any>>;
47
51
  }, z.core.$strip>;
48
52
  interface _InitOptions {
@@ -52,16 +56,13 @@ interface _InitOptions {
52
56
  }
53
57
  export interface ServerHooks {
54
58
  statusText?(): string | Promise<string>;
55
- db_init?: (opt: _InitOptions) => void | Promise<void>;
56
59
  remove?: (opt: {
57
60
  force?: boolean;
58
61
  }) => void | Promise<void>;
59
- db_wipe?: (opt: {
60
- force?: boolean;
61
- }) => void | Promise<void>;
62
62
  clean?: (opt: Partial<_InitOptions>) => void | Promise<void>;
63
63
  }
64
64
  export interface ClientHooks {
65
65
  run(): void | Promise<void>;
66
66
  }
67
+ export declare function runIntegrations(): Promise<void>;
67
68
  export {};
package/dist/plugins.js CHANGED
@@ -1,30 +1,27 @@
1
1
  import * as z from 'zod';
2
2
  import { zAsyncFunction } from './schemas.js';
3
3
  import { App } from './apps.js';
4
+ import { debug, warn } from './io.js';
5
+ const PluginCommon = z.object({
6
+ /** CLI mixin path */
7
+ cli: z.string().optional(),
8
+ /** The path to the hooks script */
9
+ hooks: z.string().optional(),
10
+ /** A map of plugin names to paths */
11
+ integrations: z.record(z.string(), z.string()).optional(),
12
+ });
4
13
  export const Plugin = z.looseObject({
5
14
  name: z.string(),
6
15
  version: z.string(),
7
16
  description: z.string().optional(),
8
17
  apps: z.array(App).optional(),
9
- client: z
10
- .object({
11
- /** CLI mixin path */
12
- cli: z.string().optional(),
13
- /** The path to the hooks script */
14
- hooks: z.string().optional(),
15
- })
16
- .optional(),
17
- server: z
18
- .object({
19
- /** The path to the hooks script */
20
- hooks: z.string().optional(),
18
+ client: PluginCommon.extend({}).optional(),
19
+ server: PluginCommon.extend({
21
20
  http_handler: z.string().optional(),
22
21
  /** The path to the HTTP handler used by the server */
23
22
  routes: z.string().optional(),
24
- /** CLI mixin path */
25
- cli: z.string().optional(),
26
- })
27
- .optional(),
23
+ db: z.string().optional(),
24
+ }).optional(),
28
25
  });
29
26
  export const plugins = new Map();
30
27
  /**
@@ -39,8 +36,22 @@ export function _findPlugin(search) {
39
36
  const fn = z.custom(data => typeof data === 'function');
40
37
  export const PluginServerHooks = z.object({
41
38
  statusText: zAsyncFunction(z.function({ input: [], output: z.string() })).optional(),
42
- db_init: fn.optional(),
43
39
  remove: fn.optional(),
44
- db_wipe: fn.optional(),
45
40
  clean: fn.optional(),
46
41
  });
42
+ export async function runIntegrations() {
43
+ for (const [pluginName, plugin] of plugins) {
44
+ const { integrations } = plugin[plugin.isServer ? 'server' : 'client'];
45
+ if (!integrations)
46
+ continue;
47
+ for (const [name, path] of Object.entries(integrations)) {
48
+ if (!plugins.has(name))
49
+ continue;
50
+ debug(`Running ${pluginName} integration with ${name}`);
51
+ await import(path).catch(e => {
52
+ const text = e instanceof Error ? e.stack : String(e);
53
+ warn(`Failed to load ${pluginName} integration with ${name}:\n\t${text}`);
54
+ });
55
+ }
56
+ }
57
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/core",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "funding": {
6
6
  "type": "individual",