@livequery/honojs 2.0.145

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 ADDED
@@ -0,0 +1,321 @@
1
+ # @livequery/honojs
2
+
3
+ Hono framework adapter for the `@livequery` ecosystem. Provides request parsing middleware, route registration helpers, response utilities, an API gateway, and a service linker for building livequery-compatible REST APIs with [Hono](https://hono.dev).
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @livequery/honojs @livequery/core hono
11
+ # ws is required for WebSocket gateway support
12
+ npm install ws
13
+ ```
14
+
15
+ Peer dependencies: `hono >= 4.12`, `ws >= 8`
16
+
17
+ ---
18
+
19
+ ## Quick start: simple service
20
+
21
+ Use `createLivequery` to register routes. It automatically applies the livequery middleware to every route and tracks paths in a registry for service discovery.
22
+
23
+ ```ts
24
+ import * as http from 'http'
25
+ import { Hono } from 'hono'
26
+ import {
27
+ createLivequery,
28
+ getLivequeryRequest,
29
+ livequeryJson,
30
+ HonoApiServiceLinker,
31
+ WebsocketGateway,
32
+ } from '@livequery/honojs'
33
+
34
+ const app = new Hono()
35
+ const server = http.createServer((req, res) => {
36
+ app.fetch(new Request(`http://localhost${req.url}`, {
37
+ method: req.method,
38
+ headers: req.headers as HeadersInit,
39
+ })).then(async response => {
40
+ res.writeHead(response.status, Object.fromEntries(response.headers.entries()))
41
+ res.end(Buffer.from(await response.arrayBuffer()))
42
+ })
43
+ })
44
+ server.listen(3001)
45
+
46
+ const websocketGateway = new WebsocketGateway(server)
47
+ const livequery = createLivequery(app, { websocketGateway })
48
+
49
+ // Collection route
50
+ livequery.get('/livequery/products', c => {
51
+ return livequeryJson(c, {
52
+ items: [
53
+ { _id: 'p-1', name: 'Keyboard' },
54
+ { _id: 'p-2', name: 'Mouse' },
55
+ ],
56
+ })
57
+ })
58
+
59
+ // Document route
60
+ livequery.get('/livequery/products/:id', c => {
61
+ const req = getLivequeryRequest(c)
62
+ return livequeryJson(c, {
63
+ item: { id: req.document_id, name: `Product ${req.document_id}` },
64
+ })
65
+ })
66
+
67
+ // POST / PATCH / DELETE
68
+ livequery.post('/livequery/products', c => {
69
+ const req = getLivequeryRequest(c)
70
+ return livequeryJson(c, { item: { id: 'new-id', ...req.body as object } }, 201)
71
+ })
72
+
73
+ // Broadcast this service's routes so a gateway can discover it
74
+ const linker = new HonoApiServiceLinker({ routes: livequery.registry, websocketGateway })
75
+ linker.start('products-service', 3001)
76
+ ```
77
+
78
+ `_id` is renamed to `id` and other `_`-prefixed fields are stripped automatically by `livequeryJson` (see [Private field stripping](#private-field-stripping)).
79
+
80
+ ---
81
+
82
+ ## Quick start: plain Hono app
83
+
84
+ If you prefer to register routes directly on a Hono app, use `collectServicePaths` to extract the path list and apply the `livequery()` middleware manually.
85
+
86
+ ```ts
87
+ import { Hono } from 'hono'
88
+ import {
89
+ livequery,
90
+ collectServicePaths,
91
+ getLivequeryRequest,
92
+ livequeryJson,
93
+ HonoApiServiceLinker,
94
+ } from '@livequery/honojs'
95
+
96
+ const app = new Hono()
97
+
98
+ app.get('/livequery/products',
99
+ livequery({ routePath: '/livequery/products' }),
100
+ c => livequeryJson(c, { items: [] })
101
+ )
102
+
103
+ app.get('/livequery/products/:id',
104
+ livequery({ routePath: '/livequery/products/:id' }),
105
+ c => {
106
+ const req = getLivequeryRequest(c)
107
+ return livequeryJson(c, { item: { id: req.document_id } })
108
+ }
109
+ )
110
+
111
+ const linker = new HonoApiServiceLinker({ routes: collectServicePaths(app) })
112
+ linker.start('products-service', 3001)
113
+ ```
114
+
115
+ Passing `routePath` to `livequery()` is required for correct `ref`, `collection_ref`, and `document_id` parsing. When omitted, the actual URL path is used as `ref` and `document_id` is never populated.
116
+
117
+ ---
118
+
119
+ ## API gateway
120
+
121
+ An API gateway auto-discovers upstream services over UDP and proxies HTTP requests. Client id headers (`x-lcid`, `x-lgid`) are forwarded so upstream services can register realtime subscriptions.
122
+
123
+ ```ts
124
+ import * as http from 'http'
125
+ import { Hono } from 'hono'
126
+ import { HonoApiGatewayLinker, WebsocketGateway } from '@livequery/honojs'
127
+
128
+ const app = new Hono()
129
+ const server = http.createServer(/* bridge to app.fetch */)
130
+ server.listen(3000)
131
+
132
+ const websocketGateway = new WebsocketGateway(server)
133
+ const gateway = new HonoApiGatewayLinker({ websocketGateway })
134
+
135
+ app.all('*', gateway.handler())
136
+ ```
137
+
138
+ Routes with no registered upstream return `404 API_NOT_FOUND`. Unreachable upstreams return `502 SERVICE_API_OFFLINE` and are marked offline; after 30 seconds with no reconnect they are removed automatically.
139
+
140
+ For manual service registration (e.g. in tests), access the underlying handler:
141
+
142
+ ```ts
143
+ gateway.gateway.register({
144
+ node_id: 'svc-1',
145
+ hostname: '127.0.0.1',
146
+ port: 3001,
147
+ paths: [{ method: 'GET', path: 'livequery/products/:id' }],
148
+ })
149
+ ```
150
+
151
+ If you need to subclass `ApiGatewayHandler` directly, use `HonoApiGateway`:
152
+
153
+ ```ts
154
+ import { HonoApiGateway } from '@livequery/honojs'
155
+
156
+ class CustomGateway extends HonoApiGateway {}
157
+
158
+ const gateway = new CustomGateway({ websocketGateway })
159
+ const res = await gateway.fetch(new Request('http://gateway/livequery/products'))
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Realtime subscriptions
165
+
166
+ When a client sends a `GET` request with the `x-lcid` header, the middleware registers a realtime subscription so the client receives push updates when data changes.
167
+
168
+ ```
169
+ GET /livequery/products
170
+ x-lcid: client-abc123
171
+ ```
172
+
173
+ The middleware calls `websocketGateway.listen(...)` with the resource `ref` and client/gateway ids. No subscription is registered when cursor params (`:after`, `:before`, `:around`) are present — pagination requests are one-off fetches.
174
+
175
+ ```ts
176
+ // Just pass websocketGateway when creating the router — no extra code needed.
177
+ const livequery = createLivequery(app, { websocketGateway })
178
+ ```
179
+
180
+ The `x-lgid` header can specify a gateway id when routing through multiple gateways. If absent, `websocketGateway.id` is used.
181
+
182
+ ---
183
+
184
+ ## Private field stripping
185
+
186
+ `livequeryJson` strips private fields from `item` and `items` before sending.
187
+
188
+ Rules applied to each item:
189
+ - `_id` is renamed to `id` (only when `id` is not already set).
190
+ - Any other key starting with `_` is removed.
191
+ - All other keys pass through unchanged.
192
+
193
+ ```ts
194
+ livequeryJson(c, {
195
+ item: { _id: 'abc', name: 'Widget', _internalToken: 'xyz', price: 9.99 },
196
+ })
197
+ // Sends: { "item": { "id": "abc", "name": "Widget", "price": 9.99 } }
198
+ ```
199
+
200
+ For array responses:
201
+
202
+ ```ts
203
+ livequeryJson(c, {
204
+ items: [
205
+ { _id: 'p-1', name: 'Keyboard', _secret: 'hidden' },
206
+ { _id: 'p-2', name: 'Mouse', _secret: 'hidden' },
207
+ ],
208
+ })
209
+ // Sends: { "items": [{ "id": "p-1", "name": "Keyboard" }, { "id": "p-2", "name": "Mouse" }] }
210
+ ```
211
+
212
+ Objects that implement `toJSON()` (e.g. Mongoose documents) are serialised via `toJSON()` before field stripping.
213
+
214
+ To apply the transformation without sending:
215
+
216
+ ```ts
217
+ import { mapLivequeryResponse } from '@livequery/honojs'
218
+
219
+ const mapped = mapLivequeryResponse({ items: [...] })
220
+ ```
221
+
222
+ ---
223
+
224
+ ## `LivequeryRequest` field reference
225
+
226
+ `getLivequeryRequest(c)` returns a `LivequeryRequest<unknown>` from `@livequery/core`.
227
+
228
+ Given route `/livequery/products/:id` and request `GET /livequery/products/p-1?limit=20`:
229
+
230
+ | Field | Example | Description |
231
+ |---|---|---|
232
+ | `ref` | `"products/p-1"` | Canonical resource reference (path minus prefix) |
233
+ | `collection_ref` | `"products"` | Reference to the parent collection |
234
+ | `schema_collection_ref` | `"products"` | Like `collection_ref` but `:param` markers replaced with key names |
235
+ | `document_id` | `"p-1"` | Document id; `undefined` for collection routes |
236
+ | `keys` | `{ id: "p-1" }` | Hono route params |
237
+ | `method` | `"GET"` | HTTP method, always uppercase |
238
+ | `body` | `{ name: "..." }` | Parsed JSON body; `undefined` for GET/HEAD |
239
+ | `query` | `{ limit: "20" }` | Query string params |
240
+ | `path` | `"/livequery/products/p-1"` | Literal URL path |
241
+
242
+ For collection routes (last route segment is not a `:param`), `document_id` is `undefined` and `ref` equals `collection_ref`.
243
+
244
+ ---
245
+
246
+ ## `createDatasourceMapper`
247
+
248
+ For services backed by a typed datasource adapter, `createDatasourceMapper` generates Hono handlers without boilerplate.
249
+
250
+ ```ts
251
+ import { Subject } from 'rxjs'
252
+ import { createDatasourceMapper, createLivequery, livequeryJson } from '@livequery/honojs'
253
+ import type { LivequeryDatasource } from '@livequery/honojs'
254
+ import type { LivequeryBaseEntity, LivequeryRequest, WebsocketSyncPayload } from '@livequery/types'
255
+
256
+ type Product = LivequeryBaseEntity & { name: string }
257
+ type Config = { db: Product[] }
258
+ type RouteOpts = { collection: 'products' }
259
+
260
+ class ProductDatasource
261
+ extends Subject<WebsocketSyncPayload<LivequeryBaseEntity>>
262
+ implements LivequeryDatasource<Config, RouteOpts>
263
+ {
264
+ #config!: Config
265
+
266
+ async init(config: Config): Promise<void> { this.#config = config }
267
+
268
+ async query(req: LivequeryRequest, opts: RouteOpts) {
269
+ const items = this.#config[opts.collection]
270
+ if (req.is_collection) return { items }
271
+ return { item: items.find(p => p.id === req.doc_id) }
272
+ }
273
+ }
274
+
275
+ const app = new Hono()
276
+ const livequery = createLivequery(app)
277
+
278
+ // Placeholder handlers — replaced after async init
279
+ let listHandler = (c: any) => livequeryJson(c, { items: [] })
280
+ let itemHandler = (c: any) => livequeryJson(c, { item: {} })
281
+
282
+ livequery.get('/livequery/products', c => listHandler(c))
283
+ livequery.get('/livequery/products/:id', c => itemHandler(c))
284
+
285
+ const useDatasource = await createDatasourceMapper({
286
+ datasource: new ProductDatasource(),
287
+ routes: livequery.registry,
288
+ config: { db: [{ id: 'p-1', name: 'Keyboard' }] },
289
+ })
290
+
291
+ listHandler = useDatasource({ collection: 'products' })
292
+ itemHandler = useDatasource({ collection: 'products' })
293
+ ```
294
+
295
+ Note: the `LivequeryRequest` received in `datasource.query()` is from `@livequery/types`
296
+ and has `doc_id`, `is_collection`, and `options` — distinct from the `@livequery/core`
297
+ type returned by `getLivequeryRequest(c)`.
298
+
299
+ ---
300
+
301
+ ## TypeScript types
302
+
303
+ ```ts
304
+ import type {
305
+ // Local types
306
+ LivequeryRoute, // { method: string; path: string }
307
+ LivequeryResponse, // { item?: T; items?: T[]; [key: string]: unknown }
308
+ LivequeryVariables, // { livequery: LivequeryRequest<unknown> }
309
+ LivequeryContext, // Context<{ Variables: LivequeryVariables }>
310
+
311
+ // Re-exported from @livequery/core
312
+ LivequeryRequest, // parsed request shape (core version)
313
+ LivequeryDatasource, // datasource contract
314
+ LivequeryDatasourceInitConfig,
315
+ RealtimeSubscription,
316
+ UdpDiscoveryNode,
317
+ UdpDiscoveryOptions,
318
+ UdpDiscoveryPacket,
319
+ UdpDiscoveryStatus,
320
+ } from '@livequery/honojs'
321
+ ```
@@ -0,0 +1,17 @@
1
+ import type { Context, Handler } from 'hono';
2
+ import { ApiGatewayHandler, UdpDiscovery, WebsocketGateway, type ServiceApiMetadata } from '@livequery/core';
3
+ export type HonoApiGatewayOptions = {
4
+ websocketGateway?: WebsocketGateway;
5
+ discovery?: UdpDiscovery<ServiceApiMetadata>;
6
+ };
7
+ export declare class HonoApiGateway extends ApiGatewayHandler {
8
+ constructor(options?: HonoApiGatewayOptions);
9
+ }
10
+ export declare class HonoApiGatewayLinker {
11
+ #private;
12
+ constructor(options?: HonoApiGatewayOptions);
13
+ get gateway(): ApiGatewayHandler;
14
+ handler(): Handler;
15
+ fetch(c: Context): Promise<Response>;
16
+ close(): void;
17
+ }
@@ -0,0 +1,28 @@
1
+ import { ApiGatewayHandler, } from '@livequery/core';
2
+ export class HonoApiGateway extends ApiGatewayHandler {
3
+ constructor(options = {}) {
4
+ super(options);
5
+ }
6
+ }
7
+ export class HonoApiGatewayLinker {
8
+ #handler;
9
+ constructor(options = {}) {
10
+ this.#handler = new ApiGatewayHandler({
11
+ ...(options.websocketGateway ? { ws: options.websocketGateway } : {}),
12
+ ...(options.discovery ? { discovery: options.discovery } : {}),
13
+ });
14
+ }
15
+ get gateway() {
16
+ return this.#handler;
17
+ }
18
+ handler() {
19
+ return async (c) => this.fetch(c);
20
+ }
21
+ fetch(c) {
22
+ return this.#handler.fetchRequest(c.req.raw);
23
+ }
24
+ close() {
25
+ this.#handler.close();
26
+ }
27
+ }
28
+ //# sourceMappingURL=api-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-gateway.js","sourceRoot":"","sources":["../../src/api-gateway.ts"],"names":[],"mappings":"AACA,OAAO,EACH,iBAAiB,GAIpB,MAAM,iBAAiB,CAAA;AAOxB,MAAM,OAAO,cAAe,SAAQ,iBAAiB;IACjD,YAAY,UAAiC,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;CACJ;AAED,MAAM,OAAO,oBAAoB;IACpB,QAAQ,CAAmB;IAEpC,YAAY,UAAiC,EAAE;QAC3C,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAC;YAClC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC,CAAA;IACN,CAAC;IAED,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,QAAQ,CAAA;IACxB,CAAC;IAED,OAAO;QACH,OAAO,KAAK,EAAC,CAAC,EAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC;IAED,KAAK,CAAC,CAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAChD,CAAC;IAED,KAAK;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;IACzB,CAAC;CACJ"}
@@ -0,0 +1,14 @@
1
+ import { UdpDiscovery, WebsocketGateway, type ServiceApiMetadata } from '@livequery/core';
2
+ import type { LivequeryRouteRegistry } from './route-registry.js';
3
+ import type { LivequeryRoute } from './types.js';
4
+ export type HonoApiServiceLinkerOptions = {
5
+ routes: LivequeryRoute[] | LivequeryRouteRegistry;
6
+ websocketGateway?: WebsocketGateway;
7
+ discovery?: UdpDiscovery<ServiceApiMetadata>;
8
+ };
9
+ export declare class HonoApiServiceLinker {
10
+ #private;
11
+ constructor(options: HonoApiServiceLinkerOptions);
12
+ start(name: string, port: number): void;
13
+ close(): void;
14
+ }
@@ -0,0 +1,21 @@
1
+ import { ApiServiceLinker as CoreApiServiceLinker } from '@livequery/core';
2
+ export class HonoApiServiceLinker {
3
+ #linker;
4
+ constructor(options) {
5
+ const linkerOptions = {
6
+ paths: Array.isArray(options.routes) ? options.routes : options.routes.routes,
7
+ };
8
+ if (options.websocketGateway)
9
+ linkerOptions.ws = options.websocketGateway;
10
+ if (options.discovery)
11
+ linkerOptions.discovery = options.discovery;
12
+ this.#linker = new CoreApiServiceLinker(linkerOptions);
13
+ }
14
+ start(name, port) {
15
+ this.#linker.start(name, port);
16
+ }
17
+ close() {
18
+ this.#linker.close();
19
+ }
20
+ }
21
+ //# sourceMappingURL=api-service-linker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-service-linker.js","sourceRoot":"","sources":["../../src/api-service-linker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAA2D,MAAM,iBAAiB,CAAA;AAUnI,MAAM,OAAO,oBAAoB;IACpB,OAAO,CAAsB;IAEtC,YAAY,OAAoC;QAC5C,MAAM,aAAa,GAA0D;YACzE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM;SAChF,CAAA;QACD,IAAI,OAAO,CAAC,gBAAgB;YAAE,aAAa,CAAC,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAA;QACzE,IAAI,OAAO,CAAC,SAAS;YAAE,aAAa,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAA;QAClE,IAAI,CAAC,OAAO,GAAG,IAAI,oBAAoB,CAAC,aAAa,CAAC,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,IAAY,EAAE,IAAY;QAC5B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,KAAK;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;CACJ"}
@@ -0,0 +1,33 @@
1
+ import type { Context, Handler } from 'hono';
2
+ import { Observable, Subject } from 'rxjs';
3
+ import { type LivequeryDatasourceInitConfig } from '@livequery/core';
4
+ import type { LivequeryBaseEntity, LivequeryRequest, UpdatedData, WebsocketSyncPayload } from '@livequery/types';
5
+ import type { LivequeryRoute, LivequeryResponse } from './types.js';
6
+ import type { LivequeryRouteRegistry } from './route-registry.js';
7
+ import { WebsocketGateway } from '@livequery/core';
8
+ export declare class LivequeryItemMapper<T extends LivequeryBaseEntity> {
9
+ readonly mapper: (item: T) => T;
10
+ constructor(mapper: (item: T) => T);
11
+ }
12
+ export type LivequeryDatasource<Config, RouteOptions> = Subject<WebsocketSyncPayload<LivequeryBaseEntity>> & {
13
+ init(config: Config, routes: Array<LivequeryDatasourceInitConfig<RouteOptions>>): Promise<void>;
14
+ query(query: LivequeryRequest, options: RouteOptions): Promise<{
15
+ items?: any[];
16
+ item?: any;
17
+ }>;
18
+ };
19
+ export type LivequeryDatasourceWatcher<Config, RouteOptions> = {
20
+ watch(config: Config, routes: Array<LivequeryDatasourceInitConfig<RouteOptions>>, ds: LivequeryDatasource<Config, RouteOptions>): Observable<UpdatedData<any>>;
21
+ };
22
+ export type CreateDatasourceOptions<Config, RouteOptions> = {
23
+ datasource: LivequeryDatasource<Config, RouteOptions>;
24
+ watcher?: LivequeryDatasourceWatcher<Config, RouteOptions>;
25
+ websocketGateway?: WebsocketGateway;
26
+ routes: LivequeryRoute[] | LivequeryRouteRegistry;
27
+ config: Config | Promise<Config>;
28
+ };
29
+ export declare function createDatasourceMapper<Config, RouteOptions>(options: CreateDatasourceOptions<Config, RouteOptions>): Promise<(routeOptions: RouteOptions, mapper?: DatasourceMapper) => Handler>;
30
+ export type DatasourceMapper = LivequeryItemMapper<any> | ((result: {
31
+ items?: any[];
32
+ item?: any;
33
+ }, c: Context) => LivequeryResponse | Promise<LivequeryResponse>);
@@ -0,0 +1,52 @@
1
+ import { hidePrivateFields } from '@livequery/core';
2
+ import { getLivequeryRequest } from './request.js';
3
+ import { livequeryJson } from './response.js';
4
+ export class LivequeryItemMapper {
5
+ mapper;
6
+ constructor(mapper) {
7
+ this.mapper = mapper;
8
+ }
9
+ }
10
+ export async function createDatasourceMapper(options) {
11
+ const routes = Array.isArray(options.routes) ? options.routes : options.routes.routes;
12
+ const config = await options.config;
13
+ const datasourceRoutes = routes.map(route => ({
14
+ path: route.path,
15
+ method: route.method,
16
+ config: undefined,
17
+ }));
18
+ await options.datasource.init(config, datasourceRoutes);
19
+ if (options.watcher && options.websocketGateway) {
20
+ options.watcher.watch(config, datasourceRoutes, options.datasource).subscribe({
21
+ next: value => options.websocketGateway?.next(value),
22
+ });
23
+ }
24
+ return function useDatasource(routeOptions, mapper) {
25
+ return async (c) => {
26
+ const livequeryRequest = getLivequeryRequest(c);
27
+ const result = await options.datasource.query(livequeryRequest, routeOptions);
28
+ return livequeryJson(c, mapDatasourceResult(c, result, mapper));
29
+ };
30
+ };
31
+ }
32
+ function mapDatasourceResult(c, result, mapper) {
33
+ if (mapper instanceof LivequeryItemMapper) {
34
+ if (result.item)
35
+ return { ...result, item: mapper.mapper(result.item) };
36
+ if (result.items)
37
+ return { ...result, items: result.items.map(item => mapper.mapper(item)) };
38
+ return result;
39
+ }
40
+ if (typeof mapper === 'function') {
41
+ const mapped = mapper(result, c);
42
+ if (mapped instanceof Promise) {
43
+ throw new Error('Async datasource mapper must be awaited by a custom Hono handler');
44
+ }
45
+ return mapped;
46
+ }
47
+ if (result.items) {
48
+ return { ...result, items: result.items.map(item => hidePrivateFields(item)) };
49
+ }
50
+ return result;
51
+ }
52
+ //# sourceMappingURL=datasource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datasource.js","sourceRoot":"","sources":["../../src/datasource.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export * from './types.js';
2
+ export * from './request.js';
3
+ export * from './response.js';
4
+ export * from './middleware.js';
5
+ export * from './route-registry.js';
6
+ export * from './api-service-linker.js';
7
+ export * from './api-gateway.js';
8
+ export * from './datasource.js';
9
+ export { UdpDiscovery, WebsocketGateway, ApiGatewayHandler, ApiServiceLinker, WEBSOCKET_PATH, type UdpDiscoveryNode, type UdpDiscoveryOptions, type UdpDiscoveryPacket, type UdpDiscoveryStatus, type RealtimeSubscription, type LivequeryDatasource, type LivequeryDatasourceInitConfig, type LivequeryRequest, } from '@livequery/core';
@@ -0,0 +1,10 @@
1
+ export * from './types.js';
2
+ export * from './request.js';
3
+ export * from './response.js';
4
+ export * from './middleware.js';
5
+ export * from './route-registry.js';
6
+ export * from './api-service-linker.js';
7
+ export * from './api-gateway.js';
8
+ export * from './datasource.js';
9
+ export { UdpDiscovery, WebsocketGateway, ApiGatewayHandler, ApiServiceLinker, WEBSOCKET_PATH, } from '@livequery/core';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EACH,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GASjB,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,7 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ import { WebsocketGateway } from '@livequery/core';
3
+ export type LivequeryMiddlewareOptions = {
4
+ websocketGateway?: WebsocketGateway;
5
+ routePath?: string;
6
+ };
7
+ export declare function livequery(options?: LivequeryMiddlewareOptions): MiddlewareHandler;
@@ -0,0 +1,25 @@
1
+ import { createLivequeryRequest } from './request.js';
2
+ export function livequery(options = {}) {
3
+ return async (c, next) => {
4
+ const requestOptions = options.routePath ? { routePath: options.routePath } : {};
5
+ const livequeryRequest = await createLivequeryRequest(c, requestOptions);
6
+ c.set('livequery', livequeryRequest);
7
+ const ws = options.websocketGateway;
8
+ if (ws && c.req.method === 'GET' && livequeryRequest) {
9
+ const client_id = c.req.header('x-lcid') || c.req.header('socket_id');
10
+ const gateway_id = c.req.header('x-lgid') || ws.id;
11
+ const query = livequeryRequest.query ?? {};
12
+ const has_cursor = !!(query[':after'] || query[':before'] || query[':around']);
13
+ if (client_id && gateway_id && !has_cursor) {
14
+ ws.listen([{
15
+ ref: livequeryRequest.ref,
16
+ client_id,
17
+ gateway_id,
18
+ listener_node_id: ws.id,
19
+ }]);
20
+ }
21
+ }
22
+ await next();
23
+ };
24
+ }
25
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAOrD,MAAM,UAAU,SAAS,CAAC,UAAsC,EAAE;IAC9D,OAAO,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAChF,MAAM,gBAAgB,GAAG,MAAM,sBAAsB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;QACxE,CAAC,CAAC,GAAG,CAAC,WAAoB,EAAE,gBAAyB,CAAC,CAAA;QAEtD,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAA;QACnC,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,gBAAgB,EAAE,CAAC;YACnD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;YACrE,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAA;YAClD,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,IAAI,EAAE,CAAA;YAC1C,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;YAE9E,IAAI,SAAS,IAAI,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;gBACzC,EAAE,CAAC,MAAM,CAAC,CAAC;wBACP,GAAG,EAAE,gBAAgB,CAAC,GAAG;wBACzB,SAAS;wBACT,UAAU;wBACV,gBAAgB,EAAE,EAAE,CAAC,EAAE;qBAC1B,CAAC,CAAC,CAAA;YACP,CAAC;QACL,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IAChB,CAAC,CAAA;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Context } from 'hono';
2
+ import type { LivequeryRequest } from '@livequery/core';
3
+ export type CreateLivequeryRequestOptions = {
4
+ routePath?: string;
5
+ body?: unknown;
6
+ };
7
+ export declare function createLivequeryRequest(c: Context, options?: CreateLivequeryRequestOptions): Promise<LivequeryRequest<unknown> | undefined>;
8
+ export declare function getLivequeryRequest(c: Context): LivequeryRequest<unknown>;
@@ -0,0 +1,33 @@
1
+ import { LivequeryRequestParser } from '@livequery/core';
2
+ const parser = new LivequeryRequestParser();
3
+ export async function createLivequeryRequest(c, options = {}) {
4
+ const ctx = {
5
+ request: {
6
+ path: c.req.path,
7
+ ref: options.routePath ?? c.req.path,
8
+ method: c.req.method.toUpperCase(),
9
+ params: c.req.param(),
10
+ query: c.req.query(),
11
+ body: options.body ?? await readBody(c),
12
+ headers: new Map(Object.entries(c.req.header())),
13
+ },
14
+ };
15
+ return parser.handle(ctx);
16
+ }
17
+ export function getLivequeryRequest(c) {
18
+ return c.get('livequery');
19
+ }
20
+ async function readBody(c) {
21
+ if (c.req.method === 'GET' || c.req.method === 'HEAD')
22
+ return undefined;
23
+ const contentType = c.req.header('content-type') ?? '';
24
+ if (!contentType.includes('application/json'))
25
+ return undefined;
26
+ try {
27
+ return await c.req.raw.clone().json();
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAGxD,MAAM,MAAM,GAAG,IAAI,sBAAsB,EAAE,CAAA;AAO3C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CACxC,CAAU,EACV,UAAyC,EAAE;IAE3C,MAAM,GAAG,GAAY;QACjB,OAAO,EAAE;YACL,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI;YAChB,GAAG,EAAE,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI;YACpC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE;YAClC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE;YACrB,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC;YACvC,OAAO,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;SACnD;KACJ,CAAA;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAU;IAC1C,OAAO,CAAC,CAAC,GAAG,CAAC,WAAoB,CAA8B,CAAA;AACnE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,CAAU;IAC9B,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,SAAS,CAAA;IACvE,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;IACtD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAAE,OAAO,SAAS,CAAA;IAC/D,IAAI,CAAC;QACD,OAAO,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAA;IACpB,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Context } from 'hono';
2
+ import type { LivequeryResponse } from './types.js';
3
+ export declare function mapLivequeryResponse<T extends LivequeryResponse>(response: T): T;
4
+ export declare function livequeryJson<T extends LivequeryResponse>(c: Context, response: T, status?: number): Response;
@@ -0,0 +1,26 @@
1
+ import { hidePrivateFields } from '@livequery/core';
2
+ export function mapLivequeryResponse(response) {
3
+ if (response.item) {
4
+ return {
5
+ ...response,
6
+ item: hidePrivateFields(toPlain(response.item)),
7
+ };
8
+ }
9
+ if (response.items) {
10
+ return {
11
+ ...response,
12
+ items: response.items.map(item => hidePrivateFields(toPlain(item))),
13
+ };
14
+ }
15
+ return response;
16
+ }
17
+ export function livequeryJson(c, response, status) {
18
+ return c.json(mapLivequeryResponse(response), status);
19
+ }
20
+ function toPlain(item) {
21
+ if (item && typeof item === 'object' && 'toJSON' in item && typeof item.toJSON === 'function') {
22
+ return item.toJSON();
23
+ }
24
+ return item;
25
+ }
26
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/response.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAGnD,MAAM,UAAU,oBAAoB,CAA8B,QAAW;IACzE,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO;YACH,GAAG,QAAQ;YACX,IAAI,EAAE,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU,CAAC;SAC3D,CAAA;IACL,CAAC;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO;YACH,GAAG,QAAQ;YACX,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAU,CAAC,CAAC;SAC/E,CAAA;IACL,CAAC;IAED,OAAO,QAAQ,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CACzB,CAAU,EACV,QAAW,EACX,MAAe;IAEf,OAAO,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAe,CAAC,CAAA;AAClE,CAAC;AAED,SAAS,OAAO,CAAC,IAAa;IAC1B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC5F,OAAO,IAAI,CAAC,MAAM,EAA6B,CAAA;IACnD,CAAC;IACD,OAAO,IAA+B,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { Hono, Handler, MiddlewareHandler } from 'hono';
2
+ import type { LivequeryRoute } from './types.js';
3
+ import { type LivequeryMiddlewareOptions } from './middleware.js';
4
+ export type HonoRouteMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
5
+ export declare class LivequeryRouteRegistry {
6
+ #private;
7
+ get routes(): LivequeryRoute[];
8
+ add(method: string, path: string): void;
9
+ }
10
+ export type LivequeryRouterOptions = LivequeryMiddlewareOptions;
11
+ export declare class LivequeryRouter {
12
+ #private;
13
+ readonly app: Hono;
14
+ readonly options: LivequeryRouterOptions;
15
+ readonly registry: LivequeryRouteRegistry;
16
+ constructor(app: Hono, options?: LivequeryRouterOptions);
17
+ get(path: string, ...handlers: Handler[]): void;
18
+ post(path: string, ...handlers: Handler[]): void;
19
+ put(path: string, ...handlers: Handler[]): void;
20
+ patch(path: string, ...handlers: Handler[]): void;
21
+ delete(path: string, ...handlers: Handler[]): void;
22
+ use(path: string, ...handlers: MiddlewareHandler[]): void;
23
+ }
24
+ export declare function createLivequery(app: Hono, options?: LivequeryRouterOptions): LivequeryRouter;
25
+ export declare function collectServicePaths(app: Hono): LivequeryRoute[];
@@ -0,0 +1,58 @@
1
+ import { livequery } from './middleware.js';
2
+ export class LivequeryRouteRegistry {
3
+ #routes = [];
4
+ get routes() {
5
+ return [...this.#routes];
6
+ }
7
+ add(method, path) {
8
+ const normalized = normalizePath(path);
9
+ const METHOD = method.toUpperCase();
10
+ if (this.#routes.some(route => route.method === METHOD && route.path === normalized))
11
+ return;
12
+ this.#routes.push({ method: METHOD, path: normalized });
13
+ }
14
+ }
15
+ export class LivequeryRouter {
16
+ app;
17
+ options;
18
+ registry = new LivequeryRouteRegistry();
19
+ constructor(app, options = {}) {
20
+ this.app = app;
21
+ this.options = options;
22
+ }
23
+ get(path, ...handlers) {
24
+ this.#route('get', path, handlers);
25
+ }
26
+ post(path, ...handlers) {
27
+ this.#route('post', path, handlers);
28
+ }
29
+ put(path, ...handlers) {
30
+ this.#route('put', path, handlers);
31
+ }
32
+ patch(path, ...handlers) {
33
+ this.#route('patch', path, handlers);
34
+ }
35
+ delete(path, ...handlers) {
36
+ this.#route('delete', path, handlers);
37
+ }
38
+ use(path, ...handlers) {
39
+ this.app.use(path, ...handlers);
40
+ }
41
+ #route(method, path, handlers) {
42
+ this.registry.add(method, path);
43
+ this.app[method](path, livequery({ ...this.options, routePath: path }), ...handlers);
44
+ }
45
+ }
46
+ export function createLivequery(app, options = {}) {
47
+ return new LivequeryRouter(app, options);
48
+ }
49
+ export function collectServicePaths(app) {
50
+ return app.routes.map(route => ({
51
+ method: route.method,
52
+ path: normalizePath(route.path),
53
+ }));
54
+ }
55
+ function normalizePath(path) {
56
+ return path.split('/').filter(Boolean).join('/');
57
+ }
58
+ //# sourceMappingURL=route-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-registry.js","sourceRoot":"","sources":["../../src/route-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Context } from 'hono';
2
+ import type { LivequeryRequest } from '@livequery/core';
3
+ export type LivequeryVariables = {
4
+ livequery: LivequeryRequest<unknown>;
5
+ };
6
+ export type LivequeryContext = Context<{
7
+ Variables: LivequeryVariables;
8
+ }>;
9
+ export type LivequeryRoute = {
10
+ method: string;
11
+ path: string;
12
+ };
13
+ export type LivequeryResponse<T = unknown> = {
14
+ item?: T;
15
+ items?: T[];
16
+ [key: string]: unknown;
17
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"root":["../src/api-gateway.ts","../src/api-service-linker.ts","../src/datasource.ts","../src/index.ts","../src/middleware.ts","../src/request.ts","../src/response.ts","../src/route-registry.ts","../src/types.ts"],"version":"5.9.3"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@livequery/honojs",
3
+ "author": "Duong Van Ba",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "url": "git@github.com:livequery/honojs.git"
7
+ },
8
+ "version": "2.0.145",
9
+ "description": "Hono adapter for @livequery ecosystem",
10
+ "main": "./build/src/index.js",
11
+ "types": "./build/src/index.d.ts",
12
+ "files": [
13
+ "build/**/*"
14
+ ],
15
+ "scripts": {
16
+ "test": "bun test tests/",
17
+ "build": "tsc -b ."
18
+ },
19
+ "exports": {
20
+ ".": {
21
+ "import": {
22
+ "types": "./build/src/index.d.ts",
23
+ "default": "./build/src/index.js"
24
+ }
25
+ }
26
+ },
27
+ "type": "module",
28
+ "devDependencies": {
29
+ "@types/bun": "latest",
30
+ "@types/node": "x",
31
+ "typescript": "^5.1.6"
32
+ },
33
+ "peerDependencies": {
34
+ "hono": "^4.12.21",
35
+ "ws": ">=8"
36
+ },
37
+ "dependencies": {
38
+ "@livequery/core": "^2.0.145",
39
+ "@livequery/types": "2.0.7",
40
+ "rxjs": "x"
41
+ }
42
+ }