@quereus/plugin-loader 4.4.0 → 4.4.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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # @quereus/plugin-loader
2
2
 
3
+ > **Stability: Stable** — the exported API keeps its shape across minor and patch
4
+ > releases. See [Stability Tiers](../../docs/stability.md#tiers).
5
+
3
6
  Plugin loading system for Quereus. This package provides dynamic module loading capabilities for extending Quereus with custom virtual tables, functions, collations, and types.
4
7
 
5
8
  **Note:** This package uses dynamic `import()` which is not compatible with React Native. For React Native environments, use static imports and manual plugin registration instead.
@@ -23,13 +26,47 @@ const db = new Database();
23
26
  // Load from npm package (Node.js)
24
27
  await loadPlugin('npm:@acme/quereus-plugin-foo@^1', db, { api_key: '...' });
25
28
 
26
- // Load from URL (Node.js or Browser)
29
+ // Load from an https:// URL. Native in the browser; Node needs the resolver below.
27
30
  await dynamicLoadModule('https://example.com/plugin.js', db, { timeout: 10000 });
28
31
 
32
+ // Load from a local file (Node.js)
33
+ await dynamicLoadModule('file:///path/to/plugin.mjs', db, { timeout: 10000 });
34
+
29
35
  // Browser with CDN (opt-in)
30
36
  await loadPlugin('npm:@acme/quereus-plugin-foo@^1', db, {}, { allowCdn: true });
31
37
  ```
32
38
 
39
+ ## Loading plugins over `https:` in Node
40
+
41
+ Browsers implement `import('https://…')`; Node's ESM loader does not — it accepts
42
+ only `file:` and `data:` URLs. A Node host that wants remote plugins installs the
43
+ resolver from the `./node` subpath once at startup:
44
+
45
+ ```typescript
46
+ import { installNodeRemoteModuleResolver } from '@quereus/plugin-loader/node';
47
+
48
+ installNodeRemoteModuleResolver({
49
+ // Awaited after each fetch, before the module is imported.
50
+ onFetched: ({ url, sha256, bytes }) => console.log(`Fetched ${url} (${bytes} B, sha256 ${sha256})`),
51
+ maxBytes: 5 * 1024 * 1024, // default
52
+ });
53
+ ```
54
+
55
+ The resolver fetches the module, refuses a redirect that leaves `https:`, enforces
56
+ the size cap, SHA-256s the bytes, writes them to a temp file, and hands the loader
57
+ that file's `file:` URL. Temp files live for the life of the process (so plugin
58
+ stack traces resolve) and the directory is removed at exit.
59
+
60
+ This entry point imports `node:fs` and is therefore deliberately kept out of the
61
+ package index — a browser or React Native bundle never reaches it. Without a
62
+ resolver installed, an `https:` load under Node fails with a message saying which
63
+ resolver to install.
64
+
65
+ Nothing is cached on disk: each load re-downloads and re-executes the remote
66
+ module, so hosts should use `onFetched` to make that visible. See
67
+ [Plugin System Documentation](https://github.com/gotchoices/quereus/blob/main/docs/plugins.md)
68
+ for the full picture.
69
+
33
70
  ## React Native
34
71
 
35
72
  This package is **not compatible** with React Native due to its use of dynamic `import()`. For React Native apps:
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,SAAS,CAkBhG;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAGzG;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAOvG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CAC1C,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,CAetE"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACtD,KAAK,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,SAAS,CAqBhG;AAYD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAGzG;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAOvG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CAC1C,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,YAAY,CAetE"}
@@ -11,9 +11,13 @@ const log = debug('quereus:config-loader');
11
11
  */
12
12
  export function interpolateEnvVars(value, env = {}) {
13
13
  if (typeof value === 'string') {
14
- return value.replace(/\$\{([^}]+)\}/g, (_match, varSpec) => {
15
- const [varName, defaultValue] = varSpec.split(':-');
16
- return env[varName.trim()] ?? defaultValue ?? _match;
14
+ return value.replace(/\$\{([^}]+)\}/g, (match, varSpec) => {
15
+ const { name, defaultValue } = parsePlaceholder(varSpec);
16
+ // Own properties only: without this, `${constructor}` or `${toString}`
17
+ // would resolve to an inherited Object.prototype member.
18
+ if (Object.hasOwn(env, name))
19
+ return env[name];
20
+ return defaultValue ?? match;
17
21
  });
18
22
  }
19
23
  if (typeof value === 'object' && value !== null) {
@@ -28,6 +32,16 @@ export function interpolateEnvVars(value, env = {}) {
28
32
  }
29
33
  return value;
30
34
  }
35
+ /**
36
+ * Splits a `${...}` body into its variable name and optional default. Only the
37
+ * *first* `:-` separates, so a default may itself contain `:-` (e.g. a URL).
38
+ */
39
+ function parsePlaceholder(varSpec) {
40
+ const separator = varSpec.indexOf(':-');
41
+ if (separator === -1)
42
+ return { name: varSpec.trim() };
43
+ return { name: varSpec.slice(0, separator).trim(), defaultValue: varSpec.slice(separator + 2) };
44
+ }
31
45
  /**
32
46
  * Interpolate environment variables in a config object
33
47
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"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"}
@@ -6,8 +6,8 @@
6
6
  * WARNING: This package uses dynamic import() which is NOT compatible with React Native.
7
7
  * For React Native environments, use static imports and manual plugin registration instead.
8
8
  */
9
- export { dynamicLoadModule, validatePluginUrl, loadPlugin } from './plugin-loader.js';
10
- export type { PluginModule, LoadPluginOptions } from './plugin-loader.js';
9
+ export { dynamicLoadModule, validatePluginUrl, loadPlugin, setRemoteModuleResolver } from './plugin-loader.js';
10
+ export type { PluginModule, LoadPluginOptions, RemoteModuleFetch, RemoteModuleResolver } from './plugin-loader.js';
11
11
  export type { PluginManifest, PluginRecord, PluginSetting, VTablePluginInfo, FunctionPluginInfo, CollationPluginInfo, TypePluginInfo, PluginRegistrations } from './manifest.js';
12
12
  export { interpolateEnvVars, interpolateConfigEnvVars, loadPluginsFromConfig, validateConfig, toPluginSqlConfig } from './config-loader.js';
13
13
  export type { PluginConfig, QuoombConfig } from './config-loader.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtF,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG1E,YAAY,EACX,cAAc,EACd,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACN,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC/G,YAAY,EACX,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,MAAM,oBAAoB,CAAC;AAM5B,YAAY,EACX,cAAc,EACd,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACN,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/src/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * For React Native environments, use static imports and manual plugin registration instead.
8
8
  */
9
9
  // Re-export plugin loader functions
10
- export { dynamicLoadModule, validatePluginUrl, loadPlugin } from './plugin-loader.js';
10
+ export { dynamicLoadModule, validatePluginUrl, loadPlugin, setRemoteModuleResolver } from './plugin-loader.js';
11
11
  // Re-export config loader
12
12
  export { interpolateEnvVars, interpolateConfigEnvVars, loadPluginsFromConfig, validateConfig, toPluginSqlConfig } from './config-loader.js';
13
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oCAAoC;AACpC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAetF,0BAA0B;AAC1B,OAAO,EACN,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oCAAoC;AACpC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAuB/G,0BAA0B;AAC1B,OAAO,EACN,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Node support for loading plugin modules over `https:`.
3
+ *
4
+ * Node's ESM loader accepts only `file:` and `data:` URLs, so `import('https://…')`
5
+ * fails with `ERR_UNSUPPORTED_ESM_URL_SCHEME`. This module supplies the missing
6
+ * step: fetch the module, hash it, drop it in a temp file, and hand the loader a
7
+ * `file:` URL it can import.
8
+ *
9
+ * It lives behind the `@quereus/plugin-loader/node` subpath — and is *not*
10
+ * re-exported from the package index — so a browser or React Native bundle never
11
+ * pulls in `node:fs`.
12
+ */
13
+ import type { RemoteModuleFetch, RemoteModuleResolver } from './plugin-loader.js';
14
+ export interface NodeRemoteResolverOptions {
15
+ /**
16
+ * Called after each successful fetch, before the module is imported. Hosts
17
+ * use it to tell the user what was downloaded and to record the hash.
18
+ * Awaited, so a host may persist from here.
19
+ */
20
+ onFetched?: (info: RemoteModuleFetch) => void | Promise<void>;
21
+ /** Reject modules larger than this. Defaults to 5 MiB. */
22
+ maxBytes?: number;
23
+ /** Injected by tests; defaults to the global `fetch`. */
24
+ fetchImpl?: typeof fetch;
25
+ }
26
+ /**
27
+ * Builds a resolver that fetches an `https:` plugin module to a temp file and
28
+ * returns that file's `file:` URL.
29
+ *
30
+ * Fetching happens on every load — there is no on-disk cache — so a plugin
31
+ * saved by URL re-downloads and re-executes remote code each time the host
32
+ * starts. That is why {@link NodeRemoteResolverOptions.onFetched} exists: the
33
+ * host is expected to make it visible rather than silent.
34
+ */
35
+ export declare function createNodeRemoteResolver(options?: NodeRemoteResolverOptions): RemoteModuleResolver;
36
+ /** Creates a resolver and installs it as the process-wide one. */
37
+ export declare function installNodeRemoteModuleResolver(options?: NodeRemoteResolverOptions): void;
38
+ //# sourceMappingURL=node-remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-remote.d.ts","sourceRoot":"","sources":["../../src/node-remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAUlF,MAAM,WAAW,yBAAyB;IACzC;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,yBAA8B,GAAG,oBAAoB,CA2BtG;AAED,kEAAkE;AAClE,wBAAgB,+BAA+B,CAAC,OAAO,GAAE,yBAA8B,GAAG,IAAI,CAE7F"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Node support for loading plugin modules over `https:`.
3
+ *
4
+ * Node's ESM loader accepts only `file:` and `data:` URLs, so `import('https://…')`
5
+ * fails with `ERR_UNSUPPORTED_ESM_URL_SCHEME`. This module supplies the missing
6
+ * step: fetch the module, hash it, drop it in a temp file, and hand the loader a
7
+ * `file:` URL it can import.
8
+ *
9
+ * It lives behind the `@quereus/plugin-loader/node` subpath — and is *not*
10
+ * re-exported from the package index — so a browser or React Native bundle never
11
+ * pulls in `node:fs`.
12
+ */
13
+ import { createHash } from 'node:crypto';
14
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
15
+ import { tmpdir } from 'node:os';
16
+ import { join } from 'node:path';
17
+ import { pathToFileURL } from 'node:url';
18
+ import debug from 'debug';
19
+ import { setRemoteModuleResolver } from './plugin-loader.js';
20
+ const log = debug('quereus:plugin-loader:node-remote');
21
+ /** Ceiling on a fetched plugin module, unless the host raises it. */
22
+ const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
23
+ /** Media types we expect a JavaScript module to be served as. */
24
+ const JS_MEDIA_TYPE = /(java|ecma)script/i;
25
+ /**
26
+ * Builds a resolver that fetches an `https:` plugin module to a temp file and
27
+ * returns that file's `file:` URL.
28
+ *
29
+ * Fetching happens on every load — there is no on-disk cache — so a plugin
30
+ * saved by URL re-downloads and re-executes remote code each time the host
31
+ * starts. That is why {@link NodeRemoteResolverOptions.onFetched} exists: the
32
+ * host is expected to make it visible rather than silent.
33
+ */
34
+ export function createNodeRemoteResolver(options = {}) {
35
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
36
+ return async (url) => {
37
+ // Resolved per call, not at construction: a host installs the resolver at
38
+ // startup, which may be before a `fetch` polyfill (or a test double) exists.
39
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
40
+ const response = await fetchImpl(url.toString());
41
+ if (!response.ok) {
42
+ throw new Error(`Failed to fetch plugin module from ${url.href}: HTTP ${response.status}` +
43
+ (response.statusText ? ` ${response.statusText}` : ''));
44
+ }
45
+ assertSecureFinalUrl(response, url);
46
+ logUnexpectedMediaType(response, url);
47
+ const bytes = await readCappedBody(response, maxBytes, url.href);
48
+ const sha256 = createHash('sha256').update(bytes).digest('hex');
49
+ const path = writeModuleFile(bytes, sha256);
50
+ await options.onFetched?.({ url: url.href, sha256, bytes: bytes.byteLength });
51
+ log('Fetched %s to %s (%d bytes, sha256 %s)', url.href, path, bytes.byteLength, sha256);
52
+ return pathToFileURL(path).href;
53
+ };
54
+ }
55
+ /** Creates a resolver and installs it as the process-wide one. */
56
+ export function installNodeRemoteModuleResolver(options = {}) {
57
+ setRemoteModuleResolver(createNodeRemoteResolver(options));
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Internal helpers
61
+ // ---------------------------------------------------------------------------
62
+ /**
63
+ * `fetch` follows redirects across protocols, so an https → http hop would
64
+ * otherwise downgrade the transport silently. Re-check where the request
65
+ * actually landed.
66
+ */
67
+ function assertSecureFinalUrl(response, requested) {
68
+ // A response with no `url` came from a fetch implementation that does not
69
+ // report one (some test doubles); there is no redirect to check.
70
+ if (!response.url)
71
+ return;
72
+ let finalUrl;
73
+ try {
74
+ finalUrl = new URL(response.url);
75
+ }
76
+ catch {
77
+ throw new Error(`Fetching plugin module ${requested.href} ended at an unparseable URL '${response.url}'.`);
78
+ }
79
+ if (finalUrl.protocol !== 'https:') {
80
+ throw new Error(`Fetching plugin module ${requested.href} was redirected to ${finalUrl.protocol}//` +
81
+ `${finalUrl.host}${finalUrl.pathname}, which is not https:. Refusing to load it.`);
82
+ }
83
+ }
84
+ /**
85
+ * Plenty of raw-file hosts serve JavaScript as `text/plain` or
86
+ * `application/octet-stream`, so an unexpected media type is a debug note, not a
87
+ * failure.
88
+ */
89
+ function logUnexpectedMediaType(response, url) {
90
+ const contentType = response.headers?.get('content-type');
91
+ if (contentType && !JS_MEDIA_TYPE.test(contentType)) {
92
+ log('Plugin module at %s served as %s, not a JavaScript media type', url.href, contentType);
93
+ }
94
+ }
95
+ /**
96
+ * Reads the response body, refusing anything over `maxBytes`. Both the declared
97
+ * `content-length` and the bytes actually received are checked, so neither a
98
+ * missing nor a lying header can get past the limit.
99
+ */
100
+ async function readCappedBody(response, maxBytes, url) {
101
+ const declared = Number(response.headers?.get('content-length') ?? Number.NaN);
102
+ if (Number.isFinite(declared)) {
103
+ assertWithinLimit(declared, maxBytes, url, 'declares');
104
+ }
105
+ if (!response.body) {
106
+ // Bodyless response (some fetch implementations and test doubles): buffer
107
+ // it, then apply the same limit to the real byte count.
108
+ const buffered = new Uint8Array(await response.arrayBuffer());
109
+ assertWithinLimit(buffered.byteLength, maxBytes, url, 'is');
110
+ return buffered;
111
+ }
112
+ return await readStreamCapped(response.body, maxBytes, url);
113
+ }
114
+ /** Streams a body, bailing out as soon as the running total exceeds the limit. */
115
+ async function readStreamCapped(body, maxBytes, url) {
116
+ const reader = body.getReader();
117
+ const chunks = [];
118
+ let total = 0;
119
+ try {
120
+ for (;;) {
121
+ const { done, value } = await reader.read();
122
+ if (done)
123
+ break;
124
+ total += value.byteLength;
125
+ assertWithinLimit(total, maxBytes, url, 'is');
126
+ chunks.push(value);
127
+ }
128
+ }
129
+ catch (error) {
130
+ // Stop the transfer rather than leaving the socket draining a body we
131
+ // have already decided to reject.
132
+ await reader.cancel().catch(cancelError => log('Cancelling %s after a read failure: %O', url, cancelError));
133
+ throw error;
134
+ }
135
+ reader.releaseLock();
136
+ return concatChunks(chunks, total);
137
+ }
138
+ function assertWithinLimit(bytes, maxBytes, url, verb) {
139
+ if (bytes > maxBytes) {
140
+ throw new Error(`Plugin module at ${url} ${verb} ${bytes} bytes, over the ${maxBytes}-byte limit.`);
141
+ }
142
+ }
143
+ function concatChunks(chunks, total) {
144
+ const joined = new Uint8Array(total);
145
+ let offset = 0;
146
+ for (const chunk of chunks) {
147
+ joined.set(chunk, offset);
148
+ offset += chunk.byteLength;
149
+ }
150
+ return joined;
151
+ }
152
+ /** Temp directory holding this process's fetched modules; created on first use. */
153
+ let moduleDir;
154
+ /** Distinguishes successive fetches — see {@link writeModuleFile}. */
155
+ let moduleCounter = 0;
156
+ /**
157
+ * Creates this process's temp directory on first use and arranges for it to be
158
+ * removed at exit.
159
+ *
160
+ * NOTE: `process.on('exit')` does not run when the process dies abruptly —
161
+ * SIGKILL, or a worker thread that the host terminates (a vitest pool worker
162
+ * does exactly this, leaving one directory per run). The OS reclaims temp space
163
+ * eventually, so this is not worth a cleanup daemon; if a long-lived host ever
164
+ * loads plugins often enough for the leftovers to matter, sweep stale
165
+ * `quereus-plugins-*` directories at startup.
166
+ */
167
+ function ensureModuleDir() {
168
+ if (moduleDir === undefined) {
169
+ moduleDir = mkdtempSync(join(tmpdir(), `quereus-plugins-${process.pid}-`));
170
+ const dir = moduleDir;
171
+ process.once('exit', () => rmSync(dir, { recursive: true, force: true }));
172
+ }
173
+ return moduleDir;
174
+ }
175
+ /**
176
+ * Writes fetched module bytes to a `.mjs` file (so Node treats them as ESM
177
+ * whatever the enclosing directory says) and returns its path.
178
+ *
179
+ * The counter in the filename matters: without it, a second load of an unchanged
180
+ * URL would produce the same specifier and Node would serve the module from its
181
+ * registry instead of re-evaluating it — the very thing the loader's `?t=`
182
+ * cache-buster exists to avoid.
183
+ *
184
+ * Files stay for the life of the process rather than being unlinked after
185
+ * import, so stack traces from inside the plugin still resolve.
186
+ *
187
+ * NOTE: as with the `?t=` cache-buster, every reload leaves the prior module
188
+ * version in Node's registry. Fine for a CLI; a long-lived host that reloads
189
+ * plugins in a loop needs a real unload story.
190
+ */
191
+ function writeModuleFile(bytes, sha256) {
192
+ const path = join(ensureModuleDir(), `${sha256.slice(0, 16)}-${moduleCounter++}.mjs`);
193
+ writeFileSync(path, bytes);
194
+ return path;
195
+ }
196
+ //# sourceMappingURL=node-remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-remote.js","sourceRoot":"","sources":["../../src/node-remote.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,26 @@ export interface PluginModule {
7
7
  /** Default export - the plugin registration function */
