Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/plugins/liveobjects/batchcontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class BatchContext {
}

getRoot<T extends API.LiveMapType = API.DefaultRoot>(): BatchContextLiveMap<T> {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();
this.throwIfClosed();
return this.getWrappedObject(ROOT_OBJECT_ID) as BatchContextLiveMap<T>;
}
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/liveobjects/batchcontextlivecounter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ export class BatchContextLiveCounter {
}

value(): number {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();
this._batchContext.throwIfClosed();
return this._counter.value();
}

increment(amount: number): void {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
this._batchContext.throwIfClosed();
const stateMessage = LiveCounter.createCounterIncMessage(this._liveObjects, this._counter.getObjectId(), amount);
this._batchContext.queueStateMessage(stateMessage);
}

decrement(amount: number): void {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
this._batchContext.throwIfClosed();
// do an explicit type safety check here before negating the amount value,
// so we don't unintentionally change the type sent by a user
Expand Down
8 changes: 4 additions & 4 deletions src/plugins/liveobjects/batchcontextlivemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class BatchContextLiveMap<T extends API.LiveMapType> {
) {}

get<TKey extends keyof T & string>(key: TKey): T[TKey] | undefined {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();
this._batchContext.throwIfClosed();
const value = this._map.get(key);
if (value instanceof LiveObject) {
Expand All @@ -23,20 +23,20 @@ export class BatchContextLiveMap<T extends API.LiveMapType> {
}

size(): number {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();
this._batchContext.throwIfClosed();
return this._map.size();
}

set<TKey extends keyof T & string>(key: TKey, value: T[TKey]): void {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
this._batchContext.throwIfClosed();
const stateMessage = LiveMap.createMapSetMessage(this._liveObjects, this._map.getObjectId(), key, value);
this._batchContext.queueStateMessage(stateMessage);
}

remove<TKey extends keyof T & string>(key: TKey): void {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
this._batchContext.throwIfClosed();
const stateMessage = LiveMap.createMapRemoveMessage(this._liveObjects, this._map.getObjectId(), key);
this._batchContext.queueStateMessage(stateMessage);
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/liveobjects/livecounter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class LiveCounter extends LiveObject<LiveCounterData, LiveCounterUpdate>
}

value(): number {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();
return this._dataRef.data;
}

Expand All @@ -137,7 +137,7 @@ export class LiveCounter extends LiveObject<LiveCounterData, LiveCounterUpdate>
* @returns A promise which resolves upon receiving the ACK message for the published operation message.
*/
async increment(amount: number): Promise<void> {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
const stateMessage = LiveCounter.createCounterIncMessage(this._liveObjects, this.getObjectId(), amount);
return this._liveObjects.publish([stateMessage]);
}
Expand All @@ -146,7 +146,7 @@ export class LiveCounter extends LiveObject<LiveCounterData, LiveCounterUpdate>
* An alias for calling {@link LiveCounter.increment | LiveCounter.increment(-amount)}
*/
async decrement(amount: number): Promise<void> {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
// do an explicit type safety check here before negating the amount value,
// so we don't unintentionally change the type sent by a user
if (typeof amount !== 'number' || !isFinite(amount)) {
Expand Down
8 changes: 4 additions & 4 deletions src/plugins/liveobjects/livemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
*/
// force the key to be of type string as we only allow strings as key in a map
get<TKey extends keyof T & string>(key: TKey): T[TKey] | undefined {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();

if (this.isTombstoned()) {
return undefined as T[TKey];
Expand Down Expand Up @@ -305,7 +305,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
}

size(): number {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();

let size = 0;
for (const value of this._dataRef.data.values()) {
Expand Down Expand Up @@ -341,7 +341,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
* @returns A promise which resolves upon receiving the ACK message for the published operation message.
*/
async set<TKey extends keyof T & string>(key: TKey, value: T[TKey]): Promise<void> {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
const stateMessage = LiveMap.createMapSetMessage(this._liveObjects, this.getObjectId(), key, value);
return this._liveObjects.publish([stateMessage]);
}
Expand All @@ -356,7 +356,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
* @returns A promise which resolves upon receiving the ACK message for the published operation message.
*/
async remove<TKey extends keyof T & string>(key: TKey): Promise<void> {
this._liveObjects.throwIfMissingStatePublishMode();
this._liveObjects.throwIfInvalidWriteApiConfiguration();
const stateMessage = LiveMap.createMapRemoveMessage(this._liveObjects, this.getObjectId(), key);
return this._liveObjects.publish([stateMessage]);
}
Expand Down
12 changes: 6 additions & 6 deletions src/plugins/liveobjects/liveobject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export abstract class LiveObject<
}

subscribe(listener: (update: TUpdate) => void): SubscribeResponse {
this._liveObjects.throwIfMissingStateSubscribeMode();
this._liveObjects.throwIfInvalidAccessApiConfiguration();

this._subscriptions.on(LiveObjectSubscriptionEvent.updated, listener);

Expand All @@ -89,7 +89,7 @@ export abstract class LiveObject<
}

unsubscribe(listener: (update: TUpdate) => void): void {
// can allow calling this public method without checking for state modes on the channel as the result of this method is not dependant on them
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.

// current implementation of the EventEmitter will remove all listeners if .off is called without arguments or with nullish arguments.
// or when called with just an event argument, it will remove all listeners for the event.
Expand All @@ -102,12 +102,12 @@ export abstract class LiveObject<
}

unsubscribeAll(): void {
// can allow calling this public method without checking for state modes on the channel as the result of this method is not dependant on them
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.
this._subscriptions.off(LiveObjectSubscriptionEvent.updated);
}

on(event: LiveObjectLifecycleEvent, callback: LiveObjectLifecycleEventCallback): OnLiveObjectLifecycleEventResponse {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.
this._lifecycleEvents.on(event, callback);

const off = () => {
Expand All @@ -118,7 +118,7 @@ export abstract class LiveObject<
}

off(event: LiveObjectLifecycleEvent, callback: LiveObjectLifecycleEventCallback): void {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.

// prevent accidentally calling .off without any arguments on an EventEmitter and removing all callbacks
if (this._client.Utils.isNil(event) && this._client.Utils.isNil(callback)) {
Expand All @@ -129,7 +129,7 @@ export abstract class LiveObject<
}

offAll(): void {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.
this._lifecycleEvents.off();
}

Expand Down
33 changes: 19 additions & 14 deletions src/plugins/liveobjects/liveobjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class LiveObjects {
* This is useful when working with LiveObjects on multiple channels with different underlying data.
*/
async getRoot<T extends API.LiveMapType = API.DefaultRoot>(): Promise<LiveMap<T>> {
this.throwIfMissingStateSubscribeMode();
this.throwIfInvalidAccessApiConfiguration();

// if we're not synced yet, wait for SYNC sequence to finish before returning root
if (this._state !== LiveObjectsState.synced) {
Expand All @@ -85,7 +85,7 @@ export class LiveObjects {
* Provides access to the synchronous write API for LiveObjects that can be used to batch multiple operations together in a single channel message.
*/
async batch(callback: BatchCallback): Promise<void> {
this.throwIfMissingStatePublishMode();
this.throwIfInvalidWriteApiConfiguration();

const root = await this.getRoot();
const context = new BatchContext(this, root);
Expand All @@ -107,7 +107,7 @@ export class LiveObjects {
* @returns A promise which resolves upon receiving the ACK message for the published operation message. A promise is resolved with an object containing provided data.
*/
async createMap<T extends API.LiveMapType>(entries?: T): Promise<LiveMap<T>> {
this.throwIfMissingStatePublishMode();
this.throwIfInvalidWriteApiConfiguration();

const stateMessage = await LiveMap.createMapCreateMessage(this, entries);
const objectId = stateMessage.operation?.objectId!;
Expand Down Expand Up @@ -139,7 +139,7 @@ export class LiveObjects {
* @returns A promise which resolves upon receiving the ACK message for the published operation message. A promise is resolved with an object containing provided data.
*/
async createCounter(count?: number): Promise<LiveCounter> {
this.throwIfMissingStatePublishMode();
this.throwIfInvalidWriteApiConfiguration();

const stateMessage = await LiveCounter.createCounterCreateMessage(this, count);
const objectId = stateMessage.operation?.objectId!;
Expand All @@ -162,7 +162,7 @@ export class LiveObjects {
}

on(event: LiveObjectsEvent, callback: LiveObjectsEventCallback): OnLiveObjectsEventResponse {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.
this._eventEmitterPublic.on(event, callback);

const off = () => {
Expand All @@ -173,7 +173,7 @@ export class LiveObjects {
}

off(event: LiveObjectsEvent, callback: LiveObjectsEventCallback): void {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.

// prevent accidentally calling .off without any arguments on an EventEmitter and removing all callbacks
if (this._client.Utils.isNil(event) && this._client.Utils.isNil(callback)) {
Expand All @@ -184,7 +184,7 @@ export class LiveObjects {
}

offAll(): void {
// we don't require any specific channel mode to be set to call this public method
// this public API method can be called without specific configuration, so checking for invalid settings is unnecessary.
this._eventEmitterPublic.off();
}

Expand Down Expand Up @@ -284,11 +284,8 @@ export class LiveObjects {

case 'detached':
case 'failed':
// TODO: do something
break;

case 'suspended':
// TODO: do something
this._liveObjectsPool.reset();
this._syncLiveObjectsDataPool.reset();
break;
}
}
Expand Down Expand Up @@ -322,15 +319,17 @@ export class LiveObjects {
/**
* @internal
*/
throwIfMissingStateSubscribeMode(): void {
throwIfInvalidAccessApiConfiguration(): void {
this._throwIfMissingChannelMode('state_subscribe');
this._throwIfInChannelState(['detached', 'failed']);
}

/**
* @internal
*/
throwIfMissingStatePublishMode(): void {
throwIfInvalidWriteApiConfiguration(): void {
this._throwIfMissingChannelMode('state_publish');
this._throwIfInChannelState(['detached', 'failed', 'suspended']);
}

private _startNewSync(syncId?: string, syncCursor?: string): void {
Expand Down Expand Up @@ -493,4 +492,10 @@ export class LiveObjects {
this._eventEmitterPublic.emit(event);
}
}

private _throwIfInChannelState(channelState: API.ChannelState[]): void {
if (channelState.includes(this._channel.state)) {
throw this._client.ErrorInfo.fromValues(this._channel.invalidStateError());
}
}
}
Loading
Loading