@jini-ai/platform 0.5.3 → 0.5.5

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,13 @@
1
1
  # @jini-ai/platform
2
2
 
3
+ ## 0.5.5 — 2026-10-13
4
+
5
+ - 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.
6
+
7
+ ## 0.5.4 — 2026-10-12
8
+
9
+ - Removed unused exports: `SecretsVaultService.commitPrepared`, `VaultCommitPreparedInput`, `VaultCopyInput.targetRevisions`, the pre-vault `InMemoryVendorCredentialSetRepo` and `buildVendorCredentialAad`. No known consumer; prepared records are committed through the vault repository's `put`/`applyBatch`.
10
+
3
11
  ## 0.5.2
4
12
 
5
13
  ### Patch Changes
package/README.md CHANGED
@@ -140,7 +140,7 @@ New factories/functions/methods accept a required object and, where needed, a se
140
140
  object. No-input operations take `{}`: `createNodeGuardedHttpPorts({})`,
141
141
  `createNodeGuardedReaderFilesystem({})`, `createNodeDurableJsonPorts({})`,
142
142
  `new FetchHttpTransportAdapter({})`, `new InMemoryTrashRepo({})`,
143
- `new InMemoryVendorCredentialSetRepo({})`, `keyring.activeKey({})`,
143
+ `keyring.activeKey({})`,
144
144
  `mailer.capabilities({})`, `clock.nowMs({})`, `clock.nowIso({})`, `random.token({})`,
145
145
  and `file.read({})`. SMTP ports receive `sendMail({ mail })`; `NodemailerPort` exposes the
146
146
  vendor-shaped `NativeSmtpTransport` so the factory adapts the payload once. Policy errors use
@@ -1,9 +1,7 @@
1
1
  export type { VendorCredentialSetRecord, VendorCredentialSetSummary, VendorCredentialSetRepoPort } from "./types.js";
2
- export { buildVendorCredentialAad } from "./aad.js";
3
- export { InMemoryVendorCredentialSetRepo } from "./repo.memory.js";
4
2
  export * from "./vault.types.js";
5
3
  export { buildVaultAad } from "./vault.aad.js";
6
4
  export { createVaultMetaParsers, isCopyableKind } from "./vault.meta.js";
7
- export { SecretsVaultService, type VaultServiceDeps, type VaultPutInput, type VaultCopyInput, type VaultCommitPreparedInput } from "./vault.service.js";
5
+ export { SecretsVaultService, type VaultServiceDeps, type VaultPutInput, type VaultCopyInput } from "./vault.service.js";
8
6
  export { InMemoryVaultRepo } from "./vault.repo.memory.js";
9
7
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,3 @@
1
- export { buildVendorCredentialAad } from "./aad.js";
2
- export { InMemoryVendorCredentialSetRepo } from "./repo.memory.js";
3
1
  export * from "./vault.types.js";
4
2
  export { buildVaultAad } from "./vault.aad.js";
5
3
  export { createVaultMetaParsers, isCopyableKind } from "./vault.meta.js";
@@ -31,15 +31,6 @@ export interface VaultPutInput extends VaultContext {
31
31
  /** A host-selected token, never a URI or serialized connection object. */
32
32
  hintToken?: string;
33
33
  }
