@quiltt/core 5.0.0 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +19 -12
  3. package/dist/api/browser.cjs +14 -0
  4. package/dist/api/browser.d.ts +128 -0
  5. package/dist/api/browser.js +12 -0
  6. package/dist/api/graphql/SubscriptionLink-12s-ufJBKwu1.js +149 -0
  7. package/dist/api/graphql/SubscriptionLink-12s-wjkChfxO.cjs +150 -0
  8. package/dist/api/graphql/index.cjs +218 -0
  9. package/dist/api/graphql/index.d.ts +82 -0
  10. package/dist/api/graphql/index.js +184 -0
  11. package/dist/api/index.cjs +26 -0
  12. package/dist/api/index.d.ts +3 -0
  13. package/dist/api/index.js +3 -0
  14. package/dist/api/rest/index.cjs +225 -0
  15. package/dist/api/rest/index.d.ts +128 -0
  16. package/dist/api/rest/index.js +217 -0
  17. package/dist/auth/index.cjs +21 -0
  18. package/dist/auth/index.d.ts +29 -0
  19. package/dist/auth/index.js +19 -0
  20. package/dist/config/index.cjs +44 -0
  21. package/dist/config/index.d.ts +9 -0
  22. package/dist/config/index.js +36 -0
  23. package/dist/index.cjs +61 -0
  24. package/dist/index.d.ts +8 -524
  25. package/dist/index.js +8 -449
  26. package/dist/observables/index.cjs +30 -0
  27. package/dist/observables/index.d.ts +21 -0
  28. package/dist/observables/index.js +28 -0
  29. package/dist/storage/index.cjs +272 -0
  30. package/dist/storage/index.d.ts +91 -0
  31. package/dist/{SubscriptionLink-12s-C2VbF8Tf.js → storage/index.js} +2 -139
  32. package/dist/timing/index.cjs +30 -0
  33. package/dist/timing/index.d.ts +15 -0
  34. package/dist/timing/index.js +28 -0
  35. package/dist/types.cjs +1 -0
  36. package/dist/types.d.ts +28 -0
  37. package/dist/types.js +1 -0
  38. package/dist/utils/index.cjs +61 -0
  39. package/dist/utils/index.d.ts +18 -0
  40. package/dist/utils/index.js +57 -0
  41. package/package.json +62 -6
  42. package/src/api/graphql/client.ts +1 -1
  43. package/src/api/graphql/links/ActionCableLink.ts +7 -6
  44. package/src/api/graphql/links/AuthLink.ts +13 -9
  45. package/src/api/graphql/links/BatchHttpLink.ts +1 -1
  46. package/src/api/graphql/links/ErrorLink.ts +4 -0
  47. package/src/api/graphql/links/HttpLink.ts +1 -1
  48. package/src/api/graphql/links/VersionLink.ts +1 -1
  49. package/src/api/rest/auth.ts +1 -1
  50. package/src/api/rest/connectors.ts +1 -1
  51. package/src/auth/index.ts +1 -0
  52. package/src/{JsonWebToken.ts → auth/json-web-token.ts} +1 -1
  53. package/src/{configuration.ts → config/configuration.ts} +1 -1
  54. package/src/config/index.ts +1 -0
  55. package/src/index.ts +5 -5
  56. package/src/observables/index.ts +1 -0
  57. package/src/{Observable.ts → observables/observable.ts} +1 -1
  58. package/src/storage/Local.ts +1 -1
  59. package/src/storage/Memory.ts +2 -2
  60. package/src/storage/Storage.ts +1 -1
  61. package/src/timing/index.ts +1 -0
  62. package/src/{Timeoutable.ts → timing/timeoutable.ts} +1 -1
  63. package/src/utils/index.ts +1 -0
  64. package/src/utils/token-validation.ts +67 -0
