orez-sync-executor 0.11.1 → 0.11.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 (57) hide show
  1. package/dist/realtime/host.d.ts +7 -0
  2. package/dist/realtime/host.d.ts.map +1 -0
  3. package/dist/realtime/host.js +77 -0
  4. package/dist/realtime/host.js.map +1 -0
  5. package/dist/realtime/hub.d.ts +67 -0
  6. package/dist/realtime/hub.d.ts.map +1 -0
  7. package/dist/realtime/hub.js +456 -0
  8. package/dist/realtime/hub.js.map +1 -0
  9. package/dist/realtime/index.d.ts +24 -0
  10. package/dist/realtime/index.d.ts.map +1 -0
  11. package/dist/realtime/index.js +27 -0
  12. package/dist/realtime/index.js.map +1 -0
  13. package/dist/realtime/local.d.ts +15 -0
  14. package/dist/realtime/local.d.ts.map +1 -0
  15. package/dist/realtime/local.js +63 -0
  16. package/dist/realtime/local.js.map +1 -0
  17. package/dist/realtime/manifest.d.ts +51 -0
  18. package/dist/realtime/manifest.d.ts.map +1 -0
  19. package/dist/realtime/manifest.js +110 -0
  20. package/dist/realtime/manifest.js.map +1 -0
  21. package/dist/realtime/message-port.d.ts +34 -0
  22. package/dist/realtime/message-port.d.ts.map +1 -0
  23. package/dist/realtime/message-port.js +141 -0
  24. package/dist/realtime/message-port.js.map +1 -0
  25. package/dist/realtime/producer-socket.d.ts +10 -0
  26. package/dist/realtime/producer-socket.d.ts.map +1 -0
  27. package/dist/realtime/producer-socket.js +90 -0
  28. package/dist/realtime/producer-socket.js.map +1 -0
  29. package/dist/realtime/producer.d.ts +16 -0
  30. package/dist/realtime/producer.d.ts.map +1 -0
  31. package/dist/realtime/producer.js +51 -0
  32. package/dist/realtime/producer.js.map +1 -0
  33. package/dist/realtime/protocol.d.ts +99 -0
  34. package/dist/realtime/protocol.d.ts.map +1 -0
  35. package/dist/realtime/protocol.js +191 -0
  36. package/dist/realtime/protocol.js.map +1 -0
  37. package/dist/realtime/publisher.d.ts +28 -0
  38. package/dist/realtime/publisher.d.ts.map +1 -0
  39. package/dist/realtime/publisher.js +309 -0
  40. package/dist/realtime/publisher.js.map +1 -0
  41. package/dist/realtime/socket-host.d.ts +25 -0
  42. package/dist/realtime/socket-host.d.ts.map +1 -0
  43. package/dist/realtime/socket-host.js +105 -0
  44. package/dist/realtime/socket-host.js.map +1 -0
  45. package/dist/realtime/store.d.ts +28 -0
  46. package/dist/realtime/store.d.ts.map +1 -0
  47. package/dist/realtime/store.js +0 -0
  48. package/dist/realtime/store.js.map +1 -0
  49. package/dist/realtime/writer.d.ts +17 -0
  50. package/dist/realtime/writer.d.ts.map +1 -0
  51. package/dist/realtime/writer.js +138 -0
  52. package/dist/realtime/writer.js.map +1 -0
  53. package/package.json +5 -1
  54. package/dist/adapters.d.ts +0 -25
  55. package/dist/adapters.d.ts.map +0 -1
  56. package/dist/adapters.js +0 -116
  57. package/dist/adapters.js.map +0 -1