8
8
  default: (db: Database, config?: Record<string, SqlValue>) => Promise<PluginRegistrations> | PluginRegistrations;
9
9
  }
10
+ /** What a host learns about a plugin module it fetched over the network. */
11
+ export interface RemoteModuleFetch {
12
+ /** The URL that was requested (before any redirects). */
13
+ url: string;
14
+ /** SHA-256 of the fetched bytes, lowercase hex. */
15
+ sha256: string;
16
+ /** Size of the fetched module, in bytes. */
17
+ bytes: number;
18
+ }
19
+ /**
20
+ * Turns an `https:` module URL into a specifier this runtime's `import()` can
21
+ * load — under Node, a `file:` URL for a locally fetched copy.
22
+ *
23
+ * Node hosts must install one (see `@quereus/plugin-loader/node`), because
24
+ * Node's ESM loader accepts only `file:` and `data:` URLs. Browsers and workers
25
+ * need none — `import('https://…')` works there natively.
26
+ */
27
+ export type RemoteModuleResolver = (url: URL) => Promise<string>;
28
+ /** Installs (or, with `null`, clears) the resolver used for `https:` module loads. */
29
+ export declare function setRemoteModuleResolver(resolver: RemoteModuleResolver | null): void;
10
30
  /**
11
31
  * Dynamically loads and registers a plugin module
12
32
  *
@@ -16,6 +36,30 @@ export interface PluginModule {
16
36
  * @returns The plugin's manifest if available
17
37
  */
