lowlander 0.2.1 → 0.2.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 +251 -6
- package/build/client/client.d.ts +153 -0
- package/build/client/client.js +317 -0
- package/build/client/client.js.map +1 -0
- package/build/examples/helloworld/client/js/admin.d.ts +11 -0
- package/build/examples/helloworld/client/js/admin.js +87 -0
- package/build/examples/helloworld/client/js/admin.js.map +1 -0
- package/build/examples/helloworld/client/js/base.d.ts +4 -0
- package/{examples/helloworld/client/js/base.ts → build/examples/helloworld/client/js/base.js} +13 -25
- package/build/examples/helloworld/client/js/base.js.map +1 -0
- package/build/examples/helloworld/server/api.d.ts +40 -0
- package/build/examples/helloworld/server/api.d.ts.map +1 -0
- package/{examples/helloworld/server/api.ts → build/examples/helloworld/server/api.js} +58 -66
- package/build/examples/helloworld/server/api.js.map +1 -0
- package/build/examples/helloworld/server/main.d.ts +2 -0
- package/build/examples/helloworld/server/main.d.ts.map +1 -0
- package/{examples/helloworld/server/main.ts → build/examples/helloworld/server/main.js} +3 -8
- package/build/examples/helloworld/server/main.js.map +1 -0
- package/build/server/protocol.d.ts +12 -0
- package/build/server/protocol.d.ts.map +1 -0
- package/build/server/protocol.js +19 -0
- package/build/server/protocol.js.map +1 -0
- package/build/server/server.d.ts +191 -0
- package/build/server/server.d.ts.map +1 -0
- package/build/server/server.js +379 -0
- package/build/server/server.js.map +1 -0
- package/build/server/wshandler.d.ts +11 -0
- package/build/server/wshandler.d.ts.map +1 -0
- package/build/server/wshandler.js +126 -0
- package/build/server/wshandler.js.map +1 -0
- package/build/tsconfig.client.tsbuildinfo +1 -0
- package/build/tsconfig.server.tsbuildinfo +1 -0
- package/package.json +14 -8
- package/server/server.ts +1 -0
- package/skill/SKILL.md +605 -0
- package/AGENTS.md +0 -2
- package/ROADMAP.md +0 -13
- package/bun.lock +0 -281
- package/examples/helloworld/client/js/admin.ts +0 -94
- package/examples/helloworld/package.json +0 -8
- package/tests/fake-warpsocket.ts +0 -452
- package/tests/helloworld.test.ts +0 -151
- package/tsconfig.client.json +0 -18
- package/tsconfig.json +0 -24
- package/tsconfig.server.json +0 -17
- package/tsconfig.test.json +0 -13
- /package/{examples → build/examples}/helloworld/client/assets/style.css +0 -0
- /package/{examples → build/examples}/helloworld/client/index.html +0 -0
|
@@ -1,110 +1,107 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var Person_1, MyModel_1;
|
|
1
8
|
import * as E from "edinburgh";
|
|
2
|
-
import { ServerProxy, createStreamType
|
|
9
|
+
import { ServerProxy, createStreamType } from "lowlander/server";
|
|
3
10
|
import * as warpsocket from "warpsocket";
|
|
4
|
-
|
|
5
11
|
export const getDebugState = warpsocket.getDebugState;
|
|
6
|
-
|
|
7
12
|
// Simple RPC function example
|
|
8
|
-
export function add(a
|
|
13
|
+
export function add(a, b) {
|
|
9
14
|
return a + b;
|
|
10
15
|
}
|
|
11
|
-
|
|
12
16
|
// Example of a stateful server-side API that's exposed via ServerProxy
|
|
13
17
|
export class UserAPI {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
userName;
|
|
19
|
+
constructor(userName) {
|
|
20
|
+
this.userName = userName;
|
|
21
|
+
}
|
|
22
|
+
get user() {
|
|
17
23
|
const result = Person.byName.get(this.userName);
|
|
18
|
-
if (!result)
|
|
24
|
+
if (!result)
|
|
25
|
+
throw new Error(`User '${this.userName}' not found`);
|
|
19
26
|
return result;
|
|
20
27
|
}
|
|
21
|
-
|
|
22
28
|
getBio() {
|
|
23
29
|
return `${this.user.name} is ${this.user.age} years old and has ${this.user.friends.length} friend(s).`;
|
|
24
30
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for(const [idx, val] of Object.entries(this.user.friends)) {
|
|
31
|
+
toggleFriend(friendName) {
|
|
32
|
+
for (const [idx, val] of Object.entries(this.user.friends)) {
|
|
28
33
|
if (val.name === friendName) {
|
|
29
34
|
this.user.friends.splice(Number(idx), 1);
|
|
30
35
|
return true;
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
38
|
const friend = Person.byName.get(friendName);
|
|
34
|
-
if (!friend)
|
|
39
|
+
if (!friend)
|
|
40
|
+
return false;
|
|
35
41
|
this.user.friends.push(friend);
|
|
36
42
|
return true;
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
// admin() {
|
|
40
|
-
// if (this.user.name !== 'Frank') {
|
|
41
|
-
// throw new Error('Access denied');
|
|
42
|
-
// }
|
|
43
|
-
// return new ServerProxy(admin);
|
|
44
|
-
// }
|
|
45
44
|
}
|
|
46
|
-
|
|
47
45
|
// Authentication example - returns a ServerProxy with both a value and API object
|
|
48
|
-
export async function authenticate(auth
|
|
46
|
+
export async function authenticate(auth) {
|
|
49
47
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
50
48
|
const user = Person.byName.get(auth);
|
|
51
|
-
if (!user)
|
|
49
|
+
if (!user)
|
|
50
|
+
throw new Error('User not found');
|
|
52
51
|
// Client receives 'secret' as .value and UserAPI methods via .serverProxy
|
|
53
52
|
return new ServerProxy(new UserAPI(auth), 'secret');
|
|
54
53
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
54
|
// Edinburgh model definitions
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
static byName = E.primary(
|
|
55
|
+
let Person = class Person extends E.Model {
|
|
56
|
+
static { Person_1 = this; }
|
|
57
|
+
static byName = E.primary(Person_1, 'name');
|
|
61
58
|
name = E.field(E.string);
|
|
62
59
|
age = E.field(E.number);
|
|
63
|
-
friends = E.field(E.array(E.link(
|
|
60
|
+
friends = E.field(E.array(E.link(Person_1)));
|
|
64
61
|
password = E.field(E.string);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
};
|
|
63
|
+
Person = Person_1 = __decorate([
|
|
64
|
+
E.registerModel
|
|
65
|
+
], Person);
|
|
66
|
+
let MyModel = class MyModel extends E.Model {
|
|
67
|
+
static { MyModel_1 = this; }
|
|
69
68
|
id = E.field(E.identifier);
|
|
70
69
|
name = E.field(E.string);
|
|
71
|
-
next = E.field(E.opt(E.link(
|
|
70
|
+
next = E.field(E.opt(E.link(MyModel_1)));
|
|
72
71
|
owner = E.field(E.link(Person));
|
|
73
72
|
createdAt = E.field(E.dateTime);
|
|
74
|
-
|
|
75
|
-
static
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
static byId = E.primary(MyModel_1, 'id');
|
|
74
|
+
static byName = E.unique(MyModel_1, 'name');
|
|
75
|
+
};
|
|
76
|
+
MyModel = MyModel_1 = __decorate([
|
|
77
|
+
E.registerModel
|
|
78
|
+
], MyModel);
|
|
79
|
+
let ids;
|
|
80
|
+
export async function resetTestData(deleteEverything) {
|
|
81
81
|
if (deleteEverything) {
|
|
82
82
|
await E.deleteEverything();
|
|
83
83
|
}
|
|
84
|
-
|
|
85
84
|
// Initialize some test data. Even if we are already running in a transaction, we need to do this
|
|
86
85
|
// in a new (nested) transaction, as deleteEverything will have done *its* work in separate transactions
|
|
87
86
|
// as well, and we need access to its results.
|
|
88
87
|
await E.transact(() => {
|
|
89
|
-
let p1 = Person.byName.get('Frank') || new Person({name: 'Frank', age: 45, password: 'secret'});
|
|
90
|
-
let p2 = Person.byName.get('Alice') || new Person({name: 'Alice', age: 25, password: 'hidden', friends: [p1]});
|
|
91
|
-
let p3 = Person.byName.get('Bob') || new Person({name: 'Bob', age: 65, password: 'himom', friends: [p1, p2]});
|
|
92
|
-
if (p1.getState() === "created")
|
|
93
|
-
|
|
94
|
-
let
|
|
95
|
-
|
|
88
|
+
let p1 = Person.byName.get('Frank') || new Person({ name: 'Frank', age: 45, password: 'secret' });
|
|
89
|
+
let p2 = Person.byName.get('Alice') || new Person({ name: 'Alice', age: 25, password: 'hidden', friends: [p1] });
|
|
90
|
+
let p3 = Person.byName.get('Bob') || new Person({ name: 'Bob', age: 65, password: 'himom', friends: [p1, p2] });
|
|
91
|
+
if (p1.getState() === "created")
|
|
92
|
+
p1.friends = [p2, p3];
|
|
93
|
+
let m1 = MyModel.byName.get('Test') || new MyModel({ name: 'Test', owner: p1 });
|
|
94
|
+
let m2 = MyModel.byName.get('Another') || new MyModel({ name: 'Another', owner: p2, next: m1 });
|
|
95
|
+
ids = { p1: p1.name, p2: p2.name, m1: m1.id, m2: m2.id };
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
resetTestData(false);
|
|
99
|
-
|
|
100
99
|
await E.transact(() => {
|
|
101
100
|
E.dump();
|
|
102
|
-
for(const p of Person.findAll()) {
|
|
101
|
+
for (const p of Person.findAll()) {
|
|
103
102
|
console.log('Person:', p.name, 'age', p.age, 'friends', p.friends.map(f => f.name).join(','), 'password', p.password);
|
|
104
103
|
}
|
|
105
104
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
105
|
// Create a stream type that specifies which fields to send to clients
|
|
109
106
|
// Note: password is excluded for security, and we include nested linked model fields
|
|
110
107
|
const MyStream = createStreamType(MyModel, {
|
|
@@ -119,29 +116,24 @@ const MyStream = createStreamType(MyModel, {
|
|
|
119
116
|
}
|
|
120
117
|
}
|
|
121
118
|
});
|
|
122
|
-
|
|
123
119
|
// Example of model streaming - returns a reactive proxy that auto-updates on changes
|
|
124
120
|
export function streamModel() {
|
|
125
|
-
const m1 = MyModel.byId.get(ids.m1)
|
|
121
|
+
const m1 = MyModel.byId.get(ids.m1);
|
|
126
122
|
return new MyStream(m1);
|
|
127
123
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const m1 = MyModel.byId.get(ids.m1)!;
|
|
124
|
+
export async function incrOwnerAge(delta) {
|
|
125
|
+
const m1 = MyModel.byId.get(ids.m1);
|
|
131
126
|
const current = m1.owner.age;
|
|
132
127
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
133
128
|
m1.owner.age = current + delta;
|
|
134
129
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const m1 = MyModel.byId.get(ids.m1)!;
|
|
130
|
+
export function setOwnerAge(age) {
|
|
131
|
+
const m1 = MyModel.byId.get(ids.m1);
|
|
138
132
|
m1.owner.age = age;
|
|
139
133
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
134
|
// Example of server-push streaming via Socket callback
|
|
143
135
|
// Client provides a callback; server pushes data by calling socket.send()
|
|
144
|
-
export function streamSomething(socket
|
|
136
|
+
export function streamSomething(socket) {
|
|
145
137
|
let interval = setInterval(() => {
|
|
146
138
|
console.log('Sending ping');
|
|
147
139
|
// socket.send() returns false when client disconnects
|
|
@@ -151,4 +143,4 @@ export function streamSomething(socket: Socket<number>) {
|
|
|
151
143
|
}
|
|
152
144
|
}, 2000);
|
|
153
145
|
}
|
|
154
|
-
|
|
146
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../examples/helloworld/server/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../examples/helloworld/server/main.ts"],"names":[],"mappings":"AA0BA,OAAO,OAAO,CAAC"}
|
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
// This example is Bun-only, as it conveniently transpiles client-files on the fly.
|
|
2
2
|
// For Node.js, you'd have to add a build step for client-files, and serve them as
|
|
3
3
|
// static files (e.g. using express.static).
|
|
4
|
-
|
|
5
4
|
import { fileURLToPath } from 'url';
|
|
6
5
|
import { dirname, resolve } from 'path';
|
|
7
6
|
import * as lowlander from "lowlander/server";
|
|
8
7
|
import index from "../client/index.html";
|
|
9
|
-
|
|
10
8
|
const apiFile = resolve(dirname(fileURLToPath(import.meta.url)), 'api.js');
|
|
11
|
-
|
|
12
9
|
// Start the WebSocket server with the given API handler
|
|
13
|
-
lowlander.start(apiFile, {threads: 1});
|
|
14
|
-
|
|
10
|
+
lowlander.start(apiFile, { threads: 1 });
|
|
15
11
|
// Serve index.html on /
|
|
16
12
|
Bun.serve({
|
|
17
13
|
port: process.env.PORT || 3000,
|
|
18
14
|
routes: {
|
|
19
15
|
'/': index,
|
|
20
|
-
},
|
|
16
|
+
},
|
|
21
17
|
development: true,
|
|
22
18
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
19
|
// We're only doing this import here such that Bun knows to reload when api.ts changes
|
|
26
20
|
// when in --watch mode.
|
|
27
21
|
import './api';
|
|
22
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../examples/helloworld/server/main.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,kFAAkF;AAClF,4CAA4C;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,MAAM,sBAAsB,CAAC;AAEzC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAE3E,wDAAwD;AACxD,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,EAAC,OAAO,EAAE,CAAC,EAAC,CAAC,CAAC;AAEvC,wBAAwB;AACxB,GAAG,CAAC,KAAK,CAAC;IACN,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI;IAC9B,MAAM,EAAE;QACJ,GAAG,EAAE,KAAK;KACb;IACD,WAAW,EAAE,IAAI;CACpB,CAAC,CAAC;AAGH,sFAAsF;AACtF,wBAAwB;AACxB,OAAO,OAAO,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const SERVER_MESSAGES: {
|
|
2
|
+
error: string;
|
|
3
|
+
response: string;
|
|
4
|
+
response_proxy: string;
|
|
5
|
+
response_model: string;
|
|
6
|
+
model_data: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const CLIENT_MESSAGES: {
|
|
9
|
+
call: number;
|
|
10
|
+
cancel: number;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../server/protocol.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe;;;;;;CAM3B,CAAC;AAOF,eAAO,MAAM,eAAe;;;CAG3B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// requestId + callbackIndex + callback arguments
|
|
2
|
+
// or
|
|
3
|
+
// requestId + one of these types:
|
|
4
|
+
export const SERVER_MESSAGES = {
|
|
5
|
+
error: 'e', // followed by errorMessage
|
|
6
|
+
response: 'r', // followed by result + virtualSocketIds
|
|
7
|
+
response_proxy: 'p', // followed by result + virtualSocketIds (like above, but indicate that a ServerProxy has been created for this request)
|
|
8
|
+
response_model: 'm', // followed by virtualSocketIds + dbKey
|
|
9
|
+
model_data: 'd', // followed by dbKey + commitId + delta
|
|
10
|
+
};
|
|
11
|
+
// The virtualSocketIds in a response or response_model is stored by the client and must
|
|
12
|
+
// be provided to 'cancel'.
|
|
13
|
+
// dbKey is a stochastically unique identifier for a subset of a model instance, defined as primaryKeyHash + steamType.id
|
|
14
|
+
// requestId + one of these types:
|
|
15
|
+
export const CLIENT_MESSAGES = {
|
|
16
|
+
call: 1, // followed by proxyId/undefined + methodName + params + ...
|
|
17
|
+
cancel: 2, // followed by cancelRequestId + virtualSocketIds/undefined
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../server/protocol.ts"],"names":[],"mappings":"AAAA,iDAAiD;AAEjD,KAAK;AAEL,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG;IAC3B,KAAK,EAAE,GAAG,EAAE,2BAA2B;IACvC,QAAQ,EAAE,GAAG,EAAE,wCAAwC;IACvD,cAAc,EAAE,GAAG,EAAE,wHAAwH;IAC7I,cAAc,EAAE,GAAG,EAAE,uCAAuC;IAC5D,UAAU,EAAE,GAAG,EAAE,uCAAuC;CAC3D,CAAC;AAEF,wFAAwF;AACxF,2BAA2B;AAC3B,yHAAyH;AAEzH,kCAAkC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG;IAC3B,IAAI,EAAE,CAAC,EAAE,4DAA4D;IACrE,MAAM,EAAE,CAAC,EAAE,2DAA2D;CACzE,CAAC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import * as E from "edinburgh";
|
|
2
|
+
import * as realWarpsocket from 'warpsocket';
|
|
3
|
+
export declare const logLevel: number;
|
|
4
|
+
/** @internal Warpsocket implementation; swapped to FakeWarpSocket in test mode. */
|
|
5
|
+
export declare let warpsocket: typeof realWarpsocket;
|
|
6
|
+
/** @internal Type alias for Edinburgh model classes */
|
|
7
|
+
type ModelClass = typeof E.Model<unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Base class for stream types created by {@link createStreamType}.
|
|
10
|
+
* @typeParam T - The projected model type
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare abstract class StreamTypeBase<T> {
|
|
14
|
+
_instance: E.Model<any> & T;
|
|
15
|
+
/** @internal */
|
|
16
|
+
static fields: {
|
|
17
|
+
[key: string]: true | number;
|
|
18
|
+
};
|
|
19
|
+
/** @internal */
|
|
20
|
+
static id: number;
|
|
21
|
+
/** @internal */
|
|
22
|
+
constructor(_instance: E.Model<any> & T);
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Type-safe selector for specifying which model fields to stream to clients.
|
|
27
|
+
* Use `true` to include a field, or an object to select nested fields in linked models.
|
|
28
|
+
*
|
|
29
|
+
* @typeParam T - The model type
|
|
30
|
+
*/
|
|
31
|
+
type FieldSelection<T> = T extends ReadonlyArray<infer U> ? true | FieldSelection<U> : T extends Array<infer U> ? true | FieldSelection<U> : T extends object ? true | {
|
|
32
|
+
[K in keyof T]?: FieldSelection<T[K]>;
|
|
33
|
+
} : true;
|
|
34
|
+
/**
|
|
35
|
+
* Validates field selection compatibility at compile time.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
type ValidateSelection<T, S> = T extends ReadonlyArray<infer U> ? S extends true ? true : ValidateSelection<U, S> : T extends Array<infer U> ? S extends true ? true : ValidateSelection<U, S> : T extends object ? S extends true ? true : S extends object ? {
|
|
39
|
+
[K in keyof S]-?: K extends keyof T ? ValidateSelection<T[K], S[K]> : never;
|
|
40
|
+
} : never : S extends true ? true : never;
|
|
41
|
+
/**
|
|
42
|
+
* Computes the resulting type after applying a field selection.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
type Project<T, S> = S extends true ? T : T extends ReadonlyArray<infer U> ? ReadonlyArray<Project<U, S>> : T extends Array<infer U> ? Array<Project<U, S>> : T extends object ? {
|
|
46
|
+
[K in Extract<keyof S, keyof T>]: Project<T[K], S[K & keyof T]>;
|
|
47
|
+
} : T;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a stream type for reactive model streaming to clients with automatic updates.
|
|
50
|
+
*
|
|
51
|
+
* Specify which fields to include; when they change, updates are pushed to subscribed clients.
|
|
52
|
+
* Supports nested linked models and type-safe field selection.
|
|
53
|
+
*
|
|
54
|
+
* @typeParam T - The model type
|
|
55
|
+
* @typeParam S - The field selection
|
|
56
|
+
*
|
|
57
|
+
* @param Model - The Edinburgh model class
|
|
58
|
+
* @param selection - Field selection: `true` for simple fields, nested object for linked models
|
|
59
|
+
* @returns Stream type class to instantiate in API functions
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* @registerModel
|
|
64
|
+
* class Person extends Model {
|
|
65
|
+
* name = field(string);
|
|
66
|
+
* age = field(number);
|
|
67
|
+
* password = field(string);
|
|
68
|
+
* friends = field(array(link(Person)));
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* // Exclude password, include friends' names
|
|
72
|
+
* const PersonStream = createStreamType(Person, {
|
|
73
|
+
* name: true,
|
|
74
|
+
* age: true,
|
|
75
|
+
* friends: { name: true }
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* export function streamPerson() {
|
|
79
|
+
* const person = Person.byName.get('Alice')!;
|
|
80
|
+
* return new PersonStream(person);
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function createStreamType<T, S extends FieldSelection<T>>(Model: ModelClass & (new (...args: any[]) => T), selection: S & ValidateSelection<T, S>): {
|
|
85
|
+
new (_instance: E.Model<any> & Project<T, S>): {
|
|
86
|
+
_instance: E.Model<any> & Project<T, S>;
|
|
87
|
+
toString(): string;
|
|
88
|
+
};
|
|
89
|
+
fields: Record<string, number | true>;
|
|
90
|
+
id: number;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Sends (updated) data for `model` to `target`.
|
|
94
|
+
* `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets.
|
|
95
|
+
*/
|
|
96
|
+
export declare function sendModel(target: Uint8Array | number | number[], model: E.Model<any>, commitId: number, StreamType: typeof StreamTypeBase<any>, changed?: E.Change): void;
|
|
97
|
+
/**
|
|
98
|
+
* Subscribes `target` to this model, and sends initial data.
|
|
99
|
+
* `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets.
|
|
100
|
+
*/
|
|
101
|
+
export declare function pushModel(target: number | Uint8Array | number[], model: E.Model<any>, commitId: number, SubStreamType: typeof StreamTypeBase<any>, delta: number): void;
|
|
102
|
+
/**
|
|
103
|
+
* Wraps a server-side API object to create a stateful, type-safe proxy accessible from clients.
|
|
104
|
+
* Use for authentication, sessions, or any stateful context that persists across RPC calls.
|
|
105
|
+
*
|
|
106
|
+
* @typeParam API - The server-side API object type
|
|
107
|
+
* @typeParam RETURN - The value type returned to the client
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* export class UserAPI {
|
|
112
|
+
* constructor(public user: User) {}
|
|
113
|
+
* getSecret() { return this.user.secret; }
|
|
114
|
+
* }
|
|
115
|
+
*
|
|
116
|
+
* export async function authenticate(token: string) {
|
|
117
|
+
* const user = await validateToken(token);
|
|
118
|
+
* return new ServerProxy(new UserAPI(user), user.name);
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* // Client: auth.value is user name, auth.serverProxy.getSecret() calls UserAPI method
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export declare class ServerProxy<API extends object, RETURN> {
|
|
125
|
+
api: API;
|
|
126
|
+
value?: RETURN | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* @param api - Server-side API object exposed to the client
|
|
129
|
+
* @param value - Value returned immediately to the client
|
|
130
|
+
*/
|
|
131
|
+
constructor(api: API, value?: RETURN | undefined);
|
|
132
|
+
toString(): string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Server-side socket for pushing data to a client. Server functions with `Socket<T>` parameters
|
|
136
|
+
* receive client callbacks on the client side.
|
|
137
|
+
*
|
|
138
|
+
* @typeParam T - Data type sent through the socket
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* // Server
|
|
143
|
+
* export function streamNumbers(socket: Socket<number>) {
|
|
144
|
+
* setInterval(() => {
|
|
145
|
+
* if (!socket.send(Math.random())) clearInterval(interval);
|
|
146
|
+
* }, 1000);
|
|
147
|
+
* }
|
|
148
|
+
*
|
|
149
|
+
* // Client
|
|
150
|
+
* api.streamNumbers(num => console.log(num));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare class Socket<T> {
|
|
154
|
+
virtualSocketId: number;
|
|
155
|
+
/** @internal */
|
|
156
|
+
constructor(virtualSocketId: number);
|
|
157
|
+
/**
|
|
158
|
+
* Sends data to the client.
|
|
159
|
+
* @param data - Data to send (automatically serialized)
|
|
160
|
+
* @returns `true` if sent, `false` if socket is closed
|
|
161
|
+
*/
|
|
162
|
+
send(data: T): number;
|
|
163
|
+
/** @internal */
|
|
164
|
+
subscribe(channel: Uint8Array, delta?: number): void;
|
|
165
|
+
toString(): string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Starts the Lowlander WebSocket server.
|
|
169
|
+
*
|
|
170
|
+
* @param mainApiFile - Absolute path to the compiled API file exporting server functions
|
|
171
|
+
* @param opts.bind - Address and port (default: '0.0.0.0:8080')
|
|
172
|
+
* @param opts.threads - Worker thread count (default: auto)
|
|
173
|
+
* @param opts.injectWarpSocket - For testing: inject a custom WarpSocket implementation (e.g. FakeWarpSocket)
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* import { start } from 'lowlander/server';
|
|
178
|
+
* import { fileURLToPath } from 'url';
|
|
179
|
+
* import { resolve, dirname } from 'path';
|
|
180
|
+
*
|
|
181
|
+
* const API_FILE = resolve(dirname(fileURLToPath(import.meta.url)), 'api.js');
|
|
182
|
+
* start(API_FILE, { bind: '0.0.0.0:8080' });
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export declare function start(mainApiFile: string, opts?: {
|
|
186
|
+
bind?: string;
|
|
187
|
+
threads?: number;
|
|
188
|
+
injectWarpSocket?: typeof realWarpsocket;
|
|
189
|
+
}): Promise<void>;
|
|
190
|
+
export {};
|
|
191
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../server/server.ts"],"names":[],"mappings":"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"}
|