@fluidframework/odsp-driver 2.113.1 → 2.115.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/api-extractor/api-extractor-lint-legacyAlpha.cjs.json +5 -0
  3. package/api-extractor/api-extractor-lint-legacyAlpha.esm.json +5 -0
  4. package/api-extractor/api-extractor.legacy.json +5 -1
  5. package/api-report/odsp-driver.legacy.alpha.api.md +232 -0
  6. package/dist/getUrlAndHeadersWithAuth.d.ts +4 -0
  7. package/dist/getUrlAndHeadersWithAuth.d.ts.map +1 -1
  8. package/dist/getUrlAndHeadersWithAuth.js +4 -0
  9. package/dist/getUrlAndHeadersWithAuth.js.map +1 -1
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/legacy.d.ts +1 -1
  15. package/dist/legacyAlpha.d.ts +49 -0
  16. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts +40 -1
  17. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
  18. package/dist/odspVersionManager/odspFileVersionFetcher.js +52 -14
  19. package/dist/odspVersionManager/odspFileVersionFetcher.js.map +1 -1
  20. package/dist/odspVersionManager/odspVersionManager.d.ts +23 -45
  21. package/dist/odspVersionManager/odspVersionManager.d.ts.map +1 -1
  22. package/dist/odspVersionManager/odspVersionManager.js +68 -33
  23. package/dist/odspVersionManager/odspVersionManager.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.js +1 -1
  26. package/dist/packageVersion.js.map +1 -1
  27. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +5 -0
  28. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
  29. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js +6 -3
  30. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
  31. package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts +25 -33
  32. package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts.map +1 -1
  33. package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js +62 -38
  34. package/dist/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js.map +1 -1
  35. package/dist/public.d.ts +1 -1
  36. package/internal.d.ts +1 -1
  37. package/legacy/alpha.d.ts +11 -0
  38. package/legacy.d.ts +1 -1
  39. package/lib/getUrlAndHeadersWithAuth.d.ts +4 -0
  40. package/lib/getUrlAndHeadersWithAuth.d.ts.map +1 -1
  41. package/lib/getUrlAndHeadersWithAuth.js +4 -0
  42. package/lib/getUrlAndHeadersWithAuth.js.map +1 -1
  43. package/lib/index.d.ts +3 -2
  44. package/lib/index.d.ts.map +1 -1
  45. package/lib/index.js +5 -3
  46. package/lib/index.js.map +1 -1
  47. package/lib/legacy.d.ts +1 -1
  48. package/lib/legacyAlpha.d.ts +49 -0
  49. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts +40 -1
  50. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
  51. package/lib/odspVersionManager/odspFileVersionFetcher.js +53 -15
  52. package/lib/odspVersionManager/odspFileVersionFetcher.js.map +1 -1
  53. package/lib/odspVersionManager/odspVersionManager.d.ts +23 -45
  54. package/lib/odspVersionManager/odspVersionManager.d.ts.map +1 -1
  55. package/lib/odspVersionManager/odspVersionManager.js +68 -33
  56. package/lib/odspVersionManager/odspVersionManager.js.map +1 -1
  57. package/lib/packageVersion.d.ts +1 -1
  58. package/lib/packageVersion.js +1 -1
  59. package/lib/packageVersion.js.map +1 -1
  60. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +5 -0
  61. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
  62. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js +6 -3
  63. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
  64. package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts +25 -33
  65. package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.d.ts.map +1 -1
  66. package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js +62 -38
  67. package/lib/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js.map +1 -1
  68. package/lib/public.d.ts +1 -1
  69. package/package.json +29 -17
  70. package/src/getUrlAndHeadersWithAuth.ts +4 -0
  71. package/src/index.ts +8 -3
  72. package/src/odspVersionManager/DEV.md +376 -54
  73. package/src/odspVersionManager/odspFileVersionFetcher.ts +111 -16
  74. package/src/odspVersionManager/odspVersionManager.ts +106 -68
  75. package/src/packageVersion.ts +1 -1
  76. package/src/pointInTimeDriver/odspPointInTimeDocumentService.ts +8 -4
  77. package/src/pointInTimeDriver/odspPointInTimeDocumentServiceFactory.ts +123 -48
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.OdspPointInTimeDocumentServiceFactory = void 0;
7
+ exports.getOdspPointInTimeDocumentServiceFactory = void 0;
8
8
  const internal_1 = require("@fluidframework/telemetry-utils/internal");
9
9
  const epochTracker_js_1 = require("../epochTracker.js");