@@ -0,0 +1,24 @@
1
+ export { defineStreamingFields, resolveTopic } from './manifest.js';
2
+ export type { FieldMode, StreamingFieldDeclaration, StreamingFieldOptions, StreamingFieldHandle, StreamingFieldRef, StreamingFieldSpec, StreamingManifest, ZeroSchemaShape, } from './manifest.js';
3
+ export { canonicalPrimaryKey, canonicalTopic, decodeFrame, encodeFrame, isLegacyWake, LEGACY_WAKE_FRAME, TOPIC_SEPARATOR, } from './protocol.js';
4
+ export type { AnyFrame, ClientFrame, FieldUpdate, HostFrame, ProducerFrame, ProducerHostFrame, RealtimeKeyValue, RealtimeTopic, } from './protocol.js';
5
+ export { canonicalEncode, RealtimeStore } from './store.js';
6
+ export type { RealtimeStoreOptions, StreamingFieldState, StreamingPhase, } from './store.js';
7
+ export { RealtimePublisher } from './publisher.js';
8
+ export type { BeginOptions, PublisherTransport, StreamSession } from './publisher.js';
9
+ export { DEFAULT_HUB_LIMITS, RealtimeHub } from './hub.js';
10
+ export type { HubConnection, HubLimits, HubOptions, HubProducer, RealtimeIdentity, SubscribeAuthorization, } from './hub.js';
11
+ export { FieldWriter } from './writer.js';
12
+ export type { FieldWriterOptions } from './writer.js';
13
+ export { createLocalRealtime } from './local.js';
14
+ export type { LocalRealtime, LocalRealtimeOptions } from './local.js';
15
+ export { BrowserRealtime, connectRealtimePort } from './message-port.js';
16
+ export type { BrowserRealtimeOptions, MembershipReader } from './message-port.js';
17
+ export { applyClientFrame, applyHostFrame, applyProducerFrame } from './host.js';
18
+ export { createProducer, inProcessTransport } from './producer.js';
19
+ export type { ProducerOptions, RealtimeProducer } from './producer.js';
20
+ export { createSocketHost } from './socket-host.js';
21
+ export type { HostConnection, HostSocket, RealtimeSocketHost } from './socket-host.js';
22
+ export { createSocketProducer } from './producer-socket.js';
23
+ export type { ProducerSocket, SocketProducer } from './producer-socket.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACnE,YAAY,EACV,SAAS,EACT,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,GAChB,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3D,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,GACf,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAErF,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC1D,YAAY,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAErE,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACxE,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGjF,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAGhF,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAItF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,27 @@
1
+ // Streaming fields: an ephemeral, typed field overlay beside Zero.
2
+ //
3
+ // The ordinary Zero row stays the durable truth. During a stream orez
4
+ // broadcasts field values without writing the application row or advancing the
5
+ // Zero cookie, and the application commits the final value through its existing
6
+ // write path. See plans/streaming-fields.md for the design and its rejected
7
+ // alternatives.
8
+ export { defineStreamingFields, resolveTopic } from './manifest.js';
9
+ export { canonicalPrimaryKey, canonicalTopic, decodeFrame, encodeFrame, isLegacyWake, LEGACY_WAKE_FRAME, TOPIC_SEPARATOR, } from './protocol.js';
10
+ export { canonicalEncode, RealtimeStore } from './store.js';
11
+ export { RealtimePublisher } from './publisher.js';
12
+ export { DEFAULT_HUB_LIMITS, RealtimeHub } from './hub.js';
13
+ export { FieldWriter } from './writer.js';
14
+ export { createLocalRealtime } from './local.js';
15
+ export { BrowserRealtime, connectRealtimePort } from './message-port.js';
16
+ // Frame routing. One applier per direction; every surface is built from these.
17
+ export { applyClientFrame, applyHostFrame, applyProducerFrame } from './host.js';
18
+ // The producer role, identical on every surface
19
+ export { createProducer, inProcessTransport } from './producer.js';
20
+ // The host role over sockets, for any runtime that has them
21
+ export { createSocketHost } from './socket-host.js';
22
+ // A producer that reaches the hub over a socket: an application server
23
+ // generating values while the subscribers are browsers elsewhere
24
+ export { createSocketProducer } from './producer-socket.js';
25
+ // The React binding lives in on-zero, which already owns the React peer
26
+ // dependency. orez-lite stays framework-free: see on-zero's useStreamingField.
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/realtime/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,sEAAsE;AACtE,+EAA+E;AAC/E,gFAAgF;AAChF,4EAA4E;AAC5E,gBAAgB;AAEhB,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAYnE,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,eAAe,GAChB,MAAM,eAAe,CAAA;AAYtB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAO3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAGlD,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAU1D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGhD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGxE,+EAA+E;AAC/E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAEhF,gDAAgD;AAChD,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAGlE,4DAA4D;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD,uEAAuE;AACvE,iEAAiE;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAG3D,wEAAwE;AACxE,+EAA+E"}
@@ -0,0 +1,15 @@
1
+ import { RealtimeStore } from './store.js';
2
+ import type { StreamingManifest } from './manifest.js';
3
+ import type { RealtimeProducer } from './producer.js';
4
+ export type LocalRealtimeOptions = {
5
+ readonly manifest: StreamingManifest;
6
+ readonly staleAfterMs?: number;
7
+ readonly onError?: (message: string) => void;
8
+ };
9
+ export type LocalRealtime = RealtimeProducer & {
10
+ readonly store: RealtimeStore;
11
+ readonly flush: () => void;
12
+ readonly close: () => void;
13
+ };
14
+ export declare function createLocalRealtime(options: LocalRealtimeOptions): LocalRealtime;
15
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/realtime/local.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGrD,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IAEpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C,CAAA;AAID,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG;IAE7C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAG7B,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B,CAAA;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA0ChF"}
@@ -0,0 +1,63 @@
1
+ // Single-client realtime: a hub, a publisher, and a store wired together in
2
+ // one JavaScript context, with no socket, no host, and no authorization.
3
+ //
4
+ // This is the shape an application needs when the thing producing the values
5
+ // and the thing displaying them are the same client. Soot's agent loop runs in
6
+ // the browser: the tab running the agent is the tab rendering its output, so
7
+ // routing those values through a server and back would add latency and an auth
8
+ // surface to reach the component sitting next to the producer.
9
+ //
10
+ // It is the same RealtimeHub every other host runs, so a stream behaves
11
+ // identically here and over a socket: same generations, same append
12
+ // accumulation, same durable handoff, same manifest bounds. Moving an
13
+ // application from local to a shared host changes which realtime it constructs
14
+ // and nothing about its components or its producer code.
15
+ //
16
+ // What it deliberately does NOT do is reach other clients. Values live in this
17
+ // context only. The durable Zero row remains the cross-client story, which is
18
+ // exactly the guarantee the overlay already makes: a reload, another tab, or
19
+ // another user sees the committed value, never the in-flight one.
20
+ import { applyClientFrame, applyHostFrame } from './host.js';
21
+ import { RealtimeHub } from './hub.js';
22
+ import { createProducer, inProcessTransport } from './producer.js';
23
+ import { RealtimeStore } from './store.js';
24
+ export function createLocalRealtime(options) {
25
+ // Every row is authorized: there is one client, it is the producer, and it
26
+ // already holds the data it is about to display. There is nothing to
27
+ // authorize against and nobody to withhold it from.
28
+ const hub = new RealtimeHub({
29
+ manifest: options.manifest,
30
+ authorizeSubscribe: () => ({ status: 'active' }),
31
+ // No batching: the window exists to collapse several updates into one
32
+ // WebSocket frame, and there is no socket here. Deferring an in-process
33
+ // call would only add a tick of latency between the producer and the
34
+ // component next to it.
35
+ scheduleFlush: (flush) => flush(),
36
+ });
37
+ const store = new RealtimeStore({
38
+ send: (frame) => void applyClientFrame(hub, connection, frame),
39
+ staleAfterMs: options.staleAfterMs,
40
+ onError: options.onError,
41
+ });
42
+ const connection = {
43
+ id: 'local',
44
+ identity: { userID: 'local', clientID: 'local', clientGroupID: 'local' },
45
+ // Frames are handed straight to the store, not serialized: this is one
46
+ // context, and a JSON round trip per token would be pure cost. The routing
47
+ // is still the shared one, so a frame means the same thing here as it does
48
+ // over a socket.
49
+ send: (frame) => applyHostFrame(store, frame),
50
+ };
51
+ const producerHandle = { id: 'local-producer', send: () => { } };
52
+ const producer = createProducer(inProcessTransport(hub, producerHandle), options);
53
+ return {
54
+ store,
55
+ ...producer,
56
+ flush: () => hub.flush(),
57
+ close: () => {
58
+ hub.dropProducer(producerHandle.id);
59
+ hub.dropConnection(connection.id);
60
+ },
61
+ };
62
+ }
63
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/realtime/local.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,+DAA+D;AAC/D,EAAE;AACF,wEAAwE;AACxE,oEAAoE;AACpE,sEAAsE;AACtE,+EAA+E;AAC/E,yDAAyD;AACzD,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,kEAAkE;AAElE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAyB1C,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,2EAA2E;IAC3E,qEAAqE;IACrE,oDAAoD;IACpD,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC;QAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAChD,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,wBAAwB;QACxB,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE;KAClC,CAAC,CAAA;IAEF,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC;QAC9B,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,KAAoB,CAAC;QAC7E,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAkB;QAChC,EAAE,EAAE,OAAO;QACX,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE;QACxE,uEAAuE;QACvE,2EAA2E;QAC3E,2EAA2E;QAC3E,iBAAiB;QACjB,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,KAAkB,CAAC;KAC3D,CAAA;IAED,MAAM,cAAc,GAAgB,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAA;IAC5E,MAAM,QAAQ,GAAG,cAAc,CAAC,kBAAkB,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAA;IAEjF,OAAO;QACL,KAAK;QACL,GAAG,QAAQ;QACX,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE;QACxB,KAAK,EAAE,GAAG,EAAE;YACV,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;YACnC,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QACnC,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { RealtimeKeyValue, RealtimeTopic } from './protocol.js';
2
+ export type ZeroSchemaShape = {
3
+ readonly tables: Readonly<Record<string, {
4
+ readonly columns: Readonly<Record<string, {
5
+ readonly type: string;
6
+ }>>;
7
+ readonly primaryKey: readonly string[];
8
+ }>>;
9
+ };
10
+ export type FieldMode = 'append' | 'replace';
11
+ export type StreamingFieldOptions = {
12
+ readonly maxBytes: number;
13
+ readonly maxUpdatesPerSecond: number;
14
+ readonly maxBytesPerSecond: number;
15
+ readonly mode?: FieldMode;
16
+ readonly validate?: (value: unknown) => boolean;
17
+ };
18
+ export type StreamingFieldSpec = StreamingFieldOptions & {
19
+ readonly table: string;
20
+ readonly field: string;
21
+ readonly mode: FieldMode;
22
+ readonly columnType: string;
23
+ readonly primaryKey: readonly string[];
24
+ };
25
+ export type StreamingManifest = {
26
+ readonly fields: ReadonlyMap<string, StreamingFieldSpec>;
27
+ readonly schemaKey: string;
28
+ };
29
+ export type StreamingFieldHandle = {
30
+ readonly topic: RealtimeTopic;
31
+ readonly spec: StreamingFieldSpec;
32
+ };
33
+ export type StreamingFieldRef<Key, Value> = ((key: Key) => StreamingFieldHandle) & {
34
+ readonly spec: StreamingFieldSpec;
35
+ readonly __value?: Value;
36
+ };
37
+ export type StreamingFieldDeclaration = Readonly<Record<string, Readonly<Record<string, StreamingFieldOptions>>>>;
38
+ export declare function defineStreamingFields<Declaration extends StreamingFieldDeclaration>(schema: ZeroSchemaShape, declaration: Declaration): {
39
+ readonly manifest: StreamingManifest;
40
+ } & {
41
+ readonly [Table in keyof Declaration]: {
42
+ readonly [Field in keyof Declaration[Table]]: StreamingFieldRef<Record<string, RealtimeKeyValue>, unknown>;
43
+ };
44
+ };
45
+ export declare function resolveTopic(manifest: StreamingManifest, topic: RealtimeTopic): {
46
+ readonly spec: StreamingFieldSpec;
47
+ readonly id: string;
48
+ } | {
49
+ readonly reason: string;
50
+ };
51
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/realtime/manifest.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEpE,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CACvB,MAAM,CACJ,MAAM,EACN;QACE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC,CAAA;QACrE,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;KACvC,CACF,CACF,CAAA;CACF,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE5C,MAAM,MAAM,qBAAqB,GAAG;IAElC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IAGpC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAElC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IAKzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,GAAG;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IAIxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B,CAAA;AAMD,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;CAClC,CAAA;AAGD,MAAM,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,oBAAoB,CAAC,GAAG;IACjF,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;IAEjC,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CACzB,CAAA;AAoBD,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAC9C,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAChE,CAAA;AAED,wBAAgB,qBAAqB,CAAC,WAAW,SAAS,yBAAyB,EACjF,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,WAAW,GACvB;IACD,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;CACrC,GAAG;IACF,QAAQ,EAAE,KAAK,IAAI,MAAM,WAAW,GAAG;QACrC,QAAQ,EAAE,KAAK,IAAI,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,iBAAiB,CAC7D,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAChC,OAAO,CACR;KACF;CACF,CA0EA;AAuBD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,aAAa,GAElB;IAAE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAU9B"}
@@ -0,0 +1,110 @@
1
+ // The streaming-field manifest: which columns may stream, in what mode, under
2
+ // what bounds.
3
+ //
4
+ // It stays PARALLEL to the Zero schema rather than being a property on it.
5
+ // Zero derives its client schema and compatibility hash from the stock column
6
+ // shape, so an orez-specific property there would change Zero's schema identity
7
+ // or depend on how its runtime treats unknown keys. The manifest takes the
8
+ // schema as input, validates every table and column against it, and produces a
9
+ // separate object.
10
+ import { canonicalTopic } from './protocol.js';
11
+ const APPENDABLE_TYPES = new Set(['string']);
12
+ const VALIDATOR_REQUIRED_TYPES = new Set(['json']);
13
+ function schemaIdentity(schema, fields) {
14
+ // identity covers exactly what a mismatch would break: the streamed columns,
15
+ // their type, their mode, and the key ordering topics are built from.
16
+ return fields
17
+ .map((spec) => {
18
+ const table = schema.tables[spec.table];
19
+ return `${spec.table}.${spec.field}:${spec.columnType}:${spec.mode}:${table.primaryKey.join(',')}`;
20
+ })
21
+ .sort()
22
+ .join('|');
23
+ }
24
+ export function defineStreamingFields(schema, declaration) {
25
+ const specs = [];
26
+ const tables = {};
27
+ for (const [table, fields] of Object.entries(declaration)) {
28
+ const schemaTable = schema.tables[table];
29
+ if (!schemaTable) {
30
+ throw new TypeError(`streaming field table '${table}' is not in the Zero schema`);
31
+ }
32
+ if (schemaTable.primaryKey.length === 0) {
33
+ throw new TypeError(`streaming field table '${table}' has no primary key`);
34
+ }
35
+ const refs = {};
36
+ for (const [field, options] of Object.entries(fields)) {
37
+ const column = schemaTable.columns[field];
38
+ if (!column) {
39
+ throw new TypeError(`streaming field '${table}.${field}' is not in the Zero schema`);
40
+ }
41
+ if (schemaTable.primaryKey.includes(field)) {
42
+ throw new TypeError(`streaming field '${table}.${field}' is a primary key column; a streamed key would change the row's identity mid-generation`);
43
+ }
44
+ validateBounds(table, field, options);
45
+ const mode = options.mode ?? (APPENDABLE_TYPES.has(column.type) ? 'append' : 'replace');
46
+ if (mode === 'append' && !APPENDABLE_TYPES.has(column.type)) {
47
+ throw new TypeError(`streaming field '${table}.${field}' is a ${column.type} column; append mode concatenates and only applies to string columns`);
48
+ }
49
+ if (VALIDATOR_REQUIRED_TYPES.has(column.type) && !options.validate) {
50
+ throw new TypeError(`streaming field '${table}.${field}' is a ${column.type} column and must supply validate(); Zero carries no runtime validator for it and realtime values bypass PayloadCodec.decodePull`);
51
+ }
52
+ const spec = {
53
+ ...options,
54
+ table,
55
+ field,
56
+ mode,
57
+ columnType: column.type,
58
+ primaryKey: schemaTable.primaryKey,
59
+ };
60
+ specs.push(spec);
61
+ const ref = ((key) => {
62
+ for (const column of spec.primaryKey) {
63
+ if (key[column] === undefined) {
64
+ throw new TypeError(`streaming topic '${table}.${field}' is missing primary key column '${column}'`);
65
+ }
66
+ }
67
+ return { topic: { table, key, field }, spec };
68
+ });
69
+ Object.defineProperty(ref, 'spec', { value: spec, enumerable: true });
70
+ refs[field] = ref;
71
+ }
72
+ tables[table] = refs;
73
+ }
74
+ const fieldMap = new Map();
75
+ for (const spec of specs)
76
+ fieldMap.set(`${spec.table}.${spec.field}`, spec);
77
+ return {
78
+ ...tables,
79
+ manifest: { fields: fieldMap, schemaKey: schemaIdentity(schema, specs) },
80
+ };
81
+ }
82
+ function validateBounds(table, field, options) {
83
+ const bounds = [
84
+ ['maxBytes', options.maxBytes],
85
+ ['maxUpdatesPerSecond', options.maxUpdatesPerSecond],
86
+ ['maxBytesPerSecond', options.maxBytesPerSecond],
87
+ ];
88
+ for (const [name, value] of bounds) {
89
+ if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
90
+ throw new TypeError(`streaming field '${table}.${field}' needs a positive ${name}`);
91
+ }
92
+ }
93
+ }
94
+ // Host-side lookup: resolve a topic against the manifest, returning the spec
95
+ // and the canonical wire identity, or a reason the topic is not streamable.
96
+ // Every host runs this before it will fan anything out, so a producer bug or a
97
+ // crafted subscribe frame cannot create a topic outside the manifest.
98
+ export function resolveTopic(manifest, topic) {
99
+ const spec = manifest.fields.get(`${topic.table}.${topic.field}`);
100
+ if (!spec)
101
+ return { reason: `'${topic.table}.${topic.field}' is not a streaming field` };
102
+ for (const column of spec.primaryKey) {
103
+ const value = topic.key[column];
104
+ if (value === undefined) {
105
+ return { reason: `topic is missing primary key column '${column}'` };
106
+ }
107
+ }
108
+ return { spec, id: canonicalTopic(spec.primaryKey, topic) };
109
+ }
110
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/realtime/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { RealtimeHub } from './hub.js';
2
+ import { RealtimeStore } from './store.js';
3
+ import type { RealtimeIdentity } from './hub.js';
4
+ import type { StreamingManifest } from './manifest.js';
5
+ import type { RealtimeTopic } from './protocol.js';
6
+ import type { RealtimePublisher } from './publisher.js';
7
+ import type { FieldWriter } from './writer.js';
8
+ export type MembershipReader = (identity: RealtimeIdentity, table: string, key: Readonly<Record<string, boolean | null | number | string>>) => Promise<{
9
+ readonly ownsGroup: boolean;
10
+ readonly authorized: boolean;
11
+ }>;
12
+ export type BrowserRealtimeOptions = {
13
+ readonly manifest: StreamingManifest;
14
+ readonly readMembership: MembershipReader;
15
+ readonly onError?: (message: string) => void;
16
+ };
17
+ export declare class BrowserRealtime {
18
+ #private;
19
+ constructor(options: BrowserRealtimeOptions);
20
+ get fields(): FieldWriter;
21
+ get publisher(): RealtimePublisher;
22
+ connect(port: MessagePort, identity: RealtimeIdentity): () => void;
23
+ revokeMembership(clientGroupID: string, removed: readonly RealtimeTopic[]): void;
24
+ flush(): void;
25
+ get hub(): RealtimeHub;
26
+ }
27
+ export declare function connectRealtimePort(port: MessagePort, options?: {
28
+ readonly staleAfterMs?: number;
29
+ readonly onError?: (message: string) => void;
30
+ }): {
31
+ readonly store: RealtimeStore;
32
+ readonly close: () => void;
33
+ };
34
+ //# sourceMappingURL=message-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-port.d.ts","sourceRoot":"","sources":["../../src/realtime/message-port.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAGtC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,OAAO,KAAK,EAGV,gBAAgB,EAEjB,MAAM,UAAU,CAAA;AACjB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAI9C,MAAM,MAAM,gBAAgB,GAAG,CAC7B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC,KAC5D,OAAO,CAAC;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAE3E,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,QAAQ,CAAC,cAAc,EAAE,gBAAgB,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C,CAAA;AAED,qBAAa,eAAe;;gBAMd,OAAO,EAAE,sBAAsB;IAqC3C,IAAI,MAAM,IAAI,WAAW,CAExB;IAID,IAAI,SAAS,IAAI,iBAAiB,CAEjC;IAKD,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAqClE,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IAIhF,KAAK,IAAI,IAAI;IAIb,IAAI,GAAG,IAAI,WAAW,CAErB;CACF;AAKD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE;IACP,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC,GACL;IAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAiC/D"}
@@ -0,0 +1,141 @@
1
+ // MessagePort realtime adapter: the browser-worker host's transport.
2
+ //
3
+ // The hub state machine, publisher, and protocol are shared with every other
4
+ // host (the realtime hub). This file is only the browser's socket lifecycle:
5
+ // a MessagePort instead of a WebSocket, and an authorizer that reads the same
6
+ // durable query membership the pull path maintains.
7
+ //
8
+ // The worker and its producer share one process lifecycle, so subscriptions and
9
+ // stream generations are memory-only here. Nothing survives a worker restart,
10
+ // which is correct: the durable value is whatever the client's next Zero pull
11
+ // produces.
12
+ import { applyClientFrame, applyHostFrame } from './host.js';
13
+ import { RealtimeHub } from './hub.js';
14
+ import { createProducer, inProcessTransport } from './producer.js';
15
+ import { decodeFrame, encodeFrame } from './protocol.js';
16
+ import { RealtimeStore } from './store.js';
17
+ export class BrowserRealtime {
18
+ #hub;
19
+ #producer;
20
+ #producerCounter = 0;
21
+ #connectionCounter = 0;
22
+ constructor(options) {
23
+ this.#hub = new RealtimeHub({
24
+ manifest: options.manifest,
25
+ authorizeSubscribe: async (identity, topic) => {
26
+ const { ownsGroup, authorized } = await options.readMembership(identity, topic.table, topic.key);
27
+ // A client group id is not a bearer token: not owning it is a denial,
28
+ // and the reason deliberately does not say whether the row exists.
29
+ if (!ownsGroup) {
30
+ return { status: 'denied', reason: 'client group does not belong to this user' };
31
+ }
32
+ // Owning the group without membership is the optimistic-row race: the
33
+ // client holds a row from its own mutation that the server has not
34
+ // recorded yet. It retries after its next pull.
35
+ return authorized ? { status: 'active' } : { status: 'pending' };
36
+ },
37
+ });
38
+ // There is no producer socket in the browser: the code running the model
39
+ // loop and the hub share one JavaScript context, so begin/publish are
40
+ // direct calls. The producer ROLE is still the shared one, so a loop
41
+ // written here runs unchanged against a socket host.
42
+ const producerHandle = {
43
+ id: `browser-producer-${++this.#producerCounter}`,
44
+ send: () => { },
45
+ };
46
+ this.#producer = createProducer(inProcessTransport(this.#hub, producerHandle), options);
47
+ }
48
+ // Imperative writing: set a row's field to its current value, generations
49
+ // managed for you. Trusted by construction, this is the worker's own code.
50
+ get fields() {
51
+ return this.#producer.fields;
52
+ }
53
+ // The explicit generation API underneath, for a producer that controls begin,
54
+ // commit, and end itself.
55
+ get publisher() {
56
+ return this.#producer.publisher;
57
+ }
58
+ // Attach a port. The identity comes from the host's authenticated pull path,
59
+ // never from the port itself, so a page cannot claim another user's client
60
+ // group by asserting one over the channel.
61
+ connect(port, identity) {
62
+ const connection = {
63
+ id: `browser-connection-${++this.#connectionCounter}`,
64
+ identity,
65
+ send: (frame) => {
66
+ port.postMessage({ event: 'realtime', frame: encodeFrame(frame) });
67
+ },
68
+ };
69
+ const onMessage = (event) => {
70
+ const message = event.data;
71
+ if (!message ||
72
+ typeof message !== 'object' ||
73
+ message.event !== 'realtime') {
74
+ return;
75
+ }
76
+ const raw = message.frame;
77
+ if (typeof raw !== 'string')
78
+ return;
79
+ const frame = decodeFrame(raw);
80
+ if (!frame)
81
+ return;
82
+ // A subscriber channel is never a publish channel. Only subscribe and
83
+ // unsubscribe are accepted here, whatever else a port sends.
84
+ if (frame[0] !== 'subscribe' && frame[0] !== 'unsubscribe')
85
+ return;
86
+ void applyClientFrame(this.#hub, connection, frame);
87
+ };
88
+ port.addEventListener('message', onMessage);
89
+ return () => {
90
+ port.removeEventListener('message', onMessage);
91
+ this.#hub.dropConnection(connection.id);
92
+ };
93
+ }
94
+ // A pull removed rows from a client group's membership, so its field
95
+ // subscriptions for those rows go with them.
96
+ revokeMembership(clientGroupID, removed) {
97
+ this.#hub.revokeMembership(clientGroupID, removed);
98
+ }
99
+ flush() {
100
+ this.#hub.flush();
101
+ }
102
+ get hub() {
103
+ return this.#hub;
104
+ }
105
+ }
106
+ // The page-side half of the port transport. Owns a RealtimeStore and pumps
107
+ // frames both ways, so `useStreamingField` sees the same store it would against
108
+ // a WebSocket host.
109
+ export function connectRealtimePort(port, options = {}) {
110
+ const store = new RealtimeStore({
111
+ send: (frame) => {
112
+ port.postMessage({ event: 'realtime', frame: encodeFrame(frame) });
113
+ },
114
+ staleAfterMs: options.staleAfterMs,
115
+ onError: options.onError,
116
+ });
117
+ const onMessage = (event) => {
118
+ const message = event.data;
119
+ if (!message ||
120
+ typeof message !== 'object' ||
121
+ message.event !== 'realtime') {
122
+ return;
123
+ }
124
+ const raw = message.frame;
125
+ if (typeof raw !== 'string')
126
+ return;
127
+ const frame = decodeFrame(raw);
128
+ if (frame)
129
+ applyHostFrame(store, frame);
130
+ };
131
+ port.addEventListener('message', onMessage);
132
+ port.start();
133
+ return {
134
+ store,
135
+ close: () => {
136
+ port.removeEventListener('message', onMessage);
137
+ store.handleDisconnect();
138
+ },
139
+ };
140
+ }
141
+ //# sourceMappingURL=message-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-port.js","sourceRoot":"","sources":["../../src/realtime/message-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ProducerOptions, RealtimeProducer } from './producer.js';
2
+ export type ProducerSocket = {
3
+ send(data: string): void;
4
+ };
5
+ export type SocketProducer = RealtimeProducer & {
6
+ handleMessage(raw: string): void;
7
+ fail(reason: string): void;
8
+ };
9
+ export declare function createSocketProducer(socket: ProducerSocket, options: ProducerOptions): SocketProducer;
10
+ //# sourceMappingURL=producer-socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"producer-socket.d.ts","sourceRoot":"","sources":["../../src/realtime/producer-socket.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAItE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG;IAE9C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAIhC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,eAAe,GACvB,cAAc,CA2EhB"}
@@ -0,0 +1,90 @@
1
+ // A PublisherTransport backed by a socket, for a producer that is not in the
2
+ // same process as the hub.
3
+ //
4
+ // This is the shape soot does NOT need and the shape agentbus and chat do: an
5
+ // application server generates the values, and the subscribers are browsers
6
+ // somewhere else, so the updates have to cross a network to reach the hub that
7
+ // fans them out.
8
+ //
9
+ // One socket carries every generation the producer has open. A server writing
10
+ // twenty agent sessions holds one connection, and the hub releases all twenty
11
+ // leases when it drops.
12
+ //
13
+ // Connecting, authenticating, and reconnecting are the caller's: it knows its
14
+ // own deployment. This owns only the frame bookkeeping on top of a socket that
15
+ // is already open.
16
+ import { createProducer } from './producer.js';
17
+ import { decodeFrame, encodeFrame } from './protocol.js';
18
+ export function createSocketProducer(socket, options) {
19
+ const pendingBegins = new Map();
20
+ // streamID -> why it is unusable. Set by a host rejection or supersession, and
21
+ // raised on the producer's next publish for that stream.
22
+ const failures = new Map();
23
+ // The socket itself died. This is deliberately not per-stream: once the
24
+ // connection is gone every generation on it is gone, including ones that
25
+ // began successfully and are therefore absent from `failures`.
26
+ let socketFailure;
27
+ const transport = {
28
+ begin(topic, streamID) {
29
+ if (socketFailure)
30
+ return Promise.reject(new Error(socketFailure));
31
+ return new Promise((resolve, reject) => {
32
+ pendingBegins.set(streamID, { resolve, reject });
33
+ socket.send(encodeFrame(['begin', { topic, streamID }]));
34
+ });
35
+ },
36
+ publish(update) {
37
+ if (socketFailure)
38
+ throw new Error(socketFailure);
39
+ const failure = failures.get(update.streamID);
40
+ if (failure)
41
+ throw new Error(failure);
42
+ socket.send(encodeFrame(['publish', { update }]));
43
+ },
44
+ end(streamID) {
45
+ failures.delete(streamID);
46
+ pendingBegins.delete(streamID);
47
+ },
48
+ };
49
+ return {
50
+ ...createProducer(transport, options),
51
+ handleMessage(raw) {
52
+ const frame = decodeFrame(raw);
53
+ if (!frame)
54
+ return;
55
+ switch (frame[0]) {
56
+ case 'begin-result': {
57
+ const { streamID, reason } = frame[1];
58
+ const pending = pendingBegins.get(streamID);
59
+ if (!pending)
60
+ return;
61
+ pendingBegins.delete(streamID);
62
+ if (reason === null)
63
+ pending.resolve();
64
+ else
65
+ pending.reject(new Error(reason));
66
+ return;
67
+ }
68
+ case 'publish-rejected': {
69
+ const { streamID, reason } = frame[1];
70
+ failures.set(streamID, reason);
71
+ return;
72
+ }
73
+ case 'superseded': {
74
+ const { topic, streamID } = frame[1];
75
+ failures.set(streamID, `generation for '${topic}' was superseded by a newer one`);
76
+ return;
77
+ }
78
+ default:
79
+ return;
80
+ }
81
+ },
82
+ fail(reason) {
83
+ socketFailure = reason;
84
+ for (const pending of pendingBegins.values())
85
+ pending.reject(new Error(reason));
86
+ pendingBegins.clear();
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=producer-socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"producer-socket.js","sourceRoot":"","sources":["../../src/realtime/producer-socket.ts"],"names":[],"mappings":"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"}