@fluidframework/container-loader 2.0.0-internal.5.2.0 → 2.0.0-internal.5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/connectionManager.d.ts +1 -1
  3. package/dist/connectionManager.d.ts.map +1 -1
  4. package/dist/connectionManager.js.map +1 -1
  5. package/dist/connectionStateHandler.d.ts +1 -1
  6. package/dist/connectionStateHandler.d.ts.map +1 -1
  7. package/dist/connectionStateHandler.js.map +1 -1
  8. package/dist/container.d.ts +10 -4
  9. package/dist/container.d.ts.map +1 -1
  10. package/dist/container.js +22 -9
  11. package/dist/container.js.map +1 -1
  12. package/dist/containerContext.d.ts +5 -12
  13. package/dist/containerContext.d.ts.map +1 -1
  14. package/dist/containerContext.js +4 -16
  15. package/dist/containerContext.js.map +1 -1
  16. package/dist/containerStorageAdapter.d.ts.map +1 -1
  17. package/dist/containerStorageAdapter.js +38 -6
  18. package/dist/containerStorageAdapter.js.map +1 -1
  19. package/dist/contracts.d.ts +1 -3
  20. package/dist/contracts.d.ts.map +1 -1
  21. package/dist/contracts.js.map +1 -1
  22. package/dist/deltaManager.d.ts +2 -1
  23. package/dist/deltaManager.d.ts.map +1 -1
  24. package/dist/deltaManager.js.map +1 -1
  25. package/dist/disposal.d.ts +13 -0
  26. package/dist/disposal.d.ts.map +1 -0
  27. package/dist/disposal.js +25 -0
  28. package/dist/disposal.js.map +1 -0
  29. package/dist/loader.d.ts +1 -2
  30. package/dist/loader.d.ts.map +1 -1
  31. package/dist/loader.js.map +1 -1
  32. package/dist/packageVersion.d.ts +1 -1
  33. package/dist/packageVersion.js +1 -1
  34. package/dist/packageVersion.js.map +1 -1
  35. package/dist/protocol.d.ts +6 -0
  36. package/dist/protocol.d.ts.map +1 -1
  37. package/dist/protocol.js +17 -1
  38. package/dist/protocol.js.map +1 -1
  39. package/dist/quorum.d.ts +1 -17
  40. package/dist/quorum.d.ts.map +1 -1
  41. package/dist/quorum.js +1 -17
  42. package/dist/quorum.js.map +1 -1
  43. package/lib/connectionManager.d.ts +1 -1
  44. package/lib/connectionManager.d.ts.map +1 -1
  45. package/lib/connectionManager.js.map +1 -1
  46. package/lib/connectionStateHandler.d.ts +1 -1
  47. package/lib/connectionStateHandler.d.ts.map +1 -1
  48. package/lib/connectionStateHandler.js.map +1 -1
  49. package/lib/container.d.ts +10 -4
  50. package/lib/container.d.ts.map +1 -1
  51. package/lib/container.js +24 -11
  52. package/lib/container.js.map +1 -1
  53. package/lib/containerContext.d.ts +5 -12
  54. package/lib/containerContext.d.ts.map +1 -1
  55. package/lib/containerContext.js +4 -16
  56. package/lib/containerContext.js.map +1 -1
  57. package/lib/containerStorageAdapter.d.ts.map +1 -1
  58. package/lib/containerStorageAdapter.js +38 -6
  59. package/lib/containerStorageAdapter.js.map +1 -1
  60. package/lib/contracts.d.ts +1 -3
  61. package/lib/contracts.d.ts.map +1 -1
  62. package/lib/contracts.js.map +1 -1
  63. package/lib/deltaManager.d.ts +2 -1
  64. package/lib/deltaManager.d.ts.map +1 -1
  65. package/lib/deltaManager.js.map +1 -1
  66. package/lib/disposal.d.ts +13 -0
  67. package/lib/disposal.d.ts.map +1 -0
  68. package/lib/disposal.js +21 -0
  69. package/lib/disposal.js.map +1 -0
  70. package/lib/loader.d.ts +1 -2
  71. package/lib/loader.d.ts.map +1 -1
  72. package/lib/loader.js.map +1 -1
  73. package/lib/packageVersion.d.ts +1 -1
  74. package/lib/packageVersion.js +1 -1
  75. package/lib/packageVersion.js.map +1 -1
  76. package/lib/protocol.d.ts +6 -0
  77. package/lib/protocol.d.ts.map +1 -1
  78. package/lib/protocol.js +15 -0
  79. package/lib/protocol.js.map +1 -1
  80. package/lib/quorum.d.ts +1 -17
  81. package/lib/quorum.d.ts.map +1 -1
  82. package/lib/quorum.js +1 -16
  83. package/lib/quorum.js.map +1 -1
  84. package/package.json +18 -14
  85. package/src/connectionManager.ts +1 -2
  86. package/src/connectionStateHandler.ts +1 -1
  87. package/src/container.ts +49 -25
  88. package/src/containerContext.ts +2 -18
  89. package/src/containerStorageAdapter.ts +46 -4
  90. package/src/contracts.ts +1 -3
  91. package/src/deltaManager.ts +15 -8
  92. package/src/disposal.ts +25 -0
  93. package/src/loader.ts +1 -1
  94. package/src/packageVersion.ts +1 -1
  95. package/src/protocol.ts +18 -0
  96. package/src/quorum.ts +2 -31
  97. package/dist/deltaManagerProxy.d.ts +0 -42
  98. package/dist/deltaManagerProxy.d.ts.map +0 -1
  99. package/dist/deltaManagerProxy.js +0 -79
  100. package/dist/deltaManagerProxy.js.map +0 -1
  101. package/lib/deltaManagerProxy.d.ts +0 -42
  102. package/lib/deltaManagerProxy.d.ts.map +0 -1
  103. package/lib/deltaManagerProxy.js +0 -74
  104. package/lib/deltaManagerProxy.js.map +0 -1
  105. package/src/deltaManagerProxy.ts +0 -109
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGN,iBAAiB,GACjB,MAAM,+BAA+B,CAAC;AAOvC,8FAA8F;AAC9F,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAU,CAAC;AAE7C,mDAAmD;AACnD,MAAM,CAAN,IAAY,UAIX;AAJD,WAAY,UAAU;IACrB,iCAAmB,CAAA;IACnB,mCAAqB,CAAA;IACrB,6BAAe,CAAA;AAChB,CAAC,EAJW,UAAU,KAAV,UAAU,QAIrB;AAgBD,MAAM,OAAO,eAAgB,SAAQ,iBAAiB;IACrD,YACC,UAA+B,EAC/B,cAA+B,EAC/B,YAAiD,EACxC,QAAwB;QAEjC,KAAK,CACJ,UAAU,CAAC,qBAAqB,EAChC,UAAU,CAAC,cAAc,EACzB,kBAAkB,EAClB,cAAc,CAAC,OAAO,EACtB,cAAc,CAAC,SAAS,EACxB,cAAc,CAAC,MAAM,EACrB,YAAY,CACZ,CAAC;QAVO,aAAQ,GAAR,QAAQ,CAAgB;QAYjC,oFAAoF;QACpF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CACjD,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAC5C,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC9E,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE;YAC3D,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;SAClD;IACF,CAAC;IAEM,aAAa,CAAC,OAAuB;;QAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,OAAyC,CAAC;QACvE,QAAQ,YAAY,CAAC,IAAI,EAAE;YAC1B,KAAK,UAAU,CAAC,KAAK,CAAC,CAAC;gBACtB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC3C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE;oBACzC,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE;wBAC3B,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;qBACrC;iBACD;gBACD,MAAM;aACN;YACD,KAAK,UAAU,CAAC,UAAU,CAAC,CAAC;gBAC3B,MAAM,SAAS,GAAG,YAAY,CAAC,OAAwB,CAAC;gBACxD,2DAA2D;gBAC3D,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE;oBACrC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;iBAC9D;gBACD,MAAM;aACN;YACD,KAAK,UAAU,CAAC,WAAW,CAAC,CAAC;gBAC5B,MAAM,YAAY,GAAG,YAAY,CAAC,OAAiB,CAAC;gBACpD,2DAA2D;gBAC3D,IAAI,CAAA,MAAA,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC,0CAAE,IAAI,MAAK,MAAM,EAAE;oBAC3D,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;iBACzC;gBACD,MAAM;aACN;YACD;gBACC,MAAM;SACP;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IAudienceOwner } from \"@fluidframework/container-definitions\";\nimport {\n\tIProtocolHandler as IBaseProtocolHandler,\n\tIQuorumSnapshot,\n\tProtocolOpHandler,\n} from \"@fluidframework/protocol-base\";\nimport {\n\tIDocumentAttributes,\n\tISignalClient,\n\tISignalMessage,\n} from \"@fluidframework/protocol-definitions\";\n\n// \"term\" was an experimental feature that is being removed. The only safe value to use is 1.\nexport const OnlyValidTermValue = 1 as const;\n\n// ADO: #1986: Start using enum from protocol-base.\nexport enum SignalType {\n\tClientJoin = \"join\", // same value as MessageType.ClientJoin,\n\tClientLeave = \"leave\", // same value as MessageType.ClientLeave,\n\tClear = \"clear\", // used only by client for synthetic signals\n}\n\n/**\n * Function to be used for creating a protocol handler.\n */\nexport type ProtocolHandlerBuilder = (\n\tattributes: IDocumentAttributes,\n\tsnapshot: IQuorumSnapshot,\n\tsendProposal: (key: string, value: any) => number,\n) => IProtocolHandler;\n\nexport interface IProtocolHandler extends IBaseProtocolHandler {\n\treadonly audience: IAudienceOwner;\n\tprocessSignal(message: ISignalMessage);\n}\n\nexport class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandler {\n\tconstructor(\n\t\tattributes: IDocumentAttributes,\n\t\tquorumSnapshot: IQuorumSnapshot,\n\t\tsendProposal: (key: string, value: any) => number,\n\t\treadonly audience: IAudienceOwner,\n\t) {\n\t\tsuper(\n\t\t\tattributes.minimumSequenceNumber,\n\t\t\tattributes.sequenceNumber,\n\t\t\tOnlyValidTermValue,\n\t\t\tquorumSnapshot.members,\n\t\t\tquorumSnapshot.proposals,\n\t\t\tquorumSnapshot.values,\n\t\t\tsendProposal,\n\t\t);\n\n\t\t// Join / leave signals are ignored for \"write\" clients in favor of join / leave ops\n\t\tthis.quorum.on(\"addMember\", (clientId, details) =>\n\t\t\taudience.addMember(clientId, details.client),\n\t\t);\n\t\tthis.quorum.on(\"removeMember\", (clientId) => audience.removeMember(clientId));\n\t\tfor (const [clientId, details] of this.quorum.getMembers()) {\n\t\t\tthis.audience.addMember(clientId, details.client);\n\t\t}\n\t}\n\n\tpublic processSignal(message: ISignalMessage) {\n\t\tconst innerContent = message.content as { content: any; type: string };\n\t\tswitch (innerContent.type) {\n\t\t\tcase SignalType.Clear: {\n\t\t\t\tconst members = this.audience.getMembers();\n\t\t\t\tfor (const [clientId, client] of members) {\n\t\t\t\t\tif (client.mode === \"read\") {\n\t\t\t\t\t\tthis.audience.removeMember(clientId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SignalType.ClientJoin: {\n\t\t\t\tconst newClient = innerContent.content as ISignalClient;\n\t\t\t\t// Ignore write clients - quorum will control such clients.\n\t\t\t\tif (newClient.client.mode === \"read\") {\n\t\t\t\t\tthis.audience.addMember(newClient.clientId, newClient.client);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SignalType.ClientLeave: {\n\t\t\t\tconst leftClientId = innerContent.content as string;\n\t\t\t\t// Ignore write clients - quorum will control such clients.\n\t\t\t\tif (this.audience.getMember(leftClientId)?.mode === \"read\") {\n\t\t\t\t\tthis.audience.removeMember(leftClientId);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.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 { IAudienceOwner } from \"@fluidframework/container-definitions\";\nimport {\n\tIProtocolHandler as IBaseProtocolHandler,\n\tIQuorumSnapshot,\n\tProtocolOpHandler,\n} from \"@fluidframework/protocol-base\";\nimport {\n\tIDocumentAttributes,\n\tISignalClient,\n\tISignalMessage,\n} from \"@fluidframework/protocol-definitions\";\n\n// \"term\" was an experimental feature that is being removed. The only safe value to use is 1.\nexport const OnlyValidTermValue = 1 as const;\n\n// ADO: #1986: Start using enum from protocol-base.\nexport enum SignalType {\n\tClientJoin = \"join\", // same value as MessageType.ClientJoin,\n\tClientLeave = \"leave\", // same value as MessageType.ClientLeave,\n\tClear = \"clear\", // used only by client for synthetic signals\n}\n\n/**\n * Function to be used for creating a protocol handler.\n */\nexport type ProtocolHandlerBuilder = (\n\tattributes: IDocumentAttributes,\n\tsnapshot: IQuorumSnapshot,\n\tsendProposal: (key: string, value: any) => number,\n) => IProtocolHandler;\n\nexport interface IProtocolHandler extends IBaseProtocolHandler {\n\treadonly audience: IAudienceOwner;\n\tprocessSignal(message: ISignalMessage);\n}\n\nexport class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandler {\n\tconstructor(\n\t\tattributes: IDocumentAttributes,\n\t\tquorumSnapshot: IQuorumSnapshot,\n\t\tsendProposal: (key: string, value: any) => number,\n\t\treadonly audience: IAudienceOwner,\n\t) {\n\t\tsuper(\n\t\t\tattributes.minimumSequenceNumber,\n\t\t\tattributes.sequenceNumber,\n\t\t\tOnlyValidTermValue,\n\t\t\tquorumSnapshot.members,\n\t\t\tquorumSnapshot.proposals,\n\t\t\tquorumSnapshot.values,\n\t\t\tsendProposal,\n\t\t);\n\n\t\t// Join / leave signals are ignored for \"write\" clients in favor of join / leave ops\n\t\tthis.quorum.on(\"addMember\", (clientId, details) =>\n\t\t\taudience.addMember(clientId, details.client),\n\t\t);\n\t\tthis.quorum.on(\"removeMember\", (clientId) => audience.removeMember(clientId));\n\t\tfor (const [clientId, details] of this.quorum.getMembers()) {\n\t\t\tthis.audience.addMember(clientId, details.client);\n\t\t}\n\t}\n\n\tpublic processSignal(message: ISignalMessage) {\n\t\tconst innerContent = message.content as { content: any; type: string };\n\t\tswitch (innerContent.type) {\n\t\t\tcase SignalType.Clear: {\n\t\t\t\tconst members = this.audience.getMembers();\n\t\t\t\tfor (const [clientId, client] of members) {\n\t\t\t\t\tif (client.mode === \"read\") {\n\t\t\t\t\t\tthis.audience.removeMember(clientId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SignalType.ClientJoin: {\n\t\t\t\tconst newClient = innerContent.content as ISignalClient;\n\t\t\t\t// Ignore write clients - quorum will control such clients.\n\t\t\t\tif (newClient.client.mode === \"read\") {\n\t\t\t\t\tthis.audience.addMember(newClient.clientId, newClient.client);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SignalType.ClientLeave: {\n\t\t\t\tconst leftClientId = innerContent.content as string;\n\t\t\t\t// Ignore write clients - quorum will control such clients.\n\t\t\t\tif (this.audience.getMember(leftClientId)?.mode === \"read\") {\n\t\t\t\t\tthis.audience.removeMember(leftClientId);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/**\n * Function to check whether the protocol handler should process the Signal.\n * The protocol handler should strictly handle only ClientJoin, ClientLeave\n * and Clear signal types.\n */\nexport function protocolHandlerShouldProcessSignal(message: ISignalMessage) {\n\t// Signal originates from server\n\tif (message.clientId === null) {\n\t\tconst innerContent = message.content as { content: unknown; type: string };\n\t\treturn (\n\t\t\tinnerContent.type === SignalType.Clear ||\n\t\t\tinnerContent.type === SignalType.ClientJoin ||\n\t\t\tinnerContent.type === SignalType.ClientLeave\n\t\t);\n\t}\n\treturn false;\n}\n"]}
package/lib/quorum.d.ts CHANGED
@@ -1,21 +1,5 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { EventForwarder } from "@fluidframework/common-utils";
6
1
  import { IFluidCodeDetails } from "@fluidframework/core-interfaces";
