@fluidframework/container-loader 2.62.0-356644 → 2.62.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 (61) hide show
  1. package/CHANGELOG.md +4 -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/container-loader.legacy.alpha.api.md +212 -0
  6. package/dist/connectionManager.d.ts.map +1 -1
  7. package/dist/connectionManager.js +8 -72
  8. package/dist/connectionManager.js.map +1 -1
  9. package/dist/container.d.ts +9 -4
  10. package/dist/container.d.ts.map +1 -1
  11. package/dist/container.js +9 -1
  12. package/dist/container.js.map +1 -1
  13. package/dist/createAndLoadContainerUtils.d.ts +48 -0
  14. package/dist/createAndLoadContainerUtils.d.ts.map +1 -1
  15. package/dist/createAndLoadContainerUtils.js +14 -1
  16. package/dist/createAndLoadContainerUtils.js.map +1 -1
  17. package/dist/frozenServices.d.ts +44 -0
  18. package/dist/frozenServices.d.ts.map +1 -0
  19. package/dist/frozenServices.js +126 -0
  20. package/dist/frozenServices.js.map +1 -0
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/legacyAlpha.d.ts +48 -0
  26. package/dist/packageVersion.d.ts +1 -1
  27. package/dist/packageVersion.d.ts.map +1 -1
  28. package/dist/packageVersion.js +1 -1
  29. package/dist/packageVersion.js.map +1 -1
  30. package/legacy/alpha.d.ts +11 -0
  31. package/lib/connectionManager.d.ts.map +1 -1
  32. package/lib/connectionManager.js +10 -74
  33. package/lib/connectionManager.js.map +1 -1
  34. package/lib/container.d.ts +9 -4
  35. package/lib/container.d.ts.map +1 -1
  36. package/lib/container.js +7 -0
  37. package/lib/container.js.map +1 -1
  38. package/lib/createAndLoadContainerUtils.d.ts +48 -0
  39. package/lib/createAndLoadContainerUtils.d.ts.map +1 -1
  40. package/lib/createAndLoadContainerUtils.js +12 -0
  41. package/lib/createAndLoadContainerUtils.js.map +1 -1
  42. package/lib/frozenServices.d.ts +44 -0
  43. package/lib/frozenServices.d.ts.map +1 -0
  44. package/lib/frozenServices.js +120 -0
  45. package/lib/frozenServices.js.map +1 -0
  46. package/lib/index.d.ts +2 -2
  47. package/lib/index.d.ts.map +1 -1
  48. package/lib/index.js +2 -2
  49. package/lib/index.js.map +1 -1
  50. package/lib/legacyAlpha.d.ts +48 -0
  51. package/lib/packageVersion.d.ts +1 -1
  52. package/lib/packageVersion.d.ts.map +1 -1
  53. package/lib/packageVersion.js +1 -1
  54. package/lib/packageVersion.js.map +1 -1
  55. package/package.json +26 -14
  56. package/src/connectionManager.ts +10 -92
  57. package/src/container.ts +12 -4
  58. package/src/createAndLoadContainerUtils.ts +66 -0
  59. package/src/frozenServices.ts +162 -0
  60. package/src/index.ts +3 -1
  61. package/src/packageVersion.ts +1 -1
@@ -3,17 +3,13 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { TypedEventEmitter, performanceNow } from "@fluid-internal/client-utils";
6
+ import { performanceNow } from "@fluid-internal/client-utils";
7
7
  import type { ICriticalContainerError } from "@fluidframework/container-definitions";
8
8
  import type {
9
9
  IDeltaQueue,
10
10
  ReadOnlyInfo,
11
11
  } from "@fluidframework/container-definitions/internal";
12
- import {
13
- type IDisposable,
14
- type ITelemetryBaseProperties,
15
- LogLevel,
16
- } from "@fluidframework/core-interfaces";
12
+ import { type ITelemetryBaseProperties, LogLevel } from "@fluidframework/core-interfaces";
17
13
  import { assert } from "@fluidframework/core-utils/internal";