@@ -0,0 +1,272 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var index_cjs = require('../observables/index.cjs');
4
+
5
+ /**
6
+ * An error and type safe wrapper for localStorage.
7
+ * It allows you to subscribe to changes;
8
+ * but localStorage changes only fire when another
9
+ * window updates the record.
10
+ */ class LocalStorage {
11
+ constructor(keyPrefix = 'quiltt'){
12
+ this.observers = {};
13
+ this.isEnabled = ()=>{
14
+ try {
15
+ const testKey = `${this.keyPrefix}.ping`;
16
+ localStorage.setItem(testKey, 'pong');
17
+ localStorage.removeItem(testKey);
18
+ return true;
19
+ } catch (_error) {
20
+ return false;
21
+ }
22
+ };
23
+ this.isDisabled = ()=>!this.isEnabled();
24
+ this.get = (key)=>{
25
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') {
26
+ return undefined;
27
+ }
28
+ const fullKey = this.getFullKey(key);
29
+ try {
30
+ const state = window.localStorage.getItem(fullKey);
31
+ return state ? JSON.parse(state) : null;
32
+ } catch (error) {
33
+ console.warn(`localStorage Error: "${fullKey}"`, error);
34
+ return undefined;
35
+ }
36
+ };
37
+ this.set = (key, state)=>{
38
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') return;
39
+ const fullKey = this.getFullKey(key);
40
+ try {
41
+ if (state !== null && state !== undefined) {
42
+ window.localStorage.setItem(fullKey, JSON.stringify(state));
43
+ } else {
44
+ window.localStorage.removeItem(fullKey);
45
+ }
46
+ } catch (error) {
47
+ console.warn(`localStorage Error: "${fullKey}"`, error);
48
+ }
49
+ };
50
+ this.remove = (key)=>{
51
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') return;
52
+ const fullKey = this.getFullKey(key);
53
+ try {
54
+ window.localStorage.removeItem(fullKey);
55
+ } catch (error) {
56
+ console.warn(`localStorage Error: "${fullKey}"`, error);
57
+ }
58
+ };
59
+ this.has = (key)=>{
60
+ return this.get(key) !== null && this.get(key) !== undefined;
61
+ };
62
+ this.clear = ()=>{
63
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') return;
64
+ try {
65
+ const keysToRemove = [];
66
+ for(let i = 0; i < localStorage.length; i++){
67
+ const key = localStorage.key(i);
68
+ if (key?.startsWith(`${this.keyPrefix}.`)) {
69
+ keysToRemove.push(key);
70
+ }
71
+ }
72
+ keysToRemove.forEach((key)=>{
73
+ localStorage.removeItem(key);
74
+ });
75
+ } catch (error) {
76
+ console.warn(`localStorage Error during clear`, error);
77
+ }
78
+ };
79
+ this.subscribe = (key, observer)=>{
80
+ const fullKey = this.getFullKey(key);
81
+ if (!this.observers[fullKey]) {
82
+ this.observers[fullKey] = [];
83
+ }
84
+ this.observers[fullKey].push(observer);
85
+ // Return unsubscribe function
86
+ return ()=>this.unsubscribe(key, observer);
87
+ };
88
+ this.unsubscribe = (key, observer)=>{
89
+ const fullKey = this.getFullKey(key);
90
+ if (this.observers[fullKey]) {
91
+ this.observers[fullKey] = this.observers[fullKey].filter((update)=>update !== observer);
92
+ // Clean up empty observer arrays
93
+ if (this.observers[fullKey].length === 0) {
94
+ delete this.observers[fullKey];
95
+ }
96
+ }
97
+ };
98
+ // Get all keys that match quiltt prefix
99
+ this.keys = ()=>{
100
+ if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') {
101
+ return [];
102
+ }
103
+ const keys = [];
104
+ try {
105
+ for(let i = 0; i < localStorage.length; i++){
106
+ const key = localStorage.key(i);
107
+ if (key?.startsWith(`${this.keyPrefix}.`)) {
108
+ keys.push(key.replace(`${this.keyPrefix}.`, ''));
109
+ }
110
+ }
111
+ } catch (error) {
112
+ console.warn('localStorage Error getting keys', error);
113
+ }
114
+ return keys;
115
+ };
116
+ this.getFullKey = (key)=>{
117
+ return `${this.keyPrefix}.${key}`;
118
+ };
119
+ /**
120
+ * Handle storage events from other windows/tabs
121
+ * If there is a key, then trigger the related updates. If there is no key
122
+ * it means that a record has been removed and everything needs to be rechecked.
123
+ */ this.handleStorageEvent = (event)=>{
124
+ const isQuilttKey = event.key?.startsWith(`${this.keyPrefix}.`);
125
+ if (isQuilttKey && event.key) {
126
+ // Parse the new value safely
127
+ let newState = null;
128
+ try {
129
+ newState = event.newValue ? JSON.parse(event.newValue) : null;
130
+ } catch (error) {
131
+ console.warn(`Failed to parse storage event value for ${event.key}`, error);
132
+ return;
133
+ }
134
+ if (this.observers[event.key]) {
135
+ this.observers[event.key].forEach((observer)=>{
136
+ try {
137
+ observer(newState);
138
+ } catch (error) {
139
+ console.warn(`Observer error for key ${event.key}`, error);
140
+ }
141
+ });
142
+ }
143
+ } else if (!event.key) {
144
+ // Storage was cleared or changed in a way that doesn't specify a key
145
+ // Re-check all observed keys
146
+ Object.entries(this.observers).forEach(([fullKey, observers])=>{
147
+ const shortKey = fullKey.replace(`${this.keyPrefix}.`, '');
148
+ const currentValue = this.get(shortKey);
149
+ observers.forEach((observer)=>{
150
+ try {
151
+ observer(currentValue);
152
+ } catch (error) {
153
+ console.warn(`Observer error for key ${fullKey}`, error);
154
+ }
155
+ });
156
+ });
157
+ }
158
+ };
159
+ this.keyPrefix = keyPrefix;
160
+ if (typeof window !== 'undefined' && typeof window.addEventListener !== 'undefined') {
161
+ window.addEventListener('storage', this.handleStorageEvent.bind(this));
162
+ }
163
+ }
164
+ }
165
+
166
+ /**
167
+ * This is designed to support effectively an in memory key value store singleton,
168
+ * similar to localStorage, but allows you to subscribe to changes within the current
169
+ * window.
170
+ */ class MemoryStorage {
171
+ constructor(){
172
+ this.observables = {};
173
+ this.get = (key)=>{
174
+ if (this.observables[key]) {
175
+ return this.observables[key].get();
176
+ }
177
+ return undefined;
178
+ };
179
+ this.set = (key, state)=>{
180
+ if (!this.observables[key]) {
181
+ this.observables[key] = new index_cjs.Observable(state);
182
+ } else {
183
+ this.observables[key].set(state);
184
+ }
185
+ };
186
+ this.subscribe = (key, observer)=>{
187
+ if (!this.observables[key]) this.observables[key] = new index_cjs.Observable();
188
+ this.observables[key].subscribe(observer);
189
+ };
190
+ this.unsubscribe = (key, observer)=>{
191
+ if (this.observables[key]) {
192
+ this.observables[key].unsubscribe(observer);
193
+ }
194
+ };
195
+ }
196
+ }
197
+
198
+ /**
199
+ * This is wraps both local and memory storage to create a unified interface, that
200
+ * allows you to subscribe to all either changes made within this window, or changes
201
+ * made by other windows.
202
+ */ class Storage {
203
+ constructor(){
204
+ this.memoryStore = new MemoryStorage();
205
+ this.localStore = new LocalStorage();
206
+ this.observers = {};
207
+ this.monitors = new Set();
208
+ /**
209
+ * Checks memoryStorage before falling back to localStorage.
210
+ */ this.get = (key)=>{
211
+ this.monitorLocalStorageChanges(key);
212
+ let state = this.memoryStore.get(key);
213
+ if (state === undefined) {
214
+ state = this.localStore.get(key);
215
+ }
216
+ return state;
217
+ };
218
+ /**
219
+ * We don't trust localStorage to always be present, so we can't rely on it to
220
+ * update memoryStorage based on emitted changes. So we manage our own
221
+ * emitting while using the underlying events to keep memoryStore in sync with
222
+ * localStore.
223
+ */ this.set = (key, newState)=>{
224
+ this.monitorLocalStorageChanges(key);
225
+ this.localStore.set(key, newState);
226
+ this.memoryStore.set(key, newState);
227
+ this.observers[key]?.forEach((update)=>{
228
+ update(newState);
229
+ });
230
+ };
231
+ /**
232
+ * Allows you to subscribe to all changes in memory or local storage as a
233
+ * single event.
234
+ */ this.subscribe = (key, observer)=>{
235
+ if (!this.observers[key]) this.observers[key] = [];
236
+ this.observers[key].push(observer);
237
+ };
238
+ this.unsubscribe = (key, observer)=>{
239
+ this.observers[key] = this.observers[key]?.filter((update)=>update !== observer);
240
+ };
241
+ /**
242
+ * Sets bubble the changes down the stack starting with memoryStore and then
243
+ * localStore. memoryStore will emit changes to everything within the current
244
+ * window context, while localStore will emit changes to every other window
245
+ * context.
246
+ *
247
+ * To ensure that the other windows are updated correctly, changes to localStore
248
+ * need to be subscribed and updated to in memory store, which then may be subscribed
249
+ * to outside of storage.
250
+ */ this.monitorLocalStorageChanges = (key)=>{
251
+ if (this.monitors.has(key)) return;
252
+ this.monitors.add(key);
253
+ this.localStore.subscribe(key, (nextState)=>{
254
+ const prevValue = this.memoryStore.get(key);
255
+ const newState = nextState instanceof Function ? nextState(prevValue) : nextState;
256
+ this.memoryStore.set(key, newState);
257
+ this.observers[key]?.forEach((update)=>{
258
+ update(newState);
259
+ });
260
+ });
261
+ };
262
+ }
263
+ }
264
+ /**
265
+ * This is an singleton to share the memory states across all instances; This
266
+ * basically acts like shared memory when there is no localStorage.
267
+ */ const GlobalStorage = new Storage();
268
+
269
+ exports.GlobalStorage = GlobalStorage;
270
+ exports.LocalStorage = LocalStorage;
271
+ exports.MemoryStorage = MemoryStorage;
272
+ exports.Storage = Storage;
@@ -0,0 +1,91 @@
1
+ import { Observer } from '../observables/index.js';
2
+ import { Maybe } from '../types.js';
3
+
4
+ /**
5
+ * An error and type safe wrapper for localStorage.
6
+ * It allows you to subscribe to changes;
7
+ * but localStorage changes only fire when another
8
+ * window updates the record.
9
+ */
10
+ declare class LocalStorage<T = any> {
11
+ private observers;
12
+ private readonly keyPrefix;
13
+ constructor(keyPrefix?: string);
14
+ isEnabled: () => boolean;
15
+ isDisabled: () => boolean;
16
+ get: (key: string) => Maybe<T> | undefined;
17
+ set: (key: string, state: Maybe<T> | undefined) => void;
18
+ remove: (key: string) => void;
19
+ has: (key: string) => boolean;
20
+ clear: () => void;
21
+ subscribe: (key: string, observer: Observer<T>) => (() => void);
22
+ unsubscribe: (key: string, observer: Observer<T>) => void;
23
+ keys: () => string[];
24
+ private getFullKey;
25
+ /**
26
+ * Handle storage events from other windows/tabs
27
+ * If there is a key, then trigger the related updates. If there is no key
28
+ * it means that a record has been removed and everything needs to be rechecked.
29
+ */
30
+ private handleStorageEvent;
31
+ }
32
+
33
+ /**
34
+ * This is designed to support effectively an in memory key value store singleton,
35
+ * similar to localStorage, but allows you to subscribe to changes within the current
36
+ * window.
37
+ */
38
+ declare class MemoryStorage<T> {
39
+ private observables;
40
+ get: (key: string) => Maybe<T> | undefined;
41
+ set: (key: string, state: Maybe<T> | undefined) => void;
42
+ subscribe: (key: string, observer: Observer<T>) => void;
43
+ unsubscribe: (key: string, observer: Observer<T>) => void;
44
+ }
45
+
46
+ /**
47
+ * This is wraps both local and memory storage to create a unified interface, that
48
+ * allows you to subscribe to all either changes made within this window, or changes
49
+ * made by other windows.
50
+ */
51
+ declare class Storage<T> {
52
+ private memoryStore;
53
+ private localStore;
54
+ private observers;
55
+ private monitors;
56
+ /**
57
+ * Checks memoryStorage before falling back to localStorage.
58
+ */
59
+ get: (key: string) => Maybe<T> | undefined;
60
+ /**
61
+ * We don't trust localStorage to always be present, so we can't rely on it to
62
+ * update memoryStorage based on emitted changes. So we manage our own
63
+ * emitting while using the underlying events to keep memoryStore in sync with
64
+ * localStore.
65
+ */
66
+ set: (key: string, newState: Maybe<T> | undefined) => void;
67
+ /**
68
+ * Allows you to subscribe to all changes in memory or local storage as a
69
+ * single event.
70
+ */
71
+ subscribe: (key: string, observer: Observer<T>) => void;
72
+ unsubscribe: (key: string, observer: Observer<T>) => void;
73
+ /**
74
+ * Sets bubble the changes down the stack starting with memoryStore and then
75
+ * localStore. memoryStore will emit changes to everything within the current
76
+ * window context, while localStore will emit changes to every other window
77
+ * context.
78
+ *
79
+ * To ensure that the other windows are updated correctly, changes to localStore
80
+ * need to be subscribed and updated to in memory store, which then may be subscribed
81
+ * to outside of storage.
82
+ */
83
+ private monitorLocalStorageChanges;
84
+ }
85
+ /**
86
+ * This is an singleton to share the memory states across all instances; This
87
+ * basically acts like shared memory when there is no localStorage.
88
+ */
89
+ declare const GlobalStorage: Storage<any>;
90
+
91
+ export { GlobalStorage, LocalStorage, MemoryStorage, Storage };
@@ -1,43 +1,4 @@
1
- 'use client';
2
- import { ApolloLink } from '@apollo/client/core';
3
- import { createConsumer } from '@rails/actioncable';
4
- import { print } from 'graphql';
5
- import { Observable as Observable$1 } from 'rxjs';
6
-
7
- var name = "@quiltt/core";
8
- var version$1 = "5.0.0";
9
-
10
- const QUILTT_API_INSECURE = (()=>{
11
- try {
12
- return process.env.QUILTT_API_INSECURE === 'true';
13
- } catch {
14
- return false;
15
- }
16
- })();
17
- const QUILTT_API_DOMAIN = (()=>{
18
- try {
19
- return process.env.QUILTT_API_DOMAIN;
20
- } catch {
21
- return undefined;
22
- }
23
- })();
24
- const QUILTT_DEBUG = (()=>{
25
- try {
26
- return process.env.NODE_ENV !== 'production' && process.env.QUILTT_DEBUG === 'true';
27
- } catch {
28
- return false;
29
- }
30
- })();
31
- const domain = QUILTT_API_DOMAIN || 'quiltt.io';
32
- const protocolHttp = `http${QUILTT_API_INSECURE ? '' : 's'}`;
33
- const protocolWebsockets = `ws${QUILTT_API_INSECURE ? '' : 's'}`;
34
- const debugging = QUILTT_DEBUG;
35
- const version = `${name}: v${version$1}`;
36
- const cdnBase = `${protocolHttp}://cdn.${domain}`;
37
- const endpointAuth = `${protocolHttp}://auth.${domain}/v1/users/session`;
38
- const endpointGraphQL = `${protocolHttp}://api.${domain}/v1/graphql`;
39
- const endpointRest = `${protocolHttp}://api.${domain}/v1`;
40
- const endpointWebsockets = `${protocolWebsockets}://api.${domain}/websockets`;
1
+ import { Observable } from '../observables/index.js';
41
2
 
