Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
223 commits
Select commit Hold shift + click to select a range
d9d6408
Expose LiveObjects as a plugin
VeskeR Oct 1, 2024
fac8a64
Move `monitorConnectionThenCloseAndFinish` to shared helper
VeskeR Oct 4, 2024
e52665c
Add abstract LiveObject class with base shared functionality for Live…
VeskeR Oct 2, 2024
96049be
Add LiveMap and LiveCounter concrete classes
VeskeR Oct 2, 2024
a63a415
Add LiveObjectsPool class to store pool of live objects
VeskeR Oct 2, 2024
d7211a4
Add LiveObjectsPool to LiveObjects and naive implementation of `getRo…
VeskeR Oct 2, 2024
ae331d9
Implement LiveCounter access API
VeskeR Oct 2, 2024
e5f0d8f
Implement LiveMap access API
VeskeR Oct 2, 2024
ac0ac6c
Merge pull request #1880 from ably/DTP-947/liveobjects-plugin-base
VeskeR Oct 8, 2024
880924d
Merge pull request #1882 from ably/liveobjects/live-object-classes
VeskeR Oct 8, 2024
8783b8b
Merge pull request #1883 from ably/liveobjects/access-api
VeskeR Oct 8, 2024
8efba44
Add STATE_SUBSCRIBE and STATE_PUBLISH channel modes
VeskeR Oct 9, 2024
8146cae
Change internal `fromDeserializedIncludingDependencies` to `makeFromD…
VeskeR Oct 9, 2024
e6e70d9
Add STATE and STATE_SYNC protocol message actions
VeskeR Oct 9, 2024
4f6fb8d
Add HAS_STATE flag
VeskeR Oct 9, 2024
9a691c4
Add StateMessage to LiveObjects plugin
VeskeR Oct 9, 2024
8e1339d
Add support for state messages to ProtocolMessage
VeskeR Oct 9, 2024
59b3aef
Implement `toJSON` method for StateMessage
VeskeR Oct 9, 2024
2dcf298
Implement `toString` method for StateMessage
VeskeR Oct 9, 2024
4b51773
Split Message `decode` function into `decode` and `decodeData`
VeskeR Oct 9, 2024
e8e9472
Implement `decode` method for StateMessage
VeskeR Oct 9, 2024
88e4736
Implement handling of the server-initiated state sync sequence
VeskeR Oct 9, 2024
d8755b3
Add missing properties to LiveMap
VeskeR Oct 10, 2024
1cc2bc2
Implement LiveObjects pool init from state SYNC sequence
VeskeR Oct 10, 2024
1d47d31
Expose EventEmitter class on BaseClient to be used by plugins
VeskeR Oct 10, 2024
0e2c3a0
Implement `LiveObjects.getRoot()` method
VeskeR Oct 10, 2024
d637bd7
Update `getRoot()` to use Promise version of `EventEmitter.once`
VeskeR Oct 22, 2024
318fd76
Add LiveObjectsHelper module for tests
VeskeR Oct 15, 2024
45502e5
Enable `enableChannelState` feature flag for test apps
VeskeR Oct 15, 2024
9483999
Add LiveMap.size() method
VeskeR Oct 17, 2024
687dee9
Refactor live objects test
VeskeR Oct 17, 2024
2526788
Add LiveObjectsHelper to live objects tests
VeskeR Oct 17, 2024
7faa72c
Add more getRoot() tests for LiveObjects
VeskeR Oct 17, 2024
7d4bcd9
Add STATE_SYNC ProtocolMessage test when LiveObjects plugin is not pr…
VeskeR Oct 17, 2024
a0c3b6c
Add initial STATE_SYNC sequence handling tests
VeskeR Oct 17, 2024
3206fe0
Add test getRoot() while STATE_SYNC is in progress
VeskeR Oct 17, 2024
566bf00
Add test for LiveObjects state modes
VeskeR Oct 17, 2024
c3a15ac
Minor changes for slightly better performance and readability
VeskeR Oct 22, 2024
fbf9d42
Fix `decodeMapEntry` call was not awaited in `StateMessage.decode` call
VeskeR Oct 22, 2024
d620d8c
Merge pull request #1887 from ably/DTP-950/handle-initial-state-sync-…
VeskeR Oct 22, 2024
c836ed1
Merge pull request #1890 from ably/DTP-949/init-objects-pool-from-sync
VeskeR Oct 22, 2024
ddadd03
Merge pull request #1891 from ably/DTP-951/implement-get-root
VeskeR Oct 22, 2024
b73a15c
Remove Utils.arrSubtract, as it is preffered to use `arr.filter((x) =…
VeskeR Oct 25, 2024
8e31a6a
Add Timeserial class to LiveObjects plugin
VeskeR Oct 18, 2024
692f6ed
Add ObjectId class to parse object id strings
VeskeR Oct 18, 2024
131fc4e
Preparation for CRDT operations implementation
VeskeR Oct 18, 2024
9b83e94
Implement support for applying incoming operations to LiveMap/LiveCou…
VeskeR Oct 18, 2024
9f98ef6
Preparation for applying incoming state operations
VeskeR Oct 21, 2024
0b646e2
Implement application of incoming state operation messages outside of…
VeskeR Oct 21, 2024
ef54890
Preparation for LiveObjects tests for applying incoming operations
VeskeR Oct 21, 2024
bda102c
Add LiveObjects tests for applying incoming operation messages outsid…
VeskeR Oct 22, 2024
3960852
Update `moduleReport` config with latest bundle info
VeskeR Oct 22, 2024
3ed285d
Add `zeroValue` static method to LiveMap and LiveCounter
VeskeR Oct 25, 2024
b988c35
Fix LiveObjects tests fail due to class name changes with static prop…
VeskeR Oct 30, 2024
0a39b23
Allow `seriesId` to be empty in Timeserial
VeskeR Oct 24, 2024
60e6474
Change seriesId comparison logic for Timeserial
VeskeR Oct 24, 2024
65c3f0f
Use zero-value timeserial if timeserial is missing for MapEntry in a …
VeskeR Oct 24, 2024
7ccfe50
Handle regional timeserials for LiveObjects
VeskeR Oct 24, 2024
81237f3
Merge pull request #1894 from ably/liveobjects/sync-sequence-tests
VeskeR Nov 8, 2024
e1e6cc7
Merge pull request #1898 from ably/liveobjects/fixes
VeskeR Nov 8, 2024
176c863
Merge pull request #1897 from ably/liveobjects/apply-incoming-operations
VeskeR Nov 8, 2024
385e1c8
Merge pull request #1908 from ably/liveobjects/timeserial-fix
VeskeR Nov 8, 2024
ad0311e
Implement buffering and application of operations during a SYNC sequence
VeskeR Oct 24, 2024
a5f8667
Make injecting state messages in LiveObjects tests simpler
VeskeR Oct 24, 2024
d919f8b
Add LiveObjects tests for buffering and flushing operations outside o…
VeskeR Oct 24, 2024
868560c
Apply timeserial dependant operations only if op timeserial is > than…
VeskeR Oct 25, 2024
30d4c9c
Add `deep-equal` package
VeskeR Nov 5, 2024
b40dc9f
Implement direct object subscription for Live Objects
VeskeR Nov 5, 2024
07cafc4
Implement .unsubscribeAll() method on Live Objects
VeskeR Nov 5, 2024
f8fda98
Add LiveObjects subscriptions tests
VeskeR Nov 5, 2024
4bca1c7
Update moduleReport to include `external` field for LiveObjects plugin
VeskeR Nov 5, 2024
82f1271
Merge pull request #1909 from ably/DTP-955/buffer-ops-during-sync
VeskeR Nov 14, 2024
ec59c04
Merge pull request #1912 from ably/liveobjects/timeserials-comparison…
VeskeR Nov 14, 2024
928dea7
Merge pull request #1917 from ably/liveobjects/subscriptions
VeskeR Nov 14, 2024
924eafd
Fix LiveObjects subscription tests were expecting incorrect `deleted`…
VeskeR Nov 22, 2024
f59c459
Refactor scenario tests in LiveObjects tests
VeskeR Nov 22, 2024
63126e2
Add `siteCode` to Timeserial
VeskeR Nov 21, 2024
8ba4b94
Handle site timeserials vector on StateObject
VeskeR Nov 21, 2024
1a828a6
Fix StateMessage.decode not correctly decoding operation.map.entries
VeskeR Nov 22, 2024
86fc932
Refactor decoding/encoding in StateMessage
VeskeR Nov 22, 2024
54d4555
Handle `createOp` field on StateObject messages
VeskeR Nov 22, 2024
245b6a2
Don't use `this` in static methods in StateMessage
VeskeR Nov 22, 2024
3adafa5
Merge pull request #1924 from ably/liveobjects/isolated-create-ops-an…
VeskeR Nov 26, 2024
0b4b1e4
Add LiveObjects access and subscription public API to the `ably.d.ts`
VeskeR Nov 19, 2024
0575e5e
Merge branch 'main' into liveobjects/2024-11-29-merge-main
VeskeR Nov 29, 2024
6876339
Use common `_decodeAndPrepareMessages` for processing of `STATE` and …
VeskeR Oct 25, 2024
6cbe7ed
Apply docstring changes suggested in the code review
VeskeR Nov 29, 2024
483f631
Merge pull request #1928 from ably/liveobjects/read-api-docs
VeskeR Nov 29, 2024
c6f8d2e
Add LiveObjects plugin test to the `package` tests
VeskeR Nov 19, 2024
d59e167
Fix incorrect `moduleResolution` in `tsconfig.json` for package tests
VeskeR Nov 28, 2024
b09f7bf
Merge pull request #1921 from ably/liveobjects/package-test
VeskeR Nov 29, 2024
f4113d8
Add support for user-provided typings for the LiveObjects data structure
VeskeR Nov 19, 2024
73c8abc
Move types required for user-provided LiveObjects typings to ably.d.ts
VeskeR Nov 19, 2024
3938b63
Add tests for user-provided LiveObjects types to the LiveObjects pack…
VeskeR Nov 19, 2024
9988504
Use lexico timeserials and `siteCode` field in StateMessages
VeskeR Nov 27, 2024
40e258d
Merge pull request #1922 from ably/DTP-963/liveobjects-customer-typings
VeskeR Nov 29, 2024
8cdf89e
Merge pull request #1926 from ably/DTP-1078/lexico-timeserials
VeskeR Nov 29, 2024
7da28eb
Merge pull request #1930 from ably/liveobjects/2024-11-29-merge-main
VeskeR Dec 4, 2024
f08222d
Merge pull request #1931 from ably/liveobjects/refactor-state-message…
VeskeR Dec 4, 2024
7927b24
Move `applyStateMessages` to LiveObjects class
VeskeR Dec 4, 2024
c47b8c4
Handle `StateObject.tombstone` and `OBJECT_DELETE` messages
VeskeR Dec 5, 2024
a7df3b6
Update `LiveMap.get` to have `undefined` as a possible return value
VeskeR Dec 6, 2024
f7609ec
GC tombstoned map entries for LiveMap and objects in the global pool
VeskeR Dec 11, 2024
2fac0e0
Merge pull request #1934 from ably/DTP-986/handle-tombstone-and-objec…
VeskeR Jan 9, 2025
74df425
Merge pull request #1937 from ably/DTP-1024/gc-tombstoned-entries-and…
VeskeR Jan 9, 2025
f4073b9
Refactor Message and PresenceMessage payload encoding
VeskeR Dec 12, 2024
a1bf1ef
Expose message encoding functions from Message and on a BaseClient
VeskeR Jan 14, 2025
2b48dff
Refactor `StateMessage` to use message encoding functions exported vi…
VeskeR Jan 14, 2025
195e67a
Add `StateMessage.encode` method
VeskeR Jan 14, 2025
5b365bc
Add `RealtimeChannel.sendState` and mark STATE messages as those that…
VeskeR Jan 14, 2025
f2804e6
Add object-level write API for `LiveMap` and `LiveCounter` to update …
VeskeR Jan 14, 2025
f8563cb
Add tests for object-level write API
VeskeR Jan 15, 2025
78ded6c
Spelling fix
VeskeR Jan 16, 2025
cd96af0
Add `IBufferUtils.sha256` method
VeskeR Jan 15, 2025
3707c67
Add `IBufferUtils.base64UrlEncode` method
VeskeR Jan 15, 2025
ea3fd7a
Add `ObjectId.msTimestamp` property
VeskeR Jan 15, 2025
21f1c26
Add `ObjectId.fromInitialValue` method
VeskeR Jan 15, 2025
c8784a6
Fix incorrect buffer type for `StateValue`
VeskeR Jan 16, 2025
6f5b171
Add `initialValue` and `initialValueEncoding` to `StateMessage`
VeskeR Jan 16, 2025
7fdbe73
Add `StateMessage.encodeInitialValue` method
VeskeR Jan 16, 2025
d9d8c38
Update `LiveObjectsPool.createZeroValueObjectIfNotExists` to also ret…
VeskeR Jan 16, 2025
ee0ff57
Refactor `StateMessage` creation in Live Objects
VeskeR Jan 16, 2025
5d5874d
Move `getTimestamp` and related methods from `Auth` to `BaseClient`
VeskeR Jan 16, 2025
5b70e79
Add object-level write API for LiveMap and LiveCounter creation
VeskeR Jan 16, 2025
77e0c3f
Add tests for LiveMap/LiveCounter creation
VeskeR Jan 16, 2025
4a33d69
Update minimal bundle size
VeskeR Jan 16, 2025
fcf5e54
Set channel serial when receiving `STATE` message
VeskeR Jan 24, 2025
a7a160d
Add tests for RTL4c1 and RTL15b
VeskeR Jan 24, 2025
210af2d
Merge pull request #1961 from ably/DTP-1121/update-channel-serial-on-…
VeskeR Jan 24, 2025
8d6fb4e
Merge pull request #1948 from ably/liveobjects/object-mutation-api
VeskeR Jan 30, 2025
ae655f1
Add `IBufferUtils.concat` method
VeskeR Jan 30, 2025
109fefb
Encode `initialValue` for StateMessage based on the `useBinaryProtoco…
VeskeR Jan 30, 2025
6ea31da
Fix `StateMessage.encodeInitialValue` incorrectly encoded initial val…
VeskeR Jan 30, 2025
5cfbc9b
Improve comments about counter/map creation
VeskeR Jan 31, 2025
0e63215
Merge pull request #1950 from ably/DTP-1138/map-counter-creates
VeskeR Jan 31, 2025
e031f01
Add Batch write API for LiveObjects
VeskeR Jan 16, 2025
53d07ff
Surface client error when user has not attached to a channel with sta…
VeskeR Jan 22, 2025
a73e596
Merge pull request #1951 from ably/DTP-1035/batch-write-api
VeskeR Jan 31, 2025
a67ef64
Merge pull request #1956 from ably/DTP-948/error-wrong-state-mode-attach
VeskeR Jan 31, 2025
702420f
Fix fake object id functions in live objects helper
VeskeR Jan 29, 2025
9ef65e6
Fix `primitiveKeyData` sample data for was modified by some live obje…
VeskeR Jan 29, 2025
dc90742
Fix flaky live objects tests that relied on STATE/STATE_SYNC messages…
VeskeR Jan 29, 2025
98d66e2
Refactor `LiveObjects` to maintain internal state sync state
VeskeR Jan 31, 2025
cf6f5fd
Expose state sync events on `LiveObjects` via public API
VeskeR Jan 23, 2025
c00e9ab
Refactor `LiveObject` subscription events
VeskeR Jan 23, 2025
3c40056
Emit lifecycle events on `LiveObject`
VeskeR Jan 23, 2025
de71cef
Refactor maximum size of messages exceeded error message
VeskeR Jan 27, 2025
e6aa40e
Add missing `helper.recordPrivateApi` calls to live objects tests
VeskeR Jan 27, 2025
85d988c
Update `Utils.dataSizeBytes` function to include numbers, booleans an…
VeskeR Jan 27, 2025
2b60024
Apply `ConnectionDetails.maxMessageSize` limit when publishing state …
VeskeR Jan 27, 2025
d0f06b4
Merge pull request #1964 from ably/DTP-1147/fix-flaky-liveobjects-tests
VeskeR Feb 7, 2025
81e1156
Merge pull request #1958 from ably/DTP-1034/liveobjects-lifecycle-events
VeskeR Feb 11, 2025
2f5d208
Merge pull request #1963 from ably/DTP-1118/apply-maxMessageSize-for-…
VeskeR Feb 11, 2025
d50ea2d
Fix test failures
VeskeR Feb 12, 2025
b23d31c
Refactor `SharedHelper.restTestOnJsonMsgpack`
VeskeR Jan 31, 2025
48cb5ef
Refactor `SharedHelper.testOnAllTransports` function
VeskeR Feb 12, 2025
9be2e53
Run LiveObjects tests on all transports and protocols (MsgPack and JSON)
VeskeR Jan 31, 2025
bf842fa
Use more specific error codes for LiveObjects errors
VeskeR Feb 12, 2025
922d0a9
Fix LiveObjects docstrings
VeskeR Feb 12, 2025
f2dcf8a
Add type declarations to `ably.d.ts` for Live Objects write, batch an…
VeskeR Feb 12, 2025
b2d8c67
Merge pull request #1968 from ably/liveobjects/fix-tests
VeskeR Feb 12, 2025
bb7d211
Merge pull request #1965 from ably/DTP-1096/msgpack-json-encodings-tests
VeskeR Feb 13, 2025
19ab536
Merge pull request #1967 from ably/liveobjects/update-types
VeskeR Feb 13, 2025
6fc1702
Merge pull request #1966 from ably/PUB-1011/update-error-codes
VeskeR Feb 13, 2025
fcceb2c
Update Live Objects README section
VeskeR Feb 13, 2025
007477d
Refactor channel modes tests
VeskeR Feb 25, 2025
717ff16
Implement LiveObjects behavior under different channel states
VeskeR Feb 25, 2025
22f980d
Merge pull request #1969 from ably/PUB-1039/update-readme
VeskeR Feb 26, 2025
efdce88
Merge pull request #1972 from ably/PUB-1030/liveobjects-channel-state
VeskeR Feb 26, 2025
dff82cd
Refactor live objects tests to reuse existing methods
VeskeR Mar 4, 2025
24aba84
Add enumeration API to LiveMap and BatchContextLiveMap
VeskeR Mar 4, 2025
b7e3887
Merge pull request #1981 from ably/PUB-1235/enumerate-map-keys
VeskeR Mar 5, 2025
af21938
Rename "LiveObjects API" to "Objects API"
VeskeR Mar 5, 2025
706d4ba
Rename "LiveObjects" file names to just "Objects"
VeskeR Mar 5, 2025
1aa89e3
Update bitwise value for `HAS_STATE` flag
VeskeR Mar 20, 2025
9d98638
Merge pull request #1982 from ably/PUB-1242/rename-to-objects
VeskeR Mar 26, 2025
fbccd00
Merge pull request #1985 from ably/PUB-1529/update-has_state
VeskeR Mar 26, 2025
bb41379
Change Counter update object to have `amount` property instead of `inc`
VeskeR Mar 26, 2025
e2b6b6f
Merge pull request #1991 from ably/PUB-1540/change-counter-update-object
VeskeR Mar 27, 2025
55977dd
Replace internal usage of "state" term with "objects" for LiveObjects…
VeskeR Mar 27, 2025
8846a8b
Change `statemessage.ts` filename to `objectmessage.ts`
VeskeR Mar 27, 2025
84c1643
Don't use server side terminology and knowledge regarding timeserials…
VeskeR Mar 27, 2025
fef0155
Add `@experimental` tags to LiveObjects methods
VeskeR Apr 9, 2025
5f9da2c
Infer key name of the LiveMap in its direct subscription update object
VeskeR Apr 9, 2025
44b9f75
Merge pull request #1992 from ably/PUB-1539/rename-internal-state-ter…
VeskeR Apr 9, 2025
df9b96f
Merge pull request #1993 from ably/liveobjects/dont-use-serverside-terms
VeskeR Apr 9, 2025
2689b47
Update ably-js objects tests to use new REST API for Objects
VeskeR Mar 26, 2025
291a2a4
Merge pull request #1995 from ably/PUB-1094/infer-key-in-map-update
VeskeR Apr 10, 2025
41c0fa0
Merge pull request #1996 from ably/PUB-1580/add-experimental-tags
VeskeR Apr 15, 2025
319d33c
Merge pull request #1990 from ably/PUB-1530/update-rest-api
VeskeR Apr 15, 2025
12b84ab
Merge commit '1d6483a' into liveobjects/merge-main
VeskeR Apr 16, 2025
2a920d2
Merge commit '494500f' into liveobjects/merge-main
VeskeR Apr 16, 2025
bcc0d09
Merge commit '806163b' into liveobjects/merge-main
VeskeR Apr 16, 2025
4a51ccd
`BaseMessage.strMsg` should not print undefined data
VeskeR Apr 16, 2025
b95ab1f
Replace `deep-equal` with `dequal` package
VeskeR Apr 17, 2025
8bfdce7
Update LiveObjects docs link in README
VeskeR Apr 17, 2025
217be89
Merge pull request #2011 from ably/liveobjects/fix-deep-equal-in-brow…
lawrence-forooghian Apr 17, 2025
fdefe2c
Merge pull request #2006 from ably/liveobjects/merge-main
VeskeR Apr 17, 2025
a9719c6
Merge pull request #2012 from ably/liveobjects/update-docs-link
VeskeR Apr 17, 2025
895ead7
Merge branch 'main' into liveobjects/merge-main-2025-04-17
VeskeR Apr 17, 2025
caa8ba1
Merge pull request #2014 from ably/liveobjects/merge-main-2025-04-17
VeskeR Apr 17, 2025
335e808
Update test for RTL4c1 to not set `channelSerial` externally
VeskeR Apr 28, 2025
bc8d2cf
Add `ANNOTATION` to RTL15b test
VeskeR Apr 28, 2025
5599ad8
Add comment for Utils.dataSizeBytes to explain its return values
VeskeR Apr 28, 2025
95be48c
Update spelling in ably.d.ts
VeskeR Apr 28, 2025
bd3873c
Rename `ObjectsTypes` to `AblyObjectsTypes`
VeskeR Apr 28, 2025
0643266
Use `"strict": true` in package tests
VeskeR Apr 28, 2025
73bcc1d
Move `AblyObjectsTypes` definition to `index-objects` file in package…
VeskeR Apr 28, 2025
92c7cfc
Clarify that user provided typings for Objects don't provide runtime …
VeskeR Apr 28, 2025
5106329
Revert "Fix incorrect `moduleResolution` in `tsconfig.json` for packa…
VeskeR Apr 28, 2025
c47738c
Merge pull request #2017 from ably/liveobjects/fixes
VeskeR Apr 29, 2025
44aae8e
Remove StateValue from ObjectMessage
VeskeR May 6, 2025
540bf1e
Merge pull request #2026 from ably/PUB-1666/remove-state-value
VeskeR May 7, 2025
9e225aa
Refactor OBJECT_SYNC sequence tests
VeskeR May 5, 2025
567d58c
Remove `ObjectMessage.channel`
VeskeR May 6, 2025
18a0684
Handle `MapEntry.data` could be missing in the map entry
VeskeR May 7, 2025
882c592
Fix `ObjectMessage.encode` should not be async
VeskeR May 7, 2025
d565623
Add nonce and initial value ObjectMessage message size tests
VeskeR May 7, 2025
d2f79e0
Fix "Data type is unsupported" errors for Object message encoding
VeskeR May 7, 2025
b777e50
Fix object references were reset on channel detach/fail and reattach …
VeskeR May 8, 2025
671243c
Remove `enableChannelState` feature flag
VeskeR May 8, 2025
a238857
Objects Write API should throw an error when "echoMessages" client op…
VeskeR May 8, 2025
d440c47
Merge pull request #2028 from ably/liveobjects/fixes
VeskeR May 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ module.exports = function (grunt) {
});
});

