@jini-ai/platform 0.5.2 → 0.5.4

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/dist/asset-cache.d.ts +12 -1
  4. package/dist/asset-cache.js +9 -5
  5. package/dist/child-environment.d.ts +18 -0
  6. package/dist/child-environment.js +26 -0
  7. package/dist/fs/boot-identity.d.ts +10 -0
  8. package/dist/fs/boot-identity.js +34 -0
  9. package/dist/fs/directory-home.d.ts +15 -0
  10. package/dist/fs/directory-home.js +17 -0
  11. package/dist/fs/directory-registry.d.ts +50 -0
  12. package/dist/fs/directory-registry.js +99 -0
  13. package/dist/fs/directory-running-lock.d.ts +43 -0
  14. package/dist/fs/directory-running-lock.js +66 -0
  15. package/dist/fs/directory-sync.d.ts +20 -0
  16. package/dist/fs/directory-sync.js +87 -0
  17. package/dist/fs/directory-user-config.d.ts +79 -0
  18. package/dist/fs/directory-user-config.js +183 -0
  19. package/dist/fs/directory-workspace.d.ts +132 -0
  20. package/dist/fs/directory-workspace.js +266 -0
  21. package/dist/fs/durable-json.d.ts +21 -0
  22. package/dist/fs/durable-json.js +59 -4
  23. package/dist/fs/file-lock.d.ts +3 -0
  24. package/dist/fs/file-lock.js +16 -7
  25. package/dist/fs/index.d.ts +6 -0
  26. package/dist/fs/index.js +6 -0
  27. package/dist/fs/user-data-directories.d.ts +28 -0
  28. package/dist/fs/user-data-directories.js +53 -0
  29. package/dist/fs/verified-directory-move.d.ts +37 -0
  30. package/dist/fs/verified-directory-move.js +138 -0
  31. package/dist/fs/verified-file-relocation.d.ts +27 -0
  32. package/dist/fs/verified-file-relocation.js +115 -0
  33. package/dist/fs/workspace-directory.d.ts +19 -0
  34. package/dist/fs/workspace-directory.js +23 -0
  35. package/dist/index.d.ts +2 -1
  36. package/dist/index.js +2 -1
  37. package/dist/secrets/credential-sets/index.d.ts +5 -2
  38. package/dist/secrets/credential-sets/index.js +5 -2
  39. package/dist/secrets/credential-sets/vault.aad.d.ts +4 -0
  40. package/dist/secrets/credential-sets/vault.aad.js +8 -0
  41. package/dist/secrets/credential-sets/vault.meta.d.ts +10 -0
  42. package/dist/secrets/credential-sets/vault.meta.js +52 -0
  43. package/dist/secrets/credential-sets/vault.repo.memory.d.ts +51 -0
  44. package/dist/secrets/credential-sets/vault.repo.memory.js +148 -0
  45. package/dist/secrets/credential-sets/vault.service.d.ts +115 -0
  46. package/dist/secrets/credential-sets/vault.service.js +273 -0
  47. package/dist/secrets/credential-sets/vault.types.d.ts +151 -0
  48. package/dist/secrets/credential-sets/vault.types.js +28 -0
  49. package/dist/secrets/testing.d.ts +0 -1
  50. package/dist/secrets/testing.js +0 -1
  51. package/dist/web/html-document.d.ts +70 -0
  52. package/dist/web/html-document.js +268 -0
  53. package/dist/web/html-resource.d.ts +15 -0
  54. package/dist/web/html-resource.js +12 -0
  55. package/dist/web/html-to-markdown.d.ts +11 -0
  56. package/dist/web/html-to-markdown.js +245 -0
  57. package/dist/web/index.d.ts +5 -0
  58. package/dist/web/index.js +5 -0
  59. package/dist/web/web-page.d.ts +157 -0
  60. package/dist/web/web-page.js +310 -0
  61. package/package.json +14 -3
  62. package/dist/secrets/credential-sets/aad.d.ts +0 -7
  63. package/dist/secrets/credential-sets/aad.js +0 -7
  64. package/dist/secrets/credential-sets/repo.memory.d.ts +0 -44
  65. package/dist/secrets/credential-sets/repo.memory.js +0 -80