7
- import { ICommittedProposal, IQuorum, IQuorumEvents, ISequencedClient } from "@fluidframework/protocol-definitions";
8
- /**
9
- * Proxies Quorum events.
10
- */
11
- export declare class QuorumProxy extends EventForwarder<IQuorumEvents> implements IQuorum {
12
- readonly propose: (key: string, value: any) => Promise<void>;
13
- readonly has: (key: string) => boolean;
14
- readonly get: (key: string) => any;
15
- readonly getMembers: () => Map<string, ISequencedClient>;
16
- readonly getMember: (clientId: string) => ISequencedClient | undefined;
17
- constructor(quorum: IQuorum);
18
- }
2
+ import { ICommittedProposal } from "@fluidframework/protocol-definitions";
19
3
  export declare function getCodeDetailsFromQuorumValues(quorumValues: [string, ICommittedProposal][]): IFluidCodeDetails;
20
4
  export declare function initQuorumValuesFromCodeDetails(source: IFluidCodeDetails): [string, ICommittedProposal][];
21
5
  //# sourceMappingURL=quorum.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAU,cAAc,EAAmB,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EACN,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,MAAM,sCAAsC,CAAC;AAE9C;;GAEG;AACH,qBAAa,WAAY,SAAQ,cAAc,CAAC,aAAa,CAAE,YAAW,OAAO;IAChF,SAAgB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,SAAgB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,SAAgB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;IAC1C,SAAgB,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAChE,SAAgB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;gBAElE,MAAM,EAAE,OAAO;CAY3B;AAED,wBAAgB,8BAA8B,CAC7C,YAAY,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,GAC1C,iBAAiB,CAKnB;AAED,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,iBAAiB,GACvB,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAUhC"}