18
38
  export declare function dynamicLoadModule(url: string, db: Database, config?: Record<string, SqlValue>): Promise<PluginManifest | undefined>;
39
+ /**
40
+ * Turns a validated plugin module URL into a specifier this runtime's `import()`
41
+ * can actually load.
42
+ *
43
+ * Never mutates `moduleUrl` — the caller still needs the original to resolve the
44
+ * plugin's `package.json` against.
45
+ *
46
+ * @internal Exported for tests only — the browser/worker branch cannot be
47
+ * reached through {@link dynamicLoadModule} under Node, since the import it
48
+ * returns a specifier for would then be attempted for real.
49
+ */
50
+ export declare function resolveImportSpecifier(moduleUrl: URL): Promise<string>;
51
+ /**
52
+ * True when this runtime is Node, whose ESM loader accepts only `file:` and
53
+ * `data:` specifiers.
54
+ *
55
+ * Deliberately not `resolveEnvironment() === 'node'`: that treats "no `document`"
56
+ * as Node, and a Web Worker — which is where quoomb-web loads its plugins —
57
+ * has no `document` yet imports `https:` URLs natively. A bundler's `process`
58
+ * shim declares no `versions.node`, so it does not trip this either.
59
+ *
60
+ * @internal Exported for tests only — see {@link resolveEnvironment}.
61
+ */
62
+ export declare function isNodeRuntime(): boolean;
19
63
  /**
20
64
  * Validates that a URL is likely to be a valid plugin module
21
65
  *
@@ -48,4 +92,26 @@ export interface LoadPluginOptions {
48
92
  * - file:///path/to/plugin.js (Node only)
49
93
  */
