@jini-ai/platform 0.5.5 → 0.5.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @jini-ai/platform
2
2
 
3
+ ## 0.5.7 — 2026-10-14
4
+
5
+ - The asset cache's optional `undici` load moves behind `asset-cache.adapter.ts` (64eafe35); injected dispatchers, DNS validation and the MODULE_NOT_FOUND message are unchanged. No API change.
6
+
7
+ ## 0.5.6 — 2026-10-13
8
+
9
+ - `undici` and `hast-util-from-parse5`, `hast-util-to-mdast`, `mdast-util-to-markdown`, `mdast-util-gfm-table` (with `parse5`) are now optional peers instead of dependencies. Only `./web` needs the HTML/Markdown set; only the default `createAssetCacheDispatcher` needs undici, loaded lazily (a missing peer throws `AssetCacheError` 500; a host-supplied dispatcher needs none). Hosts using those must list the packages themselves.
10
+ - New `./asset-cache` subpath (node) exporting the asset cache without the root barrel.
11
+ - New universal `./secrets/credential-sets/contracts` leaf (vault contracts without the vault runtime); `@jini-ai/db` 0.3.4's SQL vault repo imports it.
12
+
3
13
  ## 0.5.5 — 2026-10-13
4
14
 
5
15
  - New narrow subpaths for the existing OS helpers: `./command`, `./process`, `./toolchain`, `./proxy-env`, `./shell`, `./child-environment`. Importing one loads 1-2 modules instead of the root barrel's 181 (incl. undici). The root still exports everything; no signature change.
package/README.md CHANGED
@@ -14,8 +14,14 @@ that were split out of OD's monolithic daemon (see the archived provenance ledge
14
14
  npm install @jini-ai/platform
15
15
  ```
16
16
 
17
- No peer dependencies. `undici` is a regular dependency (used by the SSRF-safe asset cache's
18
- connection-time DNS-rebinding guard). Interactive terminal sessions (`createTerminalService`)
17
+ `undici@^7.25.0` is an optional peer for the SSRF-safe asset cache's default dispatcher.
18
+ Install it when calling `createAssetCacheDispatcher` or creating a cache without a host-supplied
19
+ guarded dispatcher. Root imports and `@jini-ai/platform/asset-cache` imports do not load undici;
20
+ the synchronous factory loads it on demand and reports a missing-peer error if it is absent.
21
+ The root declarations retain undici types, so TypeScript consumers of those declarations also
22
+ need the peer available. The dispatcher validates DNS at connection time, and cache `close()`
23
+ closes only its default dispatcher; a host-supplied dispatcher remains owned by the host.
24
+ Interactive terminal sessions (`createTerminalService`)
19
25
  need a `PtySpawn` implementation supplied by the caller — this package defines the `PtyProcess`/
20
26
  `PtySpawn` port only, it does not depend on `node-pty` itself, so bring your own adapter (or use
21
27
  `@jini-ai/daemon`'s, which wires a real `node-pty` behind the same port).
@@ -92,6 +98,20 @@ The package also exposes `./http/guarded`, `./mail`, `./mail/smtp`,
92
98
  `./fs/guarded-reader`, `./fs/durable-json`, and `./secrets`. New APIs take a required
93
99
  object followed by an optional object. Application identity and policy values belong to the caller.
94
100
 
101
+ `@jini-ai/platform/web` loads these optional peers at import time: `parse5@7.3.0`,
102
+ `hast-util-from-parse5@8.0.3`, `hast-util-to-mdast@10.1.2`,
103
+ `mdast-util-to-markdown@2.1.2`, and `mdast-util-gfm-table@2.0.0`. Install all five
104
+ when using that subpath; the other entries do not load them. Existing web consumers that
105
+ relied on transitive installation must add them before upgrading.
106
+
107
+ ```sh
108
+ npm install parse5@7.3.0 hast-util-from-parse5@8.0.3 hast-util-to-mdast@10.1.2 mdast-util-to-markdown@2.1.2 mdast-util-gfm-table@2.0.0
109
+ ```
110
+
111
+ The isolation metadata shares only the address classifiers (including their literal
112
+ endpoint policy), timeout wrapper and egress refusal class across domains. These
113
+ leaves retain one owner so HTTP and web adapters use the same security decisions.
114
+
95
115
  ```ts