1
+ {"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAE1E,wBAAgB,8BAA8B,CAC7C,YAAY,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,GAC1C,iBAAiB,CAKnB;AAED,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,iBAAiB,GACvB,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAUhC"}
package/lib/quorum.js CHANGED
@@ -2,22 +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, EventForwarder, doIfNotDisposed } from "@fluidframework/common-utils";
6
- /**
7
- * Proxies Quorum events.
8
- */
9
- export class QuorumProxy extends EventForwarder {
10
- constructor(quorum) {
11
- super(quorum);
12
- // This is heavily used object, increase limit at which Node prints warnings.
13
- super.setMaxListeners(50);
14
- this.propose = doIfNotDisposed(this, quorum.propose.bind(quorum));
15
- this.has = doIfNotDisposed(this, quorum.has.bind(quorum));
16
- this.get = doIfNotDisposed(this, quorum.get.bind(quorum));
17
- this.getMembers = doIfNotDisposed(this, quorum.getMembers.bind(quorum));
18
- this.getMember = doIfNotDisposed(this, quorum.getMember.bind(quorum));
19
- }
20
- }
5
+ import { assert } from "@fluidframework/common-utils";
21
6
  export function getCodeDetailsFromQuorumValues(quorumValues) {
22
7
  const qValuesMap = new Map(quorumValues);
23
8
  const proposal = qValuesMap.get("code");
package/lib/quorum.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AASvF;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,cAA6B;IAO7D,YAAY,MAAe;QAC1B,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,6EAA6E;QAC7E,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAE1B,IAAI,CAAC,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,CAAC;CACD;AAED,MAAM,UAAU,8BAA8B,CAC7C,YAA4C;IAE5C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACxE,OAAO,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,KAA0B,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC9C,MAAyB;IAEzB,kEAAkE;IAClE,MAAM,qBAAqB,GAAuB;QACjD,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,MAAM;QACb,sBAAsB,EAAE,CAAC;QACzB,oBAAoB,EAAE,CAAC;QACvB,cAAc,EAAE,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { assert, EventForwarder, doIfNotDisposed } from \"@fluidframework/common-utils\";\nimport { IFluidCodeDetails } from \"@fluidframework/core-interfaces\";\nimport {\n\tICommittedProposal,\n\tIQuorum,\n\tIQuorumEvents,\n\tISequencedClient,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Proxies Quorum events.\n */\nexport class QuorumProxy extends EventForwarder<IQuorumEvents> implements IQuorum {\n\tpublic readonly propose: (key: string, value: any) => Promise<void>;\n\tpublic readonly has: (key: string) => boolean;\n\tpublic readonly get: (key: string) => any;\n\tpublic readonly getMembers: () => Map<string, ISequencedClient>;\n\tpublic readonly getMember: (clientId: string) => ISequencedClient | undefined;\n\n\tconstructor(quorum: IQuorum) {\n\t\tsuper(quorum);\n\n\t\t// This is heavily used object, increase limit at which Node prints warnings.\n\t\tsuper.setMaxListeners(50);\n\n\t\tthis.propose = doIfNotDisposed(this, quorum.propose.bind(quorum));\n\t\tthis.has = doIfNotDisposed(this, quorum.has.bind(quorum));\n\t\tthis.get = doIfNotDisposed(this, quorum.get.bind(quorum));\n\t\tthis.getMembers = doIfNotDisposed(this, quorum.getMembers.bind(quorum));\n\t\tthis.getMember = doIfNotDisposed(this, quorum.getMember.bind(quorum));\n\t}\n}\n\nexport function getCodeDetailsFromQuorumValues(\n\tquorumValues: [string, ICommittedProposal][],\n): IFluidCodeDetails {\n\tconst qValuesMap = new Map(quorumValues);\n\tconst proposal = qValuesMap.get(\"code\");\n\tassert(proposal !== undefined, 0x2dc /* \"Cannot find code proposal\" */);\n\treturn proposal?.value as IFluidCodeDetails;\n}\n\nexport function initQuorumValuesFromCodeDetails(\n\tsource: IFluidCodeDetails,\n): [string, ICommittedProposal][] {\n\t// Seed the base quorum to be an empty list with a code quorum set\n\tconst committedCodeProposal: ICommittedProposal = {\n\t\tkey: \"code\",\n\t\tvalue: source,\n\t\tapprovalSequenceNumber: 0,\n\t\tcommitSequenceNumber: 0,\n\t\tsequenceNumber: 0,\n\t};\n\treturn [[\"code\", committedCodeProposal]];\n}\n"]}
1
+ {"version":3,"file":"quorum.js","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAItD,MAAM,UAAU,8BAA8B,CAC7C,YAA4C;IAE5C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACxE,OAAO,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,KAA0B,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC9C,MAAyB;IAEzB,kEAAkE;IAClE,MAAM,qBAAqB,GAAuB;QACjD,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,MAAM;QACb,sBAAsB,EAAE,CAAC;QACzB,oBAAoB,EAAE,CAAC;QACvB,cAAc,EAAE,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IFluidCodeDetails } from \"@fluidframework/core-interfaces\";\nimport { ICommittedProposal } from \"@fluidframework/protocol-definitions\";\n\nexport function getCodeDetailsFromQuorumValues(\n\tquorumValues: [string, ICommittedProposal][],\n): IFluidCodeDetails {\n\tconst qValuesMap = new Map(quorumValues);\n\tconst proposal = qValuesMap.get(\"code\");\n\tassert(proposal !== undefined, 0x2dc /* \"Cannot find code proposal\" */);\n\treturn proposal?.value as IFluidCodeDetails;\n}\n\nexport function initQuorumValuesFromCodeDetails(\n\tsource: IFluidCodeDetails,\n): [string, ICommittedProposal][] {\n\t// Seed the base quorum to be an empty list with a code quorum set\n\tconst committedCodeProposal: ICommittedProposal = {\n\t\tkey: \"code\",\n\t\tvalue: source,\n\t\tapprovalSequenceNumber: 0,\n\t\tcommitSequenceNumber: 0,\n\t\tsequenceNumber: 0,\n\t};\n\treturn [[\"code\", committedCodeProposal]];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "2.0.0-internal.5.2.0",
3
+ "version": "2.0.0-internal.5.3.0",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -37,14 +37,14 @@
37
37
  "dependencies": {
38
38
  "@fluidframework/common-definitions": "^0.20.1",
39
39
  "@fluidframework/common-utils": "^1.1.1",
40
- "@fluidframework/container-definitions": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
41
- "@fluidframework/container-utils": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
42
- "@fluidframework/core-interfaces": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
43
- "@fluidframework/driver-definitions": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
44
- "@fluidframework/driver-utils": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
40
+ "@fluidframework/container-definitions": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
41
+ "@fluidframework/container-utils": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
42
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
43
+ "@fluidframework/driver-definitions": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
44
+ "@fluidframework/driver-utils": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
45
45
  "@fluidframework/protocol-base": "^0.1039.1000",
46
46
  "@fluidframework/protocol-definitions": "^1.1.0",
47
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
47
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
48
48
  "abort-controller": "^3.0.0",
49
49
  "double-ended-queue": "^2.1.0-0",
50
50
  "events": "^3.1.0",
@@ -53,13 +53,13 @@
53
53
  "uuid": "^8.3.1"
54
54
  },
55
55
  "devDependencies": {
56
- "@fluid-internal/test-loader-utils": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
57
- "@fluid-tools/build-cli": "^0.20.0",
56
+ "@fluid-internal/test-loader-utils": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
57
+ "@fluid-tools/build-cli": "^0.21.0",
58
58
  "@fluidframework/build-common": "^1.2.0",
59
- "@fluidframework/build-tools": "^0.20.0",
60
- "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.5.0.0",
59
+ "@fluidframework/build-tools": "^0.21.0",
60
+ "@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@2.0.0-internal.5.2.0",
61
61
  "@fluidframework/eslint-config-fluid": "^2.0.0",
62
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.5.2.0 <2.0.0-internal.5.3.0",
62
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.5.3.0 <2.0.0-internal.5.4.0",
63
63
  "@microsoft/api-extractor": "^7.34.4",
64
64
  "@types/double-ended-queue": "^2.1.0",
65
65
  "@types/events": "^3.0.0",
@@ -82,7 +82,11 @@
82
82
  "typescript": "~4.5.5"
83
83
  },
84
84
  "typeValidation": {
85
- "broken": {}
85
+ "broken": {
86
+ "InterfaceDeclaration_IContainerExperimental": {
87
+ "backCompat": false
88
+ }
89
+ }
86
90
  },
87
91
  "scripts": {
88
92
  "build": "fluid-build . --task build",
@@ -109,6 +113,6 @@
109
113
  "tsc": "tsc",
110
114
  "tsc:watch": "tsc --watch",
111
115
  "typetests:gen": "fluid-type-test-generator",
112
- "typetests:prepare": "flub generate typetests --prepare --dir . --pin"
116
+ "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
113
117
  }
114
118
  }
