@fluidframework/counter 2.80.0 → 2.81.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 +4 -0
- package/dist/counter.d.ts.map +1 -1
- package/dist/counter.js +6 -2
- package/dist/counter.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/eslint.config.mts +4 -4
- package/lib/counter.d.ts.map +1 -1
- package/lib/counter.js +6 -2
- package/lib/counter.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +17 -17
- package/src/counter.ts +2 -0
- package/src/packageVersion.ts +1 -1
- package/.eslintrc.cjs +0 -11
package/CHANGELOG.md
CHANGED
package/dist/counter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACxB;AAwBD;;;GAGG;AACH,qBAAa,aACZ,SAAQ,YAAY,CAAC,oBAAoB,CACzC,YAAW,cAAc;gBAGxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAK/B,OAAO,CAAC,MAAM,CAAa;IAE3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAa;IAEzC;;OAEG;IACH,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED;;OAEG;IACI,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAqB/C,OAAO,CAAC,aAAa;IAKrB;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAU5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACxB;AAwBD;;;GAGG;AACH,qBAAa,aACZ,SAAQ,YAAY,CAAC,oBAAoB,CACzC,YAAW,cAAc;gBAGxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAK/B,OAAO,CAAC,MAAM,CAAa;IAE3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAa;IAEzC;;OAEG;IACH,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED;;OAEG;IACI,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAqB/C,OAAO,CAAC,aAAa;IAKrB;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAU5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;IAuCtB;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAU3C;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;CAmBpE"}
|
package/dist/counter.js
CHANGED
|
@@ -102,7 +102,9 @@ class SharedCounter extends internal_4.SharedObject {
|
|
|
102
102
|
const pendingOp = this.pendingOps.shift();
|
|
103
103
|
const messageId = messageContent.localOpMetadata;
|
|
104
104
|
(0, internal_1.assert)(typeof messageId === "number", 0xc8e /* localOpMetadata should be a number */);
|
|
105
|
-
(0, internal_1.assert)(
|
|
105
|
+
(0, internal_1.assert)(
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
107
|
+
pendingOp !== undefined &&
|
|
106
108
|
pendingOp.messageId === messageId &&
|
|
107
109
|
pendingOp.type === op.type &&
|
|
108
110
|
pendingOp.incrementAmount === op.incrementAmount, 0xc8f /* local op mismatch */);
|
|
@@ -137,7 +139,9 @@ class SharedCounter extends internal_4.SharedObject {
|
|
|
137
139
|
assertIsIncrementOp(content);
|
|
138
140
|
(0, internal_1.assert)(typeof localOpMetadata === "number", 0xc90 /* localOpMetadata should be a number */);
|
|
139
141
|
const pendingOp = this.pendingOps.pop();
|
|
140
|
-
(0, internal_1.assert)(
|
|
142
|
+
(0, internal_1.assert)(
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
144
|
+
pendingOp !== undefined &&
|
|
141
145
|
pendingOp.messageId === localOpMetadata &&
|
|
142
146
|
pendingOp.type === content.type &&
|
|
143
147
|
pendingOp.incrementAmount === content.incrementAmount, 0xc91 /* op to rollback mismatch with pending op */);
|
package/dist/counter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../src/counter.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/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { ISharedCounter, ISharedCounterEvents } from \"./interfaces.js\";\n\n/**\n * Describes the operation (op) format for incrementing the {@link SharedCounter}.\n */\nexport interface IIncrementOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n}\n\n/**\n * Represents a pending op that has been submitted but not yet ack'd.\n * Includes the messageId that was used when submitting the op.\n */\ninterface IPendingOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n\tmessageId: number;\n}\n\n/**\n * @remarks Used in snapshotting.\n */\ninterface ICounterSnapshotFormat {\n\t/**\n\t * The value of the counter.\n\t */\n\tvalue: number;\n}\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc ISharedCounter}\n * @legacy @beta\n */\nexport class SharedCounter\n\textends SharedObject<ISharedCounterEvents>\n\timplements ISharedCounter\n{\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_counter_\");\n\t}\n\n\tprivate _value: number = 0;\n\n\t/**\n\t * Tracks pending local ops that have not been ack'd yet.\n\t */\n\tprivate readonly pendingOps: IPendingOperation[] = [];\n\n\t/**\n\t * The next message id to be used when submitting an op.\n\t */\n\tprivate nextPendingMessageId: number = 0;\n\n\t/**\n\t * {@inheritDoc ISharedCounter.value}\n\t */\n\tpublic get value(): number {\n\t\treturn this._value;\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedCounter.increment}\n\t */\n\tpublic increment(incrementAmount: number): void {\n\t\t// Incrementing by floating point numbers will be eventually inconsistent, since the order in which the\n\t\t// increments are applied affects the result. A more-robust solution would be required to support this.\n\t\tif (incrementAmount % 1 !== 0) {\n\t\t\tthrow new Error(\"Must increment by a whole number\");\n\t\t}\n\n\t\tconst op: IIncrementOperation = {\n\t\t\ttype: \"increment\",\n\t\t\tincrementAmount,\n\t\t};\n\t\tconst messageId = this.nextPendingMessageId++;\n\n\t\tthis.incrementCore(incrementAmount);\n\t\t// We don't need to send the op if we are not attached yet.\n\t\tif (this.isAttached()) {\n\t\t\tthis.pendingOps.push({ ...op, messageId });\n\t\t\tthis.submitLocalMessage(op, messageId);\n\t\t}\n\t}\n\n\tprivate incrementCore(incrementAmount: number): void {\n\t\tthis._value += incrementAmount;\n\t\tthis.emit(\"incremented\", incrementAmount, this._value);\n\t}\n\n\t/**\n\t * Create a summary for the counter.\n\t *\n\t * @returns The summary of the current state of the counter.\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\t// Get a serializable form of data\n\t\tconst content: ICounterSnapshotFormat = {\n\t\t\tvalue: this.value,\n\t\t};\n\n\t\t// And then construct the summary for it\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(content));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<ICounterSnapshotFormat>(storage, snapshotFileName);\n\n\t\tthis._value = content.value;\n\t}\n\n\t/**\n\t * Called when the object has disconnected from the delta stream.\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IIncrementOperation;\n\n\t\t\t// If the message is local we have already optimistically processed\n\t\t\t// and we should now remove it from this.pendingOps.\n\t\t\t// If the message is from a remote client, we should process it.\n\t\t\tif (local) {\n\t\t\t\tconst pendingOp = this.pendingOps.shift();\n\t\t\t\tconst messageId = messageContent.localOpMetadata;\n\t\t\t\tassert(typeof messageId === \"number\", 0xc8e /* localOpMetadata should be a number */);\n\t\t\t\tassert(\n\t\t\t\t\tpendingOp !== undefined &&\n\t\t\t\t\t\tpendingOp.messageId === messageId &&\n\t\t\t\t\t\tpendingOp.type === op.type &&\n\t\t\t\t\t\tpendingOp.incrementAmount === op.incrementAmount,\n\t\t\t\t\t0xc8f /* local op mismatch */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"increment\": {\n\t\t\t\t\t\tthis.incrementCore(op.incrementAmount);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritdoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}\n\t */\n\tprotected applyStashedOp(op: unknown): void {\n\t\tconst counterOp = op as IIncrementOperation;\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\n\t\tassert(counterOp.type === \"increment\", 0x3ec /* Op type is not increment */);\n\n\t\tthis.increment(counterOp.incrementAmount);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.rollback}\n\t * @sealed\n\t */\n\tprotected rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tassertIsIncrementOp(content);\n\t\tassert(\n\t\t\ttypeof localOpMetadata === \"number\",\n\t\t\t0xc90 /* localOpMetadata should be a number */,\n\t\t);\n\t\tconst pendingOp = this.pendingOps.pop();\n\t\tassert(\n\t\t\tpendingOp !== undefined &&\n\t\t\t\tpendingOp.messageId === localOpMetadata &&\n\t\t\t\tpendingOp.type === content.type &&\n\t\t\t\tpendingOp.incrementAmount === content.incrementAmount,\n\t\t\t0xc91 /* op to rollback mismatch with pending op */,\n\t\t);\n\t\t// To rollback the optimistic increment we can increment by the opposite amount.\n\t\t// This will also emit another incremented event with the opposite amount.\n\t\tthis.incrementCore(-content.incrementAmount);\n\t}\n}\n\nfunction assertIsIncrementOp(op: unknown): asserts op is IIncrementOperation {\n\tassert(\n\t\ttypeof op === \"object\" &&\n\t\t\top !== null &&\n\t\t\t\"type\" in op &&\n\t\t\t\"incrementAmount\" in op &&\n\t\t\top.type === \"increment\" &&\n\t\t\ttypeof op.incrementAmount === \"number\",\n\t\t0xc92 /* invalid increment op format */,\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../src/counter.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/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { ISharedCounter, ISharedCounterEvents } from \"./interfaces.js\";\n\n/**\n * Describes the operation (op) format for incrementing the {@link SharedCounter}.\n */\nexport interface IIncrementOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n}\n\n/**\n * Represents a pending op that has been submitted but not yet ack'd.\n * Includes the messageId that was used when submitting the op.\n */\ninterface IPendingOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n\tmessageId: number;\n}\n\n/**\n * @remarks Used in snapshotting.\n */\ninterface ICounterSnapshotFormat {\n\t/**\n\t * The value of the counter.\n\t */\n\tvalue: number;\n}\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc ISharedCounter}\n * @legacy @beta\n */\nexport class SharedCounter\n\textends SharedObject<ISharedCounterEvents>\n\timplements ISharedCounter\n{\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_counter_\");\n\t}\n\n\tprivate _value: number = 0;\n\n\t/**\n\t * Tracks pending local ops that have not been ack'd yet.\n\t */\n\tprivate readonly pendingOps: IPendingOperation[] = [];\n\n\t/**\n\t * The next message id to be used when submitting an op.\n\t */\n\tprivate nextPendingMessageId: number = 0;\n\n\t/**\n\t * {@inheritDoc ISharedCounter.value}\n\t */\n\tpublic get value(): number {\n\t\treturn this._value;\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedCounter.increment}\n\t */\n\tpublic increment(incrementAmount: number): void {\n\t\t// Incrementing by floating point numbers will be eventually inconsistent, since the order in which the\n\t\t// increments are applied affects the result. A more-robust solution would be required to support this.\n\t\tif (incrementAmount % 1 !== 0) {\n\t\t\tthrow new Error(\"Must increment by a whole number\");\n\t\t}\n\n\t\tconst op: IIncrementOperation = {\n\t\t\ttype: \"increment\",\n\t\t\tincrementAmount,\n\t\t};\n\t\tconst messageId = this.nextPendingMessageId++;\n\n\t\tthis.incrementCore(incrementAmount);\n\t\t// We don't need to send the op if we are not attached yet.\n\t\tif (this.isAttached()) {\n\t\t\tthis.pendingOps.push({ ...op, messageId });\n\t\t\tthis.submitLocalMessage(op, messageId);\n\t\t}\n\t}\n\n\tprivate incrementCore(incrementAmount: number): void {\n\t\tthis._value += incrementAmount;\n\t\tthis.emit(\"incremented\", incrementAmount, this._value);\n\t}\n\n\t/**\n\t * Create a summary for the counter.\n\t *\n\t * @returns The summary of the current state of the counter.\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\t// Get a serializable form of data\n\t\tconst content: ICounterSnapshotFormat = {\n\t\t\tvalue: this.value,\n\t\t};\n\n\t\t// And then construct the summary for it\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(content));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<ICounterSnapshotFormat>(storage, snapshotFileName);\n\n\t\tthis._value = content.value;\n\t}\n\n\t/**\n\t * Called when the object has disconnected from the delta stream.\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IIncrementOperation;\n\n\t\t\t// If the message is local we have already optimistically processed\n\t\t\t// and we should now remove it from this.pendingOps.\n\t\t\t// If the message is from a remote client, we should process it.\n\t\t\tif (local) {\n\t\t\t\tconst pendingOp = this.pendingOps.shift();\n\t\t\t\tconst messageId = messageContent.localOpMetadata;\n\t\t\t\tassert(typeof messageId === \"number\", 0xc8e /* localOpMetadata should be a number */);\n\t\t\t\tassert(\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior\n\t\t\t\t\tpendingOp !== undefined &&\n\t\t\t\t\t\tpendingOp.messageId === messageId &&\n\t\t\t\t\t\tpendingOp.type === op.type &&\n\t\t\t\t\t\tpendingOp.incrementAmount === op.incrementAmount,\n\t\t\t\t\t0xc8f /* local op mismatch */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"increment\": {\n\t\t\t\t\t\tthis.incrementCore(op.incrementAmount);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritdoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}\n\t */\n\tprotected applyStashedOp(op: unknown): void {\n\t\tconst counterOp = op as IIncrementOperation;\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\n\t\tassert(counterOp.type === \"increment\", 0x3ec /* Op type is not increment */);\n\n\t\tthis.increment(counterOp.incrementAmount);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.rollback}\n\t * @sealed\n\t */\n\tprotected rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tassertIsIncrementOp(content);\n\t\tassert(\n\t\t\ttypeof localOpMetadata === \"number\",\n\t\t\t0xc90 /* localOpMetadata should be a number */,\n\t\t);\n\t\tconst pendingOp = this.pendingOps.pop();\n\t\tassert(\n\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior\n\t\t\tpendingOp !== undefined &&\n\t\t\t\tpendingOp.messageId === localOpMetadata &&\n\t\t\t\tpendingOp.type === content.type &&\n\t\t\t\tpendingOp.incrementAmount === content.incrementAmount,\n\t\t\t0xc91 /* op to rollback mismatch with pending op */,\n\t\t);\n\t\t// To rollback the optimistic increment we can increment by the opposite amount.\n\t\t// This will also emit another incremented event with the opposite amount.\n\t\tthis.incrementCore(-content.incrementAmount);\n\t}\n}\n\nfunction assertIsIncrementOp(op: unknown): asserts op is IIncrementOperation {\n\tassert(\n\t\ttypeof op === \"object\" &&\n\t\t\top !== null &&\n\t\t\t\"type\" in op &&\n\t\t\t\"incrementAmount\" in op &&\n\t\t\top.type === \"increment\" &&\n\t\t\ttypeof op.incrementAmount === \"number\",\n\t\t0xc92 /* invalid increment op format */,\n\t);\n}\n"]}
|
package/dist/packageVersion.d.ts
CHANGED
package/dist/packageVersion.js
CHANGED
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.pkgVersion = exports.pkgName = void 0;
|
|
10
10
|
exports.pkgName = "@fluidframework/counter";
|
|
11
|
-
exports.pkgVersion = "2.
|
|
11
|
+
exports.pkgVersion = "2.81.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,yBAAyB,CAAC;AACpC,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/counter\";\nexport const pkgVersion = \"2.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,yBAAyB,CAAC;AACpC,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/counter\";\nexport const pkgVersion = \"2.81.0\";\n"]}
|
package/eslint.config.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* To regenerate: pnpm tsx scripts/generate-flat-eslint-configs.ts --typescript
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
5
4
|
*/
|
|
5
|
+
|
|
6
6
|
import type { Linter } from "eslint";
|
|
7
7
|
import { strict } from "../../../common/build/eslint-config-fluid/flat.mts";
|
|
8
8
|
|
package/lib/counter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACxB;AAwBD;;;GAGG;AACH,qBAAa,aACZ,SAAQ,YAAY,CAAC,oBAAoB,CACzC,YAAW,cAAc;gBAGxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAK/B,OAAO,CAAC,MAAM,CAAa;IAE3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAa;IAEzC;;OAEG;IACH,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED;;OAEG;IACI,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAqB/C,OAAO,CAAC,aAAa;IAKrB;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAU5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAGxD,OAAO,KAAK,EACX,qBAAqB,EACrB,yBAAyB,EAGzB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACN,YAAY,EAEZ,MAAM,6CAA6C,CAAC;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACxB;AAwBD;;;GAGG;AACH,qBAAa,aACZ,SAAQ,YAAY,CAAC,oBAAoB,CACzC,YAAW,cAAc;gBAGxB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,sBAAsB,EAC/B,UAAU,EAAE,kBAAkB;IAK/B,OAAO,CAAC,MAAM,CAAa;IAE3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAAa;IAEzC;;OAEG;IACH,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED;;OAEG;IACI,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAqB/C,OAAO,CAAC,aAAa;IAKrB;;;;OAIG;IACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,gBAAgB,GAAG,qBAAqB;IAU5E;;OAEG;cACa,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAE9B;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,IAAI;IAOlF,OAAO,CAAC,cAAc;IAuCtB;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAU3C;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,GAAG,IAAI;CAmBpE"}
|
package/lib/counter.js
CHANGED
|
@@ -99,7 +99,9 @@ export class SharedCounter extends SharedObject {
|
|
|
99
99
|
const pendingOp = this.pendingOps.shift();
|
|
100
100
|
const messageId = messageContent.localOpMetadata;
|
|
101
101
|
assert(typeof messageId === "number", 0xc8e /* localOpMetadata should be a number */);
|
|
102
|
-
assert(
|
|
102
|
+
assert(
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
104
|
+
pendingOp !== undefined &&
|
|
103
105
|
pendingOp.messageId === messageId &&
|
|
104
106
|
pendingOp.type === op.type &&
|
|
105
107
|
pendingOp.incrementAmount === op.incrementAmount, 0xc8f /* local op mismatch */);
|
|
@@ -134,7 +136,9 @@ export class SharedCounter extends SharedObject {
|
|
|
134
136
|
assertIsIncrementOp(content);
|
|
135
137
|
assert(typeof localOpMetadata === "number", 0xc90 /* localOpMetadata should be a number */);
|
|
136
138
|
const pendingOp = this.pendingOps.pop();
|
|
137
|
-
assert(
|
|
139
|
+
assert(
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
141
|
+
pendingOp !== undefined &&
|
|
138
142
|
pendingOp.messageId === localOpMetadata &&
|
|
139
143
|
pendingOp.type === content.type &&
|
|
140
144
|
pendingOp.incrementAmount === content.incrementAmount, 0xc91 /* op to rollback mismatch with pending op */);
|
package/lib/counter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../src/counter.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/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { ISharedCounter, ISharedCounterEvents } from \"./interfaces.js\";\n\n/**\n * Describes the operation (op) format for incrementing the {@link SharedCounter}.\n */\nexport interface IIncrementOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n}\n\n/**\n * Represents a pending op that has been submitted but not yet ack'd.\n * Includes the messageId that was used when submitting the op.\n */\ninterface IPendingOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n\tmessageId: number;\n}\n\n/**\n * @remarks Used in snapshotting.\n */\ninterface ICounterSnapshotFormat {\n\t/**\n\t * The value of the counter.\n\t */\n\tvalue: number;\n}\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc ISharedCounter}\n * @legacy @beta\n */\nexport class SharedCounter\n\textends SharedObject<ISharedCounterEvents>\n\timplements ISharedCounter\n{\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_counter_\");\n\t}\n\n\tprivate _value: number = 0;\n\n\t/**\n\t * Tracks pending local ops that have not been ack'd yet.\n\t */\n\tprivate readonly pendingOps: IPendingOperation[] = [];\n\n\t/**\n\t * The next message id to be used when submitting an op.\n\t */\n\tprivate nextPendingMessageId: number = 0;\n\n\t/**\n\t * {@inheritDoc ISharedCounter.value}\n\t */\n\tpublic get value(): number {\n\t\treturn this._value;\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedCounter.increment}\n\t */\n\tpublic increment(incrementAmount: number): void {\n\t\t// Incrementing by floating point numbers will be eventually inconsistent, since the order in which the\n\t\t// increments are applied affects the result. A more-robust solution would be required to support this.\n\t\tif (incrementAmount % 1 !== 0) {\n\t\t\tthrow new Error(\"Must increment by a whole number\");\n\t\t}\n\n\t\tconst op: IIncrementOperation = {\n\t\t\ttype: \"increment\",\n\t\t\tincrementAmount,\n\t\t};\n\t\tconst messageId = this.nextPendingMessageId++;\n\n\t\tthis.incrementCore(incrementAmount);\n\t\t// We don't need to send the op if we are not attached yet.\n\t\tif (this.isAttached()) {\n\t\t\tthis.pendingOps.push({ ...op, messageId });\n\t\t\tthis.submitLocalMessage(op, messageId);\n\t\t}\n\t}\n\n\tprivate incrementCore(incrementAmount: number): void {\n\t\tthis._value += incrementAmount;\n\t\tthis.emit(\"incremented\", incrementAmount, this._value);\n\t}\n\n\t/**\n\t * Create a summary for the counter.\n\t *\n\t * @returns The summary of the current state of the counter.\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\t// Get a serializable form of data\n\t\tconst content: ICounterSnapshotFormat = {\n\t\t\tvalue: this.value,\n\t\t};\n\n\t\t// And then construct the summary for it\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(content));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<ICounterSnapshotFormat>(storage, snapshotFileName);\n\n\t\tthis._value = content.value;\n\t}\n\n\t/**\n\t * Called when the object has disconnected from the delta stream.\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IIncrementOperation;\n\n\t\t\t// If the message is local we have already optimistically processed\n\t\t\t// and we should now remove it from this.pendingOps.\n\t\t\t// If the message is from a remote client, we should process it.\n\t\t\tif (local) {\n\t\t\t\tconst pendingOp = this.pendingOps.shift();\n\t\t\t\tconst messageId = messageContent.localOpMetadata;\n\t\t\t\tassert(typeof messageId === \"number\", 0xc8e /* localOpMetadata should be a number */);\n\t\t\t\tassert(\n\t\t\t\t\tpendingOp !== undefined &&\n\t\t\t\t\t\tpendingOp.messageId === messageId &&\n\t\t\t\t\t\tpendingOp.type === op.type &&\n\t\t\t\t\t\tpendingOp.incrementAmount === op.incrementAmount,\n\t\t\t\t\t0xc8f /* local op mismatch */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"increment\": {\n\t\t\t\t\t\tthis.incrementCore(op.incrementAmount);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritdoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}\n\t */\n\tprotected applyStashedOp(op: unknown): void {\n\t\tconst counterOp = op as IIncrementOperation;\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\n\t\tassert(counterOp.type === \"increment\", 0x3ec /* Op type is not increment */);\n\n\t\tthis.increment(counterOp.incrementAmount);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.rollback}\n\t * @sealed\n\t */\n\tprotected rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tassertIsIncrementOp(content);\n\t\tassert(\n\t\t\ttypeof localOpMetadata === \"number\",\n\t\t\t0xc90 /* localOpMetadata should be a number */,\n\t\t);\n\t\tconst pendingOp = this.pendingOps.pop();\n\t\tassert(\n\t\t\tpendingOp !== undefined &&\n\t\t\t\tpendingOp.messageId === localOpMetadata &&\n\t\t\t\tpendingOp.type === content.type &&\n\t\t\t\tpendingOp.incrementAmount === content.incrementAmount,\n\t\t\t0xc91 /* op to rollback mismatch with pending op */,\n\t\t);\n\t\t// To rollback the optimistic increment we can increment by the opposite amount.\n\t\t// This will also emit another incremented event with the opposite amount.\n\t\tthis.incrementCore(-content.incrementAmount);\n\t}\n}\n\nfunction assertIsIncrementOp(op: unknown): asserts op is IIncrementOperation {\n\tassert(\n\t\ttypeof op === \"object\" &&\n\t\t\top !== null &&\n\t\t\t\"type\" in op &&\n\t\t\t\"incrementAmount\" in op &&\n\t\t\top.type === \"increment\" &&\n\t\t\ttypeof op.incrementAmount === \"number\",\n\t\t0xc92 /* invalid increment op format */,\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../src/counter.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/internal\";\nimport type {\n\tIChannelAttributes,\n\tIFluidDataStoreRuntime,\n\tIChannelStorageService,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { MessageType } from \"@fluidframework/driver-definitions/internal\";\nimport { readAndParse } from \"@fluidframework/driver-utils/internal\";\nimport type {\n\tISummaryTreeWithStats,\n\tIRuntimeMessageCollection,\n\tIRuntimeMessagesContent,\n\tISequencedMessageEnvelope,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport type { IFluidSerializer } from \"@fluidframework/shared-object-base/internal\";\nimport {\n\tSharedObject,\n\tcreateSingleBlobSummary,\n} from \"@fluidframework/shared-object-base/internal\";\n\nimport type { ISharedCounter, ISharedCounterEvents } from \"./interfaces.js\";\n\n/**\n * Describes the operation (op) format for incrementing the {@link SharedCounter}.\n */\nexport interface IIncrementOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n}\n\n/**\n * Represents a pending op that has been submitted but not yet ack'd.\n * Includes the messageId that was used when submitting the op.\n */\ninterface IPendingOperation {\n\ttype: \"increment\";\n\tincrementAmount: number;\n\tmessageId: number;\n}\n\n/**\n * @remarks Used in snapshotting.\n */\ninterface ICounterSnapshotFormat {\n\t/**\n\t * The value of the counter.\n\t */\n\tvalue: number;\n}\n\nconst snapshotFileName = \"header\";\n\n/**\n * {@inheritDoc ISharedCounter}\n * @legacy @beta\n */\nexport class SharedCounter\n\textends SharedObject<ISharedCounterEvents>\n\timplements ISharedCounter\n{\n\tpublic constructor(\n\t\tid: string,\n\t\truntime: IFluidDataStoreRuntime,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(id, runtime, attributes, \"fluid_counter_\");\n\t}\n\n\tprivate _value: number = 0;\n\n\t/**\n\t * Tracks pending local ops that have not been ack'd yet.\n\t */\n\tprivate readonly pendingOps: IPendingOperation[] = [];\n\n\t/**\n\t * The next message id to be used when submitting an op.\n\t */\n\tprivate nextPendingMessageId: number = 0;\n\n\t/**\n\t * {@inheritDoc ISharedCounter.value}\n\t */\n\tpublic get value(): number {\n\t\treturn this._value;\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedCounter.increment}\n\t */\n\tpublic increment(incrementAmount: number): void {\n\t\t// Incrementing by floating point numbers will be eventually inconsistent, since the order in which the\n\t\t// increments are applied affects the result. A more-robust solution would be required to support this.\n\t\tif (incrementAmount % 1 !== 0) {\n\t\t\tthrow new Error(\"Must increment by a whole number\");\n\t\t}\n\n\t\tconst op: IIncrementOperation = {\n\t\t\ttype: \"increment\",\n\t\t\tincrementAmount,\n\t\t};\n\t\tconst messageId = this.nextPendingMessageId++;\n\n\t\tthis.incrementCore(incrementAmount);\n\t\t// We don't need to send the op if we are not attached yet.\n\t\tif (this.isAttached()) {\n\t\t\tthis.pendingOps.push({ ...op, messageId });\n\t\t\tthis.submitLocalMessage(op, messageId);\n\t\t}\n\t}\n\n\tprivate incrementCore(incrementAmount: number): void {\n\t\tthis._value += incrementAmount;\n\t\tthis.emit(\"incremented\", incrementAmount, this._value);\n\t}\n\n\t/**\n\t * Create a summary for the counter.\n\t *\n\t * @returns The summary of the current state of the counter.\n\t */\n\tprotected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {\n\t\t// Get a serializable form of data\n\t\tconst content: ICounterSnapshotFormat = {\n\t\t\tvalue: this.value,\n\t\t};\n\n\t\t// And then construct the summary for it\n\t\treturn createSingleBlobSummary(snapshotFileName, JSON.stringify(content));\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.loadCore}\n\t */\n\tprotected async loadCore(storage: IChannelStorageService): Promise<void> {\n\t\tconst content = await readAndParse<ICounterSnapshotFormat>(storage, snapshotFileName);\n\n\t\tthis._value = content.value;\n\t}\n\n\t/**\n\t * Called when the object has disconnected from the delta stream.\n\t */\n\tprotected onDisconnect(): void {}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.processMessagesCore}\n\t */\n\tprotected processMessagesCore(messagesCollection: IRuntimeMessageCollection): void {\n\t\tconst { envelope, local, messagesContent } = messagesCollection;\n\t\tfor (const messageContent of messagesContent) {\n\t\t\tthis.processMessage(envelope, messageContent, local);\n\t\t}\n\t}\n\n\tprivate processMessage(\n\t\tmessageEnvelope: ISequencedMessageEnvelope,\n\t\tmessageContent: IRuntimeMessagesContent,\n\t\tlocal: boolean,\n\t): void {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison\n\t\tif (messageEnvelope.type === MessageType.Operation) {\n\t\t\tconst op = messageContent.contents as IIncrementOperation;\n\n\t\t\t// If the message is local we have already optimistically processed\n\t\t\t// and we should now remove it from this.pendingOps.\n\t\t\t// If the message is from a remote client, we should process it.\n\t\t\tif (local) {\n\t\t\t\tconst pendingOp = this.pendingOps.shift();\n\t\t\t\tconst messageId = messageContent.localOpMetadata;\n\t\t\t\tassert(typeof messageId === \"number\", 0xc8e /* localOpMetadata should be a number */);\n\t\t\t\tassert(\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior\n\t\t\t\t\tpendingOp !== undefined &&\n\t\t\t\t\t\tpendingOp.messageId === messageId &&\n\t\t\t\t\t\tpendingOp.type === op.type &&\n\t\t\t\t\t\tpendingOp.incrementAmount === op.incrementAmount,\n\t\t\t\t\t0xc8f /* local op mismatch */,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tswitch (op.type) {\n\t\t\t\t\tcase \"increment\": {\n\t\t\t\t\t\tthis.incrementCore(op.incrementAmount);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthrow new Error(\"Unknown operation\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * {@inheritdoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}\n\t */\n\tprotected applyStashedOp(op: unknown): void {\n\t\tconst counterOp = op as IIncrementOperation;\n\n\t\t// TODO: Clean up error code linter violations repo-wide.\n\n\t\tassert(counterOp.type === \"increment\", 0x3ec /* Op type is not increment */);\n\n\t\tthis.increment(counterOp.incrementAmount);\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/shared-object-base#SharedObject.rollback}\n\t * @sealed\n\t */\n\tprotected rollback(content: unknown, localOpMetadata: unknown): void {\n\t\tassertIsIncrementOp(content);\n\t\tassert(\n\t\t\ttypeof localOpMetadata === \"number\",\n\t\t\t0xc90 /* localOpMetadata should be a number */,\n\t\t);\n\t\tconst pendingOp = this.pendingOps.pop();\n\t\tassert(\n\t\t\t// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior\n\t\t\tpendingOp !== undefined &&\n\t\t\t\tpendingOp.messageId === localOpMetadata &&\n\t\t\t\tpendingOp.type === content.type &&\n\t\t\t\tpendingOp.incrementAmount === content.incrementAmount,\n\t\t\t0xc91 /* op to rollback mismatch with pending op */,\n\t\t);\n\t\t// To rollback the optimistic increment we can increment by the opposite amount.\n\t\t// This will also emit another incremented event with the opposite amount.\n\t\tthis.incrementCore(-content.incrementAmount);\n\t}\n}\n\nfunction assertIsIncrementOp(op: unknown): asserts op is IIncrementOperation {\n\tassert(\n\t\ttypeof op === \"object\" &&\n\t\t\top !== null &&\n\t\t\t\"type\" in op &&\n\t\t\t\"incrementAmount\" in op &&\n\t\t\top.type === \"increment\" &&\n\t\t\ttypeof op.incrementAmount === \"number\",\n\t\t0xc92 /* invalid increment op format */,\n\t);\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,yBAAyB,CAAC;AACjD,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/counter\";\nexport const pkgVersion = \"2.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,yBAAyB,CAAC;AACjD,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/counter\";\nexport const pkgVersion = \"2.81.0\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/counter",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.81.0",
|
|
4
4
|
"description": "Counter DDS",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -81,27 +81,27 @@
|
|
|
81
81
|
"temp-directory": "nyc/.nyc_output"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@fluidframework/core-interfaces": "~2.
|
|
85
|
-
"@fluidframework/core-utils": "~2.
|
|
86
|
-
"@fluidframework/datastore-definitions": "~2.
|
|
87
|
-
"@fluidframework/driver-definitions": "~2.
|
|
88
|
-
"@fluidframework/driver-utils": "~2.
|
|
89
|
-
"@fluidframework/runtime-definitions": "~2.
|
|
90
|
-
"@fluidframework/shared-object-base": "~2.
|
|
84
|
+
"@fluidframework/core-interfaces": "~2.81.0",
|
|
85
|
+
"@fluidframework/core-utils": "~2.81.0",
|
|
86
|
+
"@fluidframework/datastore-definitions": "~2.81.0",
|
|
87
|
+
"@fluidframework/driver-definitions": "~2.81.0",
|
|
88
|
+
"@fluidframework/driver-utils": "~2.81.0",
|
|
89
|
+
"@fluidframework/runtime-definitions": "~2.81.0",
|
|
90
|
+
"@fluidframework/shared-object-base": "~2.81.0"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
94
94
|
"@biomejs/biome": "~1.9.3",
|
|
95
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
96
|
-
"@fluid-private/stochastic-test-utils": "~2.
|
|
97
|
-
"@fluid-private/test-dds-utils": "~2.
|
|
98
|
-
"@fluid-tools/build-cli": "^0.
|
|
95
|
+
"@fluid-internal/mocha-test-setup": "~2.81.0",
|
|
96
|
+
"@fluid-private/stochastic-test-utils": "~2.81.0",
|
|
97
|
+
"@fluid-private/test-dds-utils": "~2.81.0",
|
|
98
|
+
"@fluid-tools/build-cli": "^0.63.0",
|
|
99
99
|
"@fluidframework/build-common": "^2.0.3",
|
|
100
|
-
"@fluidframework/build-tools": "^0.
|
|
101
|
-
"@fluidframework/container-definitions": "~2.
|
|
102
|
-
"@fluidframework/counter-previous": "npm:@fluidframework/counter@2.
|
|
103
|
-
"@fluidframework/eslint-config-fluid": "~2.
|
|
104
|
-
"@fluidframework/test-runtime-utils": "~2.
|
|
100
|
+
"@fluidframework/build-tools": "^0.63.0",
|
|
101
|
+
"@fluidframework/container-definitions": "~2.81.0",
|
|
102
|
+
"@fluidframework/counter-previous": "npm:@fluidframework/counter@2.80.0",
|
|
103
|
+
"@fluidframework/eslint-config-fluid": "~2.81.0",
|
|
104
|
+
"@fluidframework/test-runtime-utils": "~2.81.0",
|
|
105
105
|
"@microsoft/api-extractor": "7.52.11",
|
|
106
106
|
"@types/mocha": "^10.0.10",
|
|
107
107
|
"@types/node": "^18.19.0",
|
package/src/counter.ts
CHANGED
|
@@ -175,6 +175,7 @@ export class SharedCounter
|
|
|
175
175
|
const messageId = messageContent.localOpMetadata;
|
|
176
176
|
assert(typeof messageId === "number", 0xc8e /* localOpMetadata should be a number */);
|
|
177
177
|
assert(
|
|
178
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
178
179
|
pendingOp !== undefined &&
|
|
179
180
|
pendingOp.messageId === messageId &&
|
|
180
181
|
pendingOp.type === op.type &&
|
|
@@ -221,6 +222,7 @@ export class SharedCounter
|
|
|
221
222
|
);
|
|
222
223
|
const pendingOp = this.pendingOps.pop();
|
|
223
224
|
assert(
|
|
225
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- using ?. could change behavior
|
|
224
226
|
pendingOp !== undefined &&
|
|
225
227
|
pendingOp.messageId === localOpMetadata &&
|
|
226
228
|
pendingOp.type === content.type &&
|
package/src/packageVersion.ts
CHANGED
package/.eslintrc.cjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
extends: [require.resolve("@fluidframework/eslint-config-fluid/strict"), "prettier"],
|
|
8
|
-
parserOptions: {
|
|
9
|
-
project: ["./tsconfig.json", "./src/test/tsconfig.json"],
|
|
10
|
-
},
|
|
11
|
-
};
|