grunt.registerTask('build', ['webpack:all', 'build:browser', 'build:node', 'build:push']);
grunt.registerTask('build', ['webpack:all', 'build:browser', 'build:node', 'build:push', 'build:objects']);

grunt.registerTask('all', ['build', 'requirejs']);

Expand Down Expand Up @@ -138,9 +138,26 @@ module.exports = function (grunt) {
});
});

grunt.registerTask('build:objects', function () {
var done = this.async();

Promise.all([
esbuild.build(esbuildConfig.objectsPluginConfig),
esbuild.build(esbuildConfig.objectsPluginCdnConfig),
esbuild.build(esbuildConfig.minifiedObjectsPluginCdnConfig),
])
.then(() => {
done(true);
})
.catch((err) => {
done(err);
});
});

grunt.registerTask('test:webserver', 'Launch the Mocha test web server on http://localhost:3000/', [
'build:browser',
'build:push',
'build:objects',
'checkGitSubmodules',
'mocha:webserver',
]);
Expand Down
328 changes: 327 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,333 @@ const client = new Ably.Rest({

The Push plugin is developed as part of the Ably client library, so it is available for the same versions as the Ably client library itself. It also means that it follows the same semantic versioning rules as they were defined for [the Ably client library](#for-browsers). For example, to lock into a major or minor version of the Push plugin, you can specify a specific version number such as https://cdn.ably.com/lib/push.umd.min-2.js for all v2._ versions, or https://cdn.ably.com/lib/push.umd.min-2.4.js for all v2.4._ versions, or you can lock into a single release with https://cdn.ably.com/lib/push.umd.min-2.4.0.js. Note you can load the non-minified version by omitting `.min` from the URL such as https://cdn.ably.com/lib/push.umd-2.js.

For more information on publishing push notifcations over Ably, see the [Ably push documentation](https://ably.com/docs/push).
For more information on publishing push notifications over Ably, see the [Ably push documentation](https://ably.com/docs/push).

### LiveObjects

#### Using the Objects plugin

LiveObjects functionality is supported for Realtime clients via the Objects plugin. In order to use Objects on a channel, you must pass in the plugin via client options.

```typescript
import * as Ably from 'ably';
import Objects from 'ably/objects';

const client = new Ably.Realtime({
...options,
plugins: { Objects },
});
```

Objects plugin also works with the [Modular variant](#modular-tree-shakable-variant) of the library.

Alternatively, you can load the Objects plugin directly in your HTML using `script` tag (in case you can't use a package manager):

```html
<script src="https://cdn.ably.com/lib/objects.umd.min-2.js"></script>
```

When loaded this way, the Objects plugin will be available on the global object via the `AblyObjectsPlugin` property, so you will need to pass it to the Ably instance as follows:

```typescript
const client = new Ably.Realtime({
...options,
plugins: { Objects: AblyObjectsPlugin },
});
```

The Objects plugin is developed as part of the Ably client library, so it is available for the same versions as the Ably client library itself. It also means that it follows the same semantic versioning rules as they were defined for [the Ably client library](#for-browsers). For example, to lock into a major or minor version of the Objects plugin, you can specify a specific version number such as https://cdn.ably.com/lib/objects.umd.min-2.js for all v2._ versions, or https://cdn.ably.com/lib/objects.umd.min-2.4.js for all v2.4._ versions, or you can lock into a single release with https://cdn.ably.com/lib/objects.umd.min-2.4.0.js. Note you can load the non-minified version by omitting `.min` from the URL such as https://cdn.ably.com/lib/objects.umd-2.js.

For more information about the LiveObjects product, see the [Ably LiveObjects documentation](https://ably.com/docs/liveobjects).

#### Objects Channel Modes

To use the Objects on a channel, clients must attach to a channel with the correct channel mode:

- `object_subscribe` - required to retrieve Objects for a channel
- `object_publish` - required to create new and modify existing Objects on a channel

```typescript
const client = new Ably.Realtime({
// authentication options
...options,
plugins: { Objects },
});
const channelOptions = { modes: ['object_subscribe', 'object_publish'] };
const channel = client.channels.get('my_objects_channel', channelOptions);
const objects = channel.objects;
```

The authentication token must include corresponding capabilities for the client to interact with Objects.

#### Getting the Root Object

The root object represents the top-level entry point for objects within a channel. It gives access to all other nested objects.

```typescript
const root = await objects.getRoot();
```

The root object is a `LiveMap` instance and serves as the starting point for storing and organizing Objects on a channel.

#### Object Types

LiveObjects currently supports two primary data structures; `LiveMap` and `LiveCounter`.

`LiveMap` - A key/value map data structure, similar to a JavaScript `Map`, where all changes are synchronized across clients in realtime. It enables you to store primitive values and other objects, enabling composability.

You can use `LiveMap` as follows:

```typescript
// root object is a LiveMap
const root = await objects.getRoot();

// you can read values for a key with .get
root.get('foo');
root.get('bar');

// get a number of key/value pairs in a map with .size
root.size();

// iterate over keys/values in a map
for (const [key, value] of root.entries()) {
/**/
}
for (const key of root.keys()) {
/**/
}
for (const value of root.values()) {
/**/
}

// set keys on a map with .set
// different data types are supported
await root.set('foo', 'Alice');
await root.set('bar', 1);
await root.set('baz', true);
await root.set('qux', new Uint8Array([21, 31]));
// as well as other objects
const counter = await objects.createCounter();
await root.set('quux', counter);

// and you can remove keys with .remove
await root.remove('name');
```

`LiveCounter` - A counter that can be incremented or decremented and is synchronized across clients in realtime

You can use `LiveCounter` as follows:

```typescript
const counter = await objects.createCounter();

// you can get current value of a counter with .value
counter.value();

// and change its value with .increment or .decrement
await counter.increment(5);
await counter.decrement(2);
```

#### Subscribing to Updates

Subscribing to updates on objects enables you to receive changes made by other clients in realtime. Since multiple clients may modify the same objects, subscribing ensures that your application reacts to external updates as soon as they are received.

Additionally, mutation methods such as `LiveMap.set`, `LiveCounter.increment`, and `LiveCounter.decrement` do not directly edit the current state of the object locally. Instead, they send the intended operation to the Ably system, and the change is applied to the local object only when the corresponding realtime operation is echoed back to the client. This means that the state you retrieve immediately after a mutation may not reflect the latest updates yet.

You can subscribe to updates on all objects using subscription listeners as follows:

```typescript
const root = await objects.getRoot();

// subscribe to updates on a LiveMap
root.subscribe((update: LiveMapUpdate) => {
console.log('LiveMap "name" key:', root.get('name')); // can read the current value for a key in a map inside this callback
console.log('LiveMap update details:', update); // and can get update details from the provided update object
});

// subscribe to updates on a LiveCounter
const counter = await objects.createCounter();
counter.subscribe((update: LiveCounterUpdate) => {
console.log('LiveCounter new value:', counter.value()); // can read the current value of the counter inside this callback
console.log('LiveCounter update details:', update); // and can get update details from the provided update object
});

// perform operations on LiveMap and LiveCounter
await root.set('name', 'Alice');
// LiveMap "name" key: Alice
// LiveMap update details: { update: { name: 'updated' } }

await root.remove('name');
// LiveMap "name" key: undefined
// LiveMap update details: { update: { name: 'removed' } }

await counter.increment(5);
// LiveCounter new value: 5
// LiveCounter update details: { update: { amount: 5 } }

await counter.decrement(2);
// LiveCounter new value: 3
// LiveCounter update details: { update: { amount: -2 } }
```

You can deregister subscription listeners as follows:

```typescript
// use dedicated unsubscribe function from the .subscribe call
const { unsubscribe } = root.subscribe(() => {});
unsubscribe();

// call .unsubscribe with a listener reference
const listener = () => {};
root.subscribe(listener);
root.unsubscribe(listener);

// deregister all listeners using .unsubscribeAll
root.unsubscribeAll();
```

#### Creating New Objects

New `LiveMap` and `LiveCounter` objects can be created as follows:

```typescript
const counter = await objects.createCounter(123); // with optional initial counter value
const map = await objects.createMap({ key: 'value' }); // with optional initial map entries
```

To persist them on a channel and share them between clients, they must be assigned to a parent `LiveMap` that is connected to the root object through the object hierarchy:

```typescript
const root = await objects.getRoot();

const counter = await objects.createCounter();
const map = await objects.createMap({ counter });
const outerMap = await objects.createMap({ map });

await root.set('outerMap', outerMap);

// resulting structure:
// root (LiveMap)
// └── outerMap (LiveMap)
// └── map (LiveMap)
// └── counter (LiveCounter)
```

#### Batch Operations

Batching enables multiple operations to be grouped into a single channel message that is sent to the Ably service. This guarantees that all changes are applied atomically.

Within a batch callback, the `BatchContext` instance provides wrapper objects around regular `LiveMap` and `LiveCounter` objects with a synchronous API for storing changes in the batch context.

```typescript
await objects.batch((ctx) => {
const root = ctx.getRoot();

root.set('foo', 'bar');
root.set('baz', 42);

const counter = root.get('counter');
counter.increment(5);

// batched operations are sent to the Ably service when the batch callback returns
});
```

#### Lifecycle Events

LiveObjects emit events that allow you to monitor objects' lifecycle changes, such as synchronization progress and object deletions.

**Synchronization Events** - the `syncing` and `synced` events notify when the local Objects state on a client is being synchronized with the Ably service. These events can be useful for displaying loading indicators, preventing user edits during synchronization, or triggering application logic when the data was loaded for the first time.

```typescript
objects.on('syncing', () => {
console.log('Objects are syncing...');
// Example: Show a loading indicator
});

objects.on('synced', () => {
console.log('Objects have been synced.');
// Example: Hide loading indicator
});
```

**Object Deletion Events** - objects that have been orphaned for a long period (i.e., not connected to the object tree by being set as a key in a map accessible from the root map object) will eventually be deleted. Once an object is deleted, it can no longer be interacted with. You should avoid accessing its data or trying to update its value and you should remove all references to the deleted object in your application.

```typescript
const root = await objects.getRoot();
const counter = root.get('counter');

counter.on('deleted', () => {
console.log('Object has been deleted.');
// Example: Remove references to the object from the application
});
```

To unsubscribe from lifecycle events:

```typescript
// same API for channel.objects and LiveObject instances
// use dedicated off function from the .on call
const { off } = objects.on('synced', () => {});
off();

// call .off with an event name and a listener reference
const listener = () => {};
objects.on('synced', listener);
objects.off('synced', listener);

// deregister all listeners using .offAll
objects.offAll();
```

#### Typing Objects

You can provide your own TypeScript typings for Objects by providing a globally defined `AblyObjectsTypes` interface.

```typescript
// file: ably.config.d.ts
import { LiveCounter, LiveMap } from 'ably';

type MyCustomRoot = {
map: LiveMap<{
foo: string;
counter: LiveCounter;
}>;
};

declare global {
export interface AblyObjectsTypes {
root: MyCustomRoot;
}
}
```

Note that using TypeScript typings for Objects does not provide runtime type checking; instead, it enables code completion and editor hints (if supported by your IDE) when interacting with the Objects API:

```typescript
const root = await objects.getRoot(); // uses types defined by global AblyObjectsTypes interface by default

const map = root.get('map'); // LiveMap<{ foo: string; counter: LiveCounter }>
map.set('foo', 1); // TypeError
map.get('counter').value(); // autocompletion for counter method names
```

You can also provide typings for the channel Objects when calling the `objects.getRoot` method, allowing you to have different typings for different channels:

```typescript
type ReactionsRoot = {
hearts: LiveCounter;
likes: LiveCounter;
};

type PollsRoot = {
currentPoll: LiveMap;
};

const reactionsRoot = await reactionsChannel.objects.getRoot<ReactionsRoot>();
const pollsRoot = await pollsChannel.objects.getRoot<PollsRoot>();
```

## Delta Plugin

Expand Down
Loading
Loading