@@ -4,8 +4,7 @@
4
4
  */
5
5
 
6
6
  import { default as AbortController } from "abort-controller";
7
- import { ITelemetryProperties } from "@fluidframework/common-definitions";
8
- import { IDisposable } from "@fluidframework/core-interfaces";
7
+ import { IDisposable, ITelemetryProperties } from "@fluidframework/core-interfaces";
9
8
  import { assert, performance, TypedEventEmitter } from "@fluidframework/common-utils";
10
9
  import {
11
10
  IDeltaQueue,
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryProperties, TelemetryEventCategory } from "@fluidframework/common-definitions";
6
+ import { ITelemetryProperties, TelemetryEventCategory } from "@fluidframework/core-interfaces";
7
7
  import { assert, Timer } from "@fluidframework/common-utils";
8
8
  import { IConnectionDetailsInternal, IDeltaManager } from "@fluidframework/container-definitions";
9
9
  import { IAnyDriverError } from "@fluidframework/driver-definitions";
package/src/container.ts CHANGED
@@ -7,18 +7,21 @@
7
7
  import merge from "lodash/merge";
8
8
 
9
9
  import { v4 as uuid } from "uuid";
10
- import {
11
- IEvent,
12
- ITelemetryProperties,
13
- TelemetryEventCategory,
14
- } from "@fluidframework/common-definitions";
10
+ import { IEvent } from "@fluidframework/common-definitions";
15
11
  import {
16
12
  TypedEventEmitter,
17
13
  assert,
18
14
  performance,
19
15
  unreachableCase,
20
16
  } from "@fluidframework/common-utils";