42
3
  /**
43
4
  * An error and type safe wrapper for localStorage.
@@ -200,33 +161,6 @@ const endpointWebsockets = `${protocolWebsockets}://api.${domain}/websockets`;
200
161
  }
201
162
  }
202
163
 
203
- /**
204
- * This is designed to support singletons to share the memory states across all
205
- * instance of hooks to ensure that updates only process once, by storing a value
206
- * then notifying all subscribers when it's updated.
207
- */ class Observable {
208
- constructor(initialState){
209
- this.observers = [];
210
- this.get = ()=>{
211
- return this.state;
212
- };
213
- this.set = (nextState)=>{
214
- if (this.state === nextState) return;
215
- this.state = nextState;
216
- this.observers.forEach((update)=>{
217
- update(nextState);
218
- });
219
- };
220
- this.subscribe = (observer)=>{
221
- this.observers.push(observer);
222
- };
223
- this.unsubscribe = (observer)=>{
224
- this.observers = this.observers.filter((update)=>update !== observer);
225
- };
226
- this.state = initialState;
227
- }
228
- }
229
-
230
164
  /**
231
165
  * This is designed to support effectively an in memory key value store singleton,
232
166
  * similar to localStorage, but allows you to subscribe to changes within the current
@@ -330,75 +264,4 @@ const endpointWebsockets = `${protocolWebsockets}://api.${domain}/websockets`;
330
264
  * basically acts like shared memory when there is no localStorage.
331
265
  */ const GlobalStorage = new Storage();
