@fluidframework/datastore 2.0.0-dev-rc.1.0.0.228517 → 2.0.0-dev-rc.2.0.0.245554

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +4 -1
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +42 -0
  4. package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
  5. package/api-extractor-lint.json +1 -1
  6. package/api-extractor.json +1 -1
  7. package/api-report/datastore.api.md +7 -11
  8. package/dist/channelContext.d.ts +5 -4
  9. package/dist/channelContext.d.ts.map +1 -1
  10. package/dist/channelContext.js +6 -5
  11. package/dist/channelContext.js.map +1 -1
  12. package/dist/channelDeltaConnection.d.ts +6 -3
  13. package/dist/channelDeltaConnection.d.ts.map +1 -1
  14. package/dist/channelDeltaConnection.js +46 -7
  15. package/dist/channelDeltaConnection.js.map +1 -1
  16. package/dist/dataStoreRuntime.d.ts +25 -6
  17. package/dist/dataStoreRuntime.d.ts.map +1 -1
  18. package/dist/dataStoreRuntime.js +145 -62
  19. package/dist/dataStoreRuntime.js.map +1 -1
  20. package/dist/datastore-alpha.d.ts +23 -6
  21. package/dist/datastore-beta.d.ts +1 -2
  22. package/dist/datastore-public.d.ts +1 -2
  23. package/dist/datastore-untrimmed.d.ts +23 -6
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +7 -7
  27. package/dist/index.js.map +1 -1
  28. package/dist/localChannelContext.d.ts +18 -3
  29. package/dist/localChannelContext.d.ts.map +1 -1
  30. package/dist/localChannelContext.js +32 -10
  31. package/dist/localChannelContext.js.map +1 -1
  32. package/dist/package.json +3 -0
  33. package/dist/remoteChannelContext.d.ts +2 -2
  34. package/dist/remoteChannelContext.d.ts.map +1 -1
  35. package/dist/remoteChannelContext.js +6 -5
  36. package/dist/remoteChannelContext.js.map +1 -1
  37. package/dist/tsdoc-metadata.json +1 -1
  38. package/lib/{channelContext.d.mts → channelContext.d.ts} +6 -5
  39. package/lib/channelContext.d.ts.map +1 -0
  40. package/lib/{channelContext.mjs → channelContext.js} +6 -5
  41. package/lib/channelContext.js.map +1 -0
  42. package/lib/{channelDeltaConnection.d.mts → channelDeltaConnection.d.ts} +7 -4
  43. package/lib/channelDeltaConnection.d.ts.map +1 -0
  44. package/lib/channelDeltaConnection.js +92 -0
  45. package/lib/channelDeltaConnection.js.map +1 -0
  46. package/lib/{channelStorageService.d.mts → channelStorageService.d.ts} +1 -1
  47. package/lib/channelStorageService.d.ts.map +1 -0
  48. package/lib/{channelStorageService.mjs → channelStorageService.js} +1 -1
  49. package/lib/channelStorageService.js.map +1 -0
  50. package/lib/{dataStoreRuntime.d.mts → dataStoreRuntime.d.ts} +26 -7
  51. package/lib/dataStoreRuntime.d.ts.map +1 -0
  52. package/lib/{dataStoreRuntime.mjs → dataStoreRuntime.js} +142 -59
  53. package/lib/dataStoreRuntime.js.map +1 -0
  54. package/lib/{datastore-alpha.d.mts → datastore-alpha.d.ts} +23 -6
  55. package/lib/{datastore-public.d.mts → datastore-beta.d.ts} +1 -2
  56. package/lib/{datastore-beta.d.mts → datastore-public.d.ts} +1 -2
  57. package/lib/{datastore-untrimmed.d.mts → datastore-untrimmed.d.ts} +23 -6
  58. package/lib/{fluidHandle.d.mts → fluidHandle.d.ts} +1 -1
  59. package/lib/fluidHandle.d.ts.map +1 -0
  60. package/lib/{fluidHandle.mjs → fluidHandle.js} +1 -1
  61. package/lib/fluidHandle.js.map +1 -0
  62. package/lib/{index.d.mts → index.d.ts} +3 -3
  63. package/lib/index.d.ts.map +1 -0
  64. package/lib/{index.mjs → index.js} +3 -3
  65. package/lib/index.js.map +1 -0
  66. package/lib/{localChannelContext.d.mts → localChannelContext.d.ts} +19 -4
  67. package/lib/localChannelContext.d.ts.map +1 -0
  68. package/lib/{localChannelContext.mjs → localChannelContext.js} +29 -7
  69. package/lib/localChannelContext.js.map +1 -0
  70. package/lib/{localChannelStorageService.d.mts → localChannelStorageService.d.ts} +1 -1
  71. package/lib/localChannelStorageService.d.ts.map +1 -0
  72. package/lib/{localChannelStorageService.mjs → localChannelStorageService.js} +1 -1
  73. package/lib/localChannelStorageService.js.map +1 -0
  74. package/lib/{remoteChannelContext.d.mts → remoteChannelContext.d.ts} +3 -3
  75. package/lib/remoteChannelContext.d.ts.map +1 -0
  76. package/lib/{remoteChannelContext.mjs → remoteChannelContext.js} +4 -3
  77. package/lib/remoteChannelContext.js.map +1 -0
  78. package/lib/test/channelStorageService.spec.js +70 -0
  79. package/lib/test/channelStorageService.spec.js.map +1 -0
  80. package/lib/test/dataStoreRuntime.spec.js +121 -0
  81. package/lib/test/dataStoreRuntime.spec.js.map +1 -0
  82. package/lib/test/localChannelContext.spec.js +41 -0
  83. package/lib/test/localChannelContext.spec.js.map +1 -0
  84. package/lib/test/localChannelStorageService.spec.js +72 -0
  85. package/lib/test/localChannelStorageService.spec.js.map +1 -0
  86. package/lib/test/remoteChannelContext.spec.js +33 -0
  87. package/lib/test/remoteChannelContext.spec.js.map +1 -0
  88. package/lib/test/types/validateDatastorePrevious.generated.js +16 -0
  89. package/lib/test/types/validateDatastorePrevious.generated.js.map +1 -0
  90. package/package.json +48 -50
  91. package/src/channelContext.ts +6 -3
  92. package/src/channelDeltaConnection.ts +69 -5
  93. package/src/dataStoreRuntime.ts +181 -81
  94. package/src/index.ts +2 -2
  95. package/src/localChannelContext.ts +38 -5
  96. package/src/remoteChannelContext.ts +4 -2
  97. package/tsconfig.cjs.json +7 -0
  98. package/tsconfig.json +2 -5
  99. package/lib/channelContext.d.mts.map +0 -1
  100. package/lib/channelContext.mjs.map +0 -1
  101. package/lib/channelDeltaConnection.d.mts.map +0 -1
  102. package/lib/channelDeltaConnection.mjs +0 -53
  103. package/lib/channelDeltaConnection.mjs.map +0 -1
  104. package/lib/channelStorageService.d.mts.map +0 -1
  105. package/lib/channelStorageService.mjs.map +0 -1
  106. package/lib/dataStoreRuntime.d.mts.map +0 -1
  107. package/lib/dataStoreRuntime.mjs.map +0 -1
  108. package/lib/fluidHandle.d.mts.map +0 -1
  109. package/lib/fluidHandle.mjs.map +0 -1
  110. package/lib/index.d.mts.map +0 -1
  111. package/lib/index.mjs.map +0 -1
  112. package/lib/localChannelContext.d.mts.map +0 -1
  113. package/lib/localChannelContext.mjs.map +0 -1
  114. package/lib/localChannelStorageService.d.mts.map +0 -1
  115. package/lib/localChannelStorageService.mjs.map +0 -1
  116. package/lib/remoteChannelContext.d.mts.map +0 -1
  117. package/lib/remoteChannelContext.mjs.map +0 -1