10
10
  const odspCache_js_1 = require("../odspCache.js");
@@ -13,20 +13,15 @@ const odspDriverUrlResolver_js_1 = require("../odspDriverUrlResolver.js");
13
13
  const odspUtils_js_1 = require("../odspUtils.js");
14
14
  const index_js_1 = require("../odspVersionManager/index.js");
15
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
16
  class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCore_js_1.OdspDocumentServiceFactoryCore {
17
+ /**
18
+ * Creates a point-in-time-capable ODSP document service factory.
19
+ *
20
+ * @param getStorageToken - Fetches storage access tokens.
21
+ * @param getWebsocketToken - Fetches websocket access tokens, or `undefined` when unavailable.
22
+ * @param persistedCache - Optional persisted ODSP cache.
23
+ * @param hostPolicy - Optional host storage policy.
24
+ */
30
25
  constructor(getStorageToken, getWebsocketToken, persistedCache, hostPolicy) {
31
26
  super(getStorageToken, getWebsocketToken, persistedCache, hostPolicy);
32
27
  this.getStorageTokenForVersions = getStorageToken;
@@ -35,9 +30,33 @@ class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCo
35
30
  * Creates a document service that reads its snapshot from the closest file version at or before
36
31
  * the target and its deltas from the live document, materializing a requested sequence number
37
32
  * through replay.
33
+ *
34
+ * @param resolvedUrl - The resolved ODSP document URL.
35
+ * @param targetSequenceNumber - The sequence number at which to materialize the document.
36
+ * @param logger - Optional telemetry logger.
37
+ * @param clientIsSummarizer - Whether the requesting client is a summarizer.
38
+ * @returns A read-only document service materialized at the requested sequence number.
38
39
  */
39
40
  async createPointInTimeDocumentService(resolvedUrl, targetSequenceNumber, logger, clientIsSummarizer) {
40
- const versionManager = await this.createVersionManager(resolvedUrl, logger, clientIsSummarizer);
41
+ const odspLogger = (0, odspUtils_js_1.createOdspLogger)(logger);
42
+ const extLogger = (0, internal_1.createChildLogger)({ logger: odspLogger });
43
+ const odspResolvedUrl = (0, odspUtils_js_1.getOdspResolvedUrl)(resolvedUrl);
44
+ // Build ONE cache-and-tracker and thread its EpochTracker through every read this method
45
+ // makes: the version-history reads that pick the base, the recoverable base snapshot, and the
46
+ // live op stream. This shared tracker IS the lineage guard.
47
+ //
48
+ // ODSP stamps each response with the file's epoch; an EpochTracker instance pins itself to the
49
+ // first epoch it sees and throws on any later divergence (see setEpoch / checkForEpochError in
50
+ // epochTracker.ts).
51
+ //
52
+ // A fresh NonPersistentCache keeps this read-only historical load isolated from the factory's
53
+ // shared cache, so a base file version's snapshot can never leak into a normal live load.
54
+ const cacheAndTracker = (0, epochTracker_js_1.createOdspCacheAndTracker)(this.persistedCache, new odspCache_js_1.NonPersistentCache(), {
55
+ resolvedUrl: odspResolvedUrl,
56
+ docId: odspResolvedUrl.hashedDocumentId,
57
+ fileVersion: odspResolvedUrl.fileVersion,
58
+ }, extLogger, clientIsSummarizer);
59
+ const versionManager = this.createVersionManager(odspResolvedUrl, extLogger, cacheAndTracker.epochTracker);
41
60
  const baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);
42
61
  if (baseResult.kind === "noBaseVersion") {
43
62
  const oldestResolvedSequenceDetail = baseResult.oldestResolvedSeq === undefined
@@ -46,8 +65,10 @@ class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCo
46
65
  throw new internal_1.UsageError(`No ODSP file version is available at or before sequence number ${targetSequenceNumber}.${oldestResolvedSequenceDetail}`);
47
66
  }
48
67
  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);
68
+ // Both services are created via createDocumentServiceCore with the shared cacheAndTracker, so
69
+ // their reads validate against the same epoch - see the lineage-guard note above.
70
+ const recoverableDocumentService = await this.createDocumentServiceCore(recoverableResolvedUrl, odspLogger, cacheAndTracker, clientIsSummarizer);
71
+ const liveDocumentService = await this.createDocumentServiceCore(resolvedUrl, odspLogger, cacheAndTracker, clientIsSummarizer);
51
72
  return new odspPointInTimeDocumentService_js_1.OdspPointInTimeDocumentService(recoverableResolvedUrl, recoverableDocumentService, liveDocumentService, targetSequenceNumber);
52
73
  }
