@buenos-nachos/time-sync 0.3.2 → 0.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/CHANGELOG.md +7 -1
- package/package.json +1 -1
- package/src/TimeSync.test.ts +0 -47
- package/src/TimeSync.ts +8 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @buenos-nachos/time-sync
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
- 663479e: Removed `isSubscribed` property from context and made all other context properties readonly.
|
|
8
|
+
|
|
3
9
|
## 0.3.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -14,7 +20,7 @@
|
|
|
14
20
|
|
|
15
21
|
## 0.3.0
|
|
16
22
|
|
|
17
|
-
###
|
|
23
|
+
### Breaking Changes
|
|
18
24
|
|
|
19
25
|
- 122f6c1: Updated `SubscriptionContext.timeSync` type to be readonly and non-nullable, and renamed `SubscriptionContext.isLive` to `SubscriptionContext.isSubscribed`.
|
|
20
26
|
|
package/package.json
CHANGED
package/src/TimeSync.test.ts
CHANGED
|
@@ -131,7 +131,6 @@ describe(TimeSync, () => {
|
|
|
131
131
|
|
|
132
132
|
const expectedCtx: SubscriptionContext = {
|
|
133
133
|
unsubscribe,
|
|
134
|
-
isSubscribed: true,
|
|
135
134
|
timeSync: sync,
|
|
136
135
|
intervalLastFulfilledAt: dateAfter,
|
|
137
136
|
registeredAt: dateBefore,
|
|
@@ -563,28 +562,6 @@ describe(TimeSync, () => {
|
|
|
563
562
|
const dateAfter = sync.getStateSnapshot().date;
|
|
564
563
|
expect(dateAfter).not.toEqual(dateBefore);
|
|
565
564
|
});
|
|
566
|
-
|
|
567
|
-
it("Mutates the isLive context value to be false on unsubscribe", async ({
|
|
568
|
-
expect,
|
|
569
|
-
}) => {
|
|
570
|
-
const sync = new TimeSync();
|
|
571
|
-
|
|
572
|
-
let ejectedContext: SubscriptionContext | undefined;
|
|
573
|
-
const onUpdate = vi.fn((_: unknown, ctx: SubscriptionContext) => {
|
|
574
|
-
ejectedContext = ctx;
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
const unsub = sync.subscribe({
|
|
578
|
-
onUpdate,
|
|
579
|
-
targetRefreshIntervalMs: refreshRates.oneMinute,
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
await vi.advanceTimersByTimeAsync(refreshRates.oneMinute);
|
|
583
|
-
expect(ejectedContext?.isSubscribed).toBe(true);
|
|
584
|
-
|
|
585
|
-
unsub();
|
|
586
|
-
expect(ejectedContext?.isSubscribed).toBe(false);
|
|
587
|
-
});
|
|
588
565
|
});
|
|
589
566
|
|
|
590
567
|
describe("Subscriptions: context values", () => {
|
|
@@ -827,7 +804,6 @@ describe(TimeSync, () => {
|
|
|
827
804
|
|
|
828
805
|
await vi.advanceTimersByTimeAsync(refreshRates.oneSecond);
|
|
829
806
|
expect(ejectedContext).toEqual<SubscriptionContext>({
|
|
830
|
-
isSubscribed: true,
|
|
831
807
|
intervalLastFulfilledAt: null,
|
|
832
808
|
registeredAt: snapBefore,
|
|
833
809
|
targetRefreshIntervalMs: refreshRates.oneHour,
|
|
@@ -840,7 +816,6 @@ describe(TimeSync, () => {
|
|
|
840
816
|
|
|
841
817
|
const snapAfter = sync.getStateSnapshot().date;
|
|
842
818
|
expect(ejectedContext).toEqual<SubscriptionContext>({
|
|
843
|
-
isSubscribed: true,
|
|
844
819
|
intervalLastFulfilledAt: snapAfter,
|
|
845
820
|
registeredAt: snapBefore,
|
|
846
821
|
targetRefreshIntervalMs: refreshRates.oneHour,
|
|
@@ -1086,28 +1061,6 @@ describe(TimeSync, () => {
|
|
|
1086
1061
|
await vi.advanceTimersByTimeAsync(refreshRates.oneMinute);
|
|
1087
1062
|
expect(sharedOnUpdate).not.toHaveBeenCalled();
|
|
1088
1063
|
});
|
|
1089
|
-
|
|
1090
|
-
it("Mutates the isLive context value to be false", async ({ expect }) => {
|
|
1091
|
-
const sync = new TimeSync();
|
|
1092
|
-
|
|
1093
|
-
let ejectedContext: SubscriptionContext | undefined;
|
|
1094
|
-
const onUpdate = vi.fn((_: unknown, ctx: SubscriptionContext) => {
|
|
1095
|
-
if (ejectedContext === undefined) {
|
|
1096
|
-
ejectedContext = ctx;
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1099
|
-
|
|
1100
|
-
void sync.subscribe({
|
|
1101
|
-
onUpdate,
|
|
1102
|
-
targetRefreshIntervalMs: refreshRates.oneMinute,
|
|
1103
|
-
});
|
|
1104
|
-
|
|
1105
|
-
await vi.advanceTimersByTimeAsync(refreshRates.oneMinute);
|
|
1106
|
-
expect(ejectedContext?.isSubscribed).toBe(true);
|
|
1107
|
-
|
|
1108
|
-
sync.clearAll();
|
|
1109
|
-
expect(ejectedContext?.isSubscribed).toBe(false);
|
|
1110
|
-
});
|
|
1111
1064
|
});
|
|
1112
1065
|
|
|
1113
1066
|
/**
|
package/src/TimeSync.ts
CHANGED
|
@@ -135,9 +135,8 @@ export interface Snapshot {
|
|
|
135
135
|
* TimeSync.
|
|
136
136
|
*
|
|
137
137
|
* For performance reasons, this object has ZERO readonly guarantees enforced at
|
|
138
|
-
* runtime.
|
|
139
|
-
*
|
|
140
|
-
* state. Proceed with caution.
|
|
138
|
+
* runtime. All properties are defined as readonly at the type level, but an
|
|
139
|
+
* accidental mutation can still slip through.
|
|
141
140
|
*/
|
|
142
141
|
export interface SubscriptionContext {
|
|
143
142
|
/**
|
|
@@ -162,12 +161,6 @@ export interface SubscriptionContext {
|
|
|
162
161
|
*/
|
|
163
162
|
readonly timeSync: TimeSync;
|
|
164
163
|
|
|
165
|
-
/**
|
|
166
|
-
* Indicates whether the subscription is still live. Will be mutated to be
|
|
167
|
-
* false when a subscription is
|
|
168
|
-
*/
|
|
169
|
-
isSubscribed: boolean;
|
|
170
|
-
|
|
171
164
|
/**
|
|
172
165
|
* Indicates when the last time the subscription had its explicit interval
|
|
173
166
|
* "satisfied".
|
|
@@ -176,7 +169,7 @@ export interface SubscriptionContext {
|
|
|
176
169
|
* the active interval is set to fire every second, you may need to know
|
|
177
170
|
* which update actually happened five minutes later.
|
|
178
171
|
*/
|
|
179
|
-
intervalLastFulfilledAt: ReadonlyDate | null;
|
|
172
|
+
readonly intervalLastFulfilledAt: ReadonlyDate | null;
|
|
180
173
|
}
|
|
181
174
|
|
|
182
175
|
/**
|
|
@@ -439,7 +432,7 @@ export class TimeSync implements TimeSyncApi {
|
|
|
439
432
|
// first context in a sub array gets removed by unsubscribing, we
|
|
440
433
|
// want what was the the second element to still be up to date
|
|
441
434
|
let shouldCallOnUpdate = true;
|
|
442
|
-
for (const
|
|
435
|
+
for (const ctx of subs as readonly Writeable<SubscriptionContext>[]) {
|
|
443
436
|
// We're not doing anything more sophisticated here because
|
|
444
437
|
// we're assuming that any systems that can clear out the
|
|
445
438
|
// subscriptions will handle cleaning up each context, too
|
|
@@ -448,17 +441,15 @@ export class TimeSync implements TimeSyncApi {
|
|
|
448
441
|
break outer;
|
|
449
442
|
}
|
|
450
443
|
|
|
451
|
-
const comparisonDate =
|
|
452
|
-
context.intervalLastFulfilledAt ?? context.registeredAt;
|
|
444
|
+
const comparisonDate = ctx.intervalLastFulfilledAt ?? ctx.registeredAt;
|
|
453
445
|
const isIntervalMatch =
|
|
454
|
-
dateTime - comparisonDate.getTime() >=
|
|
455
|
-
context.targetRefreshIntervalMs;
|
|
446
|
+
dateTime - comparisonDate.getTime() >= ctx.targetRefreshIntervalMs;
|
|
456
447
|
if (isIntervalMatch) {
|
|
457
|
-
|
|
448
|
+
ctx.intervalLastFulfilledAt = date;
|
|
458
449
|
}
|
|
459
450
|
|
|
460
451
|
if (shouldCallOnUpdate) {
|
|
461
|
-
onUpdate(date,
|
|
452
|
+
onUpdate(date, ctx);
|
|
462
453
|
shouldCallOnUpdate = config.allowDuplicateOnUpdateCalls;
|
|
463
454
|
}
|
|
464
455
|
}
|
|
@@ -586,7 +577,6 @@ export class TimeSync implements TimeSyncApi {
|
|
|
586
577
|
// Have to define this as a writeable to avoid a chicken-and-the-egg
|
|
587
578
|
// problem for the unsubscribe callback
|
|
588
579
|
const context: Writeable<SubscriptionContext> = {
|
|
589
|
-
isSubscribed: true,
|
|
590
580
|
timeSync: this,
|
|
591
581
|
unsubscribe: noOp,
|
|
592
582
|
registeredAt: new ReadonlyDate(),
|
|
@@ -604,7 +594,6 @@ export class TimeSync implements TimeSyncApi {
|
|
|
604
594
|
const subsOnSetup = this.#subscriptions;
|
|
605
595
|
const unsubscribe = (): void => {
|
|
606
596
|
if (!subscribed || this.#subscriptions !== subsOnSetup) {
|
|
607
|
-
context.isSubscribed = false;
|
|
608
597
|
subscribed = false;
|
|
609
598
|
return;
|
|
610
599
|
}
|
|
@@ -631,7 +620,6 @@ export class TimeSync implements TimeSyncApi {
|
|
|
631
620
|
subscriberCount: Math.max(0, this.#latestSnapshot.subscriberCount - 1),
|
|
632
621
|
});
|
|
633
622
|
|
|
634
|
-
context.isSubscribed = false;
|
|
635
623
|
subscribed = false;
|
|
636
624
|
};
|
|
637
625
|
context.unsubscribe = unsubscribe;
|
|
@@ -671,12 +659,6 @@ export class TimeSync implements TimeSyncApi {
|
|
|
671
659
|
// As long as we clean things the internal state, it's safe not to
|
|
672
660
|
// bother calling each unsubscribe callback. Not calling them one by
|
|
673
661
|
// one actually has much better time complexity
|
|
674
|
-
for (const subArray of this.#subscriptions.values()) {
|
|
675
|
-
for (const ctx of subArray) {
|
|
676
|
-
ctx.isSubscribed = false;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
662
|
this.#subscriptions.clear();
|
|
681
663
|
|
|
682
664
|
// We swap the map out so that the unsubscribe callbacks can detect
|