@@ -0,0 +1,92 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { assert } from "@fluidframework/core-utils";
6
+ import { DataProcessingError } from "@fluidframework/telemetry-utils";
7
+ const stashedOpMetadataMark = Symbol();
8
+ function createStashedOpMetadata() {
9
+ const arr = [];
10
+ Object.defineProperty(arr, stashedOpMetadataMark, {
11
+ value: stashedOpMetadataMark,
12
+ writable: false,
13
+ enumerable: true,
14
+ });
15
+ return arr;
16
+ }
17
+ function isStashedOpMetadata(md) {
18
+ return (Array.isArray(md) &&
19
+ stashedOpMetadataMark in md &&
20
+ md[stashedOpMetadataMark] === stashedOpMetadataMark);
21
+ }
22
+ function processWithStashedOpMetadataHandling(content, localOpMetaData, func) {
23
+ if (isStashedOpMetadata(localOpMetaData)) {
24
+ localOpMetaData.forEach(({ contents, metadata }) => func(contents, metadata));
25
+ }
26
+ else {
27
+ func(content, localOpMetaData);
28
+ }
29
+ }
30
+ export class ChannelDeltaConnection {
31
+ get handler() {
32
+ assert(!!this._handler, 0x177 /* "Missing delta handler" */);
33
+ return this._handler;
34
+ }
35
+ get connected() {
36
+ return this._connected;
37
+ }
38
+ constructor(_connected, submitFn, dirty,
39
+ /** @deprecated There is no replacement for this, its functionality is no longer needed at this layer. */
40
+ addedGCOutboundReference, isAttachedAndVisible) {
41
+ this._connected = _connected;
42
+ this.submitFn = submitFn;
43
+ this.dirty = dirty;
44
+ this.addedGCOutboundReference = addedGCOutboundReference;
45
+ this.isAttachedAndVisible = isAttachedAndVisible;
46
+ }
47
+ attach(handler) {
48
+ assert(this._handler === undefined, 0x178 /* "Missing delta handler on attach" */);
49
+ this._handler = handler;
50
+ }
51
+ setConnectionState(connected) {
52
+ this._connected = connected;
53
+ this.handler.setConnectionState(connected);
54
+ }
55
+ process(message, local, localOpMetadata) {
56
+ try {
57
+ // catches as data processing error whether or not they come from async pending queues
58
+ processWithStashedOpMetadataHandling(message.contents, localOpMetadata, (contents, metadata) => this.handler.process({ ...message, contents }, local, metadata));
59
+ }
60
+ catch (error) {
61
+ throw DataProcessingError.wrapIfUnrecognized(error, "channelDeltaConnectionFailedToProcessMessage", message);
62
+ }
63
+ }
64
+ reSubmit(content, localOpMetadata) {
65
+ processWithStashedOpMetadataHandling(content, localOpMetadata, this.handler.reSubmit.bind(this.handler));
66
+ }
67
+ rollback(content, localOpMetadata) {
68
+ if (this.handler.rollback === undefined) {
69
+ throw new Error("Handler doesn't support rollback");
70
+ }
71
+ processWithStashedOpMetadataHandling(content, localOpMetadata, this.handler.rollback.bind(this.handler));
72
+ }
73
+ applyStashedOp(content) {
74
+ try {
75
+ this.stashedOpMd = this.isAttachedAndVisible() ? createStashedOpMetadata() : undefined;
76
+ this.handler.applyStashedOp(content);
77
+ return this.stashedOpMd;
78
+ }
79
+ finally {
80
+ this.stashedOpMd = undefined;
81
+ }
82
+ }
83
+ submit(contents, metadata) {
84
+ if (this.stashedOpMd !== undefined) {
85
+ this.stashedOpMd.push({ contents, metadata });
86
+ }
87
+ else {
88
+ this.submitFn(contents, metadata);
89
+ }
90
+ }
91
+ }
92
+ //# sourceMappingURL=channelDeltaConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelDeltaConnection.js","sourceRoot":"","sources":["../src/channelDeltaConnection.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 { assert } from \"@fluidframework/core-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { IDeltaConnection, IDeltaHandler } from \"@fluidframework/datastore-definitions\";\nimport { DataProcessingError } from \"@fluidframework/telemetry-utils\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\n\nconst stashedOpMetadataMark = Symbol();\n\ntype StashedOpMetadata = { contents: any; metadata: unknown }[] &\n\tRecord<typeof stashedOpMetadataMark, typeof stashedOpMetadataMark>;\n\nfunction createStashedOpMetadata(): StashedOpMetadata {\n\tconst arr = [];\n\tObject.defineProperty(arr, stashedOpMetadataMark, {\n\t\tvalue: stashedOpMetadataMark,\n\t\twritable: false,\n\t\tenumerable: true,\n\t});\n\treturn arr as any as StashedOpMetadata;\n}\n\nfunction isStashedOpMetadata(md: unknown): md is StashedOpMetadata {\n\treturn (\n\t\tArray.isArray(md) &&\n\t\tstashedOpMetadataMark in md &&\n\t\tmd[stashedOpMetadataMark] === stashedOpMetadataMark\n\t);\n}\n\nfunction processWithStashedOpMetadataHandling(\n\tcontent: any,\n\tlocalOpMetaData: unknown,\n\tfunc: (contents: any, metadata: unknown) => void,\n) {\n\tif (isStashedOpMetadata(localOpMetaData)) {\n\t\tlocalOpMetaData.forEach(({ contents, metadata }) => func(contents, metadata));\n\t} else {\n\t\tfunc(content, localOpMetaData);\n\t}\n}\n\nexport class ChannelDeltaConnection implements IDeltaConnection {\n\tprivate _handler: IDeltaHandler | undefined;\n\tprivate stashedOpMd: StashedOpMetadata | undefined;\n\n\tprivate get handler(): IDeltaHandler {\n\t\tassert(!!this._handler, 0x177 /* \"Missing delta handler\" */);\n\t\treturn this._handler;\n\t}\n\tpublic get connected(): boolean {\n\t\treturn this._connected;\n\t}\n\n\tconstructor(\n\t\tprivate _connected: boolean,\n\t\tprivate readonly submitFn: (content: any, localOpMetadata: unknown) => void,\n\t\tpublic readonly dirty: () => void,\n\t\t/** @deprecated There is no replacement for this, its functionality is no longer needed at this layer. */\n\t\tpublic readonly addedGCOutboundReference: (\n\t\t\tsrcHandle: IFluidHandle,\n\t\t\toutboundHandle: IFluidHandle,\n\t\t) => void,\n\t\tprivate readonly isAttachedAndVisible: () => boolean,\n\t) {}\n\n\tpublic attach(handler: IDeltaHandler) {\n\t\tassert(this._handler === undefined, 0x178 /* \"Missing delta handler on attach\" */);\n\t\tthis._handler = handler;\n\t}\n\n\tpublic setConnectionState(connected: boolean) {\n\t\tthis._connected = connected;\n\t\tthis.handler.setConnectionState(connected);\n\t}\n\n\tpublic process(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown) {\n\t\ttry {\n\t\t\t// catches as data processing error whether or not they come from async pending queues\n\t\t\tprocessWithStashedOpMetadataHandling(\n\t\t\t\tmessage.contents,\n\t\t\t\tlocalOpMetadata,\n\t\t\t\t(contents, metadata) =>\n\t\t\t\t\tthis.handler.process({ ...message, contents }, local, metadata),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow DataProcessingError.wrapIfUnrecognized(\n\t\t\t\terror,\n\t\t\t\t\"channelDeltaConnectionFailedToProcessMessage\",\n\t\t\t\tmessage,\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic reSubmit(content: any, localOpMetadata: unknown) {\n\t\tprocessWithStashedOpMetadataHandling(\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\tthis.handler.reSubmit.bind(this.handler),\n\t\t);\n\t}\n\n\tpublic rollback(content: any, localOpMetadata: unknown) {\n\t\tif (this.handler.rollback === undefined) {\n\t\t\tthrow new Error(\"Handler doesn't support rollback\");\n\t\t}\n\t\tprocessWithStashedOpMetadataHandling(\n\t\t\tcontent,\n\t\t\tlocalOpMetadata,\n\t\t\tthis.handler.rollback.bind(this.handler),\n\t\t);\n\t}\n\n\tpublic applyStashedOp(content: any): unknown {\n\t\ttry {\n\t\t\tthis.stashedOpMd = this.isAttachedAndVisible() ? createStashedOpMetadata() : undefined;\n\t\t\tthis.handler.applyStashedOp(content);\n\t\t\treturn this.stashedOpMd;\n\t\t} finally {\n\t\t\tthis.stashedOpMd = undefined;\n\t\t}\n\t}\n\n\tpublic submit(contents: any, metadata: unknown): void {\n\t\tif (this.stashedOpMd !== undefined) {\n\t\t\tthis.stashedOpMd.push({ contents, metadata });\n\t\t} else {\n\t\t\tthis.submitFn(contents, metadata);\n\t\t}\n\t}\n}\n"]}
@@ -19,4 +19,4 @@ export declare class ChannelStorageService implements IChannelStorageService {
19
19
  list(path: string): Promise<string[]>;
20
20
  private getIdForPath;
21
21
  }