53
74
  /**
@@ -55,35 +76,24 @@ class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCo
55
76
  * versions and resolves the closest version at or before a target sequence number.
56
77
  *
57
78
  * @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.
79
+ * The caller passes in the shared {@link EpochTracker} so the version-history reads validate
80
+ * against the same epoch as the recoverable and live document services - this is the lineage
81
+ * guard used by `createPointInTimeDocumentService`.
82
+ * The manager itself only needs the URL parts and an instrumented storage-token/auth-header
83
+ * fetcher wired to that tracker.
64
84
  */
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);
85
+ createVersionManager(odspResolvedUrl, logger, epochTracker) {
69
86
  const urlParts = {
70
87
  siteUrl: odspResolvedUrl.siteUrl,
71
88
  driveId: odspResolvedUrl.driveId,
72
89
  itemId: odspResolvedUrl.itemId,
73
90
  };
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);
91
+ const getAuthHeader = (0, odspUtils_js_1.toInstrumentedOdspStorageTokenFetcher)(logger, urlParts, this.getStorageTokenForVersions);
82
92
  return (0, index_js_1.createOdspVersionManager)({
83
93
  urlParts,
84
94
  getAuthHeader,
85
- epochTracker: cacheAndTracker.epochTracker,
86
- logger: extLogger,
95
+ epochTracker,
96
+ logger,
87
97
  });
88
98
  }
89
99
  async resolveFileVersion(resolvedUrl, fileVersion) {
@@ -104,5 +114,19 @@ class OdspPointInTimeDocumentServiceFactory extends odspDocumentServiceFactoryCo
104
114
  });
105
115
  }
106
116
  }
107
- exports.OdspPointInTimeDocumentServiceFactory = OdspPointInTimeDocumentServiceFactory;
117
+ /**
118
+ * Creates an ODSP document service factory that supports point-in-time loading.
119
+ *
120
+ * @param getStorageToken - Fetches storage access tokens.
121
+ * @param getWebsocketToken - Fetches websocket access tokens, or `undefined` when unavailable.
122
+ * @param persistedCache - Optional persisted ODSP cache.
123
+ * @param hostPolicy - Optional host storage policy.
124
+ * @returns An ODSP document service factory with point-in-time loading capability.
125
+ *
126
+ * @legacy @alpha
127
+ */
128
+ function getOdspPointInTimeDocumentServiceFactory(getStorageToken, getWebsocketToken, persistedCache, hostPolicy) {
129
+ return new OdspPointInTimeDocumentServiceFactory(getStorageToken, getWebsocketToken, persistedCache, hostPolicy);
130
+ }
131
+ exports.getOdspPointInTimeDocumentServiceFactory = getOdspPointInTimeDocumentServiceFactory;
108
132
  //# sourceMappingURL=odspPointInTimeDocumentServiceFactory.js.map
