@livequery/rest 2.0.133 → 2.0.135
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 +241 -187
- package/dist/RestTransporter.d.ts +3 -2
- package/dist/RestTransporter.d.ts.map +1 -1
- package/dist/RestTransporter.js +59 -10
- package/dist/RestTransporter.js.map +1 -1
- package/dist/Socket.d.ts +0 -1
- package/dist/Socket.d.ts.map +1 -1
- package/dist/Socket.js +39 -14
- package/dist/Socket.js.map +1 -1
- package/package.json +52 -48
package/README.md
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
# @livequery/rest
|
|
2
2
|
|
|
3
|
-
`@livequery/rest` is
|
|
3
|
+
`@livequery/rest` is the REST and optional WebSocket transport adapter for `@livequery/client`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use this package when your application state is managed by `@livequery/client`, but the remote backend is exposed through HTTP endpoints and, optionally, a realtime WebSocket gateway.
|
|
6
6
|
|
|
7
|
-
It
|
|
7
|
+
This package is transport-only. It does not implement local cache, optimistic state, collection modes, or reactive document state. Those responsibilities stay in `@livequery/client`.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- optional WebSocket subscriptions for realtime collection updates
|
|
11
|
-
- request/response hooks for auth, caching, logging, or mocking
|
|
9
|
+
## What It Does
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
`RestTransporter` implements the `LivequeryTransporter` contract:
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- `query()` performs HTTP `GET` requests and emits `LivequeryQueryResult` changes.
|
|
14
|
+
- `add()` performs HTTP `POST` requests.
|
|
15
|
+
- `update()` performs HTTP `PATCH` requests.
|
|
16
|
+
- `delete()` performs HTTP `DELETE` requests.
|
|
17
|
+
- `trigger()` performs action calls through `POST /<ref>/~<action>`.
|
|
18
|
+
- When `ws` is configured, `query()` can merge server-pushed realtime changes from `Socket`.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
- `copilot-instructions.md` provides repo-level instructions for Copilot when generating or reviewing code in this workspace.
|
|
21
|
-
- Both documents assume this repo is a transport library package, so agent changes should avoid app-specific scaffolding and should preserve public API compatibility by default.
|
|
22
|
-
- Agents generating consumer code should build around a shared `RestTransporter` inside a shared `LivequeryClient` instance.
|
|
20
|
+
`Socket` manages the WebSocket connection, client id, gateway handshake, subscriptions, reconnect loop, and JSON/MessagePack message parsing.
|
|
23
21
|
|
|
24
22
|
## Installation
|
|
25
23
|
|
|
@@ -31,21 +29,9 @@ npm install @livequery/rest
|
|
|
31
29
|
bun add @livequery/rest
|
|
32
30
|
```
|
|
33
31
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
`RestTransporter` implements the `LivequeryTransporter` contract from `@livequery/client`:
|
|
37
|
-
|
|
38
|
-
- `query()` returns an `Observable<Partial<LivequeryQueryResult>>`
|
|
39
|
-
- `add()` sends `POST`
|
|
40
|
-
- `update()` sends `PATCH`
|
|
41
|
-
- `delete()` sends `DELETE`
|
|
42
|
-
- `trigger()` sends `POST /<ref>/~<action>`
|
|
43
|
-
|
|
44
|
-
When a WebSocket endpoint is configured, `query()` can also attach a realtime subscription and merge server-pushed `DataChangeEvent`s into the observable stream.
|
|
32
|
+
## Basic Usage
|
|
45
33
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### REST only
|
|
34
|
+
### REST Only
|
|
49
35
|
|
|
50
36
|
```ts
|
|
51
37
|
import { RestTransporter } from '@livequery/rest'
|
|
@@ -55,7 +41,7 @@ const transporter = new RestTransporter({
|
|
|
55
41
|
})
|
|
56
42
|
```
|
|
57
43
|
|
|
58
|
-
### REST +
|
|
44
|
+
### REST + Realtime
|
|
59
45
|
|
|
60
46
|
```ts
|
|
61
47
|
import { RestTransporter } from '@livequery/rest'
|
|
@@ -68,6 +54,8 @@ const transporter = new RestTransporter({
|
|
|
68
54
|
|
|
69
55
|
### With `@livequery/client`
|
|
70
56
|
|
|
57
|
+
Create one transporter per backend boundary and reuse it in a shared `LivequeryClient`.
|
|
58
|
+
|
|
71
59
|
```ts
|
|
72
60
|
import { LivequeryClient } from '@livequery/client'
|
|
73
61
|
import { RestTransporter } from '@livequery/rest'
|
|
@@ -85,7 +73,7 @@ const client = new LivequeryClient({
|
|
|
85
73
|
})
|
|
86
74
|
```
|
|
87
75
|
|
|
88
|
-
##
|
|
76
|
+
## Configuration
|
|
89
77
|
|
|
90
78
|
```ts
|
|
91
79
|
type RestTransporterConfig = {
|
|
@@ -104,18 +92,16 @@ type RestTransporterConfig = {
|
|
|
104
92
|
}
|
|
105
93
|
```
|
|
106
94
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
| Option | Type | Description |
|
|
95
|
+
| Option | Required | Meaning |
|
|
110
96
|
| --- | --- | --- |
|
|
111
|
-
| `api` |
|
|
112
|
-
| `ws` |
|
|
113
|
-
| `onRequest` |
|
|
114
|
-
| `onResponse` |
|
|
97
|
+
| `api` | Yes | Base HTTP URL used for all REST calls, for example `https://api.example.com`. Trailing slashes are normalized. |
|
|
98
|
+
| `ws` | No | WebSocket endpoint for realtime sync. When omitted, the package works as a REST-only transporter. |
|
|
99
|
+
| `onRequest` | No | Hook called before `fetch()`. Use it to add headers, override request fields, or return a fake `response` to skip the network. |
|
|
100
|
+
| `onResponse` | No | Hook called after a network or fake response is available. Use it for logging, metrics, error inspection, or tracing. |
|
|
115
101
|
|
|
116
102
|
## Request Model
|
|
117
103
|
|
|
118
|
-
Outgoing requests use this shape
|
|
104
|
+
Outgoing requests use this internal shape:
|
|
119
105
|
|
|
120
106
|
```ts
|
|
121
107
|
type RestTransporterRequest = {
|
|
@@ -127,40 +113,115 @@ type RestTransporterRequest = {
|
|
|
127
113
|
}
|
|
128
114
|
```
|
|
129
115
|
|
|
130
|
-
|
|
116
|
+
URL construction:
|
|
131
117
|
|
|
132
118
|
```text
|
|
133
|
-
<api>/<ref>
|
|
134
|
-
<api>/<ref
|
|
135
|
-
<api>/<
|
|
119
|
+
GET <api>/<ref>?<query>
|
|
120
|
+
POST <api>/<ref>
|
|
121
|
+
PATCH <api>/<collectionRef>/<id>
|
|
122
|
+
DELETE <api>/<collectionRef>/<id>
|
|
123
|
+
POST <api>/<ref>/~<action>
|
|
136
124
|
```
|
|
137
125
|
|
|
138
|
-
|
|
126
|
+
Query values are serialized with `URLSearchParams`.
|
|
139
127
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
128
|
+
- `null` and `undefined` query values are skipped.
|
|
129
|
+
- Array query values are encoded as repeated params, for example `tag:in=a&tag:in=b`.
|
|
130
|
+
- Action names are URI encoded.
|
|
131
|
+
|
|
132
|
+
## Methods
|
|
133
|
+
|
|
134
|
+
### `query({ ref, filters, headers })`
|
|
135
|
+
|
|
136
|
+
Runs a collection or document read through HTTP `GET`.
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const result$ = transporter.query({
|
|
140
|
+
ref: 'users',
|
|
141
|
+
filters: {
|
|
142
|
+
':limit': 20,
|
|
143
|
+
'role:in': ['admin', 'editor'],
|
|
144
|
+
'createdAt:sort': 'desc'
|
|
145
|
+
},
|
|
146
|
+
headers: {
|
|
147
|
+
Authorization: `Bearer ${token}`
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
result$.subscribe(result => {
|
|
152
|
+
if (result.error) return console.error(result.error)
|
|
153
|
+
console.log(result.changes)
|
|
154
|
+
})
|
|
147
155
|
```
|
|
148
156
|
|
|
149
|
-
|
|
157
|
+
Parameters:
|
|
158
|
+
|
|
159
|
+
| Parameter | Meaning |
|
|
160
|
+
| --- | --- |
|
|
161
|
+
| `ref` | Collection ref such as `users`, or document ref such as `users/u1`. |
|
|
162
|
+
| `filters` | Optional `LivequeryFilters<T>` object. Paging filters include `:limit`, `:after`, `:before`, `:around`, and `:page`. |
|
|
163
|
+
| `headers` | Optional per-query headers. These are merged into the outgoing request. |
|
|
164
|
+
|
|
165
|
+
When `ws` is configured, `query()` waits briefly for the socket to connect so it can attach socket metadata headers. If the socket is not ready, the REST query still runs.
|
|
166
|
+
|
|
167
|
+
Realtime watching is skipped for cursor/around paging filters:
|
|
150
168
|
|
|
151
|
-
|
|
169
|
+
- `:after`
|
|
170
|
+
- `:before`
|
|
171
|
+
- `:around`
|
|
152
172
|
|
|
153
|
-
|
|
173
|
+
### `add(ref, data)`
|
|
154
174
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
175
|
+
Creates a document through HTTP `POST`.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const user = await transporter.add('users', {
|
|
179
|
+
name: 'Ada',
|
|
180
|
+
role: 'admin'
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Private fields whose names start with `_` are not sent.
|
|
185
|
+
|
|
186
|
+
### `update(collectionRef, id, data)`
|
|
187
|
+
|
|
188
|
+
Updates a document through HTTP `PATCH`.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const user = await transporter.update('users', 'u1', {
|
|
192
|
+
name: 'Ada Lovelace'
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `delete(collectionRef, id)`
|
|
197
|
+
|
|
198
|
+
Deletes a document through HTTP `DELETE`.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
await transporter.delete('users', 'u1')
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `trigger({ ref, action, payload })`
|
|
205
|
+
|
|
206
|
+
Calls a custom backend action through `POST /<ref>/~<action>`.
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
await transporter.trigger({
|
|
210
|
+
ref: 'users/u1',
|
|
211
|
+
action: 'ban',
|
|
212
|
+
payload: {
|
|
213
|
+
reason: 'policy_violation'
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Hooks
|
|
219
|
+
|
|
220
|
+
### Add Auth Headers
|
|
159
221
|
|
|
160
222
|
```ts
|
|
161
223
|
const transporter = new RestTransporter({
|
|
162
224
|
api: 'https://api.example.com',
|
|
163
|
-
ws: 'wss://api.example.com/ws',
|
|
164
225
|
onRequest: async ({ headers }) => {
|
|
165
226
|
const token = await getAccessToken()
|
|
166
227
|
|
|
@@ -174,7 +235,9 @@ const transporter = new RestTransporter({
|
|
|
174
235
|
})
|
|
175
236
|
```
|
|
176
237
|
|
|
177
|
-
|
|
238
|
+
### Serve A Cached Response
|
|
239
|
+
|
|
240
|
+
Returning `response` from `onRequest` skips `fetch()` entirely. `onResponse` still runs.
|
|
178
241
|
|
|
179
242
|
```ts
|
|
180
243
|
const transporter = new RestTransporter({
|
|
@@ -192,28 +255,24 @@ const transporter = new RestTransporter({
|
|
|
192
255
|
})
|
|
193
256
|
```
|
|
194
257
|
|
|
195
|
-
###
|
|
196
|
-
|
|
197
|
-
Use `onResponse` for logging, metrics, or centralized error inspection:
|
|
258
|
+
### Log Responses
|
|
198
259
|
|
|
199
260
|
```ts
|
|
200
261
|
const transporter = new RestTransporter({
|
|
201
262
|
api: 'https://api.example.com',
|
|
202
263
|
onResponse: async (request, response) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
})
|
|
209
|
-
}
|
|
264
|
+
console.info('livequery request', {
|
|
265
|
+
method: request.method,
|
|
266
|
+
url: request.url,
|
|
267
|
+
failed: Boolean(response.error)
|
|
268
|
+
})
|
|
210
269
|
}
|
|
211
270
|
})
|
|
212
271
|
```
|
|
213
272
|
|
|
214
|
-
##
|
|
273
|
+
## Backend Contract
|
|
215
274
|
|
|
216
|
-
The
|
|
275
|
+
The backend must return a `LivequeryResult<T>` envelope:
|
|
217
276
|
|
|
218
277
|
```ts
|
|
219
278
|
type LivequeryResult<T> = {
|
|
@@ -225,33 +284,11 @@ type LivequeryResult<T> = {
|
|
|
225
284
|
}
|
|
226
285
|
```
|
|
227
286
|
|
|
228
|
-
|
|
287
|
+
Do not return raw arrays or raw documents. Wrap responses in `{ data }`.
|
|
229
288
|
|
|
230
|
-
|
|
289
|
+
### Collection Reads
|
|
231
290
|
|
|
232
|
-
|
|
233
|
-
type LivequeryCollectionResponse<T> = {
|
|
234
|
-
summary?: Record<string, any>
|
|
235
|
-
items: T[]
|
|
236
|
-
subscription_token?: string
|
|
237
|
-
count?: {
|
|
238
|
-
prev: number
|
|
239
|
-
next: number
|
|
240
|
-
total: number
|
|
241
|
-
current: number
|
|
242
|
-
}
|
|
243
|
-
has?: {
|
|
244
|
-
prev: boolean
|
|
245
|
-
next: boolean
|
|
246
|
-
}
|
|
247
|
-
cursor?: {
|
|
248
|
-
first: string
|
|
249
|
-
last: string
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Example:
|
|
291
|
+
For collection refs, return `data.items`:
|
|
255
292
|
|
|
256
293
|
```json
|
|
257
294
|
{
|
|
@@ -282,9 +319,11 @@ Example:
|
|
|
282
319
|
}
|
|
283
320
|
```
|
|
284
321
|
|
|
285
|
-
|
|
322
|
+
`query()` converts each item to an `added` change for `@livequery/client`.
|
|
323
|
+
|
|
324
|
+
### Document Reads
|
|
286
325
|
|
|
287
|
-
For document
|
|
326
|
+
For document refs, return `data.item`:
|
|
288
327
|
|
|
289
328
|
```json
|
|
290
329
|
{
|
|
@@ -297,20 +336,9 @@ For document reads, `data` should contain `item`:
|
|
|
297
336
|
}
|
|
298
337
|
```
|
|
299
338
|
|
|
300
|
-
### Create
|
|
339
|
+
### Create Responses
|
|
301
340
|
|
|
302
|
-
`add()` accepts either
|
|
303
|
-
|
|
304
|
-
```json
|
|
305
|
-
{
|
|
306
|
-
"data": {
|
|
307
|
-
"item": {
|
|
308
|
-
"id": "u1",
|
|
309
|
-
"name": "Ada"
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
```
|
|
341
|
+
`add()` accepts either a direct document:
|
|
314
342
|
|
|
315
343
|
```json
|
|
316
344
|
{
|
|
@@ -321,78 +349,75 @@ For document reads, `data` should contain `item`:
|
|
|
321
349
|
}
|
|
322
350
|
```
|
|
323
351
|
|
|
324
|
-
|
|
352
|
+
or a named wrapper such as `item`:
|
|
325
353
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
total: number
|
|
334
|
-
current: number
|
|
335
|
-
next?: { count: number; cursor: string }
|
|
336
|
-
prev?: { count: number; cursor: string }
|
|
354
|
+
```json
|
|
355
|
+
{
|
|
356
|
+
"data": {
|
|
357
|
+
"item": {
|
|
358
|
+
"id": "u1",
|
|
359
|
+
"name": "Ada"
|
|
360
|
+
}
|
|
337
361
|
}
|
|
338
|
-
source: 'query' | 'realtime' | 'action'
|
|
339
|
-
error: { code: string; message: string }
|
|
340
362
|
}
|
|
341
363
|
```
|
|
342
364
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
## Realtime
|
|
365
|
+
## Realtime WebSocket
|
|
346
366
|
|
|
347
|
-
|
|
367
|
+
When `ws` is configured, `RestTransporter` creates a `Socket` and attaches these metadata headers to REST calls:
|
|
348
368
|
|
|
349
369
|
- `socket_id`
|
|
350
370
|
- `x-lcid`
|
|
351
|
-
- `x-lgid`
|
|
371
|
+
- `x-lgid`, when the gateway id has been received from `hello`
|
|
352
372
|
|
|
353
|
-
This lets
|
|
373
|
+
This lets the backend bind an HTTP query to the active realtime socket.
|
|
354
374
|
|
|
355
|
-
### Realtime
|
|
375
|
+
### Realtime Flow
|
|
356
376
|
|
|
357
|
-
1.
|
|
358
|
-
2. The
|
|
359
|
-
3.
|
|
360
|
-
4.
|
|
377
|
+
1. The socket opens and sends `start`.
|
|
378
|
+
2. The server replies with `hello`.
|
|
379
|
+
3. A collection HTTP query returns `subscription_token`.
|
|
380
|
+
4. The transporter sends `subscribe` through the socket.
|
|
381
|
+
5. The server pushes `sync` messages.
|
|
382
|
+
6. `Socket.listen(ref)` emits `DataChangeEvent`s.
|
|
361
383
|
|
|
362
|
-
|
|
384
|
+
### WebSocket Messages
|
|
363
385
|
|
|
364
|
-
|
|
365
|
-
- the request is a cursor query using `:after`
|
|
366
|
-
- the request is a cursor query using `:before`
|
|
367
|
-
- the request is an around query using `:around`
|
|
368
|
-
|
|
369
|
-
### WebSocket protocol expected by `Socket`
|
|
370
|
-
|
|
371
|
-
When the socket opens, it sends:
|
|
386
|
+
When the socket opens, the client sends:
|
|
372
387
|
|
|
373
388
|
```json
|
|
374
389
|
{ "event": "start", "data": { "id": "<client_id>" } }
|
|
375
390
|
```
|
|
376
391
|
|
|
377
|
-
|
|
392
|
+
Every 60 seconds after open, the client sends:
|
|
378
393
|
|
|
379
394
|
```json
|
|
380
395
|
{ "event": "ping" }
|
|
381
396
|
```
|
|
382
397
|
|
|
383
|
-
To subscribe
|
|
398
|
+
To subscribe:
|
|
384
399
|
|
|
385
400
|
```json
|
|
386
401
|
{ "event": "subscribe", "data": { "realtime_token": "<token>" } }
|
|
387
402
|
```
|
|
388
403
|
|
|
389
|
-
The server should
|
|
404
|
+
The server should reply with:
|
|
390
405
|
|
|
391
406
|
```json
|
|
392
407
|
{ "event": "hello", "gid": "gateway-1" }
|
|
393
408
|
```
|
|
394
409
|
|
|
395
|
-
|
|
410
|
+
If the server wants the client to send future socket messages as MessagePack binary payloads, set `binary: true`:
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
{ "event": "hello", "gid": "gateway-1", "binary": true }
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The initial `start` message is always JSON because it is sent before `hello` is received. Messages sent after `hello.binary === true`, such as `ping`, `subscribe`, and `unsubscribe`, are encoded with MessagePack.
|
|
417
|
+
|
|
418
|
+
Incoming messages may be JSON strings or MessagePack binary payloads. The socket parses JSON strings first and decodes binary payloads with MessagePack.
|
|
419
|
+
|
|
420
|
+
Realtime sync messages should use this shape:
|
|
396
421
|
|
|
397
422
|
```json
|
|
398
423
|
{
|
|
@@ -410,7 +435,7 @@ Realtime sync messages should look like:
|
|
|
410
435
|
}
|
|
411
436
|
```
|
|
412
437
|
|
|
413
|
-
Each sync change is
|
|
438
|
+
Each sync change is normalized to:
|
|
414
439
|
|
|
415
440
|
```ts
|
|
416
441
|
type DataChangeEvent = {
|
|
@@ -421,66 +446,91 @@ type DataChangeEvent = {
|
|
|
421
446
|
}
|
|
422
447
|
```
|
|
423
448
|
|
|
424
|
-
##
|
|
449
|
+
## Direct `Socket` Usage
|
|
425
450
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
```ts
|
|
429
|
-
import { RestTransporter } from '@livequery/rest'
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
Methods:
|
|
433
|
-
|
|
434
|
-
- `query({ ref, filters })`
|
|
435
|
-
- `add(ref, data)`
|
|
436
|
-
- `update(collectionRef, id, data)`
|
|
437
|
-
- `delete(collectionRef, id)`
|
|
438
|
-
- `trigger({ ref, action, payload })`
|
|
439
|
-
|
|
440
|
-
### `Socket`
|
|
451
|
+
Most applications should use `RestTransporter` rather than `Socket` directly. `Socket` is exported for low-level integrations and debugging.
|
|
441
452
|
|
|
442
453
|
```ts
|
|
443
454
|
import { Socket } from '@livequery/rest'
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
Subpath import is also available:
|
|
447
|
-
|
|
448
|
-
```ts
|
|
449
|
-
import { Socket } from '@livequery/rest/Socket'
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
The socket class is exported for low-level integrations and debugging.
|
|
453
455
|
|
|
454
|
-
Example:
|
|
455
|
-
|
|
456
|
-
```ts
|
|
457
456
|
const socket = new Socket('wss://api.example.com/ws')
|
|
458
457
|
|
|
459
|
-
socket.listen('users').subscribe(change => {
|
|
458
|
+
const sub = socket.listen('users').subscribe(change => {
|
|
460
459
|
console.log(change)
|
|
461
460
|
})
|
|
462
461
|
|
|
462
|
+
socket.subscribeWith('rt_abc123')
|
|
463
|
+
|
|
464
|
+
sub.unsubscribe()
|
|
463
465
|
socket.stop()
|
|
464
466
|
```
|
|
465
467
|
|
|
466
468
|
## Error Handling
|
|
467
469
|
|
|
468
|
-
If `fetch()` throws
|
|
470
|
+
If `fetch()` throws, the backend returns an error envelope, the backend returns invalid JSON, or the HTTP status is non-2xx, the transporter surfaces a structured error.
|
|
471
|
+
|
|
472
|
+
For `query()`, errors are emitted as observable results:
|
|
469
473
|
|
|
470
474
|
```ts
|
|
471
475
|
{
|
|
476
|
+
source: 'query',
|
|
472
477
|
error: {
|
|
473
|
-
code:
|
|
474
|
-
message:
|
|
478
|
+
code: 'HTTP_500',
|
|
479
|
+
message: 'Internal Server Error'
|
|
475
480
|
}
|
|
476
481
|
}
|
|
477
482
|
```
|
|
478
483
|
|
|
479
|
-
For `query()`, errors are emitted as an observable result with `source: 'query'`.
|
|
480
|
-
|
|
481
484
|
For `add()`, `update()`, `delete()`, and `trigger()`, errors are thrown as rejected promises.
|
|
482
485
|
|
|
483
|
-
|
|
486
|
+
Invalid JSON becomes:
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
{
|
|
490
|
+
code: 'InvalidResponse',
|
|
491
|
+
message: 'The server did not return valid JSON.'
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Practical Example
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
import { LivequeryClient } from '@livequery/client'
|
|
499
|
+
import { RestTransporter } from '@livequery/rest'
|
|
500
|
+
|
|
501
|
+
export const livequery = new LivequeryClient({
|
|
502
|
+
storage,
|
|
503
|
+
transporters: {
|
|
504
|
+
rest: new RestTransporter({
|
|
505
|
+
api: import.meta.env.VITE_API_URL,
|
|
506
|
+
ws: import.meta.env.VITE_WS_URL,
|
|
507
|
+
onRequest: async ({ headers }) => ({
|
|
508
|
+
headers: {
|
|
509
|
+
...headers,
|
|
510
|
+
Authorization: `Bearer ${await auth.getToken()}`
|
|
511
|
+
}
|
|
512
|
+
}),
|
|
513
|
+
onResponse: (_request, response) => {
|
|
514
|
+
if (response.error?.code === 'Unauthorized') {
|
|
515
|
+
auth.logout()
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
})
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Application code should create collections from the shared `LivequeryClient`. Do not create a new transporter per component render.
|
|
524
|
+
|
|
525
|
+
## Development
|
|
526
|
+
|
|
527
|
+
Run tests:
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
bun run test
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
Build:
|
|
484
534
|
|
|
485
535
|
```bash
|
|
486
536
|
bun run build
|
|
@@ -489,16 +539,20 @@ bun run build
|
|
|
489
539
|
Build steps:
|
|
490
540
|
|
|
491
541
|
- clean `dist/`
|
|
492
|
-
- emit Node.js ESM files with TypeScript
|
|
542
|
+
- emit Node.js ESM files with TypeScript
|
|
493
543
|
- generate `.js`, `.d.ts`, `.js.map`, and `.d.ts.map`
|
|
494
544
|
|
|
495
|
-
The
|
|
545
|
+
The package exposes these entrypoints:
|
|
496
546
|
|
|
497
547
|
- `@livequery/rest`
|
|
498
548
|
- `@livequery/rest/RestTransporter`
|
|
499
549
|
- `@livequery/rest/Socket`
|
|
500
550
|
- `@livequery/rest/helpers/parseJson`
|
|
501
551
|
|
|
552
|
+
## AI Agent Guidance
|
|
553
|
+
|
|
554
|
+
Repository-specific agent guidance lives in `AGENTS.md`. That file is for coding agents modifying this repository. This README is for package users.
|
|
555
|
+
|
|
502
556
|
## License
|
|
503
557
|
|
|
504
558
|
ISC
|
|
@@ -44,9 +44,10 @@ export declare class RestTransporter implements LivequeryTransporter {
|
|
|
44
44
|
private config;
|
|
45
45
|
private socket;
|
|
46
46
|
constructor(config: RestTransporterConfig);
|
|
47
|
-
query<T extends Doc>({ ref, filters }: {
|
|
47
|
+
query<T extends Doc>({ ref, filters, headers }: {
|
|
48
48
|
ref: string;
|
|
49
|
-
filters
|
|
49
|
+
filters?: Partial<LivequeryFilters<T>>;
|
|
50
|
+
headers?: Record<string, string>;
|
|
50
51
|
}): import("rxjs").Observable<Partial<LivequeryQueryResult>>;
|
|
51
52
|
add<T extends Doc>(ref: string, data: Partial<Omit<T, 'id'>>): Promise<T>;
|
|
52
53
|
update<T extends Doc>(collection_ref: string, id: string, data: Partial<T>): Promise<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RestTransporter.d.ts","sourceRoot":"","sources":["../src/RestTransporter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,oBAAoB,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAI5I,MAAM,MAAM,sBAAsB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAC/C,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAE3C,MAAM,MAAM,qBAAqB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,WAAW,CAAC,OAAO,CAAC,sBAAsB,GAAG;QAAE,QAAQ,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC,CAAC,GAAG,IAAI,CAAA;IAC5J,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC3H,CAAA;AAID,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,GAAG,IAAI;IACrD,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,IAAI,EAAE,CAAC,CAAA;IACP,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAC7D,CAAA;IACD,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAA;IACrC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1C,CAAA;AAGD,qBAAa,eAAgB,YAAW,oBAAoB;;IAKpD,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,MAAM,CAAoB;gBAGtB,MAAM,EAAE,qBAAqB;
|
|
1
|
+
{"version":3,"file":"RestTransporter.d.ts","sourceRoot":"","sources":["../src/RestTransporter.ts"],"names":[],"mappings":"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"}
|
package/dist/RestTransporter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { of, firstValueFrom, EMPTY, from } from 'rxjs';
|
|
2
|
-
import { catchError, filter, first, map, mergeMap, take } from 'rxjs/operators';
|
|
2
|
+
import { catchError, delay, filter, first, map, mergeMap, take } from 'rxjs/operators';
|
|
3
3
|
import { merge } from 'rxjs';
|
|
4
4
|
import { Socket } from './Socket.js';
|
|
5
5
|
import { parseJson } from './helpers/parseJson.js';
|
|
@@ -12,8 +12,32 @@ export class RestTransporter {
|
|
|
12
12
|
this.socket = new Socket(config.ws);
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
#buildUrl(req) {
|
|
16
|
+
const base = this.config.api.replace(/\/+$/, '');
|
|
17
|
+
const ref = req.ref.replace(/^\/+/, '');
|
|
18
|
+
const action = req.action ? `/~${encodeURIComponent(req.action)}` : '';
|
|
19
|
+
const params = new URLSearchParams();
|
|
20
|
+
for (const [key, value] of Object.entries(req.query || {})) {
|
|
21
|
+
if (value === undefined || value === null)
|
|
22
|
+
continue;
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
for (const item of value)
|
|
25
|
+
params.append(key, String(item));
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
params.set(key, String(value));
|
|
29
|
+
}
|
|
30
|
+
const query = params.toString();
|
|
31
|
+
return `${base}/${ref}${action}${query ? `?${query}` : ''}`;
|
|
32
|
+
}
|
|
15
33
|
async #call(req) {
|
|
16
|
-
const url =
|
|
34
|
+
const url = this.#buildUrl(req);
|
|
35
|
+
const gateway_id = this.socket
|
|
36
|
+
? await Promise.race([
|
|
37
|
+
firstValueFrom(this.socket.$gateway),
|
|
38
|
+
new Promise(r => setTimeout(() => r(undefined), 3000))
|
|
39
|
+
])
|
|
40
|
+
: undefined;
|
|
17
41
|
const base_headers = {
|
|
18
42
|
...req.body ? {
|
|
19
43
|
'Content-Type': 'application/json'
|
|
@@ -21,14 +45,18 @@ export class RestTransporter {
|
|
|
21
45
|
...this.socket ? {
|
|
22
46
|
socket_id: this.socket.client_id,
|
|
23
47
|
'x-lcid': this.socket.client_id,
|
|
24
|
-
'x-lgid':
|
|
48
|
+
...(gateway_id ? { 'x-lgid': gateway_id } : {})
|
|
25
49
|
} : {}
|
|
26
50
|
};
|
|
51
|
+
const request_headers = {
|
|
52
|
+
...base_headers,
|
|
53
|
+
...req.headers
|
|
54
|
+
};
|
|
27
55
|
const original_request = {
|
|
28
56
|
url,
|
|
29
57
|
method: req.method,
|
|
30
58
|
body: req.body,
|
|
31
|
-
headers:
|
|
59
|
+
headers: request_headers,
|
|
32
60
|
query: req.query,
|
|
33
61
|
ref: req.ref
|
|
34
62
|
};
|
|
@@ -47,14 +75,32 @@ export class RestTransporter {
|
|
|
47
75
|
...modified,
|
|
48
76
|
headers: {
|
|
49
77
|
...req.body && typeof req.body != 'string' ? { 'Content-Type': 'application/json' } : {},
|
|
50
|
-
...
|
|
78
|
+
...request_headers,
|
|
51
79
|
...headers
|
|
52
80
|
},
|
|
53
81
|
};
|
|
54
|
-
const response =
|
|
82
|
+
const response = await (async () => {
|
|
55
83
|
try {
|
|
56
84
|
const result = await fetch(request.url, request);
|
|
57
|
-
|
|
85
|
+
const body = await result.text();
|
|
86
|
+
const parsed = parseJson(body);
|
|
87
|
+
if (!result.ok) {
|
|
88
|
+
return {
|
|
89
|
+
error: {
|
|
90
|
+
code: `HTTP_${result.status}`,
|
|
91
|
+
message: parsed?.error?.message || result.statusText || 'Request failed'
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (!parsed) {
|
|
96
|
+
return {
|
|
97
|
+
error: {
|
|
98
|
+
code: 'InvalidResponse',
|
|
99
|
+
message: 'The server did not return valid JSON.'
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return parsed;
|
|
58
104
|
}
|
|
59
105
|
catch (e) {
|
|
60
106
|
return {
|
|
@@ -70,15 +116,18 @@ export class RestTransporter {
|
|
|
70
116
|
throw response.error;
|
|
71
117
|
return response.data;
|
|
72
118
|
}
|
|
73
|
-
query({ ref, filters }) {
|
|
74
|
-
const ready$ =
|
|
119
|
+
query({ ref, filters, headers }) {
|
|
120
|
+
const ready$ = this.socket
|
|
121
|
+
? merge(this.socket.pipe(filter(s => !!s.connected), map(() => Date.now())), of(Date.now()).pipe(delay(3000))).pipe(first())
|
|
122
|
+
: of(1);
|
|
75
123
|
const watch$ = (!this.socket || !filters || filters[':after'] || filters[':before'] || filters[':around']) ? EMPTY : this.socket.listen(ref);
|
|
76
124
|
const refs = ref.split('/');
|
|
77
125
|
const collection_ref = refs.length % 2 == 0 ? refs.slice(0, -1).join('/') : ref;
|
|
78
126
|
return merge(ready$.pipe(take(1), mergeMap(() => (from(this.#call({
|
|
79
127
|
ref,
|
|
80
128
|
method: 'GET',
|
|
81
|
-
query: filters
|
|
129
|
+
query: filters,
|
|
130
|
+
headers
|
|
82
131
|
})).pipe(map(collection => {
|
|
83
132
|
collection.subscription_token && this.socket?.subscribeWith(collection.subscription_token);
|
|
84
133
|
// If collection
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RestTransporter.js","sourceRoot":"","sources":["../src/RestTransporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"RestTransporter.js","sourceRoot":"","sources":["../src/RestTransporter.ts"],"names":[],"mappings":"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"}
|
package/dist/Socket.d.ts
CHANGED
|
@@ -11,7 +11,6 @@ export declare class Socket extends BehaviorSubject<LivequerySocketMetadata> {
|
|
|
11
11
|
private endpoint;
|
|
12
12
|
readonly client_id: string;
|
|
13
13
|
readonly $gateway: ReplaySubject<string>;
|
|
14
|
-
readonly $connected: BehaviorSubject<boolean>;
|
|
15
14
|
constructor(endpoint: string);
|
|
16
15
|
stop(): void;
|
|
17
16
|
private $sync;
|
package/dist/Socket.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Socket.d.ts","sourceRoot":"","sources":["../src/Socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,eAAe,EAAS,aAAa,EAAqC,MAAM,MAAM,CAAC;AAEhI,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"Socket.d.ts","sourceRoot":"","sources":["../src/Socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,eAAe,EAAS,aAAa,EAAqC,MAAM,MAAM,CAAC;AAEhI,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAIxD,MAAM,MAAM,uBAAuB,GAAG;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,qBAAa,MAAO,SAAQ,eAAe,CAAC,uBAAuB,CAAC;;IAYpD,OAAO,CAAC,QAAQ;IAV5B,SAAgB,SAAS,EAAE,MAAM,CAAA;IACjC,SAAgB,QAAQ,wBAA+B;gBASnC,QAAQ,EAAE,MAAM;IA0EpC,IAAI;IAMJ,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,MAAM;IAMd,aAAa,CAAC,cAAc,EAAE,MAAM;IAKpC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC;CAoBnD"}
|
package/dist/Socket.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { fromEvent, Observable, Subject, BehaviorSubject, merge, ReplaySubject, Subscription, of, interval, EMPTY } from "rxjs";
|
|
2
|
-
import { catchError, finalize,
|
|
2
|
+
import { catchError, finalize, map, mergeMap, retry, switchMap, takeUntil, tap } from "rxjs/operators";
|
|
3
3
|
import { v7 as uuidv7 } from 'uuid';
|
|
4
|
+
import { decode, encode } from '@msgpack/msgpack';
|
|
4
5
|
export class Socket extends BehaviorSubject {
|
|
5
6
|
endpoint;
|
|
6
|
-
client_id
|
|
7
|
+
client_id;
|
|
7
8
|
$gateway = new ReplaySubject(1);
|
|
8
|
-
$connected = new BehaviorSubject(false);
|
|
9
9
|
#topics = new Map();
|
|
10
10
|
#$input = new ReplaySubject(1000);
|
|
11
11
|
#running;
|
|
12
|
+
#stop$ = new Subject();
|
|
13
|
+
#binary = false;
|
|
12
14
|
constructor(endpoint) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
connected: false,
|
|
16
|
-
session: 0
|
|
17
|
-
});
|
|
15
|
+
const client_id = uuidv7();
|
|
16
|
+
super({ client_id, connected: false, session: 0 });
|
|
18
17
|
this.endpoint = endpoint;
|
|
18
|
+
this.client_id = client_id;
|
|
19
19
|
this.#init();
|
|
20
20
|
}
|
|
21
21
|
#init() {
|
|
@@ -23,24 +23,47 @@ export class Socket extends BehaviorSubject {
|
|
|
23
23
|
return;
|
|
24
24
|
if (this.#running)
|
|
25
25
|
return;
|
|
26
|
-
this.#running = of(1).pipe(takeUntil(this
|
|
26
|
+
this.#running = of(1).pipe(takeUntil(this.#stop$), mergeMap(async () => {
|
|
27
|
+
const ws = new WebSocket(this.endpoint);
|
|
28
|
+
ws.binaryType = 'arraybuffer';
|
|
29
|
+
return ws;
|
|
30
|
+
}), switchMap(ws => merge(fromEvent(ws, 'close').pipe(map(e => { throw e; })), fromEvent(ws, 'error').pipe(map(e => { throw e; })), fromEvent(ws, 'open').pipe(switchMap(() => interval(60000)), tap(() => this.#send(ws, { event: 'ping' }))), fromEvent(ws, 'open').pipe(tap(() => {
|
|
27
31
|
this.next({
|
|
28
32
|
...this.value,
|
|
29
33
|
connected: true,
|
|
30
34
|
session: this.value.session + 1
|
|
31
35
|
});
|
|
32
36
|
console.log(this.value.session == 1 ? 'Websocket connected' : `Websocket re-connected (${this.value.session})`);
|
|
33
|
-
|
|
34
|
-
}), mergeMap(() => this.#$input), tap(data =>
|
|
35
|
-
const e =
|
|
37
|
+
this.#send(ws, { event: 'start', data: { id: this.client_id } });
|
|
38
|
+
}), mergeMap(() => this.#$input), tap(data => this.#send(ws, data))), fromEvent(ws, 'message').pipe(tap((evt) => {
|
|
39
|
+
const e = this.#parseMessage(evt.data);
|
|
36
40
|
const fn = this[`$${e.event}`];
|
|
37
41
|
typeof fn == 'function' && fn.call(this, e);
|
|
38
42
|
}))).pipe(finalize(() => ws.close()))), catchError(e => {
|
|
39
|
-
this
|
|
43
|
+
this.next({
|
|
44
|
+
...this.value,
|
|
45
|
+
connected: false
|
|
46
|
+
});
|
|
40
47
|
throw e;
|
|
41
|
-
}), retry({ delay: 1000 })).subscribe();
|
|
48
|
+
}), retry({ delay: 1000 }), takeUntil(this.#stop$)).subscribe();
|
|
49
|
+
}
|
|
50
|
+
#parseMessage(data) {
|
|
51
|
+
if (typeof data === 'string') {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(data);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return decode(new TextEncoder().encode(data));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return decode(new Uint8Array(data));
|
|
60
|
+
}
|
|
61
|
+
#send(ws, data) {
|
|
62
|
+
ws.send(this.#binary ? encode(data) : JSON.stringify(data));
|
|
42
63
|
}
|
|
43
64
|
stop() {
|
|
65
|
+
this.#stop$.next();
|
|
66
|
+
this.#stop$.complete();
|
|
44
67
|
this.complete();
|
|
45
68
|
}
|
|
46
69
|
$sync(e) {
|
|
@@ -50,6 +73,7 @@ export class Socket extends BehaviorSubject {
|
|
|
50
73
|
}
|
|
51
74
|
}
|
|
52
75
|
$hello(e) {
|
|
76
|
+
this.#binary = e.binary === true;
|
|
53
77
|
this.$gateway.next(e.gid);
|
|
54
78
|
}
|
|
55
79
|
subscribeWith(realtime_token) {
|
|
@@ -69,6 +93,7 @@ export class Socket extends BehaviorSubject {
|
|
|
69
93
|
setTimeout(() => {
|
|
70
94
|
if (topic.listen_count == 0) {
|
|
71
95
|
this.#$input.next({ event: 'unsubscribe', data: { ref } });
|
|
96
|
+
this.#topics.delete(ref);
|
|
72
97
|
}
|
|
73
98
|
}, 2000);
|
|
74
99
|
}));
|
package/dist/Socket.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Socket.js","sourceRoot":"","sources":["../src/Socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAChI,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"Socket.js","sourceRoot":"","sources":["../src/Socket.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,52 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
"name": "@livequery/rest",
|
|
3
|
+
"repository": {
|
|
4
|
+
"url": "https://github.com/livequery/rest"
|
|
5
|
+
},
|
|
6
|
+
"version": "2.0.135",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"description": "",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
5
16
|
},
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js",
|
|
15
|
-
"default": "./dist/index.js"
|
|
16
|
-
},
|
|
17
|
-
"./RestTransporter": {
|
|
18
|
-
"types": "./dist/RestTransporter.d.ts",
|
|
19
|
-
"import": "./dist/RestTransporter.js",
|
|
20
|
-
"default": "./dist/RestTransporter.js"
|
|
21
|
-
},
|
|
22
|
-
"./Socket": {
|
|
23
|
-
"types": "./dist/Socket.d.ts",
|
|
24
|
-
"import": "./dist/Socket.js",
|
|
25
|
-
"default": "./dist/Socket.js"
|
|
26
|
-
},
|
|
27
|
-
"./helpers/parseJson": {
|
|
28
|
-
"types": "./dist/helpers/parseJson.d.ts",
|
|
29
|
-
"import": "./dist/helpers/parseJson.js",
|
|
30
|
-
"default": "./dist/helpers/parseJson.js"
|
|
31
|
-
}
|
|
17
|
+
"./RestTransporter": {
|
|
18
|
+
"types": "./dist/RestTransporter.d.ts",
|
|
19
|
+
"import": "./dist/RestTransporter.js",
|
|
20
|
+
"default": "./dist/RestTransporter.js"
|
|
32
21
|
},
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"@livequery/client": "^2.0.133",
|
|
38
|
-
"typescript": "5.6.3"
|
|
22
|
+
"./Socket": {
|
|
23
|
+
"types": "./dist/Socket.d.ts",
|
|
24
|
+
"import": "./dist/Socket.js",
|
|
25
|
+
"default": "./dist/Socket.js"
|
|
39
26
|
},
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
}
|
|
27
|
+
"./helpers/parseJson": {
|
|
28
|
+
"types": "./dist/helpers/parseJson.d.ts",
|
|
29
|
+
"import": "./dist/helpers/parseJson.js",
|
|
30
|
+
"default": "./dist/helpers/parseJson.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*"
|
|
35
|
+
],
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@livequery/client": "^2.0.135",
|
|
38
|
+
"typescript": "5.6.3"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"rxjs": "^7.8.1",
|
|
42
|
+
"uuid": "^13.0.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"clean": "rm -rf dist",
|
|
46
|
+
"test": "bun test",
|
|
47
|
+
"build": "bun run clean && bunx tsc -p tsconfig.build.json",
|
|
48
|
+
"build:watch": "bunx tsc -p tsconfig.build.json --watch",
|
|
49
|
+
"prepublishOnly": "bun run build"
|
|
50
|
+
},
|
|
51
|
+
"author": "",
|
|
52
|
+
"license": "ISC",
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@msgpack/msgpack": "^3.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|