22
- //# sourceMappingURL=channelStorageService.d.mts.map
22
+ //# sourceMappingURL=channelStorageService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelStorageService.d.ts","sourceRoot":"","sources":["../src/channelStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEtE,qBAAa,qBAAsB,YAAW,sBAAsB;IAoBlE,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAtB7B,OAAO,CAAC,MAAM,CAAC,WAAW;IAgB1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;gBAGzC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,EAClD,MAAM,EAAE,mBAAmB,EAC3B,UAAU,CAAC,0CAA8B;IAS9C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAehD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAepC,YAAY;CAG1B"}
@@ -55,4 +55,4 @@ export class ChannelStorageService {
55
55
  return this.flattenedTree[path];
56
56
  }
57
57
  }
58
- //# sourceMappingURL=channelStorageService.mjs.map
58
+ //# sourceMappingURL=channelStorageService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channelStorageService.js","sourceRoot":"","sources":["../src/channelStorageService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,mCAAmC,EAAE,MAAM,+BAA+B,CAAC;AAGpF,MAAM,OAAO,qBAAqB;IACzB,MAAM,CAAC,WAAW,CACzB,IAAY,EACZ,IAAmB,EACnB,OAAmC;QAEnC,8DAA8D;QAC9D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;YAC9B,qBAAqB,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;SAChF;QAED,8DAA8D;QAC9D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;YAC9B,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAC7C;IACF,CAAC;IAID,YACkB,IAA+B,EAC/B,OAAkD,EAClD,MAA2B,EAC3B,UAAyC;QAHzC,SAAI,GAAJ,IAAI,CAA2B;QAC/B,YAAO,GAAP,OAAO,CAA2C;QAClD,WAAM,GAAN,MAAM,CAAqB;QAC3B,eAAU,GAAV,UAAU,CAA+B;QAE1D,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,mCAAmC;QACnC,IAAI,IAAI,KAAK,SAAS,EAAE;YACvB,qBAAqB,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;SAChE;IACF,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,IAAY;QACjC,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC;IAC/C,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,IAAY;QACjC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjF,IAAI,IAAI,KAAK,SAAS,EAAE;YACvB,OAAO,IAAI,CAAC;SACZ;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CACrB,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,yBAAyB,EAAE,EAAE,KAAK,CAAC,CAC3E,CAAC;QAEF,OAAO,KAAK,CAAC;IACd,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAY;QAC7B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,MAAM,SAAS,GAAG,mCAAmC,CAAC,IAAI,CAAC,CAAC;QAC5D,OAAO,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;YAClD,oEAAoE;YACpE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAG,CAAC;YAChC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SACxB;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;YACjD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;SACvC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,IAAY;QACtC,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport { ISnapshotTree } from \"@fluidframework/protocol-definitions\";\nimport { IChannelStorageService } from \"@fluidframework/datastore-definitions\";\nimport { getNormalizedObjectStoragePathParts } from \"@fluidframework/runtime-utils\";\nimport { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils\";\n\nexport class ChannelStorageService implements IChannelStorageService {\n\tprivate static flattenTree(\n\t\tbase: string,\n\t\ttree: ISnapshotTree,\n\t\tresults: { [path: string]: string },\n\t) {\n\t\t// eslint-disable-next-line guard-for-in, no-restricted-syntax\n\t\tfor (const path in tree.trees) {\n\t\t\tChannelStorageService.flattenTree(`${base}${path}/`, tree.trees[path], results);\n\t\t}\n\n\t\t// eslint-disable-next-line guard-for-in, no-restricted-syntax\n\t\tfor (const blob in tree.blobs) {\n\t\t\tresults[`${base}${blob}`] = tree.blobs[blob];\n\t\t}\n\t}\n\n\tprivate readonly flattenedTree: { [path: string]: string };\n\n\tconstructor(\n\t\tprivate readonly tree: ISnapshotTree | undefined,\n\t\tprivate readonly storage: Pick<IDocumentStorageService, \"readBlob\">,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly extraBlobs?: Map<string, ArrayBufferLike>,\n\t) {\n\t\tthis.flattenedTree = {};\n\t\t// Create a map from paths to blobs\n\t\tif (tree !== undefined) {\n\t\t\tChannelStorageService.flattenTree(\"\", tree, this.flattenedTree);\n\t\t}\n\t}\n\n\tpublic async contains(path: string): Promise<boolean> {\n\t\treturn this.flattenedTree[path] !== undefined;\n\t}\n\n\tpublic async readBlob(path: string): Promise<ArrayBufferLike> {\n\t\tconst id = await this.getIdForPath(path);\n\t\tconst blob = this.extraBlobs !== undefined ? this.extraBlobs.get(id) : undefined;\n\n\t\tif (blob !== undefined) {\n\t\t\treturn blob;\n\t\t}\n\t\tconst blobP = this.storage.readBlob(id);\n\t\tblobP.catch((error) =>\n\t\t\tthis.logger.sendErrorEvent({ eventName: \"ChannelStorageBlobError\" }, error),\n\t\t);\n\n\t\treturn blobP;\n\t}\n\n\tpublic async list(path: string): Promise<string[]> {\n\t\tlet tree = this.tree;\n\t\tconst pathParts = getNormalizedObjectStoragePathParts(path);\n\t\twhile (tree !== undefined && pathParts.length > 0) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst part = pathParts.shift()!;\n\t\t\ttree = tree.trees[part];\n\t\t}\n\t\tif (tree === undefined || pathParts.length !== 0) {\n\t\t\tthrow new Error(\"path does not exist\");\n\t\t}\n\n\t\treturn Object.keys(tree?.blobs ?? {});\n\t}\n\n\tprivate async getIdForPath(path: string): Promise<string> {\n\t\treturn this.flattenedTree[path];\n\t}\n}\n"]}
@@ -5,10 +5,11 @@
5
5
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
6
6
  import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