@@ -1 +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"]}
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\tIDocumentServiceFactory,\n\tIPersistedCache,\n\tIResolvedUrl,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tHostStoragePolicy,\n\tIOdspResolvedUrl,\n\tIOdspUrlParts,\n\tOdspResourceTokenFetchOptions,\n\tTokenFetcher,\n} from \"@fluidframework/odsp-driver-definitions/internal\";\nimport {\n\tUsageError,\n\tcreateChildLogger,\n\ttype TelemetryLoggerExt,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport { createOdspCacheAndTracker, type EpochTracker } 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 * An ODSP document service factory that supports point-in-time (sequence-number-based) loading.\n *\n * @remarks\n * The loader detects this capability structurally, so hosts can pass this factory directly to\n * `loadContainerToSequenceNumber`.\n *\n * @legacy @alpha\n */\nexport interface IPointInTimeDocumentServiceFactory extends IDocumentServiceFactory {\n\t/**\n\t * Creates a document service that materializes the document at the requested sequence number.\n\t *\n\t * @param resolvedUrl - The resolved ODSP document URL.\n\t * @param targetSequenceNumber - The sequence number at which to materialize the document.\n\t * @param logger - Optional telemetry logger.\n\t * @param clientIsSummarizer - Whether the requesting client is a summarizer.\n\t * @returns A read-only document service materialized at the requested sequence number.\n\t */\n\tcreatePointInTimeDocumentService(\n\t\tresolvedUrl: IResolvedUrl,\n\t\ttargetSequenceNumber: number,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tclientIsSummarizer?: boolean,\n\t): Promise<IDocumentService>;\n}\n\nclass OdspPointInTimeDocumentServiceFactory\n\textends OdspDocumentServiceFactoryCore\n\timplements IPointInTimeDocumentServiceFactory\n{\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\t/**\n\t * Creates a point-in-time-capable ODSP document service factory.\n\t *\n\t * @param getStorageToken - Fetches storage access tokens.\n\t * @param getWebsocketToken - Fetches websocket access tokens, or `undefined` when unavailable.\n\t * @param persistedCache - Optional persisted ODSP cache.\n\t * @param hostPolicy - Optional host storage policy.\n\t */\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\t * @param resolvedUrl - The resolved ODSP document URL.\n\t * @param targetSequenceNumber - The sequence number at which to materialize the document.\n\t * @param logger - Optional telemetry logger.\n\t * @param clientIsSummarizer - Whether the requesting client is a summarizer.\n\t * @returns A read-only document service materialized at the requested sequence number.\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 odspLogger = createOdspLogger(logger);\n\t\tconst extLogger = createChildLogger({ logger: odspLogger });\n\t\tconst odspResolvedUrl = getOdspResolvedUrl(resolvedUrl);\n\n\t\t// Build ONE cache-and-tracker and thread its EpochTracker through every read this method\n\t\t// makes: the version-history reads that pick the base, the recoverable base snapshot, and the\n\t\t// live op stream. This shared tracker IS the lineage guard.\n\t\t//\n\t\t// ODSP stamps each response with the file's epoch; an EpochTracker instance pins itself to the\n\t\t// first epoch it sees and throws on any later divergence (see setEpoch / checkForEpochError in\n\t\t// epochTracker.ts).\n\t\t//\n\t\t// A fresh NonPersistentCache keeps this read-only historical load isolated from the factory's\n\t\t// shared cache, so a base file version's snapshot can never leak into a normal live load.\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\n\t\tconst versionManager = this.createVersionManager(\n\t\t\todspResolvedUrl,\n\t\t\textLogger,\n\t\t\tcacheAndTracker.epochTracker,\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\t// Both services are created via createDocumentServiceCore with the shared cacheAndTracker, so\n\t\t// their reads validate against the same epoch - see the lineage-guard note above.\n\t\tconst recoverableDocumentService = await this.createDocumentServiceCore(\n\t\t\trecoverableResolvedUrl,\n\t\t\todspLogger,\n\t\t\tcacheAndTracker,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\tconst liveDocumentService = await this.createDocumentServiceCore(\n\t\t\tresolvedUrl,\n\t\t\todspLogger,\n\t\t\tcacheAndTracker,\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 * The caller passes in the shared {@link EpochTracker} so the version-history reads validate\n\t * against the same epoch as the recoverable and live document services - this is the lineage\n\t * guard used by `createPointInTimeDocumentService`.\n\t * The manager itself only needs the URL parts and an instrumented storage-token/auth-header\n\t * fetcher wired to that tracker.\n\t */\n\tprivate createVersionManager(\n\t\todspResolvedUrl: IOdspResolvedUrl,\n\t\tlogger: TelemetryLoggerExt,\n\t\tepochTracker: EpochTracker,\n\t): IOdspVersionManager {\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\tconst getAuthHeader = toInstrumentedOdspStorageTokenFetcher(\n\t\t\tlogger,\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,\n\t\t\tlogger,\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\n/**\n * Creates an ODSP document service factory that supports point-in-time loading.\n *\n * @param getStorageToken - Fetches storage access tokens.\n * @param getWebsocketToken - Fetches websocket access tokens, or `undefined` when unavailable.\n * @param persistedCache - Optional persisted ODSP cache.\n * @param hostPolicy - Optional host storage policy.\n * @returns An ODSP document service factory with point-in-time loading capability.\n *\n * @legacy @alpha\n */\nexport function getOdspPointInTimeDocumentServiceFactory(\n\tgetStorageToken: TokenFetcher<OdspResourceTokenFetchOptions>,\n\tgetWebsocketToken: TokenFetcher<OdspResourceTokenFetchOptions> | undefined,\n\tpersistedCache?: IPersistedCache,\n\thostPolicy?: HostStoragePolicy,\n): IPointInTimeDocumentServiceFactory {\n\treturn new OdspPointInTimeDocumentServiceFactory(\n\t\tgetStorageToken,\n\t\tgetWebsocketToken,\n\t\tpersistedCache,\n\t\thostPolicy,\n\t);\n}\n"]}
package/dist/public.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./dist" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {}
package/internal.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export * from "./lib/index.js";
@@ -0,0 +1,11 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /*
7
+ * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
+ */
10
+
11
+ export * from "../lib/legacyAlpha.js";
package/legacy.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export * from "./lib/legacy.js";
@@ -2,6 +2,10 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ /**
6
+ * Builds the request headers carrying the given Authorization header value.
7
+ * @internal
8
+ */
5
9
  export declare function getHeadersWithAuth(authHeader: string | null): {
6
10
  [index: string]: string;
7
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getUrlAndHeadersWithAuth.d.ts","sourceRoot":"","sources":["../src/getUrlAndHeadersWithAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,kBAAkB,CAEjC,UAAU,EAAE,MAAM,GAAG,IAAI,GACvB;IAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAM7B"}
1
+ {"version":3,"file":"getUrlAndHeadersWithAuth.d.ts","sourceRoot":"","sources":["../src/getUrlAndHeadersWithAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;GAGG;AACH,wBAAgB,kBAAkB,CAEjC,UAAU,EAAE,MAAM,GAAG,IAAI,GACvB;IAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAM7B"}
@@ -3,6 +3,10 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { assert } from "@fluidframework/core-utils/internal";
6
+ /**
7
+ * Builds the request headers carrying the given Authorization header value.
8
+ * @internal
9
+ */
6
10
  export function getHeadersWithAuth(
7
11
  // eslint-disable-next-line @rushstack/no-new-null
8
12
  authHeader) {
@@ -1 +1 @@
1
- {"version":3,"file":"getUrlAndHeadersWithAuth.js","sourceRoot":"","sources":["../src/getUrlAndHeadersWithAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAE7D,MAAM,UAAU,kBAAkB;AACjC,kDAAkD;AAClD,UAAyB;IAEzB,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAEzE,OAAO;QACN,aAAa,EAAE,UAAU;KACzB,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nexport function getHeadersWithAuth(\n\t// eslint-disable-next-line @rushstack/no-new-null\n\tauthHeader: string | null,\n): { [index: string]: string } {\n\tassert(!!authHeader, 0x936 /* authHeader should not be null or empty */);\n\n\treturn {\n\t\tAuthorization: authHeader,\n\t};\n}\n"]}
1
+ {"version":3,"file":"getUrlAndHeadersWithAuth.js","sourceRoot":"","sources":["../src/getUrlAndHeadersWithAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,kBAAkB;AACjC,kDAAkD;AAClD,UAAyB;IAEzB,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAEzE,OAAO;QACN,aAAa,EAAE,UAAU;KACzB,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\n/**\n * Builds the request headers carrying the given Authorization header value.\n * @internal\n */\nexport function getHeadersWithAuth(\n\t// eslint-disable-next-line @rushstack/no-new-null\n\tauthHeader: string | null,\n): { [index: string]: string } {\n\tassert(!!authHeader, 0x936 /* authHeader should not be null or empty */);\n\n\treturn {\n\t\tAuthorization: authHeader,\n\t};\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -7,11 +7,12 @@ export { ClpCompliantAppHeader, type IClpCompliantAppHeader, type ISharingLinkHe
7
7
  export { checkUrl } from "./checkUrl.js";
8
8
  export { createOdspUrl } from "./createOdspUrl.js";
9
9
  export { getHashedDocumentId, type ISnapshotContents } from "./odspPublicUtils.js";
10
- export { getOdspUrlParts, isOdcUrl, isSpoUrl } from "./odspUrlHelper.js";
10
+ export { getApiRoot, getOdspUrlParts, isOdcUrl, isSpoUrl } from "./odspUrlHelper.js";
11
+ export { getHeadersWithAuth } from "./getUrlAndHeadersWithAuth.js";
11
12
  export { prefetchLatestSnapshot } from "./prefetchLatestSnapshot.js";
12
13
  export { createLocalOdspDocumentServiceFactory, OdspDocumentServiceFactory, } from "./odspDocumentServiceFactory.js";
13
14
  export { OdspDocumentServiceFactoryCore } from "./odspDocumentServiceFactoryCore.js";
14
- export { OdspPointInTimeDocumentServiceFactory } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
15
+ export { getOdspPointInTimeDocumentServiceFactory, type IPointInTimeDocumentServiceFactory, } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
15
16
  export { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest.js";
16
17
  export { OdspDriverUrlResolver } from "./odspDriverUrlResolver.js";
17
18
  export { OdspDriverUrlResolverForShareLink, type ShareLinkFetcherProps, } from "./odspDriverUrlResolverForShareLink.js";
@@ -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;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"}
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,UAAU,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,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,EACN,wCAAwC,EACxC,KAAK,kCAAkC,GACvC,MAAM,8DAA8D,CAAC;AAItE,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
@@ -9,14 +9,16 @@ export { ClpCompliantAppHeader, SharingLinkHeader, } from "./contractsPublic.js"
9
9
  export { checkUrl } from "./checkUrl.js";
10
10
  export { createOdspUrl } from "./createOdspUrl.js";
11
11
  export { getHashedDocumentId } from "./odspPublicUtils.js";
12
- export { getOdspUrlParts, isOdcUrl, isSpoUrl } from "./odspUrlHelper.js";
12
+ export { getApiRoot, getOdspUrlParts, isOdcUrl, isSpoUrl } from "./odspUrlHelper.js";
13
+ export { getHeadersWithAuth } from "./getUrlAndHeadersWithAuth.js";
13
14
  // prefetch latest snapshot before container load
14
15
  export { prefetchLatestSnapshot } from "./prefetchLatestSnapshot.js";
15
16
  // Factory
16
17
  export { createLocalOdspDocumentServiceFactory, OdspDocumentServiceFactory, } from "./odspDocumentServiceFactory.js";
17
18
  export { OdspDocumentServiceFactoryCore } from "./odspDocumentServiceFactoryCore.js";
18
- // eslint-disable-next-line import-x/no-internal-modules
19
- export { OdspPointInTimeDocumentServiceFactory } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
19
+ /* eslint-disable import-x/no-internal-modules */
20
+ export { getOdspPointInTimeDocumentServiceFactory, } from "./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js";
21
+ /* eslint-enable import-x/no-internal-modules */
20
22
  // File creation
21
23
  export { createOdspCreateContainerRequest } from "./createOdspCreateContainerRequest.js";
22
24
  // 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;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"]}
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,UAAU,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,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,iDAAiD;AACjD,OAAO,EACN,wCAAwC,GAExC,MAAM,8DAA8D,CAAC;AACtE,gDAAgD;AAEhD,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 { getApiRoot, getOdspUrlParts, isOdcUrl, isSpoUrl } from \"./odspUrlHelper.js\";\nexport { getHeadersWithAuth } from \"./getUrlAndHeadersWithAuth.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 import-x/no-internal-modules */\nexport {\n\tgetOdspPointInTimeDocumentServiceFactory,\n\ttype IPointInTimeDocumentServiceFactory,\n} from \"./pointInTimeDriver/odspPointInTimeDocumentServiceFactory.js\";\n/* eslint-enable import-x/no-internal-modules */\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"]}
package/lib/legacy.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {
@@ -0,0 +1,49 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ /*
7
+ * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
+ * Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outFileLegacyAlpha legacyAlpha --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
+ */
10
+
11
+ export {
12
+ // #region @legacyBeta APIs
13
+ EpochTracker,
14
+ FetchType,
15
+ FetchTypeInternal,
16
+ ICacheAndTracker,
17
+ INonPersistentCache,
18
+ IOdspCache,
19
+ IOdspResponse,
20
+ IPersistedFileCache,
21
+ IPrefetchSnapshotContents,
22
+ ISnapshotContents,
23
+ OdcApiSiteOrigin,
24
+ OdcFileSiteOrigin,
25
+ OdspDocumentServiceFactory,
26
+ OdspDocumentServiceFactoryCore,
27
+ OdspDriverUrlResolver,
28
+ OdspDriverUrlResolverForShareLink,
29
+ OdspFluidDataStoreLocator,
30
+ ShareLinkFetcherProps,
31
+ SnapshotFormatSupportType,
32
+ checkUrl,
33
+ createLocalOdspDocumentServiceFactory,
34
+ createOdspCreateContainerRequest,
35
+ createOdspUrl,
36
+ encodeOdspFluidDataStoreLocator,
37
+ getHashedDocumentId,
38
+ getLocatorFromOdspUrl,
39
+ isOdspResolvedUrl,
40
+ locatorQueryParamName,
41
+ prefetchLatestSnapshot,
42
+ storeLocatorInOdspUrl,
43
+ // #endregion
44
+
45
+ // #region @legacyAlpha APIs
46
+ IPointInTimeDocumentServiceFactory,
47
+ getOdspPointInTimeDocumentServiceFactory
48
+ // #endregion
49
+ } from "./index.js";
@@ -5,7 +5,46 @@
5
5
  import type { IOdspUrlParts, InstrumentedStorageTokenFetcher } from "@fluidframework/odsp-driver-definitions/internal";
6
6
  import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
7
7
  import type { EpochTracker } from "../epochTracker.js";
8
- import type { IOdspFileVersionFetcher } from "./odspVersionManager.js";
8
+ /**
9
+ * A single ODSP file version, as listed by the file's version history.
10
+ */
11
+ export interface OdspFileVersionRef {
12
+ /**
13
+ * The version's label (e.g. `"42.0"`), used to address the version when fetching it.
14
+ */
15
+ readonly versionId: string;
16
+ /**
17
+ * Last-modified timestamp of this version, ISO-8601.
18
+ */
19
+ readonly lastModifiedDateTime: string;
20
+ }
21
+ /**
22
+ * Provides a file's versions and resolves each version's Fluid sequence number. Injected into
23
+ * the version manager so the selection logic does not depend on how versions are fetched.
24
+ */
25
+ export interface IOdspFileVersionFetcher {
26
+ /**
27
+ * Enumerate the file's versions, newest-first.
28
+ */
29
+ listFileVersions(): Promise<OdspFileVersionRef[]>;
30
+ /**
31
+ * Resolve a single version's Fluid sequence number. Throws on failure rather than returning a
32
+ * wrong value.
33
+ */
34
+ resolveSequenceNumber(versionId: string): Promise<number>;
35
+ /**
36
+ * Read the live document's current ODSP epoch (`x-fluid-epoch`), or `undefined`. Epoch identifies
37
+ * the file's binary lineage and changes on a version restore or download-then-reupload; compared
38
+ * with {@link IOdspFileVersionFetcher.getRecoverableVersionEpoch} to confirm a base is on the live
39
+ * document's lineage.
40
+ */
41
+ getLiveDocumentEpoch(): Promise<string | undefined>;
42
+ /**
43
+ * Read the ODSP epoch of a specific file version, or `undefined`. See
44
+ * {@link IOdspFileVersionFetcher.getLiveDocumentEpoch}.
45
+ */
46
+ getRecoverableVersionEpoch(versionId: string): Promise<string | undefined>;
47
+ }
9
48
  /**
10
49
  * Inputs needed to make authenticated requests against a specific ODSP file.
11
50
  */
@@ -1 +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"}
1
+ {"version":3,"file":"odspFileVersionFetcher.d.ts","sourceRoot":"","sources":["../../src/odspVersionManager/odspFileVersionFetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,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;AAOvD;;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;;;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;IAC1D;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD;;;OAGG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3E;AAmBD;;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,CA+HzB"}
@@ -2,11 +2,22 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ /*
6
+ * An {@link IOdspFileVersionFetcher} backed by the ODSP REST APIs:
7
+ * - GET /_api/v2.1/.../versions -- enumerate the file's versions.
8
+ * - GET /_api/v2.1/.../versions/{label}/opStream/snapshots/trees/latest?blobs=2 -- fetch a version's
9
+ * snapshot and read its sequence number, parsed with the driver's snapshot parser.
10
+ * - GET /_api/v2.1/.../[versions/{label}/]opStream/snapshots/trees/latest?blobs=0 -- read a version's
11
+ * or the live document's ODSP epoch (`x-fluid-epoch`) to compare their lineage.
12
+ */
13
+ import { NonRetryableError } from "@fluidframework/driver-utils/internal";
14
+ import { OdspErrorTypes } from "@fluidframework/odsp-driver-definitions/internal";
5
15
  import { currentReadVersion, parseCompactSnapshotResponse } from "../compactSnapshotParser.js";
6
16
  import { getHeadersWithAuth } from "../getUrlAndHeadersWithAuth.js";
7
17
  import { convertOdspSnapshotToSnapshotTreeAndBlobs } from "../odspSnapshotParser.js";
8
18
  import { getApiRoot } from "../odspUrlHelper.js";
9
- import { getWithRetryForTokenRefresh } from "../odspUtils.js";
19
+ import { fetchArray, getWithRetryForTokenRefresh } from "../odspUtils.js";
20
+ import { pkgVersion as driverVersion } from "../packageVersion.js";
10
21
  /**
11
22
  * Create an {@link IOdspFileVersionFetcher} that talks to a specific ODSP file.
12
23
  */
@@ -38,18 +49,14 @@ export function createOdspFileVersionFetcher(props) {
38
49
  return versions;
39
50
  });
40
51
  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.
52
+ // The sequence number lives in the version snapshot's `.protocol/attributes` blob, so fetch the
53
+ // version-scoped snapshot with `blobs=2` to inline it. No op stream needed.
45
54
  const url = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=2`;
46
55
  const method = "GET";
47
56
  const token = await getAuthHeader({ ...options, request: { url, method } }, "FileVersionSnapshot");
48
57
  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.
58
+ // The snapshot comes back as JSON or "ms-fluid" (ODSP's compact binary form). Accept both and
59
+ // pin the binary version (as the driver's snapshot fetch does) so the parser can read it.
53
60
  headers.accept = `application/json, application/ms-fluid; v=${currentReadVersion}`;
54
61
  const response = await epochTracker.fetch(url, { method, headers }, "treesLatest");
55
62
  const contentType = response.headers.get("content-type") ?? "";
@@ -60,18 +67,49 @@ export function createOdspFileVersionFetcher(props) {
60
67
  sequenceNumber =
61
68
  convertOdspSnapshotToSnapshotTreeAndBlobs(snapshotJson).sequenceNumber;
62
69
  }
63
- else {
70
+ else if (contentType.includes("application/ms-fluid")) {
64
71
  // ms-fluid framing: the compact binary form; read it with the driver's compact-snapshot parser.
65
72
  const bytes = new Uint8Array(await response.content.arrayBuffer());
66
73
  sequenceNumber = parseCompactSnapshotResponse(bytes, logger).sequenceNumber;
67
74
  }
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`);
75
+ else {
76
+ // Neither framing (e.g. an HTML error page). Throw the driver's typed bad-response error
77
+ // (like fetchSnapshot.ts): canRetry=false stops the loader re-driving, while the
78
+ // incorrectServerResponse errorType still earns one wire-retry from getWithRetryForTokenRefresh.
79
+ throw new NonRetryableError(`ODSP file version ${versionId} snapshot returned an unexpected content-type`, OdspErrorTypes.incorrectServerResponse, { driverVersion, contentType, accept: headers.accept });
80
+ }
81
+ // The sequence number must be a non-negative integer; a missing or malformed one throws the same
82
+ // typed error as above rather than feeding a wrong value into base selection.
83
+ if (!(typeof sequenceNumber === "number" &&
84
+ Number.isInteger(sequenceNumber) &&
85
+ sequenceNumber >= 0)) {
86
+ throw new NonRetryableError(`ODSP file version ${versionId} snapshot has a missing or invalid sequenceNumber (${String(sequenceNumber)})`, OdspErrorTypes.incorrectServerResponse, { driverVersion, contentType, accept: headers.accept });
72
87
  }
73
88
  return sequenceNumber;
74
89
  });
75
- return { listFileVersions, resolveSequenceNumber };
90
+ const itemRoot = `${getApiRoot(new URL(siteUrl))}/drives/${driveId}/items/${itemId}`;
91
+ // Reads the `x-fluid-epoch` header from `url`. Deliberately uses the raw fetch helper instead of
92
+ // `epochTracker.fetch`: the whole point is to COMPARE the base version's epoch against the live
93
+ // document's epoch, but the shared EpochTracker pins to the first epoch it sees and throws on the
94
+ // second (divergent) read - so it could never yield two epochs to compare. `fetchArray` also lets
95
+ // the body (JSON or ms-fluid binary) be consumed and discarded; only the header is needed.
96
+ const readEpoch = async (url, scenarioName) => getWithRetryForTokenRefresh(async (options) => {
97
+ const method = "GET";
98
+ const token = await getAuthHeader({ ...options, request: { url, method } }, scenarioName);
99
+ const headers = getHeadersWithAuth(token);
100
+ const response = await fetchArray(url, { method, headers });
101
+ return response.headers.get("x-fluid-epoch") ?? undefined;
102
+ });
103
+ const getLiveDocumentEpoch = async () =>
104
+ // The (unversioned) live snapshot endpoint is a current-file read, so its epoch is the live
105
+ // document's epoch. `blobs=0` keeps the response to the tree metadata.
106
+ readEpoch(`${itemRoot}/opStream/snapshots/trees/latest?blobs=0`, "LiveEpoch");
107
+ const getRecoverableVersionEpoch = async (versionId) => readEpoch(`${itemRoot}/versions/${encodeURIComponent(versionId)}/opStream/snapshots/trees/latest?blobs=0`, "FileVersionEpoch");
108
+ return {
109
+ listFileVersions,
110
+ resolveSequenceNumber,
111
+ getLiveDocumentEpoch,
112
+ getRecoverableVersionEpoch,
113
+ };
76
114
  }
77
115
  //# sourceMappingURL=odspFileVersionFetcher.js.map