@axium/core 0.12.0 → 0.13.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,5 +1,6 @@
1
1
  import * as z from 'zod';
2
2
  import type { User } from './user.js';
3
+ import { type Omit } from 'utilium';
3
4
  export interface AccessControl {
4
5
  itemId: string;
5
6
  userId?: string | null;
package/dist/api.d.ts CHANGED
@@ -1,13 +1,14 @@
1
1
  import type { PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types';
2
+ import type { Omit } from 'utilium';
2
3
  import type z from 'zod';
3
4
  import type { AccessControl, AccessMap } from './access.js';
4
5
  import type { App } from './apps.js';
5
6
  import type { AuditEvent, AuditFilter, Severity } from './audit.js';
6
7
  import type { NewSessionResponse, Session, Verification } from './auth.js';
7
8
  import type { Passkey, PasskeyAuthenticationResponse, PasskeyChangeable, PasskeyRegistration } from './passkeys.js';
9
+ import type { PluginInternal, PluginVersionInfo } from './plugins.js';
8
10
  import type { RequestMethod } from './requests.js';
9
11
  import type { LogoutSessions, User, UserAuthOptions, UserChangeable, UserInternal, UserPublic, UserRegistration } from './user.js';
10
- import type { PluginInternal } from './plugins.js';
11
12
  export interface AdminSummary {
12
13
  users: number;
13
14
  passkeys: number;
@@ -115,7 +116,7 @@ export interface $API {
115
116
  };
116
117
  };
117
118
  'admin/plugins': {
118
- GET: PluginInternal[];
119
+ GET: (Omit<PluginInternal, '_hooks' | '_client'> & PluginVersionInfo)[];
119
120
  };
120
121
  'admin/audit/events': {
121
122
  OPTIONS: {
@@ -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<PluginInternal | void>;
3
+ export declare function loadPlugin<const T extends 'client' | 'server'>(mode: T, specifier: string, loadedBy: string, safeMode?: boolean): Promise<PluginInternal | void>;
@@ -19,9 +19,9 @@ export function* pluginText(plugin) {
19
19
  yield `Hooks: ${plugin._client ? styleText(['dim', 'bold'], `(${Object.keys(plugin._client).length}) `) + Object.keys(plugin._client).join(', ') : plugin.client.hooks || styleText('dim', '(none)')}`;
20
20
  }
21
21
  }
22
- function _locatePlugin(specifier, _loadedBy) {
22
+ function _locatePlugin(specifier, loadedBy) {
23
23
  if (specifier[0] == '/' || ['.', '..'].includes(specifier.split('/')[0])) {
24
- const path = resolve(dirname(_loadedBy), specifier);
24
+ const path = resolve(dirname(loadedBy), specifier);
25
25
  const stats = fs.statSync(path);
26
26
  if (stats.isFile())
27
27
  return path;
@@ -34,10 +34,10 @@ function _locatePlugin(specifier, _loadedBy) {
34
34
  ;
35
35
  return join(packageDir, 'package.json');
36
36
  }
37
- export async function loadPlugin(mode, specifier, _loadedBy, safeMode = false) {
37
+ export async function loadPlugin(mode, specifier, loadedBy, safeMode = false) {
38
38
  try {
39
- const path = _locatePlugin(specifier, _loadedBy);
40
- io.debug(`Loading plugin at ${path} (from ${_loadedBy})`);
39
+ const path = _locatePlugin(specifier, loadedBy);
40
+ io.debug(`Loading plugin at ${path} (from ${loadedBy})`);
41
41
  let imported;
42
42
  try {
43
43
  imported = JSON.parse(fs.readFileSync(path, 'utf8'));
@@ -49,7 +49,7 @@ export async function loadPlugin(mode, specifier, _loadedBy, safeMode = false) {
49
49
  Object.assign(imported, imported.axium); // support axium field in package.json
50
50
  const plugin = Object.assign(await Plugin.parseAsync(imported).catch(e => {
51
51
  throw e instanceof z.core.$ZodError ? z.prettifyError(e) : e;
52
- }), { path, specifier, _loadedBy, dirname: dirname(path), cli: imported[mode]?.cli, isServer: mode === 'server' });
52
+ }), { path, specifier, loadedBy, dirname: dirname(path), cli: imported[mode]?.cli, isServer: mode === 'server' });
53
53
  if (!plugin[mode])
54
54
  throw `Plugin does not support running ${mode}-side`;
55
55
  if (!safeMode) {
package/dist/plugins.d.ts CHANGED
@@ -12,28 +12,34 @@ 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>;
21
23
  db: z.ZodOptional<z.ZodString>;
22
24
  }, z.core.$strip>>;
25
+ /** If set Axium can check the npm registry for updates */
26
+ update_checks: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
23
27
  }, z.core.$loose>;
24
28
  export type Plugin = z.infer<typeof Plugin>;
25
- export interface PluginInternal extends Plugin {
26
- readonly path: string;
27
- readonly dirname: string;
28
- readonly specifier: string;
29
- readonly _loadedBy: string;
30
- readonly cli?: string;
29
+ export interface PluginInfo {
30
+ path: string;
31
+ dirname: string;
32
+ specifier: string;
33
+ loadedBy: string;
34
+ cli?: string;
31
35
  /** @internal */
32
- readonly _hooks?: ServerHooks;
36
+ _hooks?: ServerHooks;
33
37
  /** @internal */
34
- readonly _client?: ClientHooks;
35
- readonly isServer: boolean;
36
- readonly _db?: any;
38
+ _client?: ClientHooks;
39
+ isServer: boolean;
40
+ _db?: any;
41
+ }
42
+ export interface PluginInternal extends Plugin, Readonly<PluginInfo> {
37
43
  }
38
44
  export declare const plugins: Map<string, PluginInternal>;
39
45
  /**
@@ -60,4 +66,9 @@ export interface ServerHooks {
60
66
  export interface ClientHooks {
61
67
  run(): void | Promise<void>;
62
68
  }
69
+ export declare function runIntegrations(): Promise<void>;
70
+ export interface PluginVersionInfo {
71
+ latest: string | null;
72
+ }
73
+ export declare function getVersionInfo(plugin: PluginInternal): Promise<PluginVersionInfo>;
63
74
  export {};
package/dist/plugins.js CHANGED
@@ -1,31 +1,30 @@
1
1
  import * as z from 'zod';
2
2
  import { zAsyncFunction } from './schemas.js';
3
3
  import { App } from './apps.js';
4
+ import { debug, info, warn } from './io.js';
5
+ import { lt as ltVersion } from 'semver';
6
+ const PluginCommon = z.object({
7
+ /** CLI mixin path */
8
+ cli: z.string().optional(),
9
+ /** The path to the hooks script */
10
+ hooks: z.string().optional(),
11
+ /** A map of plugin names to paths */
12
+ integrations: z.record(z.string(), z.string()).optional(),
13
+ });
4
14
  export const Plugin = z.looseObject({
5
15
  name: z.string(),
6
16
  version: z.string(),
7
17
  description: z.string().optional(),
8
18
  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(),
19
+ client: PluginCommon.extend({}).optional(),
20
+ server: PluginCommon.extend({
21
21
  http_handler: z.string().optional(),
22
22
  /** The path to the HTTP handler used by the server */
23
23
  routes: z.string().optional(),
24
- /** CLI mixin path */
25
- cli: z.string().optional(),
26
24
  db: z.string().optional(),
27
- })
28
- .optional(),
25
+ }).optional(),
26
+ /** If set Axium can check the npm registry for updates */
27
+ update_checks: z.boolean().nullish(),
29
28
  });
30
29
  export const plugins = new Map();
31
30
  /**
@@ -43,3 +42,33 @@ export const PluginServerHooks = z.object({
43
42
  remove: fn.optional(),
44
43
  clean: fn.optional(),
45
44
  });
45
+ export async function runIntegrations() {
46
+ for (const [pluginName, plugin] of plugins) {
47
+ const { integrations } = plugin[plugin.isServer ? 'server' : 'client'];
48
+ if (!integrations)
49
+ continue;
50
+ for (const [name, path] of Object.entries(integrations)) {
51
+ if (!plugins.has(name))
52
+ continue;
53
+ debug(`Running ${pluginName} integration with ${name}`);
54
+ await import(path).catch(e => {
55
+ const text = e instanceof Error ? e.stack : String(e);
56
+ warn(`Failed to load ${pluginName} integration with ${name}:\n\t${text}`);
57
+ });
58
+ }
59
+ }
60
+ }
61
+ export async function getVersionInfo(plugin) {
62
+ if (!plugin.update_checks)
63
+ return { latest: null };
64
+ try {
65
+ const res = await fetch('https://registry.npmjs.org/' + plugin.name);
66
+ const pkg = await res.json();
67
+ const latest = pkg['dist-tags']?.latest || Object.keys(pkg.versions).sort((a, b) => (ltVersion(a, b) ? 1 : -1))[0];
68
+ return { latest };
69
+ }
70
+ catch (e) {
71
+ warn(`Failed to fetch version info for plugin ${plugin.name}: ${e instanceof Error ? e.message : String(e)}`);
72
+ return { latest: null };
73
+ }
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/core",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "author": "James Prevett <axium@jamespre.dev>",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -35,6 +35,8 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@simplewebauthn/types": "^12.0.0",
38
- "mime": "^4.0.7"
38
+ "@types/semver": "^7.7.1",
39
+ "mime": "^4.0.7",
40
+ "semver": "^7.7.3"
39
41
  }
40
42
  }