@fluidframework/odsp-driver 3.0.1 → 3.1.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 (139) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +30 -34
  3. package/api-report/odsp-driver.legacy.alpha.api.md +5 -1
  4. package/api-report/odsp-driver.legacy.beta.api.md +5 -1
  5. package/api-report/odsp-driver.point-in-time.legacy.beta.api.md +2 -1
  6. package/dist/epochTracker.d.ts +4 -3
  7. package/dist/epochTracker.d.ts.map +1 -1
  8. package/dist/epochTracker.js +9 -5
  9. package/dist/epochTracker.js.map +1 -1
  10. package/dist/fetchSnapshot.d.ts +2 -2
  11. package/dist/fetchSnapshot.d.ts.map +1 -1
  12. package/dist/fetchSnapshot.js +12 -7
  13. package/dist/fetchSnapshot.js.map +1 -1
  14. package/dist/getFileLink.d.ts +1 -1
  15. package/dist/getFileLink.d.ts.map +1 -1
  16. package/dist/getFileLink.js +16 -11
  17. package/dist/getFileLink.js.map +1 -1
  18. package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  19. package/dist/odspDelayLoadedDeltaStream.js +1 -1
  20. package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
  21. package/dist/odspDocumentDeltaConnection.d.ts +1 -1
  22. package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
  23. package/dist/odspDocumentDeltaConnection.js +6 -3
  24. package/dist/odspDocumentDeltaConnection.js.map +1 -1
  25. package/dist/odspDocumentServiceFactory.d.ts.map +1 -1
  26. package/dist/odspDocumentServiceFactory.js +1 -0
  27. package/dist/odspDocumentServiceFactory.js.map +1 -1
  28. package/dist/odspDocumentServiceFactoryCore.d.ts +4 -1
  29. package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  30. package/dist/odspDocumentServiceFactoryCore.js +11 -5
  31. package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
  32. package/dist/odspDocumentStorageManager.d.ts.map +1 -1
  33. package/dist/odspDocumentStorageManager.js +11 -11
  34. package/dist/odspDocumentStorageManager.js.map +1 -1
  35. package/dist/odspDriverUrlResolverForShareLink.d.ts +5 -0
  36. package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  37. package/dist/odspDriverUrlResolverForShareLink.js +3 -1
  38. package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
  39. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts +1 -0
  40. package/dist/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
  41. package/dist/odspVersionManager/odspFileVersionFetcher.js +6 -2
  42. package/dist/odspVersionManager/odspFileVersionFetcher.js.map +1 -1
  43. package/dist/packageVersion.d.ts +1 -1
  44. package/dist/packageVersion.js +1 -1
  45. package/dist/packageVersion.js.map +1 -1
  46. package/dist/pointInTimeDriver/createPointInTimeDocumentService.d.ts +1 -1
  47. package/dist/pointInTimeDriver/createPointInTimeDocumentService.d.ts.map +1 -1
  48. package/dist/pointInTimeDriver/createPointInTimeDocumentService.js +5 -4
  49. package/dist/pointInTimeDriver/createPointInTimeDocumentService.js.map +1 -1
  50. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +1 -1
  51. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
  52. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js +21 -1
  53. package/dist/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
  54. package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
  55. package/dist/prefetchLatestSnapshot.js +2 -2
  56. package/dist/prefetchLatestSnapshot.js.map +1 -1
  57. package/dist/requestHeaders.d.ts +19 -0
  58. package/dist/requestHeaders.d.ts.map +1 -0
  59. package/dist/requestHeaders.js +48 -0
  60. package/dist/requestHeaders.js.map +1 -0
  61. package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
  62. package/dist/zipItDataRepresentationUtils.js +0 -1
  63. package/dist/zipItDataRepresentationUtils.js.map +1 -1
  64. package/lib/epochTracker.d.ts +4 -3
  65. package/lib/epochTracker.d.ts.map +1 -1
  66. package/lib/epochTracker.js +9 -5
  67. package/lib/epochTracker.js.map +1 -1
  68. package/lib/fetchSnapshot.d.ts +2 -2
  69. package/lib/fetchSnapshot.d.ts.map +1 -1
  70. package/lib/fetchSnapshot.js +12 -7
  71. package/lib/fetchSnapshot.js.map +1 -1
  72. package/lib/getFileLink.d.ts +1 -1
  73. package/lib/getFileLink.d.ts.map +1 -1
  74. package/lib/getFileLink.js +16 -11
  75. package/lib/getFileLink.js.map +1 -1
  76. package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -1
  77. package/lib/odspDelayLoadedDeltaStream.js +1 -1
  78. package/lib/odspDelayLoadedDeltaStream.js.map +1 -1
  79. package/lib/odspDocumentDeltaConnection.d.ts +1 -1
  80. package/lib/odspDocumentDeltaConnection.d.ts.map +1 -1
  81. package/lib/odspDocumentDeltaConnection.js +6 -3
  82. package/lib/odspDocumentDeltaConnection.js.map +1 -1
  83. package/lib/odspDocumentServiceFactory.d.ts.map +1 -1
  84. package/lib/odspDocumentServiceFactory.js +1 -0
  85. package/lib/odspDocumentServiceFactory.js.map +1 -1
  86. package/lib/odspDocumentServiceFactoryCore.d.ts +4 -1
  87. package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -1
  88. package/lib/odspDocumentServiceFactoryCore.js +11 -5
  89. package/lib/odspDocumentServiceFactoryCore.js.map +1 -1
  90. package/lib/odspDocumentStorageManager.d.ts.map +1 -1
  91. package/lib/odspDocumentStorageManager.js +11 -11
  92. package/lib/odspDocumentStorageManager.js.map +1 -1
  93. package/lib/odspDriverUrlResolverForShareLink.d.ts +5 -0
  94. package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
  95. package/lib/odspDriverUrlResolverForShareLink.js +3 -1
  96. package/lib/odspDriverUrlResolverForShareLink.js.map +1 -1
  97. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts +1 -0
  98. package/lib/odspVersionManager/odspFileVersionFetcher.d.ts.map +1 -1
  99. package/lib/odspVersionManager/odspFileVersionFetcher.js +6 -2
  100. package/lib/odspVersionManager/odspFileVersionFetcher.js.map +1 -1
  101. package/lib/packageVersion.d.ts +1 -1
  102. package/lib/packageVersion.js +1 -1
  103. package/lib/packageVersion.js.map +1 -1
  104. package/lib/pointInTimeDriver/createPointInTimeDocumentService.d.ts +1 -1
  105. package/lib/pointInTimeDriver/createPointInTimeDocumentService.d.ts.map +1 -1
  106. package/lib/pointInTimeDriver/createPointInTimeDocumentService.js +5 -4
  107. package/lib/pointInTimeDriver/createPointInTimeDocumentService.js.map +1 -1
  108. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts +1 -1
  109. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.d.ts.map +1 -1
  110. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js +21 -1
  111. package/lib/pointInTimeDriver/odspPointInTimeDocumentService.js.map +1 -1
  112. package/lib/prefetchLatestSnapshot.d.ts.map +1 -1
  113. package/lib/prefetchLatestSnapshot.js +2 -2
  114. package/lib/prefetchLatestSnapshot.js.map +1 -1
  115. package/lib/requestHeaders.d.ts +19 -0
  116. package/lib/requestHeaders.d.ts.map +1 -0
  117. package/lib/requestHeaders.js +44 -0
  118. package/lib/requestHeaders.js.map +1 -0
  119. package/lib/zipItDataRepresentationUtils.d.ts.map +1 -1
  120. package/lib/zipItDataRepresentationUtils.js +0 -1
  121. package/lib/zipItDataRepresentationUtils.js.map +1 -1
  122. package/package.json +11 -11
  123. package/src/epochTracker.ts +9 -1
  124. package/src/fetchSnapshot.ts +17 -4
  125. package/src/getFileLink.ts +21 -7
  126. package/src/odspDelayLoadedDeltaStream.ts +1 -0
  127. package/src/odspDocumentDeltaConnection.ts +6 -0
  128. package/src/odspDocumentServiceFactory.ts +1 -0
  129. package/src/odspDocumentServiceFactoryCore.ts +14 -2
  130. package/src/odspDocumentStorageManager.ts +13 -3
  131. package/src/odspDriverUrlResolverForShareLink.ts +8 -0
  132. package/src/odspVersionManager/DEV.md +5 -1
  133. package/src/odspVersionManager/odspFileVersionFetcher.ts +7 -2
  134. package/src/packageVersion.ts +1 -1
  135. package/src/pointInTimeDriver/createPointInTimeDocumentService.ts +5 -1
  136. package/src/pointInTimeDriver/odspPointInTimeDocumentService.ts +40 -10
  137. package/src/prefetchLatestSnapshot.ts +4 -0
  138. package/src/requestHeaders.ts +56 -0
  139. package/src/zipItDataRepresentationUtils.ts +0 -1
