@jini-ai/platform 0.5.1 → 0.5.3
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 +6 -0
- package/dist/asset-cache.d.ts +12 -1
- package/dist/asset-cache.js +9 -5
- package/dist/child-environment.d.ts +18 -0
- package/dist/child-environment.js +26 -0
- package/dist/fs/boot-identity.d.ts +10 -0
- package/dist/fs/boot-identity.js +34 -0
- package/dist/fs/directory-home.d.ts +15 -0
- package/dist/fs/directory-home.js +17 -0
- package/dist/fs/directory-registry.d.ts +50 -0
- package/dist/fs/directory-registry.js +99 -0
- package/dist/fs/directory-running-lock.d.ts +43 -0
- package/dist/fs/directory-running-lock.js +66 -0
- package/dist/fs/directory-sync.d.ts +20 -0
- package/dist/fs/directory-sync.js +87 -0
- package/dist/fs/directory-user-config.d.ts +79 -0
- package/dist/fs/directory-user-config.js +183 -0
- package/dist/fs/directory-workspace.d.ts +132 -0
- package/dist/fs/directory-workspace.js +266 -0
- package/dist/fs/durable-json.d.ts +21 -0
- package/dist/fs/durable-json.js +59 -4
- package/dist/fs/file-lock.d.ts +3 -0
- package/dist/fs/file-lock.js +16 -7
- package/dist/fs/index.d.ts +6 -0
- package/dist/fs/index.js +6 -0
- package/dist/fs/strict-containment.d.ts +1 -1
- package/dist/fs/strict-containment.js +1 -1
- package/dist/fs/user-data-directories.d.ts +28 -0
- package/dist/fs/user-data-directories.js +53 -0
- package/dist/fs/verified-directory-move.d.ts +37 -0
- package/dist/fs/verified-directory-move.js +138 -0
- package/dist/fs/verified-file-relocation.d.ts +27 -0
- package/dist/fs/verified-file-relocation.js +115 -0
- package/dist/fs/workspace-directory.d.ts +19 -0
- package/dist/fs/workspace-directory.js +23 -0
- package/dist/http/guarded/transport.fetch.d.ts +13 -1
- package/dist/http/guarded/transport.fetch.js +9 -3
- package/dist/index.d.ts +6 -54
- package/dist/index.js +6 -54
- package/dist/net/address.d.ts +1 -8
- package/dist/net/address.js +2 -89
- package/dist/net/endpoint-policy.d.ts +9 -0
- package/dist/net/endpoint-policy.js +98 -0
- package/dist/secrets/credential-sets/index.d.ts +5 -0
- package/dist/secrets/credential-sets/index.js +5 -0
- package/dist/secrets/credential-sets/repo.memory.d.ts +18 -10
- package/dist/secrets/credential-sets/repo.memory.js +18 -10
- package/dist/secrets/credential-sets/vault.aad.d.ts +4 -0
- package/dist/secrets/credential-sets/vault.aad.js +8 -0
- package/dist/secrets/credential-sets/vault.meta.d.ts +10 -0
- package/dist/secrets/credential-sets/vault.meta.js +52 -0
- package/dist/secrets/credential-sets/vault.repo.memory.d.ts +51 -0
- package/dist/secrets/credential-sets/vault.repo.memory.js +148 -0
- package/dist/secrets/credential-sets/vault.service.d.ts +130 -0
- package/dist/secrets/credential-sets/vault.service.js +310 -0
- package/dist/secrets/credential-sets/vault.types.d.ts +150 -0
- package/dist/secrets/credential-sets/vault.types.js +28 -0
- package/dist/secrets/credential-token.d.ts +64 -0
- package/dist/secrets/credential-token.js +75 -0
- package/dist/secrets/index.d.ts +1 -0
- package/dist/secrets/index.js +1 -0
- package/dist/secrets/secret-sealer.aesgcm.d.ts +6 -0
- package/dist/secrets/secret-sealer.aesgcm.js +9 -2
- package/dist/web/html-document.d.ts +70 -0
- package/dist/web/html-document.js +268 -0
- package/dist/web/html-resource.d.ts +15 -0
- package/dist/web/html-resource.js +12 -0
- package/dist/web/html-to-markdown.d.ts +11 -0
- package/dist/web/html-to-markdown.js +245 -0
- package/dist/web/index.d.ts +5 -0
- package/dist/web/index.js +5 -0
- package/dist/web/web-page.d.ts +157 -0
- package/dist/web/web-page.js +310 -0
- package/package.json +26 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { DurableJsonFile } from "./durable-json.js";
|
|
2
|
+
import { type UserDirectoryOptions } from "./user-data-directories.js";
|
|
3
|
+
export interface DirectoryUserConfig {
|
|
4
|
+
sitesHome: string;
|
|
5
|
+
siteRoots: string[];
|
|
6
|
+
databases: "inSite" | "appData";
|
|
7
|
+
}
|
|
8
|
+
export interface DirectoryUserConfigPolicy {
|
|
9
|
+
appName: string;
|
|
10
|
+
rootsEnvName: string;
|
|
11
|
+
sourceRoots?: readonly string[];
|
|
12
|
+
legacySettingsFile?: string;
|
|
13
|
+
legacyDefaultFolder?: string;
|
|
14
|
+
/** Nest new workspaces while retaining immediate old-level children for discovery. */
|
|
15
|
+
defaultSubfolder?: string;
|
|
16
|
+
}
|
|
17
|
+
/** One atomic settings owner for multiple processes. Existing DB files always win over preferences:
|
|
18
|
+
* changing placement controls new databases, never silently moves or abandons existing ones.
|
|
19
|
+
* @complexity O(n) canonicalizations for n roots; DB lookup probes three fixed locations.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createDirectoryUserConfig({ homeDir, defaultFolder, envName, policy, fileAt, canonicalPath, exists, isDirectory, removeFile }: {
|
|
22
|
+
homeDir: string;
|
|
23
|
+
defaultFolder: string;
|
|
24
|
+
envName: string;
|
|
25
|
+
policy: DirectoryUserConfigPolicy;
|
|
26
|
+
fileAt: (file: string) => DurableJsonFile;
|
|
27
|
+
canonicalPath: (required: {
|
|
28
|
+
path: string;
|
|
29
|
+
}) => string;
|
|
30
|
+
exists: (file: string) => boolean;
|
|
31
|
+
isDirectory: (file: string) => boolean;
|
|
32
|
+
removeFile?: (required: {
|
|
33
|
+
filePath: string;
|
|
34
|
+
}) => void;
|
|
35
|
+
}, { env, cwd, report, ...directoryOptions }?: UserDirectoryOptions & {
|
|
36
|
+
cwd?: string;
|
|
37
|
+
report?: (message: string) => void;
|
|
38
|
+
}): {
|
|
39
|
+
legacyHomes: (_required: Record<string, never>, { includeMissing }?: {
|
|
40
|
+
includeMissing?: boolean;
|
|
41
|
+
}) => string[];
|
|
42
|
+
defaultRoots: (_required: Record<string, never>, _options?: {}) => string[];
|
|
43
|
+
extraRoots: (_required: Record<string, never>, _options?: {}) => string[];
|
|
44
|
+
roots: (_required: Record<string, never>, _options?: {}) => string[];
|
|
45
|
+
runningPath: ({ dir }: {
|
|
46
|
+
dir: string;
|
|
47
|
+
}, _options?: {}) => string;
|
|
48
|
+
syncWarning: (_required: Record<string, never>, _options?: {}) => {
|
|
49
|
+
provider: "OneDrive" | "Dropbox" | "Google Drive";
|
|
50
|
+
message: string;
|
|
51
|
+
localHome: string;
|
|
52
|
+
} | null;
|
|
53
|
+
appData: string;
|
|
54
|
+
documents: string;
|
|
55
|
+
read: (_required: Record<string, never>, _options?: {}) => DirectoryUserConfig;
|
|
56
|
+
update: ({ patch }: {
|
|
57
|
+
patch: Partial<DirectoryUserConfig>;
|
|
58
|
+
}, { transform }?: {
|
|
59
|
+
transform?: (current: DirectoryUserConfig, saved: Partial<DirectoryUserConfig>) => Partial<DirectoryUserConfig>;
|
|
60
|
+
}) => DirectoryUserConfig;
|
|
61
|
+
updateRoots: ({ add, remove }: {
|
|
62
|
+
add?: readonly string[];
|
|
63
|
+
remove?: readonly string[];
|
|
64
|
+
}, _options?: {}) => DirectoryUserConfig;
|
|
65
|
+
databasePath: ({ dir, id, filename, placement }: {
|
|
66
|
+
dir: string;
|
|
67
|
+
id: string;
|
|
68
|
+
filename: string;
|
|
69
|
+
placement?: DirectoryUserConfig["databases"];
|
|
70
|
+
}, _options?: {}) => string;
|
|
71
|
+
filePath: string;
|
|
72
|
+
};
|
|
73
|
+
/** Validate only the three public settings; reject arrays, unknown fields and invalid enums.
|
|
74
|
+
* @complexity O(n) root strings. No I/O or mutation.
|
|
75
|
+
*/
|
|
76
|
+
export declare function validateDirectoryUserConfig({ value }: {
|
|
77
|
+
value: unknown;
|
|
78
|
+
}, _options?: {}): Partial<DirectoryUserConfig>;
|
|
79
|
+
//# sourceMappingURL=directory-user-config.d.ts.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { resolveDirectoryHome } from "./directory-home.js";
|
|
4
|
+
import { resolveUserDataDirectories } from "./user-data-directories.js";
|
|
5
|
+
import { detectDirectorySync } from "./directory-sync.js";
|
|
6
|
+
/** One atomic settings owner for multiple processes. Existing DB files always win over preferences:
|
|
7
|
+
* changing placement controls new databases, never silently moves or abandons existing ones.
|
|
8
|
+
* @complexity O(n) canonicalizations for n roots; DB lookup probes three fixed locations.
|
|
9
|
+
*/
|
|
10
|
+
export function createDirectoryUserConfig({ homeDir, defaultFolder, envName, policy, fileAt, canonicalPath, exists, isDirectory, removeFile }, { env = process.env, cwd = process.cwd(), report = console.warn, ...directoryOptions } = {}) {
|
|
11
|
+
const directories = resolveUserDataDirectories({ homeDir, appName: policy.appName }, { ...directoryOptions, env });
|
|
12
|
+
const paths = directoryOptions.platform === "win32" ? path.win32 : path;
|
|
13
|
+
const defaultHome = paths.join(directories.documents, defaultFolder, policy.defaultSubfolder ?? "");
|
|
14
|
+
const localHome = paths.join(homeDir, defaultFolder, policy.defaultSubfolder ?? "");
|
|
15
|
+
const legacyHomePaths = policy.defaultSubfolder ? [paths.join(directories.documents, defaultFolder), paths.join(homeDir, defaultFolder)] : [];
|
|
16
|
+
const filePath = paths.join(directories.appData, "config.json"), file = fileAt(filePath);
|
|
17
|
+
const expand = (value) => canonicalPath({ path: resolveDirectoryHome({ homeDir, defaultFolder, envName, env: {}, setting: value }, { cwd, ...(directoryOptions.platform ? { platform: directoryOptions.platform } : {}) }) });
|
|
18
|
+
const distinct = (values) => [...new Set(values.map(expand))];
|
|
19
|
+
const legacyHomes = distinct(legacyHomePaths);
|
|
20
|
+
function stored(locked = false) {
|
|
21
|
+
const result = file.read({});
|
|
22
|
+
if (result.state === "missing")
|
|
23
|
+
return {};
|
|
24
|
+
if (result.state === "ok") {
|
|
25
|
+
try {
|
|
26
|
+
return validateDirectoryUserConfig({ value: result.value });
|
|
27
|
+
}
|
|
28
|
+
catch { /* preserve invalid settings too */ }
|
|
29
|
+
}
|
|
30
|
+
// Bad settings must not stop boot, and read-only discovery/dry-run must not mutate settings.
|
|
31
|
+
// Preserve the original on reads; the next mutation quarantines it under the existing lock.
|
|
32
|
+
if (!locked) {
|
|
33
|
+
report(`User config is unreadable: ${filePath}. Using defaults; the original was left untouched.`);
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
if (!file.quarantine({ notice: { label: "user config", consequence: "Using default settings; existing databases keep their locations." } })) {
|
|
37
|
+
throw new Error(`User config is unreadable: ${filePath}. Nothing was overwritten.`);
|
|
38
|
+
}
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
const syncProvider = (sitesHome) => detectDirectorySync({ dir: sitesHome, homeDir, documents: directories.documents }, { ...directoryOptions, env, canonicalPath });
|
|
42
|
+
function read(_required, _options = {}) {
|
|
43
|
+
const saved = stored();
|
|
44
|
+
// Old default pointers follow the owner-selected nesting rule; arbitrary custom homes and
|
|
45
|
+
// explicit environment overrides keep their contracts. Reading never moves user folders.
|
|
46
|
+
const savedHome = saved.sitesHome === undefined ? defaultHome : expand(saved.sitesHome);
|
|
47
|
+
const nestedHome = legacyHomes.includes(savedHome) ? paths.join(savedHome, policy.defaultSubfolder) : savedHome;
|
|
48
|
+
const sitesHome = expand(env[envName] ?? nestedHome);
|
|
49
|
+
const sync = syncProvider(sitesHome);
|
|
50
|
+
return {
|
|
51
|
+
sitesHome,
|
|
52
|
+
siteRoots: distinct(env[policy.rootsEnvName] !== undefined ? env[policy.rootsEnvName].split(",").map((root) => root.trim()).filter(Boolean) : saved.siteRoots ?? policy.sourceRoots ?? []),
|
|
53
|
+
databases: saved.databases ?? (sync && sync !== "iCloud" ? "appData" : "inSite"),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function update({ patch }, { transform } = {}) {
|
|
57
|
+
// Compute incremental root changes inside the same lock as the write: a sibling process's
|
|
58
|
+
// added root must not disappear because this caller previously read an older array.
|
|
59
|
+
file.withLock({ critical: () => {
|
|
60
|
+
const previous = stored(true);
|
|
61
|
+
const checked = validateDirectoryUserConfig({ value: transform ? transform(read({}), previous) : patch });
|
|
62
|
+
// Prefer explicit settings, never coerce an existing regular file into a directory.
|
|
63
|
+
for (const directory of [checked.sitesHome, ...(checked.siteRoots ?? [])]) {
|
|
64
|
+
if (directory === undefined)
|
|
65
|
+
continue;
|
|
66
|
+
const expanded = expand(directory);
|
|
67
|
+
if (exists(expanded) && !isDirectory(expanded))
|
|
68
|
+
throw new Error(`Sites folder is not a directory: ${directory}`);
|
|
69
|
+
}
|
|
70
|
+
if (checked.sitesHome !== undefined && env[envName] !== undefined)
|
|
71
|
+
throw new Error(`${envName} overrides this setting. Unset it before changing the directory home.`);
|
|
72
|
+
if (checked.siteRoots !== undefined && env[policy.rootsEnvName] !== undefined)
|
|
73
|
+
throw new Error(`${policy.rootsEnvName} overrides this setting. Unset it before changing site roots.`);
|
|
74
|
+
const next = { ...previous, ...checked,
|
|
75
|
+
...(checked.sitesHome !== undefined ? { sitesHome: expand(checked.sitesHome) } : {}),
|
|
76
|
+
...(checked.siteRoots !== undefined ? { siteRoots: distinct(checked.siteRoots) } : {}),
|
|
77
|
+
};
|
|
78
|
+
// Empty incremental extras restore implicit defaults instead of persisting those defaults.
|
|
79
|
+
if (transform && checked.siteRoots?.length === 0)
|
|
80
|
+
delete next.siteRoots;
|
|
81
|
+
// With no other saved settings, removing the final extra also restores an absent config.
|
|
82
|
+
// The Node assembly supplies removal; non-Node adapters may retain the equivalent {}.
|
|
83
|
+
if (transform && Object.keys(next).length === 0 && removeFile)
|
|
84
|
+
removeFile({ filePath });
|
|
85
|
+
else
|
|
86
|
+
file.write({ value: next });
|
|
87
|
+
} });
|
|
88
|
+
return read({});
|
|
89
|
+
}
|
|
90
|
+
function updateRoots({ add = [], remove = [] }, _options = {}) {
|
|
91
|
+
return update({ patch: {} }, { transform: (current, saved) => {
|
|
92
|
+
const protectedRoots = new Set(distinct([current.sitesHome, ...(policy.sourceRoots ?? [])]));
|
|
93
|
+
const excluded = new Set(distinct(remove));
|
|
94
|
+
return { siteRoots: distinct([...(saved.siteRoots ?? []), ...add]).filter((root) => !excluded.has(root) && !protectedRoots.has(root)) };
|
|
95
|
+
} });
|
|
96
|
+
}
|
|
97
|
+
function databasePath({ dir, id, filename, placement }, _options = {}) {
|
|
98
|
+
if (path.basename(filename) !== filename || !filename.endsWith(".db"))
|
|
99
|
+
throw new Error("A database filename must be a .db basename.");
|
|
100
|
+
const inSite = path.join(dir, "data.nosync", filename), legacy = path.join(dir, filename);
|
|
101
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(id)) {
|
|
102
|
+
if (!placement && exists(legacy))
|
|
103
|
+
return legacy;
|
|
104
|
+
throw new Error("A database directory requires a safe, stable site identity.");
|
|
105
|
+
}
|
|
106
|
+
const appData = path.join(directories.appData, "databases", id, filename);
|
|
107
|
+
if (placement)
|
|
108
|
+
return placement === "inSite" ? inSite : appData;
|
|
109
|
+
const candidates = [legacy, inSite, appData];
|
|
110
|
+
// A move journal is written before copying; the old name stays authoritative until verification
|
|
111
|
+
// retires it. Recovery never guesses from two DB sizes/timestamps or asks users to delete data.
|
|
112
|
+
for (const source of candidates) {
|
|
113
|
+
const markerPath = source + ".home2-relocation.json", marker = fileAt(markerPath).read({});
|
|
114
|
+
if (marker.state === "missing")
|
|
115
|
+
continue;
|
|
116
|
+
const target = marker.state === "ok" ? marker.value?.to : undefined;
|
|
117
|
+
if (typeof target !== "string" || !candidates.includes(target))
|
|
118
|
+
throw new Error(`Interrupted database move has an invalid recovery marker: ${markerPath}. Restore the pre-move backup before starting.`);
|
|
119
|
+
const namedBackup = marker.state === "ok" ? marker.value?.backup : undefined;
|
|
120
|
+
// Old markers use the fixed home2 name; new moves identify their unique backup. Admit
|
|
121
|
+
// only a sibling of this source so malformed metadata cannot supply unrelated evidence.
|
|
122
|
+
if (namedBackup !== undefined && (typeof namedBackup !== "string" || path.dirname(namedBackup) !== path.dirname(source) || !namedBackup.startsWith(source + ".relocation-") || !namedBackup.endsWith("-backup")))
|
|
123
|
+
throw new Error(`Interrupted database move has an invalid recovery marker: ${markerPath}. Restore the pre-move backup before starting.`);
|
|
124
|
+
const backup = typeof namedBackup === "string" ? namedBackup : source + ".home2-backup";
|
|
125
|
+
const authoritative = exists(source) ? source : exists(backup) && exists(target) ? target : undefined;
|
|
126
|
+
if (!authoritative)
|
|
127
|
+
throw new Error(`Interrupted database move needs recovery: ${markerPath}. Restore the pre-move backup before starting.`);
|
|
128
|
+
report(`Recovered interrupted database move using ${authoritative}. Keep the backup files (${backup}); finish the move before changing database placement.`);
|
|
129
|
+
return authoritative;
|
|
130
|
+
}
|
|
131
|
+
const present = candidates.filter(exists);
|
|
132
|
+
if (present.length > 1)
|
|
133
|
+
throw new Error(`Multiple copies of ${filename} exist for this site. Choose the authoritative database before starting it.`);
|
|
134
|
+
if (present[0])
|
|
135
|
+
return present[0];
|
|
136
|
+
// A missing chat DB follows an existing content DB even after the user changes preferences.
|
|
137
|
+
if (filename !== "content.db") {
|
|
138
|
+
const content = databasePath({ dir, id, filename: "content.db" });
|
|
139
|
+
return path.join(path.dirname(content), filename);
|
|
140
|
+
}
|
|
141
|
+
return read({}).databases === "inSite" ? inSite : appData;
|
|
142
|
+
}
|
|
143
|
+
return { read, update, updateRoots, databasePath, filePath, ...directories,
|
|
144
|
+
// Discovery/catalog callers list real old homes. Pointer normalization and creation admission
|
|
145
|
+
// may inspect the supported spellings even before their directories have been created.
|
|
146
|
+
legacyHomes: (_required, { includeMissing = false } = {}) => distinct(legacyHomes).filter((root) => includeMissing || (exists(root) && isDirectory(root))),
|
|
147
|
+
defaultRoots: (_required, _options = {}) => distinct(policy.sourceRoots ?? []),
|
|
148
|
+
extraRoots: (_required, _options = {}) => distinct(env[policy.rootsEnvName] !== undefined ? read({}).siteRoots : stored().siteRoots ?? []),
|
|
149
|
+
roots: (_required, _options = {}) => {
|
|
150
|
+
const config = read({}), parent = paths.dirname(config.sitesHome);
|
|
151
|
+
// Discover only the selected home's existing former level. Scanning another old home
|
|
152
|
+
// crosses the local/synced boundary and admits broad or absent roots at every boot.
|
|
153
|
+
const formerRoots = legacyHomes.includes(parent) && exists(parent) && isDirectory(parent) ? [parent] : [];
|
|
154
|
+
return distinct([config.sitesHome, ...formerRoots, ...(policy.sourceRoots ?? []), ...config.siteRoots]);
|
|
155
|
+
},
|
|
156
|
+
runningPath: ({ dir }, _options = {}) => path.join(directories.appData, "running", createHash("sha256").update(canonicalPath({ path: dir })).digest("hex") + ".json"),
|
|
157
|
+
syncWarning: (_required, _options = {}) => {
|
|
158
|
+
const config = read({});
|
|
159
|
+
const sync = syncProvider(config.sitesHome);
|
|
160
|
+
if (!sync || sync === "iCloud")
|
|
161
|
+
return null;
|
|
162
|
+
return { provider: sync, message: config.databases === "appData" ? `${sync} syncs the sites folder. New databases use OS app-data for safety. Site folders are not self-contained: include their app-data databases when transferring them.` : `${sync} syncs the sites folder. It does not honor data.nosync; syncing live SQLite databases can corrupt them. Use app-data databases or a local sites folder.`, localHome };
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** Validate only the three public settings; reject arrays, unknown fields and invalid enums.
|
|
167
|
+
* @complexity O(n) root strings. No I/O or mutation.
|
|
168
|
+
*/
|
|
169
|
+
export function validateDirectoryUserConfig({ value }, _options = {}) {
|
|
170
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
171
|
+
throw new Error("User config must be an object.");
|
|
172
|
+
const row = value;
|
|
173
|
+
if (Object.keys(row).some((key) => !["sitesHome", "siteRoots", "databases"].includes(key)))
|
|
174
|
+
throw new Error("Unknown user config setting.");
|
|
175
|
+
if (row.sitesHome !== undefined && (typeof row.sitesHome !== "string" || !row.sitesHome.trim()))
|
|
176
|
+
throw new Error("sitesHome must name a directory.");
|
|
177
|
+
if (row.siteRoots !== undefined && (!Array.isArray(row.siteRoots) || !row.siteRoots.every((root) => typeof root === "string" && root.trim())))
|
|
178
|
+
throw new Error("siteRoots must be an array of directory paths.");
|
|
179
|
+
if (row.databases !== undefined && row.databases !== "inSite" && row.databases !== "appData")
|
|
180
|
+
throw new Error('databases must be "inSite" or "appData".');
|
|
181
|
+
return row;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=directory-user-config.js.map
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type DurableJsonPorts, type DurableJsonChange } from "./durable-json.js";
|
|
2
|
+
import { type DirectoryUserConfigPolicy, type DirectoryUserConfig } from "./directory-user-config.js";
|
|
3
|
+
import type { UserDirectoryOptions } from "./user-data-directories.js";
|
|
4
|
+
import { type DirectoryRegistry } from "./directory-registry.js";
|
|
5
|
+
/** Node assembly only. Policy modules receive explicit filesystem, clock and process ports.
|
|
6
|
+
* Settings live outside the selected home so changing the setting never loses the pointer.
|
|
7
|
+
* Reading a missing home/catalog does not create it. Opt-in registry recovery may prune known
|
|
8
|
+
* pollution on load; read-only hosts omit that policy. Mutations use the durable JSON owner.
|
|
9
|
+
* @complexity O(n) registry records, O(1) settings/lease operations.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createNodeDirectoryWorkspace({ homeDir, defaultFolder, envName, settingsFile, registryName, runningName, userConfig, registryRecovery }: {
|
|
12
|
+
homeDir: string;
|
|
13
|
+
defaultFolder: string;
|
|
14
|
+
envName: string;
|
|
15
|
+
settingsFile: string;
|
|
16
|
+
registryName: string;
|
|
17
|
+
runningName: string;
|
|
18
|
+
userConfig?: DirectoryUserConfigPolicy;
|
|
19
|
+
/** Opt-in host recovery of known test pollution; missing user directories alone never qualify. */
|
|
20
|
+
registryRecovery?: {
|
|
21
|
+
fixtureIdPattern: RegExp;
|
|
22
|
+
temporaryRoots?: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
}, { env, cwd, ports, canonicalPath, ...directoryOptions }?: UserDirectoryOptions & {
|
|
25
|
+
env?: NodeJS.ProcessEnv;
|
|
26
|
+
cwd?: string;
|
|
27
|
+
ports?: DurableJsonPorts;
|
|
28
|
+
canonicalPath?: (required: {
|
|
29
|
+
path: string;
|
|
30
|
+
}) => string;
|
|
31
|
+
}): {
|
|
32
|
+
homeDir: string;
|
|
33
|
+
config: (_required: Record<string, never>, _options?: {}) => {
|
|
34
|
+
defaultRoots: string[];
|
|
35
|
+
extraRoots: string[];
|
|
36
|
+
configPath: string;
|
|
37
|
+
appData: string;
|
|
38
|
+
warning: {
|
|
39
|
+
provider: "OneDrive" | "Dropbox" | "Google Drive";
|
|
40
|
+
message: string;
|
|
41
|
+
localHome: string;
|
|
42
|
+
} | null;
|
|
43
|
+
overrides: {
|
|
44
|
+
sitesHome: boolean;
|
|
45
|
+
siteRoots: boolean;
|
|
46
|
+
};
|
|
47
|
+
sitesHome: string;
|
|
48
|
+
siteRoots: string[];
|
|
49
|
+
databases: "inSite" | "appData";
|
|
50
|
+
};
|
|
51
|
+
updateConfig: (required: {
|
|
52
|
+
patch: Partial<DirectoryUserConfig>;
|
|
53
|
+
}, options?: {}) => {
|
|
54
|
+
defaultRoots: string[];
|
|
55
|
+
extraRoots: string[];
|
|
56
|
+
configPath: string;
|
|
57
|
+
appData: string;
|
|
58
|
+
warning: {
|
|
59
|
+
provider: "OneDrive" | "Dropbox" | "Google Drive";
|
|
60
|
+
message: string;
|
|
61
|
+
localHome: string;
|
|
62
|
+
} | null;
|
|
63
|
+
overrides: {
|
|
64
|
+
sitesHome: boolean;
|
|
65
|
+
siteRoots: boolean;
|
|
66
|
+
};
|
|
67
|
+
sitesHome: string;
|
|
68
|
+
siteRoots: string[];
|
|
69
|
+
databases: "inSite" | "appData";
|
|
70
|
+
};
|
|
71
|
+
updateRoots: (required: {
|
|
72
|
+
add?: readonly string[];
|
|
73
|
+
remove?: readonly string[];
|
|
74
|
+
}, options?: {}) => {
|
|
75
|
+
defaultRoots: string[];
|
|
76
|
+
extraRoots: string[];
|
|
77
|
+
configPath: string;
|
|
78
|
+
appData: string;
|
|
79
|
+
warning: {
|
|
80
|
+
provider: "OneDrive" | "Dropbox" | "Google Drive";
|
|
81
|
+
message: string;
|
|
82
|
+
localHome: string;
|
|
83
|
+
} | null;
|
|
84
|
+
overrides: {
|
|
85
|
+
sitesHome: boolean;
|
|
86
|
+
siteRoots: boolean;
|
|
87
|
+
};
|
|
88
|
+
sitesHome: string;
|
|
89
|
+
siteRoots: string[];
|
|
90
|
+
databases: "inSite" | "appData";
|
|
91
|
+
};
|
|
92
|
+
roots: (_required: Record<string, never>, _options?: {}) => string[];
|
|
93
|
+
databasePath: (required: {
|
|
94
|
+
dir: string;
|
|
95
|
+
id: string;
|
|
96
|
+
filename: string;
|
|
97
|
+
placement?: DirectoryUserConfig["databases"];
|
|
98
|
+
}, options?: {}) => string;
|
|
99
|
+
/** Only the implicit nested home may create its application parent below mounted Documents.
|
|
100
|
+
* Custom homes still require their immediate parent, so an absent volume is never fabricated.
|
|
101
|
+
*/
|
|
102
|
+
homeAvailable: (_required: Record<string, never>, _options?: {}) => boolean;
|
|
103
|
+
legacyHomes: (_required: Record<string, never>, _options?: {}) => string[];
|
|
104
|
+
/** Commit a verified move's catalog and every injected path reference as one locked unit.
|
|
105
|
+
* Uses the registry owner to preserve identity/collision rules; settings retain env precedence.
|
|
106
|
+
* @complexity O(total catalog/reference bytes), with rollback snapshots in memory.
|
|
107
|
+
*/
|
|
108
|
+
relocate({ from, to, entry, references }: {
|
|
109
|
+
from: string;
|
|
110
|
+
to: string;
|
|
111
|
+
entry: import("./directory-registry.js").DirectoryRecord;
|
|
112
|
+
references?: readonly DurableJsonChange[];
|
|
113
|
+
}, _options?: {}): void;
|
|
114
|
+
home: (_required: Record<string, never>, _options?: {}) => string;
|
|
115
|
+
setHome({ path: dir }: {
|
|
116
|
+
path: string;
|
|
117
|
+
}, _options?: {}): string;
|
|
118
|
+
registry: (_required: Record<string, never>, _options?: {}) => DirectoryRegistry;
|
|
119
|
+
running: ({ path: dir }: {
|
|
120
|
+
path: string;
|
|
121
|
+
}, _options?: {}) => import("./directory-running-lock.js").DirectoryRunningLock;
|
|
122
|
+
claim({ path: dir, app, port, scheme }: {
|
|
123
|
+
path: string;
|
|
124
|
+
app: string;
|
|
125
|
+
port?: number;
|
|
126
|
+
scheme?: "http" | "https";
|
|
127
|
+
}, _options?: {}): {
|
|
128
|
+
acquired: boolean;
|
|
129
|
+
record: import("./directory-running-lock.js").DirectoryRunningRecord;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=directory-workspace.d.ts.map
|