18
14
  import type {
19
15
  ConnectionMode,
@@ -22,7 +18,6 @@ import type {
22
18
  } from "@fluidframework/driver-definitions";
23
19
  import {
24
20
  type IDocumentDeltaConnection,
25
- type IDocumentDeltaConnectionEvents,
26
21
  type IDocumentService,
27
22
  DriverErrorTypes,
28
23
  type IAnyDriverError,
@@ -32,7 +27,6 @@ import {
32
27
  type INackContent,
33
28
  type ISequencedDocumentSystemMessage,
34
29
  type ISignalClient,
35
- type ITokenClaims,
36
30
  MessageType,
37
31
  ScopeType,
38
32
  type ISequencedDocumentMessage,
@@ -67,6 +61,7 @@ import {
67
61
  ReconnectMode,
68
62
  } from "./contracts.js";
69
63
  import { DeltaQueue } from "./deltaQueue.js";
64
+ import { FrozenDeltaStream, isFrozenDeltaStreamConnection } from "./frozenServices.js";
70
65
  import { SignalType } from "./protocol.js";
71
66
  import { isDeltaStreamConnectionForbiddenError } from "./utils.js";
72
67
 
@@ -90,85 +85,6 @@ function getNackReconnectInfo(
90
85
  );
91
86
  }
92
87
 
93
- /**
94
- * Implementation of IDocumentDeltaConnection that does not support submitting
95
- * or receiving ops. Used in storage-only mode.
96
- */
97
- const clientNoDeltaStream: IClient = {
98
- mode: "read",
99
- details: { capabilities: { interactive: true } },
100
- permission: [],
101
- user: { id: "storage-only client" }, // we need some "fake" ID here.
102
- scopes: [],
103
- };
104
- const clientIdNoDeltaStream: string = "storage-only client";
105
-
106
- class NoDeltaStream
107
- extends TypedEventEmitter<IDocumentDeltaConnectionEvents>
108
- implements IDocumentDeltaConnection, IDisposable
109
- {
110
- clientId = clientIdNoDeltaStream;
111
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
112
- claims = {
113
- scopes: [ScopeType.DocRead],
114
- } as ITokenClaims;
115
- mode: ConnectionMode = "read";
116
- existing: boolean = true;
117
- maxMessageSize: number = 0;
118
- version: string = "";
119
- initialMessages: ISequencedDocumentMessage[] = [];
120
- initialSignals: ISignalMessage[] = [];
121
- initialClients: ISignalClient[] = [
122
- { client: clientNoDeltaStream, clientId: clientIdNoDeltaStream },
123
- ];
124
- serviceConfiguration: IClientConfiguration = {
125
- maxMessageSize: 0,
126
- blockSize: 0,
127
- };
128
- checkpointSequenceNumber?: number | undefined = undefined;
129
- /**
130
- * Connection which is not connected to socket.
131
- * @param storageOnlyReason - Reason on why the connection to delta stream is not allowed.
132
- * @param readonlyConnectionReason - reason/error if any which lead to using NoDeltaStream.
133
- */
134
- constructor(
135
- public readonly storageOnlyReason?: string,
136
- public readonly readonlyConnectionReason?: IConnectionStateChangeReason,
137
- ) {
138
- super();
139
- }
140
- submit(messages: IDocumentMessage[]): void {
141
- this.emit(
142
- "nack",
143
- this.clientId,
144
- messages.map((operation) => {
145
- return {
146
- operation,
147
- content: { message: "Cannot submit with storage-only connection", code: 403 },
148
- };
149
- }),
150
- );
151
- }
152
- submitSignal(message: unknown): void {
153
- this.emit("nack", this.clientId, {
154
- operation: message,
155
- content: { message: "Cannot submit signal with storage-only connection", code: 403 },
156
- });
157
- }
158
-
159
- private _disposed = false;
160
- public get disposed(): boolean {
161
- return this._disposed;
162
- }
163
- public dispose(): void {
164
- this._disposed = true;
165
- }
166
- }
167
-
168
- function isNoDeltaStreamConnection(connection: unknown): connection is NoDeltaStream {
169
- return connection instanceof NoDeltaStream;
170
- }
171
-
172
88
  const waitForOnline = async (): Promise<void> => {
173
89
  // Only wait if we have a strong signal that we're offline - otherwise assume we're online.
174
90
  if (globalThis.navigator?.onLine === false && globalThis.addEventListener !== undefined) {
@@ -377,7 +293,7 @@ export class ConnectionManager implements IConnectionManager {
377
293
  public get readOnlyInfo(): ReadOnlyInfo {
378
294
  let storageOnly: boolean = false;
379
295
  let storageOnlyReason: string | undefined;
380
- if (isNoDeltaStreamConnection(this.connection)) {
296
+ if (isFrozenDeltaStreamConnection(this.connection)) {
381
297
  storageOnly = true;
382
298
  storageOnlyReason = this.connection.storageOnlyReason;
383
299
  }
@@ -589,7 +505,7 @@ export class ConnectionManager implements IConnectionManager {
589
505
  let connection: IDocumentDeltaConnection | undefined;
590
506
 
591
507
  if (docService.policies?.storageOnly === true) {
592
- connection = new NoDeltaStream();
508
+ connection = new FrozenDeltaStream();
593
509
  this.setupNewSuccessfulConnection(connection, "read", reason);
594
510
  assert(this.pendingConnection === undefined, 0x2b3 /* "logic error" */);
595
511
  return;
@@ -661,7 +577,7 @@ export class ConnectionManager implements IConnectionManager {
661
577
  LogLevel.verbose,
662
578
  );
663
579
  if (isDeltaStreamConnectionForbiddenError(origError)) {
664
- connection = new NoDeltaStream(origError.storageOnlyReason, {
580
+ connection = new FrozenDeltaStream(origError.storageOnlyReason, {
665
581
  text: origError.message,
666
582
  error: origError,
667
583
  });
@@ -673,7 +589,7 @@ export class ConnectionManager implements IConnectionManager {
673
589
  ) {
674
590
  // If we get out of storage error from calling joinsession, then use the NoDeltaStream object so
675
591
  // that user can at least load the container.
676
- connection = new NoDeltaStream(undefined, {
592
+ connection = new FrozenDeltaStream(undefined, {
677
593
  text: origError.message,
678
594
  error: origError,
679
595
  });
@@ -931,7 +847,9 @@ export class ConnectionManager implements IConnectionManager {
931
847
  this.set_readonlyPermissions(
932
848
  readonlyPermission,
933
849
  oldReadonlyValue,
934
- isNoDeltaStreamConnection(connection) ? connection.readonlyConnectionReason : undefined,
850
+ isFrozenDeltaStreamConnection(connection)
851
+ ? connection.readonlyConnectionReason
852
+ : undefined,
935
853
  );
936
854
 
937
855
  if (this._disposed) {
package/src/container.ts CHANGED
@@ -380,7 +380,7 @@ interface IContainerLifecycleEvents extends IEvent {
380
380
 
381
381
  export class Container
382
382
  extends EventEmitterWithErrorHandling<IContainerEvents>
383
- implements IContainer, IContainerExperimental
383
+ implements IContainer, ContainerAlpha
384
384
  {
385
385
  /**
386
386
  * Load an existing container.
@@ -2558,14 +2558,22 @@ export class Container
2558
2558
 
2559
2559
  /**
2560
2560
  * IContainer interface that includes experimental features still under development.
2561
- * @internal
2561
+ * @alpha @legacy @sealed
2562
2562
  */
2563
- export interface IContainerExperimental extends IContainer {
2563
+ export interface ContainerAlpha extends IContainer {
2564
2564
  /**
2565
2565
  * Get pending state from container. WARNING: misuse of this API can result in duplicate op
2566
2566
  * submission and potential document corruption. The blob returned MUST be deleted if and when this
2567
2567
  * container emits a "connected" event.
2568
2568
  * @returns serialized blob that can be passed to Loader.resolve()
2569
2569
  */
2570
- getPendingLocalState?(): Promise<string>;
2570
+ getPendingLocalState(): Promise<string>;
2571
+ }
2572
+
2573
+ /**
2574
+ * Converts types to their alpha counterparts to expose alpha functionality.
2575
+ * @legacy @alpha
2576
+ */
2577
+ export function asLegacyAlpha(base: IContainer): ContainerAlpha {
2578
+ return base as ContainerAlpha;
2571
2579
  }
@@ -21,6 +21,7 @@ import type {
21
21
  IUrlResolver,
22
22
  } from "@fluidframework/driver-definitions/internal";
23
23
 
24
+ import { FrozenDocumentServiceFactory } from "./frozenServices.js";
24
25
  import { Loader } from "./loader.js";
25
26
  import type { ProtocolHandlerBuilder } from "./protocol.js";
26
27
 
@@ -173,3 +174,68 @@ export async function loadExistingContainer(
173
174
  loadExistingContainerProps.pendingLocalState,
174
175
  );
175
176
  }
177
+
178
+ /**
179
+ * Properties required to load a frozen container from pending state.
180
+ * @legacy @alpha
181
+ */
182
+ export interface ILoadFrozenContainerFromPendingStateProps {
183
+ /**
184
+ * The code loader handles loading the necessary code for running a container once it is loaded.
185
+ */
186
+ readonly codeLoader: ICodeDetailsLoader;
187
+
188
+ /**
189
+ * The url resolver used by the loader for resolving external urls into Fluid urls.
190
+ */
191
+ readonly urlResolver: IUrlResolver;
192
+
193
+ /**
194
+ * The request to resolve the container.
195
+ */
196
+ readonly request: IRequest;
197
+
198
+ /**
199
+ * Pending local state to be applied to the container.
200
+ */
201
+ readonly pendingLocalState: string;
202
+
203
+ /**
204
+ * A property bag of options/policies used by various layers to control features.
205
+ */
206
+ readonly options?: IContainerPolicies | undefined;
207
+
208
+ /**
209
+ * Scope is provided to all container and is a set of shared services for container's to integrate with their host environment.
210
+ */
211
+ readonly scope?: FluidObject | undefined;
212
+
213
+ /**
214
+ * The logger that all telemetry should be pushed to.
215
+ */
216
+ readonly logger?: ITelemetryBaseLogger | undefined;
217
+
218
+ /**
219
+ * The configuration provider which may be used to control features.
220
+ */
221
+ readonly configProvider?: IConfigProviderBase | undefined;
222
+
223
+ /**
224
+ * Client details provided in the override will be merged over the default client.
225
+ */
226
+ readonly clientDetailsOverride?: IClientDetails | undefined;
227
+ }
228
+
229
+ /**
230
+ * Loads a frozen container from pending local state.
231
+ * @param props - Properties required to load a frozen container from pending state.
232
+ * @legacy @alpha
233
+ */
234
+ export async function loadFrozenContainerFromPendingState(
235
+ props: ILoadFrozenContainerFromPendingStateProps,
236
+ ): Promise<IContainer> {
237
+ return loadExistingContainer({
238
+ ...props,
239
+ documentServiceFactory: new FrozenDocumentServiceFactory(),
240
+ });
241
+ }
@@ -0,0 +1,162 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
+ import type { IDisposable } from "@fluidframework/core-interfaces";
8
+ import {
9
+ ScopeType,
10
+ type ConnectionMode,
11
+ type IClient,
12
+ type IClientConfiguration,
13
+ type IDocumentDeltaConnection,
14
+ type IDocumentDeltaConnectionEvents,
15
+ type IDocumentDeltaStorageService,
16
+ type IDocumentMessage,
17
+ type IDocumentService,
18
+ type IDocumentServiceEvents,
19
+ type IDocumentServiceFactory,
20
+ type IDocumentServicePolicies,
21
+ type IDocumentStorageService,
22
+ type IResolvedUrl,
23
+ type ISequencedDocumentMessage,
24
+ type ISignalClient,
25
+ type ISignalMessage,
26
+ type ITokenClaims,
27
+ } from "@fluidframework/driver-definitions/internal";
28
+
29
+ import type { IConnectionStateChangeReason } from "./contracts.js";
30
+
31
+ export class FrozenDocumentServiceFactory implements IDocumentServiceFactory {
32
+ async createDocumentService(resolvedUrl: IResolvedUrl): Promise<IDocumentService> {
33
+ return new FrozenDocumentService(resolvedUrl);
34
+ }
35
+ async createContainer(): Promise<IDocumentService> {
36
+ throw new Error("The FrozenDocumentServiceFactory cannot be used to create containers.");
37
+ }
38
+ }
39
+
40
+ class FrozenDocumentService
41
+ extends TypedEventEmitter<IDocumentServiceEvents>
42
+ implements IDocumentService
43
+ {
44
+ constructor(public readonly resolvedUrl: IResolvedUrl) {
45
+ super();
46
+ }
47
+
48
+ public readonly policies: IDocumentServicePolicies = {
49
+ storageOnly: true,
50
+ };
51
+ async connectToStorage(): Promise<IDocumentStorageService> {
52
+ return frozenDocumentStorageService;
53
+ }
54
+ async connectToDeltaStorage(): Promise<IDocumentDeltaStorageService> {
55
+ return frozenDocumentDeltaStorageService;
56
+ }
57
+ async connectToDeltaStream(client: IClient): Promise<IDocumentDeltaConnection> {
58
+ return new FrozenDeltaStream();
59
+ }
60
+ dispose(): void {}
61
+ }
62
+
63
+ const frozenDocumentStorageServiceHandler = (): never => {
64
+ throw new Error("Operations are not supported on the FrozenDocumentStorageService.");
65
+ };
66
+ const frozenDocumentStorageService: IDocumentStorageService = {
67
+ getSnapshotTree: frozenDocumentStorageServiceHandler,
68
+ getSnapshot: frozenDocumentStorageServiceHandler,
69
+ getVersions: frozenDocumentStorageServiceHandler,
70
+ createBlob: frozenDocumentStorageServiceHandler,
71
+ readBlob: frozenDocumentStorageServiceHandler,
72
+ uploadSummaryWithContext: frozenDocumentStorageServiceHandler,
73
+ downloadSummary: frozenDocumentStorageServiceHandler,
74
+ };
75
+
76
+ const frozenDocumentDeltaStorageService: IDocumentDeltaStorageService = {
77
+ fetchMessages: () => ({
78
+ read: async () => ({
79
+ done: true,
80
+ }),
81
+ }),
82
+ };
83
+
84
+ const clientFrozenDeltaStream: IClient = {
85
+ mode: "read",
86
+ details: { capabilities: { interactive: true } },
87
+ permission: [],
88
+ user: { id: "storage-only client" }, // we need some "fake" ID here.
89
+ scopes: [],
90
+ };
91
+ const clientIdFrozenDeltaStream: string = "storage-only client";
92
+
93
+ /**
94
+ * Implementation of IDocumentDeltaConnection that does not support submitting
95
+ * or receiving ops. Used in storage-only mode and in frozen loads.
96
+ */
97
+ export class FrozenDeltaStream
98
+ extends TypedEventEmitter<IDocumentDeltaConnectionEvents>
99
+ implements IDocumentDeltaConnection, IDisposable
100
+ {
101
+ clientId = clientIdFrozenDeltaStream;
102
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
103
+ claims = {
104
+ scopes: [ScopeType.DocRead],
105
+ } as ITokenClaims;
106
+ mode: ConnectionMode = "read";
107
+ existing: boolean = true;
108
+ maxMessageSize: number = 0;
109
+ version: string = "";
110
+ initialMessages: ISequencedDocumentMessage[] = [];
111
+ initialSignals: ISignalMessage[] = [];
112
+ initialClients: ISignalClient[] = [
113
+ { client: clientFrozenDeltaStream, clientId: clientIdFrozenDeltaStream },
114
+ ];
115
+ serviceConfiguration: IClientConfiguration = {
116
+ maxMessageSize: 0,
117
+ blockSize: 0,
118
+ };
119
+ checkpointSequenceNumber?: number | undefined = undefined;
120
+ /**
121
+ * Connection which is not connected to socket.
122
+ * @param storageOnlyReason - Reason on why the connection to delta stream is not allowed.
123
+ * @param readonlyConnectionReason - reason/error if any which lead to using FrozenDeltaStream.
124
+ */
125
+ constructor(
126
+ public readonly storageOnlyReason?: string,
127
+ public readonly readonlyConnectionReason?: IConnectionStateChangeReason,
128
+ ) {
129
+ super();
130
+ }
131
+ submit(messages: IDocumentMessage[]): void {
132
+ this.emit(
133
+ "nack",
134
+ this.clientId,
135
+ messages.map((operation) => {
136
+ return {
137
+ operation,
138
+ content: { message: "Cannot submit with storage-only connection", code: 403 },
139
+ };
140
+ }),
141
+ );
142
+ }
143
+ submitSignal(message: unknown): void {
144
+ this.emit("nack", this.clientId, {
145
+ operation: message,
146
+ content: { message: "Cannot submit signal with storage-only connection", code: 403 },
147
+ });
148
+ }
149
+
150
+ private _disposed = false;
151
+ public get disposed(): boolean {
152
+ return this._disposed;
153
+ }
154
+ public dispose(): void {
155
+ this._disposed = true;
156
+ }
157
+ }
158
+ export function isFrozenDeltaStreamConnection(
159
+ connection: unknown,
160
+ ): connection is FrozenDeltaStream {
161
+ return connection instanceof FrozenDeltaStream;
162
+ }
package/src/index.ts CHANGED
@@ -4,15 +4,17 @@
4
4
  */
5
5
 
6
6
  export { ConnectionState } from "./connectionState.js";
7
- export { type IContainerExperimental, waitContainerToCatchUp } from "./container.js";
7
+ export { type ContainerAlpha, waitContainerToCatchUp, asLegacyAlpha } from "./container.js";
8
8
  export {
9
9
  createDetachedContainer,
10
10
  loadExistingContainer,
11
11
  rehydrateDetachedContainer,
12
+ loadFrozenContainerFromPendingState,
12
13
  type ICreateAndLoadContainerProps,
13
14
  type ICreateDetachedContainerProps,
14
15
  type ILoadExistingContainerProps,
15
16
  type IRehydrateDetachedContainerProps,
17
+ type ILoadFrozenContainerFromPendingStateProps,
16
18
  } from "./createAndLoadContainerUtils.js";
17
19
  export {
18
20
  type ICodeDetailsLoader,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.62.0-356644";
9
+ export const pkgVersion = "2.62.0";