7
7
  import { FluidObject, IFluidHandle, IFluidHandleContext, IRequest, IResponse } from "@fluidframework/core-interfaces";
8
- import { IAudience, IDeltaManager, AttachState, ILoaderOptions } from "@fluidframework/container-definitions";
8
+ import { IAudience, IDeltaManager, AttachState } from "@fluidframework/container-definitions";
9
9
  import { IClientDetails, IDocumentMessage, ISequencedDocumentMessage, IQuorumClients } from "@fluidframework/protocol-definitions";
10
- import { IFluidDataStoreContext, IFluidDataStoreChannel, IGarbageCollectionData, IInboundSignalMessage, ISummaryTreeWithStats, VisibilityState, ITelemetryContext, IIdCompressor } from "@fluidframework/runtime-definitions";
10
+ import { IFluidDataStoreContext, IFluidDataStoreChannel, IGarbageCollectionData, IInboundSignalMessage, ISummaryTreeWithStats, VisibilityState, ITelemetryContext } from "@fluidframework/runtime-definitions";
11
11
  import { IChannel, IFluidDataStoreRuntime, IFluidDataStoreRuntimeEvents, IChannelFactory } from "@fluidframework/datastore-definitions";
12
+ import { IIdCompressor } from "@fluidframework/id-compressor";
12
13
  /**
13
14
  * @alpha
14
15
  */