96
116
  import { createHttpClient, createNodeGuardedHttpPorts, guardedFetch } from "@jini-ai/platform/http/guarded";
97
117
 
@@ -0,0 +1,9 @@
1
+ import type { LookupFunction } from 'node:net';
2
+ import type { Agent } from 'undici';
3
+ /** Load the optional vendor only for a default dispatcher; the cache owns lookup validation.
4
+ * @throws When the optional peer cannot be loaded or its Agent cannot be constructed.
5
+ */
6
+ export declare function createUndiciAssetCacheDispatcher({ lookup }: {
7
+ lookup: LookupFunction;
8
+ }, _options?: Record<string, never>): Agent;
9
+ //# sourceMappingURL=asset-cache.adapter.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+ /** Load the optional vendor only for a default dispatcher; the cache owns lookup validation.
4
+ * @throws When the optional peer cannot be loaded or its Agent cannot be constructed.
5
+ */
6
+ export function createUndiciAssetCacheDispatcher({ lookup }, _options = {}) {
7
+ const { Agent } = require('undici');
8
+ return new Agent({ connect: { lookup } });
9
+ }
10
+ //# sourceMappingURL=asset-cache.adapter.js.map
@@ -1,5 +1,5 @@
1
1
  import { lookup as dnsLookupCb } from 'node:dns';
2
- import { Agent, type Dispatcher } from 'undici';
2
+ import type { Agent, Dispatcher } from 'undici';
3
3
  /** Media extensions we are willing to cache + proxy. Anything else (HTML,
4
4
  * CSS, JS, fonts) is intentionally left alone so this surface never becomes a
5
5
  * general-purpose open proxy. */
@@ -52,7 +52,9 @@ export interface AssetCache {
52
52
  /** Closes only the default adapter; an injected dispatcher remains owned by its host. */
53
53
  close?(): Promise<void>;
54
54
  }
55
- /** Default adapter: validate DNS at connection time, so the checked address is the connected one. */
55
+ /** Default adapter: validate DNS at connection time, so the checked address is the connected one.
56
+ * @throws {AssetCacheError} When the host has not installed the optional undici peer.
57
+ */
56
58
  export declare function createAssetCacheDispatcher(_required: Record<string, never>, { lookupImpl }?: {
57
59
  lookupImpl?: DnsLookupCb;
58
60
  }): Agent;
@@ -24,7 +24,7 @@ import { lookup as dnsLookupCb } from 'node:dns';
24
24
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
25
25
  import { isIP } from 'node:net';
26
26
  import path from 'node:path';
27
- import { Agent } from 'undici';
27
+ import { createUndiciAssetCacheDispatcher } from './asset-cache.adapter.js';
28
28
  import { isPrivateAddress } from './net/address.js';
29
29
  /** Media extensions we are willing to cache + proxy. Anything else (HTML,
30
30
  * CSS, JS, fonts) is intentionally left alone so this surface never becomes a
@@ -127,9 +127,21 @@ export function createValidatingLookup(lookupImpl = dnsLookupCb) {
127
127
  });
128
128
  };
129
129
  }
130
- /** Default adapter: validate DNS at connection time, so the checked address is the connected one. */
130
+ /** Default adapter: validate DNS at connection time, so the checked address is the connected one.
131
+ * @throws {AssetCacheError} When the host has not installed the optional undici peer.
132
+ */
131
133
  export function createAssetCacheDispatcher(_required, { lookupImpl } = {}) {
132
- return new Agent({ connect: { lookup: createValidatingLookup(lookupImpl) } });
134
+ // Keep the factory synchronous while root imports and host-supplied dispatchers need no undici.
135
+ try {
136
+ return createUndiciAssetCacheDispatcher({ lookup: createValidatingLookup(lookupImpl) });
137
+ }
138
+ catch (error) {
139
+ if (error instanceof Error && error.code === 'MODULE_NOT_FOUND'
140
+ && error.message.split('\n')[0] === "Cannot find module 'undici'") {
141
+ throw new AssetCacheError(500, 'Asset cache dispatcher requires the optional peer "undici"; install undici@^7.25.0 or supply a guarded dispatcher.');
142
+ }
143
+ throw error;
144
+ }
133
145
  }
