@amalgm/shell 0.1.162 → 0.1.164-main.34182640231
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/PURPOSE.md +163 -17
- package/README.md +74 -11
- package/config/releases/trust/runtime/main.root.json +84 -0
- package/config/releases/trust/runtime/preview.root.json +84 -0
- package/dist/authorization/recovery-host.d.ts +1 -0
- package/dist/authorization/recovery-host.js +2 -3
- package/dist/authorization/recovery-host.js.map +1 -1
- package/dist/boot.js +28 -20
- package/dist/boot.js.map +1 -1
- package/dist/cli-arguments.d.ts +8 -0
- package/dist/cli-arguments.js +47 -0
- package/dist/cli-arguments.js.map +1 -0
- package/dist/cli.d.ts +6 -4
- package/dist/cli.js +91 -73
- package/dist/cli.js.map +1 -1
- package/dist/compose.js +4 -3
- package/dist/compose.js.map +1 -1
- package/dist/content-cache-index.js +2 -2
- package/dist/content-cache-index.js.map +1 -1
- package/dist/detection/runtime.js +2 -2
- package/dist/detection/runtime.js.map +1 -1
- package/dist/development/profile.d.ts +27 -0
- package/dist/development/profile.js +142 -0
- package/dist/development/profile.js.map +1 -0
- package/dist/entity-apply-host.js +2 -2
- package/dist/entity-apply-host.js.map +1 -1
- package/dist/entity-apply-store.d.ts +2 -1
- package/dist/entity-apply-store.js +52 -37
- package/dist/entity-apply-store.js.map +1 -1
- package/dist/files-register-host.d.ts +1 -0
- package/dist/files-register-host.js +1 -0
- package/dist/files-register-host.js.map +1 -1
- package/dist/installation/environment.d.ts +30 -0
- package/dist/installation/environment.js +28 -0
- package/dist/installation/environment.js.map +1 -0
- package/dist/installation/lease.d.ts +6 -0
- package/dist/installation/lease.js +28 -0
- package/dist/installation/lease.js.map +1 -0
- package/dist/installation/ownership.d.ts +30 -0
- package/dist/installation/ownership.js +156 -0
- package/dist/installation/ownership.js.map +1 -0
- package/dist/installation/selection.d.ts +8 -0
- package/dist/installation/selection.js +29 -0
- package/dist/installation/selection.js.map +1 -0
- package/dist/machine-host.d.ts +27 -5
- package/dist/machine-host.js +244 -96
- package/dist/machine-host.js.map +1 -1
- package/dist/main.js +56 -2
- package/dist/main.js.map +1 -1
- package/dist/platform-product-host.d.ts +9 -9
- package/dist/platform-product-host.js +17 -17
- package/dist/platform-product-host.js.map +1 -1
- package/dist/platform-tools.d.ts +4 -3
- package/dist/platform-tools.js +34 -37
- package/dist/platform-tools.js.map +1 -1
- package/dist/process-lifecycle.d.ts +6 -0
- package/dist/process-lifecycle.js +42 -0
- package/dist/process-lifecycle.js.map +1 -0
- package/dist/pty-host.d.ts +1 -1
- package/dist/pty-host.js +70 -21
- package/dist/pty-host.js.map +1 -1
- package/dist/runtime-command-host.d.ts +7 -0
- package/dist/runtime-command-host.js +49 -13
- package/dist/runtime-command-host.js.map +1 -1
- package/dist/service/adapter.d.ts +36 -0
- package/dist/service/adapter.js +24 -0
- package/dist/service/adapter.js.map +1 -0
- package/dist/service/cli.d.ts +8 -0
- package/dist/service/cli.js +237 -0
- package/dist/service/cli.js.map +1 -0
- package/dist/service/control.d.ts +38 -0
- package/dist/service/control.js +68 -0
- package/dist/service/control.js.map +1 -0
- package/dist/service/index.d.ts +9 -0
- package/dist/service/index.js +10 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/keepalive.d.ts +18 -0
- package/dist/service/keepalive.js +418 -0
- package/dist/service/keepalive.js.map +1 -0
- package/dist/service/launchd.d.ts +9 -0
- package/dist/service/launchd.js +105 -0
- package/dist/service/launchd.js.map +1 -0
- package/dist/service/owner.d.ts +4 -0
- package/dist/service/owner.js +14 -0
- package/dist/service/owner.js.map +1 -0
- package/dist/service/portable.d.ts +10 -0
- package/dist/service/portable.js +32 -0
- package/dist/service/portable.js.map +1 -0
- package/dist/service/recovery.d.ts +27 -0
- package/dist/service/recovery.js +58 -0
- package/dist/service/recovery.js.map +1 -0
- package/dist/service/registration.d.ts +82 -0
- package/dist/service/registration.js +114 -0
- package/dist/service/registration.js.map +1 -0
- package/dist/service/systemd-unit.d.ts +7 -0
- package/dist/service/systemd-unit.js +43 -0
- package/dist/service/systemd-unit.js.map +1 -0
- package/dist/service/systemd.d.ts +5 -0
- package/dist/service/systemd.js +72 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/windows-action.d.ts +9 -0
- package/dist/service/windows-action.js +55 -0
- package/dist/service/windows-action.js.map +1 -0
- package/dist/service/windows-task.d.ts +9 -0
- package/dist/service/windows-task.js +46 -0
- package/dist/service/windows-task.js.map +1 -0
- package/dist/service/windows.d.ts +2 -0
- package/dist/service/windows.js +65 -0
- package/dist/service/windows.js.map +1 -0
- package/dist/sqlite.d.ts +4 -0
- package/dist/sqlite.js +16 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/updates/artifacts.d.ts +40 -0
- package/dist/updates/artifacts.js +299 -0
- package/dist/updates/artifacts.js.map +1 -0
- package/dist/updates/bootstrap.d.ts +48 -0
- package/dist/updates/bootstrap.js +384 -0
- package/dist/updates/bootstrap.js.map +1 -0
- package/dist/updates/controller.d.ts +66 -0
- package/dist/updates/controller.js +322 -0
- package/dist/updates/controller.js.map +1 -0
- package/dist/updates/isolated-command-lifetime.d.ts +1 -0
- package/dist/updates/isolated-command-lifetime.js +63 -0
- package/dist/updates/isolated-command-lifetime.js.map +1 -0
- package/dist/updates/store.d.ts +41 -0
- package/dist/updates/store.js +80 -0
- package/dist/updates/store.js.map +1 -0
- package/dist/updates/trust.d.ts +20 -0
- package/dist/updates/trust.js +138 -0
- package/dist/updates/trust.js.map +1 -0
- package/dist/user-ground-host.d.ts +4 -1
- package/dist/user-ground-host.js +16 -3
- package/dist/user-ground-host.js.map +1 -1
- package/dist/watching/host.js +4 -2
- package/dist/watching/host.js.map +1 -1
- package/dist/workspace-add-staging.js +2 -2
- package/dist/workspace-add-staging.js.map +1 -1
- package/examinations/fixtures/machine-control-plane.js +57 -0
- package/examinations/fixtures/private-wire-authority.js +1065 -0
- package/examinations/native-service.mjs +92 -0
- package/examinations/network-view.mjs +202 -0
- package/examinations/runtime-upgrade.native-test.mjs +198 -0
- package/npm-shrinkwrap.json +2097 -218
- package/package.json +95 -14
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { BaseFetcher, Updater } from 'tuf-js';
|
|
7
|
+
import { DownloadHTTPError } from 'tuf-js/dist/error.js';
|
|
8
|
+
import { Metadata, MetadataKind } from '@tufjs/models';
|
|
9
|
+
import { admitManagedRuntimeRelease } from '@amalgm/core/supervision';
|
|
10
|
+
import { packageRoot, runtimeHost } from './store.js';
|
|
11
|
+
export const RELEASE_ORIGIN = 'https://amalgm-desktop-releases.fly.dev';
|
|
12
|
+
const ROLES = ['root', 'targets', 'snapshot', 'timestamp'];
|
|
13
|
+
const digest = (bytes) => createHash('sha256').update(bytes).digest('hex');
|
|
14
|
+
export function runtimeRoot(value, lane) {
|
|
15
|
+
const root = Metadata.fromJSON(MetadataKind.Root, value);
|
|
16
|
+
if (root.signed.unrecognizedFields.amalgm !== `runtime/${lane}` || !root.signed.consistentSnapshot)
|
|
17
|
+
throw new Error('Runtime trust scope differs');
|
|
18
|
+
const used = new Set();
|
|
19
|
+
for (const role of ROLES) {
|
|
20
|
+
const entry = root.signed.roles[role];
|
|
21
|
+
if (!entry || entry.threshold < (role === 'root' ? 2 : 1) || entry.threshold > entry.keyIDs.length)
|
|
22
|
+
throw new Error('Insufficient runtime trust threshold');
|
|
23
|
+
for (const id of entry.keyIDs) {
|
|
24
|
+
const key = root.signed.keys[id];
|
|
25
|
+
if (key?.keyType !== 'ed25519' || key.scheme !== 'ed25519' || used.has(key.keyVal.public))
|
|
26
|
+
throw new Error('Runtime signing roles must be independent');
|
|
27
|
+
used.add(key.keyVal.public);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
root.verifyDelegate('root', root);
|
|
31
|
+
return root;
|
|
32
|
+
}
|
|
33
|
+
class RuntimeFetcher extends BaseFetcher {
|
|
34
|
+
base;
|
|
35
|
+
signal;
|
|
36
|
+
constructor(base, signal) {
|
|
37
|
+
super();
|
|
38
|
+
this.base = base;
|
|
39
|
+
this.signal = signal;
|
|
40
|
+
}
|
|
41
|
+
async fetch(url) {
|
|
42
|
+
const target = new URL(url);
|
|
43
|
+
if (target.origin !== this.base.origin || !target.pathname.startsWith(this.base.pathname))
|
|
44
|
+
throw new Error('Runtime trust request escaped its repository');
|
|
45
|
+
const response = await fetch(target, { signal: this.signal, redirect: 'error', cache: 'no-store' });
|
|
46
|
+
if (!response.ok || !response.body)
|
|
47
|
+
throw new DownloadHTTPError('Runtime trust download failed', response.status);
|
|
48
|
+
return response.body;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Intentionally matches Electron's pinned host adapter: TUF owns verification;
|
|
52
|
+
* SQLite owns the four metadata writes, including partially failed refreshes.
|
|
53
|
+
* Neither consumer resets trust from a disposable filesystem mirror. */
|
|
54
|
+
export class RuntimeTrust {
|
|
55
|
+
store;
|
|
56
|
+
signal;
|
|
57
|
+
repository;
|
|
58
|
+
lane;
|
|
59
|
+
constructor(store, signal, origin = RELEASE_ORIGIN) {
|
|
60
|
+
this.store = store;
|
|
61
|
+
this.signal = signal;
|
|
62
|
+
const lane = store.identity.binding.runtimeLabel;
|
|
63
|
+
if (lane !== 'main' && lane !== 'preview')
|
|
64
|
+
throw new Error('Local development has no managed release authority');
|
|
65
|
+
this.lane = lane;
|
|
66
|
+
this.repository = new URL(`/trust/runtime/${lane}/`, origin);
|
|
67
|
+
if (createRequire(import.meta.url)('tuf-js/package.json').version !== '6.0.0')
|
|
68
|
+
throw new Error('Review the pinned TUF storage interface before upgrading');
|
|
69
|
+
if (store.read('metadata:root') === null) {
|
|
70
|
+
if (['metadata:timestamp', 'metadata:snapshot', 'metadata:targets', 'policy'].some(key => store.read(key) !== null))
|
|
71
|
+
throw new Error('Runtime trust history is incomplete');
|
|
72
|
+
const root = readFileSync(join(packageRoot, 'config/releases/trust/runtime', `${lane}.root.json`), 'utf8');
|
|
73
|
+
runtimeRoot(JSON.parse(root), lane);
|
|
74
|
+
store.write('metadata:root', root);
|
|
75
|
+
}
|
|
76
|
+
runtimeRoot(JSON.parse(store.read('metadata:root')), lane);
|
|
77
|
+
}
|
|
78
|
+
async current(previous) {
|
|
79
|
+
const scratch = await mkdtemp(join(this.store.identity.serviceDir, 'trust-refresh-'));
|
|
80
|
+
try {
|
|
81
|
+
writeFileSync(join(scratch, 'root.json'), this.store.read('metadata:root'));
|
|
82
|
+
const client = new Updater({ metadataDir: scratch, targetDir: scratch,
|
|
83
|
+
metadataBaseUrl: new URL('metadata/', this.repository).href, targetBaseUrl: new URL('targets/', this.repository).href,
|
|
84
|
+
fetcher: new RuntimeFetcher(this.repository, AbortSignal.any([this.signal, AbortSignal.timeout(30_000)])),
|
|
85
|
+
config: { maxDelegations: 1, targetsMaxLength: 4 * 1024 * 1024, fetchRetry: 0 } });
|
|
86
|
+
if (typeof Reflect.get(client, 'loadLocalMetadata') !== 'function' || typeof Reflect.get(client, 'persistMetadata') !== 'function')
|
|
87
|
+
throw new Error('The examined TUF storage interface changed');
|
|
88
|
+
const key = (role) => { if (!ROLES.includes(role))
|
|
89
|
+
throw new Error('Runtime targets do not delegate'); return `metadata:${role}`; };
|
|
90
|
+
Reflect.set(client, 'loadLocalMetadata', (role) => {
|
|
91
|
+
const bytes = this.store.read(key(role));
|
|
92
|
+
if (bytes === null)
|
|
93
|
+
throw new Error('No cached metadata');
|
|
94
|
+
return Buffer.from(bytes);
|
|
95
|
+
});
|
|
96
|
+
Reflect.set(client, 'persistMetadata', (role, bytes) => this.store.write(key(role), bytes.toString('utf8')));
|
|
97
|
+
await client.refresh();
|
|
98
|
+
const root = runtimeRoot(JSON.parse(this.store.read('metadata:root')), this.lane);
|
|
99
|
+
if (Date.parse(root.signed.expires) <= Date.now())
|
|
100
|
+
throw new Error('Runtime root expired');
|
|
101
|
+
const info = await client.getTargetInfo('current.json');
|
|
102
|
+
if (!info || info.custom.amalgm !== `runtime/${this.lane}` || info.length > 4 * 1024 * 1024)
|
|
103
|
+
throw new Error('No authorized runtime target exists');
|
|
104
|
+
const bytes = await readFile(await client.downloadTarget(info));
|
|
105
|
+
return this.admit(JSON.parse(bytes.toString('utf8')), digest(bytes), previous);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
await rm(scratch, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** A historical signature identifies existing code; only current() authorizes
|
|
112
|
+
* a desired release. Expiry cannot retroactively change the installed bytes. */
|
|
113
|
+
async baseline(version) {
|
|
114
|
+
if (!/^[\w.-]+$/.test(version))
|
|
115
|
+
throw new Error('Invalid installed version');
|
|
116
|
+
const fetcher = new RuntimeFetcher(this.repository, AbortSignal.any([this.signal, AbortSignal.timeout(30_000)]));
|
|
117
|
+
const receipt = JSON.parse((await fetcher.downloadBytes(new URL(`releases/shell-${version}/receipt.json`, this.repository).href, 4 * 1024 * 1024)).toString('utf8'));
|
|
118
|
+
const root = runtimeRoot(JSON.parse(this.store.read('metadata:root')), this.lane);
|
|
119
|
+
const authorization = Metadata.fromJSON(MetadataKind.Targets, receipt.authorization);
|
|
120
|
+
root.verifyDelegate('targets', authorization);
|
|
121
|
+
const bytes = Buffer.from(JSON.stringify(receipt.target) + '\n');
|
|
122
|
+
const file = authorization.signed.targets['current.json'];
|
|
123
|
+
if (!file || authorization.signed.delegations || Object.keys(authorization.signed.targets).length !== 1
|
|
124
|
+
|| file.custom.amalgm !== `runtime/${this.lane}` || file.length !== bytes.length || file.hashes.sha256 !== digest(bytes))
|
|
125
|
+
throw new Error('Installed receipt does not authenticate its exact target');
|
|
126
|
+
const accepted = this.admit(receipt.target, digest(bytes));
|
|
127
|
+
if (accepted.target.id !== `shell-${version}` || accepted.target.release.units[0].artifact.version !== version)
|
|
128
|
+
throw new Error('Installed receipt identity differs');
|
|
129
|
+
return accepted;
|
|
130
|
+
}
|
|
131
|
+
admit(value, hash, previous) {
|
|
132
|
+
const accepted = admitManagedRuntimeRelease(value, hash, this.store.identity.binding, runtimeHost(), previous);
|
|
133
|
+
if (accepted.target.release.units.length !== 1 || accepted.target.release.units[0].id !== 'shell')
|
|
134
|
+
throw new Error('This controller implements one Shell process unit');
|
|
135
|
+
return accepted;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=trust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.js","sourceRoot":"","sources":["../../src/updates/trust.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type UserGroundPort, type UserHomeDeclaration } from "@amalgm/core/identity";
|
|
2
2
|
import { type EntityType, type FilesAddPorts, type FilesRegisterPorts, type UserGroundIdentity } from "@amalgm/live";
|
|
3
|
-
import Database from "better-sqlite3";
|
|
3
|
+
import type Database from "better-sqlite3";
|
|
4
4
|
import { type FilesStageObserver } from "./files-observability.js";
|
|
5
5
|
import { type EntityApplyHostOptions, type EntityApplyStageEvidence } from "./entity-apply-host.js";
|
|
6
6
|
import { type DurabilityBarrier } from "./durability-barrier.js";
|
|
@@ -68,6 +68,8 @@ export interface UserGroundHostOptions {
|
|
|
68
68
|
readonly tunnelUrl: string;
|
|
69
69
|
readonly tunnelToken: string;
|
|
70
70
|
readonly runtimeVersion: string;
|
|
71
|
+
/** Installation-wide host admission, before any writer touches ground. */
|
|
72
|
+
readonly reserveWritableRoot?: (path: string) => void;
|
|
71
73
|
readonly declaration?: UserHomeDeclaration;
|
|
72
74
|
readonly now?: () => Date;
|
|
73
75
|
/** Product diagnostics consume this; Core's `/healthz` remains liveness-only. */
|
|
@@ -256,6 +258,7 @@ export declare class UserGroundHost {
|
|
|
256
258
|
* stay one read each. A lone artifact is a set of one. */
|
|
257
259
|
private downloadContentSet;
|
|
258
260
|
private downloadContent;
|
|
261
|
+
private reserveGroundRoots;
|
|
259
262
|
private ensureWatchers;
|
|
260
263
|
private scheduleRescan;
|
|
261
264
|
/** A finite cold command may suppress Detect while it owns publication, but
|
package/dist/user-ground-host.js
CHANGED
|
@@ -4,7 +4,7 @@ import { open, readFile } from "node:fs/promises";
|
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { buildUserHomeManifest, buildUserManifest, liveMachineStateDir, scopedAmalgmDir, shippedUserHomeDeclaration, } from "@amalgm/core/identity";
|
|
6
6
|
import { CHUNK_BYTES, CONTENT_CONTRACT, INLINE_CARGO_MAX_BYTES, ENTITY_CLOUD_CONTRACT, ENTITY_CLOUD_SCHEMA_VERSION, artifactForRecord, canonicalVersion, checkContentManifest, classifyDirectory, classifyFile, classifyRegisteredRoot, containedRecords, createLocalEntityRecord, createEntityRecordAuthorityPort, convergeUserGround, decodeAcceptedEntityRecord, deriveUploadManifest, createUserGroundEnrollmentPolicy, isRepositoryMetadataEntry, isContentPlacementChangedError, indexRepositoryTerritory, downloadAll as downloadAllArtifacts, encodeEntityRecord, EntityApplyRail, EntityRecordRail, membershipHash, materializedSlotNames, pathIsSuspect, CONTENT_REFS_BATCH_OBJECTS, privateEntityResourceId, repositoryIdentityHash, sameRecords, snapshotFromRecords, stableJson, streamCargo, travelingRecords, travelingRecordUUIDs, upload as uploadArtifact, userGroundRecords, portableFileMode, GRAPH_HEAD_OPERATION_KIND, } from "@amalgm/live";
|
|
7
|
-
import
|
|
7
|
+
import { openFileDatabase } from "./sqlite.js";
|
|
8
8
|
import { atomicCopy, atomicWrite, ensurePrivateDir, ensureUserDir } from "./filesystem.js";
|
|
9
9
|
import { emitFilesStage, } from "./files-observability.js";
|
|
10
10
|
import { EntityApplyHost, } from "./entity-apply-host.js";
|
|
@@ -171,6 +171,7 @@ export class UserGroundHost {
|
|
|
171
171
|
converge: async (identity) => {
|
|
172
172
|
this.converged = false;
|
|
173
173
|
this.activeIdentity = normalizedIdentity(identity);
|
|
174
|
+
this.reserveGroundRoots(this.activeIdentity);
|
|
174
175
|
const local = this.localPort(this.activeIdentity);
|
|
175
176
|
const result = await convergeUserGround(this.activeIdentity, {
|
|
176
177
|
sha256Hex,
|
|
@@ -312,6 +313,7 @@ export class UserGroundHost {
|
|
|
312
313
|
const register = createFilesRegisterPorts({
|
|
313
314
|
userRoot,
|
|
314
315
|
deviceId: identity.deviceId,
|
|
316
|
+
reserveWritableRoot: this.options.reserveWritableRoot,
|
|
315
317
|
onReferenceDeclared: () => this.scheduleRescan(),
|
|
316
318
|
findKnownWorkspaceId: ({ absolutePath, deviceNumber, inode }) => findKnownEntityId(this.databasePath(identity), absolutePath, deviceNumber, inode),
|
|
317
319
|
});
|
|
@@ -363,6 +365,7 @@ export class UserGroundHost {
|
|
|
363
365
|
return current;
|
|
364
366
|
},
|
|
365
367
|
materializeWorkspace: async (input) => {
|
|
368
|
+
this.options.reserveWritableRoot?.(join(input.destinationParent, input.workspace.name));
|
|
366
369
|
const groundWaitStarted = performance.now();
|
|
367
370
|
this.stage({
|
|
368
371
|
primitive: "download",
|
|
@@ -2060,9 +2063,19 @@ export class UserGroundHost {
|
|
|
2060
2063
|
throw new Error(`download set did not seal ${artifact.contentHash}`);
|
|
2061
2064
|
return local;
|
|
2062
2065
|
}
|
|
2066
|
+
reserveGroundRoots(identity) {
|
|
2067
|
+
if (!this.options.reserveWritableRoot)
|
|
2068
|
+
return;
|
|
2069
|
+
const userRoot = this.userRoot(identity);
|
|
2070
|
+
this.options.reserveWritableRoot(userRoot);
|
|
2071
|
+
for (const { directory } of materializedWorkspaceBindings(workspaceBindingDir(userRoot, identity.deviceId))) {
|
|
2072
|
+
this.options.reserveWritableRoot(directory);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2063
2075
|
ensureWatchers(identity, authoritativeBaselineRootIds = []) {
|
|
2064
2076
|
if (this.closing)
|
|
2065
2077
|
return this.watchHost.health();
|
|
2078
|
+
this.reserveGroundRoots(identity);
|
|
2066
2079
|
const started = performance.now();
|
|
2067
2080
|
const root = this.userRoot(identity);
|
|
2068
2081
|
const wanted = new Map([[root, {
|
|
@@ -3023,7 +3036,7 @@ function convertLegacySnapshotJournal(database, shape, columns) {
|
|
|
3023
3036
|
* heap-capped child process. */
|
|
3024
3037
|
export function initializeDatabase(file) {
|
|
3025
3038
|
ensurePrivateDir(dirname(file));
|
|
3026
|
-
const database =
|
|
3039
|
+
const database = openFileDatabase(file);
|
|
3027
3040
|
database.pragma("busy_timeout = 5000");
|
|
3028
3041
|
database.pragma("journal_mode = WAL");
|
|
3029
3042
|
database.pragma("synchronous = FULL");
|
|
@@ -4292,7 +4305,7 @@ function refreshRevealedRootEvidence(file, workspaceId, absolutePath) {
|
|
|
4292
4305
|
}
|
|
4293
4306
|
}
|
|
4294
4307
|
function assertDatabaseIdentity(file, identity) {
|
|
4295
|
-
const database =
|
|
4308
|
+
const database = openFileDatabase(file, { readonly: true });
|
|
4296
4309
|
try {
|
|
4297
4310
|
const found = database.prepare("SELECT user_id AS userId, user_email AS userEmail, device_id AS deviceId FROM ground_identity WHERE singleton = 1").get();
|
|
4298
4311
|
if (!found || found.userId !== identity.userId || found.userEmail !== identity.userEmail
|