@@ -56,7 +57,7 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
56
57
  visibilityState: VisibilityState;
57
58
  private readonly pendingHandlesToMakeVisible;
58
59
  readonly id: string;
59
- readonly options: ILoaderOptions;
60
+ readonly options: Record<string | number, any>;
60
61
  readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>;
61
62
  private readonly quorum;
62
63
  private readonly audience;
@@ -93,6 +94,13 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
93
94
  resolveHandle(request: IRequest): Promise<IResponse>;
94
95
  request(request: IRequest): Promise<IResponse>;
95
96
  getChannel(id: string): Promise<IChannel>;
97
+ /**
98
+ * Validate user provided channel ID
99
+ * Channel ID has limitations. "/" is not allowed as IDs in storage can not have slashes - we parse tree paths and use "/" as separator.
100
+ * IDs cannot start with "_" as it could result in collision of IDs with auto-assigned (by FF) short IDs.
101
+ * @param id - channel ID.
102
+ */
103
+ protected validateChannelId(id: string): void;
96
104
  /**
97
105
  * Api which allows caller to create the channel first and then add it to the runtime.
98
106
  * The channel type should be present in the registry, otherwise the runtime would reject
@@ -101,7 +109,7 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
101
109
  * @param channel - channel which needs to be added to the runtime.
102
110
  */
103
111
  addChannel(channel: IChannel): void;
104
- createChannel(id: string | undefined, type: string): IChannel;
112
+ createChannel(idArg: string | undefined, type: string): IChannel;
105
113
  private createChannelContext;
106
114
  /**
107
115
  * Binds a channel with the runtime. If the runtime is attached we will attach the channel right away.
@@ -184,6 +192,15 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
184
192
  */
185
193
  summarize(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): Promise<ISummaryTreeWithStats>;
186
194
  getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
195
+ /**
196
+ * Get the GC Data for the initial state being attached so remote clients can learn of this DataStore's outbound routes
197
+ */
198
+ getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData;
199
+ /**
200
+ * Helper method for preparing to attach this dataStore.
201
+ * Runs the callback for each bound context to incorporate its data however the caller specifies
202
+ */
203
+ private visitLocalBoundContextsDuringAttach;
187
204
  submitMessage(type: DataStoreMessageType, content: any, localOpMetadata: unknown): void;
188
205
  /**
189
206
  * Submits the signal to be sent to other clients.
@@ -197,9 +214,10 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
197
214
  */
198
215
  waitAttached(): Promise<void>;
199
216
  /**
200
- * Attach channel should only be called after the data store has been attached
217
+ * Assuming this DataStore is already attached, this will make the given channel locally visible
218
+ * by submitting its attach op.
201
219
  */
202
- private attachChannel;
220
+ private makeChannelLocallyVisible;
203
221
  private submitChannelOp;
204
222
  private submit;
205
223
  /**
@@ -227,6 +245,7 @@ export declare class FluidDataStoreRuntime extends TypedEventEmitter<IFluidDataS
227
245
  * other clients that are up-to-date till seq# 100 may not have them yet.
228
246
  */
229
247
  private identifyLocalChangeInSummarizer;
248
+ setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void;
230
249
  }
