@fluidframework/container-loader 2.0.0-internal.5.3.2 → 2.0.0-internal.6.0.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.
- package/CHANGELOG.md +85 -0
- package/README.md +6 -3
- package/dist/audience.d.ts +1 -0
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +3 -1
- package/dist/audience.js.map +1 -1
- package/dist/connectionManager.d.ts +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +30 -36
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +2 -1
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +9 -16
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +12 -8
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +199 -156
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -12
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +1 -20
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.js +3 -5
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +11 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -3
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts +30 -0
- package/dist/debugLogger.d.ts.map +1 -0
- package/dist/debugLogger.js +95 -0
- package/dist/debugLogger.js.map +1 -0
- package/dist/deltaManager.d.ts +16 -4
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +79 -33
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.js +1 -2
- package/dist/deltaQueue.js.map +1 -1
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +73 -47
- package/dist/loader.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +2 -3
- package/dist/protocol.js.map +1 -1
- package/dist/quorum.d.ts +4 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +1 -13
- package/dist/quorum.js.map +1 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +24 -6
- package/dist/utils.js.map +1 -1
- package/lib/audience.d.ts +1 -0
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js +3 -1
- package/lib/audience.js.map +1 -1
- package/lib/connectionManager.d.ts +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +32 -35
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +2 -1
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +9 -16
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +12 -8
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +200 -157
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -12
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +1 -20
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.js +3 -5
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +11 -2
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js +3 -3
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts +30 -0
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/debugLogger.js +91 -0
- package/lib/debugLogger.js.map +1 -0
- package/lib/deltaManager.d.ts +16 -4
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +77 -28
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.js +1 -2
- package/lib/deltaQueue.js.map +1 -1
- package/lib/loader.d.ts +12 -0
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +73 -47
- package/lib/loader.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +2 -3
- package/lib/protocol.js.map +1 -1
- package/lib/quorum.d.ts +4 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +0 -11
- package/lib/quorum.js.map +1 -1
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +22 -5
- package/lib/utils.js.map +1 -1
- package/package.json +14 -14
- package/src/audience.ts +6 -0
- package/src/connectionManager.ts +13 -14
- package/src/connectionStateHandler.ts +3 -2
- package/src/container.ts +178 -120
- package/src/containerContext.ts +0 -24
- package/src/contracts.ts +16 -5
- package/src/debugLogger.ts +113 -0
- package/src/deltaManager.ts +50 -9
- package/src/loader.ts +53 -30
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +0 -1
- package/src/quorum.ts +0 -10
- package/src/utils.ts +29 -0
package/src/contracts.ts
CHANGED
|
@@ -5,19 +5,20 @@
|
|
|
5
5
|
|
|
6
6
|
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
ReadOnlyInfo,
|
|
10
|
-
IConnectionDetailsInternal,
|
|
8
|
+
IConnectionDetails,
|
|
11
9
|
ICriticalContainerError,
|
|
10
|
+
IDeltaQueue,
|
|
12
11
|
IFluidCodeDetails,
|
|
13
12
|
isFluidPackage,
|
|
13
|
+
ReadOnlyInfo,
|
|
14
14
|
} from "@fluidframework/container-definitions";
|
|
15
15
|
import {
|
|
16
16
|
ConnectionMode,
|
|
17
|
-
IDocumentMessage,
|
|
18
|
-
ISequencedDocumentMessage,
|
|
19
17
|
IClientConfiguration,
|
|
20
18
|
IClientDetails,
|
|
19
|
+
IDocumentMessage,
|
|
20
|
+
ISequencedDocumentMessage,
|
|
21
|
+
ISignalClient,
|
|
21
22
|
ISignalMessage,
|
|
22
23
|
} from "@fluidframework/protocol-definitions";
|
|
23
24
|
import { IAnyDriverError, IContainerPackageInfo } from "@fluidframework/driver-definitions";
|
|
@@ -28,6 +29,16 @@ export enum ReconnectMode {
|
|
|
28
29
|
Enabled = "Enabled",
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Internal version of IConnectionDetails with props are only exposed internally
|
|
34
|
+
*/
|
|
35
|
+
export interface IConnectionDetailsInternal extends IConnectionDetails {
|
|
36
|
+
mode: ConnectionMode;
|
|
37
|
+
version: string;
|
|
38
|
+
initialClients: ISignalClient[];
|
|
39
|
+
reason: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
/**
|
|
32
43
|
* Connection manager (implements this interface) is responsible for maintaining connection
|
|
33
44
|
* to relay service.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ITelemetryBaseEvent,
|
|
8
|
+
ITelemetryBaseLogger,
|
|
9
|
+
ITelemetryProperties,
|
|
10
|
+
} from "@fluidframework/core-interfaces";
|
|
11
|
+
import { performance } from "@fluidframework/common-utils";
|
|
12
|
+
import { debug as registerDebug, IDebugger } from "debug";
|
|
13
|
+
import {
|
|
14
|
+
ITelemetryLoggerExt,
|
|
15
|
+
ITelemetryLoggerPropertyBags,
|
|
16
|
+
createMultiSinkLogger,
|
|
17
|
+
eventNamespaceSeparator,
|
|
18
|
+
formatTick,
|
|
19
|
+
} from "@fluidframework/telemetry-utils";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Implementation of debug logger
|
|
23
|
+
*/
|
|
24
|
+
export class DebugLogger implements ITelemetryBaseLogger {
|
|
25
|
+
/**
|
|
26
|
+
* Mix in debug logger with another logger.
|
|
27
|
+
* Returned logger will output events to both newly created debug logger, as well as base logger
|
|
28
|
+
* @param namespace - Telemetry event name prefix to add to all events
|
|
29
|
+
* @param properties - Base properties to add to all events
|
|
30
|
+
* @param propertyGetters - Getters to add additional properties to all events
|
|
31
|
+
* @param baseLogger - Base logger to output events (in addition to debug logger being created). Can be undefined.
|
|
32
|
+
*/
|
|
33
|
+
public static mixinDebugLogger(
|
|
34
|
+
namespace: string,
|
|
35
|
+
baseLogger?: ITelemetryBaseLogger,
|
|
36
|
+
properties?: ITelemetryLoggerPropertyBags,
|
|
37
|
+
): ITelemetryLoggerExt {
|
|
38
|
+
// Setup base logger upfront, such that host can disable it (if needed)
|
|
39
|
+
const debug = registerDebug(namespace);
|
|
40
|
+
|
|
41
|
+
// Create one for errors that is always enabled
|
|
42
|
+
// It can be silenced by replacing console.error if the debug namespace is not enabled.
|
|
43
|
+
const debugErr = registerDebug(namespace);
|
|
44
|
+
debugErr.log = function (...args) {
|
|
45
|
+
if (debug.enabled === true) {
|
|
46
|
+
// if the namespace is enabled, just use the default logger
|
|
47
|
+
registerDebug.log(...args);
|
|
48
|
+
} else {
|
|
49
|
+
// other wise, use the console logger (which could be replaced and silenced)
|
|
50
|
+
console.error(...args);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
debugErr.enabled = true;
|
|
54
|
+
|
|
55
|
+
return createMultiSinkLogger({
|
|
56
|
+
namespace,
|
|
57
|
+
loggers: [baseLogger, new DebugLogger(debug, debugErr)],
|
|
58
|
+
properties,
|
|
59
|
+
tryInheritProperties: true,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private constructor(private readonly debug: IDebugger, private readonly debugErr: IDebugger) {}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Send an event to debug loggers
|
|
67
|
+
*
|
|
68
|
+
* @param event - the event to send
|
|
69
|
+
*/
|
|
70
|
+
public send(event: ITelemetryBaseEvent): void {
|
|
71
|
+
const newEvent: ITelemetryProperties = { ...event };
|
|
72
|
+
const isError = newEvent.category === "error";
|
|
73
|
+
let logger = isError ? this.debugErr : this.debug;
|
|
74
|
+
|
|
75
|
+
// Use debug's coloring schema for base of the event
|
|
76
|
+
const index = event.eventName.lastIndexOf(eventNamespaceSeparator);
|
|
77
|
+
const name = event.eventName.substring(index + 1);
|
|
78
|
+
if (index > 0) {
|
|
79
|
+
logger = logger.extend(event.eventName.substring(0, index));
|
|
80
|
+
}
|
|
81
|
+
newEvent.eventName = undefined;
|
|
82
|
+
|
|
83
|
+
let tick = "";
|
|
84
|
+
tick = `tick=${formatTick(performance.now())}`;
|
|
85
|
+
|
|
86
|
+
// Extract stack to put it last, but also to avoid escaping '\n' in it by JSON.stringify below
|
|
87
|
+
const stack = newEvent.stack ?? "";
|
|
88
|
+
newEvent.stack = undefined;
|
|
89
|
+
|
|
90
|
+
// Watch out for circular references - they can come from two sources
|
|
91
|
+
// 1) error object - we do not control it and should remove it and retry
|
|
92
|
+
// 2) properties supplied by telemetry caller - that's a bug that should be addressed!
|
|
93
|
+
let payload: string;
|
|
94
|
+
try {
|
|
95
|
+
payload = JSON.stringify(newEvent);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
newEvent.error = undefined;
|
|
98
|
+
payload = JSON.stringify(newEvent);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (payload === "{}") {
|
|
102
|
+
payload = "";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Force errors out, to help with diagnostics
|
|
106
|
+
if (isError) {
|
|
107
|
+
logger.enabled = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Print multi-line.
|
|
111
|
+
logger(`${name} ${payload} ${tick} ${stack}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
package/src/deltaManager.ts
CHANGED
|
@@ -3,18 +3,15 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { default as AbortController } from "abort-controller";
|
|
7
6
|
import { v4 as uuid } from "uuid";
|
|
8
7
|
import { IEventProvider } from "@fluidframework/common-definitions";
|
|
9
8
|
import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
|
|
10
9
|
import {
|
|
11
|
-
|
|
10
|
+
ICriticalContainerError,
|
|
12
11
|
IDeltaManager,
|
|
13
12
|
IDeltaManagerEvents,
|
|
14
13
|
IDeltaQueue,
|
|
15
|
-
ICriticalContainerError,
|
|
16
14
|
IThrottlingWarning,
|
|
17
|
-
IConnectionDetailsInternal,
|
|
18
15
|
} from "@fluidframework/container-definitions";
|
|
19
16
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
20
17
|
import {
|
|
@@ -45,7 +42,11 @@ import {
|
|
|
45
42
|
DataProcessingError,
|
|
46
43
|
UsageError,
|
|
47
44
|
} from "@fluidframework/container-utils";
|
|
48
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
IConnectionDetailsInternal,
|
|
47
|
+
IConnectionManager,
|
|
48
|
+
IConnectionManagerFactoryArgs,
|
|
49
|
+
} from "./contracts";
|
|
49
50
|
import { DeltaQueue } from "./deltaQueue";
|
|
50
51
|
import { OnlyValidTermValue } from "./protocol";
|
|
51
52
|
|
|
@@ -74,6 +75,21 @@ interface IBatchMetadata {
|
|
|
74
75
|
batch?: boolean;
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Interface used to define a strategy for handling incoming delta messages
|
|
80
|
+
*/
|
|
81
|
+
export interface IDeltaHandlerStrategy {
|
|
82
|
+
/**
|
|
83
|
+
* Processes the message.
|
|
84
|
+
*/
|
|
85
|
+
process: (message: ISequencedDocumentMessage) => void;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Processes the signal.
|
|
89
|
+
*/
|
|
90
|
+
processSignal: (message: ISignalMessage) => void;
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
/**
|
|
78
94
|
* Determines if message was sent by client, not service
|
|
79
95
|
*/
|
|
@@ -93,6 +109,17 @@ function isClientMessage(message: ISequencedDocumentMessage | IDocumentMessage):
|
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Type is used to cast AbortController to represent new version of DOM API and prevent build issues
|
|
114
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
115
|
+
*/
|
|
116
|
+
type AbortControllerReal = AbortController & { abort(reason?: any): void };
|
|
117
|
+
/**
|
|
118
|
+
* Type is used to cast AbortSignal to represent new version of DOM API and prevent build issues
|
|
119
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
120
|
+
*/
|
|
121
|
+
type AbortSignalReal = AbortSignal & { reason: any };
|
|
122
|
+
|
|
96
123
|
/**
|
|
97
124
|
* Manages the flow of both inbound and outbound messages. This class ensures that shared objects receive delta
|
|
98
125
|
* messages in order regardless of possible network conditions or timings causing out of order delivery.
|
|
@@ -485,7 +512,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
485
512
|
minSequenceNumber: number,
|
|
486
513
|
sequenceNumber: number,
|
|
487
514
|
handler: IDeltaHandlerStrategy,
|
|
488
|
-
prefetchType: "cached" | "all" | "none" = "none",
|
|
515
|
+
prefetchType: "sequenceNumber" | "cached" | "all" | "none" = "none",
|
|
489
516
|
) {
|
|
490
517
|
this.initSequenceNumber = sequenceNumber;
|
|
491
518
|
this.lastProcessedSequenceNumber = sequenceNumber;
|
|
@@ -624,7 +651,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
624
651
|
// This is useless for known ranges (to is defined) as it means request is over either way.
|
|
625
652
|
// And it will cancel unbound request too early, not allowing us to learn where the end of the file is.
|
|
626
653
|
if (!opsFromFetch && cancelFetch(op)) {
|
|
627
|
-
|
|
654
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
655
|
+
(controller as AbortControllerReal).abort("DeltaManager getDeltas fetch cancelled");
|
|
628
656
|
this._inbound.off("push", opListener);
|
|
629
657
|
}
|
|
630
658
|
};
|
|
@@ -632,7 +660,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
632
660
|
try {
|
|
633
661
|
this._inbound.on("push", opListener);
|
|
634
662
|
assert(this.closeAbortController.signal.onabort === null, 0x1e8 /* "reentrancy" */);
|
|
635
|
-
this.closeAbortController.signal.onabort = () =>
|
|
663
|
+
this.closeAbortController.signal.onabort = () =>
|
|
664
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
665
|
+
(controller as AbortControllerReal).abort(
|
|
666
|
+
(this.closeAbortController.signal as AbortSignalReal).reason,
|
|
667
|
+
);
|
|
636
668
|
|
|
637
669
|
const stream = this.deltaStorage.fetchMessages(
|
|
638
670
|
from, // inclusive
|
|
@@ -656,6 +688,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
656
688
|
}
|
|
657
689
|
}
|
|
658
690
|
} finally {
|
|
691
|
+
if (controller.signal.aborted) {
|
|
692
|
+
this.logger.sendTelemetryEvent({
|
|
693
|
+
eventName: "DeltaManager_GetDeltasAborted",
|
|
694
|
+
fetchReason,
|
|
695
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
696
|
+
reason: (controller.signal as AbortSignalReal).reason,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
659
699
|
this.closeAbortController.signal.onabort = null;
|
|
660
700
|
this._inbound.off("push", opListener);
|
|
661
701
|
assert(!opsFromFetch, 0x289 /* "logic error" */);
|
|
@@ -710,7 +750,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
710
750
|
}
|
|
711
751
|
|
|
712
752
|
private clearQueues() {
|
|
713
|
-
|
|
753
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
754
|
+
(this.closeAbortController as AbortControllerReal).abort("DeltaManager is closed");
|
|
714
755
|
|
|
715
756
|
this._inbound.clear();
|
|
716
757
|
this._inboundSignal.clear();
|
package/src/loader.ts
CHANGED
|
@@ -6,14 +6,12 @@
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
7
|
import {
|
|
8
8
|
ITelemetryLoggerExt,
|
|
9
|
-
ChildLogger,
|
|
10
|
-
DebugLogger,
|
|
11
9
|
IConfigProviderBase,
|
|
12
|
-
loggerToMonitoringContext,
|
|
13
10
|
mixinMonitoringContext,
|
|
14
11
|
MonitoringContext,
|
|
15
12
|
PerformanceEvent,
|
|
16
13
|
sessionStorageConfigProvider,
|
|
14
|
+
createChildMonitoringContext,
|
|
17
15
|
} from "@fluidframework/telemetry-utils";
|
|
18
16
|
import {
|
|
19
17
|
ITelemetryBaseLogger,
|
|
@@ -39,18 +37,15 @@ import {
|
|
|
39
37
|
IResolvedUrl,
|
|
40
38
|
IUrlResolver,
|
|
41
39
|
} from "@fluidframework/driver-definitions";
|
|
42
|
-
import {
|
|
40
|
+
import { UsageError } from "@fluidframework/container-utils";
|
|
43
41
|
import { Container, IPendingContainerState } from "./container";
|
|
44
42
|
import { IParsedUrl, parseUrl } from "./utils";
|
|
45
43
|
import { pkgVersion } from "./packageVersion";
|
|
46
44
|
import { ProtocolHandlerBuilder } from "./protocol";
|
|
45
|
+
import { DebugLogger } from "./debugLogger";
|
|
47
46
|
|
|
48
47
|
function canUseCache(request: IRequest): boolean {
|
|
49
|
-
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return request.headers[LoaderHeader.cache] !== false;
|
|
48
|
+
return request.headers?.[LoaderHeader.cache] === true;
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
function ensureResolvedUrlDefined(
|
|
@@ -69,6 +64,9 @@ export class RelativeLoader implements ILoader {
|
|
|
69
64
|
private readonly loader: ILoader | undefined,
|
|
70
65
|
) {}
|
|
71
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
69
|
+
*/
|
|
72
70
|
public get IFluidRouter(): IFluidRouter {
|
|
73
71
|
return this;
|
|
74
72
|
}
|
|
@@ -100,6 +98,9 @@ export class RelativeLoader implements ILoader {
|
|
|
100
98
|
return this.loader.resolve(request);
|
|
101
99
|
}
|
|
102
100
|
|
|
101
|
+
/**
|
|
102
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
103
|
+
*/
|
|
103
104
|
public async request(request: IRequest): Promise<IResponse> {
|
|
104
105
|
if (request.url.startsWith("/")) {
|
|
105
106
|
const container = await this.resolve(request);
|
|
@@ -343,9 +344,15 @@ export class Loader implements IHostLoader {
|
|
|
343
344
|
protocolHandlerBuilder,
|
|
344
345
|
subLogger: subMc.logger,
|
|
345
346
|
};
|
|
346
|
-
this.mc =
|
|
347
|
+
this.mc = createChildMonitoringContext({
|
|
348
|
+
logger: this.services.subLogger,
|
|
349
|
+
namespace: "Loader",
|
|
350
|
+
});
|
|
347
351
|
}
|
|
348
352
|
|
|
353
|
+
/**
|
|
354
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
355
|
+
*/
|
|
349
356
|
public get IFluidRouter(): IFluidRouter {
|
|
350
357
|
return this;
|
|
351
358
|
}
|
|
@@ -381,6 +388,9 @@ export class Loader implements IHostLoader {
|
|
|
381
388
|
});
|
|
382
389
|
}
|
|
383
390
|
|
|
391
|
+
/**
|
|
392
|
+
* @deprecated - Will be removed in future major release. Migrate all usage of IFluidRouter to the Container's IFluidRouter/request.
|
|
393
|
+
*/
|
|
384
394
|
public async request(request: IRequest): Promise<IResponse> {
|
|
385
395
|
return PerformanceEvent.timedExecAsync(
|
|
386
396
|
this.mc.logger,
|
|
@@ -407,16 +417,23 @@ export class Loader implements IHostLoader {
|
|
|
407
417
|
this.containers.set(key, containerP);
|
|
408
418
|
containerP
|
|
409
419
|
.then((container) => {
|
|
410
|
-
// If the container is closed or becomes closed after we resolve it,
|
|
411
|
-
|
|
420
|
+
// If the container is closed/disposed or becomes closed/disposed after we resolve it,
|
|
421
|
+
// remove it from the cache.
|
|
422
|
+
if (container.closed || container.disposed) {
|
|
412
423
|
this.containers.delete(key);
|
|
413
424
|
} else {
|
|
414
425
|
container.once("closed", () => {
|
|
415
426
|
this.containers.delete(key);
|
|
416
427
|
});
|
|
428
|
+
container.once("disposed", () => {
|
|
429
|
+
this.containers.delete(key);
|
|
430
|
+
});
|
|
417
431
|
}
|
|
418
432
|
})
|
|
419
|
-
.catch((error) => {
|
|
433
|
+
.catch((error) => {
|
|
434
|
+
// If an error occured while resolving the container request, then remove it from the cache.
|
|
435
|
+
this.containers.delete(key);
|
|
436
|
+
});
|
|
420
437
|
}
|
|
421
438
|
|
|
422
439
|
private async resolveCore(
|
|
@@ -447,11 +464,29 @@ export class Loader implements IHostLoader {
|
|
|
447
464
|
// If set in both query string and headers, use query string. Also write the value from the query string into the header either way.
|
|
448
465
|
request.headers[LoaderHeader.version] =
|
|
449
466
|
parsed.version ?? request.headers[LoaderHeader.version];
|
|
467
|
+
const cacheHeader = request.headers[LoaderHeader.cache];
|
|
450
468
|
const canCache =
|
|
451
|
-
|
|
452
|
-
|
|
469
|
+
// Take header value if present, else use ILoaderOptions.cache value
|
|
470
|
+
(cacheHeader !== undefined ? cacheHeader === true : this.cachingEnabled) &&
|
|
453
471
|
pendingLocalState === undefined;
|
|
454
|
-
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber]
|
|
472
|
+
const fromSequenceNumber = request.headers[LoaderHeader.sequenceNumber] as
|
|
473
|
+
| number
|
|
474
|
+
| undefined;
|
|
475
|
+
const opsBeforeReturn = request.headers[LoaderHeader.loadMode]?.opsBeforeReturn as
|
|
476
|
+
| string
|
|
477
|
+
| undefined;
|
|
478
|
+
|
|
479
|
+
if (
|
|
480
|
+
opsBeforeReturn === "sequenceNumber" &&
|
|
481
|
+
(fromSequenceNumber === undefined || fromSequenceNumber < 0)
|
|
482
|
+
) {
|
|
483
|
+
// If opsBeforeReturn is set to "sequenceNumber", then fromSequenceNumber should be set to a non-negative integer.
|
|
484
|
+
throw new UsageError("sequenceNumber must be set to a non-negative integer");
|
|
485
|
+
} else if (opsBeforeReturn !== "sequenceNumber" && fromSequenceNumber !== undefined) {
|
|
486
|
+
// If opsBeforeReturn is not set to "sequenceNumber", then fromSequenceNumber should be undefined (default value).
|
|
487
|
+
// In this case, we should throw an error since opsBeforeReturn is not explicitly set to "sequenceNumber".
|
|
488
|
+
throw new UsageError('opsBeforeReturn must be set to "sequenceNumber"');
|
|
489
|
+
}
|
|
455
490
|
|
|
456
491
|
let container: Container;
|
|
457
492
|
if (canCache) {
|
|
@@ -468,24 +503,11 @@ export class Loader implements IHostLoader {
|
|
|
468
503
|
container = await this.loadContainer(request, resolvedAsFluid, pendingLocalState);
|
|
469
504
|
}
|
|
470
505
|
|
|
471
|
-
if (container.deltaManager.lastSequenceNumber <= fromSequenceNumber) {
|
|
472
|
-
await new Promise<void>((resolve, reject) => {
|
|
473
|
-
function opHandler(message: ISequencedDocumentMessage) {
|
|
474
|
-
if (message.sequenceNumber > fromSequenceNumber) {
|
|
475
|
-
resolve();
|
|
476
|
-
container.removeListener("op", opHandler);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
container.on("op", opHandler);
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
|
|
484
506
|
return { container, parsed };
|
|
485
507
|
}
|
|
486
508
|
|
|
487
509
|
private get cachingEnabled() {
|
|
488
|
-
return this.services.options.cache
|
|
510
|
+
return this.services.options.cache === true;
|
|
489
511
|
}
|
|
490
512
|
|
|
491
513
|
private async loadContainer(
|
|
@@ -499,6 +521,7 @@ export class Loader implements IHostLoader {
|
|
|
499
521
|
version: request.headers?.[LoaderHeader.version] ?? undefined,
|
|
500
522
|
loadMode: request.headers?.[LoaderHeader.loadMode],
|
|
501
523
|
pendingLocalState,
|
|
524
|
+
loadToSequenceNumber: request.headers?.[LoaderHeader.sequenceNumber],
|
|
502
525
|
},
|
|
503
526
|
{
|
|
504
527
|
canReconnect: request.headers?.[LoaderHeader.reconnect],
|
package/src/packageVersion.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -49,7 +49,6 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
|
|
|
49
49
|
super(
|
|
50
50
|
attributes.minimumSequenceNumber,
|
|
51
51
|
attributes.sequenceNumber,
|
|
52
|
-
OnlyValidTermValue,
|
|
53
52
|
quorumSnapshot.members,
|
|
54
53
|
quorumSnapshot.proposals,
|
|
55
54
|
quorumSnapshot.values,
|
package/src/quorum.ts
CHANGED
|
@@ -2,19 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { assert } from "@fluidframework/common-utils";
|
|
6
5
|
import { IFluidCodeDetails } from "@fluidframework/core-interfaces";
|
|
7
6
|
import { ICommittedProposal } from "@fluidframework/protocol-definitions";
|
|
8
7
|
|
|
9
|
-
export function getCodeDetailsFromQuorumValues(
|
|
10
|
-
quorumValues: [string, ICommittedProposal][],
|
|
11
|
-
): IFluidCodeDetails {
|
|
12
|
-
const qValuesMap = new Map(quorumValues);
|
|
13
|
-
const proposal = qValuesMap.get("code");
|
|
14
|
-
assert(proposal !== undefined, 0x2dc /* "Cannot find code proposal" */);
|
|
15
|
-
return proposal?.value as IFluidCodeDetails;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
8
|
export function initQuorumValuesFromCodeDetails(
|
|
19
9
|
source: IFluidCodeDetails,
|
|
20
10
|
): [string, ICommittedProposal][] {
|
package/src/utils.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
|
|
15
15
|
import { LoggingError } from "@fluidframework/telemetry-utils";
|
|
16
16
|
import {
|
|
17
|
+
CombinedAppAndProtocolSummary,
|
|
17
18
|
DeltaStreamConnectionForbiddenError,
|
|
18
19
|
isCombinedAppAndProtocolSummary,
|
|
19
20
|
} from "@fluidframework/driver-utils";
|
|
@@ -51,6 +52,34 @@ export function parseUrl(url: string): IParsedUrl | undefined {
|
|
|
51
52
|
: undefined;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Combine the app summary and protocol summary in 1 tree.
|
|
57
|
+
* @param appSummary - Summary of the app.
|
|
58
|
+
* @param protocolSummary - Summary of the protocol.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export function combineAppAndProtocolSummary(
|
|
62
|
+
appSummary: ISummaryTree,
|
|
63
|
+
protocolSummary: ISummaryTree,
|
|
64
|
+
): CombinedAppAndProtocolSummary {
|
|
65
|
+
assert(
|
|
66
|
+
!isCombinedAppAndProtocolSummary(appSummary),
|
|
67
|
+
0x5a8 /* app summary is already a combined tree! */,
|
|
68
|
+
);
|
|
69
|
+
assert(
|
|
70
|
+
!isCombinedAppAndProtocolSummary(protocolSummary),
|
|
71
|
+
0x5a9 /* protocol summary is already a combined tree! */,
|
|
72
|
+
);
|
|
73
|
+
const createNewSummary: CombinedAppAndProtocolSummary = {
|
|
74
|
+
type: SummaryType.Tree,
|
|
75
|
+
tree: {
|
|
76
|
+
".protocol": protocolSummary,
|
|
77
|
+
".app": appSummary,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
return createNewSummary;
|
|
81
|
+
}
|
|
82
|
+
|
|
54
83
|
/**
|
|
55
84
|
* Converts summary tree (for upload) to snapshot tree (for download).
|
|
56
85
|
* Summary tree blobs contain contents, but snapshot tree blobs normally
|