@@ -284,6 +284,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
284
284
  hostSnapshotOptions,
285
285
  snapshotFetchOptions.loadingGroupIds,
286
286
  snapshotFetchOptions.scenarioName,
287
+ true /* avoidPrefetchSnapshotCache */,
287
288
  );
288
289
  method = "networkOnly";
289
290
  } else {
@@ -355,6 +356,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
355
356
  hostSnapshotOptions,
356
357
  snapshotFetchOptions.loadingGroupIds,
357
358
  snapshotFetchOptions.scenarioName,
359
+ false /* avoidPrefetchSnapshotCache */,
358
360
  );
359
361
 
360
362
  // Ensure that failures on both paths are ignored initially.
@@ -412,6 +414,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
412
414
  hostSnapshotOptions,
413
415
  snapshotFetchOptions.loadingGroupIds,
414
416
  snapshotFetchOptions.scenarioName,
417
+ false /* avoidPrefetchSnapshotCache */,
415
418
  );
416
419
  }
417
420
  }
@@ -553,11 +556,13 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
553
556
  hostSnapshotOptions: ISnapshotOptions | undefined,
554
557
  loadingGroupIds: string[] | undefined,
555
558
  scenarioName?: string,
559
+ avoidPrefetchSnapshotCache: boolean = false,
556
560
  ): Promise<ISnapshot | IPrefetchSnapshotContents> {
557
561
  return this.fetchSnapshotFromNetworkCore(
558
562
  hostSnapshotOptions,
559
563
  loadingGroupIds,
560
564
  scenarioName,
565
+ avoidPrefetchSnapshotCache,
561
566
  ).catch((error) => {
562
567
  // Issue #5895:
563
568
  // If we are offline, this error is retryable. But that means that RetriableDocumentStorageService
@@ -576,10 +581,13 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
576
581
  hostSnapshotOptions: ISnapshotOptions | undefined,
577
582
  loadingGroupIds: string[] | undefined,
578
583
  scenarioName?: string,
584
+ avoidPrefetchSnapshotCache: boolean = false,
579
585
  ): Promise<ISnapshot | IPrefetchSnapshotContents> {
580
- // Don't look into cache, if the host specifically tells us so. Also, if request is
581
- // for initial snapshot, don't consult the prefetch cache.
582
- if (!this.hostPolicy.avoidPrefetchSnapshotCache && this.firstSnapshotFetchCall) {
586
+ if (
587
+ !avoidPrefetchSnapshotCache &&
588
+ !this.hostPolicy.avoidPrefetchSnapshotCache &&
589
+ this.firstSnapshotFetchCall
590
+ ) {
583
591
  const prefetchCacheKey = getKeyForCacheEntry(
584
592
  createCacheSnapshotKey(
585
593
  this.odspResolvedUrl,
@@ -668,6 +676,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
668
676
  removeEntries,
669
677
  loadingGroupIds,
670
678
  this.hostPolicy.enableRedeemFallback,
679
+ this.hostPolicy.hostProvidedRequestHeaders,
671
680
  );
672
681
  return odspSnapshot;
673
682
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -709,6 +718,7 @@ export class OdspDocumentStorageService extends OdspDocumentStorageServiceBase {
709
718
  removeEntries,
710
719
  loadingGroupIds,
711
720
  this.hostPolicy.enableRedeemFallback,
721
+ this.hostPolicy.hostProvidedRequestHeaders,
712
722
  );
713
723
  return odspSnapshot;
714
724
  }
@@ -21,6 +21,7 @@ import type { TelemetryLoggerExt } from "@fluidframework/telemetry-utils/interna
21
21
  import { type OdspFluidDataStoreLocator, SharingLinkHeader } from "./contractsPublic.js";
22
22
  import { createOdspUrl } from "./createOdspUrl.js";
23
23
  import { getFileLink } from "./getFileLink.js";
24
+ import { copyRequestHeaders } from "./requestHeaders.js";
24
25
  import { OdspDriverUrlResolver } from "./odspDriverUrlResolver.js";
25
26
  import {
26
27
  getLocatorFromOdspUrl,
@@ -48,6 +49,11 @@ export interface ShareLinkFetcherProps {
48
49
  * Identity type determining the shape of share link as it differs for Enterprise and Consumer users.
49
50
  */
50
51
  identityType: IdentityType;
52
+ /**
53
+ * Host-owned attribution metadata for ODSP requests made while resolving share links.
54
+ * Driver-owned headers take precedence on case-insensitive collisions.
55
+ */
56
+ requestHeaders?: Readonly<Record<string, string>>;
51
57
  }
52
58
 
53
59
  /**
@@ -90,6 +96,7 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
90
96
  this.shareLinkFetcherProps = {
91
97
  ...shareLinkFetcherProps,
92
98
  tokenFetcher: shareLinkFetcherProps.tokenFetcher,
99
+ requestHeaders: copyRequestHeaders(shareLinkFetcherProps.requestHeaders),
93
100
  };
94
101
  }
95
102
  }
@@ -209,6 +216,7 @@ export class OdspDriverUrlResolverForShareLink implements IUrlResolver {
209
216
  this.shareLinkFetcherProps.tokenFetcher,
210
217
  resolvedUrl,
211
218
  this.logger,
219
+ this.shareLinkFetcherProps.requestHeaders,
212
220
  ).catch((error) => {
213
221
  // This should imply that error is a non-retriable error.
214
222
  this.logger.sendErrorEvent({ eventName: "FluidFileUrlError" }, error);
@@ -571,7 +571,11 @@ The injected implementation:
571
571
  document services: a **recoverable** one bound to that base version (its storage is the base
572
572
  snapshot) and a **live** one (its delta storage supplies the ops to replay). Both are created via
573
573
  `createDocumentServiceCore` with a **single shared** `EpochTracker` (the same one the version
574
- manager reads through) — this is the structural lineage guard; see the next question.
574
+ manager reads through) — this is the structural lineage guard; see the next question. The
575
+ point-in-time storage wrapper forces the recoverable service's initial snapshot read to bypass
576
+ both the persistent latest-snapshot cache and the in-memory snapshot-prefetch cache so the
577
+ selected base cannot be replaced by a newer cached live snapshot. Both loader snapshot paths
578
+ (`getSnapshot` and the legacy `getVersions` + `getSnapshotTree` path) apply this rule.
575
579
  3. Return an `OdspPointInTimeDocumentService` composing the two.
576
580
 
577
581
  It lives in this package rather than a generic wrapping driver (e.g. `@fluidframework/replay-driver`)
@@ -28,6 +28,7 @@ import { convertOdspSnapshotToSnapshotTreeAndBlobs } from "../odspSnapshotParser
28
28
  import { getApiRoot } from "../odspUrlHelper.js";
29
29
  import { fetchArray, getWithRetryForTokenRefresh } from "../odspUtils.js";
30
30
  import { pkgVersion as driverVersion } from "../packageVersion.js";
31
+ import { mergeRequestHeaders } from "../requestHeaders.js";
31
32
 
32
33
  /**
33
34
  * A single ODSP file version, as listed by the file's version history.
@@ -96,6 +97,7 @@ export interface OdspFileVersionFetcherProps {
96
97
  readonly getAuthHeader: InstrumentedStorageTokenFetcher;
97
98
  readonly epochTracker: EpochTracker;
98
99
  readonly logger: TelemetryLoggerExt;
100
+ readonly requestHeaders?: Readonly<Record<string, string>>;
99
101
  }
100
102
 
101
103
  /**
@@ -104,7 +106,7 @@ export interface OdspFileVersionFetcherProps {
104
106
  export function createOdspFileVersionFetcher(
105
107
  props: OdspFileVersionFetcherProps,
106
108
  ): IOdspFileVersionFetcher {
107
- const { urlParts, getAuthHeader, epochTracker, logger } = props;
109
+ const { urlParts, getAuthHeader, epochTracker, logger, requestHeaders } = props;
108
110
  const { siteUrl, driveId, itemId } = urlParts;
109
111
 
110
112
  const listFileVersions = async (): Promise<OdspFileVersionRef[]> =>
@@ -209,7 +211,10 @@ export function createOdspFileVersionFetcher(
209
211
  scenarioName,
210
212
  );
211
213
  const headers = getHeadersWithAuth(token);
212
- const response = await fetchArray(url, { method, headers });
214
+ const response = await fetchArray(url, {
215
+ method,
216
+ headers: mergeRequestHeaders(requestHeaders, headers),
217
+ });
213
218
  return response.headers.get("x-fluid-epoch") ?? undefined;
214
219
  });
215
220
 
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/odsp-driver";
9
- export const pkgVersion = "3.0.1";
9
+ export const pkgVersion = "3.1.0";
@@ -51,6 +51,7 @@ async function createVersionManager(
51
51
  logger: TelemetryLoggerExt,
52
52
  epochTracker: EpochTracker,
53
53
  getStorageToken: IOdspPointInTimeDocumentServiceImplementationProps["getStorageToken"],
54
+ requestHeaders?: Readonly<Record<string, string>>,
54
55
  ): Promise<IOdspVersionManager> {
55
56
  const urlParts: IOdspUrlParts = {
56
57
  siteUrl: odspResolvedUrl.siteUrl,
@@ -67,6 +68,7 @@ async function createVersionManager(
67
68
  getAuthHeader,
68
69
  epochTracker,
69
70
  logger,
71
+ requestHeaders,
70
72
  });
71
73
  }
72
74
 
@@ -120,6 +122,7 @@ export async function createPointInTimeDocumentServiceCore(
120
122
  clientIsSummarizer,
121
123
  persistedCache,
122
124
  getStorageToken,
125
+ requestHeaders,
123
126
  createDocumentService,
124
127
  }: IOdspPointInTimeDocumentServiceImplementationProps,
125
128
  dependencies: IPointInTimeDocumentServiceDependencies = {},
@@ -137,12 +140,13 @@ export async function createPointInTimeDocumentServiceCore(
137
140
  },
138
141
  extLogger,
139
142
  clientIsSummarizer,
143
+ requestHeaders,
140
144
  );
141
145
 
142
146
  const versionManager = await (
143
147
  dependencies.createVersionManager ??
144
148
  (async (url, versionLogger, epochTracker) =>
145
- createVersionManager(url, versionLogger, epochTracker, getStorageToken))
149
+ createVersionManager(url, versionLogger, epochTracker, getStorageToken, requestHeaders))
146
150
  )(odspResolvedUrl, extLogger, cacheAndTracker.epochTracker);
147
151
  const baseResult = await versionManager.findBaseForSeq(targetSequenceNumber);
148
152
  if (baseResult.kind === "noBaseVersion") {
@@ -4,16 +4,45 @@
4
4
  */
5
5
 
6
6
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
- import type {
8
- IClient,
9
- IDocumentDeltaConnection,
10
- IDocumentDeltaStorageService,
11
- IDocumentService,
12
- IDocumentServiceEvents,
13
- IDocumentServicePolicies,
14
- IDocumentStorageService,
15
- IResolvedUrl,
7
+ import {
8
+ FetchSource,
9
+ type IClient,
10
+ type IDocumentDeltaConnection,
11
+ type IDocumentDeltaStorageService,
12
+ type IDocumentService,
13
+ type IDocumentServiceEvents,
14
+ type IDocumentServicePolicies,
15
+ type IDocumentStorageService,
16
+ type IResolvedUrl,
17
+ type ISnapshot,
18
+ type ISnapshotFetchOptions,
19
+ type IVersion,
16
20
  } from "@fluidframework/driver-definitions/internal";
21
+ import { DocumentStorageServiceProxy } from "@fluidframework/driver-utils/internal";
22
+
23
+ /**
24
+ * Forces point-in-time snapshot reads to bypass caches while forwarding all other storage operations
25
+ * to the selected historical document service.
26
+ */
27
+ class PointInTimeDocumentStorageService extends DocumentStorageServiceProxy {
28
+ public override async getSnapshot(
29
+ snapshotFetchOptions?: ISnapshotFetchOptions,
30
+ ): Promise<ISnapshot> {
31
+ return super.getSnapshot({
32
+ ...snapshotFetchOptions,
33
+ fetchSource: FetchSource.noCache,
34
+ });
35
+ }
36
+
37
+ public override async getVersions(
38
+ // eslint-disable-next-line @rushstack/no-new-null -- IDocumentStorageService is a legacy API that requires null.
39
+ versionId: string | null,
40
+ count: number,
41
+ scenarioName?: string,
42
+ ): Promise<IVersion[]> {
43
+ return super.getVersions(versionId, count, scenarioName, FetchSource.noCache);
44
+ }
45
+ }
17
46
 
18
47
  /**
19
48
  * A read-only document service that materializes a document at a target sequence number by combining
@@ -64,7 +93,8 @@ export class OdspPointInTimeDocumentService
64
93
  }
65
94
 
66
95
  public async connectToStorage(): Promise<IDocumentStorageService> {
67
- return this.recoverableDocumentService.connectToStorage();
96
+ const storage = await this.recoverableDocumentService.connectToStorage();
97
+ return new PointInTimeDocumentStorageService(storage);
68
98
  }
69
99
 
70
100
  public async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {
@@ -113,6 +113,9 @@ export async function prefetchLatestSnapshot(
113
113
  odspLogger,
114
114
  undefined,
115
115
  controller,
116
+ undefined,
117
+ undefined,
118
+ odspDocumentServiceFactory?.requestHeaders,
116
119
  );
117
120
  };
118
121
  const snapshotKey = createCacheSnapshotKey(odspResolvedUrl, useGroupIdsForSnapshotFetch);
@@ -150,6 +153,7 @@ export async function prefetchLatestSnapshot(
150
153
  removeEntries,
151
154
  loadingGroupIds,
152
155
  enableRedeemFallback,
156
+ odspDocumentServiceFactory?.requestHeaders,
153
157
  )
154
158
  .then(async (value) => {
155
159
  assert(!!snapshotEpoch, 0x585 /* prefetched snapshot should have a valid epoch */);
@@ -0,0 +1,56 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ const driverOwnedHeaderNames = new Set([
7
+ "authorization",
8
+ "content-type",
9
+ "x-fluid-epoch",
10
+ "x-http-method-override",
11
+ "x-requeststats",
12
+ ]);
13
+
14
+ /**
15
+ * Creates an immutable snapshot of host-provided per-session headers after removing names owned by
16
+ * the ODSP driver. The factory, URL resolver, epoch tracker, and Socket.IO connection use the
17
+ * returned value so later host mutations cannot change an active document session or override
18
+ * authentication and protocol headers.
19
+ */
20
+ export function copyRequestHeaders(
21
+ requestHeaders: Readonly<Record<string, string>> | undefined,
22
+ ): Readonly<Record<string, string>> | undefined {
23
+ if (requestHeaders === undefined || Object.keys(requestHeaders).length === 0) {
24
+ return undefined;
25
+ }
26
+ const copiedHeaders = Object.fromEntries(
27
+ Object.entries(requestHeaders).filter(
28
+ ([name]) => !driverOwnedHeaderNames.has(name.toLowerCase()),
29
+ ),
30
+ );
31
+ return Object.keys(copiedHeaders).length === 0 ? undefined : Object.freeze(copiedHeaders);
32
+ }
33
+
34
+ /**
35
+ * Adds sanitized host headers to one ODSP request. Request-specific headers are applied last, so
36
+ * driver-generated values win case-insensitive collisions. ODSP fetch paths use this helper for
37
+ * snapshot, delta, blob, share-link, file-link, and version requests; Socket.IO applies the copied
38
+ * headers separately as Node.js `extraHeaders`.
39
+ */
40
+ export function mergeRequestHeaders(
41
+ hostHeaders: Readonly<Record<string, string>> | undefined,
42
+ requestHeaders: HeadersInit | undefined,
43
+ ): HeadersInit | undefined {
44
+ const safeHostHeaders = copyRequestHeaders(hostHeaders);
45
+ if (safeHostHeaders === undefined) {
46
+ return requestHeaders;
47
+ }
48
+
49
+ const merged = new Headers(safeHostHeaders);
50
+ if (requestHeaders !== undefined) {
51
+ for (const [key, value] of new Headers(requestHeaders)) {
52
+ merged.set(key, value);
53
+ }
54
+ }
55
+ return Object.fromEntries(merged);
56
+ }
@@ -541,7 +541,6 @@ export class NodeCore {
541
541
 
542
542
  length = 0;
543
543
  const input = buffer.buffer;
544
- assert(input.byteOffset === 0, 0x3e8 /* code below assumes no offset */);
545
544
 
546
545
  for (const el of stringsToResolve) {
547
546
  for (let it = el.startPos; it < el.endPos; it++) {