332
266
 
333
- // Adapted from https://github.com/rmosolgo/graphql-ruby/blob/master/javascript_client/src/subscriptions/ActionCableLink.ts
334
- class ActionCableLink extends ApolloLink {
335
- constructor(options){
336
- super();
337
- this.cables = {};
338
- this.channelName = options.channelName || 'GraphqlChannel';
339
- this.actionName = options.actionName || 'execute';
340
- this.connectionParams = options.connectionParams || {};
341
- this.callbacks = options.callbacks || {};
342
- }
343
- // Interestingly, this link does _not_ call through to `next` because
344
- // instead, it sends the request to ActionCable.
345
- request(operation, _next) {
346
- const token = GlobalStorage.get('session');
347
- if (!token) {
348
- console.warn('QuilttClient attempted to send an unauthenticated Subscription');
349
- return new Observable$1((observer)=>{
350
- observer.error(new Error('No authentication token available'));
351
- });
352
- }
353
- if (!this.cables[token]) {
354
- this.cables[token] = createConsumer(endpointWebsockets + (token ? `?token=${token}` : ''));
355
- }
356
- return new Observable$1((observer)=>{
357
- const channelId = Math.round(Date.now() + Math.random() * 100000).toString(16);
358
- const actionName = this.actionName;
359
- const connectionParams = typeof this.connectionParams === 'function' ? this.connectionParams(operation) : this.connectionParams;
360
- const callbacks = this.callbacks;
361
- const channel = this.cables[token].subscriptions.create(Object.assign({}, {
362
- channel: this.channelName,
363
- channelId: channelId
364
- }, connectionParams), {
365
- connected: (args)=>{
366
- channel.perform(actionName, {
367
- query: operation.query ? print(operation.query) : null,
368
- variables: operation.variables,
369
- // This is added for persisted operation support:
370
- operationId: operation.operationId,
371
- operationName: operation.operationName
372
- });
373
- callbacks.connected?.(args);
374
- },
375
- received: (payload)=>{
376
- if (payload?.result?.data || payload?.result?.errors) {
377
- observer.next(payload.result);
378
- }
379
- if (!payload.more) {
380
- observer.complete();
381
- }
382
- callbacks.received?.(payload);
383
- },
384
- disconnected: ()=>{
385
- callbacks.disconnected?.();
386
- }
387
- });
388
- // Make the ActionCable subscription behave like an Apollo subscription
389
- return Object.assign(channel, {
390
- closed: false
391
- });
392
- });
393
- }
394
- }
395
-
396
- class SubscriptionLink extends ActionCableLink {
397
- constructor(){
398
- super({
399
- channelName: 'GraphQLChannel'
400
- });
401
- }
402
- }
403
-
404
- export { GlobalStorage as G, LocalStorage as L, MemoryStorage as M, Observable as O, SubscriptionLink as S, endpointAuth as a, endpointRest as b, Storage as c, debugging as d, endpointGraphQL as e, cdnBase as f, endpointWebsockets as g, version as v };
267
+ export { GlobalStorage, LocalStorage, MemoryStorage, Storage };
@@ -0,0 +1,30 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ /**
4
+ * This is designed to support singletons to timeouts that can broadcast
5
+ * to any observers, preventing race conditions with multiple timeouts.
6
+ */ class Timeoutable {
7
+ constructor(){
8
+ this.observers = [];
9
+ this.set = (callback, delay)=>{
10
+ if (this.timeout) {
11
+ clearTimeout(this.timeout);
12
+ }
13
+ // Replace all observers with the new one
14
+ this.observers = [
15
+ callback
16
+ ];
17
+ this.timeout = setTimeout(this.broadcast.bind(this), delay);
18
+ };
19
+ this.clear = (observer)=>{
20
+ this.observers = this.observers.filter((callback)=>callback !== observer);
21
+ };
22
+ // Only sends to the 1st listener, but ensures that someone is notified
23
+ this.broadcast = ()=>{
24
+ if (this.observers.length === 0) return;
25
+ this.observers[0](undefined);
26
+ };
27
+ }
28
+ }
29
+
30
+ exports.Timeoutable = Timeoutable;
@@ -0,0 +1,15 @@
1
+ import { Observer } from '../observables/index.js';
2
+
3
+ /**
4
+ * This is designed to support singletons to timeouts that can broadcast
5
+ * to any observers, preventing race conditions with multiple timeouts.
6
+ */
7
+ declare class Timeoutable {
8
+ private timeout?;
9
+ private observers;
10
+ set: (callback: () => void, delay: number | undefined) => void;
11
+ clear: (observer: Observer<void>) => void;
12
+ private broadcast;
13
+ }
14
+
15
+ export { Timeoutable };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This is designed to support singletons to timeouts that can broadcast
3
+ * to any observers, preventing race conditions with multiple timeouts.
4
+ */ class Timeoutable {
5
+ constructor(){
6
+ this.observers = [];
7
+ this.set = (callback, delay)=>{
8
+ if (this.timeout) {
9
+ clearTimeout(this.timeout);
10
+ }
11
+ // Replace all observers with the new one
12
+ this.observers = [
13
+ callback
14
+ ];
15
+ this.timeout = setTimeout(this.broadcast.bind(this), delay);
16
+ };
17
+ this.clear = (observer)=>{
18
+ this.observers = this.observers.filter((callback)=>callback !== observer);
19
+ };
20
+ // Only sends to the 1st listener, but ensures that someone is notified
21
+ this.broadcast = ()=>{
22
+ if (this.observers.length === 0) return;
23
+ this.observers[0](undefined);
24
+ };
25
+ }
26
+ }
27
+
28
+ export { Timeoutable };
package/dist/types.cjs ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,28 @@
1
+ /** Utility types to extend default TS utilities */
2
+ type Maybe<T> = T | null;
3
+ type InputMaybe<T> = Maybe<T>;
4
+ type Exact<T extends {
5
+ [key: string]: unknown;
6
+ }> = {
7
+ [K in keyof T]: T[K];
8
+ };
9
+ type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
10
+ [SubKey in K]?: Maybe<T[SubKey]>;
11
+ };
12
+ type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
13
+ [SubKey in K]: Maybe<T[SubKey]>;
14
+ };
15
+ type Nullable<T> = {
16
+ [K in keyof T]: T[K] | null;
17
+ };
18
+ type Mutable<Type> = {
19
+ -readonly [Key in keyof Type]: Type[Key];
20
+ };
21
+ type DeepPartial<T> = T extends object ? {
22
+ [P in keyof T]?: DeepPartial<T[P]>;
23
+ } : T;
24
+ type DeepReadonly<T> = T extends object ? {
25
+ [P in keyof T]: DeepReadonly<T[P]>;
26
+ } : T;
27
+
28
+ export type { DeepPartial, DeepReadonly, Exact, InputMaybe, MakeMaybe, MakeOptional, Maybe, Mutable, Nullable };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+