@fluidframework/container-loader 2.101.0 → 2.102.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.
@@ -13,11 +13,11 @@ export declare const loaderCoreCompatDetails: {
13
13
  /**
14
14
  * The package version of the Loader layer.
15
15
  */
16
- readonly pkgVersion: "2.101.0";
16
+ readonly pkgVersion: "2.102.0";
17
17
  /**
18
18
  * The current generation of the Loader layer.
19
19
  */
20
- readonly generation: 6;
20
+ readonly generation: 7;
21
21
  };
22
22
  /**
23
23
  * Loader's compatibility details that is exposed to the Runtime layer.
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-loader";
8
- export declare const pkgVersion = "2.101.0";
8
+ export declare const pkgVersion = "2.102.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-loader";
8
- export const pkgVersion = "2.101.0";
8
+ export const pkgVersion = "2.102.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.101.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"2.102.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotRefresher.d.ts","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAEN,KAAK,6CAA6C,EAClD,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AAyBrC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAyBnD,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,cAAc,CAA4B;IAGlD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,cAAc,CAS7B;IACF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA+B;gBAIvE,SAAS,EAAE,oBAAoB,EACd,cAAc,EAAE,6CAA6C,EAC7D,kBAAkB,EAAE,OAAO,EAC3B,qBAAqB,EAAE,MAAM,OAAO,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,EACzE,wBAAwB,CAAC,EAAE,MAAM;IAmB3B,kBAAkB,IAAI,IAAI;IAYjC;;;;;OAKG;YACW,qBAAqB;IAsCnC;;;OAGG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,UAAU,IAAI,IAAI;IAIzB;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;;OAGG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAEzD;IAED;;OAEG;IACI,OAAO,IAAI,IAAI;CAItB"}
1
+ {"version":3,"file":"snapshotRefresher.d.ts","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAQ5E,OAAO,EAEN,KAAK,6CAA6C,EAClD,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AAyBrC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAyBnD,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,cAAc,CAA4B;IAGlD,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,cAAc,CAS7B;IACF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAA+B;gBAIvE,SAAS,EAAE,oBAAoB,EACd,cAAc,EAAE,6CAA6C,EAC7D,kBAAkB,EAAE,OAAO,EAC3B,qBAAqB,EAAE,MAAM,OAAO,EACpC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,EACzE,wBAAwB,CAAC,EAAE,MAAM;IAkB3B,kBAAkB,IAAI,IAAI;IAYjC;;;;;OAKG;YACW,qBAAqB;IAsCnC;;;OAGG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,UAAU,IAAI,IAAI;IAIzB;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;;OAGG;IACH,IAAW,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAEzD;IAED;;OAEG;IACI,OAAO,IAAI,IAAI;CAItB"}
@@ -79,8 +79,7 @@ export class SnapshotRefresher {
79
79
  });
80
80
  this.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;
81
81
  __classPrivateFieldSet(this, _SnapshotRefresher_snapshotRefreshEnabled, this.offlineLoadEnabled &&
82
- (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ??
83
- this.mc.config.getBoolean("Fluid.Container.enableOfflineFull")) === true, "f");
82
+ (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ?? false), "f");
84
83
  this.refreshTimer = __classPrivateFieldGet(this, _SnapshotRefresher_snapshotRefreshEnabled, "f")
85
84
  ? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())
86
85
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotRefresher.js","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert, Timer } from \"@fluidframework/core-utils/internal\";\nimport { FetchSource } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tcreateChildMonitoringContext,\n\ttype MonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetLatestSnapshotInfo,\n\ttype ISerializedStateManagerDocumentStorageService,\n\ttype ISnapshotInfo,\n} from \"./serializedStateManager.js\";\n\nclass RefreshPromiseTracker {\n\tpublic get hasPromise(): boolean {\n\t\treturn this.#promise !== undefined;\n\t}\n\tpublic get promise(): Promise<number> | undefined {\n\t\treturn this.#promise;\n\t}\n\tconstructor(private readonly catchHandler: (error: Error) => void) {}\n\n\t#promise: Promise<number> | undefined;\n\tsetPromise(p: Promise<number>): void {\n\t\tif (this.hasPromise) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cannot start new snapshot refresh while a refresh is already in progress\",\n\t\t\t);\n\t\t}\n\t\tthis.#promise = p.finally(() => {\n\t\t\tthis.#promise = undefined;\n\t\t});\n\t\tp.catch(this.catchHandler);\n\t}\n}\n\n/**\n * Manages periodic refresh of the latest snapshot for a document.\n *\n * `SnapshotRefresher` polls the storage service for the most recent snapshot and, when a newer\n * snapshot is discovered, invokes the provided `onSnapshotRefreshed` callback with the updated\n * snapshot metadata. It is responsible for:\n *\n * - Tracking the most recent snapshot that has been observed.\n * - Scheduling and managing refresh attempts via an internal timer.\n * - Emitting telemetry for successful and failed refresh attempts.\n *\n * The refresh behavior can be configured via constructor arguments, including whether offline\n * loading and the `getSnapshot` API are supported, as well as the refresh timeout. Callers\n * should dispose this instance when snapshot refresh is no longer needed to stop any pending\n * timers and prevent further refresh attempts.\n */\nexport class SnapshotRefresher implements IDisposable {\n\tprivate readonly mc: MonitoringContext;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\t#disposed: boolean = false;\n\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\n\tprivate readonly refreshTracker = new RefreshPromiseTracker(\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\t(error) =>\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"RefreshLatestSnapshotFailed\",\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t),\n\t);\n\tprivate readonly refreshTimer: Timer | undefined;\n\tprivate readonly snapshotRefreshTimeoutMs: number = 60 * 60 * 24 * 1000;\n\treadonly #snapshotRefreshEnabled: boolean;\n\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tprivate readonly onSnapshotRefreshed: (snapshot: ISnapshotInfo) => number,\n\t\tsnapshotRefreshTimeoutMs?: number,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\n\t\tthis.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;\n\n\t\tthis.#snapshotRefreshEnabled =\n\t\t\tthis.offlineLoadEnabled &&\n\t\t\t(this.mc.config.getBoolean(\"Fluid.Container.enableOfflineSnapshotRefresh\") ??\n\t\t\t\tthis.mc.config.getBoolean(\"Fluid.Container.enableOfflineFull\")) === true;\n\n\t\tthis.refreshTimer = this.#snapshotRefreshEnabled\n\t\t\t? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())\n\t\t\t: undefined;\n\t}\n\n\tpublic tryRefreshSnapshot(): void {\n\t\tif (\n\t\t\tthis.#snapshotRefreshEnabled &&\n\t\t\t!this.#disposed &&\n\t\t\t!this.refreshTracker.hasPromise &&\n\t\t\tthis.latestSnapshot === undefined\n\t\t) {\n\t\t\t// Don't block on the refresh snapshot call - it is for the next time we serialize, not booting this incarnation\n\t\t\tthis.refreshTracker.setPromise(this.refreshLatestSnapshot(this.supportGetSnapshotApi()));\n\t\t}\n\t}\n\n\t/**\n\t * Fetch the latest snapshot for the container, including delay-loaded groupIds if pendingLocalState was provided and contained any groupIds.\n\t * Note that this will update the StorageAdapter's cached snapshots for the groupIds (if present)\n\t *\n\t * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree (must be true to fetch by groupIds)\n\t */\n\tprivate async refreshLatestSnapshot(supportGetSnapshotApi: boolean): Promise<number> {\n\t\tthis.latestSnapshot = await getLatestSnapshotInfo(\n\t\t\tthis.mc,\n\t\t\tthis.storageAdapter,\n\t\t\tsupportGetSnapshotApi,\n\t\t);\n\n\t\tif (this.#disposed) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// These are loading groupIds that the containerRuntime has requested over its lifetime.\n\t\t// We will fetch the latest snapshot for the groupIds, which will update storageAdapter.loadedGroupIdSnapshots's cache\n\t\tconst downloadedGroupIds = Object.keys(this.storageAdapter.loadedGroupIdSnapshots);\n\t\tif (supportGetSnapshotApi && downloadedGroupIds.length > 0) {\n\t\t\tassert(\n\t\t\t\tthis.storageAdapter.getSnapshot !== undefined,\n\t\t\t\t0x972 /* getSnapshot should exist */,\n\t\t\t);\n\t\t\t// (This is a separate network call from above because it requires work for storage to add a special base groupId)\n\t\t\tconst snapshot = await this.storageAdapter.getSnapshot({\n\t\t\t\tversionId: undefined,\n\t\t\t\tscenarioName: \"getLatestSnapshotInfo\",\n\t\t\t\tcacheSnapshot: false,\n\t\t\t\tloadingGroupIds: downloadedGroupIds,\n\t\t\t\tfetchSource: FetchSource.noCache,\n\t\t\t});\n\t\t\tassert(snapshot !== undefined, 0x973 /* Snapshot should exist */);\n\t\t}\n\n\t\t// Notify the manager about the fetched snapshot - let it decide what to do with it\n\t\tconst result =\n\t\t\tthis.latestSnapshot === undefined ? -1 : this.onSnapshotRefreshed(this.latestSnapshot);\n\n\t\tthis.refreshTimer?.restart();\n\t\treturn result;\n\t}\n\n\t/**\n\t * Clears the latest snapshot after it's been consumed by the manager.\n\t * This allows the next refresh cycle to proceed.\n\t */\n\tpublic clearLatestSnapshot(): void {\n\t\tthis.latestSnapshot = undefined;\n\t}\n\n\t/**\n\t * Starts the refresh timer.\n\t */\n\tpublic startTimer(): void {\n\t\tthis.refreshTimer?.start();\n\t}\n\n\t/**\n\t * Restarts the refresh timer.\n\t */\n\tpublic restartTimer(): void {\n\t\tthis.refreshTimer?.restart();\n\t}\n\n\t/**\n\t * Gets the current refresh promise for testing purposes.\n\t * @returns The snapshot sequence number promise, or undefined if no refresh is in progress\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.refreshTracker.promise;\n\t}\n\n\t/**\n\t * Disposes the refresher and clears the timer.\n\t */\n\tpublic dispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.refreshTimer?.clear();\n\t}\n}\n"]}
1
+ {"version":3,"file":"snapshotRefresher.js","sourceRoot":"","sources":["../src/snapshotRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport type { IDisposable } from \"@fluidframework/core-interfaces/internal\";\nimport { assert, Timer } from \"@fluidframework/core-utils/internal\";\nimport { FetchSource } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tcreateChildMonitoringContext,\n\ttype MonitoringContext,\n} from \"@fluidframework/telemetry-utils/internal\";\n\nimport {\n\tgetLatestSnapshotInfo,\n\ttype ISerializedStateManagerDocumentStorageService,\n\ttype ISnapshotInfo,\n} from \"./serializedStateManager.js\";\n\nclass RefreshPromiseTracker {\n\tpublic get hasPromise(): boolean {\n\t\treturn this.#promise !== undefined;\n\t}\n\tpublic get promise(): Promise<number> | undefined {\n\t\treturn this.#promise;\n\t}\n\tconstructor(private readonly catchHandler: (error: Error) => void) {}\n\n\t#promise: Promise<number> | undefined;\n\tsetPromise(p: Promise<number>): void {\n\t\tif (this.hasPromise) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Cannot start new snapshot refresh while a refresh is already in progress\",\n\t\t\t);\n\t\t}\n\t\tthis.#promise = p.finally(() => {\n\t\t\tthis.#promise = undefined;\n\t\t});\n\t\tp.catch(this.catchHandler);\n\t}\n}\n\n/**\n * Manages periodic refresh of the latest snapshot for a document.\n *\n * `SnapshotRefresher` polls the storage service for the most recent snapshot and, when a newer\n * snapshot is discovered, invokes the provided `onSnapshotRefreshed` callback with the updated\n * snapshot metadata. It is responsible for:\n *\n * - Tracking the most recent snapshot that has been observed.\n * - Scheduling and managing refresh attempts via an internal timer.\n * - Emitting telemetry for successful and failed refresh attempts.\n *\n * The refresh behavior can be configured via constructor arguments, including whether offline\n * loading and the `getSnapshot` API are supported, as well as the refresh timeout. Callers\n * should dispose this instance when snapshot refresh is no longer needed to stop any pending\n * timers and prevent further refresh attempts.\n */\nexport class SnapshotRefresher implements IDisposable {\n\tprivate readonly mc: MonitoringContext;\n\tprivate latestSnapshot: ISnapshotInfo | undefined;\n\t#disposed: boolean = false;\n\n\tpublic get disposed(): boolean {\n\t\treturn this.#disposed;\n\t}\n\n\tprivate readonly refreshTracker = new RefreshPromiseTracker(\n\t\t// eslint-disable-next-line unicorn/consistent-function-scoping\n\t\t(error) =>\n\t\t\tthis.mc.logger.sendErrorEvent(\n\t\t\t\t{\n\t\t\t\t\teventName: \"RefreshLatestSnapshotFailed\",\n\t\t\t\t},\n\t\t\t\terror,\n\t\t\t),\n\t);\n\tprivate readonly refreshTimer: Timer | undefined;\n\tprivate readonly snapshotRefreshTimeoutMs: number = 60 * 60 * 24 * 1000;\n\treadonly #snapshotRefreshEnabled: boolean;\n\n\tconstructor(\n\t\tsubLogger: ITelemetryBaseLogger,\n\t\tprivate readonly storageAdapter: ISerializedStateManagerDocumentStorageService,\n\t\tprivate readonly offlineLoadEnabled: boolean,\n\t\tprivate readonly supportGetSnapshotApi: () => boolean,\n\t\tprivate readonly onSnapshotRefreshed: (snapshot: ISnapshotInfo) => number,\n\t\tsnapshotRefreshTimeoutMs?: number,\n\t) {\n\t\tthis.mc = createChildMonitoringContext({\n\t\t\tlogger: subLogger,\n\t\t\tnamespace: \"serializedStateManager\",\n\t\t});\n\n\t\tthis.snapshotRefreshTimeoutMs = snapshotRefreshTimeoutMs ?? this.snapshotRefreshTimeoutMs;\n\n\t\tthis.#snapshotRefreshEnabled =\n\t\t\tthis.offlineLoadEnabled &&\n\t\t\t(this.mc.config.getBoolean(\"Fluid.Container.enableOfflineSnapshotRefresh\") ?? false);\n\n\t\tthis.refreshTimer = this.#snapshotRefreshEnabled\n\t\t\t? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())\n\t\t\t: undefined;\n\t}\n\n\tpublic tryRefreshSnapshot(): void {\n\t\tif (\n\t\t\tthis.#snapshotRefreshEnabled &&\n\t\t\t!this.#disposed &&\n\t\t\t!this.refreshTracker.hasPromise &&\n\t\t\tthis.latestSnapshot === undefined\n\t\t) {\n\t\t\t// Don't block on the refresh snapshot call - it is for the next time we serialize, not booting this incarnation\n\t\t\tthis.refreshTracker.setPromise(this.refreshLatestSnapshot(this.supportGetSnapshotApi()));\n\t\t}\n\t}\n\n\t/**\n\t * Fetch the latest snapshot for the container, including delay-loaded groupIds if pendingLocalState was provided and contained any groupIds.\n\t * Note that this will update the StorageAdapter's cached snapshots for the groupIds (if present)\n\t *\n\t * @param supportGetSnapshotApi - a boolean indicating whether to use the fetchISnapshot or fetchISnapshotTree (must be true to fetch by groupIds)\n\t */\n\tprivate async refreshLatestSnapshot(supportGetSnapshotApi: boolean): Promise<number> {\n\t\tthis.latestSnapshot = await getLatestSnapshotInfo(\n\t\t\tthis.mc,\n\t\t\tthis.storageAdapter,\n\t\t\tsupportGetSnapshotApi,\n\t\t);\n\n\t\tif (this.#disposed) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// These are loading groupIds that the containerRuntime has requested over its lifetime.\n\t\t// We will fetch the latest snapshot for the groupIds, which will update storageAdapter.loadedGroupIdSnapshots's cache\n\t\tconst downloadedGroupIds = Object.keys(this.storageAdapter.loadedGroupIdSnapshots);\n\t\tif (supportGetSnapshotApi && downloadedGroupIds.length > 0) {\n\t\t\tassert(\n\t\t\t\tthis.storageAdapter.getSnapshot !== undefined,\n\t\t\t\t0x972 /* getSnapshot should exist */,\n\t\t\t);\n\t\t\t// (This is a separate network call from above because it requires work for storage to add a special base groupId)\n\t\t\tconst snapshot = await this.storageAdapter.getSnapshot({\n\t\t\t\tversionId: undefined,\n\t\t\t\tscenarioName: \"getLatestSnapshotInfo\",\n\t\t\t\tcacheSnapshot: false,\n\t\t\t\tloadingGroupIds: downloadedGroupIds,\n\t\t\t\tfetchSource: FetchSource.noCache,\n\t\t\t});\n\t\t\tassert(snapshot !== undefined, 0x973 /* Snapshot should exist */);\n\t\t}\n\n\t\t// Notify the manager about the fetched snapshot - let it decide what to do with it\n\t\tconst result =\n\t\t\tthis.latestSnapshot === undefined ? -1 : this.onSnapshotRefreshed(this.latestSnapshot);\n\n\t\tthis.refreshTimer?.restart();\n\t\treturn result;\n\t}\n\n\t/**\n\t * Clears the latest snapshot after it's been consumed by the manager.\n\t * This allows the next refresh cycle to proceed.\n\t */\n\tpublic clearLatestSnapshot(): void {\n\t\tthis.latestSnapshot = undefined;\n\t}\n\n\t/**\n\t * Starts the refresh timer.\n\t */\n\tpublic startTimer(): void {\n\t\tthis.refreshTimer?.start();\n\t}\n\n\t/**\n\t * Restarts the refresh timer.\n\t */\n\tpublic restartTimer(): void {\n\t\tthis.refreshTimer?.restart();\n\t}\n\n\t/**\n\t * Gets the current refresh promise for testing purposes.\n\t * @returns The snapshot sequence number promise, or undefined if no refresh is in progress\n\t */\n\tpublic get refreshSnapshotP(): Promise<number> | undefined {\n\t\treturn this.refreshTracker.promise;\n\t}\n\n\t/**\n\t * Disposes the refresher and clears the timer.\n\t */\n\tpublic dispose(): void {\n\t\tthis.#disposed = true;\n\t\tthis.refreshTimer?.clear();\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.101.0",
3
+ "version": "2.102.0",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -129,13 +129,13 @@
129
129
  "temp-directory": "nyc/.nyc_output"
130
130
  },
131
131
  "dependencies": {
132
- "@fluid-internal/client-utils": "~2.101.0",
133
- "@fluidframework/container-definitions": "~2.101.0",
134
- "@fluidframework/core-interfaces": "~2.101.0",
135
- "@fluidframework/core-utils": "~2.101.0",
136
- "@fluidframework/driver-definitions": "~2.101.0",
137
- "@fluidframework/driver-utils": "~2.101.0",
138
- "@fluidframework/telemetry-utils": "~2.101.0",
132
+ "@fluid-internal/client-utils": "~2.102.0",
133
+ "@fluidframework/container-definitions": "~2.102.0",
134
+ "@fluidframework/core-interfaces": "~2.102.0",
135
+ "@fluidframework/core-utils": "~2.102.0",
136
+ "@fluidframework/driver-definitions": "~2.102.0",
137
+ "@fluidframework/driver-utils": "~2.102.0",
138
+ "@fluidframework/telemetry-utils": "~2.102.0",
139
139
  "debug": "^4.3.4",
140
140
  "double-ended-queue": "^2.1.0-0",
141
141
  "events_pkg": "npm:events@^3.1.0",
@@ -144,13 +144,13 @@
144
144
  "devDependencies": {
145
145
  "@arethetypeswrong/cli": "^0.18.2",
146
146
  "@biomejs/biome": "~2.4.5",
147
- "@fluid-internal/client-utils": "~2.101.0",
148
- "@fluid-internal/mocha-test-setup": "~2.101.0",
149
- "@fluid-private/test-loader-utils": "~2.101.0",
147
+ "@fluid-internal/client-utils": "~2.102.0",
148
+ "@fluid-internal/mocha-test-setup": "~2.102.0",
149
+ "@fluid-private/test-loader-utils": "~2.102.0",
150
150
  "@fluid-tools/build-cli": "^0.65.0",
151
151
  "@fluidframework/build-common": "^2.0.3",
152
152
  "@fluidframework/build-tools": "^0.65.0",
153
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.92.0",
153
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.101.0",
154
154
  "@fluidframework/eslint-config-fluid": "^9.0.0",
155
155
  "@microsoft/api-extractor": "7.58.1",
156
156
  "@types/debug": "^4.1.5",
package/src/container.ts CHANGED
@@ -2614,6 +2614,14 @@ export class Container
2614
2614
 
2615
2615
  /**
2616
2616
  * IContainer interface that includes experimental features still under development.
2617
+ *
2618
+ * @remarks
2619
+ * For `getPendingLocalState`, prefer
2620
+ * {@link @fluidframework/container-definitions#IContainer.getPendingLocalState | IContainer.getPendingLocalState}
2621
+ * on the `@legacy @beta` surface. This interface is retained for callers that require the
2622
+ * typed-required (non-optional) shape and will be removed in a future breaking release once
2623
+ * `IContainer.getPendingLocalState` is made required.
2624
+ *
2617
2625
  * @alpha @legacy @sealed
2618
2626
  */
2619
2627
  export interface ContainerAlpha extends IContainer {
@@ -2628,6 +2636,13 @@ export interface ContainerAlpha extends IContainer {
2628
2636
 
2629
2637
  /**
2630
2638
  * Converts types to their alpha counterparts to expose alpha functionality.
2639
+ *
2640
+ * @remarks
2641
+ * For `getPendingLocalState`, prefer calling
2642
+ * {@link @fluidframework/container-definitions#IContainer.getPendingLocalState | IContainer.getPendingLocalState}
2643
+ * directly on the `@legacy @beta` surface. This helper is retained for callers that need the
2644
+ * typed-required shape and will be removed in a future breaking release.
2645
+ *
2631
2646
  * @legacy @alpha
2632
2647
  */
2633
2648
  export function asLegacyAlpha(base: IContainer): ContainerAlpha {
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.101.0";
9
+ export const pkgVersion = "2.102.0";
@@ -97,8 +97,7 @@ export class SnapshotRefresher implements IDisposable {
97
97
 
98
98
  this.#snapshotRefreshEnabled =
99
99
  this.offlineLoadEnabled &&
100
- (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ??
101
- this.mc.config.getBoolean("Fluid.Container.enableOfflineFull")) === true;
100
+ (this.mc.config.getBoolean("Fluid.Container.enableOfflineSnapshotRefresh") ?? false);
102
101
 
103
102
  this.refreshTimer = this.#snapshotRefreshEnabled
104
103
  ? new Timer(this.snapshotRefreshTimeoutMs, () => this.tryRefreshSnapshot())