134
146
  /** Build a disk-backed cache for external sandboxed-content media. Concurrent
135
147
  * requests for the same URL share one in-flight fetch; completed fetches
@@ -36,7 +36,8 @@
36
36
  * **Also exported as its own subpath, `@jini-ai/platform/fetch-with-timeout`, deliberately.** This
37
37
  * module has zero imports of its own — no `node:*` builtin, no `undici` — unlike the package's root
38
38
  * barrel (`index.ts`), which re-exports sibling modules (`process.ts`, `fs.ts`, `terminal.ts`,
39
- * `asset-cache.ts`, …) that import `node:child_process`, `node:fs`, `undici`'s `Agent`, etc.
39
+ * `asset-cache.ts`, …) that import `node:child_process`, `node:fs`, etc.; the asset-cache
40
+ * dispatcher loads the optional `undici` peer only when its synchronous factory is called.
40
41
  * Importing from the root barrel in browser-bundled code is silently fine in a *production* build
41
42
  * through Vite/Rollup — tree-shaking (this package sets `sideEffects: false`) proves the Node-only
42
43
  * re-exports are unused and drops them before the `node:*` imports are ever resolved — but it is
@@ -36,7 +36,8 @@
36
36
  * **Also exported as its own subpath, `@jini-ai/platform/fetch-with-timeout`, deliberately.** This
37
37
  * module has zero imports of its own — no `node:*` builtin, no `undici` — unlike the package's root
38
38
  * barrel (`index.ts`), which re-exports sibling modules (`process.ts`, `fs.ts`, `terminal.ts`,
39
- * `asset-cache.ts`, …) that import `node:child_process`, `node:fs`, `undici`'s `Agent`, etc.
39
+ * `asset-cache.ts`, …) that import `node:child_process`, `node:fs`, etc.; the asset-cache
40
+ * dispatcher loads the optional `undici` peer only when its synchronous factory is called.
40
41
  * Importing from the root barrel in browser-bundled code is silently fine in a *production* build
41
42
  * through Vite/Rollup — tree-shaking (this package sets `sideEffects: false`) proves the Node-only
42
43
  * re-exports are unused and drops them before the `node:*` imports are ever resolved — but it is
@@ -0,0 +1,6 @@
1
+ /** Universal vault contracts and invariants, without service, keyring or storage adapters.
2
+ * Re-export the owner so aggregate callers and persistence adapters share VaultError identity.
3
+ * @example import { VaultError, type VaultRepoPort } from "@jini-ai/platform/secrets/credential-sets/contracts";
4
+ */
5
+ export * from "./vault.types.js";
6
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1,6 @@
1
+ /** Universal vault contracts and invariants, without service, keyring or storage adapters.
2
+ * Re-export the owner so aggregate callers and persistence adapters share VaultError identity.
3
+ * @example import { VaultError, type VaultRepoPort } from "@jini-ai/platform/secrets/credential-sets/contracts";
4
+ */
5
+ export * from "./vault.types.js";
6
+ //# sourceMappingURL=contracts.js.map
@@ -1,4 +1,5 @@
1
- /** Public-page projections and an anonymous reader over injected guarded HTTP ports. */
1
+ /** Public-page projections and an anonymous reader over injected guarded HTTP ports.
2
+ * Importing this entry requires the optional `parse5` peer listed in README.md. */
2
3
  export * from "./web-page.js";
3
4
  export * from "./html-document.js";
4
5
  export { htmlToMarkdown } from "./html-to-markdown.js";
package/dist/web/index.js CHANGED
@@ -1,4 +1,5 @@
1
- /** Public-page projections and an anonymous reader over injected guarded HTTP ports. */
1
+ /** Public-page projections and an anonymous reader over injected guarded HTTP ports.
2
+ * Importing this entry requires the optional `parse5` peer listed in README.md. */
2
3
  export * from "./web-page.js";
3
4
  export * from "./html-document.js";
4
5
  export { htmlToMarkdown } from "./html-to-markdown.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/platform",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Generic OS/platform primitives: process exec and lifecycle, filesystem containment, HTTP readiness polling, toolchain discovery, blob storage, AWS signing, and an SSRF-safe asset cache.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -15,8 +15,10 @@
