sealkeep 0.8.1 → 0.11.0
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/ARCHITECTURE.md +163 -14
- package/CHANGELOG.md +244 -1
- package/CONTROL_PLANE.md +2 -2
- package/LICENSE +1 -1
- package/README.md +108 -22
- package/THIRD_PARTY.md +2 -2
- package/THREAT_MODEL.md +23 -4
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/chunk-access.d.ts +26 -4
- package/dist/packages/sealkeep-crypto/src/chunk-access.js +219 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.d.ts +11 -1
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/envelope.js +58 -21
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.d.ts +2 -2
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.d.ts +1 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/index.js +1 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.js +4 -4
- package/dist/packages/sealkeep-crypto/src/squeeze.d.ts +6 -0
- package/dist/packages/sealkeep-crypto/src/squeeze.js +39 -0
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.d.ts +36 -3
- package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/stream.js +196 -37
- package/dist/site/index.html +1808 -1904
- package/dist/site/llms.txt +67 -0
- package/dist/site/trust/architecture-data-flow.html +53 -0
- package/dist/site/trust/audit-roadmap.html +37 -0
- package/dist/site/trust/deployment-responsibility.html +11 -0
- package/dist/site/trust/dpa-sample.html +30 -0
- package/dist/site/trust/release-provenance.html +21 -0
- package/dist/site/trust/subprocessors.html +15 -0
- package/dist/site/trust/threat-model.html +34 -0
- package/dist/site/trust/toms.html +41 -0
- package/dist/site/trust-document.css +32 -0
- package/dist/site/trust.html +73 -0
- package/dist/site/visual/assets/index-8Nxnkc7o.js +207 -0
- package/dist/site/visual/assets/index-oxLy1bpy.css +1 -0
- package/dist/site/visual/index.html +18 -0
- package/dist/site.zip +0 -0
- package/dist/src/activity.d.ts +9 -0
- package/dist/src/activity.js +90 -1
- package/dist/src/adapters.d.ts +175 -5
- package/dist/src/adapters.js +961 -73
- package/dist/src/agent-context.d.ts +135 -0
- package/dist/src/agent-context.js +1059 -0
- package/dist/src/archive-copies.d.ts +47 -0
- package/dist/src/archive-copies.js +179 -0
- package/dist/src/audit.d.ts +1 -1
- package/dist/src/audit.js +29 -4
- package/dist/src/autopilot.d.ts +52 -7
- package/dist/src/autopilot.js +143 -25
- package/dist/src/background-bandwidth.d.ts +46 -0
- package/dist/src/background-bandwidth.js +301 -0
- package/dist/src/background-cpu.d.ts +82 -0
- package/dist/src/background-cpu.js +212 -0
- package/dist/src/background-worker-error.d.ts +12 -0
- package/dist/src/background-worker-error.js +18 -0
- package/dist/src/branding.d.ts +24 -1
- package/dist/src/branding.js +31 -1
- package/dist/src/bridge.d.ts +233 -0
- package/dist/src/bridge.js +604 -0
- package/dist/src/byte-stream.d.ts +91 -0
- package/dist/src/byte-stream.js +385 -0
- package/dist/src/chunk-store.d.ts +41 -8
- package/dist/src/chunk-store.js +161 -65
- package/dist/src/cli.js +1746 -166
- package/dist/src/cloud.d.ts +841 -31
- package/dist/src/cloud.js +3196 -277
- package/dist/src/context-background.d.ts +37 -0
- package/dist/src/context-background.js +309 -0
- package/dist/src/context-drain-child.d.ts +1 -0
- package/dist/src/context-drain-child.js +98 -0
- package/dist/src/context-reader.d.ts +118 -0
- package/dist/src/context-reader.js +447 -0
- package/dist/src/control-plane/auth.d.ts +32 -4
- package/dist/src/control-plane/auth.js +85 -24
- package/dist/src/control-plane/server.js +19 -6
- package/dist/src/control-plane.d.ts +17 -1
- package/dist/src/control-plane.js +32 -6
- package/dist/src/crypto.d.ts +1 -1
- package/dist/src/crypto.js +5 -5
- package/dist/src/daemon-lease.d.ts +70 -0
- package/dist/src/daemon-lease.js +420 -0
- package/dist/src/daemon.d.ts +94 -1
- package/dist/src/daemon.js +1082 -105
- package/dist/src/darwin-service-policy.d.ts +41 -0
- package/dist/src/darwin-service-policy.js +60 -0
- package/dist/src/dashboard-cli.js +15 -15
- package/dist/src/device-authorization.d.ts +37 -0
- package/dist/src/device-authorization.js +199 -0
- package/dist/src/device-enrollment.d.ts +91 -0
- package/dist/src/device-enrollment.js +349 -0
- package/dist/src/disk.d.ts +17 -12
- package/dist/src/disk.js +43 -17
- package/dist/src/doctor.d.ts +35 -1
- package/dist/src/doctor.js +316 -41
- package/dist/src/durable-ticket-lock.d.ts +24 -0
- package/dist/src/durable-ticket-lock.js +232 -0
- package/dist/src/enroll.d.ts +1 -1
- package/dist/src/enroll.js +13 -7
- package/dist/src/env.d.ts +10 -1
- package/dist/src/env.js +11 -3
- package/dist/src/errors.d.ts +8 -8
- package/dist/src/errors.js +6 -6
- package/dist/src/flush.d.ts +12 -0
- package/dist/src/flush.js +37 -0
- package/dist/src/heartbeat.d.ts +86 -12
- package/dist/src/heartbeat.js +415 -29
- package/dist/src/index-background-watchdog.d.ts +1 -0
- package/dist/src/index-background-watchdog.js +94 -0
- package/dist/src/index-background-work.d.ts +21 -0
- package/dist/src/index-background-work.js +25 -0
- package/dist/src/index-background.d.ts +64 -0
- package/dist/src/index-background.js +394 -0
- package/dist/src/index-build-child.d.ts +1 -0
- package/dist/src/index-build-child.js +109 -0
- package/dist/src/index-manifest.d.ts +52 -0
- package/dist/src/index-manifest.js +444 -0
- package/dist/src/index-publication-proof.d.ts +84 -0
- package/dist/src/index-publication-proof.js +380 -0
- package/dist/src/index-publication-state.d.ts +149 -0
- package/dist/src/index-publication-state.js +696 -0
- package/dist/src/index-publication-verifier.d.ts +89 -0
- package/dist/src/index-publication-verifier.js +341 -0
- package/dist/src/index-publish.d.ts +62 -0
- package/dist/src/index-publish.js +540 -0
- package/dist/src/index-scratch-cleanup.d.ts +19 -0
- package/dist/src/index-scratch-cleanup.js +166 -0
- package/dist/src/index-segment-types.d.ts +132 -0
- package/dist/src/index-segment-types.js +21 -0
- package/dist/src/index-segments.d.ts +9 -0
- package/dist/src/index-segments.js +516 -0
- package/dist/src/index-store.d.ts +123 -0
- package/dist/src/index-store.js +495 -0
- package/dist/src/index-sync.d.ts +91 -15
- package/dist/src/index-sync.js +286 -53
- package/dist/src/index-upgrade-publication.d.ts +30 -0
- package/dist/src/index-upgrade-publication.js +179 -0
- package/dist/src/integration-manager.d.ts +32 -0
- package/dist/src/integration-manager.js +394 -0
- package/dist/src/leakscan.js +1 -1
- package/dist/src/local-api.d.ts +56 -15
- package/dist/src/local-api.js +4979 -541
- package/dist/src/machine-settings.d.ts +51 -0
- package/dist/src/machine-settings.js +166 -0
- package/dist/src/managed-chunks.d.ts +5 -2
- package/dist/src/managed-chunks.js +14 -14
- package/dist/src/mcp-install.d.ts +11 -9
- package/dist/src/mcp-install.js +73 -28
- package/dist/src/mcp-workspace.d.ts +18 -0
- package/dist/src/mcp-workspace.js +50 -0
- package/dist/src/mcp.js +294 -25
- package/dist/src/migrate.d.ts +1 -0
- package/dist/src/migrate.js +33 -5
- package/dist/src/notify.d.ts +1 -1
- package/dist/src/notify.js +5 -5
- package/dist/src/offload.d.ts +201 -14
- package/dist/src/offload.js +1848 -140
- package/dist/src/onboarding.d.ts +8 -1
- package/dist/src/onboarding.js +4 -4
- package/dist/src/packages.d.ts +2 -2
- package/dist/src/packages.js +10 -2
- package/dist/src/passkey.d.ts +0 -1
- package/dist/src/passkey.js +2 -7
- package/dist/src/password-lock.d.ts +2 -2
- package/dist/src/password-lock.js +6 -6
- package/dist/src/paths.d.ts +2 -0
- package/dist/src/paths.js +2 -0
- package/dist/src/presence.d.ts +86 -0
- package/dist/src/presence.js +240 -0
- package/dist/src/progress-deadline.d.ts +21 -0
- package/dist/src/progress-deadline.js +91 -0
- package/dist/src/project-repair.d.ts +55 -0
- package/dist/src/project-repair.js +131 -0
- package/dist/src/providers/gcs.d.ts +28 -7
- package/dist/src/providers/gcs.js +35 -24
- package/dist/src/providers/gdrive.d.ts +71 -8
- package/dist/src/providers/gdrive.js +223 -50
- package/dist/src/providers/index.d.ts +11 -3
- package/dist/src/providers/index.js +30 -10
- package/dist/src/providers/s3.d.ts +30 -8
- package/dist/src/providers/s3.js +41 -30
- package/dist/src/providers/safe-storage-fetch.d.ts +12 -0
- package/dist/src/providers/safe-storage-fetch.js +72 -0
- package/dist/src/queue.d.ts +136 -19
- package/dist/src/queue.js +862 -96
- package/dist/src/reclaim-transaction.d.ts +156 -0
- package/dist/src/reclaim-transaction.js +1027 -0
- package/dist/src/recovery-codes.d.ts +32 -0
- package/dist/src/recovery-codes.js +338 -0
- package/dist/src/recovery.js +12 -9
- package/dist/src/rehydrate.d.ts +25 -22
- package/dist/src/rehydrate.js +319 -23
- package/dist/src/restore.d.ts +57 -4
- package/dist/src/restore.js +272 -36
- package/dist/src/resume-stub.d.ts +92 -0
- package/dist/src/resume-stub.js +417 -0
- package/dist/src/retention.d.ts +98 -7
- package/dist/src/retention.js +1066 -62
- package/dist/src/rotate.js +3 -3
- package/dist/src/search.d.ts +566 -8
- package/dist/src/search.js +5897 -290
- package/dist/src/secrets.d.ts +51 -7
- package/dist/src/secrets.js +316 -24
- package/dist/src/service.d.ts +49 -11
- package/dist/src/service.js +776 -35
- package/dist/src/share.js +3 -3
- package/dist/src/shared-spaces.d.ts +98 -0
- package/dist/src/shared-spaces.js +214 -0
- package/dist/src/source-reader.d.ts +73 -0
- package/dist/src/source-reader.js +715 -0
- package/dist/src/spool.d.ts +1 -1
- package/dist/src/spool.js +1 -1
- package/dist/src/start-tui.js +2 -1
- package/dist/src/start.js +2 -2
- package/dist/src/storage-endpoint.d.ts +21 -0
- package/dist/src/storage-endpoint.js +122 -0
- package/dist/src/storage-setup.js +12 -12
- package/dist/src/storage-targets.d.ts +109 -6
- package/dist/src/storage-targets.js +975 -67
- package/dist/src/stream-to-cloud.d.ts +5 -1
- package/dist/src/stream-to-cloud.js +34 -14
- package/dist/src/sync-rules.d.ts +31 -6
- package/dist/src/sync-rules.js +153 -14
- package/dist/src/team-backfill-scheduling.d.ts +8 -0
- package/dist/src/team-backfill-scheduling.js +33 -0
- package/dist/src/team-backfill.d.ts +116 -0
- package/dist/src/team-backfill.js +1429 -0
- package/dist/src/team-index-cache.d.ts +16 -0
- package/dist/src/team-index-cache.js +152 -0
- package/dist/src/team-offboarding.d.ts +38 -0
- package/dist/src/team-offboarding.js +1043 -0
- package/dist/src/team-presence.d.ts +127 -0
- package/dist/src/team-presence.js +904 -0
- package/dist/src/team-publication-policy.d.ts +20 -0
- package/dist/src/team-publication-policy.js +140 -0
- package/dist/src/team-realtime.d.ts +68 -0
- package/dist/src/team-realtime.js +816 -0
- package/dist/src/team-source-facts-cache.d.ts +23 -0
- package/dist/src/team-source-facts-cache.js +255 -0
- package/dist/src/trash.d.ts +1 -1
- package/dist/src/trash.js +2 -2
- package/dist/src/tui.js +11 -12
- package/dist/src/types.d.ts +173 -7
- package/dist/src/types.js +20 -0
- package/dist/src/ui-server.d.ts +163 -35
- package/dist/src/ui-server.js +712 -72
- package/dist/src/ui.d.ts +1 -2
- package/dist/src/ui.js +1 -2
- package/dist/src/upload.d.ts +27 -0
- package/dist/src/upload.js +383 -43
- package/dist/src/vault.d.ts +235 -29
- package/dist/src/vault.js +1783 -190
- package/dist/src/watcher.d.ts +7 -1
- package/dist/src/watcher.js +198 -55
- package/dist/src/worker.d.ts +27 -3
- package/dist/src/worker.js +274 -55
- package/package.json +33 -12
- package/scripts/native-reboot-rehearsal.mjs +90 -0
- package/web/app.js +6032 -343
- package/web/bootstrap.js +17 -0
- package/web/index.html +255 -57
- package/web/rail.js +317 -40
- package/web/retention.html +2 -2
- package/web/rules-view.js +188 -16
- package/web/sessions-view.js +485 -62
- package/web/sessions.html +2 -2
- package/web/setup-api.js +152 -29
- package/web/setup-logic.js +68 -9
- package/web/setup.html +113 -44
- package/web/setup.js +604 -71
- package/web/style.css +513 -98
- package/dist/packages/vaultline-crypto/src/chunk-access.js +0 -93
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/aead.js +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/format.js +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/recipients.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.d.ts +0 -0
- /package/dist/packages/{vaultline-crypto → sealkeep-crypto}/src/sha256-stream.js +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ManagedIndexReceipt } from "./cloud.js";
|
|
2
|
+
/** Ciphertext transport cache only. A hit is never membership or index-semantic proof. */
|
|
3
|
+
export type TeamIndexCacheIdentity = {
|
|
4
|
+
origin: string;
|
|
5
|
+
accountId: number;
|
|
6
|
+
vaultId: string;
|
|
7
|
+
spaceKey: string;
|
|
8
|
+
receipt: ManagedIndexReceipt;
|
|
9
|
+
};
|
|
10
|
+
export declare const TEAM_INDEX_CACHE_BYTES: number;
|
|
11
|
+
export declare function readTeamIndexCache(dataDir: string, identity: TeamIndexCacheIdentity, maxBytes?: number): Promise<{
|
|
12
|
+
meta: Buffer;
|
|
13
|
+
ciphertext: Buffer;
|
|
14
|
+
} | null>;
|
|
15
|
+
/** Installs one verified encrypted pair atomically; the previous version survives interrupted refreshes. */
|
|
16
|
+
export declare function writeTeamIndexCache(dataDir: string, identity: TeamIndexCacheIdentity, meta: Buffer, ciphertext: Buffer): Promise<void>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { mkdir, open, readdir, rename, stat, unlink } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
export const TEAM_INDEX_CACHE_BYTES = 256 * 1024 * 1024;
|
|
6
|
+
const MAX_ENTRIES = 32;
|
|
7
|
+
const NAME = /^[a-f0-9]{64}\.checkpoint$/;
|
|
8
|
+
const PARTIAL = /^\.(\d+)\.([a-f0-9-]{36})\.partial$/;
|
|
9
|
+
const activePartials = new Set();
|
|
10
|
+
const directory = (dataDir) => join(dataDir, "index", "team-generation-cache");
|
|
11
|
+
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
12
|
+
function cacheName(identity) {
|
|
13
|
+
const { receipt } = identity;
|
|
14
|
+
// No leases, tokens, key material or decoded index data are persisted. Include
|
|
15
|
+
// the complete immutable head, not merely a timestamp or an object basename.
|
|
16
|
+
const key = JSON.stringify([
|
|
17
|
+
"sealkeep-team-generation-cache-v1",
|
|
18
|
+
identity.origin, identity.accountId, identity.vaultId, identity.spaceKey,
|
|
19
|
+
receipt.membershipVersion, receipt.revision, receipt.generationId,
|
|
20
|
+
receipt.blob.objectKey, receipt.blob.bytes, receipt.blob.sha256,
|
|
21
|
+
receipt.meta.objectKey, receipt.meta.bytes, receipt.meta.sha256,
|
|
22
|
+
Object.entries(receipt.coverageJson).sort(([a], [b]) => a.localeCompare(b)), receipt.committedAt,
|
|
23
|
+
]);
|
|
24
|
+
return `${createHash("sha256").update(key).digest("hex")}.checkpoint`;
|
|
25
|
+
}
|
|
26
|
+
function expectedBytes(identity) {
|
|
27
|
+
return identity.receipt.meta.bytes + identity.receipt.blob.bytes;
|
|
28
|
+
}
|
|
29
|
+
function verified(identity, meta, ciphertext) {
|
|
30
|
+
return meta.length === identity.receipt.meta.bytes && ciphertext.length === identity.receipt.blob.bytes
|
|
31
|
+
&& digest(meta) === identity.receipt.meta.sha256 && digest(ciphertext) === identity.receipt.blob.sha256;
|
|
32
|
+
}
|
|
33
|
+
async function removeAbandonedPartials(dataDir) {
|
|
34
|
+
const dir = directory(dataDir);
|
|
35
|
+
for (const name of await readdir(dir).catch(() => [])) {
|
|
36
|
+
const match = PARTIAL.exec(name);
|
|
37
|
+
if (!match)
|
|
38
|
+
continue;
|
|
39
|
+
const path = join(dir, name);
|
|
40
|
+
const pid = Number(match[1]);
|
|
41
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || activePartials.has(path))
|
|
42
|
+
continue;
|
|
43
|
+
let alive = pid === process.pid;
|
|
44
|
+
if (!alive) {
|
|
45
|
+
try {
|
|
46
|
+
process.kill(pid, 0);
|
|
47
|
+
alive = true;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
alive = error.code !== "ESRCH";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Same-PID leftovers cannot be ours unless present in activePartials. Other
|
|
54
|
+
// living processes retain their scratch files until their writer finishes.
|
|
55
|
+
if (!alive || pid === process.pid)
|
|
56
|
+
await unlink(path).catch(() => undefined);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function readTeamIndexCache(dataDir, identity, maxBytes = TEAM_INDEX_CACHE_BYTES) {
|
|
60
|
+
const size = expectedBytes(identity);
|
|
61
|
+
if (!Number.isSafeInteger(size) || size < 0 || size > Math.min(maxBytes, TEAM_INDEX_CACHE_BYTES))
|
|
62
|
+
return null;
|
|
63
|
+
const path = join(directory(dataDir), cacheName(identity));
|
|
64
|
+
try {
|
|
65
|
+
await removeAbandonedPartials(dataDir);
|
|
66
|
+
// An opened descriptor pins the inode while another reader evicts old files.
|
|
67
|
+
// Copying bytes into this request's Buffer also isolates later file changes.
|
|
68
|
+
const handle = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
69
|
+
try {
|
|
70
|
+
const before = await handle.stat();
|
|
71
|
+
if (!before.isFile() || before.size !== size)
|
|
72
|
+
return null;
|
|
73
|
+
const body = Buffer.alloc(size);
|
|
74
|
+
let at = 0;
|
|
75
|
+
while (at < size) {
|
|
76
|
+
const read = await handle.read(body, at, size - at, at);
|
|
77
|
+
if (!read.bytesRead)
|
|
78
|
+
return null;
|
|
79
|
+
at += read.bytesRead;
|
|
80
|
+
}
|
|
81
|
+
const after = await handle.stat();
|
|
82
|
+
if (after.size !== size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs)
|
|
83
|
+
return null;
|
|
84
|
+
const meta = body.subarray(0, identity.receipt.meta.bytes);
|
|
85
|
+
const ciphertext = body.subarray(identity.receipt.meta.bytes);
|
|
86
|
+
return verified(identity, meta, ciphertext) ? { meta, ciphertext } : null;
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await handle.close();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function evict(dataDir, keep) {
|
|
97
|
+
const dir = directory(dataDir);
|
|
98
|
+
const rows = await Promise.all((await readdir(dir)).filter((name) => NAME.test(name)).map(async (name) => {
|
|
99
|
+
const entry = await stat(join(dir, name)).catch(() => null);
|
|
100
|
+
return entry?.isFile() ? { name, bytes: entry.size, at: entry.mtimeMs } : null;
|
|
101
|
+
}));
|
|
102
|
+
const ordered = rows.filter((row) => row !== null)
|
|
103
|
+
.sort((a, b) => Number(b.name === keep) - Number(a.name === keep) || b.at - a.at || a.name.localeCompare(b.name));
|
|
104
|
+
let bytes = 0;
|
|
105
|
+
let count = 0;
|
|
106
|
+
for (const row of ordered) {
|
|
107
|
+
bytes += row.bytes;
|
|
108
|
+
count += 1;
|
|
109
|
+
if (bytes > TEAM_INDEX_CACHE_BYTES || count > MAX_ENTRIES)
|
|
110
|
+
await unlink(join(dir, row.name)).catch(() => undefined);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Installs one verified encrypted pair atomically; the previous version survives interrupted refreshes. */
|
|
114
|
+
export async function writeTeamIndexCache(dataDir, identity, meta, ciphertext) {
|
|
115
|
+
const size = expectedBytes(identity);
|
|
116
|
+
if (size > TEAM_INDEX_CACHE_BYTES || !verified(identity, meta, ciphertext))
|
|
117
|
+
return;
|
|
118
|
+
const dir = directory(dataDir);
|
|
119
|
+
const name = cacheName(identity);
|
|
120
|
+
const path = join(dir, name);
|
|
121
|
+
const temporary = join(dir, `.${process.pid}.${randomUUID()}.partial`);
|
|
122
|
+
try {
|
|
123
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
124
|
+
await removeAbandonedPartials(dataDir);
|
|
125
|
+
activePartials.add(temporary);
|
|
126
|
+
const handle = await open(temporary, "wx", 0o600);
|
|
127
|
+
try {
|
|
128
|
+
await handle.writeFile(meta);
|
|
129
|
+
await handle.writeFile(ciphertext);
|
|
130
|
+
await handle.sync();
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await handle.close();
|
|
134
|
+
}
|
|
135
|
+
// Replacement is safe even when the previous same-key cache was corrupt:
|
|
136
|
+
// readers already hold an inode or an independent verified Buffer.
|
|
137
|
+
await rename(temporary, path);
|
|
138
|
+
const directoryHandle = await open(dir, "r").catch(() => null);
|
|
139
|
+
try {
|
|
140
|
+
await directoryHandle?.sync().catch(() => undefined);
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
await directoryHandle?.close();
|
|
144
|
+
}
|
|
145
|
+
await evict(dataDir, name);
|
|
146
|
+
}
|
|
147
|
+
catch { /* Derived cache failure must not fail an otherwise verified read. */ }
|
|
148
|
+
finally {
|
|
149
|
+
activePartials.delete(temporary);
|
|
150
|
+
await unlink(temporary).catch(() => undefined);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BackendName } from "./secrets.js";
|
|
2
|
+
/** Only an explicitly bound team scope may enter a departure handoff. */
|
|
3
|
+
export type TeamOffboardingScope = {
|
|
4
|
+
project: string;
|
|
5
|
+
projectKey?: string;
|
|
6
|
+
spaceKey: string;
|
|
7
|
+
targetAccountId: number;
|
|
8
|
+
/** Invitation captures share the machinery, never a departure journal. */
|
|
9
|
+
transition?: "invitation";
|
|
10
|
+
targetPublicKey?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Pin already-shared history before the membership commit. Only ciphertext,
|
|
14
|
+
* wrapped keys and opaque references survive a process exit; transcript and
|
|
15
|
+
* searchable index plaintext are never written to the durable journal.
|
|
16
|
+
*/
|
|
17
|
+
export declare function prepareTeamOffboarding(dataDir: string, scope: TeamOffboardingScope, phrase: string, preferred?: BackendName): Promise<{
|
|
18
|
+
membershipVersion: number;
|
|
19
|
+
keyVersion?: number;
|
|
20
|
+
indexRevision: number;
|
|
21
|
+
archiveRefs: string[];
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Resume after the authoritative removal, including a lost removal response.
|
|
25
|
+
* The surviving uploader owns new immutable aliases; old author-owned grants
|
|
26
|
+
* and old membership receipts are never promoted to the new epoch.
|
|
27
|
+
*/
|
|
28
|
+
export declare function completeTeamOffboarding(dataDir: string, scope: TeamOffboardingScope, phrase: string, preferred?: BackendName): Promise<void>;
|
|
29
|
+
export declare function prepareTeamInvitationHistory(dataDir: string, scope: Omit<TeamOffboardingScope, "transition"> & {
|
|
30
|
+
targetPublicKey: string;
|
|
31
|
+
}, phrase: string, preferred?: BackendName): Promise<{
|
|
32
|
+
membershipVersion: number;
|
|
33
|
+
keyVersion?: number;
|
|
34
|
+
indexRevision: number;
|
|
35
|
+
archiveRefs: string[];
|
|
36
|
+
}>;
|
|
37
|
+
/** Owner-side background continuation; pending invitations grant no access. */
|
|
38
|
+
export declare function reconcileTeamInvitationHandoffs(dataDir: string, phrase: string, preferred?: BackendName): Promise<number>;
|