@quereus/plugin-loader 4.3.2 → 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 +38 -1
- package/dist/src/config-loader.d.ts.map +1 -1
- package/dist/src/config-loader.js +17 -3
- package/dist/src/config-loader.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/node-remote.d.ts +38 -0
- package/dist/src/node-remote.d.ts.map +1 -0
- package/dist/src/node-remote.js +196 -0
- package/dist/src/node-remote.js.map +1 -0
- package/dist/src/plugin-loader.d.ts +66 -0
- package/dist/src/plugin-loader.d.ts.map +1 -1
- package/dist/src/plugin-loader.js +100 -10
- package/dist/src/plugin-loader.js.map +1 -1
- package/package.json +19 -6
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
|
|
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,
|
|
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, (
|
|
15
|
-
const
|
|
16
|
-
|
|
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":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAsB3C;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAgB,EAAE,MAA8B,EAAE;IACpF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/config-loader.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
package/dist/src/index.js.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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 */
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-loader.js","sourceRoot":"","sources":["../../src/plugin-loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AA8BrD;;;;;GAKG;AACH,IAAI,oBAAoB,GAAgC,IAAI,CAAC;AAE7D,sFAAsF;AACtF,MAAM,UAAU,uBAAuB,CAAC,QAAqC;IAC5E,oBAAoB,GAAG,QAAQ,CAAC;AACjC,CAAC;AAeD;;GAEG;AACH,SAAS,8BAA8B,CAAC,GAAgB;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;IAElC,OAAO;QACN,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,gBAAgB;QAClC,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,OAAO;QAC/B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;KAClC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,GAAY,EAAE,MAAc;IAC5D,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,aAAa,MAAM,iCAAiC,CAAC,CAAC;IACvE,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,sBAAsB,CAAC,SAAc;IACnD,IAAI,CAAC;QACJ,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxD,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAiB,CAAC;YACjD,OAAO,8BAA8B,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,GAAG,CAAC,8CAA8C,EAAE,SAAS,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,GAAW,EACX,EAAY,EACZ,SAAmC,EAAE;IAErC,IAAI,CAAC;QACJ,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAE/B,yEAAyE;QACzE,yEAAyE;QACzE,4EAA4E;QAC5E,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CACd,oCAAoC,SAAS,CAAC,QAAQ,KAAK;gBAC3D,YAAY,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAClD,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAE1D,oEAAoE;QACpE,MAAM,GAAG,GAAY,MAAM,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAEhE,uBAAuB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAElC,MAAM,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9C,GAAG,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;QAElC,sEAAsE;QACtE,0EAA0E;QAC1E,iEAAiE;QACjE,OAAO,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,KAAK,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;AACF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,SAAc;IAC1D,IAAI,SAAS,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACpC,OAAO,eAAe,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED,uEAAuE;IACvE,yEAAyE;IACzE,2EAA2E;IAC3E,IAAI,oBAAoB,EAAE,CAAC;QAC1B,OAAO,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,aAAa,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACd,wEAAwE;YACxE,oEAAoE;YACpE,2EAA2E;YAC3E,2BAA2B,CAC3B,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,iEAAiE;IACjE,OAAO,SAAS,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;AAC/F,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa;IAC5B,MAAM,IAAI,GAAI,UAA6D,CAAC,OAAO,CAAC;IACpF,OAAO,OAAO,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAC;AACjD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe,CAAC,SAAc;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC5C,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAE5B,4EAA4E;QAC5E,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,OAAO,KAAK,CAAC;QACd,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAmBD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,IAAY,EACZ,EAAY,EACZ,SAAmC,EAAE,EACrC,UAA6B,EAAE;IAE/B,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAE5C,gDAAgD;IAChD,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,6CAA6C;IAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACd,wBAAwB,IAAI,uEAAuE,CACnG,CAAC;IACH,CAAC;IAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,MAAM,mBAAmB,CAAC,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,kEAAkE;IAClE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACd,8EAA8E,IAAI,KAAK;YACvF,kFAAkF,CAClF,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC;IACxD,OAAO,MAAM,iBAAiB,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAiC;IACnE,IAAI,GAAG,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,GAAG,CAAC;IACtC,OAAO,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC;AAED,SAAS,YAAY;IACpB,OAAO,OAAO,UAAU,KAAK,WAAW;WACpC,OAAQ,UAAgD,CAAC,QAAQ,KAAK,WAAW,CAAC;AACvF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,CAAS;IAC3B,IAAI,CAAC;QACJ,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACzC,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9D,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAChC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACvF,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QACrF,CAAC;IACF,CAAC;IACD,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,cAAsB,EAAE,OAAgB;IAC7D,MAAM,OAAO,GAAG,cAAc,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,eAAe,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAEvD,IAAI,OAAO,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,mBAAmB,CACjC,GAAY,EACZ,EAAY,EACZ,MAAgC;IAEhC,MAAM,aAAa,GAAG,GAAG,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;IAC/D,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAEtE,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3D,uBAAuB,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAEvC,MAAM,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9C,GAAG,CAAC,+BAA+B,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAE/C,OAAO,MAAM,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,UAAoB,EAAE,WAAmB;IAC1E,IAAI,OAAgB,CAAC;IACrB,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,OAAO,MAAM,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,OAAO,GAAG,CAAC,CAAC;QACb,CAAC;IACF,CAAC;IACD,MAAM,IAAI,KAAK,CACd,qCAAqC,WAAW,KAAK;QACrD,oDAAoD;QACpD,eAAe,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAC7E,CAAC;AACH,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,WAAmB;IAC5D,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,GAAG,WAAW,eAAe,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACvG,OAAO,8BAA8B,CAAC,GAAG,CAAC,OAAsB,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACR,GAAG,CAAC,2CAA2C,EAAE,WAAW,CAAC,CAAC;QAC9D,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,GAAoC;IAC3E,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1E,QAAQ,GAAG,EAAE,CAAC;QACb,KAAK,OAAO;YACX,OAAO,qBAAqB,IAAI,CAAC,IAAI,GAAG,cAAc,IAAI,OAAO,EAAE,CAAC;QACrE,KAAK,QAAQ;YACZ,OAAO,kBAAkB,IAAI,CAAC,IAAI,GAAG,cAAc,IAAI,OAAO,EAAE,CAAC;QAClE,KAAK,UAAU,CAAC;QAChB;YACC,OAAO,gCAAgC,IAAI,CAAC,IAAI,GAAG,cAAc,IAAI,OAAO,EAAE,CAAC;IACjF,CAAC;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/plugin-loader",
|
|
3
|
-
"version": "4.
|
|
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": "
|
|
30
|
-
"
|
|
31
|
-
"test": "
|
|
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.
|
|
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.
|
|
57
|
+
"@quereus/quereus": "^4.4.1",
|
|
45
58
|
"debug": "^4.4.3"
|
|
46
59
|
}
|
|
47
60
|
}
|