@tearleads/client-sdk 0.1.77 → 0.1.79
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/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobEnvelopeStream.js.map +1 -1
- package/data/blobs/attachments/blobRecordCrypto.d.ts +26 -0
- package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js +2 -2
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.d.ts +1 -1
- package/data/{documents/blob/shared → blobs/attachments}/blobSourceSnapshot.js +2 -2
- package/data/blobs/attachments/blobSourceSnapshot.js.map +1 -0
- package/data/blobs/attachments/chunkedBlobCrypto.d.ts +17 -0
- package/data/{documents/blob/shared → blobs/attachments}/chunkedBlobCrypto.js +3 -3
- package/data/blobs/attachments/chunkedBlobCrypto.js.map +1 -0
- package/data/blobs/attachments/crypto.d.ts +3 -0
- package/data/blobs/attachments/encryptedUploadParts.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/events.js +3 -3
- package/data/blobs/attachments/events.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/projection.js +8 -8
- package/data/blobs/attachments/projection.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/readers.js +3 -3
- package/data/blobs/attachments/readers.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/responses.js +2 -2
- package/data/blobs/attachments/responses.js.map +1 -0
- package/data/{documents/blob/shared → blobs/attachments}/types.d.ts +8 -8
- package/data/blobs/attachments/types.js.map +1 -0
- package/data/{sync → documents/shared/sync}/documentSyncOutgoingBatch.d.ts +1 -1
- package/data/{sync → documents/shared/sync}/documentSyncOutgoingBatch.js +1 -1
- package/package.json +1 -1
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js +1 -2
- package/stores/documents/documentStore/attachmentUpload/attachmentSourceUpload.js.map +1 -1
- package/stores/documents/documentStore/sync/syncAttachments.js.map +1 -1
- package/workflows/blobs/detach.js +2 -2
- package/workflows/blobs/detach.js.map +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js +1 -1
- package/workflows/blobs/hydration/blobChunkDecryption.js.map +1 -1
- package/workflows/blobs/hydration/decrypt.d.ts +1 -1
- package/workflows/blobs/hydration/decrypt.js +4 -4
- package/workflows/blobs/hydration/decrypt.js.map +1 -1
- package/workflows/blobs/index.d.ts +3 -1
- package/workflows/blobs/index.js +3 -0
- package/workflows/blobs/index.js.map +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js +1 -1
- package/workflows/blobs/upload/automaticMultipartUpload.js.map +1 -1
- package/workflows/blobs/upload/index.d.ts +2 -2
- package/workflows/blobs/upload/index.js +4 -4
- package/workflows/blobs/upload/index.js.map +1 -1
- package/workflows/blobs/upload/multipartFirstParts.js.map +1 -1
- package/workflows/blobs/upload/multipartStageFailures.js.map +1 -1
- package/workflows/blobs/upload/multipartStageResolution.js.map +1 -1
- package/workflows/blobs/upload/multipartUpload.js.map +1 -1
- package/workflows/blobs/verification/attachmentBindingVerification.js.map +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js +1 -1
- package/workflows/blobs/verification/attachmentKeyAuthenticator.js.map +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js +1 -1
- package/workflows/blobs/verification/retainedAttachmentVerification.js.map +1 -1
- package/workflows/blobs/verification/writerProjection.js +1 -1
- package/workflows/blobs/verification/writerProjection.js.map +1 -1
- package/workflows/documents/index.d.ts +1 -1
- package/workflows/documents/index.js +1 -1
- package/workflows/documents/index.js.map +1 -1
- package/workflows/documents/sync/readOnlySync.js +1 -1
- package/workflows/documents/sync/readOnlySync.js.map +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js +1 -1
- package/workflows/documents/sync/syncAttemptPlanning.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js +1 -1
- package/workflows/documents/syncPlan/syncPlanMaterial.js.map +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.js +1 -1
- package/workflows/documents/syncPlan/syncPlanRequestBounds.js.map +1 -1
- package/data/documents/blob/shared/blobSourceSnapshot.js.map +0 -1
- package/data/documents/blob/shared/chunkedBlobCrypto.js.map +0 -1
- package/data/documents/blob/shared/encryptedUploadParts.js.map +0 -1
- package/data/documents/blob/shared/events.js.map +0 -1
- package/data/documents/blob/shared/projection.js.map +0 -1
- package/data/documents/blob/shared/readers.js.map +0 -1
- package/data/documents/blob/shared/responses.js.map +0 -1
- package/data/documents/blob/shared/types.js.map +0 -1
- /package/data/{documents/blob/shared → blobs/attachments}/blobRecordCrypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/crypto.js.map +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/encryptedUploadParts.js +0 -0
- /package/data/{documents/blob/shared → blobs/attachments}/types.js +0 -0
- /package/data/{sync → documents/shared/sync}/documentSyncOutgoingBatch.js.map +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multipartUpload.js","sourceRoot":"","sources":["multipartUpload.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAX_BLOB_CHUNK_COUNT } from \"@tearleads/crypto\";\nimport type { MultipartBlobStagePart } from \"@tearleads/validators/response\";\nimport { MAX_MULTIPART_BLOB_PART_BYTES } from \"@tearleads/validators/util\";\nimport {\n BLOB_TRANSFER_CONCURRENCY,\n runBlobTransfer,\n} from \"../../../data/blobs/transferPool\";\nimport type { BlobEncryptionPlan } from \"../../../data/documents/blob/shared/crypto\";\nimport type {\n BlobAttachmentApi,\n MultipartStageResolvedListener,\n MultipartUploadProgressListener,\n UploadDocumentAttachmentInput,\n} from \"../../../data/documents/blob/shared/types\";\nimport {\n type MultipartPartSources,\n type PreparedFirstPart,\n type PreparedMultipartPart,\n releasePreparedParts,\n sha256BytesHex,\n takePartSource,\n} from \"./multipartFirstParts\";\nimport {\n multipartApiFailureMessage,\n multipartStagePath,\n} from \"./multipartStageFailures\";\nimport { resolveMultipartStage } from \"./multipartStageResolution\";\n\nconst DEFAULT_MULTIPART_UPLOAD_CONCURRENCY = 4;\nconst MAX_MULTIPART_UPLOAD_CONCURRENCY = 4;\n// Fetch exposes no upload progress on every host. Allow a slow shared uplink\n// (8 KiB/s total, shared by every admitted part), plus setup/encryption time.\nconst MULTIPART_TRANSFER_BYTES_PER_SECOND = 8 * 1024;\n\ninterface MultipartPartCommit {\n readonly etag: string;\n readonly partNumber: number;\n}\n\ninterface MultipartPartUploadTask {\n readonly byteLength: number;\n readonly partIndex: number;\n readonly partNumber: number;\n}\n\nfunction pathSegment(value: number | string): string {\n return encodeURIComponent(String(value));\n}\n\nfunction multipartPartRequest(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly partNumber: number;\n readonly stageId: string;\n}) {\n const basePath = `${multipartStagePath(input.stageId)}/parts/${pathSegment(input.partNumber)}`;\n const authorization = { method: \"POST\" as const, path: `${basePath}/upload` };\n // A successful authorization clears its previous failure. If a memory-store\n // byte request then fails, its separate transport diagnostic is authoritative.\n return input.apiClient.getRequestFailure?.(authorization)\n ? authorization\n : { method: \"PUT\" as const, path: `${basePath}/bytes` };\n}\n\nfunction normalizeMultipartUploadConcurrency(\n value: number | undefined,\n): number {\n if (value === undefined) {\n return DEFAULT_MULTIPART_UPLOAD_CONCURRENCY;\n }\n if (\n !Number.isInteger(value) ||\n value <= 0 ||\n value > MAX_MULTIPART_UPLOAD_CONCURRENCY\n ) {\n throw new Error(\n `Multipart blob upload concurrency must be between 1 and ${MAX_MULTIPART_UPLOAD_CONCURRENCY}`,\n );\n }\n\n return value;\n}\n\nfunction isMultipartPartCommit(\n part: MultipartPartCommit | undefined,\n): part is MultipartPartCommit {\n return part !== undefined;\n}\n\nasync function uploadMultipartPartTasks(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly completeParts: (MultipartPartCommit | undefined)[];\n readonly concurrency: number;\n readonly encryption: BlobEncryptionPlan;\n readonly onPartUploaded?: (task: MultipartPartUploadTask) => void;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly sources: MultipartPartSources;\n readonly stageId: string;\n readonly tasks: readonly MultipartPartUploadTask[];\n readonly uploadId: string;\n}): Promise<void> {\n let failed = false;\n let firstFailure: { readonly error: unknown } | undefined;\n let nextTaskIndex = 0;\n const recordFailure = (error: unknown) => {\n failed = true;\n firstFailure ??= { error };\n };\n\n async function worker(): Promise<void> {\n while (!failed) {\n const task = input.tasks[nextTaskIndex];\n nextTaskIndex += 1;\n if (!task) {\n return;\n }\n\n try {\n // A first part already holds the pool slot its prepared bytes use.\n const heldPermit = input.prepared.get(task.partIndex)?.permit;\n await runBlobTransfer(\n input.apiClient,\n async (signal) => {\n if (failed) return;\n const aborted = () => recordFailure(signal.reason);\n signal.addEventListener(\"abort\", aborted, { once: true });\n try {\n const uploaded = await uploadMultipartPartBytes({\n apiClient: input.apiClient,\n encryption: input.encryption,\n prepared: input.prepared,\n sources: input.sources,\n stageId: input.stageId,\n task,\n uploadId: input.uploadId,\n signal,\n });\n signal.throwIfAborted();\n if (!uploaded) {\n failed = true;\n throw new Error(\n multipartApiFailureMessage({\n apiClient: input.apiClient,\n fallback: `Multipart blob part ${task.partNumber} upload failed for stage ${input.stageId}.`,\n request: multipartPartRequest({\n apiClient: input.apiClient,\n partNumber: task.partNumber,\n stageId: input.stageId,\n }),\n }),\n );\n }\n\n input.completeParts[task.partIndex] = {\n etag: uploaded.part.etag,\n partNumber: task.partNumber,\n };\n input.onPartUploaded?.(task);\n } catch (error) {\n // Publish failure before releasing the permit to a queued sibling.\n // Already-started parts still record success and drain through the join.\n recordFailure(error);\n } finally {\n signal.removeEventListener(\"abort\", aborted);\n }\n },\n 120_000 +\n Math.ceil(\n (task.byteLength * BLOB_TRANSFER_CONCURRENCY * 1000) /\n MULTIPART_TRANSFER_BYTES_PER_SECOND,\n ),\n heldPermit,\n );\n } catch (error) {\n recordFailure(error);\n }\n }\n }\n\n const workerCount = Math.min(input.concurrency, input.tasks.length);\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n if (firstFailure) {\n throw firstFailure.error;\n }\n}\n\n// A first part was encrypted once before the stage existed; hand its bytes\n// over (and release them) instead of encrypting it again.\nasync function encryptedPart(input: {\n readonly encryption: BlobEncryptionPlan;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly task: MultipartPartUploadTask;\n}): Promise<PreparedMultipartPart> {\n const prepared = input.prepared.get(input.task.partIndex);\n if (prepared) {\n input.prepared.delete(input.task.partIndex);\n return prepared;\n }\n const bytes = await input.encryption.encryptPart(input.task.partIndex);\n if (bytes.byteLength !== input.task.byteLength) {\n throw new Error(\n `Encrypted blob part ${input.task.partNumber} byte length mismatch: expected ${input.task.byteLength.toLocaleString()}, received ${bytes.byteLength.toLocaleString()}.`,\n );\n }\n return { bytes, sha256: await sha256BytesHex(bytes) };\n}\n\nasync function uploadMultipartPartBytes(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly encryption: BlobEncryptionPlan;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly sources: MultipartPartSources;\n readonly stageId: string;\n readonly task: MultipartPartUploadTask;\n readonly uploadId: string;\n readonly signal: AbortSignal;\n}): ReturnType<BlobAttachmentApi[\"uploadMultipartBlobPartBytes\"]> {\n input.signal.throwIfAborted();\n const { bytes: encryptedPartBytes, sha256 } = await encryptedPart(input);\n input.signal.throwIfAborted();\n const source = takePartSource(input.sources, input.task.partNumber);\n const uploaded = await input.apiClient.uploadMultipartBlobPartBytes(\n input.stageId,\n input.task.partNumber,\n {\n byteLength: encryptedPartBytes.byteLength,\n encryptedBytes: encryptedPartBytes,\n sha256,\n ...(source === undefined ? {} : { source }),\n uploadId: input.uploadId,\n },\n { signal: input.signal },\n );\n input.signal.throwIfAborted();\n if (\n uploaded &&\n (uploaded.stageId !== input.stageId ||\n uploaded.uploadId !== input.uploadId ||\n uploaded.part.partNumber !== input.task.partNumber ||\n uploaded.part.byteLength !== input.task.byteLength)\n ) {\n throw new Error(\n `Multipart blob part ${input.task.partNumber} response does not match its request.`,\n );\n }\n return uploaded;\n}\n\nfunction uploadedPartsByPartNumber(\n parts: readonly MultipartBlobStagePart[],\n): ReadonlyMap<number, MultipartBlobStagePart> {\n return new Map(parts.map((part) => [part.partNumber, part]));\n}\n\ninterface MultipartUploadProgressState {\n bytesTotal: number;\n bytesUploaded: number;\n partsCompleted: number;\n partsTotal: number;\n}\n\ninterface MultipartPartPlan {\n completeParts: (MultipartPartCommit | undefined)[];\n progress: MultipartUploadProgressState;\n uploadTasks: MultipartPartUploadTask[];\n}\n\n/**\n * Plans encrypted part indices without materializing their bytes, reusing any\n * already-staged parts and seeding cumulative progress for resumed uploads.\n */\nfunction planMultipartParts(input: {\n encryption: BlobEncryptionPlan;\n uploadedParts: ReadonlyMap<number, MultipartBlobStagePart>;\n}): MultipartPartPlan {\n const { encryption, uploadedParts } = input;\n const completeParts: (MultipartPartCommit | undefined)[] = new Array(\n encryption.partCount,\n );\n const uploadTasks: MultipartPartUploadTask[] = [];\n const progress: MultipartUploadProgressState = {\n bytesTotal: 0,\n bytesUploaded: 0,\n partsCompleted: 0,\n partsTotal: encryption.partCount,\n };\n\n for (let partIndex = 0; partIndex < encryption.partCount; partIndex += 1) {\n const partNumber = partIndex + 1;\n const byteLength = encryption.getPartByteLength(partIndex);\n progress.bytesTotal += byteLength;\n const uploadedPart = uploadedParts.get(partNumber);\n if (uploadedPart?.byteLength === byteLength) {\n completeParts[partIndex] = {\n etag: uploadedPart.etag,\n partNumber,\n };\n progress.partsCompleted += 1;\n progress.bytesUploaded += byteLength;\n continue;\n }\n\n uploadTasks.push({\n byteLength,\n partIndex,\n partNumber,\n });\n }\n\n return { completeParts, progress, uploadTasks };\n}\n\nfunction assertMultipartPlanLimits(encryption: BlobEncryptionPlan): void {\n if (encryption.partCount > MAX_BLOB_CHUNK_COUNT) {\n throw new Error(\n `Multipart blob upload would require ${encryption.partCount.toLocaleString()} parts; the maximum is ${MAX_BLOB_CHUNK_COUNT.toLocaleString()} parts.`,\n );\n }\n for (let index = 0; index < encryption.partCount; index += 1) {\n if (encryption.getPartByteLength(index) > MAX_MULTIPART_BLOB_PART_BYTES) {\n throw new Error(\n `Encrypted blob part ${index + 1} exceeds the 32 MiB multipart part limit.`,\n );\n }\n }\n}\n\ntype StageMultipartBlobAttachmentInput = {\n readonly apiClient: BlobAttachmentApi;\n readonly encryption: BlobEncryptionPlan;\n readonly multipart: NonNullable<UploadDocumentAttachmentInput[\"multipart\"]>;\n readonly organizationId: string;\n readonly onMultipartProgress?: MultipartUploadProgressListener | undefined;\n readonly onStageResolved?: MultipartStageResolvedListener | undefined;\n readonly onStageUnavailable?:\n | ((stageId: string) => Promise<void>)\n | undefined;\n};\n\nexport async function stageMultipartBlobAttachment(\n input: StageMultipartBlobAttachmentInput,\n): Promise<string | null> {\n if (input.multipart.partSize !== input.encryption.chunkSize) {\n throw new Error(\n \"Multipart part size must match the encryption chunk size exactly.\",\n );\n }\n assertMultipartPlanLimits(input.encryption);\n const concurrency = normalizeMultipartUploadConcurrency(\n input.multipart.uploadConcurrency,\n );\n const resolved = await resolveMultipartStage({\n apiClient: input.apiClient,\n concurrency,\n encryption: input.encryption,\n multipart: input.multipart,\n organizationId: input.organizationId,\n onStageUnavailable: input.onStageUnavailable,\n });\n try {\n return await uploadResolvedMultipartStage(input, concurrency, resolved);\n } finally {\n // First parts no worker consumed (an early failure) return their slots.\n releasePreparedParts(resolved.prepared);\n }\n}\n\nasync function uploadResolvedMultipartStage(\n input: StageMultipartBlobAttachmentInput,\n concurrency: number,\n {\n prepared,\n sources,\n status,\n }: Awaited<ReturnType<typeof resolveMultipartStage>>,\n): Promise<string> {\n // Surface the stage id before any parts upload so the caller can persist it;\n // an upload interrupted mid-flight can then resume this same stage.\n await input.onStageResolved?.({\n partSize: input.encryption.chunkSize,\n stageId: status.stageId,\n });\n if (status.completed) {\n input.onMultipartProgress?.({\n bytesTotal: input.encryption.byteLength,\n bytesUploaded: input.encryption.byteLength,\n partsCompleted: input.encryption.partCount,\n partsTotal: input.encryption.partCount,\n });\n return status.stageId;\n }\n\n const { completeParts, progress, uploadTasks } = planMultipartParts({\n encryption: input.encryption,\n uploadedParts: uploadedPartsByPartNumber(status.uploadedParts),\n });\n\n const reportMultipartProgress = () => {\n input.onMultipartProgress?.({\n bytesTotal: progress.bytesTotal,\n bytesUploaded: progress.bytesUploaded,\n partsCompleted: progress.partsCompleted,\n partsTotal: progress.partsTotal,\n });\n };\n reportMultipartProgress();\n\n await uploadMultipartPartTasks({\n apiClient: input.apiClient,\n completeParts,\n concurrency,\n encryption: input.encryption,\n onPartUploaded: (task) => {\n progress.partsCompleted += 1;\n progress.bytesUploaded += task.byteLength;\n reportMultipartProgress();\n },\n prepared,\n sources,\n stageId: status.stageId,\n tasks: uploadTasks,\n uploadId: status.uploadId,\n });\n const committedParts = completeParts.filter(isMultipartPartCommit);\n if (committedParts.length !== input.encryption.partCount) {\n throw new Error(\n `Multipart blob upload incomplete for stage ${status.stageId}: committed ${committedParts.length.toLocaleString()} of ${input.encryption.partCount.toLocaleString()} parts.`,\n );\n }\n\n // Binding the attachment completes the stage: the API assembles these parts\n // and verifies the object's length and SHA-256 before promoting it.\n return status.stageId;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"multipartUpload.js","sourceRoot":"","sources":["multipartUpload.ts"],"names":[],"mappings":"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","sourcesContent":["import { MAX_BLOB_CHUNK_COUNT } from \"@tearleads/crypto\";\nimport type { MultipartBlobStagePart } from \"@tearleads/validators/response\";\nimport { MAX_MULTIPART_BLOB_PART_BYTES } from \"@tearleads/validators/util\";\nimport type { BlobEncryptionPlan } from \"../../../data/blobs/attachments/crypto\";\nimport type {\n BlobAttachmentApi,\n MultipartStageResolvedListener,\n MultipartUploadProgressListener,\n UploadDocumentAttachmentInput,\n} from \"../../../data/blobs/attachments/types\";\nimport {\n BLOB_TRANSFER_CONCURRENCY,\n runBlobTransfer,\n} from \"../../../data/blobs/transferPool\";\nimport {\n type MultipartPartSources,\n type PreparedFirstPart,\n type PreparedMultipartPart,\n releasePreparedParts,\n sha256BytesHex,\n takePartSource,\n} from \"./multipartFirstParts\";\nimport {\n multipartApiFailureMessage,\n multipartStagePath,\n} from \"./multipartStageFailures\";\nimport { resolveMultipartStage } from \"./multipartStageResolution\";\n\nconst DEFAULT_MULTIPART_UPLOAD_CONCURRENCY = 4;\nconst MAX_MULTIPART_UPLOAD_CONCURRENCY = 4;\n// Fetch exposes no upload progress on every host. Allow a slow shared uplink\n// (8 KiB/s total, shared by every admitted part), plus setup/encryption time.\nconst MULTIPART_TRANSFER_BYTES_PER_SECOND = 8 * 1024;\n\ninterface MultipartPartCommit {\n readonly etag: string;\n readonly partNumber: number;\n}\n\ninterface MultipartPartUploadTask {\n readonly byteLength: number;\n readonly partIndex: number;\n readonly partNumber: number;\n}\n\nfunction pathSegment(value: number | string): string {\n return encodeURIComponent(String(value));\n}\n\nfunction multipartPartRequest(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly partNumber: number;\n readonly stageId: string;\n}) {\n const basePath = `${multipartStagePath(input.stageId)}/parts/${pathSegment(input.partNumber)}`;\n const authorization = { method: \"POST\" as const, path: `${basePath}/upload` };\n // A successful authorization clears its previous failure. If a memory-store\n // byte request then fails, its separate transport diagnostic is authoritative.\n return input.apiClient.getRequestFailure?.(authorization)\n ? authorization\n : { method: \"PUT\" as const, path: `${basePath}/bytes` };\n}\n\nfunction normalizeMultipartUploadConcurrency(\n value: number | undefined,\n): number {\n if (value === undefined) {\n return DEFAULT_MULTIPART_UPLOAD_CONCURRENCY;\n }\n if (\n !Number.isInteger(value) ||\n value <= 0 ||\n value > MAX_MULTIPART_UPLOAD_CONCURRENCY\n ) {\n throw new Error(\n `Multipart blob upload concurrency must be between 1 and ${MAX_MULTIPART_UPLOAD_CONCURRENCY}`,\n );\n }\n\n return value;\n}\n\nfunction isMultipartPartCommit(\n part: MultipartPartCommit | undefined,\n): part is MultipartPartCommit {\n return part !== undefined;\n}\n\nasync function uploadMultipartPartTasks(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly completeParts: (MultipartPartCommit | undefined)[];\n readonly concurrency: number;\n readonly encryption: BlobEncryptionPlan;\n readonly onPartUploaded?: (task: MultipartPartUploadTask) => void;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly sources: MultipartPartSources;\n readonly stageId: string;\n readonly tasks: readonly MultipartPartUploadTask[];\n readonly uploadId: string;\n}): Promise<void> {\n let failed = false;\n let firstFailure: { readonly error: unknown } | undefined;\n let nextTaskIndex = 0;\n const recordFailure = (error: unknown) => {\n failed = true;\n firstFailure ??= { error };\n };\n\n async function worker(): Promise<void> {\n while (!failed) {\n const task = input.tasks[nextTaskIndex];\n nextTaskIndex += 1;\n if (!task) {\n return;\n }\n\n try {\n // A first part already holds the pool slot its prepared bytes use.\n const heldPermit = input.prepared.get(task.partIndex)?.permit;\n await runBlobTransfer(\n input.apiClient,\n async (signal) => {\n if (failed) return;\n const aborted = () => recordFailure(signal.reason);\n signal.addEventListener(\"abort\", aborted, { once: true });\n try {\n const uploaded = await uploadMultipartPartBytes({\n apiClient: input.apiClient,\n encryption: input.encryption,\n prepared: input.prepared,\n sources: input.sources,\n stageId: input.stageId,\n task,\n uploadId: input.uploadId,\n signal,\n });\n signal.throwIfAborted();\n if (!uploaded) {\n failed = true;\n throw new Error(\n multipartApiFailureMessage({\n apiClient: input.apiClient,\n fallback: `Multipart blob part ${task.partNumber} upload failed for stage ${input.stageId}.`,\n request: multipartPartRequest({\n apiClient: input.apiClient,\n partNumber: task.partNumber,\n stageId: input.stageId,\n }),\n }),\n );\n }\n\n input.completeParts[task.partIndex] = {\n etag: uploaded.part.etag,\n partNumber: task.partNumber,\n };\n input.onPartUploaded?.(task);\n } catch (error) {\n // Publish failure before releasing the permit to a queued sibling.\n // Already-started parts still record success and drain through the join.\n recordFailure(error);\n } finally {\n signal.removeEventListener(\"abort\", aborted);\n }\n },\n 120_000 +\n Math.ceil(\n (task.byteLength * BLOB_TRANSFER_CONCURRENCY * 1000) /\n MULTIPART_TRANSFER_BYTES_PER_SECOND,\n ),\n heldPermit,\n );\n } catch (error) {\n recordFailure(error);\n }\n }\n }\n\n const workerCount = Math.min(input.concurrency, input.tasks.length);\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n if (firstFailure) {\n throw firstFailure.error;\n }\n}\n\n// A first part was encrypted once before the stage existed; hand its bytes\n// over (and release them) instead of encrypting it again.\nasync function encryptedPart(input: {\n readonly encryption: BlobEncryptionPlan;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly task: MultipartPartUploadTask;\n}): Promise<PreparedMultipartPart> {\n const prepared = input.prepared.get(input.task.partIndex);\n if (prepared) {\n input.prepared.delete(input.task.partIndex);\n return prepared;\n }\n const bytes = await input.encryption.encryptPart(input.task.partIndex);\n if (bytes.byteLength !== input.task.byteLength) {\n throw new Error(\n `Encrypted blob part ${input.task.partNumber} byte length mismatch: expected ${input.task.byteLength.toLocaleString()}, received ${bytes.byteLength.toLocaleString()}.`,\n );\n }\n return { bytes, sha256: await sha256BytesHex(bytes) };\n}\n\nasync function uploadMultipartPartBytes(input: {\n readonly apiClient: BlobAttachmentApi;\n readonly encryption: BlobEncryptionPlan;\n readonly prepared: Map<number, PreparedFirstPart>;\n readonly sources: MultipartPartSources;\n readonly stageId: string;\n readonly task: MultipartPartUploadTask;\n readonly uploadId: string;\n readonly signal: AbortSignal;\n}): ReturnType<BlobAttachmentApi[\"uploadMultipartBlobPartBytes\"]> {\n input.signal.throwIfAborted();\n const { bytes: encryptedPartBytes, sha256 } = await encryptedPart(input);\n input.signal.throwIfAborted();\n const source = takePartSource(input.sources, input.task.partNumber);\n const uploaded = await input.apiClient.uploadMultipartBlobPartBytes(\n input.stageId,\n input.task.partNumber,\n {\n byteLength: encryptedPartBytes.byteLength,\n encryptedBytes: encryptedPartBytes,\n sha256,\n ...(source === undefined ? {} : { source }),\n uploadId: input.uploadId,\n },\n { signal: input.signal },\n );\n input.signal.throwIfAborted();\n if (\n uploaded &&\n (uploaded.stageId !== input.stageId ||\n uploaded.uploadId !== input.uploadId ||\n uploaded.part.partNumber !== input.task.partNumber ||\n uploaded.part.byteLength !== input.task.byteLength)\n ) {\n throw new Error(\n `Multipart blob part ${input.task.partNumber} response does not match its request.`,\n );\n }\n return uploaded;\n}\n\nfunction uploadedPartsByPartNumber(\n parts: readonly MultipartBlobStagePart[],\n): ReadonlyMap<number, MultipartBlobStagePart> {\n return new Map(parts.map((part) => [part.partNumber, part]));\n}\n\ninterface MultipartUploadProgressState {\n bytesTotal: number;\n bytesUploaded: number;\n partsCompleted: number;\n partsTotal: number;\n}\n\ninterface MultipartPartPlan {\n completeParts: (MultipartPartCommit | undefined)[];\n progress: MultipartUploadProgressState;\n uploadTasks: MultipartPartUploadTask[];\n}\n\n/**\n * Plans encrypted part indices without materializing their bytes, reusing any\n * already-staged parts and seeding cumulative progress for resumed uploads.\n */\nfunction planMultipartParts(input: {\n encryption: BlobEncryptionPlan;\n uploadedParts: ReadonlyMap<number, MultipartBlobStagePart>;\n}): MultipartPartPlan {\n const { encryption, uploadedParts } = input;\n const completeParts: (MultipartPartCommit | undefined)[] = new Array(\n encryption.partCount,\n );\n const uploadTasks: MultipartPartUploadTask[] = [];\n const progress: MultipartUploadProgressState = {\n bytesTotal: 0,\n bytesUploaded: 0,\n partsCompleted: 0,\n partsTotal: encryption.partCount,\n };\n\n for (let partIndex = 0; partIndex < encryption.partCount; partIndex += 1) {\n const partNumber = partIndex + 1;\n const byteLength = encryption.getPartByteLength(partIndex);\n progress.bytesTotal += byteLength;\n const uploadedPart = uploadedParts.get(partNumber);\n if (uploadedPart?.byteLength === byteLength) {\n completeParts[partIndex] = {\n etag: uploadedPart.etag,\n partNumber,\n };\n progress.partsCompleted += 1;\n progress.bytesUploaded += byteLength;\n continue;\n }\n\n uploadTasks.push({\n byteLength,\n partIndex,\n partNumber,\n });\n }\n\n return { completeParts, progress, uploadTasks };\n}\n\nfunction assertMultipartPlanLimits(encryption: BlobEncryptionPlan): void {\n if (encryption.partCount > MAX_BLOB_CHUNK_COUNT) {\n throw new Error(\n `Multipart blob upload would require ${encryption.partCount.toLocaleString()} parts; the maximum is ${MAX_BLOB_CHUNK_COUNT.toLocaleString()} parts.`,\n );\n }\n for (let index = 0; index < encryption.partCount; index += 1) {\n if (encryption.getPartByteLength(index) > MAX_MULTIPART_BLOB_PART_BYTES) {\n throw new Error(\n `Encrypted blob part ${index + 1} exceeds the 32 MiB multipart part limit.`,\n );\n }\n }\n}\n\ntype StageMultipartBlobAttachmentInput = {\n readonly apiClient: BlobAttachmentApi;\n readonly encryption: BlobEncryptionPlan;\n readonly multipart: NonNullable<UploadDocumentAttachmentInput[\"multipart\"]>;\n readonly organizationId: string;\n readonly onMultipartProgress?: MultipartUploadProgressListener | undefined;\n readonly onStageResolved?: MultipartStageResolvedListener | undefined;\n readonly onStageUnavailable?:\n | ((stageId: string) => Promise<void>)\n | undefined;\n};\n\nexport async function stageMultipartBlobAttachment(\n input: StageMultipartBlobAttachmentInput,\n): Promise<string | null> {\n if (input.multipart.partSize !== input.encryption.chunkSize) {\n throw new Error(\n \"Multipart part size must match the encryption chunk size exactly.\",\n );\n }\n assertMultipartPlanLimits(input.encryption);\n const concurrency = normalizeMultipartUploadConcurrency(\n input.multipart.uploadConcurrency,\n );\n const resolved = await resolveMultipartStage({\n apiClient: input.apiClient,\n concurrency,\n encryption: input.encryption,\n multipart: input.multipart,\n organizationId: input.organizationId,\n onStageUnavailable: input.onStageUnavailable,\n });\n try {\n return await uploadResolvedMultipartStage(input, concurrency, resolved);\n } finally {\n // First parts no worker consumed (an early failure) return their slots.\n releasePreparedParts(resolved.prepared);\n }\n}\n\nasync function uploadResolvedMultipartStage(\n input: StageMultipartBlobAttachmentInput,\n concurrency: number,\n {\n prepared,\n sources,\n status,\n }: Awaited<ReturnType<typeof resolveMultipartStage>>,\n): Promise<string> {\n // Surface the stage id before any parts upload so the caller can persist it;\n // an upload interrupted mid-flight can then resume this same stage.\n await input.onStageResolved?.({\n partSize: input.encryption.chunkSize,\n stageId: status.stageId,\n });\n if (status.completed) {\n input.onMultipartProgress?.({\n bytesTotal: input.encryption.byteLength,\n bytesUploaded: input.encryption.byteLength,\n partsCompleted: input.encryption.partCount,\n partsTotal: input.encryption.partCount,\n });\n return status.stageId;\n }\n\n const { completeParts, progress, uploadTasks } = planMultipartParts({\n encryption: input.encryption,\n uploadedParts: uploadedPartsByPartNumber(status.uploadedParts),\n });\n\n const reportMultipartProgress = () => {\n input.onMultipartProgress?.({\n bytesTotal: progress.bytesTotal,\n bytesUploaded: progress.bytesUploaded,\n partsCompleted: progress.partsCompleted,\n partsTotal: progress.partsTotal,\n });\n };\n reportMultipartProgress();\n\n await uploadMultipartPartTasks({\n apiClient: input.apiClient,\n completeParts,\n concurrency,\n encryption: input.encryption,\n onPartUploaded: (task) => {\n progress.partsCompleted += 1;\n progress.bytesUploaded += task.byteLength;\n reportMultipartProgress();\n },\n prepared,\n sources,\n stageId: status.stageId,\n tasks: uploadTasks,\n uploadId: status.uploadId,\n });\n const committedParts = completeParts.filter(isMultipartPartCommit);\n if (committedParts.length !== input.encryption.partCount) {\n throw new Error(\n `Multipart blob upload incomplete for stage ${status.stageId}: committed ${committedParts.length.toLocaleString()} of ${input.encryption.partCount.toLocaleString()} parts.`,\n );\n }\n\n // Binding the attachment completes the stage: the API assembles these parts\n // and verifies the object's length and SHA-256 before promoting it.\n return status.stageId;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachmentBindingVerification.js","sourceRoot":"","sources":["attachmentBindingVerification.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n verifyAttachmentBindingEvent,\n} from \"@tearleads/crypto\";\nimport type { DecryptDocumentAttachmentBlobInput } from \"../../../data/
|
|
1
|
+
{"version":3,"file":"attachmentBindingVerification.js","sourceRoot":"","sources":["attachmentBindingVerification.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n verifyAttachmentBindingEvent,\n} from \"@tearleads/crypto\";\nimport type { DecryptDocumentAttachmentBlobInput } from \"../../../data/blobs/attachments/types\";\nimport {\n readCanonicalJson,\n readCanonicalRecord,\n} from \"../../../data/keying/canonicalJson\";\nimport {\n type DocumentWriterProjectionAuthorization,\n type ProjectionUserKeyResolver,\n readAccessEvent,\n readRecordString,\n readRequiredRecordValue,\n resolveEventContainerPaths,\n} from \"../../../data/keyingProjectionVerification\";\n\nexport async function assertAttachmentBindingVerified(input: {\n readonly authorization: DocumentWriterProjectionAuthorization | undefined;\n readonly binding: Pick<\n DecryptDocumentAttachmentBlobInput[\"binding\"],\n | \"bindingEvent\"\n | \"documentManifestHash\"\n | \"previousBindingId\"\n | \"bindingId\"\n | \"blobId\"\n >;\n readonly expectedDocumentId: string;\n readonly expectedSlotId: string;\n readonly resolveProjectionUserKey: ProjectionUserKeyResolver;\n}): Promise<void> {\n if (!input.authorization) {\n throw new Error(\"Attachment binding lacks verified document authority\");\n }\n if (\n !input.binding.bindingEvent ||\n !input.binding.documentManifestHash ||\n input.binding.previousBindingId === undefined\n ) {\n throw new Error(\"Attachment binding lacks signed verification material\");\n }\n const eventBundle = readCanonicalRecord(\n input.binding.bindingEvent,\n \"Attachment binding event bundle\",\n );\n const event = readAccessEvent(\n readRequiredRecordValue(\n eventBundle,\n \"event\",\n \"Attachment binding event bundle\",\n ),\n \"Attachment binding event\",\n );\n const signer = await input.resolveProjectionUserKey(event.signerUserId);\n if (!signer) {\n throw new Error(\"Attachment binding signer identity is unavailable\");\n }\n const documentManifest = input.authorization.documentManifestByHash.get(\n input.binding.documentManifestHash,\n );\n if (!documentManifest) {\n throw new Error(\"Attachment binding document manifest is unverified\");\n }\n const { dependencyContainerPaths } = resolveEventContainerPaths({\n containerPathByManifestHash:\n input.authorization.containerPathByManifestHash,\n dependencyManifestHashes: event.dependencyManifestHashes.filter(\n (hash) => hash !== input.binding.documentManifestHash,\n ),\n });\n const verified = await verifyAttachmentBindingEvent({\n authorizationMembership: \"referenced\",\n authorizingContainerPaths: dependencyContainerPaths,\n body: readCanonicalJson(\n readRequiredRecordValue(\n eventBundle,\n \"body\",\n \"Attachment binding event bundle\",\n ),\n \"Attachment binding event body\",\n ),\n documentManifest,\n event,\n expectedBindingId: input.binding.bindingId,\n expectedBlobId: input.binding.blobId,\n expectedDocumentId: input.expectedDocumentId,\n expectedDocumentManifestHash: input.binding.documentManifestHash,\n expectedPreviousBindingId: input.binding.previousBindingId,\n principalPolicies: input.authorization.principalPolicies,\n signerPublicKey: signer.signingPublicKey,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n if (\n verified.value.slotId !== input.expectedSlotId ||\n readRecordString(\n eventBundle,\n \"eventHash\",\n \"Attachment binding event bundle\",\n ) !== verified.value.event.eventHash\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Attachment binding slot or event hash is inconsistent\",\n );\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AES_GCM_TAG_BYTES, blobChunkPlaintextByteLength, bytesToHex, } from "../../../internal/crypto/index.js";
|
|
2
|
-
import { createBlobEnvelopeStream } from "../../../data/
|
|
2
|
+
import { createBlobEnvelopeStream } from "../../../data/blobs/attachments/blobEnvelopeStream.js";
|
|
3
3
|
import { assertEqualBytes, readWriteHeader, } from "../../../data/documents/shared/readers.js";
|
|
4
4
|
import { decryptBlobChunk } from "../hydration/blobChunkDecryption.js";
|
|
5
5
|
import { prepareDocumentAttachmentBlobDecryption } from "../hydration/decrypt.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachmentKeyAuthenticator.js","sourceRoot":"","sources":["attachmentKeyAuthenticator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"attachmentKeyAuthenticator.js","sourceRoot":"","sources":["attachmentKeyAuthenticator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,4BAA4B,EAC5B,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAK9F,OAAO,EACL,gBAAgB,EAChB,eAAe,GAChB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,uCAAuC,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAapE,MAAM,iBAAiB,GAAG,CACxB,GAA+B,EAC/B,UAAkB,EAClB,EAAE,CACF,2BAA2B,CACzB,GAAG,EACH,UAAU,EACV,uCAAuC,CACxC,CAAC;AAEJ,KAAK,UAAU,yBAAyB,CACtC,GAA+B,EAC/B,KAAyB,EACzB,SAAsB;IAEtB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI;QACP,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC;IACpD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAC5C,wEAAwE;QACxE,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACzD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC;YAC1D,MAAM,mBAAmB,GAAG,4BAA4B,CAAC;gBACvD,UAAU,EAAE,SAAS,CAAC,UAAU;gBAChC,UAAU,EAAE,KAAK;gBACjB,SAAS,EAAE,SAAS,CAAC,SAAS;gBAC9B,mBAAmB,EAAE,SAAS,CAAC,UAAU;aAC1C,CAAC,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,CAClC,mBAAmB,GAAG,iBAAiB,CACxC,CAAC;YACF,MAAM,gBAAgB,CAAC;gBACrB,GAAG,OAAO;gBACV,SAAS;gBACT,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;gBACpC,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,mBAAmB,EAAE;aAClD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,MAAM,GAAG,eAAe,CAC5B,KAAK,CAAC,OAAO,CAAC,WAAW,EACzB,8BAA8B,CAC/B,CAAC;QACF,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC,cAAc;YAC7D,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,OAAO;YACL,SAAS;YACT,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,gCAAgC,CAC9C,GAA+B,EAC/B,UAAkB;IAElB,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgC,CAAC;IAC9D,OAAO,KAAK,EAAE,KAAyB,EAAuB,EAAE;QAC9D,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,yBAAyB,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YACjE,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACjD,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,UAAU,CAAC;QACpC,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3E,IACE,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,8BAA8B,CAAC;aACvE,cAAc,KAAK,MAAM,CAAC,cAAc;YAE3C,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,gBAAgB,CACd,OAAO,CAAC,UAAU,EAClB,MAAM,CAAC,UAAU,EACjB,mDAAmD,CACpD,CAAC;QACF,OAAO,MAAM,CAAC,UAAU,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {\n AES_GCM_TAG_BYTES,\n blobChunkPlaintextByteLength,\n bytesToHex,\n} from \"@tearleads/crypto\";\nimport { createBlobEnvelopeStream } from \"../../../data/blobs/attachments/blobEnvelopeStream\";\nimport type {\n BlobEncryptedBytesHeader,\n DecryptDocumentAttachmentBlobInput,\n} from \"../../../data/blobs/attachments/types\";\nimport {\n assertEqualBytes,\n readWriteHeader,\n} from \"../../../data/documents/shared/readers\";\nimport type { DocumentLinkSetMutationApi } from \"../../../data/documents/shared/types\";\nimport { decryptBlobChunk } from \"../hydration/blobChunkDecryption\";\nimport { prepareDocumentAttachmentBlobDecryption } from \"../hydration/decrypt\";\nimport { createAttachmentProofReader } from \"./attachmentDecryptor\";\n\ntype AttachmentKeyInput = Omit<\n DecryptDocumentAttachmentBlobInput,\n \"encryptedBytes\"\n>;\ntype VerifiedKey = {\n ciphertextHash: string;\n encrypted: BlobEncryptedBytesHeader;\n contentKey: Uint8Array;\n};\ntype ProofReader = ReturnType<typeof createProofReader>;\n\nconst createProofReader = (\n api: DocumentLinkSetMutationApi,\n documentId: string,\n) =>\n createAttachmentProofReader(\n api,\n documentId,\n prepareDocumentAttachmentBlobDecryption,\n );\n\nasync function authenticateAttachmentKey(\n api: DocumentLinkSetMutationApi,\n input: AttachmentKeyInput,\n readProof: ProofReader,\n): Promise<VerifiedKey> {\n const blob = await api.getBlobBytes(input.binding.blobId);\n if (!blob)\n throw new Error(\"Attachment ciphertext is unavailable for relinking\");\n const body = new Response(blob.encryptedBytes).body;\n if (!body) throw new Error(\"Attachment ciphertext stream is unavailable\");\n const source = createBlobEnvelopeStream(body);\n try {\n const encrypted = await source.readHeader();\n // A missing citation can refresh the proof before consuming ciphertext.\n const context = await readProof({ ...input, encrypted });\n for (let index = 0; index < encrypted.chunkCount; index++) {\n const plaintextByteLength = blobChunkPlaintextByteLength({\n chunkCount: encrypted.chunkCount,\n chunkIndex: index,\n chunkSize: encrypted.chunkSize,\n plaintextByteLength: encrypted.byteLength,\n });\n const ciphertext = await source.read(\n plaintextByteLength + AES_GCM_TAG_BYTES,\n );\n await decryptBlobChunk({\n ...context,\n encrypted,\n expectedBlobId: input.binding.blobId,\n chunk: { ciphertext, index, plaintextByteLength },\n });\n }\n const header = readWriteHeader(\n input.binding.writeHeader,\n \"Attachment blob write header\",\n );\n if (bytesToHex(await source.finish()) !== header.ciphertextHash)\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n return {\n encrypted,\n contentKey: context.contentKey,\n ciphertextHash: header.ciphertextHash,\n };\n } finally {\n await source.close();\n }\n}\n\n/** Shared blobs retain only authenticated keys and metadata, never their bytes. */\nexport function createAttachmentKeyAuthenticator(\n api: DocumentLinkSetMutationApi,\n documentId: string,\n) {\n const readProof = createProofReader(api, documentId);\n const authenticated = new Map<string, Promise<VerifiedKey>>();\n return async (input: AttachmentKeyInput): Promise<Uint8Array> => {\n const existing = authenticated.get(input.binding.blobId);\n if (!existing) {\n const pending = authenticateAttachmentKey(api, input, readProof);\n authenticated.set(input.binding.blobId, pending);\n return (await pending).contentKey;\n }\n const cached = await existing;\n const context = await readProof({ ...input, encrypted: cached.encrypted });\n if (\n readWriteHeader(input.binding.writeHeader, \"Attachment blob write header\")\n .ciphertextHash !== cached.ciphertextHash\n )\n throw new Error(\"Attachment blob write header does not match ciphertext\");\n assertEqualBytes(\n context.contentKey,\n cached.contentKey,\n \"Attachment bindings contain conflicting blob keys\",\n );\n return cached.contentKey;\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KeyingVerificationError } from "../../../internal/crypto/index.js";
|
|
2
|
-
import { assertBlobContentKeyBundleTargetHash } from "../../../data/
|
|
2
|
+
import { assertBlobContentKeyBundleTargetHash } from "../../../data/blobs/attachments/responses.js";
|
|
3
3
|
import { assertDocumentWriterProjectionConsistent } from "../../../data/documents/shared/projection/index.js";
|
|
4
4
|
import { projectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
5
5
|
import { requireProjectionUserKeyResolver, } from "../../../data/keyingProjectionVerification/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retainedAttachmentVerification.js","sourceRoot":"","sources":["retainedAttachmentVerification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,oCAAoC,EAAE,MAAM
|
|
1
|
+
{"version":3,"file":"retainedAttachmentVerification.js","sourceRoot":"","sources":["retainedAttachmentVerification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,oCAAoC,EAAE,MAAM,2CAA2C,CAAC;AAEjG,OAAO,EAAE,wCAAwC,EAAE,MAAM,2CAA2C,CAAC;AACrG,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAEL,gCAAgC,GACjC,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,+BAA+B,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAElE,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAGC;IAED,MAAM,wBAAwB,GAAG,gCAAgC,CAC/D,KAAK,CAAC,wBAAwB,EAC9B,2BAA2B,CAC5B,CAAC;IACF,IAAI,aAAgE,CAAC;IACrE,MAAM,wCAAwC,CAAC,KAAK,CAAC,gBAAgB,EAAE;QACrE,0BAA0B,EAAE,IAAI;QAChC,GAAG,6BAA6B,CAAC;YAC/B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,+BAA+B,EAAE,KAAK,CAAC,+BAA+B;YACtE,wBAAwB;SACzB,CAAC;QACF,uBAAuB,EAAE,CAAC,KAAK,EAAE,EAAE;YACjC,aAAa,GAAG,KAAK,CAAC;QACxB,CAAC;KACF,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM;QAChE,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,+CAA+C,CAChD,CAAC;IACJ,MAAM,oCAAoC,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3E,MAAM,+BAA+B,CAAC;QACpC,GAAG,KAAK;QACR,aAAa;QACb,wBAAwB;KACzB,CAAC,CAAC;IACH,IAAI,CAAC,aAAa;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC3E,2BAA2B,CAAC;QAC1B,aAAa;QACb,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,UAAU,EAAE,KAAK,CAAC,kBAAkB;KACrC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { assertBlobContentKeyBundleTargetHash } from \"../../../data/blobs/attachments/responses\";\nimport type { DecryptDocumentAttachmentBlobInput } from \"../../../data/blobs/attachments/types\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport {\n type DocumentWriterProjectionAuthorization,\n requireProjectionUserKeyResolver,\n} from \"../../../data/keyingProjectionVerification\";\nimport { assertAttachmentBindingVerified } from \"./attachmentBindingVerification\";\nimport { assertBlobWrapScopeVerified } from \"./verifiedWrapScope\";\n\n/** Retaining an existing envelope does not propagate a key to a new recipient. */\nexport async function verifyRetainedAttachment(\n input: Omit<\n DecryptDocumentAttachmentBlobInput,\n \"encryptedBytes\" | \"targetSecretKey\"\n >,\n): Promise<void> {\n const resolveProjectionUserKey = requireProjectionUserKeyResolver(\n input.resolveProjectionUserKey,\n \"Retained attachment scope\",\n );\n let authorization: DocumentWriterProjectionAuthorization | undefined;\n await assertDocumentWriterProjectionConsistent(input.writerProjection, {\n allowStaleContentKeyBundle: true,\n ...projectionVerificationOptions({\n execSql: input.execSql,\n stillCurrent: input.stillCurrent,\n warmReferencedPrincipalPolicies: input.warmReferencedPrincipalPolicies,\n resolveProjectionUserKey,\n }),\n onVerifiedAuthorization: (value) => {\n authorization = value;\n },\n });\n if (input.binding.contentKeyBundle.blobId !== input.binding.blobId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Retained attachment bundle names another blob\",\n );\n await assertBlobContentKeyBundleTargetHash(input.binding.contentKeyBundle);\n await assertAttachmentBindingVerified({\n ...input,\n authorization,\n resolveProjectionUserKey,\n });\n if (!authorization) throw new Error(\"Attachment authority is unavailable\");\n assertBlobWrapScopeVerified({\n authorization,\n binding: input.binding,\n documentId: input.expectedDocumentId,\n });\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readDocumentManifestIdentity } from "../../../data/
|
|
1
|
+
import { readDocumentManifestIdentity } from "../../../data/blobs/attachments/readers.js";
|
|
2
2
|
import { assertDocumentWriterProjectionConsistent } from "../../../data/documents/shared/projection/index.js";
|
|
3
3
|
import { projectionVerificationOptions, } from "../../../data/documents/shared/types.js";
|
|
4
4
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writerProjection.js","sourceRoot":"","sources":["writerProjection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"writerProjection.js","sourceRoot":"","sources":["writerProjection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AAKvF,OAAO,EAAE,wCAAwC,EAAE,MAAM,2CAA2C,CAAC;AACrG,OAAO,EAEL,6BAA6B,GAC9B,MAAM,sCAAsC,CAAC;AAG9C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,KAQiC;IAKjC,MAAM,gBAAgB,GACpB,KAAK,CAAC,gBAAgB;QACtB,CAAC,MAAM,KAAK,CAAC,SAAS,CAAC,2BAA2B,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IACxE,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,wCAAwC,CAAC,gBAAgB,EAAE;QAC/D,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,6BAA6B,CAAC,KAAK,CAAC;KACxC,CAAC,CAAC;IACH,MAAM,gBAAgB,GAAG,4BAA4B,CAAC,gBAAgB,CAAC,CAAC;IACxE,IAAI,gBAAgB,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,CAAC,UAAU,2CAA2C,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;AAChD,CAAC","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { readDocumentManifestIdentity } from \"../../../data/blobs/attachments/readers\";\nimport type {\n BlobAttachmentApi,\n DocumentManifestIdentity,\n} from \"../../../data/blobs/attachments/types\";\nimport { assertDocumentWriterProjectionConsistent } from \"../../../data/documents/shared/projection\";\nimport {\n type ProjectionVerificationOptions,\n projectionVerificationOptions,\n} from \"../../../data/documents/shared/types\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\n\n/**\n * Shared prologue for blob attachment mutations (upload/detach): resolve the\n * document writer projection, verify its consistency, confirm it targets the\n * mutated document, and gate on a blocked organization. Returns null when the\n * projection is unavailable or the organization's remote sync is blocked.\n */\nexport async function resolveBlobMutationWriterProjection(\n input: {\n apiClient: Pick<BlobAttachmentApi, \"getDocumentWriterProjection\">;\n documentId: string;\n /** Prefix for the wrong-document error, e.g. \"Blob attachment detach\". */\n errorLabel: string;\n execSql?: ExecSql | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n } & ProjectionVerificationOptions,\n): Promise<{\n manifestIdentity: DocumentManifestIdentity;\n writerProjection: DocumentWriterProjectionResponse;\n} | null> {\n const writerProjection =\n input.writerProjection ??\n (await input.apiClient.getDocumentWriterProjection(input.documentId));\n if (!writerProjection) {\n return null;\n }\n\n await assertDocumentWriterProjectionConsistent(writerProjection, {\n execSql: input.execSql,\n ...projectionVerificationOptions(input),\n });\n const manifestIdentity = readDocumentManifestIdentity(writerProjection);\n if (manifestIdentity.documentId !== input.documentId) {\n throw new Error(\n `${input.errorLabel} writer projection targets wrong document`,\n );\n }\n if (input.isRemoteSyncBlocked?.(manifestIdentity.organizationId)) {\n return null;\n }\n\n return { manifestIdentity, writerProjection };\n}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export { unwrapContainerKekPath, unwrapDocumentContentKeyTarget, } from "../../data/documents/shared/projection/index.js";
|
|
2
2
|
export { persistedDocumentCreateStateFromResponse } from "../../data/documents/shared/responses.js";
|
|
3
|
+
export { selectDocumentSyncOutgoingBatch } from "../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
3
4
|
export { type DocumentSyncUpdateIsolationError, type IncomingDocumentSyncUpdateValidator, isDocumentSyncUpdateIsolationError, validateDocumentSyncUpdateImports, } from "../../data/documents/shared/sync/documentSyncUpdateIsolation.js";
|
|
4
5
|
export { type DocumentSyncPullContinuation, documentSyncPullContinuationsEqual, readPullContinuation, } from "../../data/documents/shared/sync/syncPagination.js";
|
|
5
6
|
export type { DocumentCreateAuthor, DocumentLinkSetFailureHandler, DocumentLinkSetMutationFailure, RelinkRemoteDocumentResult, } from "../../data/documents/shared/types.js";
|
|
6
7
|
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/sqlite/documentPersistence/index.js";
|
|
7
8
|
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/sqlite/documentPersistence/documentHistoryPersistence.js";
|
|
8
9
|
export type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
9
|
-
export { selectDocumentSyncOutgoingBatch } from "../../data/sync/documentSyncOutgoingBatch.js";
|
|
10
10
|
export { settleOutgoingPassAndDecideReArm } from "../../data/sync/outgoingUpdateSettlement.js";
|
|
11
11
|
export { didRegainSyncPrerequisites, isDatabaseUnavailableError, } from "../../data/sync/syncCoordinator.js";
|
|
12
12
|
export { deleteLocalDocumentAttachment, deletePendingDocumentAttachment, markLocalDocumentAttachmentDetached, saveLocalDocumentAttachments, savePendingDocumentAttachment, } from "./attachments/attachmentPersistence.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { unwrapContainerKekPath, unwrapDocumentContentKeyTarget, } from "../../data/documents/shared/projection/index.js";
|
|
2
2
|
export { persistedDocumentCreateStateFromResponse } from "../../data/documents/shared/responses.js";
|
|
3
|
+
export { selectDocumentSyncOutgoingBatch } from "../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
3
4
|
export { isDocumentSyncUpdateIsolationError, validateDocumentSyncUpdateImports, } from "../../data/documents/shared/sync/documentSyncUpdateIsolation.js";
|
|
4
5
|
export { documentSyncPullContinuationsEqual, readPullContinuation, } from "../../data/documents/shared/sync/syncPagination.js";
|
|
5
6
|
export { clearDocumentSyncFailure, invalidateDocumentSyncPullContinuation, recordDocumentSyncFailure, } from "../../data/sqlite/documentPersistence/index.js";
|
|
6
7
|
export { DOCUMENT_HISTORY_COMPACTION_MAX_BYTES, DOCUMENT_HISTORY_COMPACTION_MAX_ROWS, } from "../../data/sqlite/documentPersistence/documentHistoryPersistence.js";
|
|
7
|
-
export { selectDocumentSyncOutgoingBatch } from "../../data/sync/documentSyncOutgoingBatch.js";
|
|
8
8
|
export { settleOutgoingPassAndDecideReArm } from "../../data/sync/outgoingUpdateSettlement.js";
|
|
9
9
|
export { didRegainSyncPrerequisites, isDatabaseUnavailableError, } from "../../data/sync/syncCoordinator.js";
|
|
10
10
|
export { deleteLocalDocumentAttachment, deletePendingDocumentAttachment, markLocalDocumentAttachmentDetached, saveLocalDocumentAttachments, savePendingDocumentAttachment, } from "./attachments/attachmentPersistence.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EAGL,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,8DAA8D,CAAC;AACtE,OAAO,EAEL,kCAAkC,EAClC,oBAAoB,GACrB,MAAM,iDAAiD,CAAC;AAOzD,OAAO,EACL,wBAAwB,EACxB,sCAAsC,EACtC,yBAAyB,GAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,kEAAkE,CAAC;AAE1E,OAAO,EAAE
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EAAE,+BAA+B,EAAE,MAAM,4DAA4D,CAAC;AAC7G,OAAO,EAGL,kCAAkC,EAClC,iCAAiC,GAClC,MAAM,8DAA8D,CAAC;AACtE,OAAO,EAEL,kCAAkC,EAClC,oBAAoB,GACrB,MAAM,iDAAiD,CAAC;AAOzD,OAAO,EACL,wBAAwB,EACxB,sCAAsC,EACtC,yBAAyB,GAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACL,qCAAqC,EACrC,oCAAoC,GACrC,MAAM,kEAAkE,CAAC;AAE1E,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,mCAAmC,EACnC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,mCAAmC,EACnC,oBAAoB,EACpB,0CAA0C,GAC3C,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,gCAAgC,EAChC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,4CAA4C,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,kBAAkB,EAGlB,2BAA2B,EAE3B,+BAA+B,EAK/B,oBAAoB,EAEpB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,uCAAuC,EAGvC,qCAAqC,GACtC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAEL,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,GAM/B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAGjE,OAAO,EAEL,wBAAwB,EACxB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mCAAmC,EACnC,iCAAiC,GAElC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,uCAAuC,EAAE,MAAM,qCAAqC,CAAC;AAC9F,OAAO,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAE,qCAAqC,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export {\n unwrapContainerKekPath,\n unwrapDocumentContentKeyTarget,\n} from \"../../data/documents/shared/projection\";\nexport { persistedDocumentCreateStateFromResponse } from \"../../data/documents/shared/responses\";\nexport { selectDocumentSyncOutgoingBatch } from \"../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nexport {\n type DocumentSyncUpdateIsolationError,\n type IncomingDocumentSyncUpdateValidator,\n isDocumentSyncUpdateIsolationError,\n validateDocumentSyncUpdateImports,\n} from \"../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nexport {\n type DocumentSyncPullContinuation,\n documentSyncPullContinuationsEqual,\n readPullContinuation,\n} from \"../../data/documents/shared/sync/syncPagination\";\nexport type {\n DocumentCreateAuthor,\n DocumentLinkSetFailureHandler,\n DocumentLinkSetMutationFailure,\n RelinkRemoteDocumentResult,\n} from \"../../data/documents/shared/types\";\nexport {\n clearDocumentSyncFailure,\n invalidateDocumentSyncPullContinuation,\n recordDocumentSyncFailure,\n} from \"../../data/sqlite/documentPersistence\";\nexport {\n DOCUMENT_HISTORY_COMPACTION_MAX_BYTES,\n DOCUMENT_HISTORY_COMPACTION_MAX_ROWS,\n} from \"../../data/sqlite/documentPersistence/documentHistoryPersistence\";\nexport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nexport { settleOutgoingPassAndDecideReArm } from \"../../data/sync/outgoingUpdateSettlement\";\nexport {\n didRegainSyncPrerequisites,\n isDatabaseUnavailableError,\n} from \"../../data/sync/syncCoordinator\";\nexport {\n deleteLocalDocumentAttachment,\n deletePendingDocumentAttachment,\n markLocalDocumentAttachmentDetached,\n saveLocalDocumentAttachments,\n savePendingDocumentAttachment,\n} from \"./attachments/attachmentPersistence\";\nexport { runSerializedDocumentBlobMutation } from \"./attachments/blobMutationLock\";\nexport { reclaimDocumentOrphanBlobs } from \"./attachments/orphanBlobReclaims\";\nexport { resolveDocumentCreateAuthor } from \"./author\";\nexport {\n buildMaterializedDocumentCreatePlan,\n createRemoteDocument,\n documentWriterProjectionFromCreateResponse,\n} from \"./create\";\nexport {\n importDocumentHistoryTailUpdates,\n loadPersistedDocumentContent,\n mergePersistedDocumentHistory,\n} from \"./historyContent\";\nexport { buildMaterializedDocumentLinkSetMutationPlan } from \"./linkSet\";\nexport { relinkRemoteDocument } from \"./linkSet/linkSetRemote\";\nexport {\n enqueuePendingDocumentUpdate,\n listPendingDocumentUpdates,\n} from \"./pendingUpdatePersistence\";\nexport {\n type AttachmentRemovalRows,\n type AttachmentStagingRows,\n DOCUMENTS_APP_KIND,\n type DocumentRecord,\n type DocumentsPersistence,\n defaultDocumentsPersistence,\n type LocalAttachmentRecord,\n loadPersistedDocumentStoreState,\n type PendingAttachmentRecord,\n type PendingAttachmentUploadIdentity,\n type PendingUpdateInsert,\n type PendingUpdateRecord,\n persistDocumentState,\n type RelinkPersistedDocumentInput,\n runSerializedSqlMutation,\n} from \"./persistence\";\nexport {\n createDocumentProjectionUserKeyResolver,\n type DocumentProjectionKeyRuntime,\n type DocumentProjectionUserKeyResolver,\n didDocumentProjectionKeyRuntimeChange,\n} from \"./projectionKeys\";\nexport {\n buildDocumentPurgeRequest,\n purgeRemoteDocument,\n} from \"./purge\";\nexport {\n type DiscardedDocumentShellResult,\n deletePersistedDocument,\n discardPersistedDocumentToShell,\n} from \"./purge/persistedDocumentRemoval\";\nexport {\n createDocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntime,\n type DocumentsWorkflowRuntimeGroups,\n type DocumentsWorkflowRuntimeInfra,\n type DocumentsWorkflowRuntimeInput,\n type DocumentsWorkflowRuntimeInputGroups,\n} from \"./runtime\";\nexport {\n hasDocumentUpdateEvent,\n syncRemoteDocument,\n} from \"./sync\";\nexport { documentCreateSeedCandidate } from \"./sync/initialSync\";\nexport type { SyncRemoteDocumentInput } from \"./sync/readOnlySync\";\nexport type { DocumentSyncContainerRekeyBuilder } from \"./sync/syncAttemptState\";\nexport {\n type DocumentSyncLane,\n registerDocumentSyncLane,\n requestDocumentSyncLaneAndWait,\n} from \"./sync/syncLane\";\nexport {\n DOCUMENT_SYNC_TRACE_FRAGMENT,\n DOCUMENT_SYNC_TRACE_PATTERN,\n} from \"./sync/syncTrace\";\nexport {\n describeDocumentRevalidationFailure,\n describeDocumentSyncSubmitFailure,\n type TerminalSubmitFailureHandler,\n} from \"./syncFailures/syncFailureClassification\";\nexport { shouldClearDocumentSyncFailureAfterPass } from \"./syncFailures/syncFailureClearance\";\nexport { DocumentRawHistoryUnavailableError } from \"./syncPlan/syncContentKeys\";\nexport type { RekeyPendingUpdate } from \"./syncRekeys/syncRecoveryRekey\";\nexport { createDocumentWriterPublicKeyResolver } from \"./writerKeys\";\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isAccessManifestBundleWireResponse, isDocumentContentKeyBundleResponse, isDocumentKekTargetsResponse, } from "../../../internal/validators/response/index.js";
|
|
2
2
|
import { isRetryableDocumentSyncConflict, persistedDocumentSyncStateFromResponse, submitDocumentSync, } from "../../../data/documents/shared/responses.js";
|
|
3
|
+
import { limitDocumentSyncRequestBytes } from "../../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
3
4
|
import { resolvePullContinuationMinLsn, } from "../../../data/documents/shared/sync/syncPagination.js";
|
|
4
5
|
import { projectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
5
6
|
import { readCanonicalRecord } from "../../../data/keying/canonicalJson.js";
|
|
6
|
-
import { limitDocumentSyncRequestBytes } from "../../../data/sync/documentSyncOutgoingBatch.js";
|
|
7
7
|
import { assertRawContinuationCanRetry, refreshSyncAttemptWriterProjection, resolveSyncAttemptWriterProjection, } from "../syncFailures/index.js";
|
|
8
8
|
import { handleUpstreamDeletedDocumentSyncFailure, projectionIntegrityErrorCode, } from "../syncFailures/syncFailureClassification.js";
|
|
9
9
|
import { DocumentRawHistoryUnavailableError } from "../syncPlan/syncContentKeys.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readOnlySync.js","sourceRoot":"","sources":["readOnlySync.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentCreateResponse,\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isAccessManifestBundleWireResponse,\n isDocumentContentKeyBundleResponse,\n isDocumentKekTargetsResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isRetryableDocumentSyncConflict,\n persistedDocumentSyncStateFromResponse,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport type {\n DocumentSyncUpdateIsolationError,\n IncomingDocumentSyncUpdateValidator,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentWriterPublicKeyResolver,\n PersistedDocumentSyncState,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport { limitDocumentSyncRequestBytes } from \"../../../data/sync/documentSyncOutgoingBatch\";\nimport {\n assertRawContinuationCanRetry,\n refreshSyncAttemptWriterProjection,\n resolveSyncAttemptWriterProjection,\n} from \"../syncFailures\";\nimport {\n handleUpstreamDeletedDocumentSyncFailure,\n projectionIntegrityErrorCode,\n type RemoteDocumentDeletionHandler,\n type TerminalSubmitFailureHandler,\n} from \"../syncFailures/syncFailureClassification\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport { buildDocumentSyncPlan } from \"../syncPlan/syncPlanIdentity\";\nimport { buildMaterializedDocumentSyncPlan } from \"../syncPlan/syncPlanMaterial\";\nimport type { RekeyPendingUpdate } from \"../syncRekeys/syncRecoveryRekey\";\nimport {\n handleReadOnlyProjectionCompletionError,\n REFRESH_CACHED_PROJECTION,\n} from \"./readOnlyProjectionFailure\";\nimport type { DocumentSyncContainerRekeyBuilder } from \"./syncAttemptState\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { type DocumentSyncTraceEmitter, traceSubmitFailed } from \"./syncTrace\";\n\nasync function completeReadOnlyRemoteDocumentSyncWithProjection(\n input: Omit<ReadOnlyDocumentSyncCompletionInput, \"writerProjection\"> & {\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<SyncRemoteDocumentResult> {\n const materializedPlan = await buildMaterializedDocumentSyncPlan({\n author: input.author,\n execSql: input.execSql,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n pullCursor: input.pullContinuation?.cursor,\n onSyncTrace: input.onSyncTrace,\n pendingUpdates: [],\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n materializedPlan,\n recoveryPendingUpdatesById: new Map(),\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n validateIncomingUpdates: input.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n return {\n ...result,\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nfunction parsePersistedDocumentSyncRecord<T>(\n value: string | null | undefined,\n label: string,\n isRecord: (value: unknown) => value is T,\n): T | null {\n if (!value) {\n return null;\n }\n\n try {\n const record = readCanonicalRecord(JSON.parse(value), label);\n return isRecord(record) ? record : null;\n } catch {\n return null;\n }\n}\n\nfunction parsePersistedDocumentSyncState(\n persistedState: PersistedDocumentSyncState | null | undefined,\n documentId: string,\n): {\n contentKeyBundle: DocumentCreateResponse[\"contentKeyBundle\"];\n documentKekTargets: DocumentSyncResponse[\"documentKekTargets\"];\n documentManifest: DocumentCreateResponse[\"accessManifest\"];\n} | null {\n if (persistedState?.documentId !== documentId) {\n return null;\n }\n\n const contentKeyBundle = parsePersistedDocumentSyncRecord(\n persistedState.contentKeyBundle,\n \"Persisted document sync content-key bundle\",\n isDocumentContentKeyBundleResponse,\n );\n const documentKekTargets = parsePersistedDocumentSyncRecord(\n persistedState.documentKekTargets,\n \"Persisted document sync KEK targets\",\n isDocumentKekTargetsResponse,\n );\n const documentManifest = parsePersistedDocumentSyncRecord(\n persistedState.documentManifestBundle,\n \"Persisted document sync manifest\",\n isAccessManifestBundleWireResponse,\n );\n\n if (!contentKeyBundle || !documentKekTargets || !documentManifest) {\n return null;\n }\n\n return {\n contentKeyBundle,\n documentKekTargets,\n documentManifest,\n };\n}\n\nasync function buildReadOnlyDocumentSyncPlanFromPersistedState(input: {\n author: DocumentCreateAuthor;\n documentId: string;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n signedAt?: string | undefined;\n}): Promise<DocumentSyncPlan | null> {\n const persisted = parsePersistedDocumentSyncState(\n input.persistedState,\n input.documentId,\n );\n if (!persisted) {\n return null;\n }\n\n const plan = await buildDocumentSyncPlan({\n author: input.author,\n contentKeyBundle: persisted.contentKeyBundle,\n documentId: input.documentId,\n documentKekTargets: persisted.documentKekTargets,\n documentManifest: persisted.documentManifest,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n outgoingUpdates: [],\n pullCursor: input.pullContinuation?.cursor,\n signedAt: input.signedAt,\n });\n const request = limitDocumentSyncRequestBytes(plan.request);\n return request === plan.request ? plan : { ...plan, request };\n}\n\ntype PersistedReadOnlyDocumentSyncResult =\n | {\n kind: \"completed\";\n result: SyncRemoteDocumentResult | null;\n }\n | {\n kind: \"not_completed\";\n };\n\ninterface ReadOnlyDocumentSyncCompletionInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n documentId: string;\n execSql: ExecSql;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n pullComplete: boolean;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nasync function tryCompleteReadOnlyRemoteDocumentSyncWithProjection(input: {\n allowCachedProjectionRefresh: boolean;\n completion: ReadOnlyDocumentSyncCompletionInput;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION\n> {\n try {\n return await completeReadOnlyRemoteDocumentSyncWithProjection({\n ...input.completion,\n writerProjection: input.writerProjection,\n });\n } catch (error) {\n return handleReadOnlyProjectionCompletionError(error, {\n allowCachedProjectionRefresh: input.allowCachedProjectionRefresh,\n historyMode: input.completion.historyMode,\n });\n }\n}\nasync function completeReadOnlyRemoteDocumentSyncWithUpdates(\n input: ReadOnlyDocumentSyncCompletionInput,\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n const reusableWriterProjection =\n input.writerProjection?.documentId === input.documentId\n ? input.writerProjection\n : null;\n const writerProjection =\n reusableWriterProjection ??\n (await resolveSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n }));\n if (!writerProjection) {\n return { kind: \"completed\", result: null };\n }\n const canRefreshProjection =\n input.historyMode === \"raw\" || Boolean(reusableWriterProjection);\n let result:\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION = null;\n let retryAfterRollback = false;\n try {\n result = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection({\n allowCachedProjectionRefresh: canRefreshProjection,\n completion: input,\n writerProjection,\n });\n } catch (error) {\n if (projectionIntegrityErrorCode(error) !== \"rollback\") {\n throw error;\n }\n retryAfterRollback = true;\n }\n if (\n !retryAfterRollback &&\n result !== REFRESH_CACHED_PROJECTION &&\n !(result instanceof DocumentRawHistoryUnavailableError) &&\n (result || !reusableWriterProjection)\n ) {\n return { kind: \"completed\", result };\n }\n const freshWriterProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n stillCurrent: input.stillCurrent,\n unavailableError:\n result instanceof DocumentRawHistoryUnavailableError ? result : undefined,\n });\n if (!freshWriterProjection) {\n return { kind: \"completed\", result: null };\n }\n const freshResult = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection(\n {\n allowCachedProjectionRefresh: false,\n completion: input,\n writerProjection: freshWriterProjection,\n },\n );\n if (\n freshResult === REFRESH_CACHED_PROJECTION ||\n freshResult instanceof DocumentRawHistoryUnavailableError\n ) {\n throw new Error(\"Fresh document projection unexpectedly requested refresh\");\n }\n return freshResult\n ? { kind: \"completed\", result: freshResult }\n : { kind: \"not_completed\" };\n}\nasync function syncReadOnlyRemoteDocumentFromPersistedState(\n input: Omit<\n ReadOnlyDocumentSyncCompletionInput,\n \"pullComplete\" | \"response\"\n > & {\n persistedState?: PersistedDocumentSyncState | null | undefined;\n },\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n let plan: DocumentSyncPlan | null;\n try {\n plan = await buildReadOnlyDocumentSyncPlanFromPersistedState(input);\n } catch {\n plan = null;\n }\n if (!plan) {\n return { kind: \"not_completed\" };\n }\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.pullContinuation?.commitLsnMode,\n plan,\n });\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted.ok) {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: submitted,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return { kind: \"completed\", result: null };\n }\n\n if (isRetryableDocumentSyncConflict(submitted)) {\n traceSubmitFailed(input.onSyncTrace, {\n action: \"retry\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n assertRawContinuationCanRetry(input.historyMode, input.pullContinuation);\n return { kind: \"not_completed\" };\n }\n\n traceSubmitFailed(input.onSyncTrace, {\n action: \"stop\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n submitted.report();\n return { kind: \"completed\", result: null };\n }\n\n if (submitted.response.updates.length > 0) {\n return completeReadOnlyRemoteDocumentSyncWithUpdates({\n ...input,\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n });\n }\n\n try {\n const persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n submitted.response,\n { resolveWriterPublicKey: input.resolveWriterPublicKey },\n );\n\n return {\n kind: \"completed\",\n result: {\n contentKey: new Uint8Array(),\n decryptedUpdates: [],\n exhaustedPendingUpdateCount: 0,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: !submitted.pullComplete,\n persistedState,\n plan,\n rekeyedPendingUpdateIds: [],\n response: submitted.response,\n settledPendingUpdateIds: [],\n acceptedRecoveryBaseline: false,\n },\n };\n } catch (error) {\n if (input.historyMode === \"raw\") {\n throw error;\n }\n return { kind: \"not_completed\" };\n }\n}\n\nexport interface SyncRemoteDocumentInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n /**\n * Supplies a full-history Loro snapshot of the local document so a\n * write-bearing pass can heal a stale content-key bundle by rotating to a\n * fresh content key anchored by a rotation baseline.\n */\n buildRotationSnapshot?: (() => Promise<Uint8Array | null>) | undefined;\n /** Overrides automatic ancestor repair for each submission's current projection. */\n buildContainerRekeys?: DocumentSyncContainerRekeyBuilder;\n documentId: string;\n execSql: ExecSql;\n /** Explicit read-only recovery that bypasses rotation-baseline redirect. */\n historyMode?: \"raw\" | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n /** Atomically commits the verified purge proof with matching local teardown. */\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n /** Clipboard-safe trace sink (see syncTrace.ts); never receives content. */\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Fires when a pass WITHOUT queued writes cannot resolve its writer\n * projection (e.g. a coded 409 from the projection route). Read-only\n * revalidation otherwise fails silently — one burned request and a trace\n * line — leaving the document permanently stale with nothing durable to\n * explain why (edge-case row 13).\n */\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n /** Records a verified response update that could not be decrypted/imported. */\n onIncomingUpdateIsolationFailure?:\n | ((failure: DocumentSyncUpdateIsolationError) => void | Promise<void>)\n | undefined;\n /** Fires immediately before a materialized outgoing batch is submitted. */\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n /** Invalidates continuation state after the server rejects its snapshot. */\n onPullContinuationInvalidated?:\n | ((continuation: DocumentSyncPullContinuation) => void | Promise<void>)\n | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates?: readonly PendingUpdateRecord[] | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n /** Validates decrypted updates against scratch state before callers persist. */\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport async function tryPersistedReadOnlyDocumentSync(\n input: SyncRemoteDocumentInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<PersistedReadOnlyDocumentSyncResult | null> {\n if (input.stillCurrent?.() === false) return null;\n if ((input.pendingUpdates ?? []).length > 0) return null;\n\n return syncReadOnlyRemoteDocumentFromPersistedState({\n ...input,\n resolveProjectionUserKey,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"readOnlySync.js","sourceRoot":"","sources":["readOnlySync.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DocumentCreateResponse,\n DocumentSyncResponse,\n DocumentWriterProjectionResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isAccessManifestBundleWireResponse,\n isDocumentContentKeyBundleResponse,\n isDocumentKekTargetsResponse,\n} from \"@tearleads/validators/response\";\nimport {\n isRetryableDocumentSyncConflict,\n persistedDocumentSyncStateFromResponse,\n submitDocumentSync,\n} from \"../../../data/documents/shared/responses\";\nimport { limitDocumentSyncRequestBytes } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport type {\n DocumentSyncUpdateIsolationError,\n IncomingDocumentSyncUpdateValidator,\n} from \"../../../data/documents/shared/sync/documentSyncUpdateIsolation\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type {\n DocumentCreateAuthor,\n DocumentSyncApi,\n DocumentSyncPlan,\n DocumentWriterPublicKeyResolver,\n PersistedDocumentSyncState,\n SyncRemoteDocumentResult,\n} from \"../../../data/documents/shared/types\";\nimport { projectionVerificationOptions } from \"../../../data/documents/shared/types\";\nimport { readCanonicalRecord } from \"../../../data/keying/canonicalJson\";\nimport type {\n ProjectionUserKeyResolver,\n ReferencedPrincipalPolicyWarmer,\n} from \"../../../data/keyingProjectionVerification\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport {\n assertRawContinuationCanRetry,\n refreshSyncAttemptWriterProjection,\n resolveSyncAttemptWriterProjection,\n} from \"../syncFailures\";\nimport {\n handleUpstreamDeletedDocumentSyncFailure,\n projectionIntegrityErrorCode,\n type RemoteDocumentDeletionHandler,\n type TerminalSubmitFailureHandler,\n} from \"../syncFailures/syncFailureClassification\";\nimport { DocumentRawHistoryUnavailableError } from \"../syncPlan/syncContentKeys\";\nimport { buildDocumentSyncPlan } from \"../syncPlan/syncPlanIdentity\";\nimport { buildMaterializedDocumentSyncPlan } from \"../syncPlan/syncPlanMaterial\";\nimport type { RekeyPendingUpdate } from \"../syncRekeys/syncRecoveryRekey\";\nimport {\n handleReadOnlyProjectionCompletionError,\n REFRESH_CACHED_PROJECTION,\n} from \"./readOnlyProjectionFailure\";\nimport type { DocumentSyncContainerRekeyBuilder } from \"./syncAttemptState\";\nimport { syncRemoteDocumentResultFromResponse } from \"./syncResponseResult\";\nimport { type DocumentSyncTraceEmitter, traceSubmitFailed } from \"./syncTrace\";\n\nasync function completeReadOnlyRemoteDocumentSyncWithProjection(\n input: Omit<ReadOnlyDocumentSyncCompletionInput, \"writerProjection\"> & {\n writerProjection: DocumentWriterProjectionResponse;\n },\n): Promise<SyncRemoteDocumentResult> {\n const materializedPlan = await buildMaterializedDocumentSyncPlan({\n author: input.author,\n execSql: input.execSql,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n pullCursor: input.pullContinuation?.cursor,\n onSyncTrace: input.onSyncTrace,\n pendingUpdates: [],\n signedAt: input.signedAt,\n targetSecretKey: input.targetSecretKey,\n writerProjection: input.writerProjection,\n ...projectionVerificationOptions(input),\n });\n\n const result = await syncRemoteDocumentResultFromResponse({\n ...projectionVerificationOptions(input),\n execSql: input.execSql,\n materializedPlan,\n recoveryPendingUpdatesById: new Map(),\n resolveWriterPublicKey: input.resolveWriterPublicKey,\n response: input.response,\n targetSecretKey: input.targetSecretKey,\n validateIncomingUpdates: input.validateIncomingUpdates,\n writerProjection: input.writerProjection,\n resolveProjectionUserKey: input.resolveProjectionUserKey,\n });\n return {\n ...result,\n hasIncompletePull: !input.pullComplete,\n };\n}\n\nfunction parsePersistedDocumentSyncRecord<T>(\n value: string | null | undefined,\n label: string,\n isRecord: (value: unknown) => value is T,\n): T | null {\n if (!value) {\n return null;\n }\n\n try {\n const record = readCanonicalRecord(JSON.parse(value), label);\n return isRecord(record) ? record : null;\n } catch {\n return null;\n }\n}\n\nfunction parsePersistedDocumentSyncState(\n persistedState: PersistedDocumentSyncState | null | undefined,\n documentId: string,\n): {\n contentKeyBundle: DocumentCreateResponse[\"contentKeyBundle\"];\n documentKekTargets: DocumentSyncResponse[\"documentKekTargets\"];\n documentManifest: DocumentCreateResponse[\"accessManifest\"];\n} | null {\n if (persistedState?.documentId !== documentId) {\n return null;\n }\n\n const contentKeyBundle = parsePersistedDocumentSyncRecord(\n persistedState.contentKeyBundle,\n \"Persisted document sync content-key bundle\",\n isDocumentContentKeyBundleResponse,\n );\n const documentKekTargets = parsePersistedDocumentSyncRecord(\n persistedState.documentKekTargets,\n \"Persisted document sync KEK targets\",\n isDocumentKekTargetsResponse,\n );\n const documentManifest = parsePersistedDocumentSyncRecord(\n persistedState.documentManifestBundle,\n \"Persisted document sync manifest\",\n isAccessManifestBundleWireResponse,\n );\n\n if (!contentKeyBundle || !documentKekTargets || !documentManifest) {\n return null;\n }\n\n return {\n contentKeyBundle,\n documentKekTargets,\n documentManifest,\n };\n}\n\nasync function buildReadOnlyDocumentSyncPlanFromPersistedState(input: {\n author: DocumentCreateAuthor;\n documentId: string;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n signedAt?: string | undefined;\n}): Promise<DocumentSyncPlan | null> {\n const persisted = parsePersistedDocumentSyncState(\n input.persistedState,\n input.documentId,\n );\n if (!persisted) {\n return null;\n }\n\n const plan = await buildDocumentSyncPlan({\n author: input.author,\n contentKeyBundle: persisted.contentKeyBundle,\n documentId: input.documentId,\n documentKekTargets: persisted.documentKekTargets,\n documentManifest: persisted.documentManifest,\n historyMode: input.historyMode,\n localVersionVector: input.localVersionVector,\n minLsn: resolvePullContinuationMinLsn(input.pullContinuation, input.minLsn),\n outgoingUpdates: [],\n pullCursor: input.pullContinuation?.cursor,\n signedAt: input.signedAt,\n });\n const request = limitDocumentSyncRequestBytes(plan.request);\n return request === plan.request ? plan : { ...plan, request };\n}\n\ntype PersistedReadOnlyDocumentSyncResult =\n | {\n kind: \"completed\";\n result: SyncRemoteDocumentResult | null;\n }\n | {\n kind: \"not_completed\";\n };\n\ninterface ReadOnlyDocumentSyncCompletionInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n documentId: string;\n execSql: ExecSql;\n historyMode?: \"raw\" | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n pullComplete: boolean;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n response: DocumentSyncResponse;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nasync function tryCompleteReadOnlyRemoteDocumentSyncWithProjection(input: {\n allowCachedProjectionRefresh: boolean;\n completion: ReadOnlyDocumentSyncCompletionInput;\n writerProjection: DocumentWriterProjectionResponse;\n}): Promise<\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION\n> {\n try {\n return await completeReadOnlyRemoteDocumentSyncWithProjection({\n ...input.completion,\n writerProjection: input.writerProjection,\n });\n } catch (error) {\n return handleReadOnlyProjectionCompletionError(error, {\n allowCachedProjectionRefresh: input.allowCachedProjectionRefresh,\n historyMode: input.completion.historyMode,\n });\n }\n}\nasync function completeReadOnlyRemoteDocumentSyncWithUpdates(\n input: ReadOnlyDocumentSyncCompletionInput,\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n const reusableWriterProjection =\n input.writerProjection?.documentId === input.documentId\n ? input.writerProjection\n : null;\n const writerProjection =\n reusableWriterProjection ??\n (await resolveSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n reusableWriterProjection: null,\n stillCurrent: input.stillCurrent,\n }));\n if (!writerProjection) {\n return { kind: \"completed\", result: null };\n }\n const canRefreshProjection =\n input.historyMode === \"raw\" || Boolean(reusableWriterProjection);\n let result:\n | DocumentRawHistoryUnavailableError\n | SyncRemoteDocumentResult\n | null\n | typeof REFRESH_CACHED_PROJECTION = null;\n let retryAfterRollback = false;\n try {\n result = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection({\n allowCachedProjectionRefresh: canRefreshProjection,\n completion: input,\n writerProjection,\n });\n } catch (error) {\n if (projectionIntegrityErrorCode(error) !== \"rollback\") {\n throw error;\n }\n retryAfterRollback = true;\n }\n if (\n !retryAfterRollback &&\n result !== REFRESH_CACHED_PROJECTION &&\n !(result instanceof DocumentRawHistoryUnavailableError) &&\n (result || !reusableWriterProjection)\n ) {\n return { kind: \"completed\", result };\n }\n const freshWriterProjection = await refreshSyncAttemptWriterProjection({\n apiClient: input.apiClient,\n documentId: input.documentId,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n onSyncTrace: input.onSyncTrace,\n onTerminalFailure: input.onReadOnlyProjectionFailure,\n stillCurrent: input.stillCurrent,\n unavailableError:\n result instanceof DocumentRawHistoryUnavailableError ? result : undefined,\n });\n if (!freshWriterProjection) {\n return { kind: \"completed\", result: null };\n }\n const freshResult = await tryCompleteReadOnlyRemoteDocumentSyncWithProjection(\n {\n allowCachedProjectionRefresh: false,\n completion: input,\n writerProjection: freshWriterProjection,\n },\n );\n if (\n freshResult === REFRESH_CACHED_PROJECTION ||\n freshResult instanceof DocumentRawHistoryUnavailableError\n ) {\n throw new Error(\"Fresh document projection unexpectedly requested refresh\");\n }\n return freshResult\n ? { kind: \"completed\", result: freshResult }\n : { kind: \"not_completed\" };\n}\nasync function syncReadOnlyRemoteDocumentFromPersistedState(\n input: Omit<\n ReadOnlyDocumentSyncCompletionInput,\n \"pullComplete\" | \"response\"\n > & {\n persistedState?: PersistedDocumentSyncState | null | undefined;\n },\n): Promise<PersistedReadOnlyDocumentSyncResult> {\n let plan: DocumentSyncPlan | null;\n try {\n plan = await buildReadOnlyDocumentSyncPlanFromPersistedState(input);\n } catch {\n plan = null;\n }\n if (!plan) {\n return { kind: \"not_completed\" };\n }\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n const submitted = await submitDocumentSync({\n apiClient: input.apiClient,\n expectedCommitLsnMode: input.pullContinuation?.commitLsnMode,\n plan,\n });\n if (input.stillCurrent?.() === false) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted) {\n return { kind: \"completed\", result: null };\n }\n if (!submitted.ok) {\n if (\n await handleUpstreamDeletedDocumentSyncFailure({\n documentId: input.documentId,\n failure: submitted,\n onRemoteDocumentDeleted: input.onRemoteDocumentDeleted,\n })\n ) {\n return { kind: \"completed\", result: null };\n }\n\n if (isRetryableDocumentSyncConflict(submitted)) {\n traceSubmitFailed(input.onSyncTrace, {\n action: \"retry\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n assertRawContinuationCanRetry(input.historyMode, input.pullContinuation);\n return { kind: \"not_completed\" };\n }\n\n traceSubmitFailed(input.onSyncTrace, {\n action: \"stop\",\n code: submitted.code,\n documentId: input.documentId,\n status: submitted.status,\n });\n submitted.report();\n return { kind: \"completed\", result: null };\n }\n\n if (submitted.response.updates.length > 0) {\n return completeReadOnlyRemoteDocumentSyncWithUpdates({\n ...input,\n pullComplete: submitted.pullComplete,\n response: submitted.response,\n });\n }\n\n try {\n const persistedState = await persistedDocumentSyncStateFromResponse(\n plan,\n submitted.response,\n { resolveWriterPublicKey: input.resolveWriterPublicKey },\n );\n\n return {\n kind: \"completed\",\n result: {\n contentKey: new Uint8Array(),\n decryptedUpdates: [],\n exhaustedPendingUpdateCount: 0,\n hasDeferredPendingUpdates: false,\n hasIncompletePull: !submitted.pullComplete,\n persistedState,\n plan,\n rekeyedPendingUpdateIds: [],\n response: submitted.response,\n settledPendingUpdateIds: [],\n acceptedRecoveryBaseline: false,\n },\n };\n } catch (error) {\n if (input.historyMode === \"raw\") {\n throw error;\n }\n return { kind: \"not_completed\" };\n }\n}\n\nexport interface SyncRemoteDocumentInput {\n apiClient: DocumentSyncApi;\n author: DocumentCreateAuthor;\n /**\n * Supplies a full-history Loro snapshot of the local document so a\n * write-bearing pass can heal a stale content-key bundle by rotating to a\n * fresh content key anchored by a rotation baseline.\n */\n buildRotationSnapshot?: (() => Promise<Uint8Array | null>) | undefined;\n /** Overrides automatic ancestor repair for each submission's current projection. */\n buildContainerRekeys?: DocumentSyncContainerRekeyBuilder;\n documentId: string;\n execSql: ExecSql;\n /** Explicit read-only recovery that bypasses rotation-baseline redirect. */\n historyMode?: \"raw\" | undefined;\n isRemoteSyncBlocked?: ((organizationId: string) => boolean) | undefined;\n localVersionVector: string | null;\n minLsn?: string | undefined;\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n /** Atomically commits the verified purge proof with matching local teardown. */\n onRemoteDocumentDeleted?: RemoteDocumentDeletionHandler | undefined;\n onSyncAbandoned?: ((reason: string) => void) | undefined;\n /** Clipboard-safe trace sink (see syncTrace.ts); never receives content. */\n onSyncTrace?: DocumentSyncTraceEmitter | undefined;\n /**\n * Fires when a pass WITHOUT queued writes cannot resolve its writer\n * projection (e.g. a coded 409 from the projection route). Read-only\n * revalidation otherwise fails silently — one burned request and a trace\n * line — leaving the document permanently stale with nothing durable to\n * explain why (edge-case row 13).\n */\n onReadOnlyProjectionFailure?: TerminalSubmitFailureHandler | undefined;\n /** Records a verified response update that could not be decrypted/imported. */\n onIncomingUpdateIsolationFailure?:\n | ((failure: DocumentSyncUpdateIsolationError) => void | Promise<void>)\n | undefined;\n /** Fires immediately before a materialized outgoing batch is submitted. */\n onOutgoingUpdatesMaterialized?:\n | ((updateIds: readonly string[]) => void)\n | undefined;\n /** Invalidates continuation state after the server rejects its snapshot. */\n onPullContinuationInvalidated?:\n | ((continuation: DocumentSyncPullContinuation) => void | Promise<void>)\n | undefined;\n onTerminalSubmitFailure?: TerminalSubmitFailureHandler | undefined;\n pendingUpdates?: readonly PendingUpdateRecord[] | undefined;\n persistedState?: PersistedDocumentSyncState | null | undefined;\n rekeyPendingUpdate?: RekeyPendingUpdate | undefined;\n resolveProjectionUserKey: ProjectionUserKeyResolver;\n resolveWriterPublicKey: DocumentWriterPublicKeyResolver;\n signedAt?: string | undefined;\n stillCurrent?: (() => boolean) | undefined;\n targetSecretKey: Uint8Array;\n /** Validates decrypted updates against scratch state before callers persist. */\n validateIncomingUpdates: IncomingDocumentSyncUpdateValidator;\n warmReferencedPrincipalPolicies?: ReferencedPrincipalPolicyWarmer | undefined;\n writerProjection?: DocumentWriterProjectionResponse | undefined;\n}\n\nexport async function tryPersistedReadOnlyDocumentSync(\n input: SyncRemoteDocumentInput,\n resolveProjectionUserKey: ProjectionUserKeyResolver,\n): Promise<PersistedReadOnlyDocumentSyncResult | null> {\n if (input.stillCurrent?.() === false) return null;\n if ((input.pendingUpdates ?? []).length > 0) return null;\n\n return syncReadOnlyRemoteDocumentFromPersistedState({\n ...input,\n resolveProjectionUserKey,\n });\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContainerKekRepairInaccessibleError } from "../../../data/documents/shared/containerKek/containerKekCurrency.js";
|
|
2
2
|
import { assertDocumentManifestBundleConsistent } from "../../../data/documents/shared/readers.js";
|
|
3
|
+
import { isDocumentSyncRequestLimitError } from "../../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
3
4
|
import { resolvePullContinuationMinLsn, } from "../../../data/documents/shared/sync/syncPagination.js";
|
|
4
|
-
import { isDocumentSyncRequestLimitError } from "../../../data/sync/documentSyncOutgoingBatch.js";
|
|
5
5
|
import { retrySyncPlanOrAbandon } from "../syncFailures/index.js";
|
|
6
6
|
import { abandonAncestorRepair, abandonBlockedSync, abandonInaccessibleAncestorRepair, abandonOversizedSyncPlan, } from "../syncFailures/syncAbandon.js";
|
|
7
7
|
import { DocumentAncestorRepairAbandonedError, DocumentSyncPreparationRequiredError, } from "../syncFailures/syncRepairAbandon.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncAttemptPlanning.js","sourceRoot":"","sources":["syncAttemptPlanning.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mCAAmC,EAAE,MAAM,kEAAkE,CAAC;AACvH,OAAO,EAAE,sCAAsC,EAAE,MAAM,wCAAwC,CAAC;AAChG,OAAO,
|
|
1
|
+
{"version":3,"file":"syncAttemptPlanning.js","sourceRoot":"","sources":["syncAttemptPlanning.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DocumentWriterProjectionResponse } from \"@tearleads/validators/response\";\nimport { ContainerKekRepairInaccessibleError } from \"../../../data/documents/shared/containerKek/containerKekCurrency\";\nimport { assertDocumentManifestBundleConsistent } from \"../../../data/documents/shared/readers\";\nimport { isDocumentSyncRequestLimitError } from \"../../../data/documents/shared/sync/documentSyncOutgoingBatch\";\nimport {\n type DocumentSyncPullContinuation,\n resolvePullContinuationMinLsn,\n} from \"../../../data/documents/shared/sync/syncPagination\";\nimport type { PendingUpdateRecord } from \"../../../data/sqlite/documentPersistence\";\nimport { retrySyncPlanOrAbandon } from \"../syncFailures\";\nimport {\n abandonAncestorRepair,\n abandonBlockedSync,\n abandonInaccessibleAncestorRepair,\n abandonOversizedSyncPlan,\n} from \"../syncFailures/syncAbandon\";\nimport type { TerminalSubmitFailureHandler } from \"../syncFailures/syncFailureClassification\";\nimport {\n DocumentAncestorRepairAbandonedError,\n DocumentSyncPreparationRequiredError,\n} from \"../syncFailures/syncRepairAbandon\";\nimport { prepareSyncAttemptContainerRekeys } from \"../syncRekeys/syncContainerRekeyPreparation\";\nimport { buildRemoteDocumentSyncPlan } from \"../syncRekeys/syncContainerRekeys\";\nimport type { SyncRemoteDocumentInput } from \"./readOnlySync\";\n\n/**\n * A write-bearing pass records through the submit handler (its queued writes\n * are what the failure blocks). A read-only pass records through the\n * revalidation handler so the refusal still leaves a durable trail instead\n * of silently never revalidating (edge-case row 13). A cursor continuation is\n * wire-level read-only, but its failure still blocks the queued writes it\n * deliberately deferred. Update-id recovery likewise empties the in-flight\n * batch while durable rows remain. Both keep the submit classification and\n * its 403 handling.\n */\nexport function projectionFailureHandler(\n input: SyncRemoteDocumentInput,\n failureBlocksQueuedWrites: boolean,\n): TerminalSubmitFailureHandler | undefined {\n return failureBlocksQueuedWrites\n ? input.onTerminalSubmitFailure\n : input.onReadOnlyProjectionFailure;\n}\nexport async function planDocumentSyncAttempt(input: {\n pendingUpdates: readonly PendingUpdateRecord[];\n pullContinuation?: DocumentSyncPullContinuation | undefined;\n regenerateQueuedCheckpoints: boolean;\n sync: SyncRemoteDocumentInput;\n failureBlocksQueuedWrites: boolean;\n writerProjection: DocumentWriterProjectionResponse;\n}) {\n try {\n const pendingUpdates =\n input.pullContinuation === undefined ? input.pendingUpdates : [];\n if (\n pendingUpdates.length &&\n input.sync.isRemoteSyncBlocked?.(\n (\n await assertDocumentManifestBundleConsistent({\n bundle: input.writerProjection.documentManifest,\n label: \"Document sync manifest\",\n })\n ).organizationId,\n )\n ) {\n return abandonBlockedSync(input.sync);\n }\n // Durable repair happens once at this explicit attempt boundary. The\n // retryable builder below may only sign inline plans against its projection.\n const prepared =\n pendingUpdates.length &&\n !input.sync.buildContainerRekeys &&\n input.sync.buildRotationSnapshot\n ? await prepareSyncAttemptContainerRekeys(\n input.sync,\n input.writerProjection,\n )\n : { projection: input.writerProjection, plans: undefined };\n if (!prepared) return null;\n return await retrySyncPlanOrAbandon({\n apiClient: input.sync.apiClient,\n buildWithProjection: (projection) =>\n buildRemoteDocumentSyncPlan({\n pendingUpdates,\n preparedRekeys:\n projection === prepared.projection ? prepared.plans : undefined,\n minLsn: resolvePullContinuationMinLsn(\n input.pullContinuation,\n input.sync.minLsn,\n ),\n pullCursor: input.pullContinuation?.cursor,\n projection,\n regenerateQueuedCheckpoints: input.regenerateQueuedCheckpoints,\n sync: input.sync,\n }),\n documentId: input.sync.documentId,\n onRemoteDocumentDeleted: input.sync.onRemoteDocumentDeleted,\n onSyncAbandoned: input.sync.onSyncAbandoned,\n onSyncTrace: input.sync.onSyncTrace,\n onTerminalFailure: projectionFailureHandler(\n input.sync,\n input.failureBlocksQueuedWrites,\n ),\n stillCurrent: input.sync.stillCurrent,\n writerProjection: prepared.projection,\n });\n } catch (error) {\n if (error instanceof DocumentSyncPreparationRequiredError)\n return \"retry\" as const;\n if (error instanceof DocumentAncestorRepairAbandonedError) {\n return abandonAncestorRepair(input.sync, error);\n }\n if (error instanceof ContainerKekRepairInaccessibleError) {\n return abandonInaccessibleAncestorRepair(input.sync, error);\n }\n if (!isDocumentSyncRequestLimitError(error)) {\n throw error;\n }\n return abandonOversizedSyncPlan(input.sync, error);\n }\n}\n"]}
|
|
@@ -4,8 +4,8 @@ import { createPendingUpdateFields } from "../../../data/documents/documentSync.
|
|
|
4
4
|
import { assertDocumentKekPathsCurrent } from "../../../data/documents/shared/containerKek/containerKekCurrency.js";
|
|
5
5
|
import { assertDocumentWriterProjectionConsistent, authorizingContainerPathRefs, buildRotatedDocumentContentKeyBundle, ContainerKekHistoryUnavailableError, collectContainerKeksForDocumentSync, DocumentHistoryUnavailableError, unwrapDocumentContentKeyFromBundle, } from "../../../data/documents/shared/projection/index.js";
|
|
6
6
|
import { assertDocumentManifestBundleConsistent } from "../../../data/documents/shared/readers.js";
|
|
7
|
+
import { selectDocumentSyncOutgoingBatch } from "../../../data/documents/shared/sync/documentSyncOutgoingBatch.js";
|
|
7
8
|
import { projectionVerificationOptions } from "../../../data/documents/shared/types.js";
|
|
8
|
-
import { selectDocumentSyncOutgoingBatch } from "../../../data/sync/documentSyncOutgoingBatch.js";
|
|
9
9
|
import { traceCheckpointRegeneration, traceHealBlocked, traceHealPlanned, traceStaleBundle, traceStaleRead, } from "../sync/syncTrace.js";
|
|
10
10
|
import { prepareDocumentOutgoingUpdates } from "./syncContentKeys.js";
|
|
11
11
|
import { buildDocumentSyncPlan } from "./syncPlanIdentity.js";
|