15
15
  "entries": {
16
16
  ".": "node",
17
17
  "./fetch-with-timeout": "node",
18
+ "./asset-cache": "node",
18
19
  "./secrets": "node",
19
20
  "./secrets/credential-sets": "node",
21
+ "./secrets/credential-sets/contracts": "universal",
20
22
  "./secrets/testing": "node",
21
23
  "./http/guarded": "node",
22
24
  "./mail": "node",
@@ -44,7 +46,13 @@
44
46
  "./proxy-env": "os",
45
47
  "./shell": "os",
46
48
  "./child-environment": "os"
47
- }
49
+ },
50
+ "shared": [
51
+ "src/net/address.ts",
52
+ "src/net/endpoint-policy.ts",
53
+ "src/fetch-with-timeout.ts",
54
+ "src/http/guarded/errors.ts"
55
+ ]
48
56
  }
49
57
  },
50
58
  "type": "module",
@@ -62,6 +70,11 @@
62
70
  "import": "./dist/fetch-with-timeout.js",
63
71
  "default": "./dist/fetch-with-timeout.js"
64
72
  },
73
+ "./asset-cache": {
74
+ "types": "./dist/asset-cache.d.ts",
75
+ "import": "./dist/asset-cache.js",
76
+ "default": "./dist/asset-cache.js"
77
+ },
65
78
  "./secrets": {
66
79
  "types": "./dist/secrets/index.d.ts",
67
80
  "import": "./dist/secrets/index.js",
@@ -72,6 +85,11 @@
72
85
  "import": "./dist/secrets/credential-sets/index.js",
73
86
  "default": "./dist/secrets/credential-sets/index.js"
74
87
  },
88
+ "./secrets/credential-sets/contracts": {
89
+ "types": "./dist/secrets/credential-sets/contracts.d.ts",
90
+ "import": "./dist/secrets/credential-sets/contracts.js",
91
+ "default": "./dist/secrets/credential-sets/contracts.js"
92
+ },
75
93
  "./secrets/testing": {
76
94
  "types": "./dist/secrets/testing.d.ts",
77
95
  "import": "./dist/secrets/testing.js",
@@ -176,20 +194,48 @@
176
194
  "!dist/**/*.map"
177
195
  ],
178
196
  "dependencies": {
179
- "undici": "^7.25.0",
180
- "@jini-ai/core": "^0.4.0",
181
- "parse5": "7.3.0",
182
- "hast-util-from-parse5": "8.0.3",
183
- "hast-util-to-mdast": "10.1.2",
184
- "mdast-util-to-markdown": "2.1.2",
185
- "mdast-util-gfm-table": "2.0.0"
197
+ "@jini-ai/core": "^0.4.0"
186
198
  },
187
199
  "publishConfig": {
188
200
  "access": "public",
189
201
  "registry": "https://registry.npmjs.org"
190
202
  },
191
203
  "devDependencies": {
192
- "@vitest/coverage-v8": "^2.1.9"
204
+ "@vitest/coverage-v8": "^2.1.9",
205
+ "undici": "^7.25.0",
206
+ "hast-util-from-parse5": "8.0.3",
207
+ "hast-util-to-mdast": "10.1.2",
208
+ "mdast-util-to-markdown": "2.1.2",
209
+ "mdast-util-gfm-table": "2.0.0",
210
+ "parse5": "7.3.0"
211
+ },
212
+ "peerDependencies": {
213
+ "undici": "^7.25.0",
214
+ "hast-util-from-parse5": "8.0.3",
215
+ "hast-util-to-mdast": "10.1.2",
216
+ "mdast-util-to-markdown": "2.1.2",
217
+ "mdast-util-gfm-table": "2.0.0",
218
+ "parse5": "7.3.0"
219
+ },
220
+ "peerDependenciesMeta": {
221
+ "undici": {
222
+ "optional": true
223
+ },
224
+ "hast-util-from-parse5": {
225
+ "optional": true
226
+ },
227
+ "hast-util-to-mdast": {
228
+ "optional": true
229
+ },
230
+ "mdast-util-to-markdown": {
231
+ "optional": true
232
+ },
233
+ "mdast-util-gfm-table": {
234
+ "optional": true
235
+ },
236
+ "parse5": {
237
+ "optional": true
238
+ }
193
239
  },
194
240
  "scripts": {
195
241
  "build": "tsc -p tsconfig.json",