@fluidframework/shared-object-base 2.20.0 → 2.21.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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/shared-object-base
2
2
 
3
+ ## 2.21.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.20.0
4
8
 
5
9
  ### Minor Changes
@@ -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 = "2.20.0";
8
+ export declare const pkgVersion = "2.21.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -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 = "2.20.0";
11
+ exports.pkgVersion = "2.21.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,QAAQ,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 = \"2.20.0\";\n"]}
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,QAAQ,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 = \"2.21.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAKN,KAAK,iBAAiB,EACtB,MAAM,wCAAwC,CAAC;AAIhD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAEpD;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAEhC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAEtD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGpC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO;IASlE;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAS/B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAMrD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAO1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IA6C1B,SAAS,CAAC,eAAe,CACxB,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,oBAAoB,GACxB,iBAAiB;CAOpB"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAKN,KAAK,iBAAiB,EACtB,MAAM,wCAAwC,CAAC;AAIhD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAEpD;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAEhC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAEtD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGpC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO;IASlE;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAS/B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAMrD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAO1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IA4C1B,SAAS,CAAC,eAAe,CACxB,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,oBAAoB,GACxB,iBAAiB;CAOpB"}
@@ -120,8 +120,7 @@ class FluidSerializer {
120
120
  // current property is replaced by the `replaced` value.
121
121
  if (replaced !== value) {
122
122
  // Lazily create a shallow clone of the `input` object if we haven't done so already.
123
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- TODO: not sure if there's a good solution
124
- clone = clone ?? (Array.isArray(input) ? [...input] : { ...input });
123
+ clone ?? (clone = (0, internal_1.shallowCloneObject)(input));
125
124
  // Overwrite the current property `key` in the clone with the `replaced` value.
126
125
  clone[key] = replaced;
127
126
  }
@@ -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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport {\n\tIFluidHandleContext,\n\ttype IFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle.js\";\n\n/**\n * @legacy\n * @alpha\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\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)\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)\n\t\t\t: input;\n\t}\n\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tconst bindInternal = toFluidHandleInternal(bind);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bindInternal));\n\t}\n\n\t// Parses the serialized data - context must match the context with which the JSON was stringified\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\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\tprivate readonly encodeValue = (value: unknown, bind?: IFluidHandleInternal): 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.serializeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t};\n\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\tprivate readonly 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(absolutePath, this.root);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t};\n\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 IFluidHandes are present,\n\t// returns the original `input`.\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\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- TODO: not sure if there's a good solution\n\t\t\t\t\tclone = clone ?? (Array.isArray(input) ? [...input] : { ...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\tprotected serializeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: IFluidHandleInternal,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: handle.absolutePath,\n\t\t};\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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport {\n\tIFluidHandleContext,\n\ttype IFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle.js\";\n\n/**\n * @legacy\n * @alpha\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\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)\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)\n\t\t\t: input;\n\t}\n\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tconst bindInternal = toFluidHandleInternal(bind);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bindInternal));\n\t}\n\n\t// Parses the serialized data - context must match the context with which the JSON was stringified\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\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\tprivate readonly encodeValue = (value: unknown, bind?: IFluidHandleInternal): 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.serializeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t};\n\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\tprivate readonly 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(absolutePath, this.root);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t};\n\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 IFluidHandes are present,\n\t// returns the original `input`.\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\tprotected serializeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: IFluidHandleInternal,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: handle.absolutePath,\n\t\t};\n\t}\n}\n"]}
@@ -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 = "2.20.0";
8
+ export declare const pkgVersion = "2.21.0";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/shared-object-base";
8
- export const pkgVersion = "2.20.0";
8
+ export const pkgVersion = "2.21.0";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,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 = \"2.20.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,oCAAoC,CAAC;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,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 = \"2.21.0\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAKN,KAAK,iBAAiB,EACtB,MAAM,wCAAwC,CAAC;AAIhD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAEpD;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAEhC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAEtD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGpC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO;IASlE;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAS/B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAMrD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAO1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IA6C1B,SAAS,CAAC,eAAe,CACxB,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,oBAAoB,GACxB,iBAAiB;CAOpB"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EACN,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,MAAM,0CAA0C,CAAC;AAElD,OAAO,EAKN,KAAK,iBAAiB,EACtB,MAAM,wCAAwC,CAAC;AAIhD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAEpD;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAEhC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IAEtD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGpC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO;IASlE;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IAS/B,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAMrD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAO1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IA4C1B,SAAS,CAAC,eAAe,CACxB,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,oBAAoB,GACxB,iBAAiB;CAOpB"}
package/lib/serializer.js 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 { assert } from "@fluidframework/core-utils/internal";
5
+ import { assert, shallowCloneObject } from "@fluidframework/core-utils/internal";
6
6
  import { generateHandleContextPath, isSerializedHandle, isFluidHandle, toFluidHandleInternal, } from "@fluidframework/runtime-utils/internal";
