@tearleads/client-sdk 0.1.40 → 0.1.42
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/client/Tearleads.js +3 -0
- package/client/Tearleads.js.map +1 -1
- package/data/documents/shared/syncResponses.js +5 -7
- package/data/documents/shared/syncResponses.js.map +1 -1
- package/data/keyingProjectionVerification/accessManifestCheckpointEnforcement.js +2 -0
- package/data/keyingProjectionVerification/accessManifestCheckpointEnforcement.js.map +1 -1
- package/data/keyingProjectionVerification/checkpointContext.d.ts +12 -0
- package/data/keyingProjectionVerification/checkpointContext.js +16 -0
- package/data/keyingProjectionVerification/checkpointContext.js.map +1 -1
- package/data/keyingProjectionVerification/containerDestinationVerification.js +3 -1
- package/data/keyingProjectionVerification/containerDestinationVerification.js.map +1 -1
- package/data/keyingProjectionVerification/containerProjectionVerification.js +12 -6
- package/data/keyingProjectionVerification/containerProjectionVerification.js.map +1 -1
- package/data/keyingProjectionVerification/documentProjectionVerification.js +10 -4
- package/data/keyingProjectionVerification/documentProjectionVerification.js.map +1 -1
- package/data/persistence/keyingCheckpointAdvancePersistence.js +27 -8
- package/data/persistence/keyingCheckpointAdvancePersistence.js.map +1 -1
- package/data/persistence/verifiedManifestBundlePersistence.d.ts +45 -0
- package/data/persistence/verifiedManifestBundlePersistence.js +282 -0
- package/data/persistence/verifiedManifestBundlePersistence.js.map +1 -0
- package/data/sqlite/schema.d.ts +157 -0
- package/data/sqlite/schema.js +3 -0
- package/data/sqlite/schema.js.map +1 -1
- package/data/sqlite/verifiedManifestBundleSchema.d.ts +174 -0
- package/data/sqlite/verifiedManifestBundleSchema.js +36 -0
- package/data/sqlite/verifiedManifestBundleSchema.js.map +1 -0
- package/internal/api-client/ApiClient.d.ts +4 -11
- package/internal/api-client/ApiClient.js +8 -6
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/index.d.ts +1 -1
- package/internal/api-client/index.js +0 -1
- package/internal/api-client/index.js.map +1 -1
- package/internal/api-client/principalHistoryRequest.js +8 -2
- package/internal/api-client/principalHistoryRequest.js.map +1 -1
- package/internal/api-client/principalHistoryRequestContext.js +15 -5
- package/internal/api-client/principalHistoryRequestContext.js.map +1 -1
- package/internal/api-client/routes/writerProjections.js +6 -3
- package/internal/api-client/routes/writerProjections.js.map +1 -1
- package/internal/api-client/verifiedManifestCitations.d.ts +23 -0
- package/internal/api-client/verifiedManifestCitations.js +60 -0
- package/internal/api-client/verifiedManifestCitations.js.map +1 -0
- package/internal/api-client/writerProjectionRequests.js +75 -14
- package/internal/api-client/writerProjectionRequests.js.map +1 -1
- package/internal/crypto/index.d.ts +0 -1
- package/internal/crypto/index.js +0 -1
- package/internal/crypto/index.js.map +1 -1
- package/internal/validators/documentSyncRefinements.js +5 -0
- package/internal/validators/documentSyncRefinements.js.map +1 -1
- package/internal/validators/knownManifestsRefinements.js +5 -0
- package/internal/validators/knownManifestsRefinements.js.map +1 -0
- package/internal/validators/operation/documentSync.d.ts +3 -0
- package/internal/validators/operation/writerProjections.d.ts +85 -319
- package/internal/validators/operation/writerProjections.js +11 -11
- package/internal/validators/operation/writerProjections.js.map +1 -1
- package/internal/validators/response/container.d.ts +429 -20
- package/internal/validators/response/container.js +40 -5
- package/internal/validators/response/container.js.map +1 -1
- package/internal/validators/response/documentMutation.d.ts +440 -20
- package/internal/validators/response/documentMutation.js +33 -3
- package/internal/validators/response/documentMutation.js.map +1 -1
- package/internal/validators/response/documentSyncSchema.js +35 -1
- package/internal/validators/response/documentSyncSchema.js.map +1 -1
- package/internal/validators/response/index.d.ts +3 -2
- package/internal/validators/response/index.js +3 -2
- package/internal/validators/response/index.js.map +1 -1
- package/internal/validators/response/manifestBundleReferences.js +79 -0
- package/internal/validators/response/manifestBundleReferences.js.map +1 -0
- package/internal/validators/response/writerProjectionWire.d.ts +19 -0
- package/internal/validators/response/writerProjectionWire.js +132 -0
- package/internal/validators/response/writerProjectionWire.js.map +1 -0
- package/internal/validators/schema.js +20 -0
- package/internal/validators/schema.js.map +1 -1
- package/internal/validators/util/index.d.ts +1 -1
- package/internal/validators/util/index.js +1 -1
- package/internal/validators/util/index.js.map +1 -1
- package/internal/validators/util/knownManifestWire.d.ts +11 -0
- package/internal/validators/util/knownManifestWire.js +28 -0
- package/internal/validators/util/knownManifestWire.js.map +1 -0
- package/internal/validators/writerProjectionRefinements.js +5 -0
- package/internal/validators/writerProjectionRefinements.js.map +1 -1
- package/package.json +1 -1
- package/workflows/documents/syncContentKeys.js +4 -9
- package/workflows/documents/syncContentKeys.js.map +1 -1
- package/workflows/registration/provisioningBootstrapBuilders.d.ts +0 -5
- package/workflows/sync/remoteReset.js +2 -0
- package/workflows/sync/remoteReset.js.map +1 -1
- package/internal/api-client/projectionHistoryTransport.js +0 -107
- package/internal/api-client/projectionHistoryTransport.js.map +0 -1
- package/internal/api-client/verifiedProjectionHistory.d.ts +0 -4
- package/internal/api-client/verifiedProjectionHistory.js +0 -12
- package/internal/api-client/verifiedProjectionHistory.js.map +0 -1
- package/internal/crypto/projectionHistory.d.ts +0 -14
- package/internal/crypto/projectionHistory.js +0 -90
- package/internal/crypto/projectionHistory.js.map +0 -1
- package/internal/crypto/projectionHistorySlots.d.ts +0 -13
- package/internal/crypto/projectionHistorySlots.js +0 -81
- package/internal/crypto/projectionHistorySlots.js.map +0 -1
- package/internal/validators/projectionHistoryRefinements.js +0 -5
- package/internal/validators/projectionHistoryRefinements.js.map +0 -1
- package/internal/validators/util/projectionHistoryWire.d.ts +0 -23
- package/internal/validators/util/projectionHistoryWire.js +0 -33
- package/internal/validators/util/projectionHistoryWire.js.map +0 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { toFingerprint } from "../../internal/crypto/index.js";
|
|
2
|
+
import { isAccessManifestBundleWireResponse, } from "../../internal/validators/response/index.js";
|
|
3
|
+
import { KNOWN_MANIFEST_HINT_LIMIT, MAX_CONTAINER_PATH_LENGTH, } from "../../internal/validators/util/index.js";
|
|
4
|
+
import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
|
|
5
|
+
import { containers } from "../sqlite/containerSchema.js";
|
|
6
|
+
import { documentDiscoveryHeads, pendingDocumentDiscoveries, } from "../sqlite/documentDiscoveryEvidenceSchema.js";
|
|
7
|
+
import { containerTables, documentContainerProjection, documentContainerProjectionTables, } from "../sqlite/schema.js";
|
|
8
|
+
import { getClientSQLitePersistenceRuntime, } from "../sqlite/sqlitePersistenceRuntime.js";
|
|
9
|
+
import { ensureSqlTables } from "../sqlite/sqlSchema.js";
|
|
10
|
+
import { verifiedAccessManifestBundles as bundles, verifiedManifestBundleTables, } from "../sqlite/verifiedManifestBundleSchema.js";
|
|
11
|
+
/**
|
|
12
|
+
* Bounds local bytes (a bundle is ~10–20 KB). Evicting the least recently
|
|
13
|
+
* verified rows only makes a later read carry those bundles again.
|
|
14
|
+
*/
|
|
15
|
+
export const MAX_VERIFIED_MANIFEST_BUNDLES = 1024;
|
|
16
|
+
const STATEMENT_BATCH = 200;
|
|
17
|
+
function sha256Hex(text) {
|
|
18
|
+
return toFingerprint(new TextEncoder().encode(text));
|
|
19
|
+
}
|
|
20
|
+
function batches(values) {
|
|
21
|
+
const result = [];
|
|
22
|
+
for (let index = 0; index < values.length; index += STATEMENT_BATCH)
|
|
23
|
+
result.push(values.slice(index, index + STATEMENT_BATCH));
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
async function pruneInTransaction(tx) {
|
|
27
|
+
const [row] = await tx.select({ count: sql `count(*)` }).from(bundles);
|
|
28
|
+
const excess = (row?.count ?? 0) - MAX_VERIFIED_MANIFEST_BUNDLES;
|
|
29
|
+
if (excess <= 0)
|
|
30
|
+
return;
|
|
31
|
+
const evicted = await tx
|
|
32
|
+
.select({ manifestHash: bundles.manifestHash })
|
|
33
|
+
.from(bundles)
|
|
34
|
+
.orderBy(asc(bundles.verifiedAt), asc(bundles.manifestHash))
|
|
35
|
+
.limit(excess);
|
|
36
|
+
for (const batch of batches(evicted.map((entry) => entry.manifestHash)))
|
|
37
|
+
await tx.delete(bundles).where(inArray(bundles.manifestHash, batch)).run();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Prepares rows for bundles that just passed projection verification. The
|
|
41
|
+
* digests are computed here, before the checkpoint transaction that writes
|
|
42
|
+
* them begins.
|
|
43
|
+
*/
|
|
44
|
+
export function verifiedManifestBundleRows(entries) {
|
|
45
|
+
const unique = new Map(entries.map((entry) => [entry.bundle.manifestHash, entry]));
|
|
46
|
+
return Promise.all([...unique.values()].map(async ({ bundle, checkpoint }) => {
|
|
47
|
+
const bundleJson = JSON.stringify(bundle);
|
|
48
|
+
return {
|
|
49
|
+
manifestHash: bundle.manifestHash,
|
|
50
|
+
organizationId: checkpoint.organizationId,
|
|
51
|
+
objectKind: checkpoint.objectKind,
|
|
52
|
+
objectId: checkpoint.objectId,
|
|
53
|
+
epoch: checkpoint.epoch,
|
|
54
|
+
bundleJson,
|
|
55
|
+
bundleDigest: await sha256Hex(bundleJson),
|
|
56
|
+
};
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Records verified bundles inside the transaction that finalizes their
|
|
61
|
+
* projection's checkpoints, so they commit or roll back with it and no cache
|
|
62
|
+
* work outlives the verification. Freshly verified bytes replace any stored
|
|
63
|
+
* copy.
|
|
64
|
+
*/
|
|
65
|
+
export async function writeVerifiedManifestBundlesInTransaction(tx, rows, verifiedAt) {
|
|
66
|
+
if (rows.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
const stored = await storedDigests(tx, rows.map((row) => row.manifestHash));
|
|
69
|
+
// An identical stored row only needs its recency refreshed.
|
|
70
|
+
const unchanged = rows.filter((row) => stored.get(row.manifestHash) === row.bundleDigest);
|
|
71
|
+
for (const batch of batches(unchanged.map((row) => row.manifestHash)))
|
|
72
|
+
await tx
|
|
73
|
+
.update(bundles)
|
|
74
|
+
.set({ verifiedAt })
|
|
75
|
+
.where(inArray(bundles.manifestHash, batch))
|
|
76
|
+
.run();
|
|
77
|
+
for (const row of rows) {
|
|
78
|
+
if (stored.get(row.manifestHash) === row.bundleDigest)
|
|
79
|
+
continue;
|
|
80
|
+
const verified = { ...row, verifiedAt };
|
|
81
|
+
await tx
|
|
82
|
+
.insert(bundles)
|
|
83
|
+
.values(verified)
|
|
84
|
+
.onConflictDoUpdate({ target: bundles.manifestHash, set: verified })
|
|
85
|
+
.run();
|
|
86
|
+
}
|
|
87
|
+
await pruneInTransaction(tx);
|
|
88
|
+
}
|
|
89
|
+
async function storedDigests(tx, manifestHashes) {
|
|
90
|
+
const digests = new Map();
|
|
91
|
+
for (const batch of batches(manifestHashes)) {
|
|
92
|
+
const rows = await tx
|
|
93
|
+
.select({
|
|
94
|
+
bundleDigest: bundles.bundleDigest,
|
|
95
|
+
manifestHash: bundles.manifestHash,
|
|
96
|
+
})
|
|
97
|
+
.from(bundles)
|
|
98
|
+
.where(inArray(bundles.manifestHash, batch));
|
|
99
|
+
for (const row of rows)
|
|
100
|
+
digests.set(row.manifestHash, row.bundleDigest);
|
|
101
|
+
}
|
|
102
|
+
return digests;
|
|
103
|
+
}
|
|
104
|
+
/** The requested object first, then each container whose lineage it cites. */
|
|
105
|
+
async function containerLineage(db, containerId) {
|
|
106
|
+
const lineage = [containerId];
|
|
107
|
+
while (lineage.length < MAX_CONTAINER_PATH_LENGTH) {
|
|
108
|
+
const [row] = await db
|
|
109
|
+
.select({ parentId: containers.parentId })
|
|
110
|
+
.from(containers)
|
|
111
|
+
.where(eq(containers.id, lineage.at(-1) ?? ""))
|
|
112
|
+
.limit(1);
|
|
113
|
+
const parentId = row?.parentId;
|
|
114
|
+
if (!parentId || lineage.includes(parentId))
|
|
115
|
+
break;
|
|
116
|
+
lineage.push(parentId);
|
|
117
|
+
}
|
|
118
|
+
return lineage;
|
|
119
|
+
}
|
|
120
|
+
async function citedObjects(db, target) {
|
|
121
|
+
if (target.kind === "container")
|
|
122
|
+
return (await containerLineage(db, target.id)).map((id) => ({
|
|
123
|
+
kind: "container",
|
|
124
|
+
id,
|
|
125
|
+
}));
|
|
126
|
+
// Linked containers, containers listing the document before its signed
|
|
127
|
+
// placement is checked, and a container whose metadata document it is.
|
|
128
|
+
const placements = [
|
|
129
|
+
...(await db
|
|
130
|
+
.select({ containerId: documentContainerProjection.containerId })
|
|
131
|
+
.from(documentContainerProjection)
|
|
132
|
+
.where(eq(documentContainerProjection.documentId, target.id))),
|
|
133
|
+
...(await db
|
|
134
|
+
.select({ containerId: pendingDocumentDiscoveries.containerId })
|
|
135
|
+
.from(pendingDocumentDiscoveries)
|
|
136
|
+
.where(eq(pendingDocumentDiscoveries.documentId, target.id))),
|
|
137
|
+
...(await db
|
|
138
|
+
.select({ containerId: containers.id })
|
|
139
|
+
.from(containers)
|
|
140
|
+
.where(eq(containers.metadataDocumentId, target.id))),
|
|
141
|
+
];
|
|
142
|
+
const containerIds = new Set();
|
|
143
|
+
for (const { containerId } of placements)
|
|
144
|
+
if (containerId)
|
|
145
|
+
for (const id of await containerLineage(db, containerId))
|
|
146
|
+
containerIds.add(id);
|
|
147
|
+
return [
|
|
148
|
+
{ kind: "document", id: target.id },
|
|
149
|
+
...[...containerIds].map((id) => ({ kind: "container", id })),
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The one organization every local source places the read in. Verified
|
|
154
|
+
* ownership (stored verified bundles of the target and of the containers on
|
|
155
|
+
* its walk, and a document's verified discovery head) and local placement
|
|
156
|
+
* (listed container rows reached through links, pending listings, metadata,
|
|
157
|
+
* or parents) must all agree: any disagreement, or no source at all, yields
|
|
158
|
+
* null, so the read is sent with no hints rather than another
|
|
159
|
+
* organization's.
|
|
160
|
+
*/
|
|
161
|
+
async function targetOrganization(db, target, objects) {
|
|
162
|
+
const containerIds = objects
|
|
163
|
+
.filter((object) => object.kind === "container")
|
|
164
|
+
.map((object) => object.id);
|
|
165
|
+
const listed = containerIds.length === 0
|
|
166
|
+
? []
|
|
167
|
+
: await db
|
|
168
|
+
.select({ organizationId: containers.organizationId })
|
|
169
|
+
.from(containers)
|
|
170
|
+
.where(inArray(containers.id, containerIds));
|
|
171
|
+
const verifiedContainers = containerIds.length === 0
|
|
172
|
+
? []
|
|
173
|
+
: await db
|
|
174
|
+
.select({ organizationId: bundles.organizationId })
|
|
175
|
+
.from(bundles)
|
|
176
|
+
.where(and(eq(bundles.objectKind, "container"), inArray(bundles.objectId, containerIds)));
|
|
177
|
+
const verifiedTarget = await db
|
|
178
|
+
.select({ organizationId: bundles.organizationId })
|
|
179
|
+
.from(bundles)
|
|
180
|
+
.where(and(eq(bundles.objectKind, target.kind), eq(bundles.objectId, target.id)));
|
|
181
|
+
const discovered = target.kind === "document"
|
|
182
|
+
? await db
|
|
183
|
+
.select({ organizationId: documentDiscoveryHeads.organizationId })
|
|
184
|
+
.from(documentDiscoveryHeads)
|
|
185
|
+
.where(eq(documentDiscoveryHeads.documentId, target.id))
|
|
186
|
+
: [];
|
|
187
|
+
const sources = [listed, verifiedContainers, verifiedTarget, discovered];
|
|
188
|
+
const organizations = new Set(sources.flat().map((row) => row.organizationId));
|
|
189
|
+
const [organizationId] = organizations;
|
|
190
|
+
return organizations.size === 1 && organizationId ? organizationId : null;
|
|
191
|
+
}
|
|
192
|
+
const storedColumns = {
|
|
193
|
+
bundleDigest: bundles.bundleDigest,
|
|
194
|
+
bundleJson: bundles.bundleJson,
|
|
195
|
+
manifestHash: bundles.manifestHash,
|
|
196
|
+
};
|
|
197
|
+
async function readStoredBundle(row) {
|
|
198
|
+
if ((await sha256Hex(row.bundleJson)) !== row.bundleDigest)
|
|
199
|
+
return null;
|
|
200
|
+
try {
|
|
201
|
+
const bundle = JSON.parse(row.bundleJson);
|
|
202
|
+
return isAccessManifestBundleWireResponse(bundle) &&
|
|
203
|
+
bundle.manifestHash === row.manifestHash
|
|
204
|
+
? bundle
|
|
205
|
+
: null;
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function objectRows(db, organizationId, object, limit) {
|
|
212
|
+
return db
|
|
213
|
+
.select(storedColumns)
|
|
214
|
+
.from(bundles)
|
|
215
|
+
.where(and(eq(bundles.organizationId, organizationId), eq(bundles.objectKind, object.kind), eq(bundles.objectId, object.id)))
|
|
216
|
+
.orderBy(desc(bundles.epoch))
|
|
217
|
+
.limit(limit);
|
|
218
|
+
}
|
|
219
|
+
function recentRows(db, organizationId, limit) {
|
|
220
|
+
return db
|
|
221
|
+
.select(storedColumns)
|
|
222
|
+
.from(bundles)
|
|
223
|
+
.where(eq(bundles.organizationId, organizationId))
|
|
224
|
+
.orderBy(desc(bundles.verifiedAt), asc(bundles.manifestHash))
|
|
225
|
+
.limit(limit);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Verified bundles of the target's object and of the containers its
|
|
229
|
+
* projection walks, newest epochs first; then the most recently verified rows
|
|
230
|
+
* of its organization, since a just-verified parent is the likeliest part of
|
|
231
|
+
* a new child's projection. Citations never leave the target's organization:
|
|
232
|
+
* an object whose organization the device cannot place cites nothing.
|
|
233
|
+
* Damaged rows are dropped.
|
|
234
|
+
*/
|
|
235
|
+
export async function loadVerifiedManifestCitations(execSql, target, limit = KNOWN_MANIFEST_HINT_LIMIT) {
|
|
236
|
+
await ensureSqlTables(execSql, [
|
|
237
|
+
...verifiedManifestBundleTables,
|
|
238
|
+
...containerTables,
|
|
239
|
+
...documentContainerProjectionTables,
|
|
240
|
+
]);
|
|
241
|
+
const { db } = getClientSQLitePersistenceRuntime(execSql);
|
|
242
|
+
const cited = new Map();
|
|
243
|
+
const damaged = [];
|
|
244
|
+
const collect = async (rows) => {
|
|
245
|
+
for (const row of rows) {
|
|
246
|
+
if (cited.size >= limit || cited.has(row.manifestHash))
|
|
247
|
+
continue;
|
|
248
|
+
const bundle = await readStoredBundle(row);
|
|
249
|
+
if (bundle)
|
|
250
|
+
cited.set(row.manifestHash, bundle);
|
|
251
|
+
else
|
|
252
|
+
damaged.push(row.manifestHash);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const objects = await citedObjects(db, target);
|
|
256
|
+
const organizationId = await targetOrganization(db, target, objects);
|
|
257
|
+
if (organizationId === null)
|
|
258
|
+
return [];
|
|
259
|
+
for (const object of objects)
|
|
260
|
+
if (cited.size < limit)
|
|
261
|
+
await collect(await objectRows(db, organizationId, object, limit - cited.size));
|
|
262
|
+
if (cited.size < limit)
|
|
263
|
+
await collect(await recentRows(db, organizationId, limit + cited.size));
|
|
264
|
+
if (damaged.length > 0)
|
|
265
|
+
await getClientSQLitePersistenceRuntime(execSql)
|
|
266
|
+
.runMutation((handle) => handle
|
|
267
|
+
.delete(bundles)
|
|
268
|
+
.where(inArray(bundles.manifestHash, damaged))
|
|
269
|
+
.run())
|
|
270
|
+
.catch(() => undefined);
|
|
271
|
+
return [...cited.values()];
|
|
272
|
+
}
|
|
273
|
+
/** Cites from whichever database the signed-in identity currently uses. */
|
|
274
|
+
export function createVerifiedManifestCitations(resolveExecSql) {
|
|
275
|
+
return {
|
|
276
|
+
cite: async (target) => {
|
|
277
|
+
const execSql = resolveExecSql();
|
|
278
|
+
return execSql ? loadVerifiedManifestCitations(execSql, target) : [];
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=verifiedManifestBundlePersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifiedManifestBundlePersistence.js","sourceRoot":"","sources":["verifiedManifestBundlePersistence.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAEL,kCAAkC,GACnC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,iCAAiC,GAClC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,iCAAiC,GAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAgB,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EACL,6BAA6B,IAAI,OAAO,EACxC,4BAA4B,GAC7B,MAAM,wCAAwC,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;AAClD,MAAM,eAAe,GAAG,GAAG,CAAC;AAY5B,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,aAAa,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,OAAO,CAAI,MAAoB;IACtC,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,eAAe;QACjE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,EAAgC;IAEhC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,6BAA6B,CAAC;IACjE,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO;IACxB,MAAM,OAAO,GAAG,MAAM,EAAE;SACrB,MAAM,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;SAC9C,IAAI,CAAC,OAAO,CAAC;SACb,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;SAC3D,KAAK,CAAC,MAAM,CAAC,CAAC;IACjB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACrE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAC/E,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA0C;IAE1C,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAC3D,CAAC;IACF,OAAO,OAAO,CAAC,GAAG,CAChB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO;YACL,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,cAAc,EAAE,UAAU,CAAC,cAAc;YACzC,UAAU,EAAE,UAAU,CAAC,UAAU;YACjC,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,UAAU;YACV,YAAY,EAAE,MAAM,SAAS,CAAC,UAAU,CAAC;SAC1C,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yCAAyC,CAC7D,EAAgC,EAChC,IAA0C,EAC1C,UAAkB;IAElB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,EACF,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CACpC,CAAC;IACF,4DAA4D;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,YAAY,CAC3D,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACnE,MAAM,EAAE;aACL,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC;aACnB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;aAC3C,GAAG,EAAE,CAAC;IACX,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,YAAY;YAAE,SAAS;QAChE,MAAM,QAAQ,GAAG,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC;QACxC,MAAM,EAAE;aACL,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC,QAAQ,CAAC;aAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;aACnE,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,kBAAkB,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,EAAgC,EAChC,cAAiC;IAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,MAAM,EAAE;aAClB,MAAM,CAAC;YACN,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAC;aACD,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,gBAAgB,CAC7B,EAAwB,EACxB,WAAmB;IAEnB,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,MAAM,GAAG,yBAAyB,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;aACnB,MAAM,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;aACzC,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;aAC9C,KAAK,CAAC,CAAC,CAAC,CAAC;QACZ,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,CAAC;QAC/B,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,MAAM;QACnD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,EAAwB,EACxB,MAA8B;IAE9B,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;QAC7B,OAAO,CAAC,MAAM,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1D,IAAI,EAAE,WAAW;YACjB,EAAE;SACH,CAAC,CAAC,CAAC;IACN,uEAAuE;IACvE,uEAAuE;IACvE,MAAM,UAAU,GAAG;QACjB,GAAG,CAAC,MAAM,EAAE;aACT,MAAM,CAAC,EAAE,WAAW,EAAE,2BAA2B,CAAC,WAAW,EAAE,CAAC;aAChE,IAAI,CAAC,2BAA2B,CAAC;aACjC,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAChE,GAAG,CAAC,MAAM,EAAE;aACT,MAAM,CAAC,EAAE,WAAW,EAAE,0BAA0B,CAAC,WAAW,EAAE,CAAC;aAC/D,IAAI,CAAC,0BAA0B,CAAC;aAChC,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/D,GAAG,CAAC,MAAM,EAAE;aACT,MAAM,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC;aACtC,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;KACxD,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,KAAK,MAAM,EAAE,WAAW,EAAE,IAAI,UAAU;QACtC,IAAI,WAAW;YACb,KAAK,MAAM,EAAE,IAAI,MAAM,gBAAgB,CAAC,EAAE,EAAE,WAAW,CAAC;gBACtD,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO;QACL,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;QACnC,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,kBAAkB,CAC/B,EAAwB,EACxB,MAA8B,EAC9B,OAAkE;IAElE,MAAM,YAAY,GAAG,OAAO;SACzB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC;SAC/C,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GACV,YAAY,CAAC,MAAM,KAAK,CAAC;QACvB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,MAAM,EAAE;aACL,MAAM,CAAC,EAAE,cAAc,EAAE,UAAU,CAAC,cAAc,EAAE,CAAC;aACrD,IAAI,CAAC,UAAU,CAAC;aAChB,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC;IACrD,MAAM,kBAAkB,GACtB,YAAY,CAAC,MAAM,KAAK,CAAC;QACvB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,MAAM,EAAE;aACL,MAAM,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC;aAClD,IAAI,CAAC,OAAO,CAAC;aACb,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,EACnC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CACxC,CACF,CAAC;IACV,MAAM,cAAc,GAAG,MAAM,EAAE;SAC5B,MAAM,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC;SAClD,IAAI,CAAC,OAAO,CAAC;SACb,KAAK,CACJ,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAC1E,CAAC;IACJ,MAAM,UAAU,GACd,MAAM,CAAC,IAAI,KAAK,UAAU;QACxB,CAAC,CAAC,MAAM,EAAE;aACL,MAAM,CAAC,EAAE,cAAc,EAAE,sBAAsB,CAAC,cAAc,EAAE,CAAC;aACjE,IAAI,CAAC,sBAAsB,CAAC;aAC5B,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAChD,CAAC;IACF,MAAM,CAAC,cAAc,CAAC,GAAG,aAAa,CAAC;IACvC,OAAO,aAAa,CAAC,IAAI,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5E,CAAC;AAQD,MAAM,aAAa,GAAG;IACpB,YAAY,EAAE,OAAO,CAAC,YAAY;IAClC,UAAU,EAAE,OAAO,CAAC,UAAU;IAC9B,YAAY,EAAE,OAAO,CAAC,YAAY;CACnC,CAAC;AAEF,KAAK,UAAU,gBAAgB,CAC7B,GAAoB;IAEpB,IAAI,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,KAAK,GAAG,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnD,OAAO,kCAAkC,CAAC,MAAM,CAAC;YAC/C,MAAM,CAAC,YAAY,KAAK,GAAG,CAAC,YAAY;YACxC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CACjB,EAAwB,EACxB,cAAsB,EACtB,MAAsD,EACtD,KAAa;IAEb,OAAO,EAAE;SACN,MAAM,CAAC,aAAa,CAAC;SACrB,IAAI,CAAC,OAAO,CAAC;SACb,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,EAC1C,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,EACnC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAChC,CACF;SACA,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;SAC5B,KAAK,CAAC,KAAK,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,UAAU,CACjB,EAAwB,EACxB,cAAsB,EACtB,KAAa;IAEb,OAAO,EAAE;SACN,MAAM,CAAC,aAAa,CAAC;SACrB,IAAI,CAAC,OAAO,CAAC;SACb,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;SACjD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;SAC5D,KAAK,CAAC,KAAK,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAgB,EAChB,MAA8B,EAC9B,KAAK,GAAG,yBAAyB;IAEjC,MAAM,eAAe,CAAC,OAAO,EAAE;QAC7B,GAAG,4BAA4B;QAC/B,GAAG,eAAe;QAClB,GAAG,iCAAiC;KACrC,CAAC,CAAC;IACH,MAAM,EAAE,EAAE,EAAE,GAAG,iCAAiC,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4C,CAAC;IAClE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,KAAK,EAAE,IAAgC,EAAE,EAAE;QACzD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;gBAAE,SAAS;YACjE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,MAAM;gBAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;;gBAC3C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACrE,IAAI,cAAc,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACvC,KAAK,MAAM,MAAM,IAAI,OAAO;QAC1B,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK;YACpB,MAAM,OAAO,CACX,MAAM,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CACjE,CAAC;IACN,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK;QACpB,MAAM,OAAO,CAAC,MAAM,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QACpB,MAAM,iCAAiC,CAAC,OAAO,CAAC;aAC7C,WAAW,CAAC,CAAC,MAAM,EAAE,EAAE,CACtB,MAAM;aACH,MAAM,CAAC,OAAO,CAAC;aACf,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;aAC7C,GAAG,EAAE,CACT;aACA,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,+BAA+B,CAC7C,cAAoC;IAEpC,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACrB,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n VerifiedManifestCitations,\n WriterProjectionTarget,\n} from \"@tearleads/api-client\";\nimport { toFingerprint } from \"@tearleads/crypto\";\nimport {\n type AccessManifestBundleWireResponse,\n isAccessManifestBundleWireResponse,\n} from \"@tearleads/validators/response\";\nimport {\n KNOWN_MANIFEST_HINT_LIMIT,\n MAX_CONTAINER_PATH_LENGTH,\n} from \"@tearleads/validators/util\";\nimport { and, asc, desc, eq, inArray, sql } from \"drizzle-orm\";\nimport { containers } from \"../sqlite/containerSchema\";\nimport {\n documentDiscoveryHeads,\n pendingDocumentDiscoveries,\n} from \"../sqlite/documentDiscoveryEvidenceSchema\";\nimport {\n containerTables,\n documentContainerProjection,\n documentContainerProjectionTables,\n} from \"../sqlite/schema\";\nimport {\n type ClientSQLiteDatabase,\n type ClientSQLiteTransactionScope,\n getClientSQLitePersistenceRuntime,\n} from \"../sqlite/sqlitePersistenceRuntime\";\nimport { type ExecSql, ensureSqlTables } from \"../sqlite/sqlSchema\";\nimport {\n verifiedAccessManifestBundles as bundles,\n verifiedManifestBundleTables,\n} from \"../sqlite/verifiedManifestBundleSchema\";\n\n/**\n * Bounds local bytes (a bundle is ~10–20 KB). Evicting the least recently\n * verified rows only makes a later read carry those bundles again.\n */\nexport const MAX_VERIFIED_MANIFEST_BUNDLES = 1024;\nconst STATEMENT_BATCH = 200;\n\nexport interface VerifiedManifestBundle {\n readonly bundle: AccessManifestBundleWireResponse;\n readonly checkpoint: {\n readonly objectKind: string;\n readonly organizationId: string;\n readonly objectId: string;\n readonly epoch: number;\n };\n}\n\nfunction sha256Hex(text: string): Promise<string> {\n return toFingerprint(new TextEncoder().encode(text));\n}\n\nfunction batches<T>(values: readonly T[]): T[][] {\n const result: T[][] = [];\n for (let index = 0; index < values.length; index += STATEMENT_BATCH)\n result.push(values.slice(index, index + STATEMENT_BATCH));\n return result;\n}\n\nasync function pruneInTransaction(\n tx: ClientSQLiteTransactionScope,\n): Promise<void> {\n const [row] = await tx.select({ count: sql<number>`count(*)` }).from(bundles);\n const excess = (row?.count ?? 0) - MAX_VERIFIED_MANIFEST_BUNDLES;\n if (excess <= 0) return;\n const evicted = await tx\n .select({ manifestHash: bundles.manifestHash })\n .from(bundles)\n .orderBy(asc(bundles.verifiedAt), asc(bundles.manifestHash))\n .limit(excess);\n for (const batch of batches(evicted.map((entry) => entry.manifestHash)))\n await tx.delete(bundles).where(inArray(bundles.manifestHash, batch)).run();\n}\n\n/** A verified bundle's exact JSON and that JSON's digest. */\nexport type VerifiedManifestBundleRow = Omit<\n typeof bundles.$inferInsert,\n \"verifiedAt\"\n>;\n\n/**\n * Prepares rows for bundles that just passed projection verification. The\n * digests are computed here, before the checkpoint transaction that writes\n * them begins.\n */\nexport function verifiedManifestBundleRows(\n entries: readonly VerifiedManifestBundle[],\n): Promise<VerifiedManifestBundleRow[]> {\n const unique = new Map(\n entries.map((entry) => [entry.bundle.manifestHash, entry]),\n );\n return Promise.all(\n [...unique.values()].map(async ({ bundle, checkpoint }) => {\n const bundleJson = JSON.stringify(bundle);\n return {\n manifestHash: bundle.manifestHash,\n organizationId: checkpoint.organizationId,\n objectKind: checkpoint.objectKind,\n objectId: checkpoint.objectId,\n epoch: checkpoint.epoch,\n bundleJson,\n bundleDigest: await sha256Hex(bundleJson),\n };\n }),\n );\n}\n\n/**\n * Records verified bundles inside the transaction that finalizes their\n * projection's checkpoints, so they commit or roll back with it and no cache\n * work outlives the verification. Freshly verified bytes replace any stored\n * copy.\n */\nexport async function writeVerifiedManifestBundlesInTransaction(\n tx: ClientSQLiteTransactionScope,\n rows: readonly VerifiedManifestBundleRow[],\n verifiedAt: string,\n): Promise<void> {\n if (rows.length === 0) return;\n const stored = await storedDigests(\n tx,\n rows.map((row) => row.manifestHash),\n );\n // An identical stored row only needs its recency refreshed.\n const unchanged = rows.filter(\n (row) => stored.get(row.manifestHash) === row.bundleDigest,\n );\n for (const batch of batches(unchanged.map((row) => row.manifestHash)))\n await tx\n .update(bundles)\n .set({ verifiedAt })\n .where(inArray(bundles.manifestHash, batch))\n .run();\n for (const row of rows) {\n if (stored.get(row.manifestHash) === row.bundleDigest) continue;\n const verified = { ...row, verifiedAt };\n await tx\n .insert(bundles)\n .values(verified)\n .onConflictDoUpdate({ target: bundles.manifestHash, set: verified })\n .run();\n }\n await pruneInTransaction(tx);\n}\n\nasync function storedDigests(\n tx: ClientSQLiteTransactionScope,\n manifestHashes: readonly string[],\n): Promise<Map<string, string>> {\n const digests = new Map<string, string>();\n for (const batch of batches(manifestHashes)) {\n const rows = await tx\n .select({\n bundleDigest: bundles.bundleDigest,\n manifestHash: bundles.manifestHash,\n })\n .from(bundles)\n .where(inArray(bundles.manifestHash, batch));\n for (const row of rows) digests.set(row.manifestHash, row.bundleDigest);\n }\n return digests;\n}\n\n/** The requested object first, then each container whose lineage it cites. */\nasync function containerLineage(\n db: ClientSQLiteDatabase,\n containerId: string,\n): Promise<string[]> {\n const lineage = [containerId];\n while (lineage.length < MAX_CONTAINER_PATH_LENGTH) {\n const [row] = await db\n .select({ parentId: containers.parentId })\n .from(containers)\n .where(eq(containers.id, lineage.at(-1) ?? \"\"))\n .limit(1);\n const parentId = row?.parentId;\n if (!parentId || lineage.includes(parentId)) break;\n lineage.push(parentId);\n }\n return lineage;\n}\n\nasync function citedObjects(\n db: ClientSQLiteDatabase,\n target: WriterProjectionTarget,\n): Promise<{ readonly kind: string; readonly id: string }[]> {\n if (target.kind === \"container\")\n return (await containerLineage(db, target.id)).map((id) => ({\n kind: \"container\",\n id,\n }));\n // Linked containers, containers listing the document before its signed\n // placement is checked, and a container whose metadata document it is.\n const placements = [\n ...(await db\n .select({ containerId: documentContainerProjection.containerId })\n .from(documentContainerProjection)\n .where(eq(documentContainerProjection.documentId, target.id))),\n ...(await db\n .select({ containerId: pendingDocumentDiscoveries.containerId })\n .from(pendingDocumentDiscoveries)\n .where(eq(pendingDocumentDiscoveries.documentId, target.id))),\n ...(await db\n .select({ containerId: containers.id })\n .from(containers)\n .where(eq(containers.metadataDocumentId, target.id))),\n ];\n const containerIds = new Set<string>();\n for (const { containerId } of placements)\n if (containerId)\n for (const id of await containerLineage(db, containerId))\n containerIds.add(id);\n return [\n { kind: \"document\", id: target.id },\n ...[...containerIds].map((id) => ({ kind: \"container\", id })),\n ];\n}\n\n/**\n * The one organization every local source places the read in. Verified\n * ownership (stored verified bundles of the target and of the containers on\n * its walk, and a document's verified discovery head) and local placement\n * (listed container rows reached through links, pending listings, metadata,\n * or parents) must all agree: any disagreement, or no source at all, yields\n * null, so the read is sent with no hints rather than another\n * organization's.\n */\nasync function targetOrganization(\n db: ClientSQLiteDatabase,\n target: WriterProjectionTarget,\n objects: readonly { readonly kind: string; readonly id: string }[],\n): Promise<string | null> {\n const containerIds = objects\n .filter((object) => object.kind === \"container\")\n .map((object) => object.id);\n const listed =\n containerIds.length === 0\n ? []\n : await db\n .select({ organizationId: containers.organizationId })\n .from(containers)\n .where(inArray(containers.id, containerIds));\n const verifiedContainers =\n containerIds.length === 0\n ? []\n : await db\n .select({ organizationId: bundles.organizationId })\n .from(bundles)\n .where(\n and(\n eq(bundles.objectKind, \"container\"),\n inArray(bundles.objectId, containerIds),\n ),\n );\n const verifiedTarget = await db\n .select({ organizationId: bundles.organizationId })\n .from(bundles)\n .where(\n and(eq(bundles.objectKind, target.kind), eq(bundles.objectId, target.id)),\n );\n const discovered =\n target.kind === \"document\"\n ? await db\n .select({ organizationId: documentDiscoveryHeads.organizationId })\n .from(documentDiscoveryHeads)\n .where(eq(documentDiscoveryHeads.documentId, target.id))\n : [];\n const sources = [listed, verifiedContainers, verifiedTarget, discovered];\n const organizations = new Set(\n sources.flat().map((row) => row.organizationId),\n );\n const [organizationId] = organizations;\n return organizations.size === 1 && organizationId ? organizationId : null;\n}\n\ninterface StoredBundleRow {\n readonly bundleDigest: string;\n readonly bundleJson: string;\n readonly manifestHash: string;\n}\n\nconst storedColumns = {\n bundleDigest: bundles.bundleDigest,\n bundleJson: bundles.bundleJson,\n manifestHash: bundles.manifestHash,\n};\n\nasync function readStoredBundle(\n row: StoredBundleRow,\n): Promise<AccessManifestBundleWireResponse | null> {\n if ((await sha256Hex(row.bundleJson)) !== row.bundleDigest) return null;\n try {\n const bundle: unknown = JSON.parse(row.bundleJson);\n return isAccessManifestBundleWireResponse(bundle) &&\n bundle.manifestHash === row.manifestHash\n ? bundle\n : null;\n } catch {\n return null;\n }\n}\n\nfunction objectRows(\n db: ClientSQLiteDatabase,\n organizationId: string,\n object: { readonly kind: string; readonly id: string },\n limit: number,\n) {\n return db\n .select(storedColumns)\n .from(bundles)\n .where(\n and(\n eq(bundles.organizationId, organizationId),\n eq(bundles.objectKind, object.kind),\n eq(bundles.objectId, object.id),\n ),\n )\n .orderBy(desc(bundles.epoch))\n .limit(limit);\n}\n\nfunction recentRows(\n db: ClientSQLiteDatabase,\n organizationId: string,\n limit: number,\n) {\n return db\n .select(storedColumns)\n .from(bundles)\n .where(eq(bundles.organizationId, organizationId))\n .orderBy(desc(bundles.verifiedAt), asc(bundles.manifestHash))\n .limit(limit);\n}\n\n/**\n * Verified bundles of the target's object and of the containers its\n * projection walks, newest epochs first; then the most recently verified rows\n * of its organization, since a just-verified parent is the likeliest part of\n * a new child's projection. Citations never leave the target's organization:\n * an object whose organization the device cannot place cites nothing.\n * Damaged rows are dropped.\n */\nexport async function loadVerifiedManifestCitations(\n execSql: ExecSql,\n target: WriterProjectionTarget,\n limit = KNOWN_MANIFEST_HINT_LIMIT,\n): Promise<AccessManifestBundleWireResponse[]> {\n await ensureSqlTables(execSql, [\n ...verifiedManifestBundleTables,\n ...containerTables,\n ...documentContainerProjectionTables,\n ]);\n const { db } = getClientSQLitePersistenceRuntime(execSql);\n const cited = new Map<string, AccessManifestBundleWireResponse>();\n const damaged: string[] = [];\n const collect = async (rows: readonly StoredBundleRow[]) => {\n for (const row of rows) {\n if (cited.size >= limit || cited.has(row.manifestHash)) continue;\n const bundle = await readStoredBundle(row);\n if (bundle) cited.set(row.manifestHash, bundle);\n else damaged.push(row.manifestHash);\n }\n };\n const objects = await citedObjects(db, target);\n const organizationId = await targetOrganization(db, target, objects);\n if (organizationId === null) return [];\n for (const object of objects)\n if (cited.size < limit)\n await collect(\n await objectRows(db, organizationId, object, limit - cited.size),\n );\n if (cited.size < limit)\n await collect(await recentRows(db, organizationId, limit + cited.size));\n if (damaged.length > 0)\n await getClientSQLitePersistenceRuntime(execSql)\n .runMutation((handle) =>\n handle\n .delete(bundles)\n .where(inArray(bundles.manifestHash, damaged))\n .run(),\n )\n .catch(() => undefined);\n return [...cited.values()];\n}\n\n/** Cites from whichever database the signed-in identity currently uses. */\nexport function createVerifiedManifestCitations(\n resolveExecSql: () => ExecSql | null,\n): VerifiedManifestCitations {\n return {\n cite: async (target) => {\n const execSql = resolveExecSql();\n return execSql ? loadVerifiedManifestCitations(execSql, target) : [];\n },\n };\n}\n"]}
|
package/data/sqlite/schema.d.ts
CHANGED
|
@@ -9001,6 +9001,163 @@ export declare const clientSQLiteSchema: {
|
|
|
9001
9001
|
};
|
|
9002
9002
|
dialect: "sqlite";
|
|
9003
9003
|
}>;
|
|
9004
|
+
verifiedAccessManifestBundles: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
9005
|
+
name: "verified_access_manifest_bundles";
|
|
9006
|
+
schema: undefined;
|
|
9007
|
+
columns: {
|
|
9008
|
+
manifestHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9009
|
+
name: "manifest_hash";
|
|
9010
|
+
tableName: "verified_access_manifest_bundles";
|
|
9011
|
+
dataType: "string";
|
|
9012
|
+
columnType: "SQLiteText";
|
|
9013
|
+
data: string;
|
|
9014
|
+
driverParam: string;
|
|
9015
|
+
notNull: true;
|
|
9016
|
+
hasDefault: false;
|
|
9017
|
+
isPrimaryKey: true;
|
|
9018
|
+
isAutoincrement: false;
|
|
9019
|
+
hasRuntimeDefault: false;
|
|
9020
|
+
enumValues: [string, ...string[]];
|
|
9021
|
+
baseColumn: never;
|
|
9022
|
+
identity: undefined;
|
|
9023
|
+
generated: undefined;
|
|
9024
|
+
}, {}, {
|
|
9025
|
+
length: number | undefined;
|
|
9026
|
+
}>;
|
|
9027
|
+
organizationId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9028
|
+
name: "organization_id";
|
|
9029
|
+
tableName: "verified_access_manifest_bundles";
|
|
9030
|
+
dataType: "string";
|
|
9031
|
+
columnType: "SQLiteText";
|
|
9032
|
+
data: string;
|
|
9033
|
+
driverParam: string;
|
|
9034
|
+
notNull: true;
|
|
9035
|
+
hasDefault: false;
|
|
9036
|
+
isPrimaryKey: false;
|
|
9037
|
+
isAutoincrement: false;
|
|
9038
|
+
hasRuntimeDefault: false;
|
|
9039
|
+
enumValues: [string, ...string[]];
|
|
9040
|
+
baseColumn: never;
|
|
9041
|
+
identity: undefined;
|
|
9042
|
+
generated: undefined;
|
|
9043
|
+
}, {}, {
|
|
9044
|
+
length: number | undefined;
|
|
9045
|
+
}>;
|
|
9046
|
+
objectKind: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9047
|
+
name: "object_kind";
|
|
9048
|
+
tableName: "verified_access_manifest_bundles";
|
|
9049
|
+
dataType: "string";
|
|
9050
|
+
columnType: "SQLiteText";
|
|
9051
|
+
data: string;
|
|
9052
|
+
driverParam: string;
|
|
9053
|
+
notNull: true;
|
|
9054
|
+
hasDefault: false;
|
|
9055
|
+
isPrimaryKey: false;
|
|
9056
|
+
isAutoincrement: false;
|
|
9057
|
+
hasRuntimeDefault: false;
|
|
9058
|
+
enumValues: [string, ...string[]];
|
|
9059
|
+
baseColumn: never;
|
|
9060
|
+
identity: undefined;
|
|
9061
|
+
generated: undefined;
|
|
9062
|
+
}, {}, {
|
|
9063
|
+
length: number | undefined;
|
|
9064
|
+
}>;
|
|
9065
|
+
objectId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9066
|
+
name: "object_id";
|
|
9067
|
+
tableName: "verified_access_manifest_bundles";
|
|
9068
|
+
dataType: "string";
|
|
9069
|
+
columnType: "SQLiteText";
|
|
9070
|
+
data: string;
|
|
9071
|
+
driverParam: string;
|
|
9072
|
+
notNull: true;
|
|
9073
|
+
hasDefault: false;
|
|
9074
|
+
isPrimaryKey: false;
|
|
9075
|
+
isAutoincrement: false;
|
|
9076
|
+
hasRuntimeDefault: false;
|
|
9077
|
+
enumValues: [string, ...string[]];
|
|
9078
|
+
baseColumn: never;
|
|
9079
|
+
identity: undefined;
|
|
9080
|
+
generated: undefined;
|
|
9081
|
+
}, {}, {
|
|
9082
|
+
length: number | undefined;
|
|
9083
|
+
}>;
|
|
9084
|
+
epoch: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9085
|
+
name: "epoch";
|
|
9086
|
+
tableName: "verified_access_manifest_bundles";
|
|
9087
|
+
dataType: "number";
|
|
9088
|
+
columnType: "SQLiteInteger";
|
|
9089
|
+
data: number;
|
|
9090
|
+
driverParam: number;
|
|
9091
|
+
notNull: true;
|
|
9092
|
+
hasDefault: false;
|
|
9093
|
+
isPrimaryKey: false;
|
|
9094
|
+
isAutoincrement: false;
|
|
9095
|
+
hasRuntimeDefault: false;
|
|
9096
|
+
enumValues: undefined;
|
|
9097
|
+
baseColumn: never;
|
|
9098
|
+
identity: undefined;
|
|
9099
|
+
generated: undefined;
|
|
9100
|
+
}, {}, {}>;
|
|
9101
|
+
bundleJson: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9102
|
+
name: "bundle_json";
|
|
9103
|
+
tableName: "verified_access_manifest_bundles";
|
|
9104
|
+
dataType: "string";
|
|
9105
|
+
columnType: "SQLiteText";
|
|
9106
|
+
data: string;
|
|
9107
|
+
driverParam: string;
|
|
9108
|
+
notNull: true;
|
|
9109
|
+
hasDefault: false;
|
|
9110
|
+
isPrimaryKey: false;
|
|
9111
|
+
isAutoincrement: false;
|
|
9112
|
+
hasRuntimeDefault: false;
|
|
9113
|
+
enumValues: [string, ...string[]];
|
|
9114
|
+
baseColumn: never;
|
|
9115
|
+
identity: undefined;
|
|
9116
|
+
generated: undefined;
|
|
9117
|
+
}, {}, {
|
|
9118
|
+
length: number | undefined;
|
|
9119
|
+
}>;
|
|
9120
|
+
bundleDigest: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9121
|
+
name: "bundle_digest";
|
|
9122
|
+
tableName: "verified_access_manifest_bundles";
|
|
9123
|
+
dataType: "string";
|
|
9124
|
+
columnType: "SQLiteText";
|
|
9125
|
+
data: string;
|
|
9126
|
+
driverParam: string;
|
|
9127
|
+
notNull: true;
|
|
9128
|
+
hasDefault: false;
|
|
9129
|
+
isPrimaryKey: false;
|
|
9130
|
+
isAutoincrement: false;
|
|
9131
|
+
hasRuntimeDefault: false;
|
|
9132
|
+
enumValues: [string, ...string[]];
|
|
9133
|
+
baseColumn: never;
|
|
9134
|
+
identity: undefined;
|
|
9135
|
+
generated: undefined;
|
|
9136
|
+
}, {}, {
|
|
9137
|
+
length: number | undefined;
|
|
9138
|
+
}>;
|
|
9139
|
+
verifiedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
9140
|
+
name: "verified_at";
|
|
9141
|
+
tableName: "verified_access_manifest_bundles";
|
|
9142
|
+
dataType: "string";
|
|
9143
|
+
columnType: "SQLiteText";
|
|
9144
|
+
data: string;
|
|
9145
|
+
driverParam: string;
|
|
9146
|
+
notNull: true;
|
|
9147
|
+
hasDefault: false;
|
|
9148
|
+
isPrimaryKey: false;
|
|
9149
|
+
isAutoincrement: false;
|
|
9150
|
+
hasRuntimeDefault: false;
|
|
9151
|
+
enumValues: [string, ...string[]];
|
|
9152
|
+
baseColumn: never;
|
|
9153
|
+
identity: undefined;
|
|
9154
|
+
generated: undefined;
|
|
9155
|
+
}, {}, {
|
|
9156
|
+
length: number | undefined;
|
|
9157
|
+
}>;
|
|
9158
|
+
};
|
|
9159
|
+
dialect: "sqlite";
|
|
9160
|
+
}>;
|
|
9004
9161
|
trustedUserIdentityPins: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
9005
9162
|
name: "trusted_user_identity_pins";
|
|
9006
9163
|
schema: undefined;
|
package/data/sqlite/schema.js
CHANGED
|
@@ -19,6 +19,7 @@ import { principalMutationJournal, principalMutationJournalTables, } from "./pri
|
|
|
19
19
|
import { principalPolicies, principalPolicyBundleHistory, principalPolicyBundleReferences, principalPolicyCheckpoints, principalPolicyOrganizations, } from "./principalPolicySchema.js";
|
|
20
20
|
import { securityIncidents, securityIncidentTable, } from "./securityIncidentSchema.js";
|
|
21
21
|
import { defineSqlTableSchema } from "./sqlTableSchema.js";
|
|
22
|
+
import { verifiedAccessManifestBundles, verifiedManifestBundleTables, } from "./verifiedManifestBundleSchema.js";
|
|
22
23
|
export { containerHydrationTombstones, containerProjection, containers, dormantContainerMetadata, dormantMetadataSweepRequests, supersededContainerBindings, } from "./containerSchema.js";
|
|
23
24
|
export { documentAttachmentBlobProjection, documentPendingAttachments, } from "./documentAttachmentSchema.js";
|
|
24
25
|
export { documentMoveIntents } from "./documentPlacementIntentSchema.js";
|
|
@@ -588,6 +589,7 @@ export const clientSqlTables = [
|
|
|
588
589
|
...documentTables,
|
|
589
590
|
...principalPolicyTables,
|
|
590
591
|
...keyingCheckpointTables,
|
|
592
|
+
...verifiedManifestBundleTables,
|
|
591
593
|
...trustedUserIdentityPinTables,
|
|
592
594
|
...securityIncidentTables,
|
|
593
595
|
...containerTables,
|
|
@@ -623,6 +625,7 @@ export const clientSQLiteSchema = {
|
|
|
623
625
|
accessManifestCheckpoints,
|
|
624
626
|
documentPurgeCheckpoints,
|
|
625
627
|
principalPolicyCheckpoints,
|
|
628
|
+
verifiedAccessManifestBundles,
|
|
626
629
|
trustedUserIdentityPins,
|
|
627
630
|
securityIncidents,
|
|
628
631
|
...containerSQLiteSchema,
|