@ultimabase/realtime 0.1.2 → 0.2.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 +12 -0
- package/dist/computed.d.ts +5 -1
- package/dist/computed.d.ts.map +1 -1
- package/dist/computed.js +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/viewer.d.ts +2 -2
- package/dist/viewer.d.ts.map +1 -1
- package/dist/viewer.js +22 -8
- package/package.json +7 -7
- package/src/computed.ts +8 -1
- package/src/index.ts +1 -1
- package/src/viewer.ts +22 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ultimabase/realtime
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c0c5a21: `viewer.onClose(listener)` runs once a viewer closes, whatever closes it: its caller ended, the application stopped or `close()` was called. A plugin's own socket closes there.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [2c3bf4e]
|
|
12
|
+
- Updated dependencies [fd1263e]
|
|
13
|
+
- ultimabase@0.2.0
|
|
14
|
+
|
|
3
15
|
## 0.1.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/computed.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import type { Caller } from 'ultimabase';
|
|
1
|
+
import type { Caller, ExposedFunction } from 'ultimabase';
|
|
2
2
|
import type { Recorded } from 'ultimabase/internal';
|
|
3
3
|
import type { Batch } from './changes.ts';
|
|
4
4
|
import type { LiveMessage } from './messages.ts';
|
|
5
5
|
import type { Loader } from './reads.ts';
|
|
6
|
+
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
7
|
+
export declare const ownerOf: (fn: ExposedFunction) => string;
|
|
8
|
+
/** How long a live function's wake waits for quiet, in milliseconds. */
|
|
9
|
+
export declare const debounce = 50;
|
|
6
10
|
export type ComputedOptions = {
|
|
7
11
|
/** The function's result for `caller`, shaped as its transport sends it. */
|
|
8
12
|
readonly compute: (caller: Caller) => Promise<unknown>;
|
package/dist/computed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAGxC,mEAAmE;AACnE,eAAO,MAAM,OAAO,OAAQ,eAAe,KAAG,MACgB,CAAA;AAE9D,wEAAwE;AACxE,eAAO,MAAM,QAAQ,KAAK,CAAA;AAK1B,MAAM,MAAM,eAAe,GAAG;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACtD,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAC7C,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAC3B,CAAA;AAED,qBAAa,QAAQ;;IAGpB,8BAA8B;IAC9B,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAK;IAC/B,iEAAiE;IACjE,OAAO,EAAE,IAAI,GAAG,SAAS,CAAA;IASzB,YAAY,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAGnD;IAED,2EAA2E;IACrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;IAED,gEAAgE;IAC1D,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE;IAED,+DAA+D;IACzD,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1C;IAED,mEAAmE;IACnE,MAAM,IAAI,IAAI,CAKb;IAED,KAAK,IAAI,IAAI,CAIZ;CA8DD"}
|
package/dist/computed.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
import { isDeepStrictEqual } from 'node:util';
|
|
6
6
|
import { recording } from 'ultimabase/internal';
|
|
7
7
|
import { anyStale } from './stale.js';
|
|
8
|
+
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
9
|
+
export const ownerOf = (fn) => fn.plugin === undefined ? fn.name : `${fn.plugin}.${fn.name}`;
|
|
10
|
+
/** How long a live function's wake waits for quiet, in milliseconds. */
|
|
11
|
+
export const debounce = 50;
|
|
8
12
|
/** The longest a run waits after the first wake, however many follow. */
|
|
9
13
|
const longest = 1000;
|
|
10
14
|
export class Computed {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAK9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACjE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAErD,MAAM,MAAM,eAAe,GAAG;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,qDAAqD;IACrD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,iFAAiF;IACjF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC3B,gEAAgE;IAChE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACtD,kDAAkD;IAClD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,wFAAwF;IACxF,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAC/C;AAED,0CAA0C;AAC1C,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAA;CACzB;AAsDD,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAA0B,CAAA;AAC/D,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAA6B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { definePlugin } from 'ultimabase';
|
|
2
2
|
import manifest from '../package.json' with { type: 'json' };
|
|
3
|
+
import { ownerOf } from './computed.js';
|
|
3
4
|
import { Engine } from './engine.js';
|
|
4
|
-
import { ownerOf } from './viewer.js';
|
|
5
5
|
// Each running application's engine, by the context its plugin received.
|
|
6
6
|
const engines = new WeakMap();
|
|
7
7
|
const positive = (name, value) => {
|
package/dist/viewer.d.ts
CHANGED
|
@@ -25,8 +25,6 @@ export interface LiveHandle {
|
|
|
25
25
|
close(this: void): void;
|
|
26
26
|
}
|
|
27
27
|
type Built<R> = Awaited<ReturnType<typeof recording<R>>>;
|
|
28
|
-
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
29
|
-
export declare const ownerOf: (fn: ExposedFunction) => string;
|
|
30
28
|
export declare class Viewer {
|
|
31
29
|
#private;
|
|
32
30
|
/** `onDue` runs once the caller stops holding, to rebuild it. */
|
|
@@ -47,6 +45,8 @@ export declare class Viewer {
|
|
|
47
45
|
*/
|
|
48
46
|
value(name: string, compute: (caller: Caller) => Promise<unknown>, send: (message: LiveMessage) => void): Promise<LiveHandle>;
|
|
49
47
|
close(): void;
|
|
48
|
+
/** Runs `listener` once it closes, at once when it is closed (D-163). */
|
|
49
|
+
onClose(listener: () => void): void;
|
|
50
50
|
/** Follows `batch`: rebuilds the caller first when a write may change it. */
|
|
51
51
|
flush(batch: Batch, loader: Loader, missed: boolean): Promise<void>;
|
|
52
52
|
/**
|
package/dist/viewer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../src/viewer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE/E,OAAO,EAAY,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAGzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAIxC,MAAM,MAAM,QAAQ,GAAG;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,CAAC;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,CAAC;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,4BAA4B;AAC5B,MAAM,WAAW,UAAU;IAC1B,0EAA0E;IAC1E,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,oEAAoE;IACpE,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CACvB;AAaD,KAAK,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../src/viewer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE/E,OAAO,EAAY,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAGzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAIxC,MAAM,MAAM,QAAQ,GAAG;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,CAAC;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,CAAC;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,4BAA4B;AAC5B,MAAM,WAAW,UAAU;IAC1B,0EAA0E;IAC1E,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,oEAAoE;IACpE,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CACvB;AAaD,KAAK,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAcxD,qBAAa,MAAM;;IAclB,iEAAiE;IACjE,YACC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,EACzB,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,EAUnE;IAED,sEAAsE;IACtE,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,gEAAgE;IAC1D,IAAI,CACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAClC,OAAO,CAAC,UAAU,CAAC,CAErB;IAED,kDAAkD;IAC5C,GAAG,CACR,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAClC,OAAO,CAAC,UAAU,CAAC,CAErB;IAED;;;OAGG;IACG,KAAK,CACV,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAC7C,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAClC,OAAO,CAAC,UAAU,CAAC,CAgCrB;IAED,KAAK,IAAI,IAAI,CASZ;IAED,yEAAyE;IACzE,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAGlC;IAaD,6EAA6E;IACvE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAaxE;IAED;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAI9C;IAED,2DAA2D;IACrD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAwC7B;IA8BD,4CAA4C;IAC5C,GAAG,IAAI,IAAI,CAOV;CAwGD"}
|
package/dist/viewer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { livePlan, recording } from 'ultimabase/internal';
|
|
2
2
|
import { checked, invalid } from './checked.js';
|
|
3
|
-
import { Computed } from './computed.js';
|
|
3
|
+
import { Computed, debounce, ownerOf } from './computed.js';
|
|
4
4
|
import { Live } from './live.js';
|
|
5
5
|
import { liveArgs, shapeOf } from './shape.js';
|
|
6
6
|
import { anyStale } from './stale.js';
|
|
@@ -8,10 +8,6 @@ import { anyStale } from './stale.js';
|
|
|
8
8
|
const soonest = 1000;
|
|
9
9
|
/** The longest wait `setTimeout` keeps. */
|
|
10
10
|
const latest = 2 ** 31 - 1;
|
|
11
|
-
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
12
|
-
export const ownerOf = (fn) => fn.plugin === undefined ? fn.name : `${fn.plugin}.${fn.name}`;
|
|
13
|
-
/** How long a live function's wake waits for quiet, in milliseconds. */
|
|
14
|
-
const debounce = 50;
|
|
15
11
|
/** Who `caller` is, which a rebuilt caller must keep. */
|
|
16
12
|
const whoOf = (caller) => {
|
|
17
13
|
if (caller.kind !== 'user')
|
|
@@ -22,7 +18,8 @@ const whoOf = (caller) => {
|
|
|
22
18
|
export class Viewer {
|
|
23
19
|
#settings;
|
|
24
20
|
#request;
|
|
25
|
-
|
|
21
|
+
/** What runs once it closes, the engine's first (D-163). */
|
|
22
|
+
#listeners = [];
|
|
26
23
|
#onDue;
|
|
27
24
|
#live = new Map();
|
|
28
25
|
#computed = new Map();
|
|
@@ -38,7 +35,7 @@ export class Viewer {
|
|
|
38
35
|
this.#caller = identified.result;
|
|
39
36
|
this.#reads = identified.reads;
|
|
40
37
|
this.#expires = identified.expires;
|
|
41
|
-
this.#
|
|
38
|
+
this.#listeners.push(hooks.onClose);
|
|
42
39
|
this.#onDue = hooks.onDue;
|
|
43
40
|
this.#reschedule();
|
|
44
41
|
}
|
|
@@ -105,7 +102,24 @@ export class Viewer {
|
|
|
105
102
|
for (const computed of this.#computed.keys())
|
|
106
103
|
computed.close();
|
|
107
104
|
this.#computed.clear();
|
|
108
|
-
this.#
|
|
105
|
+
this.#told();
|
|
106
|
+
}
|
|
107
|
+
/** Runs `listener` once it closes, at once when it is closed (D-163). */
|
|
108
|
+
onClose(listener) {
|
|
109
|
+
this.#listeners.push(listener);
|
|
110
|
+
if (this.#closed)
|
|
111
|
+
this.#told();
|
|
112
|
+
}
|
|
113
|
+
/** Runs each listener once; one that throws is logged, not the others. */
|
|
114
|
+
#told() {
|
|
115
|
+
for (const listener of this.#listeners.splice(0)) {
|
|
116
|
+
try {
|
|
117
|
+
listener();
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.#settings.logger.error({ err: error }, 'A close listener failed.');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
109
123
|
}
|
|
110
124
|
/** Follows `batch`: rebuilds the caller first when a write may change it. */
|
|
111
125
|
async flush(batch, loader, missed) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimabase/realtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Realtime for UltimaBase: live lists and live rows that follow every write, under the read rules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"ultimabase": "^0.
|
|
34
|
+
"ultimabase": "^0.2.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@ultimabase/acl": "0.
|
|
38
|
-
"@ultimabase/roles": "0.
|
|
39
|
-
"@ultimabase/soft-delete": "0.
|
|
40
|
-
"@ultimabase/testing": "0.
|
|
41
|
-
"ultimabase": "0.
|
|
37
|
+
"@ultimabase/acl": "0.2.0",
|
|
38
|
+
"@ultimabase/roles": "0.2.0",
|
|
39
|
+
"@ultimabase/soft-delete": "0.2.0",
|
|
40
|
+
"@ultimabase/testing": "0.2.0",
|
|
41
|
+
"ultimabase": "0.2.0",
|
|
42
42
|
"vite": "8.3.4",
|
|
43
43
|
"vitest": "5.0.5"
|
|
44
44
|
}
|
package/src/computed.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// result is sent whole; one equal to the last is not. A wake during a run
|
|
4
4
|
// runs it once more after it, and an error closes it.
|
|
5
5
|
import { isDeepStrictEqual } from 'node:util'
|
|
6
|
-
import type { Caller } from 'ultimabase'
|
|
6
|
+
import type { Caller, ExposedFunction } from 'ultimabase'
|
|
7
7
|
import type { Recorded } from 'ultimabase/internal'
|
|
8
8
|
import { recording } from 'ultimabase/internal'
|
|
9
9
|
import type { Batch } from './changes.ts'
|
|
@@ -11,6 +11,13 @@ import type { LiveMessage } from './messages.ts'
|
|
|
11
11
|
import type { Loader } from './reads.ts'
|
|
12
12
|
import { anyStale } from './stale.ts'
|
|
13
13
|
|
|
14
|
+
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
15
|
+
export const ownerOf = (fn: ExposedFunction): string =>
|
|
16
|
+
fn.plugin === undefined ? fn.name : `${fn.plugin}.${fn.name}`
|
|
17
|
+
|
|
18
|
+
/** How long a live function's wake waits for quiet, in milliseconds. */
|
|
19
|
+
export const debounce = 50
|
|
20
|
+
|
|
14
21
|
/** The longest a run waits after the first wake, however many follow. */
|
|
15
22
|
const longest = 1000
|
|
16
23
|
|
package/src/index.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import type { PluginOf, PluginTypes, UseOf } from 'ultimabase'
|
|
6
6
|
import { definePlugin } from 'ultimabase'
|
|
7
7
|
import manifest from '../package.json' with { type: 'json' }
|
|
8
|
+
import { ownerOf } from './computed.ts'
|
|
8
9
|
import { Engine } from './engine.ts'
|
|
9
10
|
import type { Viewer } from './viewer.ts'
|
|
10
|
-
import { ownerOf } from './viewer.ts'
|
|
11
11
|
|
|
12
12
|
export type { LiveMessage, Removal, Upsert } from './messages.ts'
|
|
13
13
|
export type { LiveHandle, Viewer } from './viewer.ts'
|
package/src/viewer.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Recorded } from 'ultimabase/internal'
|
|
|
9
9
|
import { livePlan, recording } from 'ultimabase/internal'
|
|
10
10
|
import type { Batch } from './changes.ts'
|
|
11
11
|
import { checked, invalid } from './checked.ts'
|
|
12
|
-
import { Computed } from './computed.ts'
|
|
12
|
+
import { Computed, debounce, ownerOf } from './computed.ts'
|
|
13
13
|
import type { LiveMessage } from './messages.ts'
|
|
14
14
|
import { Live } from './live.ts'
|
|
15
15
|
import type { Loader } from './reads.ts'
|
|
@@ -53,13 +53,6 @@ const soonest = 1000
|
|
|
53
53
|
/** The longest wait `setTimeout` keeps. */
|
|
54
54
|
const latest = 2 ** 31 - 1
|
|
55
55
|
|
|
56
|
-
/** A function's name, with its plugin's for a plugin's (D-113). */
|
|
57
|
-
export const ownerOf = (fn: ExposedFunction): string =>
|
|
58
|
-
fn.plugin === undefined ? fn.name : `${fn.plugin}.${fn.name}`
|
|
59
|
-
|
|
60
|
-
/** How long a live function's wake waits for quiet, in milliseconds. */
|
|
61
|
-
const debounce = 50
|
|
62
|
-
|
|
63
56
|
/** Who `caller` is, which a rebuilt caller must keep. */
|
|
64
57
|
const whoOf = (caller: Caller): string => {
|
|
65
58
|
if (caller.kind !== 'user') return JSON.stringify(caller)
|
|
@@ -70,7 +63,8 @@ const whoOf = (caller: Caller): string => {
|
|
|
70
63
|
export class Viewer {
|
|
71
64
|
readonly #settings: Settings
|
|
72
65
|
#request: Request
|
|
73
|
-
|
|
66
|
+
/** What runs once it closes, the engine's first (D-163). */
|
|
67
|
+
readonly #listeners: (() => void)[] = []
|
|
74
68
|
readonly #onDue: () => void
|
|
75
69
|
readonly #live = new Map<Live, Subscription>()
|
|
76
70
|
readonly #computed = new Map<Computed, (message: LiveMessage) => void>()
|
|
@@ -92,7 +86,7 @@ export class Viewer {
|
|
|
92
86
|
this.#caller = identified.result
|
|
93
87
|
this.#reads = identified.reads
|
|
94
88
|
this.#expires = identified.expires
|
|
95
|
-
this.#
|
|
89
|
+
this.#listeners.push(hooks.onClose)
|
|
96
90
|
this.#onDue = hooks.onDue
|
|
97
91
|
this.#reschedule()
|
|
98
92
|
}
|
|
@@ -174,7 +168,24 @@ export class Viewer {
|
|
|
174
168
|
this.#live.clear()
|
|
175
169
|
for (const computed of this.#computed.keys()) computed.close()
|
|
176
170
|
this.#computed.clear()
|
|
177
|
-
this.#
|
|
171
|
+
this.#told()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Runs `listener` once it closes, at once when it is closed (D-163). */
|
|
175
|
+
onClose(listener: () => void): void {
|
|
176
|
+
this.#listeners.push(listener)
|
|
177
|
+
if (this.#closed) this.#told()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Runs each listener once; one that throws is logged, not the others. */
|
|
181
|
+
#told(): void {
|
|
182
|
+
for (const listener of this.#listeners.splice(0)) {
|
|
183
|
+
try {
|
|
184
|
+
listener()
|
|
185
|
+
} catch (error) {
|
|
186
|
+
this.#settings.logger.error({ err: error }, 'A close listener failed.')
|
|
187
|
+
}
|
|
188
|
+
}
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
/** Follows `batch`: rebuilds the caller first when a write may change it. */
|