@fluidframework/odsp-driver 2.112.0 → 2.113.1
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 +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +37 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js +70 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts +49 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts.map +1 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js +108 -0
- package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +37 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js +66 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts +49 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts.map +1 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js +104 -0
- package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js.map +1 -0
- package/package.json +11 -11
- package/src/index.ts +2 -0
- package/src/odspVersionManager/DEV.md +101 -29
- package/src/packageVersion.ts +1 -1
- package/src/pointInTimeDriver/odspPointInTimeDocumentService.ts +94 -0
- package/src/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.ts +185 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
7
|
+
import type {
|
|
8
|
+
IDocumentService,
|
|
9
|
+
IPersistedCache,
|
|
10
|
+
IResolvedUrl,
|
|
11
|
+
} from "@fluidframework/driver-definitions/internal";
|
|
12
|
+
import type {
|
|
13
|
+
HostStoragePolicy,
|
|
14
|
+
IOdspUrlParts,
|
|
15
|
+
OdspResourceTokenFetchOptions,
|
|
16
|
+
TokenFetcher,
|
|
17
|
+
} from "@fluidframework/odsp-driver-definitions/internal";
|
|
18
|
+
import { UsageError, createChildLogger } from "@fluidframework/telemetry-utils/internal";
|
|
19
|
+
|
|
20
|
+
import { createOdspCacheAndTracker } from "../epochTracker.js";
|
|
21
|
+
import { NonPersistentCache } from "../odspCache.js";
|
|
22
|
+
import { OdspDocumentServiceFactoryCore } from "../odspDocumentServiceFactoryCore.js";
|
|
23
|
+
import { OdspDriverUrlResolver } from "../odspDriverUrlResolver.js";
|
|
24
|
+
import {
|
|
25
|
+
createOdspLogger,
|
|
26
|
+
getOdspResolvedUrl,
|
|
27
|
+
toInstrumentedOdspStorageTokenFetcher,
|
|
28
|
+
} from "../odspUtils.js";
|
|
29
|
+
import {
|
|
30
|
+
createOdspVersionManager,
|
|
31
|
+
type IOdspVersionManager,
|
|
32
|
+
} from "../odspVersionManager/index.js";
|
|
33
|
+
|
|
34
|
+
import { OdspPointInTimeDocumentService } from "./odspPointInTimeDocumentService.js";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* ODSP document service factory that additionally supports point-in-time (sequence-number-based)
|
|
38
|
+
* loading.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* This extends {@link OdspDocumentServiceFactoryCore} with the ability to materialize a read-only
|
|
42
|
+
* document service at a requested Fluid sequence number. The loader detects this capability via the
|
|
43
|
+
* presence of {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService}, so
|
|
44
|
+
* hosts that want to load a container to a target sequence number must construct this factory
|
|
45
|
+
* (rather than the legacy `OdspDocumentServiceFactory`) and pass it to the loader.
|
|
46
|
+
*
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
export class OdspPointInTimeDocumentServiceFactory extends OdspDocumentServiceFactoryCore {
|
|
50
|
+
/**
|
|
51
|
+
* The storage token fetcher, captured here because the base class keeps it private.
|
|
52
|
+
*/
|
|
53
|
+
private readonly getStorageTokenForVersions: TokenFetcher<OdspResourceTokenFetchOptions>;
|
|
54
|
+
|
|
55
|
+
constructor(
|
|
56
|
+
getStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>,
|
|
57
|
+
getWebsocketToken: TokenFetcher<OdspResourceTokenFetchOptions> | undefined,
|
|
58
|
+
persistedCache?: IPersistedCache,
|
|
59
|
+
hostPolicy?: HostStoragePolicy,
|
|
60
|
+
) {
|
|
61
|
+
super(getStorageToken, getWebsocketToken, persistedCache, hostPolicy);
|
|
62
|
+
this.getStorageTokenForVersions = getStorageToken;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Creates a document service that reads its snapshot from the closest file version at or before
|
|
67
|
+
* the target and its deltas from the live document, materializing a requested sequence number
|
|
68
|
+
* through replay.
|
|
69
|
+
*/
|
|
70
|
+
public async createPointInTimeDocumentService(
|
|
71
|
+
resolvedUrl: IResolvedUrl,
|
|
72
|
+
targetSequenceNumber: number,
|
|
73
|
+
logger?: ITelemetryBaseLogger,
|
|
74
|
+
clientIsSummarizer?: boolean,
|
|
75
|
+
): Promise<IDocumentService> {
|
|
76
|
+
const versionManager = await this.createVersionManager(
|
|
77
|
+
resolvedUrl,
|
|
78
|
+
logger,
|
|
79
|
+
clientIsSummarizer,
|
|
80
|
+
);
|
|
81
|
+
const baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);
|
|
82
|
+
if (baseResult.kind === "noBaseVersion") {
|
|
83
|
+
const oldestResolvedSequenceDetail =
|
|
84
|
+
baseResult.oldestResolvedSeq === undefined
|
|
85
|
+
? ""
|
|
86
|
+
: ` The oldest resolved file version is at sequence number ${baseResult.oldestResolvedSeq}.`;
|
|
87
|
+
throw new UsageError(
|
|
88
|
+
`No ODSP file version is available at or before sequence number ${targetSequenceNumber}.${oldestResolvedSequenceDetail}`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const recoverableResolvedUrl = await this.resolveFileVersion(
|
|
93
|
+
resolvedUrl,
|
|
94
|
+
baseResult.base.versionId,
|
|
95
|
+
);
|
|
96
|
+
const recoverableDocumentService = await this.createDocumentService(
|
|
97
|
+
recoverableResolvedUrl,
|
|
98
|
+
logger,
|
|
99
|
+
clientIsSummarizer,
|
|
100
|
+
);
|
|
101
|
+
const liveDocumentService = await this.createDocumentService(
|
|
102
|
+
resolvedUrl,
|
|
103
|
+
logger,
|
|
104
|
+
clientIsSummarizer,
|
|
105
|
+
);
|
|
106
|
+
return new OdspPointInTimeDocumentService(
|
|
107
|
+
recoverableResolvedUrl,
|
|
108
|
+
recoverableDocumentService,
|
|
109
|
+
liveDocumentService,
|
|
110
|
+
targetSequenceNumber,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Builds an IOdspVersionManager for the given file, which enumerates the file's stored
|
|
116
|
+
* versions and resolves the closest version at or before a target sequence number.
|
|
117
|
+
*
|
|
118
|
+
* @remarks
|
|
119
|
+
* This wires up the plumbing the version manager needs to talk to ODSP: it resolves the URL to
|
|
120
|
+
* its ODSP parts (site/drive/item), creates a scoped child logger, an epoch tracker (from a fresh
|
|
121
|
+
* NonPersistentCache, since only the tracker is needed for consistency checks), and an
|
|
122
|
+
* instrumented storage-token/auth-header fetcher. The resulting manager is used by
|
|
123
|
+
* {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService} to pick the base
|
|
124
|
+
* snapshot for point-in-time loading.
|
|
125
|
+
*/
|
|
126
|
+
private async createVersionManager(
|
|
127
|
+
resolvedUrl: IResolvedUrl,
|
|
128
|
+
logger?: ITelemetryBaseLogger,
|
|
129
|
+
clientIsSummarizer?: boolean,
|
|
130
|
+
): Promise<IOdspVersionManager> {
|
|
131
|
+
const odspLogger = createOdspLogger(logger);
|
|
132
|
+
const extLogger = createChildLogger({ logger: odspLogger });
|
|
133
|
+
const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
|
|
134
|
+
const urlParts: IOdspUrlParts = {
|
|
135
|
+
siteUrl: odspResolvedUrl.siteUrl,
|
|
136
|
+
driveId: odspResolvedUrl.driveId,
|
|
137
|
+
itemId: odspResolvedUrl.itemId,
|
|
138
|
+
};
|
|
139
|
+
// Only the epochTracker from the returned cacheAndTracker is used below, so a fresh
|
|
140
|
+
// NonPersistentCache is sufficient here.
|
|
141
|
+
const cacheAndTracker = createOdspCacheAndTracker(
|
|
142
|
+
this.persistedCache,
|
|
143
|
+
new NonPersistentCache(),
|
|
144
|
+
{
|
|
145
|
+
resolvedUrl: odspResolvedUrl,
|
|
146
|
+
docId: odspResolvedUrl.hashedDocumentId,
|
|
147
|
+
fileVersion: odspResolvedUrl.fileVersion,
|
|
148
|
+
},
|
|
149
|
+
extLogger,
|
|
150
|
+
clientIsSummarizer,
|
|
151
|
+
);
|
|
152
|
+
const getAuthHeader = toInstrumentedOdspStorageTokenFetcher(
|
|
153
|
+
extLogger,
|
|
154
|
+
urlParts,
|
|
155
|
+
this.getStorageTokenForVersions,
|
|
156
|
+
);
|
|
157
|
+
return createOdspVersionManager({
|
|
158
|
+
urlParts,
|
|
159
|
+
getAuthHeader,
|
|
160
|
+
epochTracker: cacheAndTracker.epochTracker,
|
|
161
|
+
logger: extLogger,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private async resolveFileVersion(
|
|
166
|
+
resolvedUrl: IResolvedUrl,
|
|
167
|
+
fileVersion: string,
|
|
168
|
+
): Promise<IResolvedUrl> {
|
|
169
|
+
const odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);
|
|
170
|
+
const query = new URLSearchParams({
|
|
171
|
+
driveId: odspResolvedUrl.driveId,
|
|
172
|
+
itemId: odspResolvedUrl.itemId,
|
|
173
|
+
fileVersion,
|
|
174
|
+
});
|
|
175
|
+
if (odspResolvedUrl.dataStorePath !== undefined) {
|
|
176
|
+
query.set("path", odspResolvedUrl.dataStorePath);
|
|
177
|
+
}
|
|
178
|
+
if (odspResolvedUrl.codeHint?.containerPackageName !== undefined) {
|
|
179
|
+
query.set("containerPackageName", odspResolvedUrl.codeHint.containerPackageName);
|
|
180
|
+
}
|
|
181
|
+
return new OdspDriverUrlResolver().resolve({
|
|
182
|
+
url: `${odspResolvedUrl.siteUrl}?${query.toString()}`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|