@estiva-app/platform 0.1.0 → 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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @estiva-app/platform
2
2
 
3
+ ## 0.2.0
4
+
5
+ A Folder notification may carry the event that caused it (PER-8). Additive:
6
+ every existing listener keeps compiling and behaving as before.
7
+
8
+ - `watchFolders`' listener is called `(folder, event)`. The wide filter always
9
+ had the event in hand and dropped it, so a reader that keeps what it has read
10
+ — Peek's sidebar, which re-read 90 days of every Folder to learn about the one
11
+ message the socket had just delivered — had nothing to apply and could only
12
+ re-read, against a relay quota metered per HTTP request.
13
+ - `watchFolders` takes `since`, bounding what the REQ replays on subscribe and
14
+ on every reconnect. Without it the relay replays up to its default limit,
15
+ shared across every Folder in the filter.
16
+ - `FolderListener` is `(event?) => void` and `FolderActivity.notify` takes the
17
+ event. A notification with nothing to carry — another app's record moved —
18
+ still sends none, so a missing event means "re-read", never "nothing".
19
+
3
20
  ## 0.1.0
4
21
 
5
22
  First release. The plumbing a second consumer of the live socket needs, taken
@@ -23,11 +23,26 @@
23
23
  * reader watching its own Folders is in the same position mechanically and the
24
24
  * word stops fitting, so the shared name is about the Folder rather than about
25
25
  * whose records are in it.