34
- /** Prepared records contain envelopes and stay private to the host, never a public read model.
35
- * Expected revisions are mandatory for every ID; null means create-only. Deletes carry full
36
- * expected ownership. Default side effects follow repository operation order (records, deletes).
37
- */
38
- export interface VaultCommitPreparedInput {
39
- records: readonly VaultRecord[];
40
- deletes: readonly VaultIdentity[];
41
- expectedRevisions: Readonly<Record<string, number | null>>;
42
- }
43
34
  export interface VaultCopyInput {
44
35
  /** This service owns the source repository, authorization and keyring-backed sealer. */
45
36
  source: SecretsVaultService;
@@ -47,9 +38,8 @@ export interface VaultCopyInput {
47
38
  targetContext: VaultContext;
48
39
  ids: readonly string[];
49
40
  overwrite: boolean;
50
- /** Optional selection-time guards; otherwise the revisions read by this operation are used. */
41
+ /** Optional selection-time guard; otherwise the revisions read by this operation are used. */
51
42
  sourceRevisions?: Readonly<Record<string, number>>;
52
- targetRevisions?: Readonly<Record<string, number | null>>;
53
43
  }
54
44
  /** Shared vault lifecycle. Policy/catalogs are injected; persistence and encryption are ports.
55
45
  * Expected context is checked before opening. Normal reads have no legacy-AAD fallback.
@@ -68,15 +58,10 @@ export declare class SecretsVaultService {
68
58
  /** Authorize, validate and seal before the host enters its transaction, without persisting.
69
59
  * Replacements retain identity/createdAt; omitted payload preserves the existing envelope.
70
60
  * Commit must CAS again because preparation does not reserve a revision or a default.
71
- * @example const record = await vault.prepare(input); // pass to commitPrepared inside the host transaction
61
+ * Prepared records contain envelopes and stay private to the host, never a public read model.
62
+ * @example const record = await vault.prepare(input); await repo.put({ record, expectedRevision: input.expectedRevision }); // inside the host transaction
72
63
  */
73
64
  prepare(input: VaultPutInput, _options?: VaultOptions): Promise<VaultRecord>;
74
- /** Reauthorize prepared rows, validate ownership/metadata, then commit through the batch owner.
75
- * No plaintext is opened or sealed. Missing capability/revisions and duplicate identities fail
76
- * before writes; stale CAS or a later operation failure rolls back the whole repository batch.
77
- * @example await vault.commitPrepared({ records: [record], deletes: [], expectedRevisions: { [record.id]: null } });
78
- */
79
- commitPrepared(input: VaultCommitPreparedInput, _options?: VaultOptions): Promise<VaultSummary[]>;
80
65
  /** Authorized runtime read; returns plaintext only to the caller that supplied exact ownership. */
81
66
  get(input: VaultIdentity, _options?: VaultOptions): Promise<{
82
67
  summary: VaultSummary;
@@ -81,7 +81,8 @@ export class SecretsVaultService {
81
81
  /** Authorize, validate and seal before the host enters its transaction, without persisting.
82
82
  * Replacements retain identity/createdAt; omitted payload preserves the existing envelope.
83
83
  * Commit must CAS again because preparation does not reserve a revision or a default.
84
- * @example const record = await vault.prepare(input); // pass to commitPrepared inside the host transaction
84
+ * Prepared records contain envelopes and stay private to the host, never a public read model.
85
+ * @example const record = await vault.prepare(input); await repo.put({ record, expectedRevision: input.expectedRevision }); // inside the host transaction
85
86
  */
86
87
  async prepare(input, _options = {}) {
87
88
  assertContext(input);
@@ -109,42 +110,6 @@ export class SecretsVaultService {
109
110
  createdAt: existing?.createdAt ?? now, updatedAt: now };
110
111
  return record;
111
112
  }
112
- /** Reauthorize prepared rows, validate ownership/metadata, then commit through the batch owner.
113
- * No plaintext is opened or sealed. Missing capability/revisions and duplicate identities fail
114
- * before writes; stale CAS or a later operation failure rolls back the whole repository batch.
115
- * @example await vault.commitPrepared({ records: [record], deletes: [], expectedRevisions: { [record.id]: null } });
116
- */
117
- async commitPrepared(input, _options = {}) {
118
- if (!this.deps.repo.applyBatch)
119
- throw new VaultError({ code: "invalid-record" });
120
- const { records, deletes, expectedRevisions } = structuredClone(input);
121
- const identities = new Set();
122
- const ops = [];
123
- const entries = [...records.map(record => ({ put: record })), ...deletes.map(record => ({ delete: record }))];
124
- for (const entry of entries) {
125
- const record = "put" in entry ? entry.put : entry.delete;
126
- assertContext(record);
127
- const key = JSON.stringify([record.workspaceId, record.id]);
128
- if (identities.has(key) || !Object.hasOwn(expectedRevisions, record.id))
129
- throw new VaultError({ code: "invalid-record" });
130
- identities.add(key);
131
- const expectedRevision = expectedRevisions[record.id];
132
- const putting = "put" in entry;
133
- await this.authorize({ action: putting ? "put" : "delete", context: record });
134
- const existing = await this.find(record);
135
- if (expectedRevision === null ? existing !== null : existing?.revision !== expectedRevision)
136
- throw new VaultError({ code: "conflict" });
137
- if ("put" in entry)
138
- ops.push({ put: { record: this.parse(entry.put), expectedRevision } });
139
- else {
140
- if (expectedRevision === null)
141
- throw new VaultError({ code: "invalid-record" });
142
- ops.push({ delete: { workspaceId: record.workspaceId, id: record.id, expectedRevision } });
143
- }
144
- }
145
- const results = await this.deps.repo.applyBatch({ ops });
146
- return results.filter((result) => typeof result !== "boolean").map(summary);
147
- }
148
113
  /** Authorized runtime read; returns plaintext only to the caller that supplied exact ownership. */
149
114
  async get(input, _options = {}) {
150
115
  assertContext(input);
@@ -240,8 +205,6 @@ export class SecretsVaultService {
240
205
  if (existing && existing.provider !== record.provider)
241
206
  throw new VaultError({ code: "context" });
242
207
  const expectedRevision = existing?.revision ?? null;
243
- if (input.targetRevisions && Object.hasOwn(input.targetRevisions, id) && input.targetRevisions[id] !== expectedRevision)
244
- throw new VaultError({ code: "conflict" });
245
208
  const now = this.deps.now({});
246
209
  const candidate = this.parse({ ...record, ...targetIdentity, isDefault: existing?.isDefault ?? false,
247
210
  revision: (expectedRevision ?? 0) + 1, createdAt: existing?.createdAt ?? now, updatedAt: now });
@@ -111,7 +111,8 @@ export interface VaultRepoPort {
111
111
  findDefault?(input: VaultDefaultQuery, options?: VaultOptions): Promise<VaultRecord | null>;
112
112
  /** Optional additions keep older injected ports source-compatible; built-in adapters implement both. */
113
113
  findOne?(input: VaultSingletonQuery, options?: VaultOptions): Promise<VaultRecord | null>;
114
- /** All operations commit together or throw with no published changes.
114
+ /** All operations commit together or throw with no published changes. Default side effects
115
+ * follow operation order; a delete carries full expected ownership.
115
116
  * SQL joins the host transaction: callers must propagate failures to roll that transaction back.
116
117
  * @example await repo.applyBatch!({ ops: [{ put: { record, expectedRevision: null } }] });
117
118
  */
@@ -1,4 +1,3 @@
1
1
  export { InMemoryKeyring } from "./keyring.memory.js";
2
2
  export { FixedRootKeyKeyring } from "./keyring.env.js";
3
- export { InMemoryVendorCredentialSetRepo } from "./credential-sets/repo.memory.js";
4
3
  //# sourceMappingURL=testing.d.ts.map
@@ -1,4 +1,3 @@
1
1
  export { InMemoryKeyring } from "./keyring.memory.js";
2
2
  export { FixedRootKeyKeyring } from "./keyring.env.js";
3
- export { InMemoryVendorCredentialSetRepo } from "./credential-sets/repo.memory.js";
4
3
  //# sourceMappingURL=testing.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/platform",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
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": {
@@ -28,7 +28,23 @@
28
28
  "./net/endpoint-policy": "universal",
29
29
  "./fs/file-lock": "node",
30
30
  "./secrets/credential-token": "universal",
31
- "./web": "node"
31
+ "./web": "node",
32
+ "./command": "node",
33
+ "./process": "node",
34
+ "./toolchain": "node",
35
+ "./proxy-env": "node",
36
+ "./shell": "node",
37
+ "./child-environment": "node"
38
+ },
39
+ "isolation": {
40
+ "entries": {
41
+ "./command": "os",
42
+ "./process": "os",
43
+ "./toolchain": "os",
44
+ "./proxy-env": "os",
45
+ "./shell": "os",
46
+ "./child-environment": "os"
47
+ }
32
48
  }
33
49
  },
34
50
  "type": "module",
@@ -115,6 +131,36 @@
115
131
  "types": "./dist/web/index.d.ts",
116
132
  "import": "./dist/web/index.js",
117
133
  "default": "./dist/web/index.js"
134
+ },
135
+ "./command": {
136
+ "types": "./dist/command.d.ts",
137
+ "import": "./dist/command.js",
138
+ "default": "./dist/command.js"
139
+ },
140
+ "./process": {
141
+ "types": "./dist/process.d.ts",
142
+ "import": "./dist/process.js",
143
+ "default": "./dist/process.js"
144
+ },
145
+ "./toolchain": {
146
+ "types": "./dist/toolchain.d.ts",
147
+ "import": "./dist/toolchain.js",
148
+ "default": "./dist/toolchain.js"
149
+ },
150
+ "./proxy-env": {
151
+ "types": "./dist/proxy-env.d.ts",
152
+ "import": "./dist/proxy-env.js",
153
+ "default": "./dist/proxy-env.js"
154
+ },
155
+ "./shell": {
156
+ "types": "./dist/shell.d.ts",
157
+ "import": "./dist/shell.js",
158
+ "default": "./dist/shell.js"
159
+ },
160
+ "./child-environment": {
161
+ "types": "./dist/child-environment.d.ts",
162
+ "import": "./dist/child-environment.js",
163
+ "default": "./dist/child-environment.js"
118
164
  }
119
165
  },
120
166
  "files": [
@@ -1,7 +0,0 @@
1
- /** Stable v1 AAD binding workspace, vendor, and credential identity. */
2
- export declare function buildVendorCredentialAad(input: {
3
- workspaceId: string;
4
- vendorId: string;
5
- id: string;
6
- }): string;
7
- //# sourceMappingURL=aad.d.ts.map
@@ -1,7 +0,0 @@
1
- import { formatAad } from "../aad.js";
2
- const AAD_VERSION = "v1";
3
- /** Stable v1 AAD binding workspace, vendor, and credential identity. */
4
- export function buildVendorCredentialAad(input) {
5
- return formatAad({ kind: "vendor-credential-set", version: AAD_VERSION, parts: [input.workspaceId, input.vendorId, input.id] });
6
- }
7
- //# sourceMappingURL=aad.js.map
@@ -1,44 +0,0 @@
1
- import type { VendorCredentialSetRecord, VendorCredentialSetRepoPort } from "./types.js";
2
- /**
3
- * @file `VendorCredentialSetRepoPort`'s in-memory adapter — the ADR-006 rule-of-two test double,
4
- * mirroring `../deployments/publish-credentials/repo.memory.ts`'s shape byte-for-byte with
5
- * `providerId` swapped for `vendorId`. See that file's own header for the full reasoning (row
6
- * keying, the enforced UNIQUE constraint matching better-sqlite3's own error wording, why no
7
- * explicit lock is needed for the `isDefault` group invariant in a single-threaded JS process).
8
- */
9
- export declare class InMemoryVendorCredentialSetRepo implements VendorCredentialSetRepoPort {
10
- constructor(_required: Record<string, never>, _optional?: Record<string, never>);
11
- private readonly rows;
12
- private static rowKey;
13
- private assertLabelAvailable;
14
- private clearOtherDefaults;
15
- insert(record: VendorCredentialSetRecord, _optional?: Record<string, never>): Promise<void>;
16
- update(record: VendorCredentialSetRecord, _optional?: Record<string, never>): Promise<void>;
17
- findById(input: {
18
- workspaceId: string;
19
- id: string;
20
- }, _optional?: Record<string, never>): Promise<VendorCredentialSetRecord | null>;
21
- findDefaultByVendor(input: {
22
- workspaceId: string;
23
- vendorId: string;
24
- }, _optional?: Record<string, never>): Promise<VendorCredentialSetRecord | null>;
25
- listByVendor(input: {
26
- workspaceId: string;
27
- vendorId: string;
28
- }, _optional?: Record<string, never>): Promise<VendorCredentialSetRecord[]>;
29
- listByWorkspace(input: {
30
- workspaceId: string;
31
- }, _optional?: Record<string, never>): Promise<VendorCredentialSetRecord[]>;
32
- delete(input: {
33
- workspaceId: string;
34
- id: string;
35
- }, _optional?: Record<string, never>): Promise<void>;
36
- /** Mirrors the SQLite adapter's targeted single-column write — see
37
- * `VendorCredentialSetRepoPort.updateAccountLabel`'s own doc. No-op if the row vanished. */
38
- updateAccountLabel(input: {
39
- workspaceId: string;
40
- id: string;
41
- accountLabel: string;
42
- }, _optional?: Record<string, never>): Promise<void>;
43
- }
44
- //# sourceMappingURL=repo.memory.d.ts.map
@@ -1,80 +0,0 @@
1
- /**
2
- * @file `VendorCredentialSetRepoPort`'s in-memory adapter — the ADR-006 rule-of-two test double,
3
- * mirroring `../deployments/publish-credentials/repo.memory.ts`'s shape byte-for-byte with
4
- * `providerId` swapped for `vendorId`. See that file's own header for the full reasoning (row
5
- * keying, the enforced UNIQUE constraint matching better-sqlite3's own error wording, why no
6
- * explicit lock is needed for the `isDefault` group invariant in a single-threaded JS process).
7
- */
8
- export class InMemoryVendorCredentialSetRepo {
9
- constructor(_required, _optional = {}) { }
10
- rows = new Map();
11
- static rowKey(workspaceId, id) {
12
- return `${workspaceId}::${id}`;
13
- }
14
- assertLabelAvailable(workspaceId, vendorId, label, excludingId) {
15
- for (const row of this.rows.values()) {
16
- if (row.workspaceId !== workspaceId || row.vendorId !== vendorId || row.label !== label)
17
- continue;
18
- if (excludingId !== undefined && row.id === excludingId)
19
- continue;
20
- throw new Error(`UNIQUE constraint failed: vendor_credential_sets.workspace_id, vendor_credential_sets.vendor_id, vendor_credential_sets.label`);
21
- }
22
- }
23
- clearOtherDefaults(workspaceId, vendorId, keepId) {
24
- for (const [key, row] of this.rows) {
25
- if (row.workspaceId !== workspaceId || row.vendorId !== vendorId || row.id === keepId || !row.isDefault)
26
- continue;
27
- this.rows.set(key, { ...row, isDefault: false });
28
- }
29
- }
30
- async insert(record, _optional = {}) {
31
- this.assertLabelAvailable(record.workspaceId, record.vendorId, record.label);
32
- this.rows.set(InMemoryVendorCredentialSetRepo.rowKey(record.workspaceId, record.id), { ...record });
33
- if (record.isDefault)
34
- this.clearOtherDefaults(record.workspaceId, record.vendorId, record.id);
35
- }
36
- async update(record, _optional = {}) {
37
- this.assertLabelAvailable(record.workspaceId, record.vendorId, record.label, record.id);
38
- this.rows.set(InMemoryVendorCredentialSetRepo.rowKey(record.workspaceId, record.id), { ...record });
39
- if (record.isDefault)
40
- this.clearOtherDefaults(record.workspaceId, record.vendorId, record.id);
41
- }
42
- async findById(input, _optional = {}) {
43
- return this.rows.get(InMemoryVendorCredentialSetRepo.rowKey(input.workspaceId, input.id)) ?? null;
44
- }
45
- async findDefaultByVendor(input, _optional = {}) {
46
- for (const row of this.rows.values()) {
47
- if (row.workspaceId === input.workspaceId && row.vendorId === input.vendorId && row.isDefault)
48
- return row;
49
- }
50
- return null;
51
- }
52
- async listByVendor(input, _optional = {}) {
53
- return [...this.rows.values()].filter((row) => row.workspaceId === input.workspaceId && row.vendorId === input.vendorId);
54
- }
55
- async listByWorkspace(input, _optional = {}) {
56
- return [...this.rows.values()].filter((row) => row.workspaceId === input.workspaceId);
57
- }
58
- async delete(input, _optional = {}) {
59
- const key = InMemoryVendorCredentialSetRepo.rowKey(input.workspaceId, input.id);
60
- const removed = this.rows.get(key);
61
- this.rows.delete(key);
62
- if (!removed?.isDefault)
63
- return;
64
- const remaining = [...this.rows.values()].filter((row) => row.workspaceId === removed.workspaceId && row.vendorId === removed.vendorId);
65
- if (remaining.length === 0)
66
- return;
67
- const promoted = remaining.reduce((latest, row) => (row.updatedAt > latest.updatedAt ? row : latest));
68
- this.rows.set(InMemoryVendorCredentialSetRepo.rowKey(promoted.workspaceId, promoted.id), { ...promoted, isDefault: true });
69
- }
70
- /** Mirrors the SQLite adapter's targeted single-column write — see
71
- * `VendorCredentialSetRepoPort.updateAccountLabel`'s own doc. No-op if the row vanished. */
72
- async updateAccountLabel(input, _optional = {}) {
73
- const key = InMemoryVendorCredentialSetRepo.rowKey(input.workspaceId, input.id);
74
- const existing = this.rows.get(key);
75
- if (!existing)
76
- return;
77
- this.rows.set(key, { ...existing, accountLabel: input.accountLabel });
78
- }
79
- }
80
- //# sourceMappingURL=repo.memory.js.map