@clockworkdog/cogs-client 2.3.0 → 2.4.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/README.md CHANGED
@@ -112,7 +112,7 @@ Initialize a [CogsConnection](https://clockwork-dog.github.io/cogs-client-lib/in
112
112
  ```ts
113
113
  let connected = false;
114
114
 
115
- import manifest from './cogs-plugin-manifest.js'; // Requires `"allowJs": true` in `tsconfig.json`
115
+ import * as manifest from './cogs-plugin-manifest.js'; // Requires `"allowJs": true` in `tsconfig.json`
116
116
 
117
117
  const cogsConnection = new CogsConnection(manifest);
118
118
  cogsConnection.addEventListener('open', () => {
@@ -147,6 +147,29 @@ function sendPortUpdateToCogs() {
147
147
  }
148
148
  ```
149
149
 
150
+ You can save arbitrary data to COGS which will be restored when reconnecting with COGS:
151
+
152
+ ```ts
153
+ const cogsConnection = new CogsConnection(manifest, {
154
+ // Initial items in the store
155
+ 'my-key': { foo: 0, bar: '' }
156
+ });
157
+
158
+ // Update the store
159
+ cogsConnection.store.setItems({ 'my-key': { foo: 1, bar: 'two' } });
160
+
161
+ // Get item from data store
162
+ cogsConnection.store.items.getItem('my-key')
163
+
164
+ // Listen for data changes
165
+ cogsConnection.store.addEventListener('item', ({ key, value }) => {
166
+ console.log(key, 'item changed:', value);
167
+ });
168
+ cogsConnection.store.addEventListener('items', ({ items }) => {
169
+ console.log('items changed:', items);
170
+ });
171
+ ```
172
+
150
173
  ### Support audio actions
151
174
 
152
175
  Add `audio` to `cogs-plugin-manifest.js`:
@@ -5,7 +5,10 @@ import AllMediaClipStatesMessage from './types/AllMediaClipStatesMessage';
5
5
  import { CogsPluginManifest, PluginManifestEventJson } from './types/CogsPluginManifest';
6
6
  import * as ManifestTypes from './types/ManifestTypes';
7
7
  import { DeepReadonly } from './types/utils';
8
- export default class CogsConnection<Manifest extends CogsPluginManifest> {
8
+ import DataStore from './DataStore';
9
+ export default class CogsConnection<Manifest extends CogsPluginManifest, DataT extends {
10
+ [key: string]: unknown;
11
+ } = Record<never, never>> {
9
12
  readonly manifest: Manifest;
10
13
  private websocket;
11
14
  private eventTarget;
@@ -35,6 +38,10 @@ export default class CogsConnection<Manifest extends CogsPluginManifest> {
35
38
  private audioOutputs;
36
39
  private _selectedAudioOutput;
37
40
  get selectedAudioOutput(): string;
41
+ /**
42
+ * Stores data in COGS
43
+ */
44
+ store: DataStore<DataT>;
38
45
  /**
39
46
  * URL parameters use for the websocket connection and asset URLs
40
47
  */
@@ -44,7 +51,7 @@ export default class CogsConnection<Manifest extends CogsPluginManifest> {
44
51
  port?: number;
45
52
  }, initialClientState?: Partial<ManifestTypes.StateAsObject<Manifest, {
46
53
  writableFromClient: true;
47
- }>> | undefined);
54
+ }>>, initialDataStoreData?: DataT);
48
55
  get isConnected(): boolean;
49
56
  close(): void;
50
57
  sendEvent<EventName extends ManifestTypes.EventNameToCogs<Manifest>>(eventName: EventName, ...[eventValue]: ManifestTypes.EventToCogsAsObject<Manifest>[EventName] extends undefined ? [] : [ManifestTypes.EventToCogsAsObject<Manifest>[EventName]]): void;
@@ -55,6 +62,7 @@ export default class CogsConnection<Manifest extends CogsPluginManifest> {
55
62
  sendInitialMediaClipStates(allMediaClipStates: AllMediaClipStatesMessage): void;
56
63
  sendMediaClipState(mediaClipState: MediaClipStateMessage): void;
57
64
  sendAudioOutputs(audioOutputs: MediaDeviceInfo[]): void;
65
+ private sendDataStoreItems;
58
66
  /**
59
67
  * Show or hide the plugin window.
60
68
  * @param visible Whether to show or hide the window
@@ -8,6 +8,7 @@ const compare_versions_1 = require("compare-versions");
8
8
  const ShowPhase_1 = __importDefault(require("./types/ShowPhase"));
9
9
  const reconnecting_websocket_1 = __importDefault(require("reconnecting-websocket"));
10
10
  const urls_1 = require("./helpers/urls");
11
+ const DataStore_1 = __importDefault(require("./DataStore"));
11
12
  class CogsConnection {
12
13
  get config() {
13
14
  return { ...this.currentConfig };
@@ -34,7 +35,7 @@ class CogsConnection {
34
35
  get selectedAudioOutput() {
35
36
  return this._selectedAudioOutput;
36
37
  }
37
- constructor(manifest, { hostname = document.location.hostname, port = urls_1.COGS_SERVER_PORT } = {}, initialClientState = undefined) {
38
+ constructor(manifest, { hostname = document.location.hostname, port = urls_1.COGS_SERVER_PORT } = {}, initialClientState, initialDataStoreData) {
38
39
  var _a;
39
40
  this.manifest = manifest;
40
41
  this.eventTarget = new EventTarget();
@@ -55,6 +56,7 @@ class CogsConnection {
55
56
  this.audioOutputs = undefined;
56
57
  this._selectedAudioOutput = '';
57
58
  this.currentState = { ...initialClientState };
59
+ this.store = new DataStore_1.default(initialDataStoreData !== null && initialDataStoreData !== void 0 ? initialDataStoreData : {});
58
60
  const { useReconnectingWebsocket, path, pathParams, supportsHttp2Assets } = websocketParametersFromUrl(document.location.href);
59
61
  // Store the URL parameters for use in asset URLs
60
62
  // and add screen dimensions which COGS can use to determine the best asset quality to serve
@@ -122,6 +124,9 @@ class CogsConnection {
122
124
  }
123
125
  }
124
126
  break;
127
+ case 'data_store_items':
128
+ this.store.handleDataStoreItemsMessage(message);
129
+ break;
125
130
  }
126
131
  this.dispatchEvent(new CogsMessageEvent(message));
127
132
  }
@@ -134,6 +139,10 @@ class CogsConnection {
134
139
  console.error('Unable to parse incoming data from server', data, e);
135
140
  }
136
141
  };
142
+ // Tell COGS when any data store items change
143
+ this.store.addEventListener('items', (event) => {
144
+ this.sendDataStoreItems(event.items);
145
+ });
137
146
  // Send a list of audio outputs to COGS and keep it up to date
138
147
  {
139
148
  const refreshAudioOutputs = async () => {
@@ -190,6 +199,11 @@ class CogsConnection {
190
199
  this.websocket.send(JSON.stringify({ audioOutputs }));
191
200
  }
192
201
  }
202
+ sendDataStoreItems(partialItems) {
203
+ if (this.isConnected) {
204
+ this.websocket.send(JSON.stringify({ dataStoreItems: partialItems }));
205
+ }
206
+ }
193
207
  /**
194
208
  * Show or hide the plugin window.
195
209
  * @param visible Whether to show or hide the window
@@ -0,0 +1,41 @@
1
+ import { DataStoreItemsClientMessage } from './types/CogsClientMessage';
2
+ /**
3
+ * A simple key-value store for storing data in COGS
4
+ *
5
+ * When reconnected the data will be restored.
6
+ */
7
+ export default class DataStore<ItemsT extends {
8
+ [key: string]: unknown;
9
+ } = {
10
+ [key: string]: unknown;
11
+ }> {
12
+ #private;
13
+ private _items;
14
+ constructor(defaultItems: ItemsT);
15
+ handleDataStoreItemsMessage(message: DataStoreItemsClientMessage): void;
16
+ get items(): Readonly<typeof this._items>;
17
+ getItem(key: string): unknown | undefined;
18
+ setItems(partialItems: Partial<ItemsT>): this;
19
+ addEventListener<K extends keyof DataStoreEventMap>(type: K, listener: (event: DataStoreEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
20
+ removeEventListener<K extends keyof DataStoreEventMap>(type: K, listener: (event: DataStoreEventMap[K]) => void, options?: boolean | EventListenerOptions): void;
21
+ private dispatchEvent;
22
+ }
23
+ export declare class DataStoreItemEvent extends Event {
24
+ readonly key: string;
25
+ readonly value: unknown;
26
+ readonly _cogsConnectionEventType = "item";
27
+ constructor(key: string, value: unknown);
28
+ }
29
+ export declare class DataStoreItemsEvent extends Event {
30
+ readonly items: {
31
+ [key: string]: unknown;
32
+ };
33
+ readonly _cogsConnectionEventType = "item";
34
+ constructor(items: {
35
+ [key: string]: unknown;
36
+ });
37
+ }
38
+ export interface DataStoreEventMap {
39
+ item: DataStoreItemEvent;
40
+ items: DataStoreItemsEvent;
41
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _DataStore_eventTarget;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DataStoreItemsEvent = exports.DataStoreItemEvent = void 0;
10
+ /**
11
+ * A simple key-value store for storing data in COGS
12
+ *
13
+ * When reconnected the data will be restored.
14
+ */
15
+ class DataStore {
16
+ constructor(defaultItems) {
17
+ _DataStore_eventTarget.set(this, new EventTarget());
18
+ this._items = { ...defaultItems };
19
+ }
20
+ handleDataStoreItemsMessage(message) {
21
+ this._items = { ...this._items, ...message.items };
22
+ Object.entries(message.items).forEach(([key, value]) => {
23
+ this.dispatchEvent(new DataStoreItemEvent(key, value));
24
+ });
25
+ this.dispatchEvent(new DataStoreItemsEvent(message.items));
26
+ }
27
+ get items() {
28
+ return this._items;
29
+ }
30
+ getItem(key) {
31
+ return this._items[key];
32
+ }
33
+ setItems(partialItems) {
34
+ this._items = { ...this._items, ...partialItems };
35
+ Object.entries(partialItems).forEach(([key, value]) => {
36
+ this.dispatchEvent(new DataStoreItemEvent(key, value));
37
+ });
38
+ this.dispatchEvent(new DataStoreItemsEvent(partialItems));
39
+ return this;
40
+ }
41
+ // Type-safe listeners
42
+ addEventListener(type, listener, options) {
43
+ __classPrivateFieldGet(this, _DataStore_eventTarget, "f").addEventListener(type, listener, options);
44
+ }
45
+ removeEventListener(type, listener, options) {
46
+ __classPrivateFieldGet(this, _DataStore_eventTarget, "f").removeEventListener(type, listener, options);
47
+ }
48
+ dispatchEvent(event) {
49
+ __classPrivateFieldGet(this, _DataStore_eventTarget, "f").dispatchEvent(event);
50
+ }
51
+ }
52
+ _DataStore_eventTarget = new WeakMap();
53
+ exports.default = DataStore;
54
+ class DataStoreItemEvent extends Event {
55
+ constructor(key, value) {
56
+ super('item');
57
+ this.key = key;
58
+ this.value = value;
59
+ this._cogsConnectionEventType = 'item';
60
+ }
61
+ }
62
+ exports.DataStoreItemEvent = DataStoreItemEvent;
63
+ class DataStoreItemsEvent extends Event {
64
+ constructor(items) {
65
+ super('items');
66
+ this.items = items;
67
+ this._cogsConnectionEventType = 'item';
68
+ }
69
+ }
70
+ exports.DataStoreItemsEvent = DataStoreItemsEvent;