lowlander 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -38
- package/build/client/client.d.ts +5 -1
- package/build/client/client.js +15 -4
- package/build/client/client.js.map +1 -1
- package/build/dashboard/client/main.d.ts +1 -0
- package/build/dashboard/client/main.js +623 -0
- package/build/dashboard/client/main.js.map +1 -0
- package/build/dashboard/client/shim-server.d.ts +3 -0
- package/build/dashboard/client/shim-server.js +2 -0
- package/build/dashboard/client/shim-server.js.map +1 -0
- package/build/dashboard/dashboard.html +20 -0
- package/build/dashboard/index.d.ts +18 -0
- package/build/dashboard/index.d.ts.map +1 -0
- package/build/dashboard/index.js +50 -0
- package/build/dashboard/index.js.map +1 -0
- package/build/dashboard/serve.d.ts +18 -0
- package/build/dashboard/serve.d.ts.map +1 -0
- package/build/dashboard/serve.js +53 -0
- package/build/dashboard/serve.js.map +1 -0
- package/build/dashboard/server.d.ts +82 -0
- package/build/dashboard/server.d.ts.map +1 -0
- package/build/dashboard/server.js +248 -0
- package/build/dashboard/server.js.map +1 -0
- package/build/examples/helloworld/.edinburgh/commit_worker.log +3162 -0
- package/build/examples/helloworld/.edinburgh/data.mdb +0 -0
- package/build/examples/helloworld/.edinburgh/lock.mdb +0 -0
- package/build/examples/helloworld/client/index.html +1 -1
- package/build/examples/helloworld/client/js/base.css +1 -0
- package/build/examples/helloworld/client/js/base.js +217 -71
- package/build/examples/helloworld/client/js/base.js.map +1 -1
- package/build/examples/helloworld/server/api.d.ts +37 -26
- package/build/examples/helloworld/server/api.d.ts.map +1 -1
- package/build/examples/helloworld/server/api.js +38 -10
- package/build/examples/helloworld/server/api.js.map +1 -1
- package/build/examples/helloworld/server/main.d.ts +1 -1
- package/build/examples/helloworld/server/main.d.ts.map +1 -1
- package/build/examples/helloworld/server/main.js +6 -17
- package/build/examples/helloworld/server/main.js.map +1 -1
- package/build/server/password.d.ts +10 -0
- package/build/server/password.d.ts.map +1 -0
- package/build/server/password.js +38 -0
- package/build/server/password.js.map +1 -0
- package/build/server/protocol.d.ts +1 -0
- package/build/server/protocol.d.ts.map +1 -1
- package/build/server/protocol.js +1 -0
- package/build/server/protocol.js.map +1 -1
- package/build/server/server.d.ts +9 -9
- package/build/server/server.d.ts.map +1 -1
- package/build/server/server.js +21 -2
- package/build/server/server.js.map +1 -1
- package/build/server/wshandler.d.ts +7 -1
- package/build/server/wshandler.d.ts.map +1 -1
- package/build/server/wshandler.js +62 -14
- package/build/server/wshandler.js.map +1 -1
- package/build/tsconfig.client.tsbuildinfo +1 -1
- package/build/tsconfig.server.tsbuildinfo +1 -1
- package/client/client.ts +20 -6
- package/dashboard/build-bundle.ts +38 -0
- package/dashboard/client/index.html +12 -0
- package/dashboard/client/main.ts +566 -0
- package/dashboard/client/shim-server.ts +5 -0
- package/dashboard/index.ts +49 -0
- package/dashboard/server.ts +255 -0
- package/package.json +22 -11
- package/server/protocol.ts +1 -0
- package/server/server.ts +53 -17
- package/server/wshandler.ts +66 -13
- package/skill/SKILL.md +85 -4
- package/skill/createStreamType.md +1 -1
- package/skill/getStreamTypesForModel.md +7 -0
package/skill/SKILL.md
CHANGED
|
@@ -25,17 +25,25 @@ This library is built on top of a number of libraries by the same author:
|
|
|
25
25
|
|
|
26
26
|
Lowlander glues these together and adds real-time partial data synchronization and type-safe RPCs to provide a framework for rapidly building performant full-stack (database included!) web applications.
|
|
27
27
|
|
|
28
|
+
## Example project
|
|
29
|
+
|
|
30
|
+
An example project is included in `examples/helloworld`. To run it:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run example
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Opens at http://localhost:8080 with the Aberdeen dashboard at http://localhost:8080/_dashboard (password printed to console on start).
|
|
37
|
+
|
|
28
38
|
## Tutorial
|
|
29
39
|
|
|
30
40
|
### Project Setup
|
|
31
41
|
|
|
32
42
|
```bash
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
npm init
|
|
44
|
+
npm add lowlander aberdeen edinburgh
|
|
35
45
|
```
|
|
36
46
|
|
|
37
|
-
(npm should also work for all of this.)
|
|
38
|
-
|
|
39
47
|
Create the project structure:
|
|
40
48
|
|
|
41
49
|
```
|
|
@@ -179,6 +187,20 @@ export async function authenticate(token: string) {
|
|
|
179
187
|
|
|
180
188
|
The client receives `'secret-value'` as `.value` and can call `UserAPI` methods via `.serverProxy`.
|
|
181
189
|
|
|
190
|
+
You can also pass a stream type instance as the value — the client's `.value` will then be reactive and update live whenever the model changes:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const PersonStream = createStreamType(Person, { name: true, age: true });
|
|
194
|
+
|
|
195
|
+
export async function authenticate(token: string) {
|
|
196
|
+
const user = Person.getBy('name', token);
|
|
197
|
+
if (!user) throw new Error('User not found');
|
|
198
|
+
return new ServerProxy(new UserAPI(token), new PersonStream(user));
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The client gets both `.serverProxy` (for calling `UserAPI` methods) and a live-updating `.value`.
|
|
203
|
+
|
|
182
204
|
When a proxy is dropped, because the request's Aberdeen scope was destroyed or the WebSocket disconnected, Lowlander calls `onDrop()` on the API object if it exists, letting you clean up server-side state.
|
|
183
205
|
|
|
184
206
|
```ts
|
|
@@ -295,6 +317,25 @@ Reconnection is automatic with exponential backoff.
|
|
|
295
317
|
|
|
296
318
|
Aberdeen's `clean()` handles RPC lifecycle. When a reactive scope is destroyed, active requests and subscriptions are cancelled automatically.
|
|
297
319
|
|
|
320
|
+
|
|
321
|
+
#### Named Client-Side Types
|
|
322
|
+
|
|
323
|
+
Use `ClientProxyObject<T>` to get the fully-typed client API shape, which is useful for deriving types from stream methods without duplicating field selections:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import type { ClientProxyObject } from 'lowlander/client';
|
|
327
|
+
import type * as API from './server/api.js';
|
|
328
|
+
|
|
329
|
+
type APIClient = ClientProxyObject<typeof API>;
|
|
330
|
+
const api: APIClient = new Connection<typeof API>('ws://localhost:8080/').api;
|
|
331
|
+
|
|
332
|
+
type SomethingType = ReturnType<APIClient['streamSomething']>;
|
|
333
|
+
const something: SomethingType = api.streamSomething();
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
`ClientProxyObject` maps server return types to their client-side equivalents. Stream methods return `PromiseProxy<ProjectedData>`, plain values return `PromiseProxy<T>`, and `ServerProxy<API, R>` methods return a proxy with a `.serverProxy` of type `ClientProxyObject<SubAPI>`.
|
|
337
|
+
|
|
338
|
+
|
|
298
339
|
### Logging
|
|
299
340
|
|
|
300
341
|
Set the `LOWLANDER_LOG_LEVEL` environment variable to a number from 0 to 3:
|
|
@@ -306,10 +347,50 @@ Set the `LOWLANDER_LOG_LEVEL` environment variable to a number from 0 to 3:
|
|
|
306
347
|
|
|
307
348
|
Set `EDINBURGH_LOG_LEVEL` similarly for Edinburgh internals.
|
|
308
349
|
|
|
350
|
+
### Dashboard
|
|
351
|
+
|
|
352
|
+
Lowlander ships with an optional admin/developer dashboard for inspecting
|
|
353
|
+
Edinburgh models, browsing index rows, listing RPC methods, viewing source
|
|
354
|
+
code, and peeking at warpsocket debug state (channels, sockets, workers,
|
|
355
|
+
KV). It's a single self-contained HTML bundle.
|
|
356
|
+
|
|
357
|
+
To enable it:
|
|
358
|
+
|
|
359
|
+
1. Re-export `_dashboard` from your top-level API module:
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
// server/api.ts
|
|
363
|
+
export { _dashboard } from "lowlander/dashboard";
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
2. Serve the bundled HTML by calling `serveDashboard(res)` from a
|
|
367
|
+
`warpsocket` `handleHttpRequest` export:
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
import type { HttpRequest, HttpResponse } from "warpsocket";
|
|
371
|
+
import { serveDashboard } from "lowlander/dashboard";
|
|
372
|
+
|
|
373
|
+
export function handleHttpRequest(req: HttpRequest, res: HttpResponse) {
|
|
374
|
+
if (req.url === '/_dashboard' || req.url.startsWith('/_dashboard?')) {
|
|
375
|
+
return serveDashboard(res);
|
|
376
|
+
}
|
|
377
|
+
// … serve your own static files …
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
3. On first server start (per warpsocket KV namespace), a random password
|
|
382
|
+
is generated and printed to the console. Override with the
|
|
383
|
+
`LOWLANDER_DASHBOARD_PASSWORD` env var.
|
|
384
|
+
|
|
385
|
+
The dashboard prompts for the websocket URL (defaults to the current host)
|
|
386
|
+
and password on first load, then stores them in localStorage.
|
|
387
|
+
|
|
309
388
|
## Server API Reference
|
|
310
389
|
|
|
311
390
|
The following is auto-generated from `server/server.ts`:
|
|
312
391
|
|
|
392
|
+
### [getStreamTypesForModel](getStreamTypesForModel.md) · function
|
|
393
|
+
|
|
313
394
|
### [createStreamType](createStreamType.md) · function
|
|
314
395
|
|
|
315
396
|
Creates a stream type for reactive model streaming to clients with automatic updates.
|
|
@@ -5,7 +5,7 @@ Creates a stream type for reactive model streaming to clients with automatic upd
|
|
|
5
5
|
Specify which fields to include; when they change, updates are pushed to subscribed clients.
|
|
6
6
|
Supports nested linked models and type-safe field selection.
|
|
7
7
|
|
|
8
|
-
**Signature:** `<T, S extends FieldSelection<T>>(Model:
|
|
8
|
+
**Signature:** `<T, S extends FieldSelection<T>>(Model: object & ModelClassRuntime<any, readonly any[], any, any> & (new (initial?: Partial<any>, txn?: Transaction) => any) & (new (...args: any[]) => T), selection: S & ValidateSelection<...>, options?: { ...; }) => { ...; }`
|
|
9
9
|
|
|
10
10
|
**Type Parameters:**
|
|
11
11
|
|