@fluidframework/odsp-driver 2.111.0 → 2.113.0-411909
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/odspVersionManager/index.d.ts +6 -0
- package/dist/odspVersionManager/index.d.ts.map +1 -0
- package/dist/odspVersionManager/index.js +10 -0
- package/dist/odspVersionManager/index.js.map +1 -0
- package/dist/odspVersionManager/odspFileVersionFetcher.d.ts +22 -0
- package/dist/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -0
- package/dist/odspVersionManager/odspFileVersionFetcher.js +81 -0
- package/dist/odspVersionManager/odspFileVersionFetcher.js.map +1 -0
- package/dist/odspVersionManager/odspVersionManager.d.ts +98 -0
- package/dist/odspVersionManager/odspVersionManager.d.ts.map +1 -0
- package/dist/odspVersionManager/odspVersionManager.js +87 -0
- package/dist/odspVersionManager/odspVersionManager.js.map +1 -0
- 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/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/odspVersionManager/index.d.ts +6 -0
- package/lib/odspVersionManager/index.d.ts.map +1 -0
- package/lib/odspVersionManager/index.js +6 -0
- package/lib/odspVersionManager/index.js.map +1 -0
- package/lib/odspVersionManager/odspFileVersionFetcher.d.ts +22 -0
- package/lib/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -0
- package/lib/odspVersionManager/odspFileVersionFetcher.js +77 -0
- package/lib/odspVersionManager/odspFileVersionFetcher.js.map +1 -0
- package/lib/odspVersionManager/odspVersionManager.d.ts +98 -0
- package/lib/odspVersionManager/odspVersionManager.d.ts.map +1 -0
- package/lib/odspVersionManager/odspVersionManager.js +82 -0
- package/lib/odspVersionManager/odspVersionManager.js.map +1 -0
- 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/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 +12 -12
- package/src/index.ts +2 -0
- package/src/odspVersionManager/DEV.md +349 -0
- package/src/odspVersionManager/index.ts +12 -0
- package/src/odspVersionManager/odspFileVersionFetcher.ts +138 -0
- package/src/odspVersionManager/odspVersionManager.ts +170 -0
- package/src/packageVersion.ts +1 -1
- package/src/pointInTimeDriver/odspPointInTimeDocumentService.ts +94 -0
- package/src/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.ts +185 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
|
|
6
|
+
import type { IDocumentService, IPersistedCache, IResolvedUrl } from "@fluidframework/driver-definitions/internal";
|
|
7
|
+
import type { HostStoragePolicy, OdspResourceTokenFetchOptions, TokenFetcher } from "@fluidframework/odsp-driver-definitions/internal";
|
|
8
|
+
import { OdspDocumentServiceFactoryCore } from "../odspDocumentServiceFactoryCore.js";
|
|
9
|
+
/**
|
|
10
|
+
* ODSP document service factory that additionally supports point-in-time (sequence-number-based)
|
|
11
|
+
* loading.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* This extends {@link OdspDocumentServiceFactoryCore} with the ability to materialize a read-only
|
|
15
|
+
* document service at a requested Fluid sequence number. The loader detects this capability via the
|
|
16
|
+
* presence of {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService}, so
|
|
17
|
+
* hosts that want to load a container to a target sequence number must construct this factory
|
|
18
|
+
* (rather than the legacy `OdspDocumentServiceFactory`) and pass it to the loader.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare class OdspPointInTimeDocumentServiceFactory extends OdspDocumentServiceFactoryCore {
|
|
23
|
+
/**
|
|
24
|
+
* The storage token fetcher, captured here because the base class keeps it private.
|
|
25
|
+
*/
|
|
26
|
+
private readonly getStorageTokenForVersions;
|
|
27
|
+
constructor(getStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>, getWebsocketToken: TokenFetcher<OdspResourceTokenFetchOptions> | undefined, persistedCache?: IPersistedCache, hostPolicy?: HostStoragePolicy);
|
|
28
|
+
/**
|
|
29
|
+
* Creates a document service that reads its snapshot from the closest file version at or before
|
|
30
|
+
* the target and its deltas from the live document, materializing a requested sequence number
|
|
31
|
+
* through replay.
|
|
32
|
+
*/
|
|
33
|
+
createPointInTimeDocumentService(resolvedUrl: IResolvedUrl, targetSequenceNumber: number, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
|
|
34
|
+
/**
|
|
35
|
+
* Builds an IOdspVersionManager for the given file, which enumerates the file's stored
|
|
36
|
+
* versions and resolves the closest version at or before a target sequence number.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* This wires up the plumbing the version manager needs to talk to ODSP: it resolves the URL to
|
|
40
|
+
* its ODSP parts (site/drive/item), creates a scoped child logger, an epoch tracker (from a fresh
|
|
41
|
+
* NonPersistentCache, since only the tracker is needed for consistency checks), and an
|
|
42
|
+
* instrumented storage-token/auth-header fetcher. The resulting manager is used by
|
|
43
|
+
* {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService} to pick the base
|
|
44
|
+
* snapshot for point-in-time loading.
|
|
45
|
+
*/
|
|
46
|
+
private createVersionManager;
|
|
47
|
+
private resolveFileVersion;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=odspPointInTimeDocumentServiceFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspPointInTimeDocumentServiceFactory.d.ts","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EACX,iBAAiB,EAEjB,6BAA6B,EAC7B,YAAY,EACZ,MAAM,kDAAkD,CAAC;AAK1D,OAAO,EAAE,8BAA8B,EAAE,MAAM,sCAAsC,CAAC;AActF;;;;;;;;;;;;GAYG;AACH,qBAAa,qCAAsC,SAAQ,8BAA8B;IACxF;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAA8C;gBAGxF,eAAe,EAAE,YAAY,CAAC,6BAA6B,CAAC,EAC5D,iBAAiB,EAAE,YAAY,CAAC,6BAA6B,CAAC,GAAG,SAAS,EAC1E,cAAc,CAAC,EAAE,eAAe,EAChC,UAAU,CAAC,EAAE,iBAAiB;IAM/B;;;;OAIG;IACU,gCAAgC,CAC5C,WAAW,EAAE,YAAY,EACzB,oBAAoB,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,oBAAoB,EAC7B,kBAAkB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAuC5B;;;;;;;;;;;OAWG;YACW,oBAAoB;YAuCpB,kBAAkB;CAoBhC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.OdspPointInTimeDocumentServiceFactory = void 0;
|
|
8
|
+
const internal_1 = require("@fluidframework/telemetry-utils/internal");
|
|
9
|
+
const epochTracker_js_1 = require("../epochTracker.js");
|
|
10
|
+
const odspCache_js_1 = require("../odspCache.js");
|
|
11
|
+
const odspDocumentServiceFactoryCore_js_1 = require("../odspDocumentServiceFactoryCore.js");
|
|
12
|
+
const odspDriverUrlResolver_js_1 = require("../odspDriverUrlResolver.js");
|
|
13
|
+
const odspUtils_js_1 = require("../odspUtils.js");
|
|
14
|
+
const index_js_1 = require("../odspVersionManager/index.js");
|
|
15
|
+
const odspPointInTimeDocumentService_js_1 = require("./odspPointInTimeDocumentService.js");
|
|
16
|
+
/**
|
|
17
|
+
* ODSP document service factory that additionally supports point-in-time (sequence-number-based)
|
|
18
|
+
* loading.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* This extends {@link OdspDocumentServiceFactoryCore} with the ability to materialize a read-only
|
|
22
|
+
* document service at a requested Fluid sequence number. The loader detects this capability via the
|
|
23
|
+
* presence of {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService}, so
|
|
24
|
+
* hosts that want to load a container to a target sequence number must construct this factory
|
|
25
|
+
* (rather than the legacy `OdspDocumentServiceFactory`) and pass it to the loader.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCore_js_1.OdspDocumentServiceFactoryCore {
|
|
30
|
+
constructor(getStorageToken, getWebsocketToken, persistedCache, hostPolicy) {
|
|
31
|
+
super(getStorageToken, getWebsocketToken, persistedCache, hostPolicy);
|
|
32
|
+
this.getStorageTokenForVersions = getStorageToken;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a document service that reads its snapshot from the closest file version at or before
|
|
36
|
+
* the target and its deltas from the live document, materializing a requested sequence number
|
|
37
|
+
* through replay.
|
|
38
|
+
*/
|
|
39
|
+
async createPointInTimeDocumentService(resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer) {
|
|
40
|
+
const versionManager = await this.createVersionManager(resolvedUrl, logger, clientIsSummarizer);
|
|
41
|
+
const baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);
|
|
42
|
+
if (baseResult.kind === "noBaseVersion") {
|
|
43
|
+
const oldestResolvedSequenceDetail = baseResult.oldestResolvedSeq === undefined
|
|
44
|
+
? ""
|
|
45
|
+
: ` The oldest resolved file version is at sequence number ${baseResult.oldestResolvedSeq}.`;
|
|
46
|
+
throw new internal_1.UsageError(`No ODSP file version is available at or before sequence number ${targetSequenceNumber}.${oldestResolvedSequenceDetail}`);
|
|
47
|
+
}
|
|
48
|
+
const recoverableResolvedUrl = await this.resolveFileVersion(resolvedUrl, baseResult.base.versionId);
|
|
49
|
+
const recoverableDocumentService = await this.createDocumentService(recoverableResolvedUrl, logger, clientIsSummarizer);
|
|
50
|
+
const liveDocumentService = await this.createDocumentService(resolvedUrl, logger, clientIsSummarizer);
|
|
51
|
+
return new odspPointInTimeDocumentService_js_1.OdspPointInTimeDocumentService(recoverableResolvedUrl, recoverableDocumentService, liveDocumentService, targetSequenceNumber);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Builds an IOdspVersionManager for the given file, which enumerates the file's stored
|
|
55
|
+
* versions and resolves the closest version at or before a target sequence number.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* This wires up the plumbing the version manager needs to talk to ODSP: it resolves the URL to
|
|
59
|
+
* its ODSP parts (site/drive/item), creates a scoped child logger, an epoch tracker (from a fresh
|
|
60
|
+
* NonPersistentCache, since only the tracker is needed for consistency checks), and an
|
|
61
|
+
* instrumented storage-token/auth-header fetcher. The resulting manager is used by
|
|
62
|
+
* {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService} to pick the base
|
|
63
|
+
* snapshot for point-in-time loading.
|
|
64
|
+
*/
|
|
65
|
+
async createVersionManager(resolvedUrl, logger, clientIsSummarizer) {
|
|
66
|
+
const odspLogger = (0, odspUtils_js_1.createOdspLogger)(logger);
|
|
67
|
+
const extLogger = (0, internal_1.createChildLogger)({ logger: odspLogger });
|
|
68
|
+
const odspResolvedUrl = (0, odspUtils_js_1.getOdspResolvedUrl)(resolvedUrl);
|
|
69
|
+
const urlParts = {
|
|
70
|
+
siteUrl: odspResolvedUrl.siteUrl,
|
|
71
|
+
driveId: odspResolvedUrl.driveId,
|
|
72
|
+
itemId: odspResolvedUrl.itemId,
|
|
73
|
+
};
|
|
74
|
+
// Only the epochTracker from the returned cacheAndTracker is used below, so a fresh
|
|
75
|
+
// NonPersistentCache is sufficient here.
|
|
76
|
+
const cacheAndTracker = (0, epochTracker_js_1.createOdspCacheAndTracker)(this.persistedCache, new odspCache_js_1.NonPersistentCache(), {
|
|
77
|
+
resolvedUrl: odspResolvedUrl,
|
|
78
|
+
docId: odspResolvedUrl.hashedDocumentId,
|
|
79
|
+
fileVersion: odspResolvedUrl.fileVersion,
|
|
80
|
+
}, extLogger, clientIsSummarizer);
|
|
81
|
+
const getAuthHeader = (0, odspUtils_js_1.toInstrumentedOdspStorageTokenFetcher)(extLogger, urlParts, this.getStorageTokenForVersions);
|
|
82
|
+
return (0, index_js_1.createOdspVersionManager)({
|
|
83
|
+
urlParts,
|
|
84
|
+
getAuthHeader,
|
|
85
|
+
epochTracker: cacheAndTracker.epochTracker,
|
|
86
|
+
logger: extLogger,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async resolveFileVersion(resolvedUrl, fileVersion) {
|
|
90
|
+
const odspResolvedUrl = (0, odspUtils_js_1.getOdspResolvedUrl)(resolvedUrl);
|
|
91
|
+
const query = new URLSearchParams({
|
|
92
|
+
driveId: odspResolvedUrl.driveId,
|
|
93
|
+
itemId: odspResolvedUrl.itemId,
|
|
94
|
+
fileVersion,
|
|
95
|
+
});
|
|
96
|
+
if (odspResolvedUrl.dataStorePath !== undefined) {
|
|
97
|
+
query.set("path", odspResolvedUrl.dataStorePath);
|
|
98
|
+
}
|
|
99
|
+
if (odspResolvedUrl.codeHint?.containerPackageName !== undefined) {
|
|
100
|
+
query.set("containerPackageName", odspResolvedUrl.codeHint.containerPackageName);
|
|
101
|
+
}
|
|
102
|
+
return new odspDriverUrlResolver_js_1.OdspDriverUrlResolver().resolve({
|
|
103
|
+
url: `${odspResolvedUrl.siteUrl}?${query.toString()}`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.OdspPointInTimeDocumentServiceFactory = OdspPointInTimeDocumentServiceFactory;
|
|
108
|
+
//# sourceMappingURL=odspPointInTimeDocumentServiceFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspPointInTimeDocumentServiceFactory.js","sourceRoot":"","sources":["../../src/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.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 { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIDocumentService,\n\tIPersistedCache,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tHostStoragePolicy,\n\tIOdspUrlParts,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport { UsageError, createChildLogger } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { createOdspCacheAndTracker } from \"../epochTracker.js\";\nimport { NonPersistentCache } from \"../odspCache.js\";\nimport { OdspDocumentServiceFactoryCore } from \"../odspDocumentServiceFactoryCore.js\";\nimport { OdspDriverUrlResolver } from \"../odspDriverUrlResolver.js\";\nimport {\n\tcreateOdspLogger,\n\tgetOdspResolvedUrl,\n\ttoInstrumentedOdspStorageTokenFetcher,\n} from \"../odspUtils.js\";\nimport {\n\tcreateOdspVersionManager,\n\ttype IOdspVersionManager,\n} from \"../odspVersionManager/index.js\";\n\nimport { OdspPointInTimeDocumentService } from \"./odspPointInTimeDocumentService.js\";\n\n/**\n * ODSP document service factory that additionally supports point-in-time (sequence-number-based)\n * loading.\n *\n * @remarks\n * This extends {@link OdspDocumentServiceFactoryCore} with the ability to materialize a read-only\n * document service at a requested Fluid sequence number. The loader detects this capability via the\n * presence of {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService}, so\n * hosts that want to load a container to a target sequence number must construct this factory\n * (rather than the legacy `OdspDocumentServiceFactory`) and pass it to the loader.\n *\n * @internal\n */\nexport class OdspPointInTimeDocumentServiceFactory extends OdspDocumentServiceFactoryCore {\n\t/**\n\t * The storage token fetcher, captured here because the base class keeps it private.\n\t */\n\tprivate readonly getStorageTokenForVersions: TokenFetcher<OdspResourceTokenFetchOptions>;\n\n\tconstructor(\n\t\tgetStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>,\n\t\tgetWebsocketToken: TokenFetcher<OdspResourceTokenFetchOptions> | undefined,\n\t\tpersistedCache?: IPersistedCache,\n\t\thostPolicy?: HostStoragePolicy,\n\t) {\n\t\tsuper(getStorageToken, getWebsocketToken, persistedCache, hostPolicy);\n\t\tthis.getStorageTokenForVersions = getStorageToken;\n\t}\n\n\t/**\n\t * Creates a document service that reads its snapshot from the closest file version at or before\n\t * the target and its deltas from the live document, materializing a requested sequence number\n\t * through replay.\n\t */\n\tpublic async createPointInTimeDocumentService(\n\t\tresolvedUrl: IResolvedUrl,\n\t\ttargetSequenceNumber: number,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tclientIsSummarizer?: boolean,\n\t): Promise<IDocumentService> {\n\t\tconst versionManager = await this.createVersionManager(\n\t\t\tresolvedUrl,\n\t\t\tlogger,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\tconst baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);\n\t\tif (baseResult.kind === \"noBaseVersion\") {\n\t\t\tconst oldestResolvedSequenceDetail =\n\t\t\t\tbaseResult.oldestResolvedSeq === undefined\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: ` The oldest resolved file version is at sequence number ${baseResult.oldestResolvedSeq}.`;\n\t\t\tthrow new UsageError(\n\t\t\t\t`No ODSP file version is available at or before sequence number ${targetSequenceNumber}.${oldestResolvedSequenceDetail}`,\n\t\t\t);\n\t\t}\n\n\t\tconst recoverableResolvedUrl = await this.resolveFileVersion(\n\t\t\tresolvedUrl,\n\t\t\tbaseResult.base.versionId,\n\t\t);\n\t\tconst recoverableDocumentService = await this.createDocumentService(\n\t\t\trecoverableResolvedUrl,\n\t\t\tlogger,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\tconst liveDocumentService = await this.createDocumentService(\n\t\t\tresolvedUrl,\n\t\t\tlogger,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\treturn new OdspPointInTimeDocumentService(\n\t\t\trecoverableResolvedUrl,\n\t\t\trecoverableDocumentService,\n\t\t\tliveDocumentService,\n\t\t\ttargetSequenceNumber,\n\t\t);\n\t}\n\n\t/**\n\t * Builds an IOdspVersionManager for the given file, which enumerates the file's stored\n\t * versions and resolves the closest version at or before a target sequence number.\n\t *\n\t * @remarks\n\t * This wires up the plumbing the version manager needs to talk to ODSP: it resolves the URL to\n\t * its ODSP parts (site/drive/item), creates a scoped child logger, an epoch tracker (from a fresh\n\t * NonPersistentCache, since only the tracker is needed for consistency checks), and an\n\t * instrumented storage-token/auth-header fetcher. The resulting manager is used by\n\t * {@link OdspPointInTimeDocumentServiceFactory.createPointInTimeDocumentService} to pick the base\n\t * snapshot for point-in-time loading.\n\t */\n\tprivate async createVersionManager(\n\t\tresolvedUrl: IResolvedUrl,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tclientIsSummarizer?: boolean,\n\t): Promise<IOdspVersionManager> {\n\t\tconst odspLogger = createOdspLogger(logger);\n\t\tconst extLogger = createChildLogger({ logger: odspLogger });\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\t\tconst urlParts: IOdspUrlParts = {\n\t\t\tsiteUrl: odspResolvedUrl.siteUrl,\n\t\t\tdriveId: odspResolvedUrl.driveId,\n\t\t\titemId: odspResolvedUrl.itemId,\n\t\t};\n\t\t// Only the epochTracker from the returned cacheAndTracker is used below, so a fresh\n\t\t// NonPersistentCache is sufficient here.\n\t\tconst cacheAndTracker = createOdspCacheAndTracker(\n\t\t\tthis.persistedCache,\n\t\t\tnew NonPersistentCache(),\n\t\t\t{\n\t\t\t\tresolvedUrl: odspResolvedUrl,\n\t\t\t\tdocId: odspResolvedUrl.hashedDocumentId,\n\t\t\t\tfileVersion: odspResolvedUrl.fileVersion,\n\t\t\t},\n\t\t\textLogger,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\tconst getAuthHeader = toInstrumentedOdspStorageTokenFetcher(\n\t\t\textLogger,\n\t\t\turlParts,\n\t\t\tthis.getStorageTokenForVersions,\n\t\t);\n\t\treturn createOdspVersionManager({\n\t\t\turlParts,\n\t\t\tgetAuthHeader,\n\t\t\tepochTracker: cacheAndTracker.epochTracker,\n\t\t\tlogger: extLogger,\n\t\t});\n\t}\n\n\tprivate async resolveFileVersion(\n\t\tresolvedUrl: IResolvedUrl,\n\t\tfileVersion: string,\n\t): Promise<IResolvedUrl> {\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\t\tconst query = new URLSearchParams({\n\t\t\tdriveId: odspResolvedUrl.driveId,\n\t\t\titemId: odspResolvedUrl.itemId,\n\t\t\tfileVersion,\n\t\t});\n\t\tif (odspResolvedUrl.dataStorePath !== undefined) {\n\t\t\tquery.set(\"path\", odspResolvedUrl.dataStorePath);\n\t\t}\n\t\tif (odspResolvedUrl.codeHint?.containerPackageName !== undefined) {\n\t\t\tquery.set(\"containerPackageName\", odspResolvedUrl.codeHint.containerPackageName);\n\t\t}\n\t\treturn new OdspDriverUrlResolver().resolve({\n\t\t\turl: `${odspResolvedUrl.siteUrl}?${query.toString()}`,\n\t\t});\n\t}\n}\n"]}
|
package/lib/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { getOdspUrlParts, isOdcUrl, isSpoUrl } from "./odspUrlHelper.js";
|
|
|
11
11
|
export { prefetchLatestSnapshot } from "./prefetchLatestSnapshot.js";
|
|
12
12
|
export { createLocalOdspDocumentServiceFactory, OdspDocumentServiceFactory, } from "./odspDocumentServiceFactory.js";
|
|
13
13
|
export { OdspDocumentServiceFactoryCore } from "./odspDocumentServiceFactoryCore.js";
|
|
14
|
+
export { OdspPointInTimeDocumentServiceFactory } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
|
|
14
15
|
export { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest.js";
|
|
15
16
|
export { OdspDriverUrlResolver } from "./odspDriverUrlResolver.js";
|
|
16
17
|
export { OdspDriverUrlResolverForShareLink, type ShareLinkFetcherProps, } from "./odspDriverUrlResolverForShareLink.js";
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EACN,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EACN,qCAAqC,EACrC,0BAA0B,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EACN,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EACN,qCAAqC,EACrC,0BAA0B,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AAErF,OAAO,EAAE,qCAAqC,EAAE,MAAM,8DAA8D,CAAC;AAGrH,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AAGzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACN,iCAAiC,EACjC,KAAK,qBAAqB,GAC1B,MAAM,wCAAwC,CAAC;AAGhD,OAAO,EACN,+BAA+B,EAC/B,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,iBAAiB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EACN,KAAK,0BAA0B,EAC/B,4BAA4B,GAC5B,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -15,6 +15,8 @@ export { prefetchLatestSnapshot } from "./prefetchLatestSnapshot.js";
|
|
|
15
15
|
// Factory
|
|
16
16
|
export { createLocalOdspDocumentServiceFactory, OdspDocumentServiceFactory, } from "./odspDocumentServiceFactory.js";
|
|
17
17
|
export { OdspDocumentServiceFactoryCore } from "./odspDocumentServiceFactoryCore.js";
|
|
18
|
+
// eslint-disable-next-line import-x/no-internal-modules
|
|
19
|
+
export { OdspPointInTimeDocumentServiceFactory } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
|
|
18
20
|
// File creation
|
|
19
21
|
export { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest.js";
|
|
20
22
|
// URI Resolver functionality, URI management
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY;AACZ,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EACN,qBAAqB,EAIrB,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAE9B,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAA0B,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzE,iDAAiD;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,UAAU;AACV,OAAO,EACN,qCAAqC,EACrC,0BAA0B,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY;AACZ,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EACN,qBAAqB,EAIrB,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAE9B,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAA0B,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzE,iDAAiD;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAErE,UAAU;AACV,OAAO,EACN,qCAAqC,EACrC,0BAA0B,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,wDAAwD;AACxD,OAAO,EAAE,qCAAqC,EAAE,MAAM,8DAA8D,CAAC;AAErH,gBAAgB;AAChB,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AAEzF,6CAA6C;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EACN,iCAAiC,GAEjC,MAAM,wCAAwC,CAAC;AAEhD,oEAAoE;AACpE,OAAO,EACN,+BAA+B,EAC/B,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,wBAAwB,CAAC;AAchC,OAAO,EAAsB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAEN,4BAA4B,GAC5B,MAAM,4BAA4B,CAAC;AAEpC,uBAAuB;AACvB,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Constants\nexport { OdcApiSiteOrigin, OdcFileSiteOrigin } from \"./constants.js\";\n\nexport {\n\tClpCompliantAppHeader,\n\ttype IClpCompliantAppHeader,\n\ttype ISharingLinkHeader,\n\ttype OdspFluidDataStoreLocator,\n\tSharingLinkHeader,\n} from \"./contractsPublic.js\";\n\n// public utils\nexport { checkUrl } from \"./checkUrl.js\";\nexport { createOdspUrl } from \"./createOdspUrl.js\";\nexport { getHashedDocumentId, type ISnapshotContents } from \"./odspPublicUtils.js\";\nexport { getOdspUrlParts, isOdcUrl, isSpoUrl } from \"./odspUrlHelper.js\";\n\n// prefetch latest snapshot before container load\nexport { prefetchLatestSnapshot } from \"./prefetchLatestSnapshot.js\";\n\n// Factory\nexport {\n\tcreateLocalOdspDocumentServiceFactory,\n\tOdspDocumentServiceFactory,\n} from \"./odspDocumentServiceFactory.js\";\nexport { OdspDocumentServiceFactoryCore } from \"./odspDocumentServiceFactoryCore.js\";\n// eslint-disable-next-line import-x/no-internal-modules\nexport { OdspPointInTimeDocumentServiceFactory } from \"./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js\";\n\n// File creation\nexport { createOdspCreateContainerRequest } from \"./createOdspCreateContainerRequest.js\";\n\n// URI Resolver functionality, URI management\nexport { OdspDriverUrlResolver } from \"./odspDriverUrlResolver.js\";\nexport {\n\tOdspDriverUrlResolverForShareLink,\n\ttype ShareLinkFetcherProps,\n} from \"./odspDriverUrlResolverForShareLink.js\";\n\n// It's used by URL resolve code, but also has some public functions\nexport {\n\tencodeOdspFluidDataStoreLocator,\n\tgetLocatorFromOdspUrl,\n\tlocatorQueryParamName,\n\tstoreLocatorInOdspUrl,\n} from \"./odspFluidFileLink.js\";\n\nexport type {\n\tIOdspCache,\n\tIPersistedFileCache,\n\tINonPersistentCache,\n\tIPrefetchSnapshotContents,\n} from \"./odspCache.js\";\nexport type {\n\tICacheAndTracker,\n\tEpochTracker,\n\tFetchType,\n\tFetchTypeInternal,\n} from \"./epochTracker.js\";\nexport { type IOdspResponse, isOdspResolvedUrl } from \"./odspUtils.js\";\nexport { SnapshotFormatSupportType } from \"./fetchSnapshot.js\";\nexport {\n\ttype ISnapshotContentsWithProps,\n\tparseCompactSnapshotResponse,\n} from \"./compactSnapshotParser.js\";\n\n// Layer Compat details\nexport { odspDriverCompatDetailsForLoader } from \"./odspLayerCompatState.js\";\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
export { createOdspVersionManager, type BaseForSeq, type IOdspVersionManager, type OdspFileVersionRef, type ResolvedVersion, } from "./odspVersionManager.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,wBAAwB,EACxB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACpB,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/odspVersionManager/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,wBAAwB,GAKxB,MAAM,yBAAyB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tcreateOdspVersionManager,\n\ttype BaseForSeq,\n\ttype IOdspVersionManager,\n\ttype OdspFileVersionRef,\n\ttype ResolvedVersion,\n} from \"./odspVersionManager.js\";\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { IOdspUrlParts, InstrumentedStorageTokenFetcher } from "@fluidframework/odsp-driver-definitions/internal";
|
|
6
|
+
import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
|
|
7
|
+
import type { EpochTracker } from "../epochTracker.js";
|
|
8
|
+
import type { IOdspFileVersionFetcher } from "./odspVersionManager.js";
|
|
9
|
+
/**
|
|
10
|
+
* Inputs needed to make authenticated requests against a specific ODSP file.
|
|
11
|
+
*/
|
|
12
|
+
export interface OdspFileVersionFetcherProps {
|
|
13
|
+
readonly urlParts: IOdspUrlParts;
|
|
14
|
+
readonly getAuthHeader: InstrumentedStorageTokenFetcher;
|
|
15
|
+
readonly epochTracker: EpochTracker;
|
|
16
|
+
readonly logger: TelemetryLoggerExt;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createOdspFileVersionFetcher(props: OdspFileVersionFetcherProps): IOdspFileVersionFetcher;
|
|
22
|
+
//# sourceMappingURL=odspFileVersionFetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspFileVersionFetcher.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,KAAK,EACX,aAAa,EACb,+BAA+B,EAC/B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAInF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,OAAO,KAAK,EAAsB,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAmB3F;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,+BAA+B,CAAC;IACxD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACpC;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,2BAA2B,GAChC,uBAAuB,CA6EzB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { currentReadVersion, parseCompactSnapshotResponse } from "../compactSnapshotParser.js";
|
|
6
|
+
import { getHeadersWithAuth } from "../getUrlAndHeadersWithAuth.js";
|
|
7
|
+
import { convertOdspSnapshotToSnapshotTreeAndBlobs } from "../odspSnapshotParser.js";
|
|
8
|
+
import { getApiRoot } from "../odspUrlHelper.js";
|
|
9
|
+
import { getWithRetryForTokenRefresh } from "../odspUtils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
|
|
12
|
+
*/
|
|
13
|
+
export function createOdspFileVersionFetcher(props) {
|
|
14
|
+
const { urlParts, getAuthHeader, epochTracker, logger } = props;
|
|
15
|
+
const { siteUrl, driveId, itemId } = urlParts;
|
|
16
|
+
const listFileVersions = async () => getWithRetryForTokenRefresh(async (options) => {
|
|
17
|
+
const method = "GET";
|
|
18
|
+
const versions = [];
|
|
19
|
+
// The file's version history (distinct from the driver's snapshot list), from the same API
|
|
20
|
+
// root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.
|
|
21
|
+
// A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base
|
|
22
|
+
// version beyond the first page would be missed and wrongly reported as "no base version".
|
|
23
|
+
let url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;
|
|
24
|
+
do {
|
|
25
|
+
const token = await getAuthHeader({ ...options, request: { url, method } }, "FileVersions");
|
|
26
|
+
const headers = getHeadersWithAuth(token);
|
|
27
|
+
const response = await epochTracker.fetchAndParseAsJSON(url, { method, headers }, "versions");
|
|
28
|
+
const page = response.content;
|
|
29
|
+
// The API returns versions newest-first.
|
|
30
|
+
for (const version of page.value ?? []) {
|
|
31
|
+
versions.push({
|
|
32
|
+
versionId: version.id,
|
|
33
|
+
lastModifiedDateTime: version.lastModifiedDateTime,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
url = page["@odata.nextLink"] ?? "";
|
|
37
|
+
} while (url);
|
|
38
|
+
return versions;
|
|
39
|
+
});
|
|
40
|
+
const resolveSequenceNumber = async (versionId) => getWithRetryForTokenRefresh(async (options) => {
|
|
41
|
+
// A file version's sequence number lives inside that version's snapshot, so fetch the snapshot
|
|
42
|
+
// from the version-scoped endpoint. `blobs=2` inlines blob contents so the `.protocol/attributes`
|
|
43
|
+
// blob (which carries the sequence number) is included; `deltas=1` is intentionally omitted, as
|
|
44
|
+
// it would bundle the op stream and its op-level sequence numbers.
|
|
45
|
+
const url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=2`;
|
|
46
|
+
const method = "GET";
|
|
47
|
+
const token = await getAuthHeader({ ...options, request: { url, method } }, "FileVersionSnapshot");
|
|
48
|
+
const headers = getHeadersWithAuth(token);
|
|
49
|
+
// The server can return the snapshot in one of two equivalent framings: verbose JSON, or
|
|
50
|
+
// "ms-fluid" — ODSP's compact binary encoding of the same snapshot. Advertise both, and pin the
|
|
51
|
+
// binary format version (as the driver's own snapshot fetch does) so the server cannot hand back
|
|
52
|
+
// a binary version this code's parser does not understand.
|
|
53
|
+
headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
|
|
54
|
+
const response = await epochTracker.fetch(url, { method, headers }, "treesLatest");
|
|
55
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
56
|
+
let sequenceNumber;
|
|
57
|
+
if (contentType.includes("application/json")) {
|
|
58
|
+
// JSON framing: read it with the driver's JSON snapshot parser.
|
|
59
|
+
const snapshotJson = (await response.content.json());
|
|
60
|
+
sequenceNumber =
|
|
61
|
+
convertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.
|
|
65
|
+
const bytes = new Uint8Array(await response.content.arrayBuffer());
|
|
66
|
+
sequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;
|
|
67
|
+
}
|
|
68
|
+
// A version's snapshot must carry a sequence number; a missing one is surfaced as an error
|
|
69
|
+
// naming the version, rather than returning a wrong value.
|
|
70
|
+
if (sequenceNumber === undefined) {
|
|
71
|
+
throw new Error(`ODSP file version ${versionId} snapshot is missing a sequenceNumber`);
|
|
72
|
+
}
|
|
73
|
+
return sequenceNumber;
|
|
74
|
+
});
|
|
75
|
+
return { listFileVersions, resolveSequenceNumber };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=odspFileVersionFetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspFileVersionFetcher.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.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\n/*\n * An {@link IOdspFileVersionFetcher} backed by the ODSP REST APIs:\n * - GET /_api/v2.1/.../versions -- enumerate the file's versions.\n * - GET /_api/v2.1/.../versions/{label}/opStream/snapshots/trees/latest?blobs=2 -- fetch a version's\n * snapshot and read its sequence number, parsed with the driver's snapshot parser.\n */\n\nimport type {\n\tIOdspUrlParts,\n\tInstrumentedStorageTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport type { TelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport { currentReadVersion, parseCompactSnapshotResponse } from \"../compactSnapshotParser.js\";\nimport type { IOdspSnapshot } from \"../contracts.js\";\nimport type { EpochTracker } from \"../epochTracker.js\";\nimport { getHeadersWithAuth } from \"../getUrlAndHeadersWithAuth.js\";\nimport { convertOdspSnapshotToSnapshotTreeAndBlobs } from \"../odspSnapshotParser.js\";\nimport { getApiRoot } from \"../odspUrlHelper.js\";\nimport { getWithRetryForTokenRefresh } from \"../odspUtils.js\";\n\nimport type { OdspFileVersionRef, IOdspFileVersionFetcher } from \"./odspVersionManager.js\";\n\n/**\n * Raw shape of a OneDrive/SharePoint driveItem version (an entry in the `/versions` response).\n * @see https://learn.microsoft.com/en-us/onedrive/developer/rest-api/resources/driveitemversion\n */\ninterface IDriveItemVersion {\n\t/** The version's label, e.g. \"42.0\". */\n\treadonly id: string;\n\treadonly lastModifiedDateTime: string;\n}\n\n/** A single page of the driveItem `/versions` response. */\ninterface IDriveItemVersionsPage {\n\treadonly value?: IDriveItemVersion[];\n\t/** Absolute URL of the next page, present only while more versions remain. */\n\treadonly \"@odata.nextLink\"?: string;\n}\n\n/**\n * Inputs needed to make authenticated requests against a specific ODSP file.\n */\nexport interface OdspFileVersionFetcherProps {\n\treadonly urlParts: IOdspUrlParts;\n\treadonly getAuthHeader: InstrumentedStorageTokenFetcher;\n\treadonly epochTracker: EpochTracker;\n\treadonly logger: TelemetryLoggerExt;\n}\n\n/**\n * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.\n */\nexport function createOdspFileVersionFetcher(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspFileVersionFetcher {\n\tconst { urlParts, getAuthHeader, epochTracker, logger } = props;\n\tconst { siteUrl, driveId, itemId } = urlParts;\n\n\tconst listFileVersions = async (): Promise<OdspFileVersionRef[]> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\tconst method = \"GET\";\n\t\t\tconst versions: OdspFileVersionRef[] = [];\n\t\t\t// The file's version history (distinct from the driver's snapshot list), from the same API\n\t\t\t// root as the snapshot call so consumer (ODC) and enterprise (SPO) hosts are handled alike.\n\t\t\t// A long history is paged, so follow `@odata.nextLink` until it is absent; otherwise a base\n\t\t\t// version beyond the first page would be missed and wrongly reported as \"no base version\".\n\t\t\tlet url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions`;\n\t\t\tdo {\n\t\t\t\tconst token = await getAuthHeader(\n\t\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\t\"FileVersions\",\n\t\t\t\t);\n\t\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t\tconst response = await epochTracker.fetchAndParseAsJSON<{\n\t\t\t\t\tvalue?: IDriveItemVersion[];\n\t\t\t\t}>(url, { method, headers }, \"versions\");\n\t\t\t\tconst page = response.content as IDriveItemVersionsPage;\n\t\t\t\t// The API returns versions newest-first.\n\t\t\t\tfor (const version of page.value ?? []) {\n\t\t\t\t\tversions.push({\n\t\t\t\t\t\tversionId: version.id,\n\t\t\t\t\t\tlastModifiedDateTime: version.lastModifiedDateTime,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\turl = page[\"@odata.nextLink\"] ?? \"\";\n\t\t\t} while (url);\n\t\t\treturn versions;\n\t\t});\n\n\tconst resolveSequenceNumber = async (versionId: string): Promise<number> =>\n\t\tgetWithRetryForTokenRefresh(async (options) => {\n\t\t\t// A file version's sequence number lives inside that version's snapshot, so fetch the snapshot\n\t\t\t// from the version-scoped endpoint. `blobs=2` inlines blob contents so the `.protocol/attributes`\n\t\t\t// blob (which carries the sequence number) is included; `deltas=1` is intentionally omitted, as\n\t\t\t// it would bundle the op stream and its op-level sequence numbers.\n\t\t\tconst url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(\n\t\t\t\tversionId,\n\t\t\t)}/opStream/snapshots/trees/latest?blobs=2`;\n\t\t\tconst method = \"GET\";\n\t\t\tconst token = await getAuthHeader(\n\t\t\t\t{ ...options, request: { url, method } },\n\t\t\t\t\"FileVersionSnapshot\",\n\t\t\t);\n\t\t\tconst headers = getHeadersWithAuth(token);\n\t\t\t// The server can return the snapshot in one of two equivalent framings: verbose JSON, or\n\t\t\t// \"ms-fluid\" — ODSP's compact binary encoding of the same snapshot. Advertise both, and pin the\n\t\t\t// binary format version (as the driver's own snapshot fetch does) so the server cannot hand back\n\t\t\t// a binary version this code's parser does not understand.\n\t\t\theaders.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;\n\t\t\tconst response = await epochTracker.fetch(url, { method, headers }, \"treesLatest\");\n\t\t\tconst contentType = response.headers.get(\"content-type\") ?? \"\";\n\t\t\tlet sequenceNumber: number | undefined;\n\t\t\tif (contentType.includes(\"application/json\")) {\n\t\t\t\t// JSON framing: read it with the driver's JSON snapshot parser.\n\t\t\t\tconst snapshotJson = (await response.content.json()) as IOdspSnapshot;\n\t\t\t\tsequenceNumber =\n\t\t\t\t\tconvertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;\n\t\t\t} else {\n\t\t\t\t// ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.\n\t\t\t\tconst bytes = new Uint8Array(await response.content.arrayBuffer());\n\t\t\t\tsequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;\n\t\t\t}\n\t\t\t// A version's snapshot must carry a sequence number; a missing one is surfaced as an error\n\t\t\t// naming the version, rather than returning a wrong value.\n\t\t\tif (sequenceNumber === undefined) {\n\t\t\t\tthrow new Error(`ODSP file version ${versionId} snapshot is missing a sequenceNumber`);\n\t\t\t}\n\t\t\treturn sequenceNumber;\n\t\t});\n\n\treturn { listFileVersions, resolveSequenceNumber };\n}\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —
|
|
7
|
+
* the base to load or replay from when materializing a document at a point in time.
|
|
8
|
+
*
|
|
9
|
+
* The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of
|
|
10
|
+
* how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).
|
|
11
|
+
*/
|
|
12
|
+
import { type OdspFileVersionFetcherProps } from "./odspFileVersionFetcher.js";
|
|
13
|
+
/**
|
|
14
|
+
* A single ODSP file version, as listed by the file's version history.
|
|
15
|
+
*/
|
|
16
|
+
export interface OdspFileVersionRef {
|
|
17
|
+
/**
|
|
18
|
+
* The version's label (e.g. `"42.0"`), used to address the version when fetching it.
|
|
19
|
+
*/
|
|
20
|
+
readonly versionId: string;
|
|
21
|
+
/**
|
|
22
|
+
* Last-modified timestamp of this version, ISO-8601.
|
|
23
|
+
*/
|
|
24
|
+
readonly lastModifiedDateTime: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* An ODSP file version together with its resolved Fluid sequence number.
|
|
28
|
+
*/
|
|
29
|
+
export interface ResolvedVersion extends OdspFileVersionRef {
|
|
30
|
+
/**
|
|
31
|
+
* The Fluid sequence number the version's snapshot represents.
|
|
32
|
+
*/
|
|
33
|
+
readonly sequenceNumber: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Result of resolving the base version for a target sequence number.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* There is intentionally no `targetIsLive` case: when the target is at/after the newest recoverable
|
|
40
|
+
* version, the greatest version with `seq <= target` IS that newest version, so it is a normal
|
|
41
|
+
* `found`. A consumer may separately choose to load the live file when the target is near the head.
|
|
42
|
+
*/
|
|
43
|
+
export type BaseForSeq = {
|
|
44
|
+
/** A recoverable version with `sequenceNumber <= target` was found. */
|
|
45
|
+
readonly kind: "found";
|
|
46
|
+
readonly base: ResolvedVersion;
|
|
47
|
+
} | {
|
|
48
|
+
/** No recoverable version has `sequenceNumber <= target` (target predates retained history). */
|
|
49
|
+
readonly kind: "noBaseVersion";
|
|
50
|
+
/** The oldest sequence number that was resolved while searching, if any. */
|
|
51
|
+
readonly oldestResolvedSeq?: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Provides a file's versions and resolves each version's Fluid sequence number. Injected into
|
|
55
|
+
* the version manager so the selection logic does not depend on how versions are fetched.
|
|
56
|
+
*/
|
|
57
|
+
export interface IOdspFileVersionFetcher {
|
|
58
|
+
/**
|
|
59
|
+
* Enumerate the file's versions, newest-first.
|
|
60
|
+
*/
|
|
61
|
+
listFileVersions(): Promise<OdspFileVersionRef[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Resolve a single version's Fluid sequence number. Throws on failure rather than returning a
|
|
64
|
+
* wrong value.
|
|
65
|
+
*/
|
|
66
|
+
resolveSequenceNumber(versionId: string): Promise<number>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Selects the file version to use as the base for loading or replaying to a target sequence number.
|
|
70
|
+
*/
|
|
71
|
+
export interface IOdspVersionManager {
|
|
72
|
+
/**
|
|
73
|
+
* Given a target sequence number, return the closest version at or before it (`found`), or
|
|
74
|
+
* `noBaseVersion` if the target predates the oldest retained version.
|
|
75
|
+
*/
|
|
76
|
+
findBaseForSeq(target: number): Promise<BaseForSeq>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The
|
|
80
|
+
* resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind
|
|
81
|
+
* {@link findBaseForSeq} and can change without affecting callers.
|
|
82
|
+
*/
|
|
83
|
+
export declare class OdspVersionManager implements IOdspVersionManager {
|
|
84
|
+
private readonly fetcher;
|
|
85
|
+
private versionsCache;
|
|
86
|
+
private readonly seqByVersion;
|
|
87
|
+
constructor(fetcher: IOdspFileVersionFetcher);
|
|
88
|
+
refresh(): void;
|
|
89
|
+
findBaseForSeq(target: number): Promise<BaseForSeq>;
|
|
90
|
+
listVersions(): Promise<ResolvedVersion[]>;
|
|
91
|
+
private getVersions;
|
|
92
|
+
private resolveSeq;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.
|
|
96
|
+
*/
|
|
97
|
+
export declare function createOdspVersionManager(props: OdspFileVersionFetcherProps): IOdspVersionManager;
|
|
98
|
+
//# sourceMappingURL=odspVersionManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspVersionManager.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspVersionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,EAEN,KAAK,2BAA2B,EAChC,MAAM,6BAA6B,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IAC1D;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GACnB;IACA,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAC9B,GACD;IACA,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEL;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACvC;;OAEG;IACH,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAClD;;;OAGG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAI1C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH3C,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;gBAE/B,OAAO,EAAE,uBAAuB;IAE7D,OAAO,IAAI,IAAI;IAKT,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAyBnD,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAYzC,WAAW;YAOX,UAAU;CAUxB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,2BAA2B,GAChC,mBAAmB,CAErB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —
|
|
7
|
+
* the base to load or replay from when materializing a document at a point in time.
|
|
8
|
+
*
|
|
9
|
+
* The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of
|
|
10
|
+
* how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).
|
|
11
|
+
*/
|
|
12
|
+
import { createOdspFileVersionFetcher, } from "./odspFileVersionFetcher.js";
|
|
13
|
+
/**
|
|
14
|
+
* Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The
|
|
15
|
+
* resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind
|
|
16
|
+
* {@link findBaseForSeq} and can change without affecting callers.
|
|
17
|
+
*/
|
|
18
|
+
export class OdspVersionManager {
|
|
19
|
+
constructor(fetcher) {
|
|
20
|
+
this.fetcher = fetcher;
|
|
21
|
+
this.seqByVersion = new Map();
|
|
22
|
+
}
|
|
23
|
+
refresh() {
|
|
24
|
+
this.versionsCache = undefined;
|
|
25
|
+
this.seqByVersion.clear();
|
|
26
|
+
}
|
|
27
|
+
async findBaseForSeq(target) {
|
|
28
|
+
// Recoverable base candidates = every version except the tip (index 0 ≈ the live document).
|
|
29
|
+
const versions = await this.getVersions();
|
|
30
|
+
const candidates = versions.slice(1);
|
|
31
|
+
// Versions are listed newest-first, and version order is expected to track sequence number, so
|
|
32
|
+
// the first candidate whose seq is at or before the target is taken as the closest base. Because
|
|
33
|
+
// any base at or before the target replays forward to the same state, this early stop is an
|
|
34
|
+
// optimization, not a correctness requirement: if version order and sequence order ever diverge,
|
|
35
|
+
// a base that is valid but not strictly the closest may be chosen.
|
|
36
|
+
// Scanning newest-first also yields the newest of versions sharing a sequence number (dedup).
|
|
37
|
+
let oldestResolvedSeq;
|
|
38
|
+
for (const version of candidates) {
|
|
39
|
+
const sequenceNumber = await this.resolveSeq(version.versionId);
|
|
40
|
+
oldestResolvedSeq =
|
|
41
|
+
oldestResolvedSeq === undefined
|
|
42
|
+
? sequenceNumber
|
|
43
|
+
: Math.min(oldestResolvedSeq, sequenceNumber);
|
|
44
|
+
if (sequenceNumber <= target) {
|
|
45
|
+
return { kind: "found", base: { ...version, sequenceNumber } };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { kind: "noBaseVersion", oldestResolvedSeq };
|
|
49
|
+
}
|
|
50
|
+
async listVersions() {
|
|
51
|
+
const versions = await this.getVersions();
|
|
52
|
+
// Resolution order does not matter here, so resolve concurrently; the newest-first array order is
|
|
53
|
+
// preserved by Promise.all regardless of completion order.
|
|
54
|
+
return Promise.all(versions.map(async (version) => ({
|
|
55
|
+
...version,
|
|
56
|
+
sequenceNumber: await this.resolveSeq(version.versionId),
|
|
57
|
+
})));
|
|
58
|
+
}
|
|
59
|
+
async getVersions() {
|
|
60
|
+
// Cache the pending promise, not the awaited value, so concurrent callers share one fetch and a
|
|
61
|
+
// refresh() that runs while the fetch is in flight is not overwritten when the fetch settles.
|
|
62
|
+
this.versionsCache ??= this.fetcher.listFileVersions();
|
|
63
|
+
return this.versionsCache;
|
|
64
|
+
}
|
|
65
|
+
async resolveSeq(versionId) {
|
|
66
|
+
// Cache the pending promise (a version's sequence number never changes) so concurrent callers
|
|
67
|
+
// coalesce and a refresh() is not clobbered by a fetch that was already in flight.
|
|
68
|
+
let pending = this.seqByVersion.get(versionId);
|
|
69
|
+
if (pending === undefined) {
|
|
70
|
+
pending = this.fetcher.resolveSequenceNumber(versionId);
|
|
71
|
+
this.seqByVersion.set(versionId, pending);
|
|
72
|
+
}
|
|
73
|
+
return pending;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.
|
|
78
|
+
*/
|
|
79
|
+
export function createOdspVersionManager(props) {
|
|
80
|
+
return new OdspVersionManager(createOdspFileVersionFetcher(props));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=odspVersionManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"odspVersionManager.js","sourceRoot":"","sources":["../../src/odspVersionManager/odspVersionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AAEH,OAAO,EACN,4BAA4B,GAE5B,MAAM,6BAA6B,CAAC;AA0ErC;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IAI9B,YAAoC,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;QAFnD,iBAAY,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEI,CAAC;IAEjE,OAAO;QACb,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,MAAc;QACzC,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAErC,+FAA+F;QAC/F,iGAAiG;QACjG,4FAA4F;QAC5F,iGAAiG;QACjG,mEAAmE;QACnE,8FAA8F;QAC9F,IAAI,iBAAqC,CAAC;QAC1C,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YAClC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChE,iBAAiB;gBAChB,iBAAiB,KAAK,SAAS;oBAC9B,CAAC,CAAC,cAAc;oBAChB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;YAChD,IAAI,cAAc,IAAI,MAAM,EAAE,CAAC;gBAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,EAAE,CAAC;YAChE,CAAC;QACF,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,YAAY;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,kGAAkG;QAClG,2DAA2D;QAC3D,OAAO,OAAO,CAAC,GAAG,CACjB,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAChC,GAAG,OAAO;YACV,cAAc,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC;SACxD,CAAC,CAAC,CACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW;QACxB,gGAAgG;QAChG,8FAA8F;QAC9F,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,SAAiB;QACzC,8FAA8F;QAC9F,mFAAmF;QACnF,IAAI,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;YACxD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACvC,KAAkC;IAElC,OAAO,IAAI,kBAAkB,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Selects the ODSP file version whose snapshot sits at or before a target Fluid sequence number —\n * the base to load or replay from when materializing a document at a point in time.\n *\n * The selection logic depends on an injected {@link IOdspFileVersionFetcher}, so it is independent of\n * how versions are enumerated and resolved (real ODSP, a test double, or an alternative backend).\n */\n\nimport {\n\tcreateOdspFileVersionFetcher,\n\ttype OdspFileVersionFetcherProps,\n} from \"./odspFileVersionFetcher.js\";\n\n/**\n * A single ODSP file version, as listed by the file's version history.\n */\nexport interface OdspFileVersionRef {\n\t/**\n\t * The version's label (e.g. `\"42.0\"`), used to address the version when fetching it.\n\t */\n\treadonly versionId: string;\n\t/**\n\t * Last-modified timestamp of this version, ISO-8601.\n\t */\n\treadonly lastModifiedDateTime: string;\n}\n\n/**\n * An ODSP file version together with its resolved Fluid sequence number.\n */\nexport interface ResolvedVersion extends OdspFileVersionRef {\n\t/**\n\t * The Fluid sequence number the version's snapshot represents.\n\t */\n\treadonly sequenceNumber: number;\n}\n\n/**\n * Result of resolving the base version for a target sequence number.\n *\n * @remarks\n * There is intentionally no `targetIsLive` case: when the target is at/after the newest recoverable\n * version, the greatest version with `seq <= target` IS that newest version, so it is a normal\n * `found`. A consumer may separately choose to load the live file when the target is near the head.\n */\nexport type BaseForSeq =\n\t| {\n\t\t\t/** A recoverable version with `sequenceNumber <= target` was found. */\n\t\t\treadonly kind: \"found\";\n\t\t\treadonly base: ResolvedVersion;\n\t }\n\t| {\n\t\t\t/** No recoverable version has `sequenceNumber <= target` (target predates retained history). */\n\t\t\treadonly kind: \"noBaseVersion\";\n\t\t\t/** The oldest sequence number that was resolved while searching, if any. */\n\t\t\treadonly oldestResolvedSeq?: number;\n\t };\n\n/**\n * Provides a file's versions and resolves each version's Fluid sequence number. Injected into\n * the version manager so the selection logic does not depend on how versions are fetched.\n */\nexport interface IOdspFileVersionFetcher {\n\t/**\n\t * Enumerate the file's versions, newest-first.\n\t */\n\tlistFileVersions(): Promise<OdspFileVersionRef[]>;\n\t/**\n\t * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a\n\t * wrong value.\n\t */\n\tresolveSequenceNumber(versionId: string): Promise<number>;\n}\n\n/**\n * Selects the file version to use as the base for loading or replaying to a target sequence number.\n */\nexport interface IOdspVersionManager {\n\t/**\n\t * Given a target sequence number, return the closest version at or before it (`found`), or\n\t * `noBaseVersion` if the target predates the oldest retained version.\n\t */\n\tfindBaseForSeq(target: number): Promise<BaseForSeq>;\n}\n\n/**\n * Default {@link IOdspVersionManager}. Caches the version list and resolved sequence numbers. The\n * resolution strategy (eager, newest-to-oldest, stopping at the first usable base) is hidden behind\n * {@link findBaseForSeq} and can change without affecting callers.\n */\nexport class OdspVersionManager implements IOdspVersionManager {\n\tprivate versionsCache: Promise<OdspFileVersionRef[]> | undefined;\n\tprivate readonly seqByVersion = new Map<string, Promise<number>>();\n\n\tpublic constructor(private readonly fetcher: IOdspFileVersionFetcher) {}\n\n\tpublic refresh(): void {\n\t\tthis.versionsCache = undefined;\n\t\tthis.seqByVersion.clear();\n\t}\n\n\tpublic async findBaseForSeq(target: number): Promise<BaseForSeq> {\n\t\t// Recoverable base candidates = every version except the tip (index 0 ≈ the live document).\n\t\tconst versions = await this.getVersions();\n\t\tconst candidates = versions.slice(1);\n\n\t\t// Versions are listed newest-first, and version order is expected to track sequence number, so\n\t\t// the first candidate whose seq is at or before the target is taken as the closest base. Because\n\t\t// any base at or before the target replays forward to the same state, this early stop is an\n\t\t// optimization, not a correctness requirement: if version order and sequence order ever diverge,\n\t\t// a base that is valid but not strictly the closest may be chosen.\n\t\t// Scanning newest-first also yields the newest of versions sharing a sequence number (dedup).\n\t\tlet oldestResolvedSeq: number | undefined;\n\t\tfor (const version of candidates) {\n\t\t\tconst sequenceNumber = await this.resolveSeq(version.versionId);\n\t\t\toldestResolvedSeq =\n\t\t\t\toldestResolvedSeq === undefined\n\t\t\t\t\t? sequenceNumber\n\t\t\t\t\t: Math.min(oldestResolvedSeq, sequenceNumber);\n\t\t\tif (sequenceNumber <= target) {\n\t\t\t\treturn { kind: \"found\", base: { ...version, sequenceNumber } };\n\t\t\t}\n\t\t}\n\t\treturn { kind: \"noBaseVersion\", oldestResolvedSeq };\n\t}\n\n\tpublic async listVersions(): Promise<ResolvedVersion[]> {\n\t\tconst versions = await this.getVersions();\n\t\t// Resolution order does not matter here, so resolve concurrently; the newest-first array order is\n\t\t// preserved by Promise.all regardless of completion order.\n\t\treturn Promise.all(\n\t\t\tversions.map(async (version) => ({\n\t\t\t\t...version,\n\t\t\t\tsequenceNumber: await this.resolveSeq(version.versionId),\n\t\t\t})),\n\t\t);\n\t}\n\n\tprivate async getVersions(): Promise<OdspFileVersionRef[]> {\n\t\t// Cache the pending promise, not the awaited value, so concurrent callers share one fetch and a\n\t\t// refresh() that runs while the fetch is in flight is not overwritten when the fetch settles.\n\t\tthis.versionsCache ??= this.fetcher.listFileVersions();\n\t\treturn this.versionsCache;\n\t}\n\n\tprivate async resolveSeq(versionId: string): Promise<number> {\n\t\t// Cache the pending promise (a version's sequence number never changes) so concurrent callers\n\t\t// coalesce and a refresh() is not clobbered by a fetch that was already in flight.\n\t\tlet pending = this.seqByVersion.get(versionId);\n\t\tif (pending === undefined) {\n\t\t\tpending = this.fetcher.resolveSequenceNumber(versionId);\n\t\t\tthis.seqByVersion.set(versionId, pending);\n\t\t}\n\t\treturn pending;\n\t}\n}\n\n/**\n * Create an {@link IOdspVersionManager} for a specific ODSP file, wired to the real ODSP REST APIs.\n */\nexport function createOdspVersionManager(\n\tprops: OdspFileVersionFetcherProps,\n): IOdspVersionManager {\n\treturn new OdspVersionManager(createOdspFileVersionFetcher(props));\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/odsp-driver";
|
|
8
|
-
export declare const pkgVersion = "2.
|
|
8
|
+
export declare const pkgVersion = "2.113.0-411909";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,gCAAgC,CAAC;AACrD,eAAO,MAAM,UAAU,mBAAmB,CAAC"}
|
package/lib/packageVersion.js
CHANGED