50
94
  export declare function loadPlugin(spec: string, db: Database, config?: Record<string, SqlValue>, options?: LoadPluginOptions): Promise<PluginManifest | undefined>;
95
+ /**
96
+ * @internal Exported for tests only — not re-exported from `index.js`, so it is
97
+ * not part of the package's public API.
98
+ */
99
+ export declare function resolveEnvironment(env?: 'auto' | 'browser' | 'node'): 'browser' | 'node';
100
+ /** @internal Exported for tests only — see {@link resolveEnvironment}. */
101
+ export interface NpmSpec {
102
+ name: string;
103
+ version?: string;
104
+ subpath?: string;
105
+ }
106
+ /**
107
+ * Parses an npm spec (`npm:@scope/name@version/subpath`, or a bare package
108
+ * name) into its parts. Returns null for input that cannot be a package spec
109
+ * (empty, or containing whitespace); it does *not* attempt full npm name
110
+ * validation — resolution failures surface from the import itself.
111
+ *
112
+ * @internal Exported for tests only — see {@link resolveEnvironment}.
113
+ */
114
+ export declare function parseNpmSpec(input: string): NpmSpec | null;
115
+ /** @internal Exported for tests only — see {@link resolveEnvironment}. */
116
+ export declare function toCdnUrl(spec: NpmSpec, cdn: 'jsdelivr' | 'unpkg' | 'esm.sh'): string;
51
117
  //# sourceMappingURL=plugin-loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../../src/plugin-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAazE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,wDAAwD;IACxD,OAAO,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,mBAAmB,CAAC,GAAG,mBAAmB,CAAC;CACjH;AA6DD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACtC,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,QAAQ,EACZ,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM,GACnC,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAgCrC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAkBtD;AAGD,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,QAAQ,EACZ,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM,EACrC,OAAO,GAAE,iBAAsB,GAC7B,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CA8BrC"}