231
250
  /**
232
251
  * Mixin class that adds request handler to FluidDataStoreRuntime
@@ -247,4 +266,4 @@ export declare const mixinSummaryHandler: (handler: (runtime: FluidDataStoreRunt
247
266
  path: string[];
248
267
  content: string;
249
268
  } | undefined>, Base?: typeof FluidDataStoreRuntime) => typeof FluidDataStoreRuntime;
250
- //# sourceMappingURL=dataStoreRuntime.d.mts.map
269
+ //# sourceMappingURL=dataStoreRuntime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataStoreRuntime.d.ts","sourceRoot":"","sources":["../src/dataStoreRuntime.ts"],"names":[],"mappings":"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"}
@@ -5,16 +5,16 @@
5
5
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
6
6
  import { DataProcessingError, generateStack, LoggingError, raiseConnectedEvent, createChildMonitoringContext, tagCodeArtifacts, UsageError, } from "@fluidframework/telemetry-utils";
7
7
  import { assert, Deferred, LazyPromise, unreachableCase } from "@fluidframework/core-utils";
8
- import { AttachState, } from "@fluidframework/container-definitions";
8
+ import { AttachState } from "@fluidframework/container-definitions";
9
9
  import { buildSnapshotTree } from "@fluidframework/driver-utils";
10
10
  import { SummaryType, } from "@fluidframework/protocol-definitions";
11
- import { CreateSummarizerNodeSource, VisibilityState, } from "@fluidframework/runtime-definitions";
12
- import { convertSnapshotTreeToSummaryTree, convertSummaryTreeToITree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, create404Response, createResponseError, exceptionToResponse, GCDataBuilder, unpackChildNodesUsedRoutes, } from "@fluidframework/runtime-utils";
11
+ import { CreateSummarizerNodeSource, VisibilityState, gcDataBlobKey, } from "@fluidframework/runtime-definitions";
12
+ import { convertSnapshotTreeToSummaryTree, convertSummaryTreeToITree, generateHandleContextPath, RequestParser, SummaryTreeBuilder, create404Response, createResponseError, exceptionToResponse, GCDataBuilder, unpackChildNodesUsedRoutes, addBlobToSummary, processAttachMessageGCData, encodeCompactIdToString, } from "@fluidframework/runtime-utils";
13
13
  import { v4 as uuid } from "uuid";
14
- import { summarizeChannel } from "./channelContext.mjs";
15
- import { LocalChannelContext, LocalChannelContextBase, RehydratedLocalChannelContext, } from "./localChannelContext.mjs";
16
- import { RemoteChannelContext } from "./remoteChannelContext.mjs";
17
- import { FluidObjectHandle } from "./fluidHandle.mjs";
14
+ import { summarizeChannel } from "./channelContext.js";
15
+ import { LocalChannelContext, LocalChannelContextBase, RehydratedLocalChannelContext, } from "./localChannelContext.js";
16
+ import { RemoteChannelContext } from "./remoteChannelContext.js";
17
+ import { FluidObjectHandle } from "./fluidHandle.js";
18
18
  /**
19
19
  * @alpha
20
20
  */
@@ -230,6 +230,20 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
230
230
  }
231
231
  return context.getChannel();
232
232
  }
233
+ /**
234
+ * Validate user provided channel ID
235
+ * Channel ID has limitations. "/" is not allowed as IDs in storage can not have slashes - we parse tree paths and use "/" as separator.
236
+ * IDs cannot start with "_" as it could result in collision of IDs with auto-assigned (by FF) short IDs.
237
+ * @param id - channel ID.
238
+ */
239
+ validateChannelId(id) {
240
+ if (id.includes("/")) {
241
+ throw new UsageError(`Id cannot contain slashes: ${id}`);
242
+ }
243
+ if (id.startsWith("_")) {
244
+ throw new UsageError(`Id cannot start with underscore: ${id}`);
245
+ }
246
+ }
233
247
  /**
234
248
  * Api which allows caller to create the channel first and then add it to the runtime.
235
249
  * The channel type should be present in the registry, otherwise the runtime would reject
@@ -239,9 +253,7 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
239
253
  */
240
254
  addChannel(channel) {
241
255
  const id = channel.id;
242
- if (id.includes("/")) {
243
- throw new UsageError(`Id cannot contain slashes: ${id}`);
244
- }
256
+ this.validateChannelId(id);
245
257
  this.verifyNotClosed();
246
258
  assert(!this.contexts.has(id), 0x865 /* addChannel() with existing ID */);
247
259
  const type = channel.attributes.type;
@@ -253,9 +265,30 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
253
265
  // Channels (DDS) should not be created in summarizer client.
254
266
  this.identifyLocalChangeInSummarizer("DDSCreatedInSummarizer", id, type);
255
267
  }
