@fluidframework/driver-definitions 3.1.0 → 3.3.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 +40 -0
- package/dist/serviceClient.d.ts +6 -3
- package/dist/serviceClient.d.ts.map +1 -1
- package/dist/serviceClient.js.map +1 -1
- package/lib/serviceClient.d.ts +6 -3
- package/lib/serviceClient.d.ts.map +1 -1
- package/lib/serviceClient.js.map +1 -1
- package/package.json +3 -3
- package/src/serviceClient.ts +10 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @fluidframework/driver-definitions
|
|
2
2
|
|
|
3
|
+
## 3.3.0
|
|
4
|
+
|
|
5
|
+
Dependency updates only.
|
|
6
|
+
|
|
7
|
+
## 3.2.0
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- Require the oldest supported client version in ServiceOptions ([#27902](https://github.com/microsoft/FluidFramework/pull/27902)) [da0dd40c087](https://github.com/microsoft/FluidFramework/commit/da0dd40c087b075822f0a9be723e1879f25d23b5)
|
|
12
|
+
|
|
13
|
+
The alpha [`ServiceOptions.oldestSupportedClient`](https://fluidframework.com/docs/api/driver-definitions/serviceoptions-interface#oldestsupportedclient-propertysignature) property is now required. Code that constructs service options must specify the oldest Fluid Framework client version that can open and process documents written by the service client.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const options: ServiceOptions = {
|
|
17
|
+
oldestSupportedClient: "2.100.0",
|
|
18
|
+
};
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- Collect container telemetry through ServiceClient ([#28259](https://github.com/microsoft/FluidFramework/pull/28259)) [11261004291](https://github.com/microsoft/FluidFramework/commit/11261004291599575a23483fbaf8b20f4ff1afc1)
|
|
22
|
+
|
|
23
|
+
The alpha [ServiceOptions](https://fluidframework.com/docs/api/driver-definitions/serviceoptions-interface) interface now accepts an optional `logger`.
|
|
24
|
+
Session, ephemeral, and Tinylicious clients forward telemetry from containers they create or load to this logger.
|
|
25
|
+
Existing callers can omit the option without changing their behavior.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { startEphemeralService } from "@fluidframework/local-driver/alpha";
|
|
29
|
+
|
|
30
|
+
const service = startEphemeralService();
|
|
31
|
+
const client = service.newClient({
|
|
32
|
+
oldestSupportedClient: "2.100.0",
|
|
33
|
+
logger: {
|
|
34
|
+
send(event) {
|
|
35
|
+
console.log(event);
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The same `logger` option is supported by `getSessionService().newClient(...)` and `createTinyliciousServiceClient(...)`.
|
|
42
|
+
|
|
3
43
|
## 3.1.0
|
|
4
44
|
|
|
5
45
|
Dependency updates only.
|
package/dist/serviceClient.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import type { ErasedBaseType } from "@fluidframework/core-interfaces/internal";
|
|
5
|
+
import type { ErasedBaseType, ITelemetryBaseLogger } from "@fluidframework/core-interfaces/internal";
|
|
6
6
|
/**
|
|
7
7
|
* This file defines the external facing API for the {@link ServiceClient} and related types.
|
|
8
8
|
*
|
|
@@ -142,6 +142,10 @@ export declare function featureVersion<major extends `${bigint}`, minor extends
|
|
|
142
142
|
* @alpha
|
|
143
143
|
*/
|
|
144
144
|
export interface ServiceOptions {
|
|
145
|
+
/**
|
|
146
|
+
* Optional logger that receives telemetry from containers created or loaded by this client.
|
|
147
|
+
*/
|
|
148
|
+
readonly logger?: ITelemetryBaseLogger;
|
|
145
149
|
/**
|
|
146
150
|
* Oldest Fluid Framework client version that must be able to open and process documents written
|
|
147
151
|
* by the service client.
|
|
@@ -150,9 +154,8 @@ export interface ServiceOptions {
|
|
|
150
154
|
* Choosing an older version may limit the features and write formats the application can use to
|
|
151
155
|
* those supported by that version.
|
|
152
156
|
*
|
|
153
|
-
* A service may provide a default when this option is omitted.
|
|
154
157
|
*/
|
|
155
|
-
readonly oldestSupportedClient
|
|
158
|
+
readonly oldestSupportedClient: OldestSupportedServiceClientVersion;
|
|
156
159
|
}
|
|
157
160
|
/**
|
|
158
161
|
* A {@link RegistryKey} for a {@link DataStoreKind}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceClient.d.ts","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"serviceClient.d.ts","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceClient.js","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA4FH,4CAKC;AAOD,wDAKC;AA6CD,wCAQC;AA5ED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC/B,QAAuB,EACvB,GAA2B;IAE3B,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAAI,IAAY;IACrD,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;KACvB,CAAC;AACH,CAAC;AAgCD;;;;;;;;;;;;GAYG;AACH,SAAgB,cAAc,CAC7B,OAAgF;IAEhF,6KAA6K;IAC7K,2JAA2J;IAC3J,6KAA6K;IAC7K,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAU,IAAI,MAAM,CAAC,CAAC,CAAU,IAAI,CAAC;AACxD,CAAC;AAoRD,aAAa","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ErasedBaseType } from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * This file defines the external facing API for the {@link ServiceClient} and related types.\n *\n * It provides an API surface at a similar abstraction level to aqueduct and fluid-static, but is intended to be a replacement for those which solves several problems with them.\n * Mainly it strives to have the encapsulation of implementation details (including all legacy APIs from aqueduct and lower level internals) like fluid-static\n * while being both more flexible and simpler.\n *\n * This aims to be the cleanest practical way to build applications on the Fluid Framework Client.\n * There are however several known cases where the API quality was sacrificed to ease initial implementation,\n * since some of the unification desired in this API's design are not yet implemented in the underlying Fluid Framework Client code or require additional work to implement.\n * These cases are called out with TODOs in this file.\n * These should be considered and addressed before stabilizing this API past alpha.\n *\n * All code interacting through this API surface within a single client must avoid using multiple copies of any Fluid Framework client package (at the same or different versions).\n * This mirrors the `@public` \"declarative model\" APIs and is a deliberate simplification of what is allowed in the legacy API surface.\n * It is enforced best-effort only: `@sealed` nominal erased types catch many mismatches at compile time, and factory identity checks throw a UsageError (\"Conflicting ... with same type\") at run time, but the checking is not exhaustive.\n * See `LayerCompatibilityUnified.md` for the full policy, rationale, and failure signatures.\n *\n * TODO:\n * Before stabilizing any of this past beta, evaluate whether this single-copy requirement must be relaxed, and if so how.\n * Whatever rule is chosen (relaxed or not) should be enforced at both compile time and run time as much as possible.\n *\n * TODO:\n * Fault isolation should be considered in this API design.\n * When are exceptions recoverable and how?\n * Likely we can fault isolate exceptions to containers in most cases,\n * and containers can indicate their status by being closed or disposed.\n * Non fatal errors should not be exceptions.\n */\n\n// #region Registry types\n\n/**\n * A collection of entries looked up by a `type` string.\n * @remarks\n * Use of a function for this allows a few things that most collections would not:\n * 1. It's possible to generate placeholder / error values on demand.\n * 2. It makes loading from some external registry on demand practical.\n * 3. The lookup can throw an exception if appropriate (this would typically indicate a bug and produce a fatal error).\n * 4. Generation of values can be lazy, and even asynchronous if `T` allows for a promise.\n *\n * This flexibility lets the implementer decide how to handle requests for unknown types.\n * They can produce placeholders, assert, fall back to a generic implementation etc.\n * @typeParam T - The type of entry produced for any given `type` string.\n * @input\n * @alpha\n */\nexport type Registry<T> = (type: string) => T;\n\n/**\n * A strongly typed key for a {@link Registry}.\n * Use with {@link lookupInRegistry}.\n * @remarks\n * Used to look up a `TIn` in a `Registry<TIn>`, and produce a `TOut` from it.\n * @typeParam TOut - The type produced by {@link RegistryKey.adapt} from a looked-up entry.\n * @typeParam TIn - The type of the entries in the {@link Registry} this key is used with.\n * @privateRemarks\n * This is currently input and sealed, meaning effectively type erased since the design might change.\n * @input\n * @sealed\n * @alpha\n */\nexport interface RegistryKey<TOut, TIn = unknown> {\n\t/**\n\t * Identifier to provide to the {@link Registry}.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * Convert a value from the registry to the desired output type.\n\t * @remarks\n\t * How this is done is up to the implementation.\n\t *\n\t * This might be a type guard which throws if the input is not valid.\n\t * Or it could be a conversion, an identity function, or something else.\n\t *\n\t * @param value - The value from the registry.\n\t * @returns The converted value.\n\t */\n\tadapt(value: TIn): TOut;\n}\n\n/**\n * Lookup an entry in a {@link Registry} using a {@link RegistryKey}.\n * @typeParam TOut - The type produced from the looked-up entry.\n * @typeParam TIn - The type of the entries in `registry`.\n * @alpha\n */\nexport function lookupInRegistry<TOut, TIn>(\n\tregistry: Registry<TIn>,\n\tkey: RegistryKey<TOut, TIn>,\n): TOut {\n\treturn key.adapt(registry(key.type));\n}\n\n/**\n * Creates a simple {@link RegistryKey} which does no type conversion.\n * @typeParam T - The type of the registry entry, which is returned unchanged by the key.\n * @alpha\n */\nexport function createBasicRegistryKey<T>(type: string): RegistryKey<T, T> {\n\treturn {\n\t\ttype,\n\t\tadapt: (value) => value,\n\t};\n}\n\n// #endregion\n\n// #region ServiceClient types\n\n/**\n * Oldest Fluid Framework client version that must be able to open and process documents written\n * by a service client.\n * @remarks\n * A string in SemVer format indicating a specific stable version of the Fluid Framework client package.\n *\n * Service clients use this value to select write formats and features. Clients using this version\n * or newer must be able to open and process documents written by the service client. Choosing an\n * older version may limit the features and write formats the application can use to those\n * supported by that version.\n *\n * Cannot exceed the version of any Fluid Framework client package in use by the local client.\n *\n * @privateRemarks\n * This is similar to, and a subset of, the `OldestSupportedClientVersion` type in `@fluidframework/runtime-definitions`.\n * This differs in that:\n * - This is `alpha` instead of `public`.\n * - This is available to drivers due to its location in `driver-definitions` instead of `runtime-definitions`.\n * - Patch versions cannot be set: a given minor release is not guaranteed to be greater or equal compat wise to all patches of the previous release, so we do not enable features based on patch versions (instead fall back to the next minor if needed).\n * Therefore allowing patch versions here could be misleading and could lead to bugs.\n *\n * @input\n * @alpha\n */\nexport type OldestSupportedServiceClientVersion = `${2 | 3}.${bigint}.0`;\n\n/**\n * Strips patch and prerelease from a SemVer string, returning only the major and minor version with a \".0\" patch.\n * @remarks\n * This formats a version in the same style used by {@link OldestSupportedServiceClientVersion}, specifying only the major and minor versions,\n * which are the portions used for feature selection.\n * @typeParam major - The major version number of `version` as a string, preserved in the result type.\n * @typeParam minor - The minor version number of `version` as a string, preserved in the result type.\n * @privateRemarks\n * This fills a similar role as cleanedPackageVersion in `@fluidframework/runtime-utils`.\n * It can be used to workaround our generated pkgVersion values being invalid\n * `OldestSupportedServiceClientVersion` on CI due to prerelease or patched release branches.\n * @alpha\n */\nexport function featureVersion<major extends `${bigint}`, minor extends `${bigint}`>(\n\tversion: `${major}.${minor}.${bigint}-${string}` | `${major}.${minor}.${bigint}`,\n): `${major}.${minor}.0` {\n\t// The SemVer package could be used to parse this version, but it wouldn't gain us anything, and would just make it harder to determine that the down casting below is valid.\n\t// Since we have a strongly typed string input, we know exactly which formats are allowed, so we don't need its more general parsing and validation either.\n\t// If we wanted to preserve the patch or prerelease version, that would require more complex parsing and would justify using the SemVer package, but we don't need that here.\n\tconst parsed = version.split(\".\");\n\treturn `${parsed[0] as major}.${parsed[1] as minor}.0`;\n}\n\n/**\n * Options for configuring a {@link ServiceClient}.\n * @remarks\n * These are the options which apply to all services.\n *\n * Individual services will extend with additional options.\n *\n * @input\n * @alpha\n */\nexport interface ServiceOptions {\n\t/**\n\t * Oldest Fluid Framework client version that must be able to open and process documents written\n\t * by the service client.\n\t *\n\t * @remarks\n\t * Choosing an older version may limit the features and write formats the application can use to\n\t * those supported by that version.\n\t *\n\t * A service may provide a default when this option is omitted.\n\t */\n\treadonly oldestSupportedClient?: OldestSupportedServiceClientVersion;\n}\n\n/**\n * A {@link RegistryKey} for a {@link DataStoreKind}.\n * @remarks\n * This is implemented by {@link DataStoreKind}, but alternative implementations can be used if needed.\n *\n * If you want lazy loading and need a key that does not eagerly load the {@link DataStoreKind}, an alternative {@link DataStoreKey} can be implemented.\n * @typeParam T - The type to expose from the {@link DataStoreKind} this key resolves to.\n * @typeParam TAll - The type covering all {@link DataStoreKind}s in the {@link Registry} this key is used with.\n * @privateRemarks\n * TODO: A built in common pattern for the lazy key case should be provided.\n * TODO: things probably break if \"adapt\" does anything except throw or return the result from the input promise.\n * @input\n * @alpha\n */\nexport type DataStoreKey<T, TAll = unknown> = RegistryKey<\n\tPromise<DataStoreKind<T>>,\n\tPromise<DataStoreKind<TAll>>\n>;\n\n/**\n * A context which has a registry and can create data stores using it.\n * @sealed\n * @alpha\n */\nexport interface DataStoreCreator {\n\t/**\n\t * Create a new detached data store `T` which can be attached to the {@link FluidContainer}.\n\t * by adding a handle to a data store or shared object which is already attached to the {@link FluidContainer}.\n\t * @remarks\n\t * `kind` will be looked up in the {@link Registry} used to create or load this {@link DataStoreCreator}.\n\t * It is up to that registry to decide how it handles unknown types, for example by throwing an exception or returning a placeholder.\n\t * @typeParam T - type implemented by the data store to expose in the result, as defined by `kind`.\n\t */\n\tcreateDataStore<T>(kind: DataStoreKey<T>): Promise<T>;\n}\n\n/**\n * A Fluid container.\n * @remarks\n * A document which can be stored to or loaded from a Fluid service using a {@link ServiceClient}.\n *\n * @typeParam TData - The type of the container's root data store, exposed via {@link FluidContainer.data}.\n * @privateRemarks\n * This will likely end up needing many of IFluidContainer's APIs, like disconnect, connectionState, events etc.\n * Before adding them though, care should be taken to consider if they can be improved or simplified.\n * For example maybe a single status enum for `detached -> attaching -> dirty -> saved -> closed` would be good.\n * Or maybe `detached -> attaching -> attached -> closed` and a timer for how long since the last unsaved change was created.\n *\n * The underlying IContainer has a lifecycle which includes both a closed and disposed state.\n * This should be avoidable: the closed but not disposed state exists so its possible to read out some state at that time.\n * We have made the close remove all the timers, so the the dispose step should be unnecessary and we can just have a single closed state.\n *\n * @sealed\n * @alpha\n */\nexport interface FluidContainer<TData = unknown>\n\textends DataStoreCreator,\n\t\tErasedBaseType<readonly [\"FluidContainer\", TData]> {\n\t/**\n\t * The unique identifier for this container within its service.\n\t * @remarks\n\t * `undefined` if the container has not yet been attached to a service.\n\t * This can be used to load another instance of this container from the service using {@link ServiceClient.loadContainer}.\n\t */\n\treadonly id?: string | undefined;\n\n\t/**\n\t * The root data store of the container.\n\t * @remarks\n\t * The type of the root data store is defined by the {@link DataStoreKind} used to create the container.\n\t */\n\treadonly data: TData;\n\n\t/**\n\t * Close the container, stopping all networking and cancelling runtime timers.\n\t *\n\t * @remarks\n\t * After calling `close()`, the container's data can still be read but no further operations can be sent.\n\t * @privateRemarks\n\t * TODO: we should document the what the expected behavior is if one tries to modify the data after close, or tries to call close multiple times.\n\t * TODO: we also likely want to have a way to detect if closed and events for on close.\n\t * TODO: ensure this truly closes all timers: it seems like we might still leak some related to the summarizer.\n\t * TODO: we should clarify how this interacts with unsaved content including inprogress summaries,\n\t * and likely also provide an async API with some options for how to handle that.\n\t */\n\tclose(): void;\n}\n\n/**\n * A Fluid container with an associated {@link ServiceClient} it can attach to.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerWithService<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * Attaches this container to the associated service client.\n\t *\n\t * The returned promise resolves once the container is attached: the container from the promise is the same one passed in as the argument.\n\t */\n\tattach(): Promise<FluidContainerAttached<TData>>;\n\n\t// This could expose access to the ServiceClient if needed.\n}\n\n/**\n * A Fluid container that has been attached to a service.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerAttached<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * {@inheritdoc FluidContainer.id}\n\t */\n\treadonly id: string;\n}\n\n/**\n * Defines a {@link https://en.wikipedia.org/wiki/Kind_(type_theory) | kind} of data store, allowing creating and loading instances of it.\n * @remarks\n * A `DataStoreKind` acts as the factory and type descriptor for a category of data store:\n * it defines the `type` used to identify the data store in a {@link DataStoreRegistry},\n * and the `T` API surface that instances of that data store expose.\n *\n * Provide a `DataStoreKind` to {@link ServiceClient.(createContainer:1)} or {@link DataStoreCreator.createDataStore}\n * to create new instances, and to {@link ServiceClient.loadContainer} to load existing ones.\n *\n * A `DataStoreKind` is not constructed directly.\n * Instead, obtain one from a framework-provided factory:\n * use {@link @fluidframework/shared-object-base#defineDataStore} to define a data store which wraps a root shared object,\n * or use a more specific wrapper around that,\n * such as {@link @fluidframework/tree#defineTreeDataStore} for a {@link @fluidframework/tree#TreeView}-backed data store.\n *\n * Since it implements {@link DataStoreKey}, a `DataStoreKind` can also be used directly as the key to look\n * itself up in a {@link Registry}.\n * @typeParam T - The API surface that instances of this data store kind expose.\n * @privateRemarks\n * TODO:\n * SharedObjects should be usable as these (though putting shared objects directly in the container might need special logic).\n * Type erased {@link IFluidDataStoreFactory}.\n * @sealed\n * @alpha\n */\nexport interface DataStoreKind<out T = unknown>\n\textends DataStoreKey<T>,\n\t\tErasedBaseType<readonly [\"DataStoreKind\", T]> {}\n\n/**\n * A registry of {@link DataStoreKind}s.\n * @privateRemarks\n * TODO: unify this with SharedObjectRegistry.\n *\n * @typeParam T - The type covering all {@link DataStoreKind}s in the registry.\n * @input\n * @alpha\n */\nexport type DataStoreRegistry<out T = unknown> = Registry<Promise<DataStoreKind<T>>>;\n\n/**\n * A connection to a Fluid storage service.\n * @sealed\n * @alpha\n */\nexport interface ServiceClient {\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKind} to use for the root.\n\t * @remarks\n\t * This overload is a shorthand for a simple case of {@link ServiceClient.(createContainer:2)}\n\t * where a single item registry is produced which contains only the root.\n\t * This is usable only when the root {@link DataStoreKind} is available eagerly (e.g. not lazy loaded),\n\t * and when the container does not need a registry for creating additional data stores beyond the root.\n\t * @privateRemarks\n\t * TODO: As this is a detached container, it should be able to be created synchronously.\n\t *\n\t * TODO: Provide more general alternative to this in the form of a service-independent `createContainer` free function.\n\t * It would work with a `ServiceClient.attachContainer<T>(detached: FluidContainer<T>): Promise<FluidContainerAttached<T>>`\n\t * which returns a promise that resolves once the detached container has been attached\n\t * (pointing to the same container object, but with the new type).\n\t *\n\t * Challenges:\n\t *\n\t * Currently the service must be provided at creation time because `IContainer.attach` does not accept a service client,\n\t * making it unclear whether a truly service-independent path is feasible in the near term.\n\t */\n\tcreateContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKey} used to look up the root's {@link DataStoreKind} from `registry`.\n\t * @param registry - The {@link DataStoreRegistry} supplying the {@link DataStoreKind} for the root and any other data stores the container may need to create.\n\t * @remarks\n\t * Use this overload when the root {@link DataStoreKind} is not available eagerly (e.g. for lazy loading),\n\t * or when the container needs a registry for creating additional data stores beyond the root.\n\t */\n\tcreateContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:1)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t * @privateRemarks\n\t * TODO: We should fix ergonomics issues that make this helpful,\n\t * then remove (or deprecate) this method in favor of `service.attach(createContainer(root))` as a better orthogonalized API.\n\t * See private remarks on {@link ServiceClient.(createContainer:1)}.\n\t */\n\tcreateAttachedContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:2)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t */\n\tcreateAttachedContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * Loads an existing container from the service.\n\t * @typeParam T - The type of the container's root data store.\n\t * @param id - The unique identifier of the container to load.\n\t * @param root - The {@link DataStoreKind} for the root, or a registry which will be used to look up the root based on its type.\n\t *\n\t * @throws a {@link @fluidframework/telemetry-utils#UsageError} if the DataStoreKind's type (either the root directly or looked up from the registry) does not match the type of the root data store in the container.\n\t *\n\t * @privateRemarks\n\t * The ability to provide a registry here means that it's possible to:\n\t * 1. Load a container which might have a few different possible roots, for example because of versioning.\n\t * 2. Generate the DataStoreKind on demand based on the type: this approach could be used for things like debug tools which can load any possible container.\n\t * 3. Generating the DataStoreKind if the type is unrecognized, for example to provide a placeholder which might support some minimal functionality (like debug inspection, and summary).\n\t *\n\t * The ability to provide just a single DataStoreKind<T> is purely a convenience to make it cleaner to use this in simple cases.\n\t */\n\tloadContainer<T>(\n\t\tid: string,\n\t\troot: DataStoreKind<T> | DataStoreRegistry<T>,\n\t): Promise<FluidContainerAttached<T>>;\n}\n\n// #endregion\n"]}
|
|
1
|
+
{"version":3,"file":"serviceClient.js","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA+FH,4CAKC;AAOD,wDAKC;AA6CD,wCAQC;AA5ED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAC/B,QAAuB,EACvB,GAA2B;IAE3B,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAAI,IAAY;IACrD,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;KACvB,CAAC;AACH,CAAC;AAgCD;;;;;;;;;;;;GAYG;AACH,SAAgB,cAAc,CAC7B,OAAgF;IAEhF,6KAA6K;IAC7K,2JAA2J;IAC3J,6KAA6K;IAC7K,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAU,IAAI,MAAM,CAAC,CAAC,CAAU,IAAI,CAAC;AACxD,CAAC;AAwRD,aAAa","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tErasedBaseType,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * This file defines the external facing API for the {@link ServiceClient} and related types.\n *\n * It provides an API surface at a similar abstraction level to aqueduct and fluid-static, but is intended to be a replacement for those which solves several problems with them.\n * Mainly it strives to have the encapsulation of implementation details (including all legacy APIs from aqueduct and lower level internals) like fluid-static\n * while being both more flexible and simpler.\n *\n * This aims to be the cleanest practical way to build applications on the Fluid Framework Client.\n * There are however several known cases where the API quality was sacrificed to ease initial implementation,\n * since some of the unification desired in this API's design are not yet implemented in the underlying Fluid Framework Client code or require additional work to implement.\n * These cases are called out with TODOs in this file.\n * These should be considered and addressed before stabilizing this API past alpha.\n *\n * All code interacting through this API surface within a single client must avoid using multiple copies of any Fluid Framework client package (at the same or different versions).\n * This mirrors the `@public` \"declarative model\" APIs and is a deliberate simplification of what is allowed in the legacy API surface.\n * It is enforced best-effort only: `@sealed` nominal erased types catch many mismatches at compile time, and factory identity checks throw a UsageError (\"Conflicting ... with same type\") at run time, but the checking is not exhaustive.\n * See `LayerCompatibilityUnified.md` for the full policy, rationale, and failure signatures.\n *\n * TODO:\n * Before stabilizing any of this past beta, evaluate whether this single-copy requirement must be relaxed, and if so how.\n * Whatever rule is chosen (relaxed or not) should be enforced at both compile time and run time as much as possible.\n *\n * TODO:\n * Fault isolation should be considered in this API design.\n * When are exceptions recoverable and how?\n * Likely we can fault isolate exceptions to containers in most cases,\n * and containers can indicate their status by being closed or disposed.\n * Non fatal errors should not be exceptions.\n */\n\n// #region Registry types\n\n/**\n * A collection of entries looked up by a `type` string.\n * @remarks\n * Use of a function for this allows a few things that most collections would not:\n * 1. It's possible to generate placeholder / error values on demand.\n * 2. It makes loading from some external registry on demand practical.\n * 3. The lookup can throw an exception if appropriate (this would typically indicate a bug and produce a fatal error).\n * 4. Generation of values can be lazy, and even asynchronous if `T` allows for a promise.\n *\n * This flexibility lets the implementer decide how to handle requests for unknown types.\n * They can produce placeholders, assert, fall back to a generic implementation etc.\n * @typeParam T - The type of entry produced for any given `type` string.\n * @input\n * @alpha\n */\nexport type Registry<T> = (type: string) => T;\n\n/**\n * A strongly typed key for a {@link Registry}.\n * Use with {@link lookupInRegistry}.\n * @remarks\n * Used to look up a `TIn` in a `Registry<TIn>`, and produce a `TOut` from it.\n * @typeParam TOut - The type produced by {@link RegistryKey.adapt} from a looked-up entry.\n * @typeParam TIn - The type of the entries in the {@link Registry} this key is used with.\n * @privateRemarks\n * This is currently input and sealed, meaning effectively type erased since the design might change.\n * @input\n * @sealed\n * @alpha\n */\nexport interface RegistryKey<TOut, TIn = unknown> {\n\t/**\n\t * Identifier to provide to the {@link Registry}.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * Convert a value from the registry to the desired output type.\n\t * @remarks\n\t * How this is done is up to the implementation.\n\t *\n\t * This might be a type guard which throws if the input is not valid.\n\t * Or it could be a conversion, an identity function, or something else.\n\t *\n\t * @param value - The value from the registry.\n\t * @returns The converted value.\n\t */\n\tadapt(value: TIn): TOut;\n}\n\n/**\n * Lookup an entry in a {@link Registry} using a {@link RegistryKey}.\n * @typeParam TOut - The type produced from the looked-up entry.\n * @typeParam TIn - The type of the entries in `registry`.\n * @alpha\n */\nexport function lookupInRegistry<TOut, TIn>(\n\tregistry: Registry<TIn>,\n\tkey: RegistryKey<TOut, TIn>,\n): TOut {\n\treturn key.adapt(registry(key.type));\n}\n\n/**\n * Creates a simple {@link RegistryKey} which does no type conversion.\n * @typeParam T - The type of the registry entry, which is returned unchanged by the key.\n * @alpha\n */\nexport function createBasicRegistryKey<T>(type: string): RegistryKey<T, T> {\n\treturn {\n\t\ttype,\n\t\tadapt: (value) => value,\n\t};\n}\n\n// #endregion\n\n// #region ServiceClient types\n\n/**\n * Oldest Fluid Framework client version that must be able to open and process documents written\n * by a service client.\n * @remarks\n * A string in SemVer format indicating a specific stable version of the Fluid Framework client package.\n *\n * Service clients use this value to select write formats and features. Clients using this version\n * or newer must be able to open and process documents written by the service client. Choosing an\n * older version may limit the features and write formats the application can use to those\n * supported by that version.\n *\n * Cannot exceed the version of any Fluid Framework client package in use by the local client.\n *\n * @privateRemarks\n * This is similar to, and a subset of, the `OldestSupportedClientVersion` type in `@fluidframework/runtime-definitions`.\n * This differs in that:\n * - This is `alpha` instead of `public`.\n * - This is available to drivers due to its location in `driver-definitions` instead of `runtime-definitions`.\n * - Patch versions cannot be set: a given minor release is not guaranteed to be greater or equal compat wise to all patches of the previous release, so we do not enable features based on patch versions (instead fall back to the next minor if needed).\n * Therefore allowing patch versions here could be misleading and could lead to bugs.\n *\n * @input\n * @alpha\n */\nexport type OldestSupportedServiceClientVersion = `${2 | 3}.${bigint}.0`;\n\n/**\n * Strips patch and prerelease from a SemVer string, returning only the major and minor version with a \".0\" patch.\n * @remarks\n * This formats a version in the same style used by {@link OldestSupportedServiceClientVersion}, specifying only the major and minor versions,\n * which are the portions used for feature selection.\n * @typeParam major - The major version number of `version` as a string, preserved in the result type.\n * @typeParam minor - The minor version number of `version` as a string, preserved in the result type.\n * @privateRemarks\n * This fills a similar role as cleanedPackageVersion in `@fluidframework/runtime-utils`.\n * It can be used to workaround our generated pkgVersion values being invalid\n * `OldestSupportedServiceClientVersion` on CI due to prerelease or patched release branches.\n * @alpha\n */\nexport function featureVersion<major extends `${bigint}`, minor extends `${bigint}`>(\n\tversion: `${major}.${minor}.${bigint}-${string}` | `${major}.${minor}.${bigint}`,\n): `${major}.${minor}.0` {\n\t// The SemVer package could be used to parse this version, but it wouldn't gain us anything, and would just make it harder to determine that the down casting below is valid.\n\t// Since we have a strongly typed string input, we know exactly which formats are allowed, so we don't need its more general parsing and validation either.\n\t// If we wanted to preserve the patch or prerelease version, that would require more complex parsing and would justify using the SemVer package, but we don't need that here.\n\tconst parsed = version.split(\".\");\n\treturn `${parsed[0] as major}.${parsed[1] as minor}.0`;\n}\n\n/**\n * Options for configuring a {@link ServiceClient}.\n * @remarks\n * These are the options which apply to all services.\n *\n * Individual services will extend with additional options.\n *\n * @input\n * @alpha\n */\nexport interface ServiceOptions {\n\t/**\n\t * Optional logger that receives telemetry from containers created or loaded by this client.\n\t */\n\treadonly logger?: ITelemetryBaseLogger;\n\n\t/**\n\t * Oldest Fluid Framework client version that must be able to open and process documents written\n\t * by the service client.\n\t *\n\t * @remarks\n\t * Choosing an older version may limit the features and write formats the application can use to\n\t * those supported by that version.\n\t *\n\t */\n\treadonly oldestSupportedClient: OldestSupportedServiceClientVersion;\n}\n\n/**\n * A {@link RegistryKey} for a {@link DataStoreKind}.\n * @remarks\n * This is implemented by {@link DataStoreKind}, but alternative implementations can be used if needed.\n *\n * If you want lazy loading and need a key that does not eagerly load the {@link DataStoreKind}, an alternative {@link DataStoreKey} can be implemented.\n * @typeParam T - The type to expose from the {@link DataStoreKind} this key resolves to.\n * @typeParam TAll - The type covering all {@link DataStoreKind}s in the {@link Registry} this key is used with.\n * @privateRemarks\n * TODO: A built in common pattern for the lazy key case should be provided.\n * TODO: things probably break if \"adapt\" does anything except throw or return the result from the input promise.\n * @input\n * @alpha\n */\nexport type DataStoreKey<T, TAll = unknown> = RegistryKey<\n\tPromise<DataStoreKind<T>>,\n\tPromise<DataStoreKind<TAll>>\n>;\n\n/**\n * A context which has a registry and can create data stores using it.\n * @sealed\n * @alpha\n */\nexport interface DataStoreCreator {\n\t/**\n\t * Create a new detached data store `T` which can be attached to the {@link FluidContainer}.\n\t * by adding a handle to a data store or shared object which is already attached to the {@link FluidContainer}.\n\t * @remarks\n\t * `kind` will be looked up in the {@link Registry} used to create or load this {@link DataStoreCreator}.\n\t * It is up to that registry to decide how it handles unknown types, for example by throwing an exception or returning a placeholder.\n\t * @typeParam T - type implemented by the data store to expose in the result, as defined by `kind`.\n\t */\n\tcreateDataStore<T>(kind: DataStoreKey<T>): Promise<T>;\n}\n\n/**\n * A Fluid container.\n * @remarks\n * A document which can be stored to or loaded from a Fluid service using a {@link ServiceClient}.\n *\n * @typeParam TData - The type of the container's root data store, exposed via {@link FluidContainer.data}.\n * @privateRemarks\n * This will likely end up needing many of IFluidContainer's APIs, like disconnect, connectionState, events etc.\n * Before adding them though, care should be taken to consider if they can be improved or simplified.\n * For example maybe a single status enum for `detached -> attaching -> dirty -> saved -> closed` would be good.\n * Or maybe `detached -> attaching -> attached -> closed` and a timer for how long since the last unsaved change was created.\n *\n * The underlying IContainer has a lifecycle which includes both a closed and disposed state.\n * This should be avoidable: the closed but not disposed state exists so its possible to read out some state at that time.\n * We have made the close remove all the timers, so the the dispose step should be unnecessary and we can just have a single closed state.\n *\n * @sealed\n * @alpha\n */\nexport interface FluidContainer<TData = unknown>\n\textends DataStoreCreator,\n\t\tErasedBaseType<readonly [\"FluidContainer\", TData]> {\n\t/**\n\t * The unique identifier for this container within its service.\n\t * @remarks\n\t * `undefined` if the container has not yet been attached to a service.\n\t * This can be used to load another instance of this container from the service using {@link ServiceClient.loadContainer}.\n\t */\n\treadonly id?: string | undefined;\n\n\t/**\n\t * The root data store of the container.\n\t * @remarks\n\t * The type of the root data store is defined by the {@link DataStoreKind} used to create the container.\n\t */\n\treadonly data: TData;\n\n\t/**\n\t * Close the container, stopping all networking and cancelling runtime timers.\n\t *\n\t * @remarks\n\t * After calling `close()`, the container's data can still be read but no further operations can be sent.\n\t * @privateRemarks\n\t * TODO: we should document the what the expected behavior is if one tries to modify the data after close, or tries to call close multiple times.\n\t * TODO: we also likely want to have a way to detect if closed and events for on close.\n\t * TODO: ensure this truly closes all timers: it seems like we might still leak some related to the summarizer.\n\t * TODO: we should clarify how this interacts with unsaved content including inprogress summaries,\n\t * and likely also provide an async API with some options for how to handle that.\n\t */\n\tclose(): void;\n}\n\n/**\n * A Fluid container with an associated {@link ServiceClient} it can attach to.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerWithService<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * Attaches this container to the associated service client.\n\t *\n\t * The returned promise resolves once the container is attached: the container from the promise is the same one passed in as the argument.\n\t */\n\tattach(): Promise<FluidContainerAttached<TData>>;\n\n\t// This could expose access to the ServiceClient if needed.\n}\n\n/**\n * A Fluid container that has been attached to a service.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerAttached<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * {@inheritdoc FluidContainer.id}\n\t */\n\treadonly id: string;\n}\n\n/**\n * Defines a {@link https://en.wikipedia.org/wiki/Kind_(type_theory) | kind} of data store, allowing creating and loading instances of it.\n * @remarks\n * A `DataStoreKind` acts as the factory and type descriptor for a category of data store:\n * it defines the `type` used to identify the data store in a {@link DataStoreRegistry},\n * and the `T` API surface that instances of that data store expose.\n *\n * Provide a `DataStoreKind` to {@link ServiceClient.(createContainer:1)} or {@link DataStoreCreator.createDataStore}\n * to create new instances, and to {@link ServiceClient.loadContainer} to load existing ones.\n *\n * A `DataStoreKind` is not constructed directly.\n * Instead, obtain one from a framework-provided factory:\n * use {@link @fluidframework/shared-object-base#defineDataStore} to define a data store which wraps a root shared object,\n * or use a more specific wrapper around that,\n * such as {@link @fluidframework/tree#defineTreeDataStore} for a {@link @fluidframework/tree#TreeView}-backed data store.\n *\n * Since it implements {@link DataStoreKey}, a `DataStoreKind` can also be used directly as the key to look\n * itself up in a {@link Registry}.\n * @typeParam T - The API surface that instances of this data store kind expose.\n * @privateRemarks\n * TODO:\n * SharedObjects should be usable as these (though putting shared objects directly in the container might need special logic).\n * Type erased {@link IFluidDataStoreFactory}.\n * @sealed\n * @alpha\n */\nexport interface DataStoreKind<out T = unknown>\n\textends DataStoreKey<T>,\n\t\tErasedBaseType<readonly [\"DataStoreKind\", T]> {}\n\n/**\n * A registry of {@link DataStoreKind}s.\n * @privateRemarks\n * TODO: unify this with SharedObjectRegistry.\n *\n * @typeParam T - The type covering all {@link DataStoreKind}s in the registry.\n * @input\n * @alpha\n */\nexport type DataStoreRegistry<out T = unknown> = Registry<Promise<DataStoreKind<T>>>;\n\n/**\n * A connection to a Fluid storage service.\n * @sealed\n * @alpha\n */\nexport interface ServiceClient {\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKind} to use for the root.\n\t * @remarks\n\t * This overload is a shorthand for a simple case of {@link ServiceClient.(createContainer:2)}\n\t * where a single item registry is produced which contains only the root.\n\t * This is usable only when the root {@link DataStoreKind} is available eagerly (e.g. not lazy loaded),\n\t * and when the container does not need a registry for creating additional data stores beyond the root.\n\t * @privateRemarks\n\t * TODO: As this is a detached container, it should be able to be created synchronously.\n\t *\n\t * TODO: Provide more general alternative to this in the form of a service-independent `createContainer` free function.\n\t * It would work with a `ServiceClient.attachContainer<T>(detached: FluidContainer<T>): Promise<FluidContainerAttached<T>>`\n\t * which returns a promise that resolves once the detached container has been attached\n\t * (pointing to the same container object, but with the new type).\n\t *\n\t * Challenges:\n\t *\n\t * Currently the service must be provided at creation time because `IContainer.attach` does not accept a service client,\n\t * making it unclear whether a truly service-independent path is feasible in the near term.\n\t */\n\tcreateContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKey} used to look up the root's {@link DataStoreKind} from `registry`.\n\t * @param registry - The {@link DataStoreRegistry} supplying the {@link DataStoreKind} for the root and any other data stores the container may need to create.\n\t * @remarks\n\t * Use this overload when the root {@link DataStoreKind} is not available eagerly (e.g. for lazy loading),\n\t * or when the container needs a registry for creating additional data stores beyond the root.\n\t */\n\tcreateContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:1)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t * @privateRemarks\n\t * TODO: We should fix ergonomics issues that make this helpful,\n\t * then remove (or deprecate) this method in favor of `service.attach(createContainer(root))` as a better orthogonalized API.\n\t * See private remarks on {@link ServiceClient.(createContainer:1)}.\n\t */\n\tcreateAttachedContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:2)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t */\n\tcreateAttachedContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * Loads an existing container from the service.\n\t * @typeParam T - The type of the container's root data store.\n\t * @param id - The unique identifier of the container to load.\n\t * @param root - The {@link DataStoreKind} for the root, or a registry which will be used to look up the root based on its type.\n\t *\n\t * @throws a {@link @fluidframework/telemetry-utils#UsageError} if the DataStoreKind's type (either the root directly or looked up from the registry) does not match the type of the root data store in the container.\n\t *\n\t * @privateRemarks\n\t * The ability to provide a registry here means that it's possible to:\n\t * 1. Load a container which might have a few different possible roots, for example because of versioning.\n\t * 2. Generate the DataStoreKind on demand based on the type: this approach could be used for things like debug tools which can load any possible container.\n\t * 3. Generating the DataStoreKind if the type is unrecognized, for example to provide a placeholder which might support some minimal functionality (like debug inspection, and summary).\n\t *\n\t * The ability to provide just a single DataStoreKind<T> is purely a convenience to make it cleaner to use this in simple cases.\n\t */\n\tloadContainer<T>(\n\t\tid: string,\n\t\troot: DataStoreKind<T> | DataStoreRegistry<T>,\n\t): Promise<FluidContainerAttached<T>>;\n}\n\n// #endregion\n"]}
|
package/lib/serviceClient.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import type { ErasedBaseType } from "@fluidframework/core-interfaces/internal";
|
|
5
|
+
import type { ErasedBaseType, ITelemetryBaseLogger } from "@fluidframework/core-interfaces/internal";
|
|
6
6
|
/**
|
|
7
7
|
* This file defines the external facing API for the {@link ServiceClient} and related types.
|
|
8
8
|
*
|
|
@@ -142,6 +142,10 @@ export declare function featureVersion<major extends `${bigint}`, minor extends
|
|
|
142
142
|
* @alpha
|
|
143
143
|
*/
|
|
144
144
|
export interface ServiceOptions {
|
|
145
|
+
/**
|
|
146
|
+
* Optional logger that receives telemetry from containers created or loaded by this client.
|
|
147
|
+
*/
|
|
148
|
+
readonly logger?: ITelemetryBaseLogger;
|
|
145
149
|
/**
|
|
146
150
|
* Oldest Fluid Framework client version that must be able to open and process documents written
|
|
147
151
|
* by the service client.
|
|
@@ -150,9 +154,8 @@ export interface ServiceOptions {
|
|
|
150
154
|
* Choosing an older version may limit the features and write formats the application can use to
|
|
151
155
|
* those supported by that version.
|
|
152
156
|
*
|
|
153
|
-
* A service may provide a default when this option is omitted.
|
|
154
157
|
*/
|
|
155
|
-
readonly oldestSupportedClient
|
|
158
|
+
readonly oldestSupportedClient: OldestSupportedServiceClientVersion;
|
|
156
159
|
}
|
|
157
160
|
/**
|
|
158
161
|
* A {@link RegistryKey} for a {@link DataStoreKind}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceClient.d.ts","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"serviceClient.d.ts","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"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"}
|
package/lib/serviceClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serviceClient.js","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAsFH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC/B,QAAuB,EACvB,GAA2B;IAE3B,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAI,IAAY;IACrD,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;KACvB,CAAC;AACH,CAAC;AAgCD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC7B,OAAgF;IAEhF,6KAA6K;IAC7K,2JAA2J;IAC3J,6KAA6K;IAC7K,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAU,IAAI,MAAM,CAAC,CAAC,CAAU,IAAI,CAAC;AACxD,CAAC;AAoRD,aAAa","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ErasedBaseType } from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * This file defines the external facing API for the {@link ServiceClient} and related types.\n *\n * It provides an API surface at a similar abstraction level to aqueduct and fluid-static, but is intended to be a replacement for those which solves several problems with them.\n * Mainly it strives to have the encapsulation of implementation details (including all legacy APIs from aqueduct and lower level internals) like fluid-static\n * while being both more flexible and simpler.\n *\n * This aims to be the cleanest practical way to build applications on the Fluid Framework Client.\n * There are however several known cases where the API quality was sacrificed to ease initial implementation,\n * since some of the unification desired in this API's design are not yet implemented in the underlying Fluid Framework Client code or require additional work to implement.\n * These cases are called out with TODOs in this file.\n * These should be considered and addressed before stabilizing this API past alpha.\n *\n * All code interacting through this API surface within a single client must avoid using multiple copies of any Fluid Framework client package (at the same or different versions).\n * This mirrors the `@public` \"declarative model\" APIs and is a deliberate simplification of what is allowed in the legacy API surface.\n * It is enforced best-effort only: `@sealed` nominal erased types catch many mismatches at compile time, and factory identity checks throw a UsageError (\"Conflicting ... with same type\") at run time, but the checking is not exhaustive.\n * See `LayerCompatibilityUnified.md` for the full policy, rationale, and failure signatures.\n *\n * TODO:\n * Before stabilizing any of this past beta, evaluate whether this single-copy requirement must be relaxed, and if so how.\n * Whatever rule is chosen (relaxed or not) should be enforced at both compile time and run time as much as possible.\n *\n * TODO:\n * Fault isolation should be considered in this API design.\n * When are exceptions recoverable and how?\n * Likely we can fault isolate exceptions to containers in most cases,\n * and containers can indicate their status by being closed or disposed.\n * Non fatal errors should not be exceptions.\n */\n\n// #region Registry types\n\n/**\n * A collection of entries looked up by a `type` string.\n * @remarks\n * Use of a function for this allows a few things that most collections would not:\n * 1. It's possible to generate placeholder / error values on demand.\n * 2. It makes loading from some external registry on demand practical.\n * 3. The lookup can throw an exception if appropriate (this would typically indicate a bug and produce a fatal error).\n * 4. Generation of values can be lazy, and even asynchronous if `T` allows for a promise.\n *\n * This flexibility lets the implementer decide how to handle requests for unknown types.\n * They can produce placeholders, assert, fall back to a generic implementation etc.\n * @typeParam T - The type of entry produced for any given `type` string.\n * @input\n * @alpha\n */\nexport type Registry<T> = (type: string) => T;\n\n/**\n * A strongly typed key for a {@link Registry}.\n * Use with {@link lookupInRegistry}.\n * @remarks\n * Used to look up a `TIn` in a `Registry<TIn>`, and produce a `TOut` from it.\n * @typeParam TOut - The type produced by {@link RegistryKey.adapt} from a looked-up entry.\n * @typeParam TIn - The type of the entries in the {@link Registry} this key is used with.\n * @privateRemarks\n * This is currently input and sealed, meaning effectively type erased since the design might change.\n * @input\n * @sealed\n * @alpha\n */\nexport interface RegistryKey<TOut, TIn = unknown> {\n\t/**\n\t * Identifier to provide to the {@link Registry}.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * Convert a value from the registry to the desired output type.\n\t * @remarks\n\t * How this is done is up to the implementation.\n\t *\n\t * This might be a type guard which throws if the input is not valid.\n\t * Or it could be a conversion, an identity function, or something else.\n\t *\n\t * @param value - The value from the registry.\n\t * @returns The converted value.\n\t */\n\tadapt(value: TIn): TOut;\n}\n\n/**\n * Lookup an entry in a {@link Registry} using a {@link RegistryKey}.\n * @typeParam TOut - The type produced from the looked-up entry.\n * @typeParam TIn - The type of the entries in `registry`.\n * @alpha\n */\nexport function lookupInRegistry<TOut, TIn>(\n\tregistry: Registry<TIn>,\n\tkey: RegistryKey<TOut, TIn>,\n): TOut {\n\treturn key.adapt(registry(key.type));\n}\n\n/**\n * Creates a simple {@link RegistryKey} which does no type conversion.\n * @typeParam T - The type of the registry entry, which is returned unchanged by the key.\n * @alpha\n */\nexport function createBasicRegistryKey<T>(type: string): RegistryKey<T, T> {\n\treturn {\n\t\ttype,\n\t\tadapt: (value) => value,\n\t};\n}\n\n// #endregion\n\n// #region ServiceClient types\n\n/**\n * Oldest Fluid Framework client version that must be able to open and process documents written\n * by a service client.\n * @remarks\n * A string in SemVer format indicating a specific stable version of the Fluid Framework client package.\n *\n * Service clients use this value to select write formats and features. Clients using this version\n * or newer must be able to open and process documents written by the service client. Choosing an\n * older version may limit the features and write formats the application can use to those\n * supported by that version.\n *\n * Cannot exceed the version of any Fluid Framework client package in use by the local client.\n *\n * @privateRemarks\n * This is similar to, and a subset of, the `OldestSupportedClientVersion` type in `@fluidframework/runtime-definitions`.\n * This differs in that:\n * - This is `alpha` instead of `public`.\n * - This is available to drivers due to its location in `driver-definitions` instead of `runtime-definitions`.\n * - Patch versions cannot be set: a given minor release is not guaranteed to be greater or equal compat wise to all patches of the previous release, so we do not enable features based on patch versions (instead fall back to the next minor if needed).\n * Therefore allowing patch versions here could be misleading and could lead to bugs.\n *\n * @input\n * @alpha\n */\nexport type OldestSupportedServiceClientVersion = `${2 | 3}.${bigint}.0`;\n\n/**\n * Strips patch and prerelease from a SemVer string, returning only the major and minor version with a \".0\" patch.\n * @remarks\n * This formats a version in the same style used by {@link OldestSupportedServiceClientVersion}, specifying only the major and minor versions,\n * which are the portions used for feature selection.\n * @typeParam major - The major version number of `version` as a string, preserved in the result type.\n * @typeParam minor - The minor version number of `version` as a string, preserved in the result type.\n * @privateRemarks\n * This fills a similar role as cleanedPackageVersion in `@fluidframework/runtime-utils`.\n * It can be used to workaround our generated pkgVersion values being invalid\n * `OldestSupportedServiceClientVersion` on CI due to prerelease or patched release branches.\n * @alpha\n */\nexport function featureVersion<major extends `${bigint}`, minor extends `${bigint}`>(\n\tversion: `${major}.${minor}.${bigint}-${string}` | `${major}.${minor}.${bigint}`,\n): `${major}.${minor}.0` {\n\t// The SemVer package could be used to parse this version, but it wouldn't gain us anything, and would just make it harder to determine that the down casting below is valid.\n\t// Since we have a strongly typed string input, we know exactly which formats are allowed, so we don't need its more general parsing and validation either.\n\t// If we wanted to preserve the patch or prerelease version, that would require more complex parsing and would justify using the SemVer package, but we don't need that here.\n\tconst parsed = version.split(\".\");\n\treturn `${parsed[0] as major}.${parsed[1] as minor}.0`;\n}\n\n/**\n * Options for configuring a {@link ServiceClient}.\n * @remarks\n * These are the options which apply to all services.\n *\n * Individual services will extend with additional options.\n *\n * @input\n * @alpha\n */\nexport interface ServiceOptions {\n\t/**\n\t * Oldest Fluid Framework client version that must be able to open and process documents written\n\t * by the service client.\n\t *\n\t * @remarks\n\t * Choosing an older version may limit the features and write formats the application can use to\n\t * those supported by that version.\n\t *\n\t * A service may provide a default when this option is omitted.\n\t */\n\treadonly oldestSupportedClient?: OldestSupportedServiceClientVersion;\n}\n\n/**\n * A {@link RegistryKey} for a {@link DataStoreKind}.\n * @remarks\n * This is implemented by {@link DataStoreKind}, but alternative implementations can be used if needed.\n *\n * If you want lazy loading and need a key that does not eagerly load the {@link DataStoreKind}, an alternative {@link DataStoreKey} can be implemented.\n * @typeParam T - The type to expose from the {@link DataStoreKind} this key resolves to.\n * @typeParam TAll - The type covering all {@link DataStoreKind}s in the {@link Registry} this key is used with.\n * @privateRemarks\n * TODO: A built in common pattern for the lazy key case should be provided.\n * TODO: things probably break if \"adapt\" does anything except throw or return the result from the input promise.\n * @input\n * @alpha\n */\nexport type DataStoreKey<T, TAll = unknown> = RegistryKey<\n\tPromise<DataStoreKind<T>>,\n\tPromise<DataStoreKind<TAll>>\n>;\n\n/**\n * A context which has a registry and can create data stores using it.\n * @sealed\n * @alpha\n */\nexport interface DataStoreCreator {\n\t/**\n\t * Create a new detached data store `T` which can be attached to the {@link FluidContainer}.\n\t * by adding a handle to a data store or shared object which is already attached to the {@link FluidContainer}.\n\t * @remarks\n\t * `kind` will be looked up in the {@link Registry} used to create or load this {@link DataStoreCreator}.\n\t * It is up to that registry to decide how it handles unknown types, for example by throwing an exception or returning a placeholder.\n\t * @typeParam T - type implemented by the data store to expose in the result, as defined by `kind`.\n\t */\n\tcreateDataStore<T>(kind: DataStoreKey<T>): Promise<T>;\n}\n\n/**\n * A Fluid container.\n * @remarks\n * A document which can be stored to or loaded from a Fluid service using a {@link ServiceClient}.\n *\n * @typeParam TData - The type of the container's root data store, exposed via {@link FluidContainer.data}.\n * @privateRemarks\n * This will likely end up needing many of IFluidContainer's APIs, like disconnect, connectionState, events etc.\n * Before adding them though, care should be taken to consider if they can be improved or simplified.\n * For example maybe a single status enum for `detached -> attaching -> dirty -> saved -> closed` would be good.\n * Or maybe `detached -> attaching -> attached -> closed` and a timer for how long since the last unsaved change was created.\n *\n * The underlying IContainer has a lifecycle which includes both a closed and disposed state.\n * This should be avoidable: the closed but not disposed state exists so its possible to read out some state at that time.\n * We have made the close remove all the timers, so the the dispose step should be unnecessary and we can just have a single closed state.\n *\n * @sealed\n * @alpha\n */\nexport interface FluidContainer<TData = unknown>\n\textends DataStoreCreator,\n\t\tErasedBaseType<readonly [\"FluidContainer\", TData]> {\n\t/**\n\t * The unique identifier for this container within its service.\n\t * @remarks\n\t * `undefined` if the container has not yet been attached to a service.\n\t * This can be used to load another instance of this container from the service using {@link ServiceClient.loadContainer}.\n\t */\n\treadonly id?: string | undefined;\n\n\t/**\n\t * The root data store of the container.\n\t * @remarks\n\t * The type of the root data store is defined by the {@link DataStoreKind} used to create the container.\n\t */\n\treadonly data: TData;\n\n\t/**\n\t * Close the container, stopping all networking and cancelling runtime timers.\n\t *\n\t * @remarks\n\t * After calling `close()`, the container's data can still be read but no further operations can be sent.\n\t * @privateRemarks\n\t * TODO: we should document the what the expected behavior is if one tries to modify the data after close, or tries to call close multiple times.\n\t * TODO: we also likely want to have a way to detect if closed and events for on close.\n\t * TODO: ensure this truly closes all timers: it seems like we might still leak some related to the summarizer.\n\t * TODO: we should clarify how this interacts with unsaved content including inprogress summaries,\n\t * and likely also provide an async API with some options for how to handle that.\n\t */\n\tclose(): void;\n}\n\n/**\n * A Fluid container with an associated {@link ServiceClient} it can attach to.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerWithService<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * Attaches this container to the associated service client.\n\t *\n\t * The returned promise resolves once the container is attached: the container from the promise is the same one passed in as the argument.\n\t */\n\tattach(): Promise<FluidContainerAttached<TData>>;\n\n\t// This could expose access to the ServiceClient if needed.\n}\n\n/**\n * A Fluid container that has been attached to a service.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerAttached<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * {@inheritdoc FluidContainer.id}\n\t */\n\treadonly id: string;\n}\n\n/**\n * Defines a {@link https://en.wikipedia.org/wiki/Kind_(type_theory) | kind} of data store, allowing creating and loading instances of it.\n * @remarks\n * A `DataStoreKind` acts as the factory and type descriptor for a category of data store:\n * it defines the `type` used to identify the data store in a {@link DataStoreRegistry},\n * and the `T` API surface that instances of that data store expose.\n *\n * Provide a `DataStoreKind` to {@link ServiceClient.(createContainer:1)} or {@link DataStoreCreator.createDataStore}\n * to create new instances, and to {@link ServiceClient.loadContainer} to load existing ones.\n *\n * A `DataStoreKind` is not constructed directly.\n * Instead, obtain one from a framework-provided factory:\n * use {@link @fluidframework/shared-object-base#defineDataStore} to define a data store which wraps a root shared object,\n * or use a more specific wrapper around that,\n * such as {@link @fluidframework/tree#defineTreeDataStore} for a {@link @fluidframework/tree#TreeView}-backed data store.\n *\n * Since it implements {@link DataStoreKey}, a `DataStoreKind` can also be used directly as the key to look\n * itself up in a {@link Registry}.\n * @typeParam T - The API surface that instances of this data store kind expose.\n * @privateRemarks\n * TODO:\n * SharedObjects should be usable as these (though putting shared objects directly in the container might need special logic).\n * Type erased {@link IFluidDataStoreFactory}.\n * @sealed\n * @alpha\n */\nexport interface DataStoreKind<out T = unknown>\n\textends DataStoreKey<T>,\n\t\tErasedBaseType<readonly [\"DataStoreKind\", T]> {}\n\n/**\n * A registry of {@link DataStoreKind}s.\n * @privateRemarks\n * TODO: unify this with SharedObjectRegistry.\n *\n * @typeParam T - The type covering all {@link DataStoreKind}s in the registry.\n * @input\n * @alpha\n */\nexport type DataStoreRegistry<out T = unknown> = Registry<Promise<DataStoreKind<T>>>;\n\n/**\n * A connection to a Fluid storage service.\n * @sealed\n * @alpha\n */\nexport interface ServiceClient {\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKind} to use for the root.\n\t * @remarks\n\t * This overload is a shorthand for a simple case of {@link ServiceClient.(createContainer:2)}\n\t * where a single item registry is produced which contains only the root.\n\t * This is usable only when the root {@link DataStoreKind} is available eagerly (e.g. not lazy loaded),\n\t * and when the container does not need a registry for creating additional data stores beyond the root.\n\t * @privateRemarks\n\t * TODO: As this is a detached container, it should be able to be created synchronously.\n\t *\n\t * TODO: Provide more general alternative to this in the form of a service-independent `createContainer` free function.\n\t * It would work with a `ServiceClient.attachContainer<T>(detached: FluidContainer<T>): Promise<FluidContainerAttached<T>>`\n\t * which returns a promise that resolves once the detached container has been attached\n\t * (pointing to the same container object, but with the new type).\n\t *\n\t * Challenges:\n\t *\n\t * Currently the service must be provided at creation time because `IContainer.attach` does not accept a service client,\n\t * making it unclear whether a truly service-independent path is feasible in the near term.\n\t */\n\tcreateContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKey} used to look up the root's {@link DataStoreKind} from `registry`.\n\t * @param registry - The {@link DataStoreRegistry} supplying the {@link DataStoreKind} for the root and any other data stores the container may need to create.\n\t * @remarks\n\t * Use this overload when the root {@link DataStoreKind} is not available eagerly (e.g. for lazy loading),\n\t * or when the container needs a registry for creating additional data stores beyond the root.\n\t */\n\tcreateContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:1)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t * @privateRemarks\n\t * TODO: We should fix ergonomics issues that make this helpful,\n\t * then remove (or deprecate) this method in favor of `service.attach(createContainer(root))` as a better orthogonalized API.\n\t * See private remarks on {@link ServiceClient.(createContainer:1)}.\n\t */\n\tcreateAttachedContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:2)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t */\n\tcreateAttachedContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * Loads an existing container from the service.\n\t * @typeParam T - The type of the container's root data store.\n\t * @param id - The unique identifier of the container to load.\n\t * @param root - The {@link DataStoreKind} for the root, or a registry which will be used to look up the root based on its type.\n\t *\n\t * @throws a {@link @fluidframework/telemetry-utils#UsageError} if the DataStoreKind's type (either the root directly or looked up from the registry) does not match the type of the root data store in the container.\n\t *\n\t * @privateRemarks\n\t * The ability to provide a registry here means that it's possible to:\n\t * 1. Load a container which might have a few different possible roots, for example because of versioning.\n\t * 2. Generate the DataStoreKind on demand based on the type: this approach could be used for things like debug tools which can load any possible container.\n\t * 3. Generating the DataStoreKind if the type is unrecognized, for example to provide a placeholder which might support some minimal functionality (like debug inspection, and summary).\n\t *\n\t * The ability to provide just a single DataStoreKind<T> is purely a convenience to make it cleaner to use this in simple cases.\n\t */\n\tloadContainer<T>(\n\t\tid: string,\n\t\troot: DataStoreKind<T> | DataStoreRegistry<T>,\n\t): Promise<FluidContainerAttached<T>>;\n}\n\n// #endregion\n"]}
|
|
1
|
+
{"version":3,"file":"serviceClient.js","sourceRoot":"","sources":["../src/serviceClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyFH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC/B,QAAuB,EACvB,GAA2B;IAE3B,OAAO,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAI,IAAY;IACrD,OAAO;QACN,IAAI;QACJ,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK;KACvB,CAAC;AACH,CAAC;AAgCD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC7B,OAAgF;IAEhF,6KAA6K;IAC7K,2JAA2J;IAC3J,6KAA6K;IAC7K,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAU,IAAI,MAAM,CAAC,CAAC,CAAU,IAAI,CAAC;AACxD,CAAC;AAwRD,aAAa","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tErasedBaseType,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * This file defines the external facing API for the {@link ServiceClient} and related types.\n *\n * It provides an API surface at a similar abstraction level to aqueduct and fluid-static, but is intended to be a replacement for those which solves several problems with them.\n * Mainly it strives to have the encapsulation of implementation details (including all legacy APIs from aqueduct and lower level internals) like fluid-static\n * while being both more flexible and simpler.\n *\n * This aims to be the cleanest practical way to build applications on the Fluid Framework Client.\n * There are however several known cases where the API quality was sacrificed to ease initial implementation,\n * since some of the unification desired in this API's design are not yet implemented in the underlying Fluid Framework Client code or require additional work to implement.\n * These cases are called out with TODOs in this file.\n * These should be considered and addressed before stabilizing this API past alpha.\n *\n * All code interacting through this API surface within a single client must avoid using multiple copies of any Fluid Framework client package (at the same or different versions).\n * This mirrors the `@public` \"declarative model\" APIs and is a deliberate simplification of what is allowed in the legacy API surface.\n * It is enforced best-effort only: `@sealed` nominal erased types catch many mismatches at compile time, and factory identity checks throw a UsageError (\"Conflicting ... with same type\") at run time, but the checking is not exhaustive.\n * See `LayerCompatibilityUnified.md` for the full policy, rationale, and failure signatures.\n *\n * TODO:\n * Before stabilizing any of this past beta, evaluate whether this single-copy requirement must be relaxed, and if so how.\n * Whatever rule is chosen (relaxed or not) should be enforced at both compile time and run time as much as possible.\n *\n * TODO:\n * Fault isolation should be considered in this API design.\n * When are exceptions recoverable and how?\n * Likely we can fault isolate exceptions to containers in most cases,\n * and containers can indicate their status by being closed or disposed.\n * Non fatal errors should not be exceptions.\n */\n\n// #region Registry types\n\n/**\n * A collection of entries looked up by a `type` string.\n * @remarks\n * Use of a function for this allows a few things that most collections would not:\n * 1. It's possible to generate placeholder / error values on demand.\n * 2. It makes loading from some external registry on demand practical.\n * 3. The lookup can throw an exception if appropriate (this would typically indicate a bug and produce a fatal error).\n * 4. Generation of values can be lazy, and even asynchronous if `T` allows for a promise.\n *\n * This flexibility lets the implementer decide how to handle requests for unknown types.\n * They can produce placeholders, assert, fall back to a generic implementation etc.\n * @typeParam T - The type of entry produced for any given `type` string.\n * @input\n * @alpha\n */\nexport type Registry<T> = (type: string) => T;\n\n/**\n * A strongly typed key for a {@link Registry}.\n * Use with {@link lookupInRegistry}.\n * @remarks\n * Used to look up a `TIn` in a `Registry<TIn>`, and produce a `TOut` from it.\n * @typeParam TOut - The type produced by {@link RegistryKey.adapt} from a looked-up entry.\n * @typeParam TIn - The type of the entries in the {@link Registry} this key is used with.\n * @privateRemarks\n * This is currently input and sealed, meaning effectively type erased since the design might change.\n * @input\n * @sealed\n * @alpha\n */\nexport interface RegistryKey<TOut, TIn = unknown> {\n\t/**\n\t * Identifier to provide to the {@link Registry}.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * Convert a value from the registry to the desired output type.\n\t * @remarks\n\t * How this is done is up to the implementation.\n\t *\n\t * This might be a type guard which throws if the input is not valid.\n\t * Or it could be a conversion, an identity function, or something else.\n\t *\n\t * @param value - The value from the registry.\n\t * @returns The converted value.\n\t */\n\tadapt(value: TIn): TOut;\n}\n\n/**\n * Lookup an entry in a {@link Registry} using a {@link RegistryKey}.\n * @typeParam TOut - The type produced from the looked-up entry.\n * @typeParam TIn - The type of the entries in `registry`.\n * @alpha\n */\nexport function lookupInRegistry<TOut, TIn>(\n\tregistry: Registry<TIn>,\n\tkey: RegistryKey<TOut, TIn>,\n): TOut {\n\treturn key.adapt(registry(key.type));\n}\n\n/**\n * Creates a simple {@link RegistryKey} which does no type conversion.\n * @typeParam T - The type of the registry entry, which is returned unchanged by the key.\n * @alpha\n */\nexport function createBasicRegistryKey<T>(type: string): RegistryKey<T, T> {\n\treturn {\n\t\ttype,\n\t\tadapt: (value) => value,\n\t};\n}\n\n// #endregion\n\n// #region ServiceClient types\n\n/**\n * Oldest Fluid Framework client version that must be able to open and process documents written\n * by a service client.\n * @remarks\n * A string in SemVer format indicating a specific stable version of the Fluid Framework client package.\n *\n * Service clients use this value to select write formats and features. Clients using this version\n * or newer must be able to open and process documents written by the service client. Choosing an\n * older version may limit the features and write formats the application can use to those\n * supported by that version.\n *\n * Cannot exceed the version of any Fluid Framework client package in use by the local client.\n *\n * @privateRemarks\n * This is similar to, and a subset of, the `OldestSupportedClientVersion` type in `@fluidframework/runtime-definitions`.\n * This differs in that:\n * - This is `alpha` instead of `public`.\n * - This is available to drivers due to its location in `driver-definitions` instead of `runtime-definitions`.\n * - Patch versions cannot be set: a given minor release is not guaranteed to be greater or equal compat wise to all patches of the previous release, so we do not enable features based on patch versions (instead fall back to the next minor if needed).\n * Therefore allowing patch versions here could be misleading and could lead to bugs.\n *\n * @input\n * @alpha\n */\nexport type OldestSupportedServiceClientVersion = `${2 | 3}.${bigint}.0`;\n\n/**\n * Strips patch and prerelease from a SemVer string, returning only the major and minor version with a \".0\" patch.\n * @remarks\n * This formats a version in the same style used by {@link OldestSupportedServiceClientVersion}, specifying only the major and minor versions,\n * which are the portions used for feature selection.\n * @typeParam major - The major version number of `version` as a string, preserved in the result type.\n * @typeParam minor - The minor version number of `version` as a string, preserved in the result type.\n * @privateRemarks\n * This fills a similar role as cleanedPackageVersion in `@fluidframework/runtime-utils`.\n * It can be used to workaround our generated pkgVersion values being invalid\n * `OldestSupportedServiceClientVersion` on CI due to prerelease or patched release branches.\n * @alpha\n */\nexport function featureVersion<major extends `${bigint}`, minor extends `${bigint}`>(\n\tversion: `${major}.${minor}.${bigint}-${string}` | `${major}.${minor}.${bigint}`,\n): `${major}.${minor}.0` {\n\t// The SemVer package could be used to parse this version, but it wouldn't gain us anything, and would just make it harder to determine that the down casting below is valid.\n\t// Since we have a strongly typed string input, we know exactly which formats are allowed, so we don't need its more general parsing and validation either.\n\t// If we wanted to preserve the patch or prerelease version, that would require more complex parsing and would justify using the SemVer package, but we don't need that here.\n\tconst parsed = version.split(\".\");\n\treturn `${parsed[0] as major}.${parsed[1] as minor}.0`;\n}\n\n/**\n * Options for configuring a {@link ServiceClient}.\n * @remarks\n * These are the options which apply to all services.\n *\n * Individual services will extend with additional options.\n *\n * @input\n * @alpha\n */\nexport interface ServiceOptions {\n\t/**\n\t * Optional logger that receives telemetry from containers created or loaded by this client.\n\t */\n\treadonly logger?: ITelemetryBaseLogger;\n\n\t/**\n\t * Oldest Fluid Framework client version that must be able to open and process documents written\n\t * by the service client.\n\t *\n\t * @remarks\n\t * Choosing an older version may limit the features and write formats the application can use to\n\t * those supported by that version.\n\t *\n\t */\n\treadonly oldestSupportedClient: OldestSupportedServiceClientVersion;\n}\n\n/**\n * A {@link RegistryKey} for a {@link DataStoreKind}.\n * @remarks\n * This is implemented by {@link DataStoreKind}, but alternative implementations can be used if needed.\n *\n * If you want lazy loading and need a key that does not eagerly load the {@link DataStoreKind}, an alternative {@link DataStoreKey} can be implemented.\n * @typeParam T - The type to expose from the {@link DataStoreKind} this key resolves to.\n * @typeParam TAll - The type covering all {@link DataStoreKind}s in the {@link Registry} this key is used with.\n * @privateRemarks\n * TODO: A built in common pattern for the lazy key case should be provided.\n * TODO: things probably break if \"adapt\" does anything except throw or return the result from the input promise.\n * @input\n * @alpha\n */\nexport type DataStoreKey<T, TAll = unknown> = RegistryKey<\n\tPromise<DataStoreKind<T>>,\n\tPromise<DataStoreKind<TAll>>\n>;\n\n/**\n * A context which has a registry and can create data stores using it.\n * @sealed\n * @alpha\n */\nexport interface DataStoreCreator {\n\t/**\n\t * Create a new detached data store `T` which can be attached to the {@link FluidContainer}.\n\t * by adding a handle to a data store or shared object which is already attached to the {@link FluidContainer}.\n\t * @remarks\n\t * `kind` will be looked up in the {@link Registry} used to create or load this {@link DataStoreCreator}.\n\t * It is up to that registry to decide how it handles unknown types, for example by throwing an exception or returning a placeholder.\n\t * @typeParam T - type implemented by the data store to expose in the result, as defined by `kind`.\n\t */\n\tcreateDataStore<T>(kind: DataStoreKey<T>): Promise<T>;\n}\n\n/**\n * A Fluid container.\n * @remarks\n * A document which can be stored to or loaded from a Fluid service using a {@link ServiceClient}.\n *\n * @typeParam TData - The type of the container's root data store, exposed via {@link FluidContainer.data}.\n * @privateRemarks\n * This will likely end up needing many of IFluidContainer's APIs, like disconnect, connectionState, events etc.\n * Before adding them though, care should be taken to consider if they can be improved or simplified.\n * For example maybe a single status enum for `detached -> attaching -> dirty -> saved -> closed` would be good.\n * Or maybe `detached -> attaching -> attached -> closed` and a timer for how long since the last unsaved change was created.\n *\n * The underlying IContainer has a lifecycle which includes both a closed and disposed state.\n * This should be avoidable: the closed but not disposed state exists so its possible to read out some state at that time.\n * We have made the close remove all the timers, so the the dispose step should be unnecessary and we can just have a single closed state.\n *\n * @sealed\n * @alpha\n */\nexport interface FluidContainer<TData = unknown>\n\textends DataStoreCreator,\n\t\tErasedBaseType<readonly [\"FluidContainer\", TData]> {\n\t/**\n\t * The unique identifier for this container within its service.\n\t * @remarks\n\t * `undefined` if the container has not yet been attached to a service.\n\t * This can be used to load another instance of this container from the service using {@link ServiceClient.loadContainer}.\n\t */\n\treadonly id?: string | undefined;\n\n\t/**\n\t * The root data store of the container.\n\t * @remarks\n\t * The type of the root data store is defined by the {@link DataStoreKind} used to create the container.\n\t */\n\treadonly data: TData;\n\n\t/**\n\t * Close the container, stopping all networking and cancelling runtime timers.\n\t *\n\t * @remarks\n\t * After calling `close()`, the container's data can still be read but no further operations can be sent.\n\t * @privateRemarks\n\t * TODO: we should document the what the expected behavior is if one tries to modify the data after close, or tries to call close multiple times.\n\t * TODO: we also likely want to have a way to detect if closed and events for on close.\n\t * TODO: ensure this truly closes all timers: it seems like we might still leak some related to the summarizer.\n\t * TODO: we should clarify how this interacts with unsaved content including inprogress summaries,\n\t * and likely also provide an async API with some options for how to handle that.\n\t */\n\tclose(): void;\n}\n\n/**\n * A Fluid container with an associated {@link ServiceClient} it can attach to.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerWithService<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * Attaches this container to the associated service client.\n\t *\n\t * The returned promise resolves once the container is attached: the container from the promise is the same one passed in as the argument.\n\t */\n\tattach(): Promise<FluidContainerAttached<TData>>;\n\n\t// This could expose access to the ServiceClient if needed.\n}\n\n/**\n * A Fluid container that has been attached to a service.\n * @typeParam TData - The type of the container's root data store.\n * @sealed\n * @alpha\n */\nexport interface FluidContainerAttached<TData = unknown> extends FluidContainer<TData> {\n\t/**\n\t * {@inheritdoc FluidContainer.id}\n\t */\n\treadonly id: string;\n}\n\n/**\n * Defines a {@link https://en.wikipedia.org/wiki/Kind_(type_theory) | kind} of data store, allowing creating and loading instances of it.\n * @remarks\n * A `DataStoreKind` acts as the factory and type descriptor for a category of data store:\n * it defines the `type` used to identify the data store in a {@link DataStoreRegistry},\n * and the `T` API surface that instances of that data store expose.\n *\n * Provide a `DataStoreKind` to {@link ServiceClient.(createContainer:1)} or {@link DataStoreCreator.createDataStore}\n * to create new instances, and to {@link ServiceClient.loadContainer} to load existing ones.\n *\n * A `DataStoreKind` is not constructed directly.\n * Instead, obtain one from a framework-provided factory:\n * use {@link @fluidframework/shared-object-base#defineDataStore} to define a data store which wraps a root shared object,\n * or use a more specific wrapper around that,\n * such as {@link @fluidframework/tree#defineTreeDataStore} for a {@link @fluidframework/tree#TreeView}-backed data store.\n *\n * Since it implements {@link DataStoreKey}, a `DataStoreKind` can also be used directly as the key to look\n * itself up in a {@link Registry}.\n * @typeParam T - The API surface that instances of this data store kind expose.\n * @privateRemarks\n * TODO:\n * SharedObjects should be usable as these (though putting shared objects directly in the container might need special logic).\n * Type erased {@link IFluidDataStoreFactory}.\n * @sealed\n * @alpha\n */\nexport interface DataStoreKind<out T = unknown>\n\textends DataStoreKey<T>,\n\t\tErasedBaseType<readonly [\"DataStoreKind\", T]> {}\n\n/**\n * A registry of {@link DataStoreKind}s.\n * @privateRemarks\n * TODO: unify this with SharedObjectRegistry.\n *\n * @typeParam T - The type covering all {@link DataStoreKind}s in the registry.\n * @input\n * @alpha\n */\nexport type DataStoreRegistry<out T = unknown> = Registry<Promise<DataStoreKind<T>>>;\n\n/**\n * A connection to a Fluid storage service.\n * @sealed\n * @alpha\n */\nexport interface ServiceClient {\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKind} to use for the root.\n\t * @remarks\n\t * This overload is a shorthand for a simple case of {@link ServiceClient.(createContainer:2)}\n\t * where a single item registry is produced which contains only the root.\n\t * This is usable only when the root {@link DataStoreKind} is available eagerly (e.g. not lazy loaded),\n\t * and when the container does not need a registry for creating additional data stores beyond the root.\n\t * @privateRemarks\n\t * TODO: As this is a detached container, it should be able to be created synchronously.\n\t *\n\t * TODO: Provide more general alternative to this in the form of a service-independent `createContainer` free function.\n\t * It would work with a `ServiceClient.attachContainer<T>(detached: FluidContainer<T>): Promise<FluidContainerAttached<T>>`\n\t * which returns a promise that resolves once the detached container has been attached\n\t * (pointing to the same container object, but with the new type).\n\t *\n\t * Challenges:\n\t *\n\t * Currently the service must be provided at creation time because `IContainer.attach` does not accept a service client,\n\t * making it unclear whether a truly service-independent path is feasible in the near term.\n\t */\n\tcreateContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * Creates a detached container associated with this service client.\n\t * @typeParam T - The type of the container's root data store, as defined by `root`.\n\t * @param root - A {@link DataStoreKey} used to look up the root's {@link DataStoreKind} from `registry`.\n\t * @param registry - The {@link DataStoreRegistry} supplying the {@link DataStoreKind} for the root and any other data stores the container may need to create.\n\t * @remarks\n\t * Use this overload when the root {@link DataStoreKind} is not available eagerly (e.g. for lazy loading),\n\t * or when the container needs a registry for creating additional data stores beyond the root.\n\t */\n\tcreateContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerWithService<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:1)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t * @privateRemarks\n\t * TODO: We should fix ergonomics issues that make this helpful,\n\t * then remove (or deprecate) this method in favor of `service.attach(createContainer(root))` as a better orthogonalized API.\n\t * See private remarks on {@link ServiceClient.(createContainer:1)}.\n\t */\n\tcreateAttachedContainer<T>(root: DataStoreKind<T>): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * A shorthand for {@link ServiceClient.(createContainer:2)} followed by {@link FluidContainerWithService.attach}.\n\t * @remarks\n\t * Due to current implementation limitations making container creation async and service specific,\n\t * creating then attaching one is a bit verbose with two awaits that are messy to include inline.\n\t * This provides a convenient way to create and attach a container in a single step.\n\t */\n\tcreateAttachedContainer<T>(\n\t\troot: DataStoreKey<T>,\n\t\tregistry: DataStoreRegistry,\n\t): Promise<FluidContainerAttached<T>>;\n\n\t/**\n\t * Loads an existing container from the service.\n\t * @typeParam T - The type of the container's root data store.\n\t * @param id - The unique identifier of the container to load.\n\t * @param root - The {@link DataStoreKind} for the root, or a registry which will be used to look up the root based on its type.\n\t *\n\t * @throws a {@link @fluidframework/telemetry-utils#UsageError} if the DataStoreKind's type (either the root directly or looked up from the registry) does not match the type of the root data store in the container.\n\t *\n\t * @privateRemarks\n\t * The ability to provide a registry here means that it's possible to:\n\t * 1. Load a container which might have a few different possible roots, for example because of versioning.\n\t * 2. Generate the DataStoreKind on demand based on the type: this approach could be used for things like debug tools which can load any possible container.\n\t * 3. Generating the DataStoreKind if the type is unrecognized, for example to provide a placeholder which might support some minimal functionality (like debug inspection, and summary).\n\t *\n\t * The ability to provide just a single DataStoreKind<T> is purely a convenience to make it cleaner to use this in simple cases.\n\t */\n\tloadContainer<T>(\n\t\tid: string,\n\t\troot: DataStoreKind<T> | DataStoreRegistry<T>,\n\t): Promise<FluidContainerAttached<T>>;\n}\n\n// #endregion\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/driver-definitions",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Fluid driver definitions",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@fluidframework/core-interfaces": "~3.
|
|
36
|
+
"@fluidframework/core-interfaces": "~3.3.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@fluid-tools/build-cli": "^0.67.0",
|
|
42
42
|
"@fluidframework/build-common": "^2.0.3",
|
|
43
43
|
"@fluidframework/build-tools": "^0.67.0",
|
|
44
|
-
"@fluidframework/driver-definitions-previous": "npm:@fluidframework/driver-definitions@2.
|
|
44
|
+
"@fluidframework/driver-definitions-previous": "npm:@fluidframework/driver-definitions@3.2.0",
|
|
45
45
|
"@fluidframework/eslint-config-fluid": "^14.0.0",
|
|
46
46
|
"@microsoft/api-extractor": "7.58.1",
|
|
47
47
|
"concurrently": "^10.0.3",
|
package/src/serviceClient.ts
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ErasedBaseType,
|
|
8
|
+
ITelemetryBaseLogger,
|
|
9
|
+
} from "@fluidframework/core-interfaces/internal";
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* This file defines the external facing API for the {@link ServiceClient} and related types.
|
|
@@ -176,6 +179,11 @@ export function featureVersion<major extends `${bigint}`, minor extends `${bigin
|
|
|
176
179
|
* @alpha
|
|
177
180
|
*/
|
|
178
181
|
export interface ServiceOptions {
|
|
182
|
+
/**
|
|
183
|
+
* Optional logger that receives telemetry from containers created or loaded by this client.
|
|
184
|
+
*/
|
|
185
|
+
readonly logger?: ITelemetryBaseLogger;
|
|
186
|
+
|
|
179
187
|
/**
|
|
180
188
|
* Oldest Fluid Framework client version that must be able to open and process documents written
|
|
181
189
|
* by the service client.
|
|
@@ -184,9 +192,8 @@ export interface ServiceOptions {
|
|
|
184
192
|
* Choosing an older version may limit the features and write formats the application can use to
|
|
185
193
|
* those supported by that version.
|
|
186
194
|
*
|
|
187
|
-
* A service may provide a default when this option is omitted.
|
|
188
195
|
*/
|
|
189
|
-
readonly oldestSupportedClient
|
|
196
|
+
readonly oldestSupportedClient: OldestSupportedServiceClientVersion;
|
|
190
197
|
}
|
|
191
198
|
|
|
192
199
|
/**
|