@fluidframework/container-loader 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.203917
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 +122 -0
- package/api-extractor.json +9 -1
- package/api-report/container-loader.api.md +153 -0
- package/dist/catchUpMonitor.d.ts +2 -2
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/connectionManager.d.ts +2 -15
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +110 -98
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.js +1 -1
- package/dist/connectionState.js.map +1 -1
- package/dist/connectionStateHandler.js +9 -9
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container-loader-alpha.d.ts +333 -0
- package/dist/container-loader-beta.d.ts +333 -0
- package/dist/container-loader-public.d.ts +333 -0
- package/dist/container-loader-untrimmed.d.ts +333 -0
- package/dist/container.d.ts +22 -2
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +235 -222
- package/dist/container.js.map +1 -1
- package/dist/containerContext.js +16 -16
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +9 -11
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +5 -4
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts.map +1 -1
- package/dist/debugLogger.js +5 -4
- package/dist/debugLogger.js.map +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +92 -96
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +14 -14
- package/dist/deltaQueue.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +6 -9
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +26 -91
- package/dist/loader.js.map +1 -1
- package/dist/location-redirection-utilities/index.d.ts +6 -0
- package/dist/location-redirection-utilities/index.d.ts.map +1 -0
- package/dist/location-redirection-utilities/index.js +11 -0
- package/dist/location-redirection-utilities/index.js.map +1 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +22 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +51 -0
- package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +1 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +3 -5
- package/dist/protocol.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +18 -11
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/utils.d.ts +23 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -3
- package/dist/utils.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +2 -2
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/connectionManager.d.ts +2 -15
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +113 -99
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.js +9 -9
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +22 -2
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +236 -223
- package/lib/container.js.map +1 -1
- package/lib/containerContext.js +16 -16
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +9 -11
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +5 -4
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts.map +1 -1
- package/lib/debugLogger.js +5 -4
- package/lib/debugLogger.js.map +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +92 -96
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +14 -14
- package/lib/deltaQueue.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +6 -9
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +27 -92
- package/lib/loader.js.map +1 -1
- package/lib/location-redirection-utilities/index.d.ts +6 -0
- package/lib/location-redirection-utilities/index.d.ts.map +1 -0
- package/lib/location-redirection-utilities/index.js +6 -0
- package/lib/location-redirection-utilities/index.js.map +1 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +22 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +46 -0
- package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +1 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +1 -3
- package/lib/protocol.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +18 -11
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +23 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +9 -1
- package/lib/utils.js.map +1 -1
- package/package.json +24 -26
- package/src/connectionManager.ts +58 -31
- package/src/container.ts +48 -30
- package/src/containerStorageAdapter.ts +3 -9
- package/src/contracts.ts +8 -4
- package/src/debugLogger.ts +5 -1
- package/src/deltaManager.ts +16 -31
- package/src/index.ts +5 -0
- package/src/loader.ts +31 -99
- package/src/location-redirection-utilities/index.ts +9 -0
- package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +59 -0
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +2 -6
- package/src/retriableDocumentStorageService.ts +29 -15
- package/src/utils.ts +23 -1
package/src/loader.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
ITelemetryBaseLogger,
|
|
19
19
|
FluidObject,
|
|
20
|
+
// eslint-disable-next-line import/no-deprecated
|
|
20
21
|
IFluidRouter,
|
|
21
22
|
IRequest,
|
|
22
23
|
IRequestHeader,
|
|
@@ -40,15 +41,11 @@ import {
|
|
|
40
41
|
} from "@fluidframework/driver-definitions";
|
|
41
42
|
import { IClientDetails } from "@fluidframework/protocol-definitions";
|
|
42
43
|
import { Container, IPendingContainerState } from "./container";
|
|
43
|
-
import { IParsedUrl,
|
|
44
|
+
import { IParsedUrl, tryParseCompatibleResolvedUrl } from "./utils";
|
|
44
45
|
import { pkgVersion } from "./packageVersion";
|
|
45
46
|
import { ProtocolHandlerBuilder } from "./protocol";
|
|
46
47
|
import { DebugLogger } from "./debugLogger";
|
|
47
48
|
|
|
48
|
-
function canUseCache(request: IRequest): boolean {
|
|
49
|
-
return request.headers?.[LoaderHeader.cache] === true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
49
|
function ensureResolvedUrlDefined(
|
|
53
50
|
resolved: IResolvedUrl | undefined,
|
|
54
51
|
): asserts resolved is IResolvedUrl {
|
|
@@ -66,31 +63,28 @@ export class RelativeLoader implements ILoader {
|
|
|
66
63
|
) {}
|
|
67
64
|
|
|
68
65
|
/**
|
|
69
|
-
* @deprecated
|
|
66
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
70
67
|
*/
|
|
68
|
+
// eslint-disable-next-line import/no-deprecated
|
|
71
69
|
public get IFluidRouter(): IFluidRouter {
|
|
72
70
|
return this;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
public async resolve(request: IRequest): Promise<IContainer> {
|
|
76
74
|
if (request.url.startsWith("/")) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
},
|
|
91
|
-
);
|
|
92
|
-
return container;
|
|
93
|
-
}
|
|
75
|
+
ensureResolvedUrlDefined(this.container.resolvedUrl);
|
|
76
|
+
const container = await this.container.clone(
|
|
77
|
+
{
|
|
78
|
+
resolvedUrl: { ...this.container.resolvedUrl },
|
|
79
|
+
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
80
|
+
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
|
84
|
+
clientDetailsOverride: request.headers?.[LoaderHeader.clientDetails],
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
return container;
|
|
94
88
|
}
|
|
95
89
|
|
|
96
90
|
if (this.loader === undefined) {
|
|
@@ -100,7 +94,7 @@ export class RelativeLoader implements ILoader {
|
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
/**
|
|
103
|
-
* @deprecated
|
|
97
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
104
98
|
*/
|
|
105
99
|
public async request(request: IRequest): Promise<IResponse> {
|
|
106
100
|
if (request.url.startsWith("/")) {
|
|
@@ -279,18 +273,20 @@ export type IDetachedBlobStorage = Pick<IDocumentStorageService, "createBlob" |
|
|
|
279
273
|
* With an already-resolved container, we can request a component directly, without loading the container again
|
|
280
274
|
* @param container - a resolved container
|
|
281
275
|
* @returns component on the container
|
|
276
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the "entryPoint" pattern. Refer to Removing-IFluidRouter.md
|
|
282
277
|
*/
|
|
283
278
|
export async function requestResolvedObjectFromContainer(
|
|
284
279
|
container: IContainer,
|
|
285
280
|
headers?: IRequestHeader,
|
|
286
281
|
): Promise<IResponse> {
|
|
287
282
|
ensureResolvedUrlDefined(container.resolvedUrl);
|
|
288
|
-
const parsedUrl =
|
|
283
|
+
const parsedUrl = tryParseCompatibleResolvedUrl(container.resolvedUrl.url);
|
|
289
284
|
|
|
290
285
|
if (parsedUrl === undefined) {
|
|
291
286
|
throw new Error(`Invalid URL ${container.resolvedUrl.url}`);
|
|
292
287
|
}
|
|
293
288
|
|
|
289
|
+
// eslint-disable-next-line import/no-deprecated
|
|
294
290
|
const entryPoint: FluidObject<IFluidRouter> | undefined = await container.getEntryPoint?.();
|
|
295
291
|
const router = entryPoint?.IFluidRouter ?? container.IFluidRouter;
|
|
296
292
|
|
|
@@ -304,7 +300,6 @@ export async function requestResolvedObjectFromContainer(
|
|
|
304
300
|
* Manages Fluid resource loading
|
|
305
301
|
*/
|
|
306
302
|
export class Loader implements IHostLoader {
|
|
307
|
-
private readonly containers = new Map<string, Promise<Container>>();
|
|
308
303
|
public readonly services: ILoaderServices;
|
|
309
304
|
private readonly mc: MonitoringContext;
|
|
310
305
|
|
|
@@ -352,8 +347,9 @@ export class Loader implements IHostLoader {
|
|
|
352
347
|
}
|
|
353
348
|
|
|
354
349
|
/**
|
|
355
|
-
* @deprecated
|
|
350
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
356
351
|
*/
|
|
352
|
+
// eslint-disable-next-line import/no-deprecated
|
|
357
353
|
public get IFluidRouter(): IFluidRouter {
|
|
358
354
|
return this;
|
|
359
355
|
}
|
|
@@ -365,25 +361,13 @@ export class Loader implements IHostLoader {
|
|
|
365
361
|
clientDetailsOverride?: IClientDetails;
|
|
366
362
|
},
|
|
367
363
|
): Promise<IContainer> {
|
|
368
|
-
|
|
364
|
+
return Container.createDetached(
|
|
369
365
|
{
|
|
370
366
|
...createDetachedProps,
|
|
371
367
|
...this.services,
|
|
372
368
|
},
|
|
373
369
|
codeDetails,
|
|
374
370
|
);
|
|
375
|
-
|
|
376
|
-
if (this.cachingEnabled) {
|
|
377
|
-
container.once("attached", () => {
|
|
378
|
-
ensureResolvedUrlDefined(container.resolvedUrl);
|
|
379
|
-
const parsedUrl = parseUrl(container.resolvedUrl.url);
|
|
380
|
-
if (parsedUrl !== undefined) {
|
|
381
|
-
this.addToContainerCache(parsedUrl.id, Promise.resolve(container));
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return container;
|
|
387
371
|
}
|
|
388
372
|
|
|
389
373
|
public async rehydrateDetachedContainerFromSnapshot(
|
|
@@ -414,7 +398,7 @@ export class Loader implements IHostLoader {
|
|
|
414
398
|
}
|
|
415
399
|
|
|
416
400
|
/**
|
|
417
|
-
* @deprecated
|
|
401
|
+
* @deprecated Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
418
402
|
*/
|
|
419
403
|
public async request(request: IRequest): Promise<IResponse> {
|
|
420
404
|
return PerformanceEvent.timedExecAsync(
|
|
@@ -430,37 +414,6 @@ export class Loader implements IHostLoader {
|
|
|
430
414
|
);
|
|
431
415
|
}
|
|
432
416
|
|
|
433
|
-
private getKeyForContainerCache(request: IRequest, parsedUrl: IParsedUrl): string {
|
|
434
|
-
const key =
|
|
435
|
-
request.headers?.[LoaderHeader.version] !== undefined
|
|
436
|
-
? `${parsedUrl.id}@${request.headers[LoaderHeader.version]}`
|
|
437
|
-
: parsedUrl.id;
|
|
438
|
-
return key;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
private addToContainerCache(key: string, containerP: Promise<Container>) {
|
|
442
|
-
this.containers.set(key, containerP);
|
|
443
|
-
containerP
|
|
444
|
-
.then((container) => {
|
|
445
|
-
// If the container is closed/disposed or becomes closed/disposed after we resolve it,
|
|
446
|
-
// remove it from the cache.
|
|
447
|
-
if (container.closed || container.disposed) {
|
|
448
|
-
this.containers.delete(key);
|
|
449
|
-
} else {
|
|
450
|
-
container.once("closed", () => {
|
|
451
|
-
this.containers.delete(key);
|
|
452
|
-
});
|
|
453
|
-
container.once("disposed", () => {
|
|
454
|
-
this.containers.delete(key);
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
})
|
|
458
|
-
.catch((error) => {
|
|
459
|
-
// If an error occured while resolving the container request, then remove it from the cache.
|
|
460
|
-
this.containers.delete(key);
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
417
|
private async resolveCore(
|
|
465
418
|
request: IRequest,
|
|
466
419
|
pendingLocalState?: IPendingContainerState,
|
|
@@ -469,13 +422,13 @@ export class Loader implements IHostLoader {
|
|
|
469
422
|
ensureResolvedUrlDefined(resolvedAsFluid);
|
|
470
423
|
|
|
471
424
|
// Parse URL into data stores
|
|
472
|
-
const parsed =
|
|
425
|
+
const parsed = tryParseCompatibleResolvedUrl(resolvedAsFluid.url);
|
|
473
426
|
if (parsed === undefined) {
|
|
474
427
|
throw new Error(`Invalid URL ${resolvedAsFluid.url}`);
|
|
475
428
|
}
|
|
476
429
|
|
|
477
430
|
if (pendingLocalState !== undefined) {
|
|
478
|
-
const parsedPendingUrl =
|
|
431
|
+
const parsedPendingUrl = tryParseCompatibleResolvedUrl(pendingLocalState.url);
|
|
479
432
|
if (
|
|
480
433
|
parsedPendingUrl?.id !== parsed.id ||
|
|
481
434
|
parsedPendingUrl?.path.replace(/\/$/, "") !== parsed.path.replace(/\/$/, "")
|
|
@@ -489,11 +442,6 @@ export class Loader implements IHostLoader {
|
|
|
489
442
|
// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
|
|
490
443
|
request.headers[LoaderHeader.version] =
|
|
491
444
|
parsed.version ?? request.headers[LoaderHeader.version];
|
|
492
|
-
const cacheHeader = request.headers[LoaderHeader.cache];
|
|
493
|
-
const canCache =
|
|
494
|
-
// Take header value if present, else use ILoaderOptions.cache value
|
|
495
|
-
(cacheHeader !== undefined ? cacheHeader === true : this.cachingEnabled) &&
|
|
496
|
-
pendingLocalState === undefined;
|
|
497
445
|
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber] as
|
|
498
446
|
| number
|
|
499
447
|
| undefined;
|
|
@@ -513,26 +461,10 @@ export class Loader implements IHostLoader {
|
|
|
513
461
|
throw new UsageError('opsBeforeReturn must be set to "sequenceNumber"');
|
|
514
462
|
}
|
|
515
463
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (maybeContainer !== undefined) {
|
|
521
|
-
container = maybeContainer;
|
|
522
|
-
} else {
|
|
523
|
-
const containerP = this.loadContainer(request, resolvedAsFluid);
|
|
524
|
-
this.addToContainerCache(key, containerP);
|
|
525
|
-
container = await containerP;
|
|
526
|
-
}
|
|
527
|
-
} else {
|
|
528
|
-
container = await this.loadContainer(request, resolvedAsFluid, pendingLocalState);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return { container, parsed };
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
private get cachingEnabled() {
|
|
535
|
-
return this.services.options.cache === true;
|
|
464
|
+
return {
|
|
465
|
+
container: await this.loadContainer(request, resolvedAsFluid, pendingLocalState),
|
|
466
|
+
parsed,
|
|
467
|
+
};
|
|
536
468
|
}
|
|
537
469
|
|
|
538
470
|
private async loadContainer(
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ITelemetryBaseLogger, IRequest } from "@fluidframework/core-interfaces";
|
|
7
|
+
import {
|
|
8
|
+
DriverErrorTypes,
|
|
9
|
+
ILocationRedirectionError,
|
|
10
|
+
IUrlResolver,
|
|
11
|
+
} from "@fluidframework/driver-definitions";
|
|
12
|
+
import { createChildLogger } from "@fluidframework/telemetry-utils";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Checks if the error is location redirection error.
|
|
16
|
+
* @param error - error whose type is to be determined.
|
|
17
|
+
* @returns `true` is the error is location redirection error, otherwise `false`.
|
|
18
|
+
*/
|
|
19
|
+
export function isLocationRedirectionError(error: any): error is ILocationRedirectionError {
|
|
20
|
+
return (
|
|
21
|
+
typeof error === "object" &&
|
|
22
|
+
error !== null &&
|
|
23
|
+
error.errorType === DriverErrorTypes.locationRedirection
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Handles location redirection while fulfilling the loader request.
|
|
29
|
+
* @param api - Callback in which user can wrap the loader.resolve or loader.request call.
|
|
30
|
+
* @param request - request to be resolved.
|
|
31
|
+
* @param urlResolver - resolver used to resolve the url.
|
|
32
|
+
* @param logger - logger to send events.
|
|
33
|
+
* @returns Response from the API call.
|
|
34
|
+
*/
|
|
35
|
+
export async function resolveWithLocationRedirectionHandling<T>(
|
|
36
|
+
api: (request: IRequest) => Promise<T>,
|
|
37
|
+
request: IRequest,
|
|
38
|
+
urlResolver: IUrlResolver,
|
|
39
|
+
logger?: ITelemetryBaseLogger,
|
|
40
|
+
): Promise<T> {
|
|
41
|
+
let req: IRequest = request;
|
|
42
|
+
const childLogger = createChildLogger({ logger, namespace: "LocationRedirection" });
|
|
43
|
+
for (;;) {
|
|
44
|
+
try {
|
|
45
|
+
return await api(req);
|
|
46
|
+
} catch (error: any) {
|
|
47
|
+
if (!isLocationRedirectionError(error)) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
childLogger.sendTelemetryEvent({ eventName: "LocationRedirectionError" });
|
|
51
|
+
const resolvedUrl = error.redirectUrl;
|
|
52
|
+
// Generate the new request with new location details from the resolved url. For datastore/relative path,
|
|
53
|
+
// we don't need to pass "/" as host could have asked for a specific data store. So driver need to
|
|
54
|
+
// extract it from the resolved url.
|
|
55
|
+
const absoluteUrl = await urlResolver.getAbsoluteUrl(resolvedUrl, "", undefined);
|
|
56
|
+
req = { url: absoluteUrl, headers: req.headers };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/packageVersion.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -13,16 +13,12 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
IDocumentAttributes,
|
|
15
15
|
IProcessMessageResult,
|
|
16
|
-
ISequencedClient,
|
|
17
16
|
ISequencedDocumentMessage,
|
|
18
17
|
ISignalClient,
|
|
19
18
|
ISignalMessage,
|
|
20
19
|
MessageType,
|
|
21
20
|
} from "@fluidframework/protocol-definitions";
|
|
22
21
|
|
|
23
|
-
// "term" was an experimental feature that is being removed. The only safe value to use is 1.
|
|
24
|
-
export const OnlyValidTermValue = 1 as const;
|
|
25
|
-
|
|
26
22
|
// ADO: #1986: Start using enum from protocol-base.
|
|
27
23
|
export enum SignalType {
|
|
28
24
|
ClientJoin = "join", // same value as MessageType.ClientJoin,
|
|
@@ -75,11 +71,11 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
|
|
|
75
71
|
message: ISequencedDocumentMessage,
|
|
76
72
|
local: boolean,
|
|
77
73
|
): IProcessMessageResult {
|
|
78
|
-
const client: ISequencedClient | undefined = this.quorum.getMember(message.clientId);
|
|
79
|
-
|
|
80
74
|
// Check and report if we're getting messages from a clientId that we previously
|
|
81
75
|
// flagged as shouldHaveLeft, or from a client that's not in the quorum but should be
|
|
82
76
|
if (message.clientId != null) {
|
|
77
|
+
const client = this.quorum.getMember(message.clientId);
|
|
78
|
+
|
|
83
79
|
if (client === undefined && message.type !== MessageType.ClientJoin) {
|
|
84
80
|
// pre-0.58 error message: messageClientIdMissingFromQuorum
|
|
85
81
|
throw new Error("Remote message's clientId is missing from the quorum");
|
|
@@ -23,13 +23,19 @@ import { runWithRetry } from "@fluidframework/driver-utils";
|
|
|
23
23
|
|
|
24
24
|
export class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {
|
|
25
25
|
private _disposed = false;
|
|
26
|
+
private internalStorageService: IDocumentStorageService | undefined;
|
|
26
27
|
constructor(
|
|
27
|
-
private readonly
|
|
28
|
+
private readonly internalStorageServiceP: Promise<IDocumentStorageService>,
|
|
28
29
|
private readonly logger: ITelemetryLoggerExt,
|
|
29
|
-
) {
|
|
30
|
+
) {
|
|
31
|
+
this.internalStorageServiceP.then((s) => (this.internalStorageService = s)).catch(() => {});
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
public get policies(): IDocumentStorageServicePolicies | undefined {
|
|
32
|
-
|
|
35
|
+
if (this.internalStorageService) {
|
|
36
|
+
return this.internalStorageService.policies;
|
|
37
|
+
}
|
|
38
|
+
throw new Error("storage service not yet instantiated");
|
|
33
39
|
}
|
|
34
40
|
public get disposed() {
|
|
35
41
|
return this._disposed;
|
|
@@ -39,7 +45,10 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
public get repositoryUrl(): string {
|
|
42
|
-
|
|
48
|
+
if (this.internalStorageService) {
|
|
49
|
+
return this.internalStorageService.repositoryUrl;
|
|
50
|
+
}
|
|
51
|
+
throw new Error("storage service not yet instantiated");
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
public async getSnapshotTree(
|
|
@@ -47,14 +56,17 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
47
56
|
scenarioName?: string,
|
|
48
57
|
): Promise<ISnapshotTree | null> {
|
|
49
58
|
return this.runWithRetry(
|
|
50
|
-
async () =>
|
|
59
|
+
async () =>
|
|
60
|
+
this.internalStorageServiceP.then(async (s) =>
|
|
61
|
+
s.getSnapshotTree(version, scenarioName),
|
|
62
|
+
),
|
|
51
63
|
"storage_getSnapshotTree",
|
|
52
64
|
);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
public async readBlob(id: string): Promise<ArrayBufferLike> {
|
|
56
68
|
return this.runWithRetry(
|
|
57
|
-
async () => this.
|
|
69
|
+
async () => this.internalStorageServiceP.then(async (s) => s.readBlob(id)),
|
|
58
70
|
"storage_readBlob",
|
|
59
71
|
);
|
|
60
72
|
}
|
|
@@ -67,11 +79,8 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
67
79
|
): Promise<IVersion[]> {
|
|
68
80
|
return this.runWithRetry(
|
|
69
81
|
async () =>
|
|
70
|
-
this.
|
|
71
|
-
versionId,
|
|
72
|
-
count,
|
|
73
|
-
scenarioName,
|
|
74
|
-
fetchSource,
|
|
82
|
+
this.internalStorageServiceP.then(async (s) =>
|
|
83
|
+
s.getVersions(versionId, count, scenarioName, fetchSource),
|
|
75
84
|
),
|
|
76
85
|
"storage_getVersions",
|
|
77
86
|
);
|
|
@@ -95,26 +104,31 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
|
|
|
95
104
|
0x251 /* "creation summary has to have seq=0 && handle === undefined" */,
|
|
96
105
|
);
|
|
97
106
|
if (context.referenceSequenceNumber !== 0) {
|
|
98
|
-
return this.
|
|
107
|
+
return this.internalStorageServiceP.then(async (s) =>
|
|
108
|
+
s.uploadSummaryWithContext(summary, context),
|
|
109
|
+
);
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
// Creation flow with attachment blobs - need to do retries!
|
|
102
113
|
return this.runWithRetry(
|
|
103
|
-
async () =>
|
|
114
|
+
async () =>
|
|
115
|
+
this.internalStorageServiceP.then(async (s) =>
|
|
116
|
+
s.uploadSummaryWithContext(summary, context),
|
|
117
|
+
),
|
|
104
118
|
"storage_uploadSummaryWithContext",
|
|
105
119
|
);
|
|
106
120
|
}
|
|
107
121
|
|
|
108
122
|
public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
|
|
109
123
|
return this.runWithRetry(
|
|
110
|
-
async () => this.
|
|
124
|
+
async () => this.internalStorageServiceP.then(async (s) => s.downloadSummary(handle)),
|
|
111
125
|
"storage_downloadSummary",
|
|
112
126
|
);
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
116
130
|
return this.runWithRetry(
|
|
117
|
-
async () => this.
|
|
131
|
+
async () => this.internalStorageServiceP.then(async (s) => s.createBlob(file)),
|
|
118
132
|
"storage_createBlob",
|
|
119
133
|
);
|
|
120
134
|
}
|
package/src/utils.ts
CHANGED
|
@@ -23,9 +23,23 @@ export interface ISnapshotTreeWithBlobContents extends ISnapshotTree {
|
|
|
23
23
|
trees: { [path: string]: ISnapshotTreeWithBlobContents };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Interface to represent the parsed parts of IResolvedUrl.url to help
|
|
28
|
+
* in getting info about different parts of the url.
|
|
29
|
+
* May not be compatible or relevant for any Url Resolver
|
|
30
|
+
*/
|
|
26
31
|
export interface IParsedUrl {
|
|
32
|
+
/**
|
|
33
|
+
* It is combination of tenantid/docId part of the url.
|
|
34
|
+
*/
|
|
27
35
|
id: string;
|
|
36
|
+
/**
|
|
37
|
+
* It is the deep link path in the url.
|
|
38
|
+
*/
|
|
28
39
|
path: string;
|
|
40
|
+
/**
|
|
41
|
+
* Query string part of the url.
|
|
42
|
+
*/
|
|
29
43
|
query: string;
|
|
30
44
|
/**
|
|
31
45
|
* Null means do not use snapshots, undefined means load latest snapshot
|
|
@@ -35,7 +49,15 @@ export interface IParsedUrl {
|
|
|
35
49
|
version: string | null | undefined;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Utility api to parse the IResolvedUrl.url into specific parts like querystring, path to get
|
|
54
|
+
* deep link info etc.
|
|
55
|
+
* Warning - This function may not be compatible with any Url Resolver's resolved url. It works
|
|
56
|
+
* with urls of type: protocol://<string>/.../..?<querystring>
|
|
57
|
+
* @param url - This is the IResolvedUrl.url part of the resolved url.
|
|
58
|
+
* @returns The IParsedUrl representing the input URL, or undefined if the format was not supported
|
|
59
|
+
*/
|
|
60
|
+
export function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined {
|
|
39
61
|
const parsed = parse(url, true);
|
|
40
62
|
if (typeof parsed.pathname !== "string") {
|
|
41
63
|
throw new LoggingError("Failed to parse pathname");
|