256
- createChannel(id = uuid(), type) {
257
- if (id.includes("/")) {
258
- throw new UsageError(`Id cannot contain slashes: ${id}`);
268
+ createChannel(idArg, type) {
269
+ let id;
270
+ if (idArg !== undefined) {
271
+ id = idArg;
272
+ this.validateChannelId(id);
273
+ }
274
+ else {
275
+ // We use three non-overlapping namespaces:
276
+ // - detached state: even numbers
277
+ // - attached state: odd numbers
278
+ // - uuids
279
+ // In first two cases we will encode result as strings in more compact form, with leading underscore,
280
+ // to ensure no overlap with user-provided DDS names (see validateChannelId())
281
+ if (this.visibilityState !== VisibilityState.GloballyVisible) {
282
+ // container is detached, only one client observes content, no way to hit collisions with other clients.
283
+ id = encodeCompactIdToString(2 * this.contexts.size, "_");
284
+ }
285
+ else {
286
+ // Due to back-compat, we could not depend yet on generateDocumentUniqueId() being there.
287
+ // We can remove the need to leverage uuid() as fall-back in couple releases.
288
+ const res = this.dataStoreContext.containerRuntime.generateDocumentUniqueId?.() ?? uuid();
289
+ id = typeof res === "number" ? encodeCompactIdToString(2 * res + 1, "_") : res;
290
+ }
291
+ assert(!id.includes("/"), 0x8fc /* slash */);
259
292
  }
260
293
  this.verifyNotClosed();
261
294
  assert(!this.contexts.has(id), 0x179 /* "createChannel() with existing ID" */);
@@ -285,7 +318,7 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
285
318
  this.notBoundedChannelContextSet.delete(channel.id);
286
319
  // If our data store is attached, then attach the channel.
287
320
  if (this.isAttached) {
288
- this.attachChannel(channel);
321
+ this.makeChannelLocallyVisible(channel);
289
322
  return;
290
323
  }
291
324
  /**
@@ -367,6 +400,12 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
367
400
  case DataStoreMessageType.Attach: {
368
401
  const attachMessage = message.contents;
369
402
  const id = attachMessage.id;
403
+ // We need to process the GC Data for both local and remote attach messages
404
+ processAttachMessageGCData(attachMessage.snapshot, (nodeId, toPath) => {
405
+ // Note: nodeId will be "/" unless and until we support sub-DDS GC Nodes
406
+ const fromPath = `/${this.id}/${id}${nodeId === "/" ? "" : nodeId}`;
407
+ this.dataStoreContext.addedGCOutboundRoute?.(fromPath, toPath);
408
+ });
370
409
  // If a non-local operation then go and create the object
371
410
  // Otherwise mark it as officially attached.
372
411
  if (local) {
@@ -523,6 +562,45 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
523
562
  return summaryBuilder.getSummaryTree();
524
563
  }
525
564
  getAttachSummary(telemetryContext) {
565
+ const summaryBuilder = new SummaryTreeBuilder();
566
+ this.visitLocalBoundContextsDuringAttach((contextId, context) => {
567
+ let summaryTree;
568
+ if (context.isLoaded) {
569
+ const contextSummary = context.getAttachSummary(telemetryContext);
570
+ assert(contextSummary.summary.type === SummaryType.Tree, 0x180 /* "getAttachSummary should always return a tree" */);
571
+ summaryTree = { stats: contextSummary.stats, summary: contextSummary.summary };
572
+ }
573
+ else {
574
+ // If this channel is not yet loaded, then there should be no changes in the snapshot from which
575
+ // it was created as it is detached container. So just use the previous snapshot.
576
+ assert(!!this.dataStoreContext.baseSnapshot, 0x181 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
577
+ summaryTree = convertSnapshotTreeToSummaryTree(this.dataStoreContext.baseSnapshot.trees[contextId]);
578
+ }
579
+ summaryBuilder.addWithStats(contextId, summaryTree);
580
+ });
581
+ return summaryBuilder.getSummaryTree();
582
+ }
583
+ /**
584
+ * Get the GC Data for the initial state being attached so remote clients can learn of this DataStore's outbound routes
585
+ */
586
+ getAttachGCData(telemetryContext) {
587
+ const gcDataBuilder = new GCDataBuilder();
588
+ this.visitLocalBoundContextsDuringAttach((contextId, context) => {
589
+ if (context.isLoaded) {
590
+ const contextGCData = context.getAttachGCData(telemetryContext);
591
+ // Incorporate the GC Data for this context
592
+ gcDataBuilder.prefixAndAddNodes(contextId, contextGCData.gcNodes);
593
+ }
594
+ // else: Rehydrating detached container case. GC doesn't run until the container is attached, so nothing to do here.
595
+ });
596
+ this.updateGCNodes(gcDataBuilder);
597
+ return gcDataBuilder.getGCData();
598
+ }
599
+ /**
600
+ * Helper method for preparing to attach this dataStore.
601
+ * Runs the callback for each bound context to incorporate its data however the caller specifies
602
+ */
603
+ visitLocalBoundContextsDuringAttach(visitor) {
526
604
  /**
527
605
  * back-compat 0.59.1000 - getAttachSummary() is called when making a data store globally visible (previously
528
606
  * attaching state). Ideally, attachGraph() should have already be called making it locally visible. However,
@@ -541,29 +619,14 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
541
619
  // assert(this.visibilityState === VisibilityState.LocallyVisible,
542
620
  // "The data store should be locally visible when generating attach summary",
543
621
  // );
544
- const summaryBuilder = new SummaryTreeBuilder();
545
- // Craft the .attributes file for each shared object
546
622
  for (const [contextId, context] of this.contexts) {
547
623
  if (!(context instanceof LocalChannelContextBase)) {
548
624
  throw new LoggingError("Should only be called with local channel handles");
549
625
  }
550
626
  if (!this.notBoundedChannelContextSet.has(contextId)) {
551
- let summaryTree;
552
- if (context.isLoaded) {
553
- const contextSummary = context.getAttachSummary(telemetryContext);
554
- assert(contextSummary.summary.type === SummaryType.Tree, 0x180 /* "getAttachSummary should always return a tree" */);
555
- summaryTree = { stats: contextSummary.stats, summary: contextSummary.summary };
556
- }
557
- else {
558
- // If this channel is not yet loaded, then there should be no changes in the snapshot from which
559
- // it was created as it is detached container. So just use the previous snapshot.
560
- assert(!!this.dataStoreContext.baseSnapshot, 0x181 /* "BaseSnapshot should be there as detached container loaded from snapshot" */);
561
- summaryTree = convertSnapshotTreeToSummaryTree(this.dataStoreContext.baseSnapshot.trees[contextId]);
562
- }
563
- summaryBuilder.addWithStats(contextId, summaryTree);
627
+ visitor(contextId, context);
564
628
  }
565
629
  }
566
- return summaryBuilder.getSummaryTree();
567
630
  }
568
631
  submitMessage(type, content, localOpMetadata) {
569
632
  this.submit(type, content, localOpMetadata);
@@ -585,9 +648,10 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
585
648
  return this.deferredAttached.promise;
586
649
  }
587
650
  /**
588
- * Attach channel should only be called after the data store has been attached
651
+ * Assuming this DataStore is already attached, this will make the given channel locally visible
652
+ * by submitting its attach op.
589
653
  */