1
+ {"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../../src/plugin-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAazE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,wDAAwD;IACxD,OAAO,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,mBAAmB,CAAC,GAAG,mBAAmB,CAAC;CACjH;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IACjC,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAUjE,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAEnF;AA6DD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACtC,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,QAAQ,EACZ,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM,GACnC,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAgCrC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAGvC;AAiBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAkBtD;AAGD,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,QAAQ,EACZ,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAM,EACrC,OAAO,GAAE,iBAAsB,GAC7B,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CA8BrC;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAGxF;AAsBD,0EAA0E;AAC1E,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAM1D;AAwED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAYpF"}
@@ -8,6 +8,17 @@ const log = debug('quereus:plugin-loader');
8
8
  * re-used by {@link validatePluginUrl} for pre-flight UI validation.
9
9
  */
10
10
  const ALLOWED_PLUGIN_PROTOCOLS = ['https:', 'file:'];
11
+ /**
12
+ * Module-level singleton rather than a `dynamicLoadModule` option: the loader
13
+ * has many call sites across the CLI and the web worker, and threading a
14
+ * resolver through all of them buys nothing over the host installing it once at
15
+ * startup.
16
+ */
17
+ let remoteModuleResolver = null;
18
+ /** Installs (or, with `null`, clears) the resolver used for `https:` module loads. */
19
+ export function setRemoteModuleResolver(resolver) {
20
+ remoteModuleResolver = resolver;
21
+ }
11
22
  /**
12
23
  * Extracts plugin manifest from package.json metadata
13
24
  */
