@fluidframework/container-runtime 2.117.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -2
- package/README.md +53 -50
- package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
- package/api-report/container-runtime.legacy.alpha.api.md +3 -1
- package/api-report/container-runtime.legacy.beta.api.md +3 -1
- package/container-runtime.test-files.tar +0 -0
- package/dist/batchTracker.d.ts.map +1 -1
- package/dist/batchTracker.js +5 -1
- package/dist/batchTracker.js.map +1 -1
- package/dist/blobManager/blobManager.d.ts +1 -1
- package/dist/blobManager/blobManager.d.ts.map +1 -1
- package/dist/blobManager/blobManager.js +264 -231
- package/dist/blobManager/blobManager.js.map +1 -1
- package/dist/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/dist/channelCollection.d.ts.map +1 -1
- package/dist/channelCollection.js +70 -58
- package/dist/channelCollection.js.map +1 -1
- package/dist/connectionTelemetry.js +38 -20
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerCompatibility.d.ts +3 -3
- package/dist/containerCompatibility.d.ts.map +1 -1
- package/dist/containerCompatibility.js +36 -45
- package/dist/containerCompatibility.js.map +1 -1
- package/dist/containerHandleContext.d.ts.map +1 -1
- package/dist/containerHandleContext.js +4 -0
- package/dist/containerHandleContext.js.map +1 -1
- package/dist/containerRuntime.d.ts +4 -4
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +346 -223
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.d.ts.map +1 -1
- package/dist/dataStore.js +9 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +184 -127
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStoreContexts.js +43 -42
- package/dist/dataStoreContexts.js.map +1 -1
- package/dist/dataStoreRegistry.js +1 -0
- package/dist/dataStoreRegistry.js.map +1 -1
- package/dist/deltaManagerProxies.js +5 -0
- package/dist/deltaManagerProxies.js.map +1 -1
- package/dist/deltaScheduler.js +104 -99
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/error.js +2 -1
- package/dist/error.js.map +1 -1
- package/dist/gc/garbageCollection.js +85 -55
- package/dist/gc/garbageCollection.js.map +1 -1
- package/dist/gc/gcConfigs.js +2 -3
- package/dist/gc/gcConfigs.js.map +1 -1
- package/dist/gc/gcHelpers.js +12 -13
- package/dist/gc/gcHelpers.js.map +1 -1
- package/dist/gc/gcReferenceGraphAlgorithm.js +1 -2
- package/dist/gc/gcReferenceGraphAlgorithm.js.map +1 -1
- package/dist/gc/gcSummaryStateTracker.js +8 -3
- package/dist/gc/gcSummaryStateTracker.js.map +1 -1
- package/dist/gc/gcTelemetry.js +12 -5
- package/dist/gc/gcTelemetry.js.map +1 -1
- package/dist/gc/gcUnreferencedStateTracker.js +18 -1
- package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/dist/inboundBatchAggregator.js +122 -117
- package/dist/inboundBatchAggregator.js.map +1 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +3 -3
- package/dist/metadata.js.map +1 -1
- package/dist/opLifecycle/batchManager.d.ts.map +1 -1
- package/dist/opLifecycle/batchManager.js +11 -5
- package/dist/opLifecycle/batchManager.js.map +1 -1
- package/dist/opLifecycle/duplicateBatchDetector.js +18 -18
- package/dist/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/dist/opLifecycle/index.d.ts +2 -2
- package/dist/opLifecycle/index.d.ts.map +1 -1
- package/dist/opLifecycle/index.js +2 -1
- package/dist/opLifecycle/index.js.map +1 -1
- package/dist/opLifecycle/opCompressor.js +2 -1
- package/dist/opLifecycle/opCompressor.js.map +1 -1
- package/dist/opLifecycle/opDecompressor.js +10 -6
- package/dist/opLifecycle/opDecompressor.js.map +1 -1
- package/dist/opLifecycle/opGroupingManager.js +5 -3
- package/dist/opLifecycle/opGroupingManager.js.map +1 -1
- package/dist/opLifecycle/opSerialization.d.ts +11 -1
- package/dist/opLifecycle/opSerialization.d.ts.map +1 -1
- package/dist/opLifecycle/opSerialization.js +22 -6
- package/dist/opLifecycle/opSerialization.js.map +1 -1
- package/dist/opLifecycle/opSplitter.d.ts +17 -1
- package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
- package/dist/opLifecycle/opSplitter.js +46 -9
- package/dist/opLifecycle/opSplitter.js.map +1 -1
- package/dist/opLifecycle/outbox.d.ts.map +1 -1
- package/dist/opLifecycle/outbox.js +17 -13
- package/dist/opLifecycle/outbox.js.map +1 -1
- package/dist/opLifecycle/remoteMessageProcessor.js +6 -3
- package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/dist/opProperties.d.ts.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pendingStateManager.js +54 -47
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runCounter.js +10 -30
- package/dist/runCounter.js.map +1 -1
- package/dist/runtimeLayerCompatState.d.ts +1 -1
- package/dist/runtimeLayerCompatState.d.ts.map +1 -1
- package/dist/runtimeLayerCompatState.js +31 -11
- package/dist/runtimeLayerCompatState.js.map +1 -1
- package/dist/signalTelemetryProcessing.js +15 -17
- package/dist/signalTelemetryProcessing.js.map +1 -1
- package/dist/storageServiceWithAttachBlobs.js +2 -0
- package/dist/storageServiceWithAttachBlobs.js.map +1 -1
- package/dist/summary/documentSchema.d.ts.map +1 -1
- package/dist/summary/documentSchema.js +51 -13
- package/dist/summary/documentSchema.js.map +1 -1
- package/dist/summary/orderedClientElection.js +25 -17
- package/dist/summary/orderedClientElection.js.map +1 -1
- package/dist/summary/summarizerClientElection.d.ts.map +1 -1
- package/dist/summary/summarizerClientElection.js +18 -7
- package/dist/summary/summarizerClientElection.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNode.js +22 -13
- package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js +20 -6
- package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/dist/summary/summarizerUtils.d.ts.map +1 -1
- package/dist/summary/summarizerUtils.js +4 -3
- package/dist/summary/summarizerUtils.js.map +1 -1
- package/dist/summary/summaryCollection.js +23 -11
- package/dist/summary/summaryCollection.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js +4 -2
- package/dist/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js +65 -46
- package/dist/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizer.js +15 -6
- package/dist/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.js +30 -25
- package/dist/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js +9 -0
- package/dist/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js +3 -5
- package/dist/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -1
- package/dist/summary/summaryFormat.d.ts.map +1 -1
- package/dist/summary/summaryFormat.js +7 -7
- package/dist/summary/summaryFormat.js.map +1 -1
- package/dist/summary/summaryHelpers.js +5 -5
- package/dist/summary/summaryHelpers.js.map +1 -1
- package/dist/summary/summaryManager.js +66 -54
- package/dist/summary/summaryManager.js.map +1 -1
- package/dist/throttler.d.ts.map +1 -1
- package/dist/throttler.js +4 -1
- package/dist/throttler.js.map +1 -1
- package/dist/versionMarks/inboundBatch.d.ts +8 -6
- package/dist/versionMarks/inboundBatch.d.ts.map +1 -1
- package/dist/versionMarks/inboundBatch.js +11 -7
- package/dist/versionMarks/inboundBatch.js.map +1 -1
- package/dist/versionMarks/versionMarkResolver.d.ts +30 -23
- package/dist/versionMarks/versionMarkResolver.d.ts.map +1 -1
- package/dist/versionMarks/versionMarkResolver.js +112 -63
- package/dist/versionMarks/versionMarkResolver.js.map +1 -1
- package/lib/batchTracker.d.ts.map +1 -1
- package/lib/batchTracker.js +5 -1
- package/lib/batchTracker.js.map +1 -1
- package/lib/blobManager/blobManager.d.ts +1 -1
- package/lib/blobManager/blobManager.d.ts.map +1 -1
- package/lib/blobManager/blobManager.js +264 -231
- package/lib/blobManager/blobManager.js.map +1 -1
- package/lib/blobManager/blobManagerSnapSum.d.ts.map +1 -1
- package/lib/channelCollection.d.ts.map +1 -1
- package/lib/channelCollection.js +65 -53
- package/lib/channelCollection.js.map +1 -1
- package/lib/connectionTelemetry.js +36 -18
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerCompatibility.d.ts +3 -3
- package/lib/containerCompatibility.d.ts.map +1 -1
- package/lib/containerCompatibility.js +33 -42
- package/lib/containerCompatibility.js.map +1 -1
- package/lib/containerHandleContext.d.ts.map +1 -1
- package/lib/containerHandleContext.js +4 -0
- package/lib/containerHandleContext.js.map +1 -1
- package/lib/containerRuntime.d.ts +4 -4
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +341 -218
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.d.ts.map +1 -1
- package/lib/dataStore.js +9 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +182 -125
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStoreContexts.js +43 -42
- package/lib/dataStoreContexts.js.map +1 -1
- package/lib/dataStoreRegistry.js +1 -0
- package/lib/dataStoreRegistry.js.map +1 -1
- package/lib/deltaManagerProxies.js +5 -0
- package/lib/deltaManagerProxies.js.map +1 -1
- package/lib/deltaScheduler.js +104 -99
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/error.js +2 -1
- package/lib/error.js.map +1 -1
- package/lib/gc/garbageCollection.js +85 -55
- package/lib/gc/garbageCollection.js.map +1 -1
- package/lib/gc/gcSummaryStateTracker.js +8 -3
- package/lib/gc/gcSummaryStateTracker.js.map +1 -1
- package/lib/gc/gcTelemetry.js +12 -5
- package/lib/gc/gcTelemetry.js.map +1 -1
- package/lib/gc/gcUnreferencedStateTracker.js +18 -1
- package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
- package/lib/inboundBatchAggregator.js +122 -117
- package/lib/inboundBatchAggregator.js.map +1 -1
- package/lib/legacy.d.ts +1 -1
- package/lib/legacyAlpha.d.ts +1 -1
- package/lib/metadata.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.d.ts.map +1 -1
- package/lib/opLifecycle/batchManager.js +8 -2
- package/lib/opLifecycle/batchManager.js.map +1 -1
- package/lib/opLifecycle/duplicateBatchDetector.js +18 -18
- package/lib/opLifecycle/duplicateBatchDetector.js.map +1 -1
- package/lib/opLifecycle/index.d.ts +2 -2
- package/lib/opLifecycle/index.d.ts.map +1 -1
- package/lib/opLifecycle/index.js +2 -2
- package/lib/opLifecycle/index.js.map +1 -1
- package/lib/opLifecycle/opCompressor.js +3 -2
- package/lib/opLifecycle/opCompressor.js.map +1 -1
- package/lib/opLifecycle/opDecompressor.js +10 -6
- package/lib/opLifecycle/opDecompressor.js.map +1 -1
- package/lib/opLifecycle/opGroupingManager.js +3 -1
- package/lib/opLifecycle/opGroupingManager.js.map +1 -1
- package/lib/opLifecycle/opSerialization.d.ts +11 -1
- package/lib/opLifecycle/opSerialization.d.ts.map +1 -1
- package/lib/opLifecycle/opSerialization.js +16 -0
- package/lib/opLifecycle/opSerialization.js.map +1 -1
- package/lib/opLifecycle/opSplitter.d.ts +17 -1
- package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
- package/lib/opLifecycle/opSplitter.js +44 -7
- package/lib/opLifecycle/opSplitter.js.map +1 -1
- package/lib/opLifecycle/outbox.d.ts.map +1 -1
- package/lib/opLifecycle/outbox.js +14 -10
- package/lib/opLifecycle/outbox.js.map +1 -1
- package/lib/opLifecycle/remoteMessageProcessor.js +4 -1
- package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
- package/lib/opProperties.d.ts.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pendingStateManager.js +52 -45
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/runCounter.js +10 -30
- package/lib/runCounter.js.map +1 -1
- package/lib/runtimeLayerCompatState.d.ts +1 -1
- package/lib/runtimeLayerCompatState.d.ts.map +1 -1
- package/lib/runtimeLayerCompatState.js +28 -8
- package/lib/runtimeLayerCompatState.js.map +1 -1
- package/lib/signalTelemetryProcessing.js +15 -17
- package/lib/signalTelemetryProcessing.js.map +1 -1
- package/lib/storageServiceWithAttachBlobs.js +2 -0
- package/lib/storageServiceWithAttachBlobs.js.map +1 -1
- package/lib/summary/documentSchema.d.ts.map +1 -1
- package/lib/summary/documentSchema.js +51 -13
- package/lib/summary/documentSchema.js.map +1 -1
- package/lib/summary/orderedClientElection.js +25 -17
- package/lib/summary/orderedClientElection.js.map +1 -1
- package/lib/summary/summarizerClientElection.d.ts.map +1 -1
- package/lib/summary/summarizerClientElection.js +18 -7
- package/lib/summary/summarizerClientElection.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNode.js +22 -13
- package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js +20 -6
- package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
- package/lib/summary/summarizerUtils.d.ts.map +1 -1
- package/lib/summary/summarizerUtils.js +1 -0
- package/lib/summary/summarizerUtils.js.map +1 -1
- package/lib/summary/summaryCollection.js +23 -11
- package/lib/summary/summaryCollection.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js +4 -2
- package/lib/summary/summaryDelayLoadedModule/runWhileConnectedCoordinator.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js +65 -46
- package/lib/summary/summaryDelayLoadedModule/runningSummarizer.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizer.d.ts.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizer.js +15 -6
- package/lib/summary/summaryDelayLoadedModule/summarizer.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.js +30 -25
- package/lib/summary/summaryDelayLoadedModule/summarizerHeuristics.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js +9 -0
- package/lib/summary/summaryDelayLoadedModule/summaryGenerator.js.map +1 -1
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js +3 -5
- package/lib/summary/summaryDelayLoadedModule/summaryResultBuilder.js.map +1 -1
- package/lib/summary/summaryFormat.d.ts.map +1 -1
- package/lib/summary/summaryManager.js +66 -54
- package/lib/summary/summaryManager.js.map +1 -1
- package/lib/throttler.d.ts.map +1 -1
- package/lib/throttler.js +4 -1
- package/lib/throttler.js.map +1 -1
- package/lib/versionMarks/inboundBatch.d.ts +8 -6
- package/lib/versionMarks/inboundBatch.d.ts.map +1 -1
- package/lib/versionMarks/inboundBatch.js +10 -5
- package/lib/versionMarks/inboundBatch.js.map +1 -1
- package/lib/versionMarks/versionMarkResolver.d.ts +30 -23
- package/lib/versionMarks/versionMarkResolver.d.ts.map +1 -1
- package/lib/versionMarks/versionMarkResolver.js +112 -63
- package/lib/versionMarks/versionMarkResolver.js.map +1 -1
- package/package.json +60 -102
- package/src/containerCompatibility.ts +33 -42
- package/src/containerRuntime.ts +15 -12
- package/src/opLifecycle/index.ts +7 -1
- package/src/opLifecycle/opCompressor.ts +2 -2
- package/src/opLifecycle/opSerialization.ts +22 -1
- package/src/opLifecycle/opSplitter.ts +63 -6
- package/src/packageVersion.ts +1 -1
- package/src/runtimeLayerCompatState.ts +28 -21
- package/src/summary/documentSchema.ts +31 -6
- package/src/versionMarks/DEV.md +595 -158
- package/src/versionMarks/inboundBatch.ts +18 -8
- package/src/versionMarks/versionMarkResolver.ts +144 -75
- package/tsconfig.json +1 -1
- package/internal.d.ts +0 -11
- package/legacy/alpha.d.ts +0 -11
- package/legacy.d.ts +0 -11
- /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
- /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"versionMarkResolver.js","sourceRoot":"","sources":["../../src/versionMarks/versionMarkResolver.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tISequencedDocumentMessage,\n\tIStream,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { InboundMessageResult } from \"../opLifecycle/index.js\";\nimport { asBatchMetadata } from \"../metadata.js\";\n\nimport { inboundVersionMarkUpdate } from \"./inboundBatch.js\";\n\n/**\n * Reads sequenced ops in `[from, to)` from delta storage, injected by the container so the runtime stays\n * driver-agnostic. `abortSignal` cancels an in-flight fetch.\n *\n * @internal\n */\nexport interface IHistoricalOpReader {\n\tfetchMessages(\n\t\tfrom: number,\n\t\tto?: number,\n\t\tabortSignal?: AbortSignal,\n\t): Promise<IStream<ISequencedDocumentMessage[]>>;\n}\n\n/**\n * Result of resolving a pending batchId.\n *\n * @legacy @beta\n */\nexport type ResolveResult =\n\t| { readonly kind: \"resolved\"; readonly sequenceNumber: number }\n\t| { readonly kind: \"pending\" }\n\t| { readonly kind: \"unresolvable\" };\n\n/**\n * The data captured for a version mark. `pending` when the captured edit is local and not yet sequenced\n * (resolve it later via {@link IVersionMarkResolver.resolve}); `resolved` when there is no in-flight local\n * work, so the mark already points at a durable sequence number. The app packs its own stored record from\n * this — the runtime does not define the stored locator shape.\n *\n * @legacy @beta\n */\nexport type VersionMarkCapture =\n\t| {\n\t\t\treadonly kind: \"pending\";\n\t\t\treadonly batchId: string;\n\t\t\treadonly sequenceNumberLowerBound: number;\n\t }\n\t| { readonly kind: \"resolved\"; readonly sequenceNumber: number };\n\n/**\n * Runtime-owned resolver for app-stored version mark locators.\n *\n * @legacy @beta\n */\nexport interface IVersionMarkResolver {\n\t/**\n\t * Captures a version mark at the current point. Seals the current outbound batch first (so a just-made\n\t * local edit has a stable `batchId`, which is only assigned when a batch is flushed), then returns the\n\t * mark data atomically: a `pending` capture (`batchId` + `sequenceNumberLowerBound`) when there is an\n\t * unacked local batch, or a `resolved` capture (`sequenceNumber`) when there is no in-flight local work.\n\t *\n\t * @remarks Sealing the batch is a side effect (it submits the current batch), so capture at savepoint\n\t * boundaries, not per keystroke.\n\t *\n\t * @returns The pending batch identity and exclusive sequence number lower bound, or the current sequence number\n\t * when there is no pending local batch.\n\t */\n\tsealAndCaptureVersionMark(): VersionMarkCapture;\n\t/**\n\t * Resolves a pending mark's batchId to a global sequence number (`sequenceNumberLowerBound` is the\n\t * exclusive lower bound for a history read). A `resolved` sequence number feeds the loader's\n\t * `loadContainerToSequenceNumber`.\n\t *\n\t * @param batchId - The stable identity of the pending batch.\n\t * @param sequenceNumberLowerBound - The exclusive lower bound for the historical op search.\n\t * @returns The resolved sequence number, or a result indicating that the batch remains pending or can\n\t * no longer be resolved.\n\t */\n\tresolve(batchId: string, sequenceNumberLowerBound: number): Promise<ResolveResult>;\n\t/**\n\t * Subscribes to inbound batch sequencing: fires `(batchId, sequenceNumber)` per batch so any connected\n\t * client can promote a matching pending mark. Returns an unsubscribe function.\n\t *\n\t * @param listener - Called with the stable batch identity and its final sequence number.\n\t * @returns A function that unsubscribes the listener.\n\t */\n\tonBatchSequenced(listener: (batchId: string, sequenceNumber: number) => void): () => void;\n}\n\n/**\n * @internal\n */\nexport interface VersionMarkResolverRuntimeHooks {\n\treadonly getCurrentSequenceNumber: () => number;\n\treadonly getCurrentMinimumSequenceNumber: () => number;\n\treadonly getCurrentPendingBatchId: () => string | undefined;\n\t/** Logs faults from app-supplied `onBatchSequenced` listeners (see {@link VersionMarkResolver.processInboundBatch}). */\n\treadonly logger: TelemetryLoggerExt;\n\t/**\n\t * Seals the current outbound batch (flushes the runtime), so a just-submitted local edit is moved into\n\t * the pending state with a stable `batchId` before\n\t * {@link IVersionMarkResolver.sealAndCaptureVersionMark} reads it.\n\t */\n\treadonly flushPendingBatch: () => void;\n\t/**\n\t * Injected by the container, backed by delta storage. When absent, unknown batchIds resolve as `pending`.\n\t */\n\treadonly getHistoricalOpReader?: () => IHistoricalOpReader | undefined;\n\t/**\n\t * Creates a per-scan op unpacker that mirrors the live inbound path (chunk reassembly, ungroup,\n\t * decompress), so the history scan observes the same restored `batchId` — in particular for chunked\n\t * batches, whose id is stripped from the final chunk's wire metadata and restored only after\n\t * reassembly. A fresh unpacker is created per scan since it holds reassembly state. When absent, the\n\t * history scan cannot identify batches and reports `pending`/`unresolvable`.\n\t */\n\treadonly createHistoricalOpUnpacker?: () => (\n\t\top: ISequencedDocumentMessage,\n\t) => InboundMessageResult | undefined;\n}\n\n/**\n * Resolves a mark's batchId to a global sequence number. The app owns mark storage and promotion; the\n * runtime exposes the capture point and an ephemeral in-session `batchId -> sequenceNumber` map.\n *\n * @internal\n */\nexport class VersionMarkResolver implements IVersionMarkResolver {\n\tprivate readonly sequenceNumberByBatchId = new Map<string, number>();\n\tprivate readonly batchListeners = new Set<\n\t\t(batchId: string, sequenceNumber: number) => void\n\t>();\n\t/**\n\t * Sticky flag: false until the feature is first used this session (a pending capture or a listener).\n\t * While false the runtime skips all per-inbound-batch tracking, so a container that never uses version\n\t * marks pays nothing on the hot path (mirrors #22497 gating `DuplicateBatchDetector` on offline load).\n\t */\n\tprivate tracking = false;\n\n\tpublic constructor(private readonly hooks: VersionMarkResolverRuntimeHooks) {}\n\n\t/** Whether inbound batches need tracking (see {@link tracking}). Read by the runtime to gate the hot path. */\n\tpublic get isTracking(): boolean {\n\t\treturn this.tracking;\n\t}\n\n\tpublic sealAndCaptureVersionMark(): VersionMarkCapture {\n\t\t// Seal the current batch so a just-submitted local edit is flushed into the pending state with a\n\t\t// stable batchId (which is only assigned at flush) before we read it.\n\t\tthis.hooks.flushPendingBatch();\n\t\tconst sequenceNumberLowerBound = this.hooks.getCurrentSequenceNumber();\n\t\tconst batchId = this.hooks.getCurrentPendingBatchId();\n\t\tif (batchId === undefined) {\n\t\t\t// No unacked local batch: the mark already points at a durable sequence number.\n\t\t\treturn { kind: \"resolved\", sequenceNumber: sequenceNumberLowerBound };\n\t\t}\n\t\t// A pending mark needs its batch tracked so resolve() can promote it from the live map.\n\t\tthis.tracking = true;\n\t\treturn { kind: \"pending\", batchId, sequenceNumberLowerBound };\n\t}\n\n\tpublic async resolve(\n\t\tbatchId: string,\n\t\tsequenceNumberLowerBound: number,\n\t): Promise<ResolveResult> {\n\t\t// Fast path: batch sequenced live this session.\n\t\tconst sequenceNumber = this.sessionSequenceFor(batchId);\n\t\tif (sequenceNumber !== undefined) {\n\t\t\treturn { kind: \"resolved\", sequenceNumber };\n\t\t}\n\n\t\t// Otherwise scan history from the mark's reference point.\n\t\tconst reader = this.hooks.getHistoricalOpReader?.();\n\t\tif (reader === undefined) {\n\t\t\t// No reader: the batch may still sequence live, so report pending.\n\t\t\treturn { kind: \"pending\" };\n\t\t}\n\t\treturn this.resolveFromHistory(reader, batchId, sequenceNumberLowerBound);\n\t}\n\n\t/**\n\t * Scans sequenced ops after `sequenceNumberLowerBound` for `batchId`, returning its last op's\n\t * sequence number when found and aborting the fetch once found or exhausted. Each op is routed through\n\t * the same unpack pipeline the live inbound path uses (chunk reassembly, ungroup, decompress) and\n\t * {@link inboundVersionMarkUpdate} derives its batch identity, so chunked batches resolve here too. The\n\t * scan anchor is not guaranteed to be a batch boundary, so a leading batch clipped by the anchor is\n\t * tolerated (its orphan end marker is dropped rather than fed to the processor). On a miss,\n\t * {@link classifyMiss} distinguishes `pending` (not sequenced yet) from `unresolvable` (ops trimmed).\n\t * See DEV.md.\n\t */\n\tprivate async resolveFromHistory(\n\t\treader: IHistoricalOpReader,\n\t\tbatchId: string,\n\t\tsequenceNumberLowerBound: number,\n\t): Promise<ResolveResult> {\n\t\tconst from = sequenceNumberLowerBound + 1;\n\t\tconst unpack = this.hooks.createHistoricalOpUnpacker?.();\n\t\tconst abortController = new AbortController();\n\t\ttry {\n\t\t\tconst stream = await reader.fetchMessages(from, undefined, abortController.signal);\n\t\t\tlet firstScannedSequenceNumber: number | undefined;\n\t\t\tlet carriedBatchId: string | undefined;\n\t\t\t// Mirrors the processor's batch-in-progress state so we can drop an orphan end marker (below).\n\t\t\tlet inBatch = false;\n\t\t\twhile (true) {\n\t\t\t\tconst result = await stream.read();\n\t\t\t\tif (result.done) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfor (const op of result.value) {\n\t\t\t\t\tfirstScannedSequenceNumber ??= op.sequenceNumber;\n\t\t\t\t\tif (!inBatch && asBatchMetadata(op.metadata)?.batch === false) {\n\t\t\t\t\t\t// The anchor (`sequenceNumberLowerBound + 1`) may land inside a batch whose start\n\t\t\t\t\t\t// precedes the window; its orphan end marker would trip the processor's 0x9d5 assert.\n\t\t\t\t\t\t// Drop the clipped tail. The target batch is fully in-window, so this can't skip it.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// undefined = a system op, or an incomplete chunk awaiting later fragments.\n\t\t\t\t\tconst inboundResult = unpack?.(op);\n\t\t\t\t\tif (inboundResult === undefined) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// Track batch progress with the processor so the guard above skips only orphan ends.\n\t\t\t\t\tif (inboundResult.type === \"batchStartingMessage\") {\n\t\t\t\t\t\tinBatch = true;\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tinboundResult.type === \"nextBatchMessage\" &&\n\t\t\t\t\t\tinboundResult.batchEnd === true\n\t\t\t\t\t) {\n\t\t\t\t\t\tinBatch = false;\n\t\t\t\t\t}\n\t\t\t\t\t// Derive batch identity exactly as the live inbound path does, carrying the id across a\n\t\t\t\t\t// piecemeal batch's messages.\n\t\t\t\t\tconst update = inboundVersionMarkUpdate(inboundResult, carriedBatchId);\n\t\t\t\t\tcarriedBatchId = update.carriedBatchId;\n\t\t\t\t\tif (update.sequenced?.batchId === batchId) {\n\t\t\t\t\t\treturn { kind: \"resolved\", sequenceNumber: update.sequenced.sequenceNumber };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Not found: distinguish \"not sequenced yet\" from \"trimmed\" via the tip and where the scan landed.\n\t\t\treturn this.classifyMiss(from, firstScannedSequenceNumber);\n\t\t} finally {\n\t\t\t// Cancel any in-flight fetch once we stop reading (found or exhausted).\n\t\t\tabortController.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Classifies a history-scan miss as `pending` or `unresolvable`. See {@link resolveFromHistory}.\n\t */\n\tprivate classifyMiss(\n\t\tfrom: number,\n\t\tfirstScannedSequenceNumber: number | undefined,\n\t): ResolveResult {\n\t\t// Invariant: a reader must never return an op before the requested range start. If it does, the\n\t\t// trim inference below is meaningless, so fail loudly rather than misclassify.\n\t\tassert(\n\t\t\tfirstScannedSequenceNumber === undefined || firstScannedSequenceNumber >= from,\n\t\t\t0xd1c /* historical op reader returned an op before the requested range start */,\n\t\t);\n\t\tconst tip = this.hooks.getCurrentSequenceNumber();\n\t\tif (from > tip) {\n\t\t\t// Nothing is sequenced at/after the mark's reference point yet, so the batch cannot have landed.\n\t\t\treturn { kind: \"pending\" };\n\t\t}\n\t\tif (firstScannedSequenceNumber === undefined) {\n\t\t\t// Empty read though ops should exist in `[from, tip]` → trimmed. ODSP-specific: a strict driver\n\t\t\t// empties a `from`-misaligned trimmed range (validateMessages); a return-from-earliest driver\n\t\t\t// would instead surface the trim via the `firstScannedSequenceNumber > from` branch below.\n\t\t\treturn { kind: \"unresolvable\" };\n\t\t}\n\t\tif (firstScannedSequenceNumber > from) {\n\t\t\t// A trim gap at the anchor: the mark's ops (just after the reference point) are gone.\n\t\t\treturn { kind: \"unresolvable\" };\n\t\t}\n\t\t// Ops are present from the reference point and the batch is not among them: not yet sequenced.\n\t\treturn { kind: \"pending\" };\n\t}\n\n\tpublic onBatchSequenced(\n\t\tlistener: (batchId: string, sequenceNumber: number) => void,\n\t): () => void {\n\t\t// A subscriber wants live promotions, so start tracking inbound batches from here on.\n\t\tthis.tracking = true;\n\t\tthis.batchListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.batchListeners.delete(listener);\n\t\t};\n\t}\n\n\t/** The sequence number for a batch seen live this session, or undefined. */\n\tprivate sessionSequenceFor(batchId: string): number | undefined {\n\t\treturn this.sequenceNumberByBatchId.get(batchId);\n\t}\n\n\t/** Records an inbound batch and notifies listeners so any client can promote matching pending marks. */\n\tpublic processInboundBatch(batchId: string, sequenceNumber: number): void {\n\t\tconst existingSequenceNumber = this.sequenceNumberByBatchId.get(batchId);\n\t\tif (existingSequenceNumber === sequenceNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.sequenceNumberByBatchId.set(batchId, sequenceNumber);\n\t\tthis.evictBelowMinimumSequenceNumber();\n\t\tfor (const listener of this.batchListeners) {\n\t\t\ttry {\n\t\t\t\tlistener(batchId, sequenceNumber);\n\t\t\t} catch (error) {\n\t\t\t\t// Isolate each app listener (like the container's EventEmitterWithErrorHandling): one throw\n\t\t\t\t// must not abort op processing or starve the rest. Log and continue rather than fault the\n\t\t\t\t// container — a missed promotion is recoverable via resolve()'s history scan.\n\t\t\t\tthis.hooks.logger.sendErrorEvent({ eventName: \"VersionMarkListenerException\" }, error);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Bounds the map to the collaboration window by dropping entries below the MSN (mirrors\n\t * `DuplicateBatchDetector`). Safe because below the MSN every client has processed the batch, so its\n\t * `onBatchSequenced` already fired; a dropped entry falls back to the history scan. Entries insert in\n\t * sequence order, so iteration stops at the first retained one.\n\t */\n\tprivate evictBelowMinimumSequenceNumber(): void {\n\t\tconst minimumSequenceNumber = this.hooks.getCurrentMinimumSequenceNumber();\n\t\tfor (const [id, sequenceNumber] of this.sequenceNumberByBatchId) {\n\t\t\tif (sequenceNumber >= minimumSequenceNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.sequenceNumberByBatchId.delete(id);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"versionMarkResolver.js","sourceRoot":"","sources":["../../src/versionMarks/versionMarkResolver.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tISequencedDocumentMessage,\n\tIStream,\n} from \"@fluidframework/driver-definitions/internal\";\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { InboundMessageResult } from \"../opLifecycle/index.js\";\n\nimport { inboundVersionMarkUpdate } from \"./inboundBatch.js\";\n\n/**\n * Reads sequenced ops in `[from, to)` from delta storage, injected by the container so the runtime stays\n * driver-agnostic. `abortSignal` cancels an in-flight fetch.\n *\n * @internal\n */\nexport interface IHistoricalOpReader {\n\tfetchMessages(\n\t\tfrom: number,\n\t\tto?: number,\n\t\tabortSignal?: AbortSignal,\n\t): Promise<IStream<ISequencedDocumentMessage[]>>;\n}\n\n/**\n * Result of resolving a pending batchId. A resolved result includes the matched batch's last op server\n * timestamp when available. The property is optional for compatibility with previously stored results.\n *\n * @legacy @beta\n */\nexport type ResolveResult =\n\t| {\n\t\t\treadonly kind: \"resolved\";\n\t\t\treadonly sequenceNumber: number;\n\t\t\treadonly timestamp?: number;\n\t }\n\t| { readonly kind: \"pending\" }\n\t| { readonly kind: \"unresolvable\" };\n\n/**\n * The data captured for a version mark. `pending` when the captured edit is local and not yet sequenced\n * (resolve it later via {@link IVersionMarkResolver.resolve}); `resolved` when there is no in-flight local\n * work, so the mark already points at a durable sequence number. The app packs its own stored record from\n * this — the runtime does not define the stored locator shape.\n *\n * @legacy @beta\n */\nexport type VersionMarkCapture =\n\t| {\n\t\t\treadonly kind: \"pending\";\n\t\t\treadonly batchId: string;\n\t\t\treadonly sequenceNumberLowerBound: number;\n\t }\n\t| {\n\t\t\treadonly kind: \"resolved\";\n\t\t\treadonly sequenceNumber: number;\n\t\t\treadonly timestamp?: number;\n\t };\n\n/**\n * Runtime-owned resolver for app-stored version mark locators.\n *\n * @legacy @beta\n */\nexport interface IVersionMarkResolver {\n\t/**\n\t * Captures a version mark at the current point. Seals the current outbound batch first (so a just-made\n\t * local edit has a stable `batchId`, which is only assigned when a batch is flushed), then returns the\n\t * mark data atomically: a `pending` capture (`batchId` + `sequenceNumberLowerBound`) when there is an\n\t * unacked local batch, or a `resolved` capture (`sequenceNumber` + the last processed op's server\n\t * `timestamp`) when there is no in-flight local work. The timestamp property is optional both for\n\t * compatibility with previously stored captures and because it is `undefined` when neither a last\n\t * processed message nor a last-summary message is available.\n\t *\n\t * @remarks Sealing the batch is a side effect (it submits the current batch), so capture at savepoint\n\t * boundaries, not per keystroke.\n\t *\n\t * @returns The pending batch identity and inclusive sequence number lower bound, or the current sequence\n\t * number and corresponding op timestamp (when available) when there is no pending local batch.\n\t */\n\tsealAndCaptureVersionMark(): VersionMarkCapture;\n\t/**\n\t * Resolves a pending mark's batchId to a global sequence number (`sequenceNumberLowerBound` is the\n\t * inclusive lower bound for a history read). A `resolved` sequence number feeds the loader's\n\t * `loadContainerToSequenceNumber`.\n\t *\n\t * @param batchId - The stable identity of the pending batch.\n\t * @param sequenceNumberLowerBound - The inclusive lower bound for the historical op search.\n\t * @returns The resolved sequence number and server timestamp, or a result indicating that the batch\n\t * remains pending or can no longer be resolved.\n\t */\n\tresolve(batchId: string, sequenceNumberLowerBound: number): Promise<ResolveResult>;\n\t/**\n\t * Subscribes to inbound batch sequencing: fires `(batchId, sequenceNumber, timestamp)` per batch so any\n\t * connected client can promote a matching pending mark. Returns an unsubscribe function.\n\t *\n\t * @param listener - Called with the stable batch identity, its final sequence number, and the final op's\n\t * server timestamp.\n\t * @returns A function that unsubscribes the listener.\n\t */\n\tonBatchSequenced(\n\t\tlistener: (batchId: string, sequenceNumber: number, timestamp?: number) => void,\n\t): () => void;\n}\n\n/**\n * @internal\n */\nexport interface VersionMarkResolverRuntimeHooks {\n\treadonly getCurrentSequenceNumber: () => number;\n\treadonly getCurrentTimestamp: () => number | undefined;\n\treadonly getCurrentMinimumSequenceNumber: () => number;\n\treadonly getCurrentPendingBatchId: () => string | undefined;\n\t/** Logs faults from app-supplied `onBatchSequenced` listeners (see {@link VersionMarkResolver.processInboundBatch}). */\n\treadonly logger: TelemetryLoggerExt;\n\t/**\n\t * Seals the current outbound batch (flushes the runtime), so a just-submitted local edit is moved into\n\t * the pending state with a stable `batchId` before\n\t * {@link IVersionMarkResolver.sealAndCaptureVersionMark} reads it.\n\t */\n\treadonly flushPendingBatch: () => void;\n\t/**\n\t * Injected by the container, backed by delta storage. When absent, unknown batchIds resolve as `pending`.\n\t */\n\treadonly getHistoricalOpReader?: () => IHistoricalOpReader | undefined;\n\t/**\n\t * Creates a per-scan op unpacker that mirrors the live inbound path (chunk reassembly, ungroup,\n\t * decompress), so the history scan observes the same restored `batchId` — in particular for chunked\n\t * batches, whose id is stripped from the final chunk's wire metadata and restored only after\n\t * reassembly. A fresh unpacker is created per scan since it holds reassembly state. When absent, the\n\t * history scan cannot identify batches and reports `pending`/`unresolvable`.\n\t */\n\treadonly createHistoricalOpUnpacker?: () => (\n\t\top: ISequencedDocumentMessage,\n\t) => InboundMessageResult | undefined;\n}\n\n/**\n * Resolves a mark's batchId to a global sequence number. The app owns mark storage and promotion; the\n * runtime exposes the capture point and an ephemeral in-session `batchId -> sequenceNumber` map.\n *\n * @internal\n */\nexport class VersionMarkResolver implements IVersionMarkResolver {\n\tprivate readonly resolvedBatchById = new Map<\n\t\tstring,\n\t\t{ readonly sequenceNumber: number; readonly timestamp: number }\n\t>();\n\tprivate readonly batchListeners = new Set<\n\t\t(batchId: string, sequenceNumber: number, timestamp: number) => void\n\t>();\n\t/**\n\t * Sticky flag: false until the feature is first used this session (a pending capture or a listener).\n\t * While false the runtime skips all per-inbound-batch tracking, so a container that never uses version\n\t * marks pays nothing on the hot path (mirrors #22497 gating `DuplicateBatchDetector` on offline load).\n\t */\n\tprivate tracking = false;\n\n\tpublic constructor(private readonly hooks: VersionMarkResolverRuntimeHooks) {}\n\n\t/** Whether inbound batches need tracking (see {@link tracking}). Read by the runtime to gate the hot path. */\n\tpublic get isTracking(): boolean {\n\t\treturn this.tracking;\n\t}\n\n\tpublic sealAndCaptureVersionMark(): VersionMarkCapture {\n\t\t// Seal the current batch so a just-submitted local edit is flushed into the pending state with a\n\t\t// stable batchId (which is only assigned at flush) before we read it.\n\t\tthis.hooks.flushPendingBatch();\n\t\tconst referenceSequenceNumber = this.hooks.getCurrentSequenceNumber();\n\t\tconst batchId = this.hooks.getCurrentPendingBatchId();\n\t\tlet result: VersionMarkCapture;\n\t\tif (batchId === undefined) {\n\t\t\t// No unacked local batch: the mark already points at a durable sequence number.\n\t\t\tresult = {\n\t\t\t\tkind: \"resolved\",\n\t\t\t\tsequenceNumber: referenceSequenceNumber,\n\t\t\t\ttimestamp: this.hooks.getCurrentTimestamp(),\n\t\t\t};\n\t\t} else {\n\t\t\t// A pending mark needs its batch tracked so resolve() can promote it from the live map.\n\t\t\tthis.tracking = true;\n\t\t\t// The pending batch is sequenced after the reference point, so its first possible sequence\n\t\t\t// number is `referenceSequenceNumber + 1`. Store that as an inclusive lower bound so resolve()\n\t\t\t// scans directly from it.\n\t\t\tresult = {\n\t\t\t\tkind: \"pending\",\n\t\t\t\tbatchId,\n\t\t\t\tsequenceNumberLowerBound: referenceSequenceNumber + 1,\n\t\t\t};\n\t\t}\n\t\tthis.hooks.logger.sendTelemetryEvent({ eventName: \"Capture\", kind: result.kind });\n\t\treturn result;\n\t}\n\n\tpublic async resolve(\n\t\tbatchId: string,\n\t\tsequenceNumberLowerBound: number,\n\t): Promise<ResolveResult> {\n\t\tconst startTime = Date.now();\n\t\t// Track from here so inbound batches are recorded even without a prior capture/subscribe; otherwise\n\t\t// a batch sequencing during the scan (or live, in the no-reader case) is skipped and unrecoverable.\n\t\tthis.tracking = true;\n\t\t// Defaults cover the throw path (only the history scan can throw — e.g. an unpacker\n\t\t// DataCorruptionError or the 0xd1c reader-contract assert): the Resolve event still fires via\n\t\t// `finally`, with outcome \"error\".\n\t\tlet path: \"session\" | \"history\" | \"noReader\" = \"history\";\n\t\tlet outcome: ResolveResult[\"kind\"] | \"error\" = \"error\";\n\t\tlet resolvedSequenceNumber: number | undefined;\n\t\ttry {\n\t\t\t// Fast path: batch sequenced live this session.\n\t\t\tconst resolvedBatch = this.sessionResolutionFor(batchId);\n\t\t\tif (resolvedBatch === undefined) {\n\t\t\t\tconst reader = this.hooks.getHistoricalOpReader?.();\n\t\t\t\tif (reader === undefined) {\n\t\t\t\t\t// No reader: the batch may still sequence live, so report pending.\n\t\t\t\t\tpath = \"noReader\";\n\t\t\t\t\toutcome = \"pending\";\n\t\t\t\t\treturn { kind: \"pending\" };\n\t\t\t\t}\n\t\t\t\t// Otherwise scan history from the mark's reference point.\n\t\t\t\tpath = \"history\";\n\t\t\t\tlet result = await this.resolveFromHistory(reader, batchId, sequenceNumberLowerBound);\n\t\t\t\tif (result.kind !== \"resolved\") {\n\t\t\t\t\t// The batch may have sequenced live while the history scan was in progress. Prefer that\n\t\t\t\t\t// authoritative in-session result over a stale history miss.\n\t\t\t\t\tconst liveResult = this.sessionResolutionFor(batchId);\n\t\t\t\t\tif (liveResult !== undefined) {\n\t\t\t\t\t\tpath = \"session\";\n\t\t\t\t\t\tresult = { kind: \"resolved\", ...liveResult };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toutcome = result.kind;\n\t\t\t\tif (result.kind === \"resolved\") {\n\t\t\t\t\tresolvedSequenceNumber = result.sequenceNumber;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tpath = \"session\";\n\t\t\toutcome = \"resolved\";\n\t\t\tresolvedSequenceNumber = resolvedBatch.sequenceNumber;\n\t\t\treturn { kind: \"resolved\", ...resolvedBatch };\n\t\t} finally {\n\t\t\tthis.hooks.logger.sendTelemetryEvent({\n\t\t\t\teventName: \"Resolve\",\n\t\t\t\toutcome,\n\t\t\t\tpath,\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\t...(resolvedSequenceNumber === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: { sequenceNumber: resolvedSequenceNumber }),\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Scans sequenced ops from `sequenceNumberLowerBound` (inclusive) for `batchId`, returning its last op's\n\t * sequence number when found and aborting the fetch once found or exhausted. Each op is routed through\n\t * the same unpack pipeline the live inbound path uses (chunk reassembly, ungroup, decompress) and\n\t * {@link inboundVersionMarkUpdate} derives its batch identity, so virtualized batches resolve here too.\n\t * The injected historical unpacker owns virtualization details, including tolerating a requested range\n\t * that begins within an incomplete chunk stream. On a miss, {@link classifyMiss} distinguishes\n\t * `pending` (not sequenced yet) from `unresolvable` (ops trimmed).\n\t */\n\tprivate async resolveFromHistory(\n\t\treader: IHistoricalOpReader,\n\t\tbatchId: string,\n\t\tsequenceNumberLowerBound: number,\n\t): Promise<ResolveResult> {\n\t\tconst from = sequenceNumberLowerBound;\n\t\tconst unpack = this.hooks.createHistoricalOpUnpacker?.();\n\t\tconst abortController = new AbortController();\n\t\ttry {\n\t\t\tconst stream = await reader.fetchMessages(from, undefined, abortController.signal);\n\t\t\tlet firstScannedSequenceNumber: number | undefined;\n\t\t\tlet carriedBatchId: string | undefined;\n\t\t\twhile (true) {\n\t\t\t\tconst result = await stream.read();\n\t\t\t\tif (result.done) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfor (const op of result.value) {\n\t\t\t\t\tfirstScannedSequenceNumber ??= op.sequenceNumber;\n\t\t\t\t\t// undefined = a system op or virtualized input that has not produced a complete result.\n\t\t\t\t\tconst inboundResult = unpack?.(op);\n\t\t\t\t\tif (inboundResult === undefined) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// Derive batch identity exactly as the live inbound path does, carrying the id across a\n\t\t\t\t\t// piecemeal batch's messages.\n\t\t\t\t\tconst update = inboundVersionMarkUpdate(inboundResult, carriedBatchId);\n\t\t\t\t\tcarriedBatchId = update.carriedBatchId;\n\t\t\t\t\tif (update.sequenced?.batchId === batchId) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: \"resolved\",\n\t\t\t\t\t\t\tsequenceNumber: update.sequenced.sequenceNumber,\n\t\t\t\t\t\t\ttimestamp: update.sequenced.timestamp,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Not found: distinguish \"not sequenced yet\" from \"trimmed\" via the tip and where the scan landed.\n\t\t\treturn this.classifyMiss(from, firstScannedSequenceNumber);\n\t\t} finally {\n\t\t\t// Cancel any in-flight fetch once we stop reading (found or exhausted).\n\t\t\tabortController.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Classifies a history-scan miss as `pending` or `unresolvable`. See {@link resolveFromHistory}.\n\t */\n\tprivate classifyMiss(\n\t\tfrom: number,\n\t\tfirstScannedSequenceNumber: number | undefined,\n\t): ResolveResult {\n\t\t// Invariant: a reader must never return an op before the requested range start. If it does, the\n\t\t// trim inference below is meaningless, so fail loudly rather than misclassify.\n\t\tassert(\n\t\t\tfirstScannedSequenceNumber === undefined || firstScannedSequenceNumber >= from,\n\t\t\t0xd1c /* historical op reader returned an op before the requested range start */,\n\t\t);\n\t\tconst tip = this.hooks.getCurrentSequenceNumber();\n\t\tif (from > tip) {\n\t\t\t// Nothing is sequenced at/after the mark's lower bound yet, so the batch cannot have landed.\n\t\t\treturn { kind: \"pending\" };\n\t\t}\n\t\tif (firstScannedSequenceNumber === undefined) {\n\t\t\t// Empty read though ops should exist in `[from, tip]` → trimmed. ODSP-specific: a strict driver\n\t\t\t// empties a `from`-misaligned trimmed range (validateMessages); a return-from-earliest driver\n\t\t\t// would instead surface the trim via the `firstScannedSequenceNumber > from` branch below.\n\t\t\treturn { kind: \"unresolvable\" };\n\t\t}\n\t\tif (firstScannedSequenceNumber > from) {\n\t\t\t// A trim gap at the anchor: the mark's ops (at/after its lower bound) are gone.\n\t\t\treturn { kind: \"unresolvable\" };\n\t\t}\n\t\t// Ops are present from the lower bound and the batch is not among them: not yet sequenced.\n\t\treturn { kind: \"pending\" };\n\t}\n\n\tpublic onBatchSequenced(\n\t\tlistener: (batchId: string, sequenceNumber: number, timestamp?: number) => void,\n\t): () => void {\n\t\t// A subscriber wants live promotions, so start tracking inbound batches from here on.\n\t\tthis.tracking = true;\n\t\tthis.batchListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.batchListeners.delete(listener);\n\t\t};\n\t}\n\n\t/** The resolved point for a batch seen live this session, or undefined. */\n\tprivate sessionResolutionFor(\n\t\tbatchId: string,\n\t): { readonly sequenceNumber: number; readonly timestamp: number } | undefined {\n\t\treturn this.resolvedBatchById.get(batchId);\n\t}\n\n\t/** Records an inbound batch and notifies listeners so any client can promote matching pending marks. */\n\tpublic processInboundBatch(\n\t\tbatchId: string,\n\t\tsequenceNumber: number,\n\t\ttimestamp: number,\n\t): void {\n\t\tconst existingResolution = this.resolvedBatchById.get(batchId);\n\t\tif (existingResolution !== undefined) {\n\t\t\t// NOTE: It's possible (but exceedingly rare) that this is a spurious duplicated batch,\n\t\t\t// with a different sequence number/timestamp.\n\t\t\t// Rather than asserting or overwriting, we let the earlier version mark stand, it is sufficient.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.resolvedBatchById.set(batchId, { sequenceNumber, timestamp });\n\t\tthis.evictBelowMinimumSequenceNumber();\n\t\tfor (const listener of this.batchListeners) {\n\t\t\ttry {\n\t\t\t\tlistener(batchId, sequenceNumber, timestamp);\n\t\t\t} catch (error) {\n\t\t\t\t// Isolate each app listener (like the container's EventEmitterWithErrorHandling): one throw\n\t\t\t\t// must not abort op processing or starve the rest. Log and continue rather than fault the\n\t\t\t\t// container — a missed promotion is recoverable via resolve()'s history scan.\n\t\t\t\tthis.hooks.logger.sendErrorEvent({ eventName: \"VersionMarkListenerException\" }, error);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Bounds the map to the collaboration window by dropping entries below the MSN (mirrors\n\t * `DuplicateBatchDetector`). Safe because below the MSN every client has processed the batch, so its\n\t * `onBatchSequenced` already fired; a dropped entry falls back to the history scan. Entries insert in\n\t * sequence order, so iteration stops at the first retained one.\n\t */\n\tprivate evictBelowMinimumSequenceNumber(): void {\n\t\tconst minimumSequenceNumber = this.hooks.getCurrentMinimumSequenceNumber();\n\t\tfor (const [id, resolution] of this.resolvedBatchById) {\n\t\t\tif (resolution.sequenceNumber >= minimumSequenceNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.resolvedBatchById.delete(id);\n\t\t}\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Fluid container runtime",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -14,98 +14,51 @@
|
|
|
14
14
|
"type": "module",
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"require": {
|
|
22
|
-
"types": "./dist/public.d.ts",
|
|
23
|
-
"default": "./dist/index.js"
|
|
17
|
+
"types": "./lib/public.d.ts",
|
|
18
|
+
"default": "./lib/index.js",
|
|
19
|
+
"internal-entrypoint-generation": {
|
|
20
|
+
"types": "./dist/public.d.ts"
|
|
24
21
|
}
|
|
25
22
|
},
|
|
26
23
|
"./legacy": {
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"require": {
|
|
32
|
-
"types": "./dist/legacy.d.ts",
|
|
33
|
-
"default": "./dist/index.js"
|
|
24
|
+
"types": "./lib/legacy.d.ts",
|
|
25
|
+
"default": "./lib/index.js",
|
|
26
|
+
"internal-entrypoint-generation": {
|
|
27
|
+
"types": "./dist/legacy.d.ts"
|
|
34
28
|
}
|
|
35
29
|
},
|
|
36
30
|
"./legacy/alpha": {
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"require": {
|
|
42
|
-
"types": "./dist/legacyAlpha.d.ts",
|
|
43
|
-
"default": "./dist/index.js"
|
|
31
|
+
"types": "./lib/legacyAlpha.d.ts",
|
|
32
|
+
"default": "./lib/index.js",
|
|
33
|
+
"internal-entrypoint-generation": {
|
|
34
|
+
"types": "./dist/legacyAlpha.d.ts"
|
|
44
35
|
}
|
|
45
36
|
},
|
|
46
37
|
"./internal": {
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
"default": "./lib/index.js"
|
|
50
|
-
},
|
|
51
|
-
"require": {
|
|
52
|
-
"types": "./dist/index.d.ts",
|
|
53
|
-
"default": "./dist/index.js"
|
|
54
|
-
}
|
|
38
|
+
"types": "./lib/index.d.ts",
|
|
39
|
+
"default": "./lib/index.js"
|
|
55
40
|
},
|
|
56
41
|
"./internal/test/containerRuntime": {
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
"default": "./lib/containerRuntime.js"
|
|
60
|
-
},
|
|
61
|
-
"require": {
|
|
62
|
-
"types": "./dist/containerRuntime.d.ts",
|
|
63
|
-
"default": "./dist/containerRuntime.js"
|
|
64
|
-
}
|
|
42
|
+
"types": "./lib/containerRuntime.d.ts",
|
|
43
|
+
"default": "./lib/containerRuntime.js"
|
|
65
44
|
},
|
|
66
45
|
"./internal/test/deltaScheduler": {
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
"default": "./lib/deltaScheduler.js"
|
|
70
|
-
},
|
|
71
|
-
"require": {
|
|
72
|
-
"types": "./dist/deltaScheduler.d.ts",
|
|
73
|
-
"default": "./dist/deltaScheduler.js"
|
|
74
|
-
}
|
|
46
|
+
"types": "./lib/deltaScheduler.d.ts",
|
|
47
|
+
"default": "./lib/deltaScheduler.js"
|
|
75
48
|
},
|
|
76
49
|
"./internal/test/blobManager": {
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
"default": "./lib/blobManager/index.js"
|
|
80
|
-
},
|
|
81
|
-
"require": {
|
|
82
|
-
"types": "./dist/blobManager/index.d.ts",
|
|
83
|
-
"default": "./dist/blobManager/index.js"
|
|
84
|
-
}
|
|
50
|
+
"types": "./lib/blobManager/index.d.ts",
|
|
51
|
+
"default": "./lib/blobManager/index.js"
|
|
85
52
|
},
|
|
86
53
|
"./internal/test/summary": {
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
"default": "./lib/summary/index.js"
|
|
90
|
-
},
|
|
91
|
-
"require": {
|
|
92
|
-
"types": "./dist/summary/index.d.ts",
|
|
93
|
-
"default": "./dist/summary/index.js"
|
|
94
|
-
}
|
|
54
|
+
"types": "./lib/summary/index.d.ts",
|
|
55
|
+
"default": "./lib/summary/index.js"
|
|
95
56
|
},
|
|
96
57
|
"./internal/test/gc": {
|
|
97
|
-
"
|
|
98
|
-
|
|
99
|
-
"default": "./lib/gc/index.js"
|
|
100
|
-
},
|
|
101
|
-
"require": {
|
|
102
|
-
"types": "./gc/index.d.ts",
|
|
103
|
-
"default": "./gc/index.js"
|
|
104
|
-
}
|
|
58
|
+
"types": "./lib/gc/index.d.ts",
|
|
59
|
+
"default": "./lib/gc/index.js"
|
|
105
60
|
}
|
|
106
61
|
},
|
|
107
|
-
"main": "lib/index.js",
|
|
108
|
-
"types": "lib/public.d.ts",
|
|
109
62
|
"c8": {
|
|
110
63
|
"all": true,
|
|
111
64
|
"cache-dir": "nyc/.cache",
|
|
@@ -129,18 +82,18 @@
|
|
|
129
82
|
"temp-directory": "nyc/.nyc_output"
|
|
130
83
|
},
|
|
131
84
|
"dependencies": {
|
|
132
|
-
"@fluid-internal/client-utils": "~
|
|
133
|
-
"@fluidframework/container-definitions": "~
|
|
134
|
-
"@fluidframework/container-runtime-definitions": "~
|
|
135
|
-
"@fluidframework/core-interfaces": "~
|
|
136
|
-
"@fluidframework/core-utils": "~
|
|
137
|
-
"@fluidframework/datastore": "~
|
|
138
|
-
"@fluidframework/driver-definitions": "~
|
|
139
|
-
"@fluidframework/driver-utils": "~
|
|
140
|
-
"@fluidframework/id-compressor": "~
|
|
141
|
-
"@fluidframework/runtime-definitions": "~
|
|
142
|
-
"@fluidframework/runtime-utils": "~
|
|
143
|
-
"@fluidframework/telemetry-utils": "~
|
|
85
|
+
"@fluid-internal/client-utils": "~3.0.0",
|
|
86
|
+
"@fluidframework/container-definitions": "~3.0.0",
|
|
87
|
+
"@fluidframework/container-runtime-definitions": "~3.0.0",
|
|
88
|
+
"@fluidframework/core-interfaces": "~3.0.0",
|
|
89
|
+
"@fluidframework/core-utils": "~3.0.0",
|
|
90
|
+
"@fluidframework/datastore": "~3.0.0",
|
|
91
|
+
"@fluidframework/driver-definitions": "~3.0.0",
|
|
92
|
+
"@fluidframework/driver-utils": "~3.0.0",
|
|
93
|
+
"@fluidframework/id-compressor": "~3.0.0",
|
|
94
|
+
"@fluidframework/runtime-definitions": "~3.0.0",
|
|
95
|
+
"@fluidframework/runtime-utils": "~3.0.0",
|
|
96
|
+
"@fluidframework/telemetry-utils": "~3.0.0",
|
|
144
97
|
"@tylerbu/sorted-btree-es6": "^2.1.1",
|
|
145
98
|
"double-ended-queue": "^2.1.0-0",
|
|
146
99
|
"lz4js": "^0.2.0",
|
|
@@ -150,16 +103,16 @@
|
|
|
150
103
|
"devDependencies": {
|
|
151
104
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
152
105
|
"@biomejs/biome": "~2.4.5",
|
|
153
|
-
"@fluid-internal/mocha-test-setup": "~
|
|
154
|
-
"@fluid-private/stochastic-test-utils": "~
|
|
155
|
-
"@fluid-private/test-pairwise-generator": "~
|
|
106
|
+
"@fluid-internal/mocha-test-setup": "~3.0.0",
|
|
107
|
+
"@fluid-private/stochastic-test-utils": "~3.0.0",
|
|
108
|
+
"@fluid-private/test-pairwise-generator": "~3.0.0",
|
|
156
109
|
"@fluid-tools/benchmark": "^0.59.0",
|
|
157
110
|
"@fluid-tools/build-cli": "^0.67.0",
|
|
158
111
|
"@fluidframework/build-common": "^2.0.3",
|
|
159
112
|
"@fluidframework/build-tools": "^0.67.0",
|
|
160
113
|
"@fluidframework/container-runtime-previous": "npm:@fluidframework/container-runtime@2.116.0",
|
|
161
114
|
"@fluidframework/eslint-config-fluid": "^14.0.0",
|
|
162
|
-
"@fluidframework/test-runtime-utils": "~
|
|
115
|
+
"@fluidframework/test-runtime-utils": "~3.0.0",
|
|
163
116
|
"@microsoft/api-extractor": "7.58.1",
|
|
164
117
|
"@types/double-ended-queue": "^2.1.0",
|
|
165
118
|
"@types/lz4js": "^0.2.0",
|
|
@@ -177,30 +130,36 @@
|
|
|
177
130
|
"mocha-multi-reporters": "^1.5.1",
|
|
178
131
|
"rimraf": "^6.1.3",
|
|
179
132
|
"sinon": "^18.0.1",
|
|
180
|
-
"typescript": "~
|
|
133
|
+
"typescript": "~6.0.3"
|
|
181
134
|
},
|
|
182
135
|
"typeValidation": {
|
|
183
|
-
"broken": {
|
|
136
|
+
"broken": {
|
|
137
|
+
"Interface_LoadContainerRuntimeParams": {
|
|
138
|
+
"backCompat": false,
|
|
139
|
+
"forwardCompat": false
|
|
140
|
+
}
|
|
141
|
+
},
|
|
184
142
|
"entrypoint": "legacy"
|
|
185
143
|
},
|
|
186
144
|
"scripts": {
|
|
187
145
|
"bench": "cross-env FLUID_TEST_PERF_MODE=1 mocha --parentProcess",
|
|
188
146
|
"build": "fluid-build . --task build",
|
|
189
147
|
"build:api-reports": "concurrently \"npm:build:api-reports:*\"",
|
|
190
|
-
"build:api-reports:current": "api-extractor run --local --config api-extractor/api-extractor.current.json",
|
|
191
|
-
"build:api-reports:legacy": "api-extractor run --local --config api-extractor/api-extractor.legacy.json",
|
|
148
|
+
"build:api-reports:current": "api-extractor run --local --config api-extractor/api-extractor-report.current.json",
|
|
149
|
+
"build:api-reports:legacy": "api-extractor run --local --config api-extractor/api-extractor-report.legacy.json",
|
|
150
|
+
"build:cjs": "fluid-tsc commonjs --project ./tsconfig.cjs.json && npm run place:cjs:package-stub",
|
|
192
151
|
"build:commonjs": "fluid-build . --task commonjs",
|
|
193
152
|
"build:compile": "fluid-build . --task compile",
|
|
194
|
-
"build:docs": "api-extractor run --local",
|
|
153
|
+
"build:docs": "api-extractor run --local --config api-extractor/api-extractor-model.json",
|
|
195
154
|
"build:entrypoints": "fluid-build . --task build:entrypoints",
|
|
196
155
|
"build:entrypoints:cjs": "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./dist",
|
|
197
|
-
"build:entrypoints:esm": "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib
|
|
198
|
-
"build:
|
|
156
|
+
"build:entrypoints:esm": "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib",
|
|
157
|
+
"build:esm": "tsc --project ./tsconfig.json",
|
|
199
158
|
"build:genver": "gen-version",
|
|
200
159
|
"build:test": "concurrently npm:build:test:esm npm:build:test:cjs",
|
|
201
160
|
"build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
|
|
202
161
|
"build:test:esm": "tsc --project ./src/test/tsconfig.json",
|
|
203
|
-
"check:are-the-types-wrong": "attw --pack . --
|
|
162
|
+
"check:are-the-types-wrong": "attw --pack . --profile esm-only",
|
|
204
163
|
"check:biome": "biome check .",
|
|
205
164
|
"check:exports": "concurrently \"npm:check:exports:*\"",
|
|
206
165
|
"check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
|
|
@@ -212,9 +171,9 @@
|
|
|
212
171
|
"check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
|
|
213
172
|
"check:format": "npm run check:biome",
|
|
214
173
|
"ci:build:api-reports": "concurrently \"npm:ci:build:api-reports:*\"",
|
|
215
|
-
"ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor.current.json",
|
|
216
|
-
"ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
|
|
217
|
-
"ci:build:docs": "api-extractor run",
|
|
174
|
+
"ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor-report.current.json",
|
|
175
|
+
"ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor-report.legacy.json",
|
|
176
|
+
"ci:build:docs": "api-extractor run --config api-extractor/api-extractor-model.json",
|
|
218
177
|
"clean": "rimraf --glob dist lib {alpha,beta,internal,legacy}.d.ts legacyAlpha.d.ts \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
|
|
219
178
|
"depcruise": "depcruise src/",
|
|
220
179
|
"eslint": "eslint --quiet --format stylish src",
|
|
@@ -231,8 +190,7 @@
|
|
|
231
190
|
"test:mocha:cjs": "cross-env FLUID_TEST_MODULE_SYSTEM=CJS mocha",
|
|
232
191
|
"test:mocha:esm": "mocha",
|
|
233
192
|
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"typetests:gen": "flub generate typetests --dir . -v"
|
|
193
|
+
"typetests:gen": "flub generate typetests --dir . -v",
|
|
194
|
+
"watch:cjs": "npm run place:cjs:package-stub && fluid-tsc commonjs --project ./tsconfig.cjs.json --watch"
|
|
237
195
|
}
|
|
238
196
|
}
|
|
@@ -98,27 +98,28 @@ export type RuntimeOptionKeysThatRequireExplicitSchemaControl = keyof Omit<
|
|
|
98
98
|
* the format changes introduced by the property, then the default value for that OldestSupportedClientVersion will enable the feature associated with the property.
|
|
99
99
|
* Otherwise, the feature will be disabled.
|
|
100
100
|
*
|
|
101
|
-
* For example
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* with the batching feature.
|
|
101
|
+
* For example, the default value for `enableGroupedBatching` is true at the supported
|
|
102
|
+
* floor of 2.0.0 because clients running 2.0.0 or later understand the associated
|
|
103
|
+
* document format.
|
|
105
104
|
*/
|
|
106
105
|
const runtimeOptionsAffectingDocSchemaConfigMap: ConfigMap<RuntimeOptionsAffectingDocSchema> =
|
|
107
106
|
{
|
|
108
107
|
enableGroupedBatching: {
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
// Grouped batching was already enabled by default before callers explicitly selected
|
|
109
|
+
// a compatibility version. All supported 2.x clients understand this format.
|
|
110
|
+
"2.0.0": true,
|
|
111
111
|
},
|
|
112
112
|
compressionOptions: {
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
// Compression was already enabled by default before callers explicitly selected a
|
|
114
|
+
// compatibility version. All supported 2.x clients understand this format.
|
|
115
|
+
"2.0.0": enabledCompressionConfig,
|
|
115
116
|
},
|
|
116
117
|
enableRuntimeIdCompressor: {
|
|
117
118
|
// For IdCompressorMode, `undefined` represents a logical state (off).
|
|
118
119
|
// However, to satisfy the Required<> constraint while
|
|
119
120
|
// `exactOptionalPropertyTypes` is `false` (TODO: AB#8215), we need
|
|
120
121
|
// to have it defined, so we trick the type checker here.
|
|
121
|
-
"
|
|
122
|
+
"2.0.0": undefined,
|
|
122
123
|
// We do not yet want to enable idCompressor by default since it will
|
|
123
124
|
// increase bundle sizes, and not all customers will benefit from it.
|
|
124
125
|
// Therefore, we will require customers to explicitly enable it. We
|
|
@@ -126,28 +127,18 @@ const runtimeOptionsAffectingDocSchemaConfigMap: ConfigMap<RuntimeOptionsAffecti
|
|
|
126
127
|
// change in the future.
|
|
127
128
|
},
|
|
128
129
|
explicitSchemaControl: {
|
|
129
|
-
"1.0.0": false,
|
|
130
130
|
// This option's intention is to prevent 1.x clients from joining sessions
|
|
131
|
-
// when enabled.
|
|
132
|
-
//
|
|
133
|
-
// because it was not enabled by default prior to the implementation of
|
|
134
|
-
// `minVersionForCollab`.
|
|
135
|
-
// `defaultMinVersionForCollab` is set to "2.0.0-defaults" which "2.0.0"
|
|
136
|
-
// does not satisfy to avoiding enabling this option by default as of
|
|
137
|
-
// `minVersionForCollab` introduction, which could be unexpected.
|
|
138
|
-
// Only enable as a default when `minVersionForCollab` is specified at
|
|
139
|
-
// 2.0.0+.
|
|
131
|
+
// when enabled. Before Client 3.0, this became true only when callers explicitly
|
|
132
|
+
// selected 2.0.0 or later. Client 3.0 also uses 2.0.0 when the setting is omitted.
|
|
140
133
|
"2.0.0": true,
|
|
141
134
|
},
|
|
142
135
|
flushMode: {
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
"1.0.0": FlushMode.Immediate,
|
|
147
|
-
"2.0.0-defaults": FlushMode.TurnBased,
|
|
136
|
+
// TurnBased flushing was already the default before callers explicitly selected a
|
|
137
|
+
// compatibility version.
|
|
138
|
+
"2.0.0": FlushMode.TurnBased,
|
|
148
139
|
},
|
|
149
140
|
gcOptions: {
|
|
150
|
-
"
|
|
141
|
+
"2.0.0": {},
|
|
151
142
|
// Although sweep is supported in 2.x, it is disabled by default until minVersionForCollab>=3.0.0 to be extra safe.
|
|
152
143
|
// Note that enabling this is a significant change, that should likely be announced in the relevant version:
|
|
153
144
|
// It would be bad if this simple caused the enablement when when the current package version passed this point without anyone being aware.
|
|
@@ -160,7 +151,7 @@ const runtimeOptionsAffectingDocSchemaConfigMap: ConfigMap<RuntimeOptionsAffecti
|
|
|
160
151
|
// This feature is new and disabled by default. In the future we will enable it by default, but we have not
|
|
161
152
|
// closed on the version where that will happen yet. Probably a .10 release since blob functionality is not
|
|
162
153
|
// exposed on the `@public` API surface.
|
|
163
|
-
"
|
|
154
|
+
"2.0.0": undefined,
|
|
164
155
|
},
|
|
165
156
|
};
|
|
166
157
|
|
|
@@ -181,32 +172,32 @@ export const runtimeOptionKeysThatRequireExplicitSchemaControl = (
|
|
|
181
172
|
const runtimeOptionsAffectingDocSchemaConfigValidationMap: ConfigValidationMap<RuntimeOptionsAffectingDocSchema> =
|
|
182
173
|
{
|
|
183
174
|
enableGroupedBatching: configValueToMinVersionForCollab([
|
|
184
|
-
[false, "
|
|
185
|
-
[true, "2.0.0
|
|
175
|
+
[false, "2.0.0"],
|
|
176
|
+
[true, "2.0.0"],
|
|
186
177
|
]),
|
|
187
178
|
compressionOptions: configValueToMinVersionForCollab([
|
|
188
|
-
[{ ...disabledCompressionConfig }, "
|
|
189
|
-
[{ ...enabledCompressionConfig }, "2.0.0
|
|
179
|
+
[{ ...disabledCompressionConfig }, "2.0.0"],
|
|
180
|
+
[{ ...enabledCompressionConfig }, "2.0.0"],
|
|
190
181
|
]),
|
|
191
182
|
enableRuntimeIdCompressor: configValueToMinVersionForCollab([
|
|
192
|
-
[undefined, "
|
|
193
|
-
["on", "2.0.0
|
|
194
|
-
["delayed", "2.0.0
|
|
183
|
+
[undefined, "2.0.0"],
|
|
184
|
+
["on", "2.0.0"],
|
|
185
|
+
["delayed", "2.0.0"],
|
|
195
186
|
]),
|
|
196
187
|
explicitSchemaControl: configValueToMinVersionForCollab([
|
|
197
|
-
[false, "
|
|
198
|
-
[true, "2.0.0
|
|
188
|
+
[false, "2.0.0"],
|
|
189
|
+
[true, "2.0.0"],
|
|
199
190
|
]),
|
|
200
191
|
flushMode: configValueToMinVersionForCollab([
|
|
201
|
-
[FlushMode.Immediate, "
|
|
202
|
-
[FlushMode.TurnBased, "2.0.0
|
|
192
|
+
[FlushMode.Immediate, "2.0.0"],
|
|
193
|
+
[FlushMode.TurnBased, "2.0.0"],
|
|
203
194
|
]),
|
|
204
195
|
gcOptions: configValueToMinVersionForCollab([
|
|
205
|
-
[{ enableGCSweep: undefined }, "
|
|
206
|
-
[{ enableGCSweep: true }, "2.0.0
|
|
196
|
+
[{ enableGCSweep: undefined }, "2.0.0"],
|
|
197
|
+
[{ enableGCSweep: true }, "2.0.0"],
|
|
207
198
|
]),
|
|
208
199
|
createBlobPayloadPending: configValueToMinVersionForCollab([
|
|
209
|
-
[undefined, "
|
|
200
|
+
[undefined, "2.0.0"],
|
|
210
201
|
[true, "2.40.0"],
|
|
211
202
|
]),
|
|
212
203
|
};
|
|
@@ -225,8 +216,8 @@ export function getMinVersionForCollabDefaults(
|
|
|
225
216
|
|
|
226
217
|
/**
|
|
227
218
|
* Validates if the runtime options passed in from the user are compatible with the minVersionForCollab.
|
|
228
|
-
* For example, if a user
|
|
229
|
-
* is set to "
|
|
219
|
+
* For example, if a user enables an option introduced in 2.40.0 while the
|
|
220
|
+
* minVersionForCollab is set to "2.0.0", then we should throw a UsageError.
|
|
230
221
|
* */
|
|
231
222
|
export function validateRuntimeOptions(
|
|
232
223
|
minVersionForCollab: OldestSupportedClientVersion,
|
package/src/containerRuntime.ts
CHANGED
|
@@ -253,6 +253,7 @@ import {
|
|
|
253
253
|
OpSplitter,
|
|
254
254
|
Outbox,
|
|
255
255
|
RemoteMessageProcessor,
|
|
256
|
+
tryGetDeserializedRuntimeOpCopy,
|
|
256
257
|
type OutboundBatch,
|
|
257
258
|
type BatchResubmitInfo,
|
|
258
259
|
} from "./opLifecycle/index.js";
|
|
@@ -818,10 +819,10 @@ export interface LoadContainerRuntimeParams {
|
|
|
818
819
|
*
|
|
819
820
|
* @privateRemarks
|
|
820
821
|
* Used to determine the default configuration for {@link IContainerRuntimeOptionsInternal} that affect the document schema.
|
|
821
|
-
* For example, let's say that feature `foo` was added in 2.
|
|
822
|
-
* was added to `IContainerRuntimeOptionsInternal` in 2.
|
|
823
|
-
* understand the new op type. If a customer were to set oldestSupportedClient to 2.
|
|
824
|
-
* enable `foo` by default. If a customer were to set oldestSupportedClient to
|
|
822
|
+
* For example, let's say that feature `foo` was added in 2.40 which introduces a new op type. Additionally, option `bar`
|
|
823
|
+
* was added to `IContainerRuntimeOptionsInternal` in 2.40 to enable/disable `foo` since clients prior to 2.40 would not
|
|
824
|
+
* understand the new op type. If a customer were to set oldestSupportedClient to 2.40.0, then `bar` would be set to
|
|
825
|
+
* enable `foo` by default. If a customer were to set oldestSupportedClient to 2.0.0, then `bar` would be set to
|
|
825
826
|
* disable `foo` by default.
|
|
826
827
|
*/
|
|
827
828
|
oldestSupportedClient?: OldestSupportedClientVersion;
|
|
@@ -1033,8 +1034,8 @@ export class ContainerRuntime
|
|
|
1033
1034
|
|
|
1034
1035
|
// Some options require a minimum version of the FF runtime to operate, so the default configs will be generated
|
|
1035
1036
|
// based on the minVersionForCollab.
|
|
1036
|
-
// For example, if minVersionForCollab is set to "
|
|
1037
|
-
//
|
|
1037
|
+
// For example, if minVersionForCollab is set to "2.0.0", the default configs will ensure compatibility with FF runtime
|
|
1038
|
+
// 2.0.0 or later. If the minVersionForCollab is set to "2.10.0", the default values will be generated to ensure compatibility
|
|
1038
1039
|
// with FF runtime 2.10.0 or later.
|
|
1039
1040
|
if (!isValidMinVersionForCollab(minVersionForCollab)) {
|
|
1040
1041
|
throw new UsageError(
|
|
@@ -1942,6 +1943,7 @@ export class ContainerRuntime
|
|
|
1942
1943
|
const fetchOps = (context as IContainerContextInternal).fetchOps;
|
|
1943
1944
|
this.versionMarkResolverInternal = new VersionMarkResolver({
|
|
1944
1945
|
getCurrentSequenceNumber: () => this.deltaManager.lastSequenceNumber,
|
|
1946
|
+
getCurrentTimestamp: () => this.getCurrentReferenceTimestampMs(),
|
|
1945
1947
|
getCurrentMinimumSequenceNumber: () => this.deltaManager.minimumSequenceNumber,
|
|
1946
1948
|
getCurrentPendingBatchId: () => this.pendingStateManager.getMostRecentPendingBatchId(),
|
|
1947
1949
|
logger: createChildLogger({
|
|
@@ -1951,7 +1953,8 @@ export class ContainerRuntime
|
|
|
1951
1953
|
// Seal the current outbound batch so a just-submitted edit gets a stable batchId in the pending
|
|
1952
1954
|
// state before sealAndCaptureVersionMark reads it (a batchId is only assigned when flushed).
|
|
1953
1955
|
flushPendingBatch: () => this.flush(),
|
|
1954
|
-
//
|
|
1956
|
+
// Keep this optional while a supported older loader may not provide fetchOps. AB#81034 tracks
|
|
1957
|
+
// making it required once the Runtime -> Loader compatibility window reaches generation 21.
|
|
1955
1958
|
getHistoricalOpReader: fetchOps ? () => ({ fetchMessages: fetchOps }) : undefined,
|
|
1956
1959
|
// Unpack scanned historical ops through the same pipeline the live inbound path uses, so a
|
|
1957
1960
|
// chunked batch's batchId (only restored after reassembly) is observed by the history scan too.
|
|
@@ -1966,6 +1969,7 @@ export class ContainerRuntime
|
|
|
1966
1969
|
runtimeOptions.chunkSizeInBytes,
|
|
1967
1970
|
runtimeOptions.maxBatchSizeInBytes,
|
|
1968
1971
|
this.mc.logger,
|
|
1972
|
+
{ allowInitialPartialChunkStream: true },
|
|
1969
1973
|
),
|
|
1970
1974
|
new OpDecompressor(this.mc.logger),
|
|
1971
1975
|
new OpGroupingManager(
|
|
@@ -1974,13 +1978,11 @@ export class ContainerRuntime
|
|
|
1974
1978
|
),
|
|
1975
1979
|
);
|
|
1976
1980
|
return (op) => {
|
|
1977
|
-
//
|
|
1978
|
-
|
|
1979
|
-
if (
|
|
1981
|
+
// Only runtime ops carry batches; deserialize a copy so the reader-owned op stays untouched.
|
|
1982
|
+
const messageCopy = tryGetDeserializedRuntimeOpCopy(op);
|
|
1983
|
+
if (messageCopy === undefined) {
|
|
1980
1984
|
return undefined;
|
|
1981
1985
|
}
|
|
1982
|
-
const messageCopy = { ...op };
|
|
1983
|
-
ensureContentsDeserialized(messageCopy);
|
|
1984
1986
|
return scanProcessor.process(
|
|
1985
1987
|
messageCopy,
|
|
1986
1988
|
getSingleUseLegacyLogCallback(this.mc.logger, messageCopy.type),
|
|
@@ -3422,6 +3424,7 @@ export class ContainerRuntime
|
|
|
3422
3424
|
this.versionMarkResolverInternal.processInboundBatch(
|
|
3423
3425
|
versionMarkUpdate.sequenced.batchId,
|
|
3424
3426
|
versionMarkUpdate.sequenced.sequenceNumber,
|
|
3427
|
+
versionMarkUpdate.sequenced.timestamp,
|
|
3425
3428
|
);
|
|
3426
3429
|
}
|
|
3427
3430
|
this.versionMarkInboundBatchId = versionMarkUpdate.carriedBatchId;
|
package/src/opLifecycle/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export { DuplicateBatchDetector } from "./duplicateBatchDetector.js";
|
|
|
26
26
|
export {
|
|
27
27
|
serializeOp,
|
|
28
28
|
ensureContentsDeserialized,
|
|
29
|
+
tryGetDeserializedRuntimeOpCopy,
|
|
29
30
|
} from "./opSerialization.js";
|
|
30
31
|
export {
|
|
31
32
|
type BatchResubmitInfo,
|
|
@@ -36,7 +37,12 @@ export {
|
|
|
36
37
|
} from "./outbox.js";
|
|
37
38
|
export { OpCompressor } from "./opCompressor.js";
|
|
38
39
|
export { OpDecompressor } from "./opDecompressor.js";
|
|
39
|
-
export {
|
|
40
|
+
export {
|
|
41
|
+
type OpSplitterOptions,
|
|
42
|
+
OpSplitter,
|
|
43
|
+
splitOp,
|
|
44
|
+
isChunkedMessage,
|
|
45
|
+
} from "./opSplitter.js";
|
|
40
46
|
export {
|
|
41
47
|
type InboundMessageResult,
|
|
42
48
|
type BatchStartInfo,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { Uint8ArrayToString } from "@fluid-internal/client-utils";
|
|
7
7
|
import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
8
8
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
9
9
|
import {
|
|
@@ -46,7 +46,7 @@ export class OpCompressor {
|
|
|
46
46
|
const compressionStart = Date.now();
|
|
47
47
|
const contentsAsBuffer = new TextEncoder().encode(this.serializeBatchContents(batch));
|
|
48
48
|
const compressedContents = compress(contentsAsBuffer);
|
|
49
|
-
const compressedContent =
|
|
49
|
+
const compressedContent = Uint8ArrayToString(compressedContents, "base64");
|
|
50
50
|
const duration = Date.now() - compressionStart;
|
|
51
51
|
|
|
52
52
|
const messages: [OutboundBatchMessage] = [
|