@@ -0,0 +1,138 @@
1
+ import { stageVerifiedFileRelocation } from "./verified-file-relocation.js";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ /** Fingerprint relative names, entry kinds, symlink targets and file bytes without following links.
6
+ * This is verification, never a log of file contents. Lease files are excluded by the host.
7
+ * @complexity O(bytes + entries log entries), O(entries + a fixed 64 KiB read buffer) space.
8
+ */
9
+ export function directoryFingerprint({ dir }, { excluded = [], filesystem = fs } = {}) {
10
+ const digest = createHash("sha256");
11
+ function visit(relative) {
12
+ for (const entry of filesystem.readdirSync(path.join(dir, relative), { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
13
+ if (!relative && excluded.includes(entry.name))
14
+ continue;
15
+ const name = path.join(relative, entry.name), absolute = path.join(dir, name);
16
+ const stat = filesystem.lstatSync(absolute);
17
+ const kind = stat.isSymbolicLink() ? "link" : stat.isDirectory() ? "directory" : stat.isFile() ? "file" : "unsupported";
18
+ if (kind === "unsupported")
19
+ throw new Error(`Cannot move special filesystem entry: ${name}`);
20
+ digest.update(JSON.stringify([name, kind, stat.mode & 0o777]));
21
+ if (kind === "directory")
22
+ visit(name);
23
+ else if (kind === "link")
24
+ digest.update(JSON.stringify(filesystem.readlinkSync(absolute)));
25
+ else {
26
+ const fileDigest = createHash("sha256"), buffer = Buffer.allocUnsafe(64 * 1024);
27
+ const descriptor = filesystem.openSync(absolute, "r");
28
+ try {
29
+ let bytes;
30
+ while ((bytes = filesystem.readSync(descriptor, buffer, 0, buffer.length, null)) > 0)
31
+ fileDigest.update(buffer.subarray(0, bytes));
32
+ }
33
+ finally {
34
+ filesystem.closeSync(descriptor);
35
+ }
36
+ digest.update(fileDigest.digest());
37
+ }
38
+ }
39
+ }
40
+ visit("");
41
+ return digest.digest("hex");
42
+ }
43
+ /** Move only into an absent target. Verify before registry commit or source deletion.
44
+ * EXDEV uses copy/verify/retire/commit; failure restores the source and removes only our new copy.
45
+ * Same-filesystem failures roll the rename back. Commit must atomically update the host registry.
46
+ * @complexity O(bytes + entries log entries), with two verification passes.
47
+ */
48
+ export function moveDirectoryVerified({ from, to, commit }, { excluded = [], filesystem = fs, prepareDestination, relocateFiles, verifyFile, backupId = randomUUID } = {}) {
49
+ const source = filesystem.realpathSync(from);
50
+ const target = path.resolve(to);
51
+ if (target === source || target.startsWith(source + path.sep))
52
+ throw new Error("A directory cannot be moved into itself.");
53
+ try {
54
+ filesystem.lstatSync(target);
55
+ throw new Error(`Move target already exists: ${target}`);
56
+ }
57
+ catch (error) {
58
+ if (error.code !== "ENOENT")
59
+ throw error;
60
+ }
61
+ const before = directoryFingerprint({ dir: source }, { excluded, filesystem });
62
+ let copied = false;
63
+ try {
64
+ filesystem.renameSync(source, target);
65
+ }
66
+ catch (error) {
67
+ if (error.code !== "EXDEV")
68
+ throw error;
69
+ filesystem.mkdirSync(target);
70
+ copied = true;
71
+ try {
72
+ // The host may reserve the empty destination before any commit marker or database is copied.
73
+ prepareDestination?.({ path: target });
74
+ filesystem.cpSync(source, target, { recursive: true, force: false, errorOnExist: true, preserveTimestamps: true, verbatimSymlinks: true,
75
+ filter: (candidate) => candidate === source || !excluded.includes(path.relative(source, candidate).split(path.sep)[0]),
76
+ });
77
+ }
78
+ catch (failure) {
79
+ filesystem.rmSync(target, { recursive: true });
80
+ throw failure;
81
+ }
82
+ }
83
+ let retiredSource;
84
+ let staged;
85
+ try {
86
+ if (directoryFingerprint({ dir: target }, { excluded, filesystem }) !== before)
87
+ throw new Error("Moved directory verification failed.");
88
+ if (relocateFiles) {
89
+ if (!verifyFile)
90
+ throw new Error("File relocation requires a verification port.");
91
+ staged = stageVerifiedFileRelocation({ groups: relocateFiles({ source, target }), verify: verifyFile }, { filesystem, backupId, backupCovered: ({ from }) => copied && path.resolve(from).startsWith(target + path.sep) });
92
+ }
93
+ if (copied) {
94
+ const backupRoot = path.join(path.dirname(source), `.relocation-${backupId()}-backup`);
95
+ const backup = path.join(backupRoot, path.basename(source));
96
+ if (filesystem.existsSync(backup))
97
+ throw new Error(`Move backup target already exists: ${backup}`);
98
+ // The EXDEV original becomes a recovery folder before catalog commit, never a second live
99
+ // site at the old path if cleanup fails. An interrupted apply leaves explicit backups.
100
+ filesystem.mkdirSync(backupRoot);
101
+ filesystem.renameSync(source, backup);
102
+ retiredSource = backup;
103
+ const fd = filesystem.openSync(backupRoot, "r");
104
+ try {
105
+ filesystem.fsyncSync(fd);
106
+ }
107
+ finally {
108
+ filesystem.closeSync(fd);
109
+ }
110
+ }
111
+ // Persist directory-name changes for same-filesystem renames as well as EXDEV retirement.
112
+ for (const directory of new Set([path.dirname(source), path.dirname(target)])) {
113
+ const fd = filesystem.openSync(directory, "r");
114
+ try {
115
+ filesystem.fsyncSync(fd);
116
+ }
117
+ finally {
118
+ filesystem.closeSync(fd);
119
+ }
120
+ }
121
+ commit();
122
+ }
123
+ catch (error) {
124
+ if (retiredSource)
125
+ filesystem.renameSync(retiredSource, source);
126
+ staged?.rollback();
127
+ if (copied)
128
+ filesystem.rmSync(target, { recursive: true });
129
+ else
130
+ filesystem.renameSync(target, source);
131
+ throw error;
132
+ }
133
+ // If deletion fails after commit, the verified target and registry remain usable; old DB live
134
+ // names were already retired before commit. Never roll back a registry whose commit succeeded.
135
+ staged?.finalize();
136
+ // Keep the retired EXDEV recovery folder; it is never a registered/live site path.
137
+ }
138
+ //# sourceMappingURL=verified-directory-move.js.map
@@ -0,0 +1,27 @@
1
+ import fs from "node:fs";
2
+ export interface VerifiedFileGroup {
3
+ from: string;
4
+ to: string;
5
+ sidecars: readonly string[];
6
+ }
7
+ /** Stage related files together while both directory identities are reserved by the host. Raw
8
+ * sources remain intact through inspection so even WAL/SHM bytes are retained. Verification opens only
9
+ * stopped databases through an injected read-only inspector; the filesystem owner never uses SQL.
10
+ * @complexity O(total bytes + verification cost), bounded memory via native file copies.
11
+ */
12
+ export declare function stageVerifiedFileRelocation({ groups, verify }: {
13
+ groups: readonly VerifiedFileGroup[];
14
+ verify: (required: {
15
+ path: string;
16
+ }) => string;
17
+ }, { filesystem, backupCovered, backupId }?: {
18
+ filesystem?: typeof fs;
19
+ backupCovered?: (required: {
20
+ from: string;
21
+ }) => boolean;
22
+ backupId?: () => string;
23
+ }): {
24
+ rollback: () => void;
25
+ finalize: () => void;
26
+ };
27
+ //# sourceMappingURL=verified-file-relocation.d.ts.map
@@ -0,0 +1,115 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ /** Stage related files together while both directory identities are reserved by the host. Raw
5
+ * sources remain intact through inspection so even WAL/SHM bytes are retained. Verification opens only
6
+ * stopped databases through an injected read-only inspector; the filesystem owner never uses SQL.
7
+ * @complexity O(total bytes + verification cost), bounded memory via native file copies.
8
+ */
9
+ export function stageVerifiedFileRelocation({ groups, verify }, { filesystem = fs, backupCovered = () => false, backupId = randomUUID } = {}) {
10
+ const created = [], retired = [], markers = [], redundantBackups = [];
11
+ const backupSuffix = `.relocation-${backupId()}-backup`;
12
+ const copyExclusive = (from, to) => {
13
+ // Reserve before copying so a disk-full failure is still ours to clean up. COPYFILE_EXCL
14
+ // alone may create a partial file before throwing, which cannot be tracked after the fact.
15
+ const fd = filesystem.openSync(to, "wx");
16
+ created.push(to);
17
+ filesystem.closeSync(fd);
18
+ filesystem.copyFileSync(from, to);
19
+ const copied = filesystem.openSync(to, "r+");
20
+ try {
21
+ filesystem.fsyncSync(copied);
22
+ }
23
+ finally {
24
+ filesystem.closeSync(copied);
25
+ }
26
+ syncParent(to);
27
+ };
28
+ const syncParent = (file) => {
29
+ // Directory fsync persists retirement/marker ordering before the host commits its catalog.
30
+ const fd = filesystem.openSync(path.dirname(file), "r");
31
+ try {
32
+ filesystem.fsyncSync(fd);
33
+ }
34
+ finally {
35
+ filesystem.closeSync(fd);
36
+ }
37
+ };
38
+ const rollback = () => {
39
+ for (const item of [...retired].reverse()) {
40
+ filesystem.renameSync(item.backup, item.from);
41
+ syncParent(item.from);
42
+ }
43
+ for (const file of [...created].reverse()) {
44
+ filesystem.rmSync(file, { force: true });
45
+ syncParent(file);
46
+ }
47
+ };
48
+ try {
49
+ for (const group of groups) {
50
+ const pairs = ["", ...group.sidecars].filter((suffix) => filesystem.existsSync(group.from + suffix))
51
+ .map((suffix) => ({ from: group.from + suffix, to: group.to + suffix }));
52
+ for (const pair of pairs)
53
+ if (!filesystem.lstatSync(pair.from).isFile())
54
+ throw new Error(`Database move requires a regular file: ${pair.from}`);
55
+ filesystem.mkdirSync(path.dirname(group.to), { recursive: true });
56
+ const moving = path.resolve(group.from) !== path.resolve(group.to);
57
+ // A directory rename already carries unchanged DB paths atomically; verify those bytes
58
+ // without copying them. For a file move the original inode becomes the sole backup after
59
+ // verification: another full destination backup doubles storage without rollback benefit.
60
+ // Cross-volume directory moves already retain the untouched original directory. A copied
61
+ // DB inside that destination needs no second full backup of the same bytes.
62
+ if (moving) {
63
+ const marker = group.from + ".home2-relocation.json";
64
+ const fd = filesystem.openSync(marker, "wx");
65
+ created.push(marker);
66
+ markers.push(marker);
67
+ try {
68
+ filesystem.writeFileSync(fd, JSON.stringify({ to: group.to, backup: group.from + backupSuffix }));
69
+ filesystem.fsyncSync(fd);
70
+ }
71
+ finally {
72
+ filesystem.closeSync(fd);
73
+ }
74
+ syncParent(marker);
75
+ }
76
+ const before = verify({ path: group.from });
77
+ for (const pair of pairs) {
78
+ if (path.resolve(pair.from) === path.resolve(pair.to))
79
+ continue;
80
+ // A destination collision aborts; never overwrite another site's data or an old move.
81
+ copyExclusive(pair.from, pair.to);
82
+ }
83
+ if (verify({ path: group.to }) !== before)
84
+ throw new Error(`Database row counts changed while moving ${path.basename(group.to)}.`);
85
+ // Retire old live names BEFORE commit. Finalization removes recovery markers and redundant copies covered by the retained original: a crash
86
+ // or cleanup failure cannot leave two independently writable database names after commit.
87
+ if (moving)
88
+ for (const pair of pairs) {
89
+ const backup = pair.from + backupSuffix;
90
+ if (filesystem.existsSync(backup))
91
+ throw new Error(`Database backup target already exists: ${backup}`);
92
+ filesystem.renameSync(pair.from, backup);
93
+ retired.push({ from: pair.from, backup });
94
+ if (backupCovered({ from: pair.from }))
95
+ redundantBackups.push(backup);
96
+ syncParent(pair.from);
97
+ }
98
+ }
99
+ }
100
+ catch (error) {
101
+ rollback();
102
+ throw error;
103
+ }
104
+ return { rollback, finalize: () => {
105
+ for (const backup of redundantBackups) {
106
+ filesystem.rmSync(backup);
107
+ syncParent(backup);
108
+ }
109
+ for (const marker of markers) {
110
+ filesystem.rmSync(marker);
111
+ syncParent(marker);
112
+ }
113
+ } };
114
+ }
115
+ //# sourceMappingURL=verified-file-relocation.js.map
@@ -0,0 +1,19 @@
1
+ import type { DirectoryRecord } from "./directory-registry.js";
2
+ /** Shared selection policy for CLI/dev hosts. A registry ID disambiguates adopted paths;
3
+ * a basename selects the home first. No initialized home site preserves the supplied fallback.
4
+ * @complexity O(n) registered/child directories and validation probes.
5
+ */
6
+ export declare function selectWorkspaceDirectory({ home, entries, fallback, selected, roots, listDirectories, isInitialized }: {
7
+ home: string;
8
+ entries: readonly DirectoryRecord[];
9
+ fallback: string;
10
+ selected?: string | undefined;
11
+ roots?: readonly string[];
12
+ listDirectories: (required: {
13
+ root: string;
14
+ }) => readonly string[];
15
+ isInitialized: (required: {
16
+ path: string;
17
+ }) => boolean;
18
+ }, _options?: {}): string;
19
+ //# sourceMappingURL=workspace-directory.d.ts.map
@@ -0,0 +1,23 @@
1
+ import path from "node:path";
2
+ /** Shared selection policy for CLI/dev hosts. A registry ID disambiguates adopted paths;
3
+ * a basename selects the home first. No initialized home site preserves the supplied fallback.
4
+ * @complexity O(n) registered/child directories and validation probes.
5
+ */
6
+ export function selectWorkspaceDirectory({ home, entries, fallback, selected, roots = [home], listDirectories, isInitialized }, _options = {}) {
7
+ if (selected !== undefined) {
8
+ const byId = entries.find((entry) => entry.id === selected);
9
+ if (byId)
10
+ return byId.path;
11
+ const inHome = path.join(home, selected);
12
+ if (isInitialized({ path: inHome }))
13
+ return inHome;
14
+ const matches = [...new Set([...entries.filter((entry) => path.basename(entry.path) === selected).map((entry) => entry.path),
15
+ ...roots.filter((root) => root !== home).map((root) => path.join(root, selected)).filter((dir) => isInitialized({ path: dir }))])];
16
+ if (matches.length > 1)
17
+ throw new Error("More than one registered directory has this name. Select its registry ID.");
18
+ return matches[0] ?? path.join(path.dirname(fallback), selected);
19
+ }
20
+ const candidates = [...entries.filter((entry) => path.dirname(entry.path) === home).sort((a, b) => (b.lastOpened ? Date.parse(b.lastOpened) : 0) - (a.lastOpened ? Date.parse(a.lastOpened) : 0)).map((entry) => entry.path), ...roots.flatMap((root) => listDirectories({ root }))];
21
+ return candidates.find((dir) => isInitialized({ path: dir })) ?? fallback;
22
+ }
23
+ //# sourceMappingURL=workspace-directory.js.map
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@
33
33
  */
34
34
  export type { CommandInvocation, CommandInvocationRequest } from "./command.js";
35
35
  export { createCommandInvocation, createPackageManagerInvocation } from "./command.js";
36
+ export { omitEnvironmentKeys } from "./child-environment.js";
36
37
  export type { ResolveSystemProxyEnvOptions, SystemProxyCommandRunner } from "./proxy-env.js";
37
38
  export { mergeProxyAwareEnv, parseMacosScutilProxyOutput, parseWindowsInternetSettingsProxyOutput, resolveSystemProxyEnv, } from "./proxy-env.js";
38
39
  export type { ProcessSnapshot, ProcessStampContract, ProcessStampField, ProcessStampShape, SpawnProcessRequest, StampedProcessMatchCriteria, StopProcessesResult, } from "./process.js";
@@ -48,7 +49,7 @@ export { wellKnownUserToolchainBins } from "./toolchain.js";
48
49
  export type { BufferedCommandResult } from "./shell.js";
49
50
  export { execCommandViaLoginShell, execFileBuffered } from "./shell.js";
50
51
  export type { AssetCache, AssetCacheOptions, AssetCacheResult } from "./asset-cache.js";
51
- export { AssetCacheError, assertSafePublicUrl, assetCacheKey, assetCacheRewriteUrl, createAssetCache, createValidatingLookup, isCacheableExternalUrl, } from "./asset-cache.js";
52
+ export { AssetCacheError, assertSafePublicUrl, assetCacheKey, assetCacheRewriteUrl, createAssetCache, createAssetCacheDispatcher, createValidatingLookup, isCacheableExternalUrl, } from "./asset-cache.js";
52
53
  export { expandHomePrefix, resolveProjectRelativePath } from "./home-expansion.js";
53
54
  export type { SandboxEnvConfig, SandboxRuntimeConfig, SandboxRuntimeRoots } from "./sandbox-env.js";
54
55
  export { applySandboxRuntimeEnv, ensureSandboxRuntimeDirs, isSandboxImportedProjectRootAllowed, isSandboxModeEnabled, resolveSandboxRuntimeConfig, resolveSandboxRuntimeConfigFromEnv, sandboxAgentProfilesConfigPath, sandboxImportAllowedRoots, sandboxImportedProjectRootUnavailableReason, } from "./sandbox-env.js";
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@
32
32
  * Filesystem/network storage and its SigV4 signing belong here, with no kernel SQL-port dependency.
33
33
  */
34
34
  export { createCommandInvocation, createPackageManagerInvocation } from "./command.js";
35
+ export { omitEnvironmentKeys } from "./child-environment.js";
35
36
  export { mergeProxyAwareEnv, parseMacosScutilProxyOutput, parseWindowsInternetSettingsProxyOutput, resolveSystemProxyEnv, } from "./proxy-env.js";
36
37
  export { collectProcessTreePids, createProcessStampArgs, isProcessAlive, listProcessSnapshots, matchesProcessStamp, matchesStampedProcess, readFlagValue, readProcessStamp, readProcessStampFromCommand, spawnBackgroundProcess, spawnLoggedProcess, stopProcesses, waitForProcessExit, } from "./process.js";
37
38
  export { atomicCopyFile, pathContains, readLogTail, removePathBestEffort } from "./fs.js";
@@ -39,7 +40,7 @@ export { waitForHttpOk } from "./http.js";
39
40
  export { FETCH_TIMEOUT_MS, FetchTimeoutError, fetchWithTimeout } from "./fetch-with-timeout.js";
40
41
  export { wellKnownUserToolchainBins } from "./toolchain.js";
41
42
  export { execCommandViaLoginShell, execFileBuffered } from "./shell.js";
42
- export { AssetCacheError, assertSafePublicUrl, assetCacheKey, assetCacheRewriteUrl, createAssetCache, createValidatingLookup, isCacheableExternalUrl, } from "./asset-cache.js";
43
+ export { AssetCacheError, assertSafePublicUrl, assetCacheKey, assetCacheRewriteUrl, createAssetCache, createAssetCacheDispatcher, createValidatingLookup, isCacheableExternalUrl, } from "./asset-cache.js";
43
44
  export { expandHomePrefix, resolveProjectRelativePath } from "./home-expansion.js";
44
45
  export { applySandboxRuntimeEnv, ensureSandboxRuntimeDirs, isSandboxImportedProjectRootAllowed, isSandboxModeEnabled, resolveSandboxRuntimeConfig, resolveSandboxRuntimeConfigFromEnv, sandboxAgentProfilesConfigPath, sandboxImportAllowedRoots, sandboxImportedProjectRootUnavailableReason, } from "./sandbox-env.js";
45
46
  export { resolveDaemonCliPath, resolveDaemonPluginPreviewsDir, resolveDaemonResourceDir, resolveDaemonResourceRoot, resolveDataDir, resolveProcessResourcesPath, } from "./resource-paths.js";
@@ -1,4 +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";
2
+ export * from "./vault.types.js";
3
+ export { buildVaultAad } from "./vault.aad.js";
4
+ export { createVaultMetaParsers, isCopyableKind } from "./vault.meta.js";
5
+ export { SecretsVaultService, type VaultServiceDeps, type VaultPutInput, type VaultCopyInput } from "./vault.service.js";
6
+ export { InMemoryVaultRepo } from "./vault.repo.memory.js";
4
7
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,6 @@
1
- export { buildVendorCredentialAad } from "./aad.js";
2
- export { InMemoryVendorCredentialSetRepo } from "./repo.memory.js";
1
+ export * from "./vault.types.js";
2
+ export { buildVaultAad } from "./vault.aad.js";
3
+ export { createVaultMetaParsers, isCopyableKind } from "./vault.meta.js";
4
+ export { SecretsVaultService } from "./vault.service.js";
5
+ export { InMemoryVaultRepo } from "./vault.repo.memory.js";
3
6
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ import type { VaultIdentity, VaultOptions } from "./vault.types.js";
2
+ /** JSON tuple encoding prevents colons or separators in host identifiers aliasing another row. */
3
+ export declare function buildVaultAad(input: VaultIdentity, _options?: VaultOptions): string;
4
+ //# sourceMappingURL=vault.aad.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { formatAad } from "../aad.js";
2
+ /** JSON tuple encoding prevents colons or separators in host identifiers aliasing another row. */
3
+ export function buildVaultAad(input, _options = {}) {
4
+ return formatAad({ kind: "secrets-vault", version: "v1", parts: [JSON.stringify([
5
+ input.workspaceId, input.id, input.kind, input.ownerKey, input.principalId, input.binding,
6
+ ])] });
7
+ }
8
+ //# sourceMappingURL=vault.aad.js.map
@@ -0,0 +1,10 @@
1
+ import { type VaultKind, type VaultMetaParsers, type VaultOptions } from "./vault.types.js";
2
+ /** Copy eligibility lives with the kind contracts; MCP rows require their server configuration. */
3
+ export declare const isCopyableKind: Readonly<Record<VaultKind, boolean>>;
4
+ /** Minimal structural parsers. Hosts inject catalog, URL/origin and safe-metadata policy here;
5
+ * secrets stay in payload JSON. Overrides own the complete shape, including merged patches.
6
+ */
7
+ export declare function createVaultMetaParsers(_required: VaultOptions, { parsers }?: {
8
+ parsers?: Partial<VaultMetaParsers>;
9
+ }): VaultMetaParsers;
10
+ //# sourceMappingURL=vault.meta.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { VAULT_KINDS, VaultError } from "./vault.types.js";
2
+ /** Copy eligibility lives with the kind contracts; MCP rows require their server configuration. */
3
+ export const isCopyableKind = Object.freeze({
4
+ "site-assistant": true, "personal-execution": false, "media-provider": true, custom: true,
5
+ "publish-peer": true, "database-destination": true, vendor: true, "source-control": true,
6
+ "mcp-env": false, "mcp-auth": false,
7
+ });
8
+ const FIELDS = {
9
+ "site-assistant": { baseUrl: "string", model: "string" },
10
+ "personal-execution": { protocol: "string", baseUrl: "string", model: "string", maxTokens: "number" },
11
+ "media-provider": { baseUrl: "string", model: "string" },
12
+ custom: { category: "string", baseUrl: "string", additionalHosts: "strings", username: "string" },
13
+ "publish-peer": { baseUrl: "string", remoteWorkspaceId: "string" },
14
+ "database-destination": { description: "object", lastRun: "object" },
15
+ vendor: { accountLabel: "string" }, "source-control": { accountLabel: "string" },
16
+ "mcp-env": {}, "mcp-auth": {},
17
+ };
18
+ function isObject(value) {
19
+ return value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype;
20
+ }
21
+ function isJson(value) {
22
+ if (value === null || typeof value === "string" || typeof value === "boolean")
23
+ return true;
24
+ if (typeof value === "number")
25
+ return Number.isFinite(value);
26
+ if (Array.isArray(value))
27
+ return value.every(isJson);
28
+ return isObject(value) && Object.keys(value).every(key => !["__proto__", "constructor", "prototype"].includes(key) && isJson(value[key]));
29
+ }
30
+ /** Minimal structural parsers. Hosts inject catalog, URL/origin and safe-metadata policy here;
31
+ * secrets stay in payload JSON. Overrides own the complete shape, including merged patches.
32
+ */
33
+ export function createVaultMetaParsers(_required, { parsers = {} } = {}) {
34
+ return Object.fromEntries(VAULT_KINDS.map(kind => [kind, ({ meta }) => {
35
+ if (!isObject(meta) || !isJson(meta) || Object.keys(meta).some(key => !/^[A-Za-z0-9_]+$/.test(key)))
36
+ throw new VaultError({ code: "invalid-meta" });
37
+ if (parsers[kind]) {
38
+ const parsed = parsers[kind]({ meta: structuredClone(meta) });
39
+ if (!isObject(parsed) || !isJson(parsed) || Object.keys(parsed).some(key => !/^[A-Za-z0-9_]+$/.test(key)))
40
+ throw new VaultError({ code: "invalid-meta" });
41
+ return structuredClone(parsed);
42
+ }
43
+ for (const [key, value] of Object.entries(meta)) {
44
+ const field = Object.hasOwn(FIELDS[kind], key) ? FIELDS[kind][key] : undefined;
45
+ if (!field || (value !== null && !(field === "strings" ? Array.isArray(value) && value.every(v => typeof v === "string") :
46
+ field === "object" ? isObject(value) : typeof value === field)))
47
+ throw new VaultError({ code: "invalid-meta" });
48
+ }
49
+ return structuredClone(meta);
50
+ }]));
51
+ }
52
+ //# sourceMappingURL=vault.meta.js.map
@@ -0,0 +1,51 @@
1
+ import { type VaultBatchOp, type VaultBatchResult, type VaultDefaultQuery, type VaultSingletonQuery, type VaultMeta, type VaultOptions, type VaultQuery, type VaultRecord, type VaultRepoPort } from "./vault.types.js";
2
+ /** Single-turn mutations are atomic in JS; clones prevent callers bypassing CAS through aliases. */
3
+ export declare class InMemoryVaultRepo implements VaultRepoPort {
4
+ private rows;
5
+ private singletons;
6
+ constructor(_required: VaultOptions, _options?: VaultOptions);
7
+ private key;
8
+ find(input: {
9
+ workspaceId: string;
10
+ id: string;
11
+ }, _options?: VaultOptions): Promise<VaultRecord | null>;
12
+ private singletonKey;
13
+ /** Index all four optional scope combinations; copy sets so batch staging never mutates live indexes. */
14
+ private indexSingleton;
15
+ /** Indexed singleton selection; clone only the selected row, ignoring provider/default. */
16
+ findOne(input: VaultSingletonQuery, _options?: VaultOptions): Promise<VaultRecord | null>;
17
+ /** Stage through the same mutation owner, then publish once. No await can expose partial rows
18
+ * or let a concurrent writer be lost between snapshot and swap. O(n + ops*n) fixture work.
19
+ */
20
+ applyBatch({ ops }: {
21
+ ops: readonly VaultBatchOp[];
22
+ }, _options?: VaultOptions): Promise<VaultBatchResult[]>;
23
+ /** O(n) memory scan, n stored rows; clones only the default, never its siblings. */
24
+ findDefault(input: VaultDefaultQuery, _options?: VaultOptions): Promise<VaultRecord | null>;
25
+ list(input: VaultQuery, _options?: VaultOptions): Promise<VaultRecord[]>;
26
+ put(input: {
27
+ record: VaultRecord;
28
+ expectedRevision: number | null;
29
+ }, _options?: VaultOptions): Promise<VaultRecord>;
30
+ /** Synchronous mutation owner shared with batch staging; default moves never re-seal. */
31
+ private putRecord;
32
+ patchMeta(input: {
33
+ workspaceId: string;
34
+ id: string;
35
+ expectedRevision: number;
36
+ patch: VaultMeta;
37
+ updatedAt: string;
38
+ }, _options?: VaultOptions): Promise<VaultRecord>;
39
+ /** Clone merged metadata before mutating the staged/live map so failures leave it intact. */
40
+ private patchRecord;
41
+ delete(input: {
42
+ workspaceId: string;
43
+ id: string;
44
+ expectedRevision: number;
45
+ }, _options?: VaultOptions): Promise<boolean>;
46
+ /** Synchronous CAS delete shares promotion with provider moves and batch staging. */
47
+ private deleteRecord;
48
+ /** O(n) winner scan; promotion changes only default/revision, matching SQL. */
49
+ private promote;
50
+ }
51
+ //# sourceMappingURL=vault.repo.memory.d.ts.map