21
- import { IRequest, IResponse, IFluidRouter, FluidObject } from "@fluidframework/core-interfaces";
17
+ import {
18
+ ITelemetryProperties,
19
+ TelemetryEventCategory,
20
+ IRequest,
21
+ IResponse,
22
+ IFluidRouter,
23
+ FluidObject,
24
+ } from "@fluidframework/core-interfaces";
22
25
  import {
23
26
  IAudience,
24
27
  IConnectionDetailsInternal,
@@ -98,7 +101,6 @@ import { Audience } from "./audience";
98
101
  import { ContainerContext } from "./containerContext";
99
102
  import { ReconnectMode, IConnectionManagerFactoryArgs, getPackageName } from "./contracts";
100
103
  import { DeltaManager, IConnectionArgs } from "./deltaManager";
101
- import { DeltaManagerProxy } from "./deltaManagerProxy";
102
104
  import { IDetachedBlobStorage, ILoaderOptions, RelativeLoader } from "./loader";
103
105
  import { pkgVersion } from "./packageVersion";
104
106
  import {
@@ -109,19 +111,16 @@ import {
109
111
  } from "./containerStorageAdapter";
110
112
  import { IConnectionStateHandler, createConnectionStateHandler } from "./connectionStateHandler";
111
113
  import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
112
- import {
113
- initQuorumValuesFromCodeDetails,
114
- getCodeDetailsFromQuorumValues,
115
- QuorumProxy,
116
- } from "./quorum";
114
+ import { initQuorumValuesFromCodeDetails, getCodeDetailsFromQuorumValues } from "./quorum";
117
115
  import { NoopHeuristic } from "./noopHeuristic";
118
116
  import { ConnectionManager } from "./connectionManager";
119
117
  import { ConnectionState } from "./connectionState";
120
118
  import {
121
- OnlyValidTermValue,
122
119
  IProtocolHandler,
120
+ OnlyValidTermValue,
123
121
  ProtocolHandler,
124
122
  ProtocolHandlerBuilder,
123
+ protocolHandlerShouldProcessSignal,
125
124
  } from "./protocol";
126
125
 
127
126
  const detachedContainerRefSeqNumber = 0;
@@ -794,7 +793,10 @@ export class Container
794
793
  // dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
795
794
  dmLastMsqSeqNumber: () => this.deltaManager?.lastMessage?.sequenceNumber,
796
795
  dmLastMsqSeqTimestamp: () => this.deltaManager?.lastMessage?.timestamp,
797
- dmLastMsqSeqClientId: () => this.deltaManager?.lastMessage?.clientId,
796
+ dmLastMsqSeqClientId: () =>
797
+ this.deltaManager?.lastMessage?.clientId === null
798
+ ? "null"
799
+ : this.deltaManager?.lastMessage?.clientId,
798
800
  dmLastMsgClientSeq: () => this.deltaManager?.lastMessage?.clientSequenceNumber,
799
801
  connectionStateDuration: () =>
800
802
  performance.now() - this.connectionTransitionTimes[this.connectionState],
@@ -985,6 +987,11 @@ export class Container
985
987
  }
986
988
  } finally {
987
989
  this._lifecycleState = "closed";
990
+
991
+ // There is no user for summarizer, so we need to ensure dispose is called
992
+ if (this.client.details.type === summarizerClientType) {
993
+ this.dispose(error);
994
+ }
988
995
  }