26
+ *
27
+ * ## …unless it has one to give (PER-8)
28
+ *
29
+ * "Re-read now" was the right signal while nobody held what they had read. Once
30
+ * a reader keeps the events it already has — Peek's sidebar re-read 90 days of
31
+ * every Folder to learn about the one message the socket had just delivered, and
32
+ * spent the relay's per-request HTTP quota doing it — the event is the whole
33
+ * point. So a notification *may* carry the event that caused it. A listener
34
+ * that ignores the argument is exactly the listener it was before, and a
35
+ * notification with nothing to carry (another app's record moved) still sends
36
+ * none, so a reader must treat a missing event as "re-read", not as "nothing".
26
37
  */
27
- export type FolderListener = () => void;
38
+ import type { SignedEvent } from '@estiva-app/protocol';
39
+ export type FolderListener = (event?: SignedEvent) => void;
28
40
  export interface FolderActivity {
29
- /** Say that something changed in `folder`. Safe for a folder nobody watches. */
30
- notify(folder: string): void;
41
+ /**
42
+ * Say that something changed in `folder`, and hand over the event when there
43
+ * is one. Safe for a folder nobody watches.
44
+ */
45
+ notify(folder: string, event?: SignedEvent): void;
31
46
  /** Watch one folder. Returns an unsubscribe; calling it twice is harmless. */
32
47
  watch(folder: string, listener: FolderListener): () => void;
33
48
  /** Folders with at least one listener. Test and diagnostic seam. */
@@ -1 +1 @@
1
- {"version":3,"file":"folder-activity.d.ts","sourceRoot":"","sources":["../src/folder-activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,IAAI,CAAA;AAEvC,MAAM,WAAW,cAAc;IAC7B,gFAAgF;IAChF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,8EAA8E;IAC9E,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAA;IAC3D,oEAAoE;IACpE,OAAO,IAAI,MAAM,EAAE,CAAA;CACpB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CA8BrD"}
1
+ {"version":3,"file":"folder-activity.d.ts","sourceRoot":"","sources":["../src/folder-activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;AAE1D,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IACjD,8EAA8E;IAC9E,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAA;IAC3D,oEAAoE;IACpE,OAAO,IAAI,MAAM,EAAE,CAAA;CACpB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CA8BrD"}
@@ -1,12 +1,12 @@
1
1
  export function createFolderActivity() {
2
2
  const listeners = new Map();
3
3
  return {
4
- notify(folder) {
4
+ notify(folder, event) {
5
5
  for (const listener of listeners.get(folder) ?? []) {
6
6
  // One bad listener must not stop the others, and must not surface
7
7
  // somewhere unrelated as a relay error.
8
8
  try {
9
- listener();
9
+ listener(event);
10
10
  }
11
11
  catch {
12
12
  /* a listener's own problem */
@@ -1 +1 @@
1
- {"version":3,"file":"folder-activity.js","sourceRoot":"","sources":["../src/folder-activity.ts"],"names":[],"mappings":"AAqCA,MAAM,UAAU,oBAAoB;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAA;IACxD,OAAO;QACL,MAAM,CAAC,MAAM;YACX,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnD,kEAAkE;gBAClE,wCAAwC;gBACxC,IAAI,CAAC;oBACH,QAAQ,EAAE,CAAA;gBACZ,CAAC;gBAAC,MAAM,CAAC;oBACP,8BAA8B;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,QAAQ;YACpB,IAAI,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACrC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;gBACrB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YAClC,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACvB,OAAO,GAAG,EAAE;gBACV,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBACrC,IAAI,CAAC,OAAO;oBAAE,OAAM;gBACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACxB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAClD,CAAC,CAAA;QACH,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;KACrC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"folder-activity.js","sourceRoot":"","sources":["../src/folder-activity.ts"],"names":[],"mappings":"AAqDA,MAAM,UAAU,oBAAoB;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAA;IACxD,OAAO;QACL,MAAM,CAAC,MAAM,EAAE,KAAK;YAClB,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnD,kEAAkE;gBAClE,wCAAwC;gBACxC,IAAI,CAAC;oBACH,QAAQ,CAAC,KAAK,CAAC,CAAA;gBACjB,CAAC;gBAAC,MAAM,CAAC;oBACP,8BAA8B;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,QAAQ;YACpB,IAAI,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACrC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,GAAG,IAAI,GAAG,EAAE,CAAA;gBACrB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YAClC,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACvB,OAAO,GAAG,EAAE;gBACV,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBACrC,IAAI,CAAC,OAAO;oBAAE,OAAM;gBACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACxB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAClD,CAAC,CAAA;QACH,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;KACrC,CAAA;AACH,CAAC"}
@@ -126,9 +126,18 @@ export interface LiveClient {
126
126
  * `kinds` is strongly recommended rather than optional-by-taste: a kindless
127
127
  * wide filter was refused outright on that other build with `restricted:
128
128
  * p-gated events require #p matching your pubkey`.
129
+ *
130
+ * **The listener is handed the event** (PER-8). A reader that keeps what it
131
+ * has read applies it instead of re-reading the Folder; one that only wants
132
+ * the signal ignores the second argument. Stored events arrive as well as
133
+ * live ones — the REQ's replay on subscribe and on every reconnect — so a
134
+ * reader must be idempotent by event id. `since` bounds that replay: without
135
+ * it the relay replays whatever its default limit allows, shared across every
136
+ * Folder in the filter, which a keeping reader then has to dedupe.
129
137
  */
130
- watchFolders(folders: string[], listener: (folder: string) => void, options?: {
138
+ watchFolders(folders: string[], listener: (folder: string, event?: SignedEvent) => void, options?: {
131
139
  kinds?: number[];
140
+ since?: number;
132
141
  }): FolderWatch;
133
142
  /** Watch one Folder by name. The refcounted half of {@link watchFolders}. */
134
143
  onFolderActivity(folder: string, listener: FolderListener): () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"live-client.d.ts","sourceRoot":"","sources":["../src/live-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"live-client.d.ts","sourceRoot":"","sources":["../src/live-client.ts"],"names":[],"mappings":"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"}
@@ -139,11 +139,17 @@ export function createLiveClient(options) {
139
139
  },
140
140
  onFolderActivity: (folder, listener) => activity.watch(folder, listener),
141
141
  watchFolders(folders, listener, watchOptions) {
142
- const unwatch = folders.map((folder) => activity.watch(folder, () => listener(folder)));
143
- const subs = chunk([...new Set(folders)], MAX_FOLDERS_PER_SUBSCRIPTION).map((group) => relay.subscribe([{ ...(watchOptions?.kinds ? { kinds: watchOptions.kinds } : {}), '#h': group }], (event) => {
142
+ const unwatch = folders.map((folder) => activity.watch(folder, (event) => listener(folder, event)));
143
+ const subs = chunk([...new Set(folders)], MAX_FOLDERS_PER_SUBSCRIPTION).map((group) => relay.subscribe([
144
+ {
145
+ ...(watchOptions?.kinds ? { kinds: watchOptions.kinds } : {}),
146
+ '#h': group,
147
+ ...(watchOptions?.since !== undefined ? { since: watchOptions.since } : {}),
148
+ },
149
+ ], (event) => {
144
150
  const folder = folderOf(event);
145
151
  if (folder)
146
- activity.notify(folder);
152
+ activity.notify(folder, event);
147
153
  }, {
148
154
  onClosed: (reason) => options.log?.('folder subscription closed', { reason }),
149
155
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"live-client.js","sourceRoot":"","sources":["../src/live-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"live-client.js","sourceRoot":"","sources":["../src/live-client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@estiva-app/platform",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Browser lifecycle two Estiva apps share: the one live relay socket a tab should hold, its credential read per connect, and the network coming back.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,12 +23,28 @@
23
23
  * reader watching its own Folders is in the same position mechanically and the
24
24
  * word stops fitting, so the shared name is about the Folder rather than about
25
25
  * whose records are in it.
26
+ *
27
+ * ## …unless it has one to give (PER-8)
28
+ *
29
+ * "Re-read now" was the right signal while nobody held what they had read. Once
30
+ * a reader keeps the events it already has — Peek's sidebar re-read 90 days of
31
+ * every Folder to learn about the one message the socket had just delivered, and
32
+ * spent the relay's per-request HTTP quota doing it — the event is the whole
33
+ * point. So a notification *may* carry the event that caused it. A listener
34
+ * that ignores the argument is exactly the listener it was before, and a
35
+ * notification with nothing to carry (another app's record moved) still sends
36
+ * none, so a reader must treat a missing event as "re-read", not as "nothing".
26
37
  */
27
- export type FolderListener = () => void
38
+ import type { SignedEvent } from '@estiva-app/protocol'
39
+
40
+ export type FolderListener = (event?: SignedEvent) => void
28
41
 
29
42
  export interface FolderActivity {
30
- /** Say that something changed in `folder`. Safe for a folder nobody watches. */
31
- notify(folder: string): void
43
+ /**
44
+ * Say that something changed in `folder`, and hand over the event when there
45
+ * is one. Safe for a folder nobody watches.
46
+ */
47
+ notify(folder: string, event?: SignedEvent): void
32
48
  /** Watch one folder. Returns an unsubscribe; calling it twice is harmless. */
33
49
  watch(folder: string, listener: FolderListener): () => void
34
50
  /** Folders with at least one listener. Test and diagnostic seam. */
@@ -38,12 +54,12 @@ export interface FolderActivity {
38
54
  export function createFolderActivity(): FolderActivity {
39
55
  const listeners = new Map<string, Set<FolderListener>>()
40
56
  return {
41
- notify(folder) {
57
+ notify(folder, event) {
42
58
  for (const listener of listeners.get(folder) ?? []) {
43
59
  // One bad listener must not stop the others, and must not surface
44
60
  // somewhere unrelated as a relay error.
45
61
  try {
46
- listener()
62
+ listener(event)
47
63
  } catch {
48
64
  /* a listener's own problem */
49
65
  }
@@ -141,11 +141,19 @@ export interface LiveClient {
141
141
  * `kinds` is strongly recommended rather than optional-by-taste: a kindless
142
142
  * wide filter was refused outright on that other build with `restricted:
143
143
  * p-gated events require #p matching your pubkey`.
144
+ *
145
+ * **The listener is handed the event** (PER-8). A reader that keeps what it
146
+ * has read applies it instead of re-reading the Folder; one that only wants
147
+ * the signal ignores the second argument. Stored events arrive as well as
148
+ * live ones — the REQ's replay on subscribe and on every reconnect — so a
149
+ * reader must be idempotent by event id. `since` bounds that replay: without
150
+ * it the relay replays whatever its default limit allows, shared across every
151
+ * Folder in the filter, which a keeping reader then has to dedupe.
144
152
  */
145
153
  watchFolders(
146
154
  folders: string[],
147
- listener: (folder: string) => void,
148
- options?: { kinds?: number[] },
155
+ listener: (folder: string, event?: SignedEvent) => void,
156
+ options?: { kinds?: number[]; since?: number },
149
157
  ): FolderWatch
150
158
  /** Watch one Folder by name. The refcounted half of {@link watchFolders}. */
151
159
  onFolderActivity(folder: string, listener: FolderListener): () => void
@@ -247,13 +255,19 @@ export function createLiveClient(options: LiveClientOptions): LiveClient {
247
255
  },
248
256
  onFolderActivity: (folder, listener) => activity.watch(folder, listener),
249
257
  watchFolders(folders, listener, watchOptions) {
250
- const unwatch = folders.map((folder) => activity.watch(folder, () => listener(folder)))
258
+ const unwatch = folders.map((folder) => activity.watch(folder, (event) => listener(folder, event)))
251
259
  const subs = chunk([...new Set(folders)], MAX_FOLDERS_PER_SUBSCRIPTION).map((group) =>
252
260
  relay.subscribe(
253
- [{ ...(watchOptions?.kinds ? { kinds: watchOptions.kinds } : {}), '#h': group }],
261
+ [
262
+ {
263
+ ...(watchOptions?.kinds ? { kinds: watchOptions.kinds } : {}),
264
+ '#h': group,
265
+ ...(watchOptions?.since !== undefined ? { since: watchOptions.since } : {}),
266
+ },
267
+ ],
254
268
  (event) => {
255
269
  const folder = folderOf(event)
256
- if (folder) activity.notify(folder)
270
+ if (folder) activity.notify(folder, event)
257
271
  },
258
272
  {
259
273
  onClosed: (reason) => options.log?.('folder subscription closed', { reason }),