@@ -69,15 +80,15 @@ export async function dynamicLoadModule(url, db, config = {}) {
69
80
  throw new Error(`Unsupported plugin URL protocol '${moduleUrl.protocol}'. ` +
70
81
  `Allowed: ${ALLOWED_PLUGIN_PROTOCOLS.join(', ')}.`);
71
82
  }
72
- // Add cache-busting timestamp for local development
73
- if (moduleUrl.protocol === 'file:' || moduleUrl.hostname === 'localhost') {
74
- moduleUrl.searchParams.set('t', Date.now().toString());
75
- }
83
+ const specifier = await resolveImportSpecifier(moduleUrl);
76
84
  // Dynamic import with Vite ignore comment for bundler compatibility
77
- const mod = await import(/* @vite-ignore */ moduleUrl.toString());
85
+ const mod = await import(/* @vite-ignore */ specifier);
78
86
  assertValidPluginModule(mod, url);
79
87
  await registerPlugin(db, mod.default, config);
80
88
  log('Loaded plugin from %s', url);
89
+ // Deliberately the *original* URL, not `specifier`: a remote resolver
90
+ // hands back a local temp file, and resolving 'package.json' against that
91
+ // would look in the temp directory instead of beside the plugin.
81
92
  return await tryLoadManifestFromUrl(moduleUrl);
82
93
  }
83
94
  catch (error) {
@@ -85,6 +96,66 @@ export async function dynamicLoadModule(url, db, config = {}) {
85
96
  throw new Error(`Failed to load plugin from ${url}: ${message}`);
86
97
  }
87
98
  }