989
996
  }
990
997
 
@@ -1057,6 +1064,11 @@ export class Container
1057
1064
  if (!this.offlineLoadEnabled) {
1058
1065
  throw new UsageError("Can't get pending local state unless offline load is enabled");
1059
1066
  }
1067
+ if (this.closed || this._disposed) {
1068
+ throw new UsageError(
1069
+ "Pending state cannot be retried if the container is closed or disposed",
1070
+ );
1071
+ }
1060
1072
  assert(
1061
1073
  this.attachState === AttachState.Attached,
1062
1074
  0x0d1 /* "Container should be attached before close" */,
@@ -1996,7 +2008,11 @@ export class Container
1996
2008
  } else if (value === ConnectionState.CatchingUp) {
1997
2009
  // This info is of most interesting while Catching Up.
1998
2010
  checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
1999
- if (this.deltaManager.hasCheckpointSequenceNumber) {
2011
+ // Need to check that we have already loaded and fetched the snapshot.
2012
+ if (
2013
+ this.deltaManager.hasCheckpointSequenceNumber &&
2014
+ this._lifecycleState === "loaded"
2015
+ ) {
2000
2016
  opsBehind = checkpointSequenceNumber - this.deltaManager.lastSequenceNumber;
2001
2017
  }
2002
2018
  }
@@ -2230,7 +2246,7 @@ export class Container
2230
2246
 
2231
2247
  private processSignal(message: ISignalMessage) {
2232
2248
  // No clientId indicates a system signal message.
2233
- if (message.clientId === null) {
2249
+ if (protocolHandlerShouldProcessSignal(message)) {
2234
2250
  this.protocolHandler.processSignal(message);
2235
2251
  } else {
2236
2252
  const local = this.clientId === message.clientId;
@@ -2307,17 +2323,18 @@ export class Container
2307
2323
  throw new Error(packageNotFactoryError);
2308
2324
  }
2309
2325
 
2310
- const deltaManagerProxy = new DeltaManagerProxy(this._deltaManager);
2311
- const quorumProxy = new QuorumProxy(this.protocolHandler.quorum);
2326
+ const getSpecifiedCodeDetails = () =>
2327
+ (this.protocolHandler.quorum.get("code") ??
2328
+ this.protocolHandler.quorum.get("code2")) as IFluidCodeDetails | undefined;
2312
2329
 
2313
2330
  const context = new ContainerContext(
2314
2331
  this.options,
2315
2332
  this.scope,
2316
2333
  snapshot,
2317
2334
  this._loadedFromVersion,
2318
- deltaManagerProxy,
2335
+ this._deltaManager,
2319
2336
  this.storageAdapter,
2320
- quorumProxy,
2337
+ this.protocolHandler.quorum,
2321
2338
  this.protocolHandler.audience,
2322
2339
  loader,
2323
2340
  (type, contents, batch, metadata) =>
@@ -2333,9 +2350,10 @@ export class Container
2333
2350
  this.getAbsoluteUrl,
2334
2351
  () => this.resolvedUrl?.id,
2335
2352
  () => this.clientId,
2336
- () => deltaManagerProxy.serviceConfiguration,
2353
+ () => this._deltaManager.serviceConfiguration,
2337
2354
  () => this.attachState,
2338
2355
  () => this.connected,
2356
+ getSpecifiedCodeDetails,
2339
2357
  this._deltaManager.clientDetails,
2340
2358
  existing,
2341
2359
  this.subLogger,
@@ -2343,8 +2361,6 @@ export class Container
2343
2361
  );
2344
2362
  this._lifecycleEvents.once("disposed", () => {
2345
2363
  context.dispose();
2346
- quorumProxy.dispose();
2347
- deltaManagerProxy.dispose();
2348
2364
  });
2349
2365
 
2350
2366
  this._runtime = await PerformanceEvent.timedExecAsync(
@@ -2388,7 +2404,7 @@ export class Container
2388
2404
 
2389
2405
  /**
2390
2406
  * IContainer interface that includes experimental features still under development.
2391
- * @internal
2407
+ * @experimental
2392
2408
  */
2393
2409
  export interface IContainerExperimental extends IContainer {
2394
2410
  /**
@@ -2399,5 +2415,13 @@ export interface IContainerExperimental extends IContainer {
2399
2415
  * @experimental misuse of this API can result in duplicate op submission and potential document corruption
2400
2416
  * {@link https://github.com/microsoft/FluidFramework/blob/main/packages/loader/container-loader/closeAndGetPendingLocalState.md}
2401
2417
  */
2402
- getPendingLocalState(): string;
2418
+ getPendingLocalState?(): string;
2419
+
2420
+ /**
2421
+ * Closes the container and returns serialized local state intended to be
2422
+ * given to a newly loaded container.
2423
+ * @experimental
2424
+ * {@link https://github.com/microsoft/FluidFramework/blob/main/packages/loader/container-loader/closeAndGetPendingLocalState.md}
2425
+ */
2426
+ closeAndGetPendingLocalState(): string;
2403
2427
  }
@@ -21,7 +21,6 @@ import {
21
21
  IClientConfiguration,
22
22
  IClientDetails,
23
23
  IDocumentMessage,
24
- IQuorum,
25
24
  IQuorumClients,
26
25
  ISequencedDocumentMessage,
27
26
  ISnapshotTree,
@@ -72,10 +71,6 @@ export class ContainerContext implements IContainerContext {
72
71
  return this._disposed;
73
72
  }
74
73
 
75
- public get quorum(): IQuorumClients {
76
- return this._quorum;
77
- }
78
-
79
74
  constructor(
80
75
  public readonly options: ILoaderOptions,
81
76
  public readonly scope: FluidObject,
@@ -83,7 +78,7 @@ export class ContainerContext implements IContainerContext {
83
78
  private readonly _version: IVersion | undefined,
84
79
  public readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
85
80
  public readonly storage: IDocumentStorageService,
86
- private readonly _quorum: IQuorum,
81
+ public readonly quorum: IQuorumClients,
87
82
  public readonly audience: IAudience,
88
83
  public readonly loader: ILoader,
89
84
  public readonly submitFn: (
@@ -111,24 +106,13 @@ export class ContainerContext implements IContainerContext {
111
106
  private readonly _getServiceConfiguration: () => IClientConfiguration | undefined,
112
107
  private readonly _getAttachState: () => AttachState,
113
108
  private readonly _getConnected: () => boolean,
109
+ public readonly getSpecifiedCodeDetails: () => IFluidCodeDetails | undefined,
114
110
  public readonly clientDetails: IClientDetails,
115
111
  public readonly existing: boolean,
116
112
  public readonly taggedLogger: ITelemetryLoggerExt,
117
113
  public readonly pendingLocalState?: unknown,
118
114
  ) {}
119
115
 
120
- /**
121
- * @deprecated Temporary migratory API, to be removed when customers no longer need it.
122
- * When removed, `ContainerContext` should only take an {@link @fluidframework/container-definitions#IQuorumClients}
123
- * rather than an {@link @fluidframework/protocol-definitions#IQuorum}.
124
- * See {@link @fluidframework/container-definitions#IContainerContext} for more details.
125
- */
126
- public getSpecifiedCodeDetails(): IFluidCodeDetails | undefined {
127
- return (this._quorum.get("code") ?? this._quorum.get("code2")) as
128
- | IFluidCodeDetails
129
- | undefined;
130
- }
131
-
132
116
  public dispose(error?: Error): void {
133
117
  this._disposed = true;
134
118
  }
@@ -229,6 +229,14 @@ class BlobOnlyStorage implements IDocumentStorageService {
229
229
  }
230
230
  }
231
231
 
232
+ // runtime will write a tree to the summary containing "attachment" type entries
233
+ // which reference attachment blobs by ID, along with a blob containing the blob redirect table.
234
+ // However, some drivers do not support the "attachment" type and will convert them to "blob" type
235
+ // entries. We want to avoid saving these to reduce the size of stashed change blobs, but we
236
+ // need to make sure the blob redirect table is saved.
237
+ const blobsTreeName = ".blobs";
238
+ const redirectTableBlobName = ".redirectTable";
239
+
232
240
  /**
233
241
  * Get blob contents of a snapshot tree from storage (or, ideally, cache)
234
242
  */
@@ -245,10 +253,15 @@ async function getBlobContentsFromTreeCore(
245
253
  tree: ISnapshotTree,
246
254
  blobs: ISerializableBlobContents,
247
255
  storage: IDocumentStorageService,
256
+ root = true,
248
257
  ) {
249
258
  const treePs: Promise<any>[] = [];
250
- for (const subTree of Object.values(tree.trees)) {
251
- treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage));
259
+ for (const [key, subTree] of Object.entries(tree.trees)) {
260
+ if (root && key === blobsTreeName) {
261
+ treePs.push(getBlobManagerTreeFromTree(subTree, blobs, storage));
262
+ } else {
263
+ treePs.push(getBlobContentsFromTreeCore(subTree, blobs, storage, false));
264
+ }
252
265
  }
253
266
  for (const id of Object.values(tree.blobs)) {
254
267
  const blob = await storage.readBlob(id);
@@ -258,6 +271,18 @@ async function getBlobContentsFromTreeCore(
258
271
  return Promise.all(treePs);
259
272
  }
260
273
 
274
+ // save redirect table from .blobs tree but nothing else
275
+ async function getBlobManagerTreeFromTree(
276
+ tree: ISnapshotTree,
277
+ blobs: ISerializableBlobContents,
278
+ storage: IDocumentStorageService,
279
+ ) {
280
+ const id = tree.blobs[redirectTableBlobName];
281
+ const blob = await storage.readBlob(id);
282
+ // ArrayBufferLike will not survive JSON.stringify()
283
+ blobs[id] = bufferToString(blob, "utf8");
284
+ }
285
+
261
286
  /**
262
287
  * Extract blob contents from a snapshot tree with blob contents
263
288
  */
@@ -272,9 +297,14 @@ export function getBlobContentsFromTreeWithBlobContents(
272
297
  function getBlobContentsFromTreeWithBlobContentsCore(
273
298
  tree: ISnapshotTreeWithBlobContents,
274
299
  blobs: ISerializableBlobContents,
300
+ root = true,
275
301
  ) {
276
- for (const subTree of Object.values(tree.trees)) {
277
- getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs);
302
+ for (const [key, subTree] of Object.entries(tree.trees)) {
303
+ if (root && key === blobsTreeName) {
304
+ getBlobManagerTreeFromTreeWithBlobContents(subTree, blobs);
305
+ } else {
306
+ getBlobContentsFromTreeWithBlobContentsCore(subTree, blobs, false);
307
+ }
278
308
  }
279
309
  for (const id of Object.values(tree.blobs)) {
280
310
  const blob = tree.blobsContents[id];
@@ -283,3 +313,15 @@ function getBlobContentsFromTreeWithBlobContentsCore(
283
313
  blobs[id] = bufferToString(blob, "utf8");
284
314
  }
285
315
  }
316
+
317
+ // save redirect table from .blobs tree but nothing else
318
+ function getBlobManagerTreeFromTreeWithBlobContents(
319
+ tree: ISnapshotTreeWithBlobContents,
320
+ blobs: ISerializableBlobContents,
321
+ ) {
322
+ const id = tree.blobs[redirectTableBlobName];
323
+ const blob = tree.blobsContents[id];
324
+ assert(blob !== undefined, 0x70f /* Blob must be present in blobsContents */);
325
+ // ArrayBufferLike will not survive JSON.stringify()
326
+ blobs[id] = bufferToString(blob, "utf8");
327
+ }
package/src/contracts.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryProperties } from "@fluidframework/common-definitions";
6
+ import { ITelemetryProperties } from "@fluidframework/core-interfaces";
7
7
  import {
8
8
  IDeltaQueue,
9
9
  ReadOnlyInfo,
@@ -148,8 +148,6 @@ export interface IConnectionManagerFactoryArgs {
148
148
 
149
149
  /**
150
150
  * Called whenever ping/pong messages are roundtripped on connection.
151
- *
152
- * @deprecated No replacement API intended.
153
151
  */
154
152
  readonly pongHandler: (latency: number) => void;
155
153
 
@@ -5,11 +5,8 @@
5
5
 
6
6
  import { default as AbortController } from "abort-controller";
7
7
  import { v4 as uuid } from "uuid";
8
- import {
9
- IEventProvider,
10
- ITelemetryProperties,
11
- ITelemetryErrorEvent,
12
- } from "@fluidframework/common-definitions";
8
+ import { IEventProvider } from "@fluidframework/common-definitions";
9
+ import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
13
10
  import {
14
11
  IDeltaHandlerStrategy,
15
12
  IDeltaManager,
@@ -70,6 +67,13 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
70
67
  (event: "cancelEstablishingConnection", listener: (reason: string) => void);
71
68
  }
72
69
 
70
+ /**
71
+ * Batching makes assumptions about what might be on the metadata. This interface codifies those assumptions, but does not validate them.
72
+ */
73
+ interface IBatchMetadata {
74
+ batch?: boolean;
75
+ }
76
+
73
77
  /**
74
78
  * Determines if message was sent by client, not service
75
79
  */
@@ -293,13 +297,16 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
293
297
 
294
298
  if (batch.length === 1) {
295
299
  assert(
296
- batch[0].metadata?.batch === undefined,
300
+ (batch[0].metadata as IBatchMetadata)?.batch === undefined,
297
301
  0x3c9 /* no batch markup on single message */,
298
302
  );
299
303
  } else {
300
- assert(batch[0].metadata?.batch === true, 0x3ca /* no start batch markup */);
301
304
  assert(
302
- batch[batch.length - 1].metadata?.batch === false,
305
+ (batch[0].metadata as IBatchMetadata)?.batch === true,
306
+ 0x3ca /* no start batch markup */,
307
+ );
308
+ assert(
309
+ (batch[batch.length - 1].metadata as IBatchMetadata)?.batch === false,
303
310
  0x3cb /* no end batch markup */,
304
311
  );
305
312
  }
@@ -0,0 +1,25 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { IDisposable } from "@fluidframework/common-definitions";
7
+
8
+ /**
9
+ * Returns a wrapper around the provided function, which will only invoke the inner function if the provided
10
+ * {@link @fluidframework/common-definitions#IDisposable | disposable} object has not yet been disposed.
11
+ *
12
+ * @throws Will throw an error if the item has already been disposed.
13
+ */
14
+ export function doIfNotDisposed<T>(
15
+ disposable: IDisposable,
16
+ f: (...args: any[]) => T,
17
+ ): (...args: any[]) => T {
18
+ return (...args: any[]): T => {
19
+ if (disposable.disposed) {
20
+ throw new Error("Already disposed");
21
+ } else {
22
+ return f(...args);
23
+ }
24
+ };
25
+ }
package/src/loader.ts CHANGED
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { v4 as uuid } from "uuid";
7
- import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
8
7
  import {
9
8
  ITelemetryLoggerExt,
10
9
  ChildLogger,
@@ -17,6 +16,7 @@ import {
17
16
  sessionStorageConfigProvider,
18
17
  } from "@fluidframework/telemetry-utils";
19
18
  import {
19
+ ITelemetryBaseLogger,
20
20
  FluidObject,
21
21
  IFluidRouter,
22
22
  IRequest,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-internal.5.2.0";
9
+ export const pkgVersion = "2.0.0-internal.5.3.0";
package/src/protocol.ts CHANGED
@@ -99,3 +99,21 @@ export class ProtocolHandler extends ProtocolOpHandler implements IProtocolHandl
99
99
  }
100
100
  }
101
101
  }
102
+
103
+ /**
104
+ * Function to check whether the protocol handler should process the Signal.
105
+ * The protocol handler should strictly handle only ClientJoin, ClientLeave
106
+ * and Clear signal types.
107
+ */
108
+ export function protocolHandlerShouldProcessSignal(message: ISignalMessage) {
109
+ // Signal originates from server
110
+ if (message.clientId === null) {
111
+ const innerContent = message.content as { content: unknown; type: string };
112
+ return (
113
+ innerContent.type === SignalType.Clear ||
114
+ innerContent.type === SignalType.ClientJoin ||
115
+ innerContent.type === SignalType.ClientLeave
116
+ );
117
+ }
118
+ return false;
119
+ }