@fluidframework/shared-object-base 2.117.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -2
- package/README.md +53 -50
- package/{api-extractor.json → api-extractor/api-extractor-model.json} +1 -1
- package/dist/dataStoreKind.js +2 -3
- package/dist/dataStoreKind.js.map +1 -1
- package/dist/gcHandleVisitor.js +1 -4
- package/dist/gcHandleVisitor.js.map +1 -1
- package/dist/handle.js +9 -7
- package/dist/handle.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/serializer.js +2 -0
- package/dist/serializer.js.map +1 -1
- package/dist/sharedObject.js +42 -15
- package/dist/sharedObject.js.map +1 -1
- package/dist/sharedObjectKernel.js +41 -52
- package/dist/sharedObjectKernel.js.map +1 -1
- package/dist/stubSharedObject.js +1 -2
- package/dist/stubSharedObject.js.map +1 -1
- package/dist/utils.js +5 -6
- package/dist/utils.js.map +1 -1
- package/lib/gcHandleVisitor.js +1 -4
- package/lib/gcHandleVisitor.js.map +1 -1
- package/lib/handle.js +7 -5
- package/lib/handle.js.map +1 -1
- package/lib/legacy.d.ts +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/lib/serializer.js +2 -0
- package/lib/serializer.js.map +1 -1
- package/lib/sharedObject.js +39 -12
- package/lib/sharedObject.js.map +1 -1
- package/lib/sharedObjectKernel.js +38 -49
- package/lib/sharedObjectKernel.js.map +1 -1
- package/package.json +36 -50
- package/src/packageVersion.ts +1 -1
- package/tsconfig.json +1 -1
- package/internal.d.ts +0 -11
- package/legacy.d.ts +0 -11
- /package/api-extractor/{api-extractor.current.json → api-extractor-report.current.json} +0 -0
- /package/api-extractor/{api-extractor.legacy.json → api-extractor-report.legacy.json} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
1
|
# @fluidframework/shared-object-base
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 3.0.0
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Removal of direct CommonJS support ([#28124](https://github.com/microsoft/FluidFramework/pull/28124)) [0f84e3b8878](https://github.com/microsoft/FluidFramework/commit/0f84e3b8878a5e75b2253976d98fd963bbd9db88)
|
|
8
|
+
|
|
9
|
+
Direct `require()` import is no longer directly supported.
|
|
10
|
+
Package is transpiled as ECMAScript Module.
|
|
11
|
+
|
|
12
|
+
See [Removal of direct CommonJS support in v3.0](https://github.com/microsoft/FluidFramework/issues/27444) for more information.
|
|
13
|
+
|
|
14
|
+
- Require modern TypeScript module resolution ([#27970](https://github.com/microsoft/FluidFramework/pull/27970)) [325e2016ca9](https://github.com/microsoft/FluidFramework/commit/325e2016ca9978d4a1f7552c97ba34feac9df41f)
|
|
15
|
+
|
|
16
|
+
Fluid Framework Client packages no longer include type declaration compatibility entrypoints for TypeScript's legacy Node10 resolution mode (`"moduleResolution": "node"` or `"node10"`).
|
|
17
|
+
Applications upgrading to Fluid Framework 3.0 must use one of the following supported configurations:
|
|
18
|
+
- `"module": "Node16"` with `"moduleResolution": "Node16"`
|
|
19
|
+
- `"module": "NodeNext"` with `"moduleResolution": "NodeNext"`
|
|
20
|
+
- `"module": "ESNext"` with `"moduleResolution": "Bundler"`
|
|
21
|
+
|
|
22
|
+
Existing public package entrypoints exposed through `package.json` exports, including `/alpha`, `/beta`, and `/legacy`, remain available under supported module resolution modes.
|
|
23
|
+
|
|
24
|
+
See [Removal of Node10 resolutions in v3.0](https://github.com/microsoft/FluidFramework/issues/27457) for more information.
|
|
25
|
+
|
|
26
|
+
- Client packages now target ES2022 ([#27846](https://github.com/microsoft/FluidFramework/pull/27846)) [91c78541bdd](https://github.com/microsoft/FluidFramework/commit/91c78541bddcbca5d6c5f357b023eeaee617d885)
|
|
27
|
+
|
|
28
|
+
The TypeScript compilation `target` and `lib` for the Fluid Framework client packages have been raised from ES2021/ES2020 to **ES2022**.
|
|
29
|
+
The published JavaScript now uses ES2022 language features (with correspondingly less down-leveling), so consuming these packages requires a runtime that supports ES2022.
|
|
30
|
+
All actively supported Node.js versions and evergreen browsers already meet this requirement.
|
|
31
|
+
|
|
32
|
+
Note that Fluid Framework has not officially supported targets older than ES2022 since before 2.0: this is documented in [ClientRequirements.md](https://github.com/microsoft/FluidFramework/blob/main/ClientRequirements.md) as well as the README for every client package.
|
|
33
|
+
|
|
34
|
+
It is possible this change could impact users of less up to date JavaScript runtimes.
|
|
35
|
+
Impacted users can use a tool like [babel](https://babeljs.io/) to transpile out unsupported language features.
|
|
36
|
+
|
|
37
|
+
- Build with TypeScript 6 ([#28052](https://github.com/microsoft/FluidFramework/pull/28052)) [7ab015c49de](https://github.com/microsoft/FluidFramework/commit/7ab015c49deec84833cdfe1fb5e1606b901f6e81)
|
|
38
|
+
|
|
39
|
+
FluidFramework Client SDK is now built using TypeScript 6. Consumers should build with TypeScript v6 or v7 or compatible tooling.
|
|
6
40
|
|
|
7
41
|
## 2.116.0
|
|
8
42
|
|
package/README.md
CHANGED
|
@@ -9,15 +9,15 @@ Interfaces and common base implementation for a shared objects for Fluid Framewo
|
|
|
9
9
|
|
|
10
10
|
## Using Fluid Framework libraries
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
library consumers should always prefer `^`.
|
|
12
|
+
For a dependency on a Fluid Framework library's public APIs, we recommend a `^` (caret) version range.
|
|
13
|
+
For example, use `^1.3.4`.
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
For a dependency on an unstable API, such as a `beta` API, we recommend a more restrictive version range.
|
|
16
|
+
For example, use a `~` version range.
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Run this command to install the package:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
npm i @fluidframework/shared-object-base
|
|
@@ -25,16 +25,16 @@ npm i @fluidframework/shared-object-base
|
|
|
25
25
|
|
|
26
26
|
## Importing from this package
|
|
27
27
|
|
|
28
|
-
This package
|
|
29
|
-
For
|
|
28
|
+
This package uses [package.json exports](https://nodejs.org/api/packages.html#exports) to separate APIs by support level.
|
|
29
|
+
For information about the support guarantees, read [API Support Levels](https://fluidframework.com/docs/build/releases-and-apitags/#api-support-levels).
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Import the `public` APIs from `@fluidframework/shared-object-base`.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Import the `legacy` APIs from `@fluidframework/shared-object-base/legacy`.
|
|
34
34
|
|
|
35
35
|
## API Documentation
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Read the **@fluidframework/shared-object-base** API documentation at <https://fluidframework.com/docs/apis/shared-object-base>.
|
|
38
38
|
|
|
39
39
|
<!-- prettier-ignore-end -->
|
|
40
40
|
|
|
@@ -47,62 +47,69 @@ API documentation for **@fluidframework/shared-object-base** is available at <ht
|
|
|
47
47
|
|
|
48
48
|
## Minimum Client Requirements
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
These requirements
|
|
52
|
-
|
|
50
|
+
Fluid Framework client libraries support the platforms in this document.
|
|
51
|
+
These requirements are intentionally restrictive.
|
|
52
|
+
Within a major version series, we can relax these requirements, but we cannot make them stricter.
|
|
53
|
+
For a Long Term Support (LTS) version, we might need to support these platforms for several years.
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
If
|
|
56
|
-
|
|
55
|
+
Other configurations can work, but Fluid Framework does not support them.
|
|
56
|
+
If an unsupported configuration stops working, we do not classify this as a bug.
|
|
57
|
+
To request support for a configuration that is not listed, file an issue.
|
|
58
|
+
The product team will evaluate your request.
|
|
59
|
+
In the issue, specify the current status of the configuration:
|
|
60
|
+
|
|
61
|
+
- The configuration works but needs official support.
|
|
62
|
+
- The configuration does not work and requires changes.
|
|
57
63
|
|
|
58
64
|
### Supported Runtimes
|
|
59
65
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
66
|
+
- Fluid Framework supports Node.js versions 22 and 24 while they receive [upstream support](https://nodejs.org/en/about/previous-releases).
|
|
67
|
+
- Fluid Framework will stop support for version 22 [when upstream support ends on 2027-04-30](https://github.com/nodejs/release#release-schedule).
|
|
68
|
+
- Fluid Framework does not support Node.js with the `--no-experimental-fetch` flag.
|
|
69
|
+
- Fluid Framework supports modern browsers that support the ES2022 standard library.
|
|
63
70
|
|
|
64
71
|
### Supported Tools
|
|
65
72
|
|
|
66
|
-
- TypeScript
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- [
|
|
70
|
-
-
|
|
71
|
-
|
|
73
|
+
- [TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0):
|
|
74
|
+
- Fluid Framework supports all [`strict`](https://www.typescriptlang.org/tsconfig) options.
|
|
75
|
+
- Set the build targets (`lib`, `target`) to `ES2022` or later.
|
|
76
|
+
- Enable [`strictNullChecks`](https://www.typescriptlang.org/tsconfig).
|
|
77
|
+
- Fluid Framework does not support [configuration options deprecated in TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0#breaking-changes-and-deprecations-in-typescript-6-0).
|
|
78
|
+
- Fluid Framework does not fully support `exactOptionalPropertyTypes`.
|
|
79
|
+
If you enable this option, do not use `in`, `Reflect.has`, `Object.hasOwn`, or `Object.prototype.hasOwnProperty` to narrow members of Fluid Framework types.
|
|
80
|
+
These methods can incorrectly exclude `undefined` from the possible values.
|
|
72
81
|
- [webpack](https://webpack.js.org/) 5
|
|
73
|
-
- We
|
|
74
|
-
Other bundlers
|
|
82
|
+
- We do not require a specific bundler.
|
|
83
|
+
Other bundlers that handle ES Modules can work, but we actively test only webpack.
|
|
75
84
|
|
|
76
85
|
### Module Resolution
|
|
77
86
|
|
|
78
|
-
[`Node16`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution)
|
|
79
|
-
|
|
87
|
+
In TypeScript `compilerOptions`, use [`Node16`, `Node20`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution) module resolution.
|
|
88
|
+
These settings follow the [Node.js v12+ ESM Resolution and Loading algorithm](https://nodejs.github.io/nodejs.dev/en/api/v20/esm/#resolution-and-loading-algorithm).
|
|
89
|
+
|
|
90
|
+
Do not use `Node10` module resolution.
|
|
80
91
|
|
|
81
92
|
### Module Formats
|
|
82
93
|
|
|
83
94
|
- ES Modules:
|
|
84
|
-
ES Modules
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
This is done to accommodate some workflows without good ES Module support.
|
|
88
|
-
If you have a workflow you would like included in this list, file an issue.
|
|
89
|
-
Once this list of workflows motivating CommonJS support is empty, we may drop support for CommonJS one year after notice of the change is posted here.
|
|
90
|
-
|
|
91
|
-
- Testing with Jest (which lacks [stable ESM support](https://jestjs.io/docs/ecmascript-modules) due to [unstable APIs in NodeJs](https://github.com/nodejs/node/issues/37648))
|
|
95
|
+
Use ES Modules to consume Fluid Framework client packages, including in Node.js.
|
|
96
|
+
- CommonJS:
|
|
97
|
+
Fluid Framework does not officially support CommonJS in version 3.0 or later.
|
|
92
98
|
|
|
93
99
|
## Contribution Guidelines
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
You can [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid Framework in these ways:
|
|
96
102
|
|
|
97
|
-
-
|
|
98
|
-
- [Submit
|
|
99
|
-
- Review
|
|
103
|
+
- Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
|
|
104
|
+
- [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
|
|
105
|
+
- Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
|
|
100
106
|
- [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
For detailed instructions, read the [repo documentation](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
|
|
103
109
|
|
|
104
|
-
This project
|
|
105
|
-
For more information
|
|
110
|
+
This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
|
111
|
+
For more information, read the [Code of Conduct frequently asked questions](https://opensource.microsoft.com/codeofconduct/faq/).
|
|
112
|
+
For questions or comments, contact [opencode@microsoft.com](mailto:opencode@microsoft.com).
|
|
106
113
|
|
|
107
114
|
This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
|
|
108
115
|
Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
|
|
@@ -110,13 +117,9 @@ Use of Microsoft trademarks or logos in modified versions of this project must n
|
|
|
110
117
|
|
|
111
118
|
## Help
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
Check out [fluidframework.com](https://fluidframework.com/docs/).
|
|
115
|
-
|
|
116
|
-
Still not finding what you're looking for?
|
|
117
|
-
Please [file an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
|
|
120
|
+
Read the [Fluid Framework documentation](https://fluidframework.com/docs/) for information about Fluid Framework concepts and APIs.
|
|
118
121
|
|
|
119
|
-
|
|
122
|
+
To request information that the documentation does not contain, [create an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
|
|
120
123
|
|
|
121
124
|
## Trademark
|
|
122
125
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
|
3
|
-
"extends": "
|
|
3
|
+
"extends": "<projectFolder>/../../../common/build/build-common/api-extractor-model.esm.json"
|
|
4
4
|
}
|
package/dist/dataStoreKind.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
7
|
+
exports.sharedObjectRegistryFromIterable = sharedObjectRegistryFromIterable;
|
|
8
|
+
exports.defineDataStore = defineDataStore;
|
|
8
9
|
const internal_1 = require("@fluidframework/datastore/internal");
|
|
9
10
|
const internal_2 = require("@fluidframework/driver-definitions/internal");
|
|
10
11
|
const internal_3 = require("@fluidframework/runtime-utils/internal");
|
|
@@ -33,7 +34,6 @@ function sharedObjectRegistryFromIterable(entries) {
|
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
|
-
exports.sharedObjectRegistryFromIterable = sharedObjectRegistryFromIterable;
|
|
37
37
|
/**
|
|
38
38
|
* Creates a {@link @fluidframework/driver-definitions#DataStoreKind} from {@link DataStoreOptions}.
|
|
39
39
|
* @alpha
|
|
@@ -46,7 +46,6 @@ function defineDataStore(options) {
|
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
exports.defineDataStore = defineDataStore;
|
|
50
49
|
/**
|
|
51
50
|
* Casts a {@link SharedObjectKindAlpha} to its encapsulated {@link ISharedObjectKind} view.
|
|
52
51
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataStoreKind.js","sourceRoot":"","sources":["../src/dataStoreKind.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidLoadable, FluidObject } from \"@fluidframework/core-interfaces\";\nimport {\n\ttype ISharedObjectRegistry,\n\tFluidDataStoreRuntime,\n} from \"@fluidframework/datastore/internal\";\nimport type { IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions/internal\";\nimport {\n\ttype Registry,\n\ttype DataStoreKind,\n\tlookupInRegistry,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreChannel,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport { DataStoreKindImplementation } from \"@fluidframework/runtime-utils/internal\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type {\n\tISharedObjectKind,\n\tSharedObjectKey,\n\tSharedObjectKindAlpha,\n} from \"./sharedObject.js\";\nimport type { ISharedObject } from \"./types.js\";\n\n/**\n * This file provides the implementation of {@link @fluidframework/driver-definitions#DataStoreKind}\n * and is therefore a key part of the implementation of the {@link @fluidframework/driver-definitions#ServiceClient} API surface.\n *\n * Note that much of the API surface beyond {@link defineDataStore} could be removed/deduplicated\n * if the unification noted in the TODOs in {@link SharedObjectRegistry} is implemented.\n */\n\n/**\n * A {@link @fluidframework/driver-definitions#Registry} of shared object kinds that can be created or loaded within a data store.\n * @remarks\n * Supports lazy code loading in a limited way (a single lazy load per registry).\n * @privateRemarks\n * TODO: The framework provided SharedObjects should be exposed in a way indistinguishable from custom sub-data stores.\n * This can be done by unifying the DataStoreKind and SharedObjectKindAlpha types.\n * For now, this would mean having DataStoreKind extend SharedObjectKindAlpha, since we can allow a data store in all places SharedObjects are allowed,\n * but do not allow SharedObjects at the root.\n * Fixing this, and allowing shared objects at the root (maybe use a trivial wrapper data store) could simplify things, allowing data stores and Containers to share some types (like how they create detached contents, have registries, have a root etc).\n *\n * Part of this unification could be to relax the output from the factories / registries. Allowing the output to be an arbitrary type, which might be a promise, and might not be one could help.\n * Removal of the IFluidLoadable requirement, and allowing the returned type to expose handles to itself however it wants (or not at all) might be viable and simplify typing and allow for strongly typed handles at creation time at least).\n * Maybe when Registry(type) gives a promise, it could instead give a factory which outputs a promise wrapped type? The check that the provided creation key is valid for that factory can be deferred until the promise resolves.\n *\n * Idea: creation key can have an interface that subsets the factory / SharedObjectKindAlpha / DataStoreKind so they can be used, or some branded key (string, and/or object with stronger identity what knows the type string) can be used.\n * Have Key interface contain validation function to check that the factory used (or maybe the value produced from it) is valid for that key.\n * During load, validation would simply check the factory's type string matches the key's type string.\n * When using SharedObjectKindAlpha or DataStoreKind, validation can check factory object identity against key.\n *\n * Goal: Mostly unify container, data store and shared object abstractions.\n * Maybe unify a bit with service client since it also has a way to create detached things with an initialized root then attach them.\n * SharedObjects are just built in leaf data stores.\n *\n * @input\n * @alpha\n */\nexport type SharedObjectRegistry = () => Promise<\n\tRegistry<SharedObjectKindAlpha<IFluidLoadable>>\n>;\n\n/**\n * Creates a {@link SharedObjectRegistry} from an iterable of {@link SharedObjectKindAlpha}s or async getters for them.\n * @alpha\n */\nexport function sharedObjectRegistryFromIterable(\n\tentries: Iterable<\n\t\t| SharedObjectKindAlpha<IFluidLoadable>\n\t\t| { type: string; kind: () => Promise<SharedObjectKindAlpha<IFluidLoadable>> }\n\t>,\n): SharedObjectRegistry {\n\treturn async () => {\n\t\tconst map = new Map<string, SharedObjectKindAlpha<IFluidLoadable>>();\n\t\tfor (const entry of entries) {\n\t\t\tif (\"kind\" in entry) {\n\t\t\t\tmap.set(entry.type, await entry.kind());\n\t\t\t} else {\n\t\t\t\tmap.set(asSharedObjectKind(entry).getFactory().type, entry);\n\t\t\t}\n\t\t}\n\t\treturn (type: string) => {\n\t\t\tconst entry = map.get(type);\n\t\t\tif (entry === undefined) {\n\t\t\t\tthrow new UsageError(`Unknown shared object type: ${type}`);\n\t\t\t}\n\t\t\treturn entry;\n\t\t};\n\t};\n}\n\n/**\n * Options which define how to construct a particular {@link @fluidframework/driver-definitions#DataStoreKind}.\n * @remarks\n * Use {@link defineDataStore} to create a {@link @fluidframework/driver-definitions#DataStoreKind} from these options.\n * @input\n * @alpha\n */\nexport interface DataStoreOptions<in out TRoot extends IFluidLoadable, out TOutput> {\n\t/**\n\t * The type identifier for the data object factory.\n\t * @remarks\n\t * Persisted identifier which specifies which {@link @fluidframework/driver-definitions#DataStoreKind} to use when loading it.\n\t * @privateRemarks\n\t * Equivalent to `DataObjectFactoryProps.type`.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * The registry of shared object kinds (including other data stores) that can be loaded or created within this data store.\n\t *\n\t * TODO: actually allow this to contain data stores.\n\t */\n\treadonly registry: SharedObjectRegistry;\n\n\t/**\n\t * Create the initial content of the data store, and return the root shared object.\n\t * @privateRemarks\n\t * TODO:\n\t * This requires the caller to produce a single root shared object (which is keyed by {@link rootSharedObjectId}).\n\t * This should be fine for new code, but code migrated from legacy APIs might need more flexibility.\n\t * Such use-cases could be accommodated providing a legacy alternative to `defineDataStore` where `instantiateFirstTime` and `view` directly expose access to named root shared objects.\n\t * This should be easy to implement, but is currently not included.\n\t */\n\tinstantiateFirstTime(\n\t\trootCreator: SharedObjectCreator<TRoot>,\n\t\tcontext: DataStoreContext,\n\t): Promise<TRoot>;\n\n\t/**\n\t * Construct a view of the data store's root shared object.\n\t *\n\t * @param root - The root shared object of the data store, created by `instantiateFirstTime` (though possibly created by another client and loaded by this one).\n\t * @param context - A {@link DataStoreContext} that can be used to create additional shared objects.\n\t */\n\tview(root: TRoot, context: DataStoreContext): Promise<TOutput>;\n}\n\n/**\n * Creates a {@link @fluidframework/driver-definitions#DataStoreKind} from {@link DataStoreOptions}.\n * @alpha\n */\nexport function defineDataStore<T, TRoot extends IFluidLoadable>(\n\toptions: DataStoreOptions<TRoot, T>,\n): DataStoreKind<T> {\n\treturn new DataStoreKindImplementation<T>({\n\t\ttype: options.type,\n\t\tasync instantiateDataStore(\n\t\t\tcontext: IFluidDataStoreContext,\n\t\t\texisting: boolean,\n\t\t): Promise<IFluidDataStoreChannel> {\n\t\t\treturn createDataStore(context, existing, options);\n\t\t},\n\t});\n}\n\n/**\n * Casts a {@link SharedObjectKindAlpha} to its encapsulated {@link ISharedObjectKind} view.\n *\n * @remarks\n * {@link SharedObjectKindAlpha} is a sealed type,\n * so we can assume it implements {@link ISharedObjectKind} and down cast to it.\n */\nfunction asSharedObjectKind<T extends IFluidLoadable>(\n\tkind: SharedObjectKindAlpha<T>,\n): ISharedObjectKind<T> {\n\tconst candidate = kind as unknown as Partial<ISharedObjectKind<T>>;\n\t// Sanity check to help catch misuse since SharedObjectKindAlpha is typed structurally and seems implementable.\n\tif (typeof candidate.getFactory !== \"function\" || typeof candidate.create !== \"function\") {\n\t\tthrow new UsageError(\n\t\t\t\"Invalid SharedObjectKindAlpha: this type is sealed and may not have custom implementations.\",\n\t\t);\n\t}\n\treturn candidate as ISharedObjectKind<T>;\n}\n\nfunction convertRegistry(\n\tlookup: Registry<SharedObjectKindAlpha<IFluidLoadable>>,\n): ISharedObjectRegistry {\n\treturn {\n\t\tget: (type: string) => {\n\t\t\tconst entry = lookup(type);\n\t\t\treturn asSharedObjectKind(entry).getFactory();\n\t\t},\n\t};\n}\n\n/**\n * Data stores keep their shared objects inside channels which get names.\n * This is the name of the channel which we conventionally use for the root shared object of a data store in most cases.\n * @remarks\n * There can be other named channels, or the root could use a different name, but we are trying to migrate away from such patterns.\n * Currently the DataStoreKind pattern used in this file follows and requires this convention,\n * but we may relax that in the future for interop with legacy data if necessary.\n */\nconst rootSharedObjectId = \"root\";\n\n/**\n * Creates a data store channel.\n * @param context - The data store context.\n * @param existing - Whether the data store already exists. When true, this loads it, when false a new one is created.\n * @param options - The data store options.\n * @returns A promise that resolves to the created data store channel.\n * @remarks\n * Currently this is limited to data stores which have a single named channel,\n * which must have the {@link rootSharedObjectId} and is attached at creation time.\n * This limitation may be relaxed in the future.\n */\nasync function createDataStore<T, TRoot extends IFluidLoadable>(\n\tcontext: IFluidDataStoreContext,\n\texisting: boolean,\n\toptions: DataStoreOptions<TRoot, T>,\n): Promise<IFluidDataStoreChannel> {\n\tconst sharedObjectRegistry = await options.registry();\n\tconst runtime: FluidDataStoreRuntime = new FluidDataStoreRuntime(\n\t\tcontext,\n\t\tconvertRegistry(sharedObjectRegistry),\n\t\texisting,\n\t\tasync (runtimeInner: IFluidDataStoreRuntime) => {\n\t\t\tconst innerContext: DataStoreContext = {\n\t\t\t\tasync createSharedObject<T2 extends IFluidLoadable>(\n\t\t\t\t\tkey: SharedObjectKey<T2>,\n\t\t\t\t): Promise<T2> {\n\t\t\t\t\tconst kind = lookupInRegistry(sharedObjectRegistry, key);\n\t\t\t\t\t// Create detached channel.\n\t\t\t\t\treturn asSharedObjectKind(kind).create(runtimeInner);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tlet createdRoot: TRoot | undefined;\n\n\t\t\tconst rootCreator: SharedObjectCreator<TRoot> = {\n\t\t\t\tasync createSharedObject<T2 extends TRoot>(key: SharedObjectKey<T2>): Promise<T2> {\n\t\t\t\t\t// Create named channel under the root id.\n\t\t\t\t\t// Error if called twice.\n\t\t\t\t\tif (createdRoot !== undefined) {\n\t\t\t\t\t\tthrow new UsageError(\"Root shared object already created\");\n\t\t\t\t\t}\n\t\t\t\t\tconst kind = lookupInRegistry(sharedObjectRegistry, key);\n\t\t\t\t\tconst result = asSharedObjectKind(kind).create(runtimeInner, rootSharedObjectId);\n\n\t\t\t\t\t// Every shared object is also an ISharedObject;\n\t\t\t\t\tconst rootSharedObject = result as IFluidLoadable as ISharedObject;\n\t\t\t\t\t// bind the newly created root so it becomes part of this data store.\n\t\t\t\t\trootSharedObject.bindToContext();\n\n\t\t\t\t\tcreatedRoot = result;\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tlet root: TRoot | undefined;\n\t\t\tif (existing) {\n\t\t\t\t// getChannel returns the type-erased IChannel; the registered root kind guarantees it is a TRoot.\n\t\t\t\troot = (await runtimeInner.getChannel(rootSharedObjectId)) as IFluidLoadable as TRoot;\n\t\t\t} else {\n\t\t\t\troot = await options.instantiateFirstTime(rootCreator, innerContext);\n\t\t\t\tif (root !== createdRoot) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"instantiateFirstTime did not return root created with rootCreator\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// view returns the data store's output type; the runtime only needs it as an opaque FluidObject entry point.\n\t\t\treturn (await options.view(root, innerContext)) as unknown as FluidObject;\n\t\t},\n\t);\n\n\treturn runtime;\n}\n\n/**\n * Creates instances of SharedObjectKinds.\n * @privateRemarks\n * See IFluidContainer.create.\n * @sealed\n * @alpha\n */\nexport interface SharedObjectCreator<TConstraint = IFluidLoadable> {\n\t/**\n\t * Create an instance of `kind`, which must be registered in the registry of the surrounding data store.\n\t */\n\tcreateSharedObject<T extends TConstraint>(kind: SharedObjectKey<T>): Promise<T>;\n}\n\n/**\n * Contextual information about a data store which is provided when instantiating or loading it.\n * @privateRemarks\n * TODO: this can expose more contextual information about the data store as needed.\n * @sealed\n * @alpha\n */\nexport interface DataStoreContext extends SharedObjectCreator {}\n"]}
|
|
1
|
+
{"version":3,"file":"dataStoreKind.js","sourceRoot":"","sources":["../src/dataStoreKind.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidLoadable, FluidObject } from \"@fluidframework/core-interfaces\";\nimport {\n\ttype ISharedObjectRegistry,\n\tFluidDataStoreRuntime,\n} from \"@fluidframework/datastore/internal\";\nimport type { IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions/internal\";\nimport {\n\ttype Registry,\n\ttype DataStoreKind,\n\tlookupInRegistry,\n} from \"@fluidframework/driver-definitions/internal\";\nimport type {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreChannel,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport { DataStoreKindImplementation } from \"@fluidframework/runtime-utils/internal\";\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type {\n\tISharedObjectKind,\n\tSharedObjectKey,\n\tSharedObjectKindAlpha,\n} from \"./sharedObject.js\";\nimport type { ISharedObject } from \"./types.js\";\n\n/**\n * This file provides the implementation of {@link @fluidframework/driver-definitions#DataStoreKind}\n * and is therefore a key part of the implementation of the {@link @fluidframework/driver-definitions#ServiceClient} API surface.\n *\n * Note that much of the API surface beyond {@link defineDataStore} could be removed/deduplicated\n * if the unification noted in the TODOs in {@link SharedObjectRegistry} is implemented.\n */\n\n/**\n * A {@link @fluidframework/driver-definitions#Registry} of shared object kinds that can be created or loaded within a data store.\n * @remarks\n * Supports lazy code loading in a limited way (a single lazy load per registry).\n * @privateRemarks\n * TODO: The framework provided SharedObjects should be exposed in a way indistinguishable from custom sub-data stores.\n * This can be done by unifying the DataStoreKind and SharedObjectKindAlpha types.\n * For now, this would mean having DataStoreKind extend SharedObjectKindAlpha, since we can allow a data store in all places SharedObjects are allowed,\n * but do not allow SharedObjects at the root.\n * Fixing this, and allowing shared objects at the root (maybe use a trivial wrapper data store) could simplify things, allowing data stores and Containers to share some types (like how they create detached contents, have registries, have a root etc).\n *\n * Part of this unification could be to relax the output from the factories / registries. Allowing the output to be an arbitrary type, which might be a promise, and might not be one could help.\n * Removal of the IFluidLoadable requirement, and allowing the returned type to expose handles to itself however it wants (or not at all) might be viable and simplify typing and allow for strongly typed handles at creation time at least).\n * Maybe when Registry(type) gives a promise, it could instead give a factory which outputs a promise wrapped type? The check that the provided creation key is valid for that factory can be deferred until the promise resolves.\n *\n * Idea: creation key can have an interface that subsets the factory / SharedObjectKindAlpha / DataStoreKind so they can be used, or some branded key (string, and/or object with stronger identity what knows the type string) can be used.\n * Have Key interface contain validation function to check that the factory used (or maybe the value produced from it) is valid for that key.\n * During load, validation would simply check the factory's type string matches the key's type string.\n * When using SharedObjectKindAlpha or DataStoreKind, validation can check factory object identity against key.\n *\n * Goal: Mostly unify container, data store and shared object abstractions.\n * Maybe unify a bit with service client since it also has a way to create detached things with an initialized root then attach them.\n * SharedObjects are just built in leaf data stores.\n *\n * @input\n * @alpha\n */\nexport type SharedObjectRegistry = () => Promise<\n\tRegistry<SharedObjectKindAlpha<IFluidLoadable>>\n>;\n\n/**\n * Creates a {@link SharedObjectRegistry} from an iterable of {@link SharedObjectKindAlpha}s or async getters for them.\n * @alpha\n */\nexport function sharedObjectRegistryFromIterable(\n\tentries: Iterable<\n\t\t| SharedObjectKindAlpha<IFluidLoadable>\n\t\t| { type: string; kind: () => Promise<SharedObjectKindAlpha<IFluidLoadable>> }\n\t>,\n): SharedObjectRegistry {\n\treturn async () => {\n\t\tconst map = new Map<string, SharedObjectKindAlpha<IFluidLoadable>>();\n\t\tfor (const entry of entries) {\n\t\t\tif (\"kind\" in entry) {\n\t\t\t\tmap.set(entry.type, await entry.kind());\n\t\t\t} else {\n\t\t\t\tmap.set(asSharedObjectKind(entry).getFactory().type, entry);\n\t\t\t}\n\t\t}\n\t\treturn (type: string) => {\n\t\t\tconst entry = map.get(type);\n\t\t\tif (entry === undefined) {\n\t\t\t\tthrow new UsageError(`Unknown shared object type: ${type}`);\n\t\t\t}\n\t\t\treturn entry;\n\t\t};\n\t};\n}\n\n/**\n * Options which define how to construct a particular {@link @fluidframework/driver-definitions#DataStoreKind}.\n * @remarks\n * Use {@link defineDataStore} to create a {@link @fluidframework/driver-definitions#DataStoreKind} from these options.\n * @input\n * @alpha\n */\nexport interface DataStoreOptions<in out TRoot extends IFluidLoadable, out TOutput> {\n\t/**\n\t * The type identifier for the data object factory.\n\t * @remarks\n\t * Persisted identifier which specifies which {@link @fluidframework/driver-definitions#DataStoreKind} to use when loading it.\n\t * @privateRemarks\n\t * Equivalent to `DataObjectFactoryProps.type`.\n\t */\n\treadonly type: string;\n\n\t/**\n\t * The registry of shared object kinds (including other data stores) that can be loaded or created within this data store.\n\t *\n\t * TODO: actually allow this to contain data stores.\n\t */\n\treadonly registry: SharedObjectRegistry;\n\n\t/**\n\t * Create the initial content of the data store, and return the root shared object.\n\t * @privateRemarks\n\t * TODO:\n\t * This requires the caller to produce a single root shared object (which is keyed by {@link rootSharedObjectId}).\n\t * This should be fine for new code, but code migrated from legacy APIs might need more flexibility.\n\t * Such use-cases could be accommodated providing a legacy alternative to `defineDataStore` where `instantiateFirstTime` and `view` directly expose access to named root shared objects.\n\t * This should be easy to implement, but is currently not included.\n\t */\n\tinstantiateFirstTime(\n\t\trootCreator: SharedObjectCreator<TRoot>,\n\t\tcontext: DataStoreContext,\n\t): Promise<TRoot>;\n\n\t/**\n\t * Construct a view of the data store's root shared object.\n\t *\n\t * @param root - The root shared object of the data store, created by `instantiateFirstTime` (though possibly created by another client and loaded by this one).\n\t * @param context - A {@link DataStoreContext} that can be used to create additional shared objects.\n\t */\n\tview(root: TRoot, context: DataStoreContext): Promise<TOutput>;\n}\n\n/**\n * Creates a {@link @fluidframework/driver-definitions#DataStoreKind} from {@link DataStoreOptions}.\n * @alpha\n */\nexport function defineDataStore<T, TRoot extends IFluidLoadable>(\n\toptions: DataStoreOptions<TRoot, T>,\n): DataStoreKind<T> {\n\treturn new DataStoreKindImplementation<T>({\n\t\ttype: options.type,\n\t\tasync instantiateDataStore(\n\t\t\tcontext: IFluidDataStoreContext,\n\t\t\texisting: boolean,\n\t\t): Promise<IFluidDataStoreChannel> {\n\t\t\treturn createDataStore(context, existing, options);\n\t\t},\n\t});\n}\n\n/**\n * Casts a {@link SharedObjectKindAlpha} to its encapsulated {@link ISharedObjectKind} view.\n *\n * @remarks\n * {@link SharedObjectKindAlpha} is a sealed type,\n * so we can assume it implements {@link ISharedObjectKind} and down cast to it.\n */\nfunction asSharedObjectKind<T extends IFluidLoadable>(\n\tkind: SharedObjectKindAlpha<T>,\n): ISharedObjectKind<T> {\n\tconst candidate = kind as unknown as Partial<ISharedObjectKind<T>>;\n\t// Sanity check to help catch misuse since SharedObjectKindAlpha is typed structurally and seems implementable.\n\tif (typeof candidate.getFactory !== \"function\" || typeof candidate.create !== \"function\") {\n\t\tthrow new UsageError(\n\t\t\t\"Invalid SharedObjectKindAlpha: this type is sealed and may not have custom implementations.\",\n\t\t);\n\t}\n\treturn candidate as ISharedObjectKind<T>;\n}\n\nfunction convertRegistry(\n\tlookup: Registry<SharedObjectKindAlpha<IFluidLoadable>>,\n): ISharedObjectRegistry {\n\treturn {\n\t\tget: (type: string) => {\n\t\t\tconst entry = lookup(type);\n\t\t\treturn asSharedObjectKind(entry).getFactory();\n\t\t},\n\t};\n}\n\n/**\n * Data stores keep their shared objects inside channels which get names.\n * This is the name of the channel which we conventionally use for the root shared object of a data store in most cases.\n * @remarks\n * There can be other named channels, or the root could use a different name, but we are trying to migrate away from such patterns.\n * Currently the DataStoreKind pattern used in this file follows and requires this convention,\n * but we may relax that in the future for interop with legacy data if necessary.\n */\nconst rootSharedObjectId = \"root\";\n\n/**\n * Creates a data store channel.\n * @param context - The data store context.\n * @param existing - Whether the data store already exists. When true, this loads it, when false a new one is created.\n * @param options - The data store options.\n * @returns A promise that resolves to the created data store channel.\n * @remarks\n * Currently this is limited to data stores which have a single named channel,\n * which must have the {@link rootSharedObjectId} and is attached at creation time.\n * This limitation may be relaxed in the future.\n */\nasync function createDataStore<T, TRoot extends IFluidLoadable>(\n\tcontext: IFluidDataStoreContext,\n\texisting: boolean,\n\toptions: DataStoreOptions<TRoot, T>,\n): Promise<IFluidDataStoreChannel> {\n\tconst sharedObjectRegistry = await options.registry();\n\tconst runtime: FluidDataStoreRuntime = new FluidDataStoreRuntime(\n\t\tcontext,\n\t\tconvertRegistry(sharedObjectRegistry),\n\t\texisting,\n\t\tasync (runtimeInner: IFluidDataStoreRuntime) => {\n\t\t\tconst innerContext: DataStoreContext = {\n\t\t\t\tasync createSharedObject<T2 extends IFluidLoadable>(\n\t\t\t\t\tkey: SharedObjectKey<T2>,\n\t\t\t\t): Promise<T2> {\n\t\t\t\t\tconst kind = lookupInRegistry(sharedObjectRegistry, key);\n\t\t\t\t\t// Create detached channel.\n\t\t\t\t\treturn asSharedObjectKind(kind).create(runtimeInner);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tlet createdRoot: TRoot | undefined;\n\n\t\t\tconst rootCreator: SharedObjectCreator<TRoot> = {\n\t\t\t\tasync createSharedObject<T2 extends TRoot>(key: SharedObjectKey<T2>): Promise<T2> {\n\t\t\t\t\t// Create named channel under the root id.\n\t\t\t\t\t// Error if called twice.\n\t\t\t\t\tif (createdRoot !== undefined) {\n\t\t\t\t\t\tthrow new UsageError(\"Root shared object already created\");\n\t\t\t\t\t}\n\t\t\t\t\tconst kind = lookupInRegistry(sharedObjectRegistry, key);\n\t\t\t\t\tconst result = asSharedObjectKind(kind).create(runtimeInner, rootSharedObjectId);\n\n\t\t\t\t\t// Every shared object is also an ISharedObject;\n\t\t\t\t\tconst rootSharedObject = result as IFluidLoadable as ISharedObject;\n\t\t\t\t\t// bind the newly created root so it becomes part of this data store.\n\t\t\t\t\trootSharedObject.bindToContext();\n\n\t\t\t\t\tcreatedRoot = result;\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tlet root: TRoot | undefined;\n\t\t\tif (existing) {\n\t\t\t\t// getChannel returns the type-erased IChannel; the registered root kind guarantees it is a TRoot.\n\t\t\t\troot = (await runtimeInner.getChannel(rootSharedObjectId)) as IFluidLoadable as TRoot;\n\t\t\t} else {\n\t\t\t\troot = await options.instantiateFirstTime(rootCreator, innerContext);\n\t\t\t\tif (root !== createdRoot) {\n\t\t\t\t\tthrow new UsageError(\n\t\t\t\t\t\t\"instantiateFirstTime did not return root created with rootCreator\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// view returns the data store's output type; the runtime only needs it as an opaque FluidObject entry point.\n\t\t\treturn (await options.view(root, innerContext)) as unknown as FluidObject;\n\t\t},\n\t);\n\n\treturn runtime;\n}\n\n/**\n * Creates instances of SharedObjectKinds.\n * @privateRemarks\n * See IFluidContainer.create.\n * @sealed\n * @alpha\n */\nexport interface SharedObjectCreator<TConstraint = IFluidLoadable> {\n\t/**\n\t * Create an instance of `kind`, which must be registered in the registry of the surrounding data store.\n\t */\n\tcreateSharedObject<T extends TConstraint>(kind: SharedObjectKey<T>): Promise<T>;\n}\n\n/**\n * Contextual information about a data store which is provided when instantiating or loading it.\n * @privateRemarks\n * TODO: this can expose more contextual information about the data store as needed.\n * @sealed\n * @alpha\n */\nexport interface DataStoreContext extends SharedObjectCreator {}\n"]}
|
package/dist/gcHandleVisitor.js
CHANGED
|
@@ -13,10 +13,7 @@ const serializer_js_1 = require("./serializer.js");
|
|
|
13
13
|
* All that is needed is getSerializedRoutes() to get the routes. This strategy could be optimized if needed.
|
|
14
14
|
*/
|
|
15
15
|
class GCHandleVisitor extends serializer_js_1.FluidSerializer {
|
|
16
|
-
|
|
17
|
-
super(...arguments);
|
|
18
|
-
this.visitedHandlePaths = new Set();
|
|
19
|
-
}
|
|
16
|
+
visitedHandlePaths = new Set();
|
|
20
17
|
getVisitedHandlePaths() {
|
|
21
18
|
return [...this.visitedHandlePaths];
|
|
22
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcHandleVisitor.js","sourceRoot":"","sources":["../src/gcHandleVisitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAKH,mDAAkD;AAElD;;;;;GAKG;AACH,MAAa,eAAgB,SAAQ,+BAAe;
|
|
1
|
+
{"version":3,"file":"gcHandleVisitor.js","sourceRoot":"","sources":["../src/gcHandleVisitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAKH,mDAAkD;AAElD;;;;;GAKG;AACH,MAAa,eAAgB,SAAQ,+BAAe;IAClC,kBAAkB,GAAgB,IAAI,GAAG,EAAE,CAAC;IACtD,qBAAqB;QAC3B,OAAO,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrC,CAAC;IAES,mBAAmB,CAAC,MAA4B;QACzD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjD,mEAAmE;QACnE,iGAAiG;QACjG,OAAO;YACN,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,8BAA8B;SACnC,CAAC;IACH,CAAC;CACD;AAhBD,0CAgBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport type { ISerializedHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport { FluidSerializer } from \"./serializer.js\";\n\n/**\n * Implementation of IFluidSerializer used by GC to visit all the handles in the DDS to collect its outbound routes\n *\n * @remarks This is given to DDS code that typically produces a serialization of the data, which is then ignored.\n * All that is needed is getSerializedRoutes() to get the routes. This strategy could be optimized if needed.\n */\nexport class GCHandleVisitor extends FluidSerializer {\n\tprivate readonly visitedHandlePaths: Set<string> = new Set();\n\tpublic getVisitedHandlePaths(): string[] {\n\t\treturn [...this.visitedHandlePaths];\n\t}\n\n\tprotected bindAndEncodeHandle(handle: IFluidHandleInternal): ISerializedHandle {\n\t\tthis.visitedHandlePaths.add(handle.absolutePath);\n\n\t\t// Just return a dummy value. The serialization itself is not used.\n\t\t// It's especially important we don't bind since that has side effects that are irrelevant to GC.\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: \"UNUSED (see GCHandleVisitor)\",\n\t\t};\n\t}\n}\n"]}
|
package/dist/handle.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.SharedObjectHandle =
|
|
7
|
+
exports.SharedObjectHandle = void 0;
|
|
8
|
+
exports.isISharedObjectHandle = isISharedObjectHandle;
|
|
8
9
|
const internal_1 = require("@fluidframework/datastore/internal");
|
|
9
10
|
const internal_2 = require("@fluidframework/runtime-utils/internal");
|
|
10
11
|
/**
|
|
@@ -14,7 +15,6 @@ const internal_2 = require("@fluidframework/runtime-utils/internal");
|
|
|
14
15
|
function isISharedObjectHandle(handle) {
|
|
15
16
|
return (0, internal_2.isFluidHandle)(handle) && typeof handle.bind === "function";
|
|
16
17
|
}
|
|
17
|
-
exports.isISharedObjectHandle = isISharedObjectHandle;
|
|
18
18
|
/**
|
|
19
19
|
* Handle for a shared object (DDS).
|
|
20
20
|
*
|
|
@@ -26,6 +26,8 @@ exports.isISharedObjectHandle = isISharedObjectHandle;
|
|
|
26
26
|
* ensuring the target object becomes attached along with this DDS.
|
|
27
27
|
*/
|
|
28
28
|
class SharedObjectHandle extends internal_1.FluidObjectHandle {
|
|
29
|
+
value;
|
|
30
|
+
runtime;
|
|
29
31
|
/**
|
|
30
32
|
* Whether services have been attached for the associated shared object.
|
|
31
33
|
*/
|
|
@@ -50,6 +52,11 @@ class SharedObjectHandle extends internal_1.FluidObjectHandle {
|
|
|
50
52
|
*/
|
|
51
53
|
return this.isAttached || this.isLocallyVisible;
|
|
52
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Tracks whether this handle is locally visible in the container.
|
|
57
|
+
*/
|
|
58
|
+
isLocallyVisible = false;
|
|
59
|
+
pendingHandles = new Set();
|
|
53
60
|
/**
|
|
54
61
|
* Creates a new SharedObjectHandle.
|
|
55
62
|
* @param value - The shared object this handle is for.
|
|
@@ -61,11 +68,6 @@ class SharedObjectHandle extends internal_1.FluidObjectHandle {
|
|
|
61
68
|
super(value, path, runtime.IFluidHandleContext);
|
|
62
69
|
this.value = value;
|
|
63
70
|
this.runtime = runtime;
|
|
64
|
-
/**
|
|
65
|
-
* Tracks whether this handle is locally visible in the container.
|
|
66
|
-
*/
|
|
67
|
-
this.isLocallyVisible = false;
|
|
68
|
-
this.pendingHandles = new Set();
|
|
69
71
|
}
|
|
70
72
|
/**
|
|
71
73
|
* Attaches all bound handles first (which may in turn attach further handles), then attaches this handle.
|
package/dist/handle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle.js","sourceRoot":"","sources":["../src/handle.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;
|
|
1
|
+
{"version":3,"file":"handle.js","sourceRoot":"","sources":["../src/handle.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA6BH,sDAEC;AA5BD,iEAAuE;AAEvE,qEAAuE;AAoBvE;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,MAAe;IACpD,OAAO,IAAA,wBAAa,EAAC,MAAM,CAAC,IAAI,OAAQ,MAA8B,CAAC,IAAI,KAAK,UAAU,CAAC;AAC5F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAa,kBACZ,SAAQ,4BAAgC;IA4CpB;IAEF;IA3ClB;;OAEG;IACH,IAAW,UAAU;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,IAAY,SAAS;QACpB;;;;;;;;;;;WAWG;QACH,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,gBAAgB,CAAC;IACjD,CAAC;IAED;;OAEG;IACK,gBAAgB,GAAY,KAAK,CAAC;IAEzB,cAAc,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEvE;;;;;;OAMG;IACH,YACoB,KAAoB,EACvC,IAAY,EACK,OAA+B;QAEhD,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAJ7B,UAAK,GAAL,KAAK,CAAe;QAEtB,YAAO,GAAP,OAAO,CAAwB;IAGjD,CAAC;IAED;;;OAGG;IACI,WAAW;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,OAAO;QACR,CAAC;QAED,yCAAyC;QACzC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1C,MAAM,CAAC,WAAW,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAE5B,yFAAyF;QACzF,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAE3B,8EAA8E;QAC9E,KAAK,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAEM,IAAI,CAAC,MAA4B;QACvC,mFAAmF;QACnF,8GAA8G;QAC9G,wEAAwE;QACxE,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACzC,OAAO;QACR,CAAC;QAED,8EAA8E;QAC9E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO;QACR,CAAC;QAED,mGAAmG;QACnG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACD;AA5FD,gDA4FC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandleInternal } from \"@fluidframework/core-interfaces/internal\";\nimport { FluidObjectHandle } from \"@fluidframework/datastore/internal\";\nimport type { IFluidDataStoreRuntime } from \"@fluidframework/datastore-definitions/internal\";\nimport { isFluidHandle } from \"@fluidframework/runtime-utils/internal\";\n\nimport type { ISharedObject } from \"./types.js\";\n\n/**\n * Handle for a shared object. See also `SharedObjectHandle`.\n * Supports binding other handles to the underlying Shared Object (see {@link ISharedObjectHandle.bind}).\n *\n * @internal\n */\nexport interface ISharedObjectHandle extends IFluidHandleInternal<ISharedObject> {\n\t/**\n\t * Binds the given handle to this DDS or attach the given handle if this DDS is attached.\n\t * A bound handle will also be attached once this DDS is attached.\n\t *\n\t * @param handle - The target handle to bind to this DDS\n\t */\n\tbind(handle: IFluidHandleInternal): void;\n}\n\n/**\n * Type guard for {@link ISharedObjectHandle}.\n * @internal\n */\nexport function isISharedObjectHandle(handle: unknown): handle is ISharedObjectHandle {\n\treturn isFluidHandle(handle) && typeof (handle as ISharedObjectHandle).bind === \"function\";\n}\n\n/**\n * Handle for a shared object (DDS).\n *\n * @remarks\n *\n * This object is used for already loaded (in-memory) shared objects.\n *\n * It provides a \"bind\" function that is expected to be invoked on all handles stored in this DDS,\n * ensuring the target object becomes attached along with this DDS.\n */\nexport class SharedObjectHandle\n\textends FluidObjectHandle<ISharedObject>\n\timplements ISharedObjectHandle\n{\n\t/**\n\t * Whether services have been attached for the associated shared object.\n\t */\n\tpublic get isAttached(): boolean {\n\t\treturn this.value.isAttached();\n\t}\n\n\t/**\n\t * Tells whether the object of this handle is visible in the container locally or globally.\n\t */\n\tprivate get isVisible(): boolean {\n\t\t/**\n\t\t * If the object of this handle is attached, it is visible in the container. Ideally, checking local visibility\n\t\t * should be enough for a handle. However, there are scenarios where the object becomes locally visible but the\n\t\t * handle does not know this - This will happen is attachGraph is never called on the handle. Couple of examples\n\t\t * where this can happen:\n\t\t *\n\t\t * 1. Handles to DDS other than the default handle won't know if the DDS becomes visible after the handle was\n\t\t * created.\n\t\t *\n\t\t * 2. Handles to root data stores will never know that it was visible because the handle will not be stores in\n\t\t * another DDS and so, attachGraph will never be called on it.\n\t\t */\n\t\treturn this.isAttached || this.isLocallyVisible;\n\t}\n\n\t/**\n\t * Tracks whether this handle is locally visible in the container.\n\t */\n\tprivate isLocallyVisible: boolean = false;\n\n\tprivate readonly pendingHandles: Set<IFluidHandleInternal> = new Set();\n\n\t/**\n\t * Creates a new SharedObjectHandle.\n\t * @param value - The shared object this handle is for.\n\t * @param path - The id of the shared object. It is also the path to this object relative to the routeContext.\n\t * @param routeContext - The parent {@link @fluidframework/core-interfaces#IFluidHandleContext} that has a route\n\t * to this handle.\n\t */\n\tconstructor(\n\t\tprotected readonly value: ISharedObject,\n\t\tpath: string,\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t) {\n\t\tsuper(value, path, runtime.IFluidHandleContext);\n\t}\n\n\t/**\n\t * Attaches all bound handles first (which may in turn attach further handles), then attaches this handle.\n\t * When attaching the handle, it registers the associated shared object.\n\t */\n\tpublic attachGraph(): void {\n\t\tif (this.isVisible) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Recursively attach all pending handles\n\t\tthis.isLocallyVisible = true;\n\t\tfor (const handle of this.pendingHandles) {\n\t\t\thandle.attachGraph();\n\t\t}\n\t\tthis.pendingHandles.clear();\n\n\t\t// Bind this SharedObject to its context (typically the DataStore) so it attaches with it\n\t\tthis.value.bindToContext();\n\n\t\t// This will trigger the context (typically the DataStore) to attach its graph\n\t\tsuper.attachGraph();\n\t}\n\n\tpublic bind(handle: IFluidHandleInternal): void {\n\t\t// We don't bind handles in staging mode to defer the attachment of any new objects\n\t\t// until we've exited staging mode. This way if we discard changes or a new handle is not present in the final\n\t\t// committed state, we will never end up attaching the discarded object.\n\t\tif (this.runtime.inStagingMode === true) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is visible, attach the graph of the incoming handle as well.\n\t\tif (this.isVisible) {\n\t\t\thandle.attachGraph();\n\t\t\treturn;\n\t\t}\n\n\t\t// If this handle is not visible, we will attach it later when this handle's attachGraph is called.\n\t\tthis.pendingHandles.add(handle);\n\t}\n}\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/shared-object-base";
|
|
8
|
-
export declare const pkgVersion = "
|
|
8
|
+
export declare const pkgVersion = "3.0.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,uCAAuC,CAAC;AAC5D,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,uCAAuC,CAAC;AAC5D,eAAO,MAAM,UAAU,UAAU,CAAC"}
|
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/shared-object-base";
|
|
11
|
-
exports.pkgVersion = "
|
|
11
|
+
exports.pkgVersion = "3.0.0";
|
|
12
12
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,oCAAoC,CAAC;AAC/C,QAAA,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,oCAAoC,CAAC;AAC/C,QAAA,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/shared-object-base\";\nexport const pkgVersion = \"3.0.0\";\n"]}
|
package/dist/serializer.js
CHANGED
package/dist/serializer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIFluidHandleContext,\n\tIFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n\tRemoteFluidObjectHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle, type ISharedObjectHandle } from \"./handle.js\";\n\n/**\n * @legacy @beta\n */\nexport interface IFluidSerializer {\n\t/**\n\t * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n\t * where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t */\n\tencode(value: unknown, bind: IFluidHandle): unknown;\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tdecode(input: unknown): unknown;\n\n\t/**\n\t * Stringifies a given value. Converts any IFluidHandle to its stringified equivalent.\n\t */\n\tstringify(value: unknown, bind: IFluidHandle): string;\n\n\t/**\n\t * Parses the given JSON input string and returns the JavaScript object defined by it. Any Fluid\n\t * handles will be realized as part of the parse\n\t */\n\tparse(value: string): unknown;\n}\n\n/**\n * Data Store serializer implementation\n * @internal\n */\nexport class FluidSerializer implements IFluidSerializer {\n\tprivate readonly root: IFluidHandleContext;\n\n\tpublic constructor(private readonly context: IFluidHandleContext) {\n\t\tthis.root = this.context;\n\t\twhile (this.root.routeContext !== undefined) {\n\t\t\tthis.root = this.root.routeContext;\n\t\t}\n\t}\n\n\tpublic get IFluidSerializer(): IFluidSerializer {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n\t * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * Any unbound handles encountered are bound to the provided IFluidHandle.\n\t */\n\tpublic encode(input: unknown, bind: IFluidHandleInternal): unknown {\n\t\tassert(isISharedObjectHandle(bind), 0xb8c /* bind must be an ISharedObjectHandle */);\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.encodeValue.bind(this), bind)\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tpublic decode(input: unknown): unknown {\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.decodeValue.bind(this))\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Serializes the input object into a JSON string.\n\t * Any IFluidHandles in the object will be replaced with their serialized form before stringify,\n\t * being bound to the given bind context in the process.\n\t */\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tassert(isISharedObjectHandle(bind), 0xb8d /* bind must be an ISharedObjectHandle */);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n\t}\n\n\t/**\n\t * Parses the serialized data - context must match the context with which the JSON was stringified\n\t */\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\n\t/**\n\t * If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'encode()' and 'stringify()'.\n\t */\n\tprotected encodeValue(value: unknown, bind?: ISharedObjectHandle): unknown {\n\t\t// If 'value' is an IFluidHandle return its encoded form.\n\t\tif (isFluidHandle(value)) {\n\t\t\tassert(bind !== undefined, 0xa93 /* Cannot encode a handle without a bind context */);\n\t\t\treturn this.bindAndEncodeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n\t */\n\tprotected decodeValue(value: unknown): unknown {\n\t\t// If 'value' is a serialized IFluidHandle return the deserialized result.\n\t\tif (isSerializedHandle(value)) {\n\t\t\t// Old documents may have handles with relative path in their summaries. Convert these to absolute\n\t\t\t// paths. This will ensure that future summaries will have absolute paths for these handles.\n\t\t\tconst absolutePath = value.url.startsWith(\"/\")\n\t\t\t\t? value.url\n\t\t\t\t: generateHandleContextPath(value.url, this.context);\n\n\t\t\treturn new RemoteFluidObjectHandle(\n\t\t\t\tabsolutePath,\n\t\t\t\tthis.root,\n\t\t\t\tvalue.payloadPending === true,\n\t\t\t);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Invoked for non-null objects to recursively replace references to IFluidHandles.\n\t * Clones as-needed to avoid mutating the `input` object. If no IFluidHandles are present,\n\t * returns the original `input`.\n\t */\n\tprivate recursivelyReplace<TContext = unknown>(\n\t\tinput: object,\n\t\treplacer: (input: unknown, context?: TContext) => unknown,\n\t\tcontext?: TContext,\n\t): unknown {\n\t\t// Note: Caller is responsible for ensuring that `input` is defined / non-null.\n\t\t// (Required for Object.keys() below.)\n\n\t\t// Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n\t\t// is a non-null object.\n\t\tconst maybeReplaced = replacer(input, context);\n\n\t\t// If either input or the replaced result is a Fluid Handle, there is no need to descend further.\n\t\t// IFluidHandles are always leaves in the object graph, and the code below cannot deal with IFluidHandle's structure.\n\t\tif (isFluidHandle(input) || isFluidHandle(maybeReplaced)) {\n\t\t\treturn maybeReplaced;\n\t\t}\n\n\t\t// Otherwise descend into the object graph looking for IFluidHandle instances.\n\t\tlet clone: object | undefined;\n\t\tfor (const key of Object.keys(input)) {\n\t\t\tconst value: unknown = input[key];\n\t\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\t\tif (!!value && typeof value === \"object\") {\n\t\t\t\t// Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n\t\t\t\t// be JSON serializable.) Therefore, guarding against infinite recursion here would only\n\t\t\t\t// lead to a later error when attempting to stringify().\n\t\t\t\tconst replaced = this.recursivelyReplace(value, replacer, context);\n\n\t\t\t\t// If the `replaced` object is different than the original `value` then the subgraph contained one\n\t\t\t\t// or more handles. If this happens, we need to return a clone of the `input` object where the\n\t\t\t\t// current property is replaced by the `replaced` value.\n\t\t\t\tif (replaced !== value) {\n\t\t\t\t\t// Lazily create a shallow clone of the `input` object if we haven't done so already.\n\t\t\t\t\tclone ??= shallowCloneObject(input);\n\n\t\t\t\t\t// Overwrite the current property `key` in the clone with the `replaced` value.\n\t\t\t\t\tclone[key] = replaced;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn clone ?? input;\n\t}\n\n\t/**\n\t * Encodes the given IFluidHandle into a JSON-serializable form,\n\t * also binding it to another node to ensure it attaches at the right time.\n\t * @param handle - The IFluidHandle to serialize.\n\t * @param bind - The binding context for the handle (the handle will become attached whenever this context is attached).\n\t * @returns The serialized handle.\n\t */\n\tprotected bindAndEncodeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: ISharedObjectHandle,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn encodeHandleForSerialization(handle);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport type {\n\tIFluidHandleContext,\n\tIFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tencodeHandleForSerialization,\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n\tRemoteFluidObjectHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { isISharedObjectHandle, type ISharedObjectHandle } from \"./handle.js\";\n\n/**\n * @legacy @beta\n */\nexport interface IFluidSerializer {\n\t/**\n\t * Given a mostly-plain object that may have handle objects embedded within, will return a fully-plain object\n\t * where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t */\n\tencode(value: unknown, bind: IFluidHandle): unknown;\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tdecode(input: unknown): unknown;\n\n\t/**\n\t * Stringifies a given value. Converts any IFluidHandle to its stringified equivalent.\n\t */\n\tstringify(value: unknown, bind: IFluidHandle): string;\n\n\t/**\n\t * Parses the given JSON input string and returns the JavaScript object defined by it. Any Fluid\n\t * handles will be realized as part of the parse\n\t */\n\tparse(value: string): unknown;\n}\n\n/**\n * Data Store serializer implementation\n * @internal\n */\nexport class FluidSerializer implements IFluidSerializer {\n\tprivate readonly root: IFluidHandleContext;\n\n\tpublic constructor(private readonly context: IFluidHandleContext) {\n\t\tthis.root = this.context;\n\t\twhile (this.root.routeContext !== undefined) {\n\t\t\tthis.root = this.root.routeContext;\n\t\t}\n\t}\n\n\tpublic get IFluidSerializer(): IFluidSerializer {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n\t * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * Any unbound handles encountered are bound to the provided IFluidHandle.\n\t */\n\tpublic encode(input: unknown, bind: IFluidHandleInternal): unknown {\n\t\tassert(isISharedObjectHandle(bind), 0xb8c /* bind must be an ISharedObjectHandle */);\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.encodeValue.bind(this), bind)\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n\t * equivalent object tree where any encoded IFluidHandles have been replaced with their decoded form.\n\t *\n\t * The original `input` object is not mutated. This method will shallowly clone all objects in the path from\n\t * the root to any replaced handles. (If no handles are found, returns the original object.)\n\t *\n\t * The decoded handles are implicitly bound to the handle context of this serializer.\n\t */\n\tpublic decode(input: unknown): unknown {\n\t\t// If the given 'input' cannot contain handles, return it immediately. Otherwise,\n\t\t// return the result of 'recursivelyReplace()'.\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\treturn !!input && typeof input === \"object\"\n\t\t\t? this.recursivelyReplace(input, this.decodeValue.bind(this))\n\t\t\t: input;\n\t}\n\n\t/**\n\t * Serializes the input object into a JSON string.\n\t * Any IFluidHandles in the object will be replaced with their serialized form before stringify,\n\t * being bound to the given bind context in the process.\n\t */\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tassert(isISharedObjectHandle(bind), 0xb8d /* bind must be an ISharedObjectHandle */);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n\t}\n\n\t/**\n\t * Parses the serialized data - context must match the context with which the JSON was stringified\n\t */\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\n\t/**\n\t * If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'encode()' and 'stringify()'.\n\t */\n\tprotected encodeValue(value: unknown, bind?: ISharedObjectHandle): unknown {\n\t\t// If 'value' is an IFluidHandle return its encoded form.\n\t\tif (isFluidHandle(value)) {\n\t\t\tassert(bind !== undefined, 0xa93 /* Cannot encode a handle without a bind context */);\n\t\t\treturn this.bindAndEncodeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n\t * Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n\t */\n\tprotected decodeValue(value: unknown): unknown {\n\t\t// If 'value' is a serialized IFluidHandle return the deserialized result.\n\t\tif (isSerializedHandle(value)) {\n\t\t\t// Old documents may have handles with relative path in their summaries. Convert these to absolute\n\t\t\t// paths. This will ensure that future summaries will have absolute paths for these handles.\n\t\t\tconst absolutePath = value.url.startsWith(\"/\")\n\t\t\t\t? value.url\n\t\t\t\t: generateHandleContextPath(value.url, this.context);\n\n\t\t\treturn new RemoteFluidObjectHandle(\n\t\t\t\tabsolutePath,\n\t\t\t\tthis.root,\n\t\t\t\tvalue.payloadPending === true,\n\t\t\t);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t}\n\n\t/**\n\t * Invoked for non-null objects to recursively replace references to IFluidHandles.\n\t * Clones as-needed to avoid mutating the `input` object. If no IFluidHandles are present,\n\t * returns the original `input`.\n\t */\n\tprivate recursivelyReplace<TContext = unknown>(\n\t\tinput: object,\n\t\treplacer: (input: unknown, context?: TContext) => unknown,\n\t\tcontext?: TContext,\n\t): unknown {\n\t\t// Note: Caller is responsible for ensuring that `input` is defined / non-null.\n\t\t// (Required for Object.keys() below.)\n\n\t\t// Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n\t\t// is a non-null object.\n\t\tconst maybeReplaced = replacer(input, context);\n\n\t\t// If either input or the replaced result is a Fluid Handle, there is no need to descend further.\n\t\t// IFluidHandles are always leaves in the object graph, and the code below cannot deal with IFluidHandle's structure.\n\t\tif (isFluidHandle(input) || isFluidHandle(maybeReplaced)) {\n\t\t\treturn maybeReplaced;\n\t\t}\n\n\t\t// Otherwise descend into the object graph looking for IFluidHandle instances.\n\t\tlet clone: object | undefined;\n\t\tfor (const key of Object.keys(input)) {\n\t\t\tconst value: unknown = input[key];\n\t\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\t\tif (!!value && typeof value === \"object\") {\n\t\t\t\t// Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n\t\t\t\t// be JSON serializable.) Therefore, guarding against infinite recursion here would only\n\t\t\t\t// lead to a later error when attempting to stringify().\n\t\t\t\tconst replaced = this.recursivelyReplace(value, replacer, context);\n\n\t\t\t\t// If the `replaced` object is different than the original `value` then the subgraph contained one\n\t\t\t\t// or more handles. If this happens, we need to return a clone of the `input` object where the\n\t\t\t\t// current property is replaced by the `replaced` value.\n\t\t\t\tif (replaced !== value) {\n\t\t\t\t\t// Lazily create a shallow clone of the `input` object if we haven't done so already.\n\t\t\t\t\tclone ??= shallowCloneObject(input);\n\n\t\t\t\t\t// Overwrite the current property `key` in the clone with the `replaced` value.\n\t\t\t\t\tclone[key] = replaced;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn clone ?? input;\n\t}\n\n\t/**\n\t * Encodes the given IFluidHandle into a JSON-serializable form,\n\t * also binding it to another node to ensure it attaches at the right time.\n\t * @param handle - The IFluidHandle to serialize.\n\t * @param bind - The binding context for the handle (the handle will become attached whenever this context is attached).\n\t * @returns The serialized handle.\n\t */\n\tprotected bindAndEncodeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: ISharedObjectHandle,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn encodeHandleForSerialization(handle);\n\t}\n}\n"]}
|