99
+ /**
100
+ * Turns a validated plugin module URL into a specifier this runtime's `import()`
101
+ * can actually load.
102
+ *
103
+ * Never mutates `moduleUrl` — the caller still needs the original to resolve the
104
+ * plugin's `package.json` against.
105
+ *
106
+ * @internal Exported for tests only — the browser/worker branch cannot be
107
+ * reached through {@link dynamicLoadModule} under Node, since the import it
108
+ * returns a specifier for would then be attempted for real.
109
+ */
110
+ export async function resolveImportSpecifier(moduleUrl) {
111
+ if (moduleUrl.protocol === 'file:') {
112
+ return withCacheBuster(moduleUrl);
113
+ }
114
+ // Only `https:` reaches here (the allowlist rejected everything else).
115
+ // A host-installed resolver wins wherever one exists; failing that, Node
116
+ // cannot import the URL at all, while browsers and workers do it natively.
117
+ if (remoteModuleResolver) {
118
+ return await remoteModuleResolver(moduleUrl);
119
+ }
120
+ if (isNodeRuntime()) {
121
+ throw new Error(`Loading a plugin over https:// is not supported by Node's ESM loader. ` +
122
+ `Install the Node resolver (installNodeRemoteModuleResolver() from ` +
123
+ `'@quereus/plugin-loader/node'), or load the plugin from an installed npm ` +
124
+ `package or a file:// URL.`);
125
+ }
126
+ // Browser or worker: `import('https://…')` is native. Cache-bust a local dev
127
+ // server so a rebuilt plugin is picked up without a hard reload.
128
+ return moduleUrl.hostname === 'localhost' ? withCacheBuster(moduleUrl) : moduleUrl.toString();
129
+ }
130
+ /**
131
+ * True when this runtime is Node, whose ESM loader accepts only `file:` and
132
+ * `data:` specifiers.
133
+ *
134
+ * Deliberately not `resolveEnvironment() === 'node'`: that treats "no `document`"
135
+ * as Node, and a Web Worker — which is where quoomb-web loads its plugins —
136
+ * has no `document` yet imports `https:` URLs natively. A bundler's `process`
137
+ * shim declares no `versions.node`, so it does not trip this either.
138
+ *
139
+ * @internal Exported for tests only — see {@link resolveEnvironment}.
140
+ */
141
+ export function isNodeRuntime() {
142
+ const proc = globalThis.process;
143
+ return typeof proc?.versions?.node === 'string';
144
+ }
145
+ /**
146
+ * Returns `moduleUrl` with a fresh `?t=` stamp, so a reload re-evaluates the
147
+ * module instead of getting the copy already in the module registry.
148
+ *
149
+ * NOTE: each reload therefore imports a distinct specifier, so Node keeps every
150
+ * prior version of the module in its registry. Harmless for a CLI or a dev
151
+ * session; if a long-lived host starts reloading plugins in a loop, it needs a
152
+ * real unload story rather than a new query string per load.
153
+ */
154
+ function withCacheBuster(moduleUrl) {
155
+ const busted = new URL(moduleUrl.href);
156
+ busted.searchParams.set('t', Date.now().toString());
157
+ return busted.toString();
158
+ }
88
159
  /**
89
160
  * Validates that a URL is likely to be a valid plugin module
90
161
  *
@@ -142,7 +213,11 @@ export async function loadPlugin(spec, db, config = {}, options = {}) {
142
213
  // ---------------------------------------------------------------------------
143
214
  // Internal helpers
144
215
  // ---------------------------------------------------------------------------
145
- function resolveEnvironment(env) {
216
+ /**
217
+ * @internal Exported for tests only — not re-exported from `index.js`, so it is
218
+ * not part of the package's public API.
219
+ */
220
+ export function resolveEnvironment(env) {
146
221
  if (env && env !== 'auto')
147
222
  return env;
148
223
  return isBrowserEnv() ? 'browser' : 'node';
@@ -151,16 +226,30 @@ function isBrowserEnv() {
151
226
  return typeof globalThis !== 'undefined'
152
227
  && typeof globalThis.document !== 'undefined';
153
228
  }
229
+ /**
230
+ * True when a spec should be handled as a URL rather than an npm package.
231
+ * Any parseable absolute URL qualifies — *including* disallowed schemes, so that
232
+ * {@link dynamicLoadModule}'s allowlist names the offending protocol instead of
233
+ * the spec falling through to the package branch and failing as an unresolvable
234
+ * package name. `npm:` is the one scheme that means "package", so it is exempt.
235
+ */
154
236
  function isUrlLike(s) {
155
237
  try {
156
- const u = new URL(s);
157
- return u.protocol === 'https:' || u.protocol === 'file:';
238
+ return new URL(s).protocol !== 'npm:';
158
239
  }
159
240
  catch {
160
241
  return false;
161
242
  }
162
243
  }
163
- function parseNpmSpec(input) {
244
+ /**
245
+ * Parses an npm spec (`npm:@scope/name@version/subpath`, or a bare package
246
+ * name) into its parts. Returns null for input that cannot be a package spec
247
+ * (empty, or containing whitespace); it does *not* attempt full npm name
248
+ * validation — resolution failures surface from the import itself.
249
+ *
250
+ * @internal Exported for tests only — see {@link resolveEnvironment}.
251
+ */
252
+ export function parseNpmSpec(input) {
164
253
  const raw = input.startsWith('npm:') ? input.slice(4) : input;
165
254
  if (!raw || /\s/.test(raw))
166
255
  return null;
@@ -225,7 +314,8 @@ async function tryLoadManifestFromPackage(packageName) {
225
314
  return undefined;
226
315
  }
227
316
  }
228
- function toCdnUrl(spec, cdn) {
317
+ /** @internal Exported for tests only — see {@link resolveEnvironment}. */
318
+ export function toCdnUrl(spec, cdn) {
229
319
  const versionSegment = spec.version ? `@${spec.version}` : '';
230
320
  const subpath = spec.subpath ? spec.subpath.replace(/^\//, '') : 'plugin';
231
321
  switch (cdn) {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../../src/plugin-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../../src/plugin-loader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quereus/plugin-loader",
3
- "version": "4.4.0",
3
+ "version": "4.4.1",
4
4
  "type": "module",
5
5
  "description": "Plugin loading system for Quereus - supports dynamic imports for Node.js and browsers",
6
6
  "publisher": "Got Choices Foundation",
@@ -20,18 +20,31 @@
20
20
  ".": {
21
21
  "types": "./dist/src/index.d.ts",
22
22
  "import": "./dist/src/index.js"
23
+ },
24
+ "./node": {
25
+ "types": "./dist/src/node-remote.d.ts",
26
+ "import": "./dist/src/node-remote.js"
27
+ }
28
+ },
29
+ "//typesVersions": "NOTE: consumers still compile with moduleResolution 'node' (node10), which ignores the exports map above. typesVersions is how the './node' subpath's types resolve for them; drop it once every consumer moves to node16/bundler resolution.",
30
+ "typesVersions": {
31
+ "*": {
32
+ "node": [
33
+ "./dist/src/node-remote.d.ts"
34
+ ]
23
35
  }
24
36
  },
25
37
  "scripts": {
26
38
  "clean": "rimraf dist",
27
39
  "build": "tsc",
28
40
  "lint": "echo 'No lint configured'",
29
- "typecheck": "tsc --noEmit",
30
- "//test": "NOTE: test/config-channel.spec.ts covers the plugin config channel only; url parsing/validation, npm-spec resolution, and CDN url building are still untested — this is core infrastructure, so that gap is tracked as debt, not shrugged off: see tickets/backlog/debt-plugin-loader-test-coverage.md. --passWithNoTests stays so an empty glob (or a future test-file rename) doesn't fail the build.",
31
- "test": "vitest run --passWithNoTests"
41
+ "//typecheck": "NOTE: the second pass type-checks test/ too (tsconfig.json only includes src/). vitest transpiles specs without checking them, so without this a signature change in src/ would leave the specs silently stale.",
42
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.test.json --noEmit",
43
+ "//test": "NOTE: test/ covers url validation + the loader's protocol allowlist, npm-spec parsing, CDN url building, env detection, loadPlugin dispatch, config interpolation/validation, the config channel, and https:// module loads through the Node remote resolver (with fetch injected, so no test touches the network). Known gaps (both need network or a DOM): the manifest fetch from a plugin's package.json, and the real browser+CDN load path. --passWithNoTests is deliberately NOT set, so a glob that stops matching fails loudly instead of reporting green.",
44
+ "test": "vitest run"
32
45
  },
33
46
  "peerDependencies": {
34
- "@quereus/quereus": "^4.4.0"
47
+ "@quereus/quereus": "^4.4.1"
35
48
  },
36
49
  "devDependencies": {
37
50
  "@types/debug": "^4.1.13",
@@ -41,7 +54,7 @@
41
54
  "vitest": "^4.0.17"
42
55
  },
43
56
  "dependencies": {
44
- "@quereus/quereus": "^4.4.0",
57
+ "@quereus/quereus": "^4.4.1",
45
58
  "debug": "^4.4.3"
46
59
  }
47
60
  }