7
7
  import { RemoteFluidObjectHandle } from "./remoteObjectHandle.js";
8
8
  /**
@@ -117,8 +117,7 @@ export class FluidSerializer {
117
117
  // current property is replaced by the `replaced` value.
118
118
  if (replaced !== value) {
119
119
  // Lazily create a shallow clone of the `input` object if we haven't done so already.
120
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- TODO: not sure if there's a good solution
121
- clone = clone ?? (Array.isArray(input) ? [...input] : { ...input });
120
+ clone ?? (clone = shallowCloneObject(input));
122
121
  // Overwrite the current property `key` in the clone with the `replaced` value.
123
122
  clone[key] = replaced;
124
123
  }
@@ -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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport {\n\tIFluidHandleContext,\n\ttype IFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle.js\";\n\n/**\n * @legacy\n * @alpha\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\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)\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)\n\t\t\t: input;\n\t}\n\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tconst bindInternal = toFluidHandleInternal(bind);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bindInternal));\n\t}\n\n\t// Parses the serialized data - context must match the context with which the JSON was stringified\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\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\tprivate readonly encodeValue = (value: unknown, bind?: IFluidHandleInternal): 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.serializeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t};\n\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\tprivate readonly 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(absolutePath, this.root);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t};\n\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 IFluidHandes are present,\n\t// returns the original `input`.\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\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- TODO: not sure if there's a good solution\n\t\t\t\t\tclone = clone ?? (Array.isArray(input) ? [...input] : { ...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\tprotected serializeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: IFluidHandleInternal,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: handle.absolutePath,\n\t\t};\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 { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport {\n\tIFluidHandleContext,\n\ttype IFluidHandleInternal,\n} from \"@fluidframework/core-interfaces/internal\";\nimport { assert, shallowCloneObject } from \"@fluidframework/core-utils/internal\";\nimport {\n\tgenerateHandleContextPath,\n\tisSerializedHandle,\n\tisFluidHandle,\n\ttoFluidHandleInternal,\n\ttype ISerializedHandle,\n} from \"@fluidframework/runtime-utils/internal\";\n\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle.js\";\n\n/**\n * @legacy\n * @alpha\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\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)\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)\n\t\t\t: input;\n\t}\n\n\tpublic stringify(input: unknown, bind: IFluidHandle): string {\n\t\tconst bindInternal = toFluidHandleInternal(bind);\n\t\treturn JSON.stringify(input, (key, value) => this.encodeValue(value, bindInternal));\n\t}\n\n\t// Parses the serialized data - context must match the context with which the JSON was stringified\n\tpublic parse(input: string): unknown {\n\t\treturn JSON.parse(input, (key, value) => this.decodeValue(value));\n\t}\n\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\tprivate readonly encodeValue = (value: unknown, bind?: IFluidHandleInternal): 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.serializeHandle(toFluidHandleInternal(value), bind);\n\t\t}\n\t\treturn value;\n\t};\n\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\tprivate readonly 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(absolutePath, this.root);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t};\n\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 IFluidHandes are present,\n\t// returns the original `input`.\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\tprotected serializeHandle(\n\t\thandle: IFluidHandleInternal,\n\t\tbind: IFluidHandleInternal,\n\t): ISerializedHandle {\n\t\tbind.bind(handle);\n\t\treturn {\n\t\t\ttype: \"__fluid_handle__\",\n\t\t\turl: handle.absolutePath,\n\t\t};\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/shared-object-base",
3
- "version": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "Fluid base class for shared distributed data structures",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -69,30 +69,30 @@
69
69
  "temp-directory": "nyc/.nyc_output"
70
70
  },
71
71
  "dependencies": {
72
- "@fluid-internal/client-utils": "~2.20.0",
73
- "@fluidframework/container-definitions": "~2.20.0",
74
- "@fluidframework/container-runtime": "~2.20.0",
75
- "@fluidframework/core-interfaces": "~2.20.0",
76
- "@fluidframework/core-utils": "~2.20.0",
77
- "@fluidframework/datastore": "~2.20.0",
78
- "@fluidframework/datastore-definitions": "~2.20.0",
79
- "@fluidframework/driver-definitions": "~2.20.0",
80
- "@fluidframework/runtime-definitions": "~2.20.0",
81
- "@fluidframework/runtime-utils": "~2.20.0",
82
- "@fluidframework/telemetry-utils": "~2.20.0",
72
+ "@fluid-internal/client-utils": "~2.21.0",
73
+ "@fluidframework/container-definitions": "~2.21.0",
74
+ "@fluidframework/container-runtime": "~2.21.0",
75
+ "@fluidframework/core-interfaces": "~2.21.0",
76
+ "@fluidframework/core-utils": "~2.21.0",
77
+ "@fluidframework/datastore": "~2.21.0",
78
+ "@fluidframework/datastore-definitions": "~2.21.0",
79
+ "@fluidframework/driver-definitions": "~2.21.0",
80
+ "@fluidframework/runtime-definitions": "~2.21.0",
81
+ "@fluidframework/runtime-utils": "~2.21.0",
82
+ "@fluidframework/telemetry-utils": "~2.21.0",
83
83
  "uuid": "^9.0.0"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@arethetypeswrong/cli": "^0.17.1",
87
87
  "@biomejs/biome": "~1.9.3",
88
- "@fluid-internal/mocha-test-setup": "~2.20.0",
89
- "@fluid-private/test-pairwise-generator": "~2.20.0",
88
+ "@fluid-internal/mocha-test-setup": "~2.21.0",
89
+ "@fluid-private/test-pairwise-generator": "~2.21.0",
90
90
  "@fluid-tools/build-cli": "^0.51.0",
91
91
  "@fluidframework/build-common": "^2.0.3",
92
92
  "@fluidframework/build-tools": "^0.51.0",
93
- "@fluidframework/eslint-config-fluid": "^5.6.0",
94
- "@fluidframework/shared-object-base-previous": "npm:@fluidframework/shared-object-base@2.13.0",
95
- "@fluidframework/test-runtime-utils": "~2.20.0",
93
+ "@fluidframework/eslint-config-fluid": "^5.7.3",
94
+ "@fluidframework/shared-object-base-previous": "npm:@fluidframework/shared-object-base@2.20.0",
95
+ "@fluidframework/test-runtime-utils": "~2.21.0",
96
96
  "@microsoft/api-extractor": "7.47.8",
97
97
  "@types/benchmark": "^2.1.0",
98
98
  "@types/mocha": "^10.0.10",
@@ -148,7 +148,7 @@
148
148
  "ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor.current.json",
149
149
  "ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
150
150
  "ci:build:docs": "api-extractor run",
151
- "clean": "rimraf --glob dist lib \"*.d.ts\" \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
151
+ "clean": "rimraf --glob dist lib {alpha,beta,internal,legacy}.d.ts \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
152
152
  "eslint": "eslint --format stylish src",
153
153
  "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
154
154
  "format": "npm run format:biome",
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/shared-object-base";
9
- export const pkgVersion = "2.20.0";
9
+ export const pkgVersion = "2.21.0";
package/src/serializer.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  IFluidHandleContext,
9
9
  type IFluidHandleInternal,
10
10
  } from "@fluidframework/core-interfaces/internal";
11
- import { assert } from "@fluidframework/core-utils/internal";
11
+ import { assert, shallowCloneObject } from "@fluidframework/core-utils/internal";
12
12
  import {
13
13
  generateHandleContextPath,
14
14
  isSerializedHandle,
@@ -185,8 +185,7 @@ export class FluidSerializer implements IFluidSerializer {
185
185
  // current property is replaced by the `replaced` value.
186
186
  if (replaced !== value) {
187
187
  // Lazily create a shallow clone of the `input` object if we haven't done so already.
188
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- TODO: not sure if there's a good solution
189
- clone = clone ?? (Array.isArray(input) ? [...input] : { ...input });
188
+ clone ??= shallowCloneObject(input);
190
189
 
191
190
  // Overwrite the current property `key` in the clone with the `replaced` value.
192
191
  clone[key] = replaced;