@weft-js/start 0.1.0 → 0.1.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.
- package/README.md +36 -3
- package/crate/Cargo.lock +1347 -0
- package/crate/Cargo.toml +72 -0
- package/crate/rust-toolchain.toml +3 -0
- package/crate/src/build/emit.rs +103 -0
- package/crate/src/build.rs +367 -0
- package/crate/src/ctx.rs +186 -0
- package/crate/src/envelope.rs +163 -0
- package/crate/src/functions.rs +173 -0
- package/crate/src/lib.rs +118 -0
- package/crate/src/native.rs +212 -0
- package/crate/src/otel.rs +62 -0
- package/crate/src/server.rs +203 -0
- package/package.json +46 -37
- package/src/app.mjs +51 -10
- package/src/asset-receipt.d.mts +13 -0
- package/src/asset-receipt.mjs +61 -0
- package/src/auth/better-auth.ts +215 -17
- package/src/auth/drizzle.ts +1 -1
- package/src/auth.ts +21 -6
- package/src/boot.ts +19 -8
- package/src/bus/postgres.ts +32 -19
- package/src/bus.ts +7 -4
- package/src/{capture.mjs → capture.ts} +34 -1
- package/src/changes-sql.d.mts +8 -2
- package/src/changes-sql.mjs +26 -10
- package/src/changes.ts +165 -66
- package/src/channel/connections.ts +216 -0
- package/src/channel/socket.ts +396 -0
- package/src/channel-fake.ts +19 -4
- package/src/channel.ts +124 -490
- package/src/client.tsx +9 -2
- package/src/contract/describe.mjs +231 -0
- package/src/contract.mjs +146 -155
- package/src/data/cache.ts +354 -0
- package/src/data/definitions.ts +94 -0
- package/src/data/draft.ts +104 -0
- package/src/data/foundation.ts +95 -0
- package/src/data/live-api.ts +22 -0
- package/src/data/mutation.ts +138 -0
- package/src/data/primitives.ts +135 -0
- package/src/data/query.ts +106 -0
- package/src/data/transport.ts +121 -0
- package/src/data/types.ts +303 -0
- package/src/data.ts +69 -894
- package/src/db/bun-sqlite.d.ts +4 -1
- package/src/db/changes-mysql.ts +61 -21
- package/src/db/changes-postgres.ts +197 -118
- package/src/db/changes-sqlite.ts +131 -64
- package/src/db/core.ts +38 -13
- package/src/db/index.ts +20 -4
- package/src/db/mysql.ts +22 -6
- package/src/db/postgres.ts +49 -13
- package/src/db/sqlite.ts +53 -27
- package/src/derive.d.mts +4 -1
- package/src/derive.mjs +136 -39
- package/src/dev-runtime.mjs +8 -4
- package/src/exec/errors.ts +57 -0
- package/src/exec/landing.ts +66 -0
- package/src/exec/scope.ts +174 -0
- package/src/exec/touch.ts +80 -0
- package/src/exec/validation.ts +176 -0
- package/src/exec.ts +191 -341
- package/src/extension.ts +8 -2
- package/src/first-paint.ts +26 -9
- package/src/form/value.ts +15 -0
- package/src/form.tsx +132 -43
- package/src/hub/channels.ts +102 -0
- package/src/hub/connections.ts +147 -0
- package/src/hub/delivery.ts +62 -0
- package/src/hub/feed.ts +168 -0
- package/src/hub/presence.ts +64 -0
- package/src/hub/route.ts +158 -0
- package/src/hub/subscriptions.ts +212 -0
- package/src/hub/topic.ts +98 -0
- package/src/hub/tracked.ts +12 -0
- package/src/hub/types.ts +190 -0
- package/src/hub/view.ts +147 -0
- package/src/hub.ts +132 -758
- package/src/index.ts +84 -10
- package/src/inline.mjs +356 -0
- package/src/inspect/compare.mjs +162 -0
- package/src/inspect/routes.mjs +154 -0
- package/src/inspect/samples.mjs +59 -0
- package/src/inspect/url.mjs +2 -0
- package/src/inspect.mjs +146 -187
- package/src/link/election.ts +178 -0
- package/src/link/lines.ts +27 -0
- package/src/link.ts +97 -168
- package/src/list-drizzle.ts +104 -18
- package/src/list.ts +127 -36
- package/src/listen.ts +32 -6
- package/src/live/api.ts +18 -0
- package/src/live/backoff.ts +6 -0
- package/src/live/frames.ts +42 -0
- package/src/live/read.ts +77 -0
- package/src/live/sub-types.ts +24 -0
- package/src/live/transport.ts +86 -0
- package/src/live/types.ts +52 -0
- package/src/live-fake.ts +20 -5
- package/src/live-target.mjs +113 -35
- package/src/live.ts +116 -225
- package/src/media.ts +8 -1
- package/src/migrations.mjs +14 -6
- package/src/mux.ts +161 -64
- package/src/og/DefaultCard.tsx +40 -9
- package/src/og/fonts.mjs +16 -8
- package/src/og/images.mjs +43 -22
- package/src/og/index.mjs +119 -43
- package/src/og/native.mjs +11 -4
- package/src/range.mjs +15 -3
- package/src/router.ts +56 -6
- package/src/routes.mjs +73 -22
- package/src/run/admission.ts +80 -0
- package/src/run/boot.tsx +115 -0
- package/src/run/cache-presentation.ts +67 -0
- package/src/run/cache.ts +254 -0
- package/src/run/helpers.ts +197 -0
- package/src/run/listeners.ts +155 -0
- package/src/run/navigation.ts +382 -0
- package/src/run/page-skeleton.tsx +35 -0
- package/src/run/prefetch.ts +128 -0
- package/src/run/retain-view.ts +18 -0
- package/src/run/shape-preparation.ts +97 -0
- package/src/run/shape-styles.ts +72 -0
- package/src/run/source-context/pin.ts +124 -0
- package/src/run/source-context.ts +311 -0
- package/src/run.tsx +50 -174
- package/src/rust/common.ts +163 -0
- package/src/rust/native.ts +282 -0
- package/src/rust.ts +103 -229
- package/src/server/card.tsx +65 -0
- package/src/server/compression.ts +115 -0
- package/src/server/core.ts +70 -0
- package/src/server/dispatch.ts +70 -0
- package/src/server/form.ts +85 -0
- package/src/server/functions.ts +129 -0
- package/src/server/handler.ts +39 -0
- package/src/server/head.ts +96 -0
- package/src/server/media.ts +60 -0
- package/src/server/navigation-cache.ts +80 -0
- package/src/server/navigation.tsx +85 -0
- package/src/server/page-cold.ts +95 -0
- package/src/server/page-stream.tsx +181 -0
- package/src/server/page-types.ts +51 -0
- package/src/server/page-warm.ts +130 -0
- package/src/server/page.ts +69 -0
- package/src/server/payload.ts +89 -0
- package/src/server/prerender.ts +60 -0
- package/src/server/preview.tsx +67 -0
- package/src/server/render.ts +167 -0
- package/src/server/request.ts +98 -0
- package/src/server/resolver.ts +228 -0
- package/src/server/routes.ts +150 -0
- package/src/server/services.ts +69 -0
- package/src/server/text.ts +29 -0
- package/src/server/types.ts +160 -0
- package/src/server.tsx +82 -964
- package/src/shape.mjs +30 -6
- package/src/share/display.ts +50 -0
- package/src/share/network.ts +119 -0
- package/src/share/receive.ts +70 -0
- package/src/share/state.ts +30 -0
- package/src/share/tab-queue.ts +28 -0
- package/src/share-server.ts +128 -43
- package/src/share.ts +103 -209
- package/src/sheets.mjs +30 -18
- package/src/sidecar/build.mjs +170 -0
- package/src/sidecar/cargo.mjs +164 -0
- package/src/sidecar/common.mjs +17 -0
- package/src/sidecar/dev-build.mjs +91 -0
- package/src/sidecar/dev-watch.mjs +88 -0
- package/src/sidecar/manifest.mjs +19 -0
- package/src/sidecar/process.mjs +58 -0
- package/src/sidecar/refresh.mjs +19 -0
- package/src/sidecar.mjs +75 -416
- package/src/socket/check.ts +50 -0
- package/src/socket/deliver.ts +16 -0
- package/src/socket/publish.ts +56 -0
- package/src/socket/rooms.ts +41 -0
- package/src/socket/route.ts +79 -0
- package/src/socket/shared.ts +26 -0
- package/src/socket/types.ts +48 -0
- package/src/socket.ts +205 -194
- package/src/stream.ts +10 -1
- package/src/verify/app.ts +39 -0
- package/src/verify/cleanup.ts +27 -0
- package/src/verify/database.ts +11 -0
- package/src/verify/live.ts +63 -0
- package/src/verify/notify.ts +35 -0
- package/src/verify/skip.ts +19 -0
- package/src/verify/support.ts +149 -0
- package/src/verify/timing.ts +15 -0
- package/src/verify/trigger.ts +14 -0
- package/src/verify.ts +77 -176
- package/src/view.tsx +96 -11
- package/src/vite/asset-bytes.mjs +95 -0
- package/src/vite/assets.mjs +117 -0
- package/src/vite/config-hooks.mjs +166 -0
- package/src/vite/dev-hooks.mjs +103 -0
- package/src/vite/dev.mjs +102 -0
- package/src/vite/entries.mjs +145 -0
- package/src/vite/module-hooks.mjs +288 -0
- package/src/vite/route-modules.mjs +289 -0
- package/src/vite/server-functions.mjs +222 -0
- package/src/vite/shape-entry-css.mjs +187 -0
- package/src/vite/shape-override.mjs +226 -0
- package/src/vite/shared.mjs +51 -0
- package/src/vite/sheets.mjs +92 -0
- package/src/vite/state.mjs +89 -0
- package/src/vite/syntax.mjs +139 -0
- package/src/vite.mjs +152 -853
- package/src/capture.d.mts +0 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** A message with its cursor: `yield tracked(row.id, row)`, and a resumed `run` gets it as `lastEventId`. */
|
|
2
|
+
export class Tracked<M> {
|
|
3
|
+
constructor(
|
|
4
|
+
public id: string,
|
|
5
|
+
public value: M,
|
|
6
|
+
) {}
|
|
7
|
+
}
|
|
8
|
+
/** A message with an id, so a stream can resume after it. */
|
|
9
|
+
export const tracked = <M>(id: string, value: M) => new Tracked(id, value)
|
|
10
|
+
|
|
11
|
+
/** Thrown out of `run` when its cursor can't resume: the stream restarts without one. */
|
|
12
|
+
export const RESET = new Error('weft.reset')
|
package/src/hub/types.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import type { Bus } from '../bus'
|
|
2
|
+
import type { Source } from '../changes'
|
|
3
|
+
import type { Fn, LiveMode, StartError } from '../data'
|
|
4
|
+
import type { Scope, ScopeOptions, Store } from '../exec'
|
|
5
|
+
import type { ShareRule } from '../share-server'
|
|
6
|
+
|
|
7
|
+
/** What one connection may cost; every number has a default in `LIMITS`. */
|
|
8
|
+
export interface Limits {
|
|
9
|
+
subscriptions: number
|
|
10
|
+
/** Per signed-in user. */
|
|
11
|
+
connections: number
|
|
12
|
+
/** Bytes of one request (client→server). */
|
|
13
|
+
body: number
|
|
14
|
+
/** Bytes of one message (server→client). */
|
|
15
|
+
message: number
|
|
16
|
+
/** Bytes one connection may hold before it's closed. */
|
|
17
|
+
queue: number
|
|
18
|
+
/** Events a ring keeps. */
|
|
19
|
+
ring: number
|
|
20
|
+
/** Ms a ring keeps them. */
|
|
21
|
+
window: number
|
|
22
|
+
/** Ms between `: ping`s. */
|
|
23
|
+
heartbeat: number
|
|
24
|
+
/** Ms between session re-checks of `auth` subscriptions and channel joins. */
|
|
25
|
+
session: number
|
|
26
|
+
/** Channel messages a client may send per second, per socket. */
|
|
27
|
+
perSecond: number
|
|
28
|
+
/** The burst `perSecond` allows. */
|
|
29
|
+
burst: number
|
|
30
|
+
/** Keys one socket may `share`. They cost no joins: a 200-row list is one. */
|
|
31
|
+
shareKeys: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** `realtime()`: the options of an app's `src/realtime.server.ts`. */
|
|
35
|
+
export interface RealtimeOptions {
|
|
36
|
+
/** Default: `memoryBus()`, one instance only (R002). */
|
|
37
|
+
bus?: Bus
|
|
38
|
+
/** Origins allowed besides the app's own, exact: scheme, host and port. */
|
|
39
|
+
origins?: string[]
|
|
40
|
+
limits?: Partial<Limits>
|
|
41
|
+
/** Seconds the platform lets a response live: streams end 10 s earlier, and the client resumes. */
|
|
42
|
+
maxDuration?: number
|
|
43
|
+
/** Writes from outside the app: `changes: dbChanges(db, [todos])`, or a source of your own. */
|
|
44
|
+
changes?: Source
|
|
45
|
+
/**
|
|
46
|
+
* Who may share or see a key of `interaction({ share })` with other clients. Left out, nobody: tabs still work. One
|
|
47
|
+
* key at a time, `({ ctx, key }) => boolean`, or `{ keys: ({ ctx, keys }) => allowed }` to answer a whole join at once.
|
|
48
|
+
*/
|
|
49
|
+
share?: ShareRule | undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** What the app gets from `configure`, beside `src/realtime.server.ts`. */
|
|
53
|
+
export interface HubOptions extends RealtimeOptions {
|
|
54
|
+
build?: string | undefined
|
|
55
|
+
dev?: boolean | undefined
|
|
56
|
+
/** Queries marked `live: { required: true }`: without a real feed the server refuses to run (R015). */
|
|
57
|
+
required?: string[] | undefined
|
|
58
|
+
store?: Store | undefined
|
|
59
|
+
onDiagnostic?: ScopeOptions['onDiagnostic'] | undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** What `.live` reports, and a health route reads. */
|
|
63
|
+
export interface LiveState {
|
|
64
|
+
mode: LiveMode
|
|
65
|
+
via: string
|
|
66
|
+
why?: string | undefined
|
|
67
|
+
fix?: string | undefined
|
|
68
|
+
/** The feed works in general and is out right now. */
|
|
69
|
+
down?: string | undefined
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Where a connection's frames go. `data` is JSON. */
|
|
73
|
+
export interface Sink {
|
|
74
|
+
write(event: string, data: string): void
|
|
75
|
+
ping?(): void
|
|
76
|
+
/** Bytes written and not yet taken by the client. */
|
|
77
|
+
backlog(): number
|
|
78
|
+
close(): void
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** What the client sends (research 30 §4): `[n, kind, id, input, cursor, buffer]`. */
|
|
82
|
+
export type SubEntry = [
|
|
83
|
+
n: number,
|
|
84
|
+
kind: 'q' | 's',
|
|
85
|
+
id: string,
|
|
86
|
+
input?: unknown,
|
|
87
|
+
cursor?: string,
|
|
88
|
+
buffer?: number,
|
|
89
|
+
]
|
|
90
|
+
/** The body of `/_weft/rt`: the cursor, subscriptions to add, and subscriptions to drop. */
|
|
91
|
+
export interface Body {
|
|
92
|
+
k?: string
|
|
93
|
+
c?: string | undefined
|
|
94
|
+
s?: SubEntry[]
|
|
95
|
+
d?: number[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** One message in a channel's ring. */
|
|
99
|
+
export interface Ev {
|
|
100
|
+
seq: number
|
|
101
|
+
at: number
|
|
102
|
+
raw: string
|
|
103
|
+
/** Parsed once, for every socket of a room. */ p?: unknown
|
|
104
|
+
}
|
|
105
|
+
/** One hub channel: its replay ring and who's listening on this instance. */
|
|
106
|
+
export interface Channel {
|
|
107
|
+
name: string
|
|
108
|
+
ring: Ev[]
|
|
109
|
+
floor: number
|
|
110
|
+
listeners: Set<(ev: Ev | null) => void>
|
|
111
|
+
/** Take a message as if the bus had brought it: a change feed reaches this instance's connections only. */
|
|
112
|
+
got: (raw: string) => void
|
|
113
|
+
ready: Promise<void>
|
|
114
|
+
stop?: () => void
|
|
115
|
+
idle?: ReturnType<typeof setTimeout> | undefined
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface Sub {
|
|
119
|
+
n: number
|
|
120
|
+
kind: 'q' | 's'
|
|
121
|
+
fn: Fn
|
|
122
|
+
input: unknown
|
|
123
|
+
tags: string[]
|
|
124
|
+
buffer: number
|
|
125
|
+
q: { raw: string; size: number }[]
|
|
126
|
+
ac: AbortController
|
|
127
|
+
request: Request
|
|
128
|
+
options: ScopeOptions
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** One client's realtime connection. */
|
|
132
|
+
export interface Conn {
|
|
133
|
+
k: string
|
|
134
|
+
sink: Sink
|
|
135
|
+
user?: string | undefined
|
|
136
|
+
subs: Map<number, Sub>
|
|
137
|
+
tags: Map<string, number>
|
|
138
|
+
held: Set<Sub>
|
|
139
|
+
pokes?: { t: Set<string>; c: string } | undefined
|
|
140
|
+
bytes: number
|
|
141
|
+
timers: ReturnType<typeof setTimeout>[]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The realtime server of this process: channels, connections and the change feed. */
|
|
145
|
+
export interface Hub {
|
|
146
|
+
readonly bus: Bus
|
|
147
|
+
readonly limits: Limits
|
|
148
|
+
/** `realtime({ share })`. */
|
|
149
|
+
readonly share?: ShareRule | undefined
|
|
150
|
+
poke(tags: string[], origin?: string | null): Promise<void>
|
|
151
|
+
cursor(): string | undefined
|
|
152
|
+
/** Listening for pokes, or 250 ms: a page waits this long for a cursor, and goes without one. */
|
|
153
|
+
ready(): Promise<unknown>
|
|
154
|
+
cursorOf(seq: number): string
|
|
155
|
+
channel(name: string): Channel
|
|
156
|
+
replay(ch: Channel, after: string): Ev[] | undefined
|
|
157
|
+
unlisten(ch: Channel, on: (ev: Ev | null) => void): void
|
|
158
|
+
/** `line`: one tab on a shared socket (mux.ts), which `limits.connections` counted already. */
|
|
159
|
+
connect(request: Request, scope: Scope, body: Body, sink: Sink, line?: boolean): Promise<Conn>
|
|
160
|
+
change(c: Conn, request: Request, options: ScopeOptions, body: Body): Promise<void>
|
|
161
|
+
drain(c: Conn): void
|
|
162
|
+
close(c: Conn): void
|
|
163
|
+
find(k: string): Conn | undefined
|
|
164
|
+
connections(): Conn[]
|
|
165
|
+
/** @weft-js/core/test: a message straight to every reader of a stream. */
|
|
166
|
+
push(id: string, msg: unknown): number
|
|
167
|
+
/** Server-side counts for tests and `weft browser`. */
|
|
168
|
+
stats(): { connections: number; subscriptions: number; channels: number }
|
|
169
|
+
/** The live mode this server settled on: `.liveMode` on the client, and health routes. */
|
|
170
|
+
live(): LiveState
|
|
171
|
+
required: boolean
|
|
172
|
+
/** Settled once the source has been probed. */
|
|
173
|
+
probed: Promise<unknown>
|
|
174
|
+
/** R015: required live queries, and no feed. Requests get this instead of stale data. */
|
|
175
|
+
refused?: StartError | undefined
|
|
176
|
+
shutdown(): Promise<void>
|
|
177
|
+
/** The position a new listener resumes from. */
|
|
178
|
+
position(): string
|
|
179
|
+
/** Every poked tag, on this instance: socket.ts's `session:<user>` re-check. */
|
|
180
|
+
watch(fn: (tags: string[]) => void): void
|
|
181
|
+
/** Run at shutdown: socket.ts closes its sockets. */
|
|
182
|
+
closing: Set<() => void>
|
|
183
|
+
/** `room.publish` checks its messages (C002). */
|
|
184
|
+
dev?: boolean | undefined
|
|
185
|
+
/** The instance's name in a shared value's stamp. */
|
|
186
|
+
epoch: string
|
|
187
|
+
/** Seconds a connection may live (`RealtimeOptions.maxDuration`). */
|
|
188
|
+
maxDuration?: number | undefined
|
|
189
|
+
build?: string | undefined
|
|
190
|
+
}
|
package/src/hub/view.ts
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { Bus } from '../bus'
|
|
2
|
+
import type { createChannels } from './channels'
|
|
3
|
+
import type { createConnections } from './connections'
|
|
4
|
+
import type { createDelivery } from './delivery'
|
|
5
|
+
import type { createFeedState } from './feed'
|
|
6
|
+
import type { createSubscriptions } from './subscriptions'
|
|
7
|
+
import type { Channel, Conn, Hub, HubOptions, Limits } from './types'
|
|
8
|
+
|
|
9
|
+
const unref = <T>(t: T) => ((t as { unref?(): void } | null | undefined)?.unref?.(), t)
|
|
10
|
+
interface View {
|
|
11
|
+
bus: Bus
|
|
12
|
+
limits: Limits
|
|
13
|
+
epoch: string
|
|
14
|
+
options: HubOptions
|
|
15
|
+
channels: Map<string, Channel>
|
|
16
|
+
conns: Map<string, Conn>
|
|
17
|
+
watchers: Set<(tags: string[]) => void>
|
|
18
|
+
closing: Set<() => void>
|
|
19
|
+
cursorOf: (n: number) => string
|
|
20
|
+
channel: ReturnType<typeof createChannels>['channel']
|
|
21
|
+
replay: ReturnType<typeof createChannels>['replay']
|
|
22
|
+
unlisten: ReturnType<typeof createChannels>['unlisten']
|
|
23
|
+
seq: () => number
|
|
24
|
+
pokes: () => Channel
|
|
25
|
+
want: ReturnType<typeof createFeedState>['want']
|
|
26
|
+
rest: ReturnType<typeof createFeedState>['rest']
|
|
27
|
+
feedState: ReturnType<typeof createFeedState>
|
|
28
|
+
feed: ReturnType<typeof createFeedState>['feed']
|
|
29
|
+
probed: Promise<unknown>
|
|
30
|
+
deliver: ReturnType<typeof createDelivery>['deliver']
|
|
31
|
+
drain: ReturnType<typeof createDelivery>['drain']
|
|
32
|
+
connect: ReturnType<typeof createConnections>['connect']
|
|
33
|
+
close: ReturnType<typeof createConnections>['close']
|
|
34
|
+
change: ReturnType<typeof createSubscriptions>['change']
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createHubView(deps: View): Hub {
|
|
38
|
+
const {
|
|
39
|
+
bus,
|
|
40
|
+
limits,
|
|
41
|
+
epoch,
|
|
42
|
+
options,
|
|
43
|
+
channels,
|
|
44
|
+
conns,
|
|
45
|
+
watchers,
|
|
46
|
+
closing,
|
|
47
|
+
cursorOf,
|
|
48
|
+
channel,
|
|
49
|
+
replay,
|
|
50
|
+
unlisten,
|
|
51
|
+
seq,
|
|
52
|
+
pokes,
|
|
53
|
+
feedState,
|
|
54
|
+
probed,
|
|
55
|
+
drain,
|
|
56
|
+
connect,
|
|
57
|
+
close,
|
|
58
|
+
change,
|
|
59
|
+
} = deps
|
|
60
|
+
const { ready, poke, push, shutdown } = createOperations(deps)
|
|
61
|
+
return {
|
|
62
|
+
bus,
|
|
63
|
+
limits,
|
|
64
|
+
cursorOf,
|
|
65
|
+
channel,
|
|
66
|
+
replay,
|
|
67
|
+
unlisten,
|
|
68
|
+
connect,
|
|
69
|
+
change,
|
|
70
|
+
drain,
|
|
71
|
+
close,
|
|
72
|
+
closing,
|
|
73
|
+
epoch,
|
|
74
|
+
dev: options.dev,
|
|
75
|
+
maxDuration: options.maxDuration,
|
|
76
|
+
build: options.build,
|
|
77
|
+
share: options.share,
|
|
78
|
+
position: () => cursorOf(seq()),
|
|
79
|
+
watch(fn) {
|
|
80
|
+
watchers.add(fn)
|
|
81
|
+
void pokes()
|
|
82
|
+
},
|
|
83
|
+
find: (k) => conns.get(k),
|
|
84
|
+
connections: () => [...conns.values()],
|
|
85
|
+
cursor: () => (pokes().stop ? cursorOf(seq()) : undefined),
|
|
86
|
+
ready,
|
|
87
|
+
poke,
|
|
88
|
+
push,
|
|
89
|
+
stats: () => ({
|
|
90
|
+
connections: conns.size,
|
|
91
|
+
subscriptions: [...conns.values()].reduce((n, c) => n + c.subs.size, 0),
|
|
92
|
+
channels: channels.size,
|
|
93
|
+
}),
|
|
94
|
+
live: feedState.live,
|
|
95
|
+
probed,
|
|
96
|
+
required: !!options.required?.length,
|
|
97
|
+
get refused() {
|
|
98
|
+
return feedState.refused()
|
|
99
|
+
},
|
|
100
|
+
shutdown,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function createOperations(deps: View) {
|
|
105
|
+
const { want, rest, pokes, feedState, feed, bus, conns, deliver, closing, close, channels } = deps
|
|
106
|
+
return {
|
|
107
|
+
ready: () => {
|
|
108
|
+
const on = Promise.resolve(want()).then(rest)
|
|
109
|
+
return Promise.race([
|
|
110
|
+
Promise.all([pokes().ready.catch(() => {}), on]),
|
|
111
|
+
new Promise((ok) => {
|
|
112
|
+
unref(setTimeout(ok, 250))
|
|
113
|
+
}),
|
|
114
|
+
])
|
|
115
|
+
},
|
|
116
|
+
async poke(this: void, tags: string[], origin?: string | null) {
|
|
117
|
+
if (!tags.length) return
|
|
118
|
+
// In this order: a client's refetch must start after what the barrier claims is covered.
|
|
119
|
+
if (feedState.live().mode === 'feed' || feedState.live().mode === 'external')
|
|
120
|
+
await feed?.settle(tags)
|
|
121
|
+
await bus.publish('weft:poke', JSON.stringify({ t: tags, ...(origin && { o: origin }) }))
|
|
122
|
+
},
|
|
123
|
+
push(this: void, id: string, msg: unknown) {
|
|
124
|
+
let hit = 0
|
|
125
|
+
for (const c of conns.values()) {
|
|
126
|
+
for (const s of c.subs.values()) {
|
|
127
|
+
if (s.fn.$id !== id) continue
|
|
128
|
+
hit++
|
|
129
|
+
deliver(c, s, JSON.stringify([s.n, null, msg]))
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return hit
|
|
133
|
+
},
|
|
134
|
+
async shutdown(this: void) {
|
|
135
|
+
feedState.clear()
|
|
136
|
+
await feed?.stop()
|
|
137
|
+
for (const fn of closing) fn()
|
|
138
|
+
for (const c of conns.values()) close(c)
|
|
139
|
+
for (const ch of channels.values()) {
|
|
140
|
+
clearTimeout(ch.idle)
|
|
141
|
+
ch.stop?.()
|
|
142
|
+
}
|
|
143
|
+
channels.clear()
|
|
144
|
+
await bus.close?.()
|
|
145
|
+
},
|
|
146
|
+
}
|
|
147
|
+
}
|