590
- attachChannel(channel) {
654
+ makeChannelLocallyVisible(channel) {
591
655
  this.verifyNotClosed();
592
656
  // If this handle is already attached no need to attach again.
593
657
  if (channel.handle.isAttached) {
@@ -597,6 +661,9 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
597
661
  assert(this.isAttached, 0x182 /* "Data store should be attached to attach the channel." */);
598
662
  assert(this.visibilityState === VisibilityState.GloballyVisible, 0x2d0 /* "Data store should be globally visible to attach channels." */);
599
663
  const summarizeResult = summarizeChannel(channel, true /* fullTree */, false /* trackState */);
664
+ // We need to include the channel's GC Data so remote clients can learn of this channel's outbound routes
665
+ const gcData = channel.getGCData(/* fullGC: */ true);
666
+ addBlobToSummary(summarizeResult, gcDataBlobKey, JSON.stringify(gcData));
600
667
  // Attach message needs the summary in ITree format. Convert the ISummaryTree into an ITree.
601
668
  const snapshot = convertSummaryTreeToITree(summarizeResult.summary);
602
669
  const message = {
@@ -706,33 +773,15 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
706
773
  }
707
774
  attachListener() {
708
775
  this.setMaxListeners(Number.MAX_SAFE_INTEGER);
709
- this.dataStoreContext.once("attaching", () => {
710
- /**
711
- * back-compat 0.59.1000 - Ideally, attachGraph() should have already been called making the data store
712
- * locally visible. However, before visibility state was added, this may not have been the case and data
713
- * store can move to "attaching" state in 2 scenarios:
714
- * 1) Before attachGraph() is called - When a data store is created and bound in an attached container.
715
- * 2) After attachGraph() is called - When a detached container is attached.
716
- *
717
- * The basic idea is that all local object should become locally visible before they are globally visible.
718
- */
719
- this.attachGraph();
720
- this._attachState = AttachState.Attaching;
721
- assert(this.visibilityState === VisibilityState.LocallyVisible, 0x2d1 /* "Data store should be locally visible before it can become globally visible." */);
722
- // Mark the data store globally visible and make its child channels visible as well.
723
- this.visibilityState = VisibilityState.GloballyVisible;
724
- this.localChannelContextQueue.forEach((channel) => {
725
- channel.makeVisible();
726
- });
727
- this.localChannelContextQueue.clear();
728
- // This promise resolution will be moved to attached event once we fix the scheduler.
729
- this.deferredAttached.resolve();
730
- this.emit("attaching");
776
+ // back-compat, to be removed in the future.
777
+ // Added in "2.0.0-rc.2.0.0" timeframe.
778
+ this.dataStoreContext.once?.("attaching", () => {
779
+ this.setAttachState(AttachState.Attaching);
731
780
  });
732
- this.dataStoreContext.once("attached", () => {
733
- assert(this.visibilityState === VisibilityState.GloballyVisible, 0x2d2 /* "Data store should be globally visible when its attached." */);
734
- this._attachState = AttachState.Attached;
735
- this.emit("attached");
781
+ // back-compat, to be removed in the future.
782
+ // Added in "2.0.0-rc.2.0.0" timeframe.
783
+ this.dataStoreContext.once?.("attached", () => {
784
+ this.setAttachState(AttachState.Attached);
736
785
  });
737
786
  }
738
787
  verifyNotClosed() {
@@ -764,6 +813,40 @@ export class FluidDataStoreRuntime extends TypedEventEmitter {
764
813
  });
765
814
  this.localChangesTelemetryCount--;
766
815
  }
816
+ setAttachState(attachState) {
817
+ switch (attachState) {
818
+ case AttachState.Attaching:
819
+ /**
820
+ * back-compat 0.59.1000 - Ideally, attachGraph() should have already been called making the data store
821
+ * locally visible. However, before visibility state was added, this may not have been the case and data
822
+ * store can move to "attaching" state in 2 scenarios:
823
+ * 1) Before attachGraph() is called - When a data store is created and bound in an attached container.
824
+ * 2) After attachGraph() is called - When a detached container is attached.
825
+ *
826
+ * The basic idea is that all local object should become locally visible before they are globally visible.
827
+ */
828
+ this.attachGraph();
829
+ this._attachState = AttachState.Attaching;
830
+ assert(this.visibilityState === VisibilityState.LocallyVisible, 0x2d1 /* "Data store should be locally visible before it can become globally visible." */);
831
+ // Mark the data store globally visible and make its child channels visible as well.
832
+ this.visibilityState = VisibilityState.GloballyVisible;
833
+ this.localChannelContextQueue.forEach((channel) => {
834
+ channel.makeVisible();
835
+ });
836
+ this.localChannelContextQueue.clear();
837
+ // This promise resolution will be moved to attached event once we fix the scheduler.
838
+ this.deferredAttached.resolve();
839
+ this.emit("attaching");
840
+ break;
841
+ case AttachState.Attached:
842
+ assert(this.visibilityState === VisibilityState.GloballyVisible, 0x2d2 /* "Data store should be globally visible when its attached." */);
843
+ this._attachState = AttachState.Attached;
844
+ this.emit("attached");
845
+ break;
846
+ default:
847
+ unreachableCase(attachState, "unreached");
848
+ }
849
+ }
767
850
  }
768
851
  /**
769
852
  * Mixin class that adds request handler to FluidDataStoreRuntime
@@ -824,4 +907,4 @@ export const mixinSummaryHandler = (handler, Base = FluidDataStoreRuntime) => cl
824
907
  return summary;
825
908
  }
826
909
  };
827
- //# sourceMappingURL=dataStoreRuntime.mjs.map
910
+ //# sourceMappingURL=dataStoreRuntime.js.map