lowlander 0.2.1 → 0.2.3

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.
Files changed (61) hide show
  1. package/README.md +288 -40
  2. package/build/client/client.d.ts +153 -0
  3. package/build/client/client.js +320 -0
  4. package/build/client/client.js.map +1 -0
  5. package/build/examples/helloworld/client/js/admin.d.ts +11 -0
  6. package/build/examples/helloworld/client/js/admin.js +87 -0
  7. package/build/examples/helloworld/client/js/admin.js.map +1 -0
  8. package/build/examples/helloworld/client/js/base.d.ts +4 -0
  9. package/{examples/helloworld/client/js/base.ts → build/examples/helloworld/client/js/base.js} +13 -25
  10. package/build/examples/helloworld/client/js/base.js.map +1 -0
  11. package/build/examples/helloworld/server/api.d.ts +44 -0
  12. package/build/examples/helloworld/server/api.d.ts.map +1 -0
  13. package/build/examples/helloworld/server/api.js +163 -0
  14. package/build/examples/helloworld/server/api.js.map +1 -0
  15. package/build/examples/helloworld/server/main.d.ts +2 -0
  16. package/build/examples/helloworld/server/main.d.ts.map +1 -0
  17. package/{examples/helloworld/server/main.ts → build/examples/helloworld/server/main.js} +3 -8
  18. package/build/examples/helloworld/server/main.js.map +1 -0
  19. package/build/server/protocol.d.ts +12 -0
  20. package/build/server/protocol.d.ts.map +1 -0
  21. package/build/server/protocol.js +19 -0
  22. package/build/server/protocol.js.map +1 -0
  23. package/build/server/server.d.ts +191 -0
  24. package/build/server/server.d.ts.map +1 -0
  25. package/build/server/server.js +379 -0
  26. package/build/server/server.js.map +1 -0
  27. package/build/server/wshandler.d.ts +11 -0
  28. package/build/server/wshandler.d.ts.map +1 -0
  29. package/build/server/wshandler.js +126 -0
  30. package/build/server/wshandler.js.map +1 -0
  31. package/build/tsconfig.client.tsbuildinfo +1 -0
  32. package/build/tsconfig.server.tsbuildinfo +1 -0
  33. package/client/client.ts +9 -5
  34. package/package.json +16 -9
  35. package/server/server.ts +2 -1
  36. package/skill/Connection.md +35 -0
  37. package/skill/Connection_pruneCommitIds.md +8 -0
  38. package/skill/SKILL.md +430 -0
  39. package/skill/ServerProxy.md +30 -0
  40. package/skill/Socket.md +22 -0
  41. package/skill/Socket_send.md +11 -0
  42. package/skill/Socket_subscribe.md +8 -0
  43. package/skill/createStreamType.md +44 -0
  44. package/skill/pushModel.md +14 -0
  45. package/skill/sendModel.md +14 -0
  46. package/skill/start.md +21 -0
  47. package/skill/warpsocket.md +3 -0
  48. package/AGENTS.md +0 -2
  49. package/ROADMAP.md +0 -13
  50. package/bun.lock +0 -281
  51. package/examples/helloworld/client/js/admin.ts +0 -94
  52. package/examples/helloworld/package.json +0 -8
  53. package/examples/helloworld/server/api.ts +0 -154
  54. package/tests/fake-warpsocket.ts +0 -452
  55. package/tests/helloworld.test.ts +0 -151
  56. package/tsconfig.client.json +0 -18
  57. package/tsconfig.json +0 -24
  58. package/tsconfig.server.json +0 -17
  59. package/tsconfig.test.json +0 -13
  60. /package/{examples → build/examples}/helloworld/client/assets/style.css +0 -0
  61. /package/{examples → build/examples}/helloworld/client/index.html +0 -0
@@ -0,0 +1,379 @@
1
+ import * as E from "edinburgh";
2
+ import DataPack from "edinburgh/datapack";
3
+ import * as realWarpsocket from 'warpsocket';
4
+ // Get log level from environment variable
5
+ // 0: no logging (default)
6
+ // 1: connections & lifecycle (connect/disconnect/reconnect, worker startup)
7
+ // 2: RPC calls & responses (method calls, incoming responses, errors)
8
+ // 3: model streaming & internals (onSave, model changes, stream processing)
9
+ export const logLevel = parseInt(process.env.LOWLANDER_LOG_LEVEL || "0") || 0;
10
+ /** @internal Warpsocket implementation; swapped to FakeWarpSocket in test mode. */
11
+ export let warpsocket = realWarpsocket;
12
+ import { fileURLToPath } from 'url';
13
+ import { dirname, resolve } from 'path';
14
+ const WSHANDLER_FILE = resolve(dirname(fileURLToPath(import.meta.url)), 'wshandler.js');
15
+ /** @internal WarpSocket channel id prefix for model streams */
16
+ const CHANNEL_TYPE_MODEL = 1;
17
+ /** @internal Registry mapping model classes to their stream types */
18
+ const streamTypesPerModel = new Map();
19
+ /**
20
+ * Base class for stream types created by {@link createStreamType}.
21
+ * @typeParam T - The projected model type
22
+ * @internal
23
+ */
24
+ export class StreamTypeBase {
25
+ _instance;
26
+ /** @internal */
27
+ static fields;
28
+ /** @internal */
29
+ static id;
30
+ /** @internal */
31
+ constructor(_instance) {
32
+ this._instance = _instance;
33
+ }
34
+ toString() {
35
+ let streamTypes = streamTypesPerModel.get(this._instance.constructor) || [];
36
+ return `{Stream model=${this._instance.toString()} type=${streamTypes.indexOf(this.constructor)}}`;
37
+ }
38
+ }
39
+ /**
40
+ * Returns a stable numeric ID for a key tuple, allocating a new one if needed.
41
+ * Safe for multiple WarpSocket threads.
42
+ * @internal
43
+ */
44
+ function getIdForData(namespace, ...data) {
45
+ const dataKeyPack = new DataPack().write(namespace);
46
+ for (const d of data)
47
+ dataKeyPack.write(d);
48
+ const dataKey = dataKeyPack.toUint8Array();
49
+ const idPack = warpsocket.getKey(dataKey);
50
+ if (idPack) {
51
+ return new DataPack(idPack).readNumber();
52
+ }
53
+ const countKey = new DataPack().write(namespace).toUint8Array();
54
+ while (true) {
55
+ // Insert a new stream type
56
+ const countPack = warpsocket.getKey(countKey);
57
+ const newCount = countPack ? new DataPack(countPack).readNumber() + 1 : 1;
58
+ const newCountPack = new DataPack().write(newCount).toUint8Array();
59
+ if (warpsocket.setKeyIf(countKey, newCountPack, countPack)) {
60
+ if (warpsocket.setKeyIf(dataKey, newCountPack, undefined)) {
61
+ return newCount; // Success
62
+ }
63
+ }
64
+ // Raced, try again
65
+ }
66
+ }
67
+ /**
68
+ * Creates a stream type for reactive model streaming to clients with automatic updates.
69
+ *
70
+ * Specify which fields to include; when they change, updates are pushed to subscribed clients.
71
+ * Supports nested linked models and type-safe field selection.
72
+ *
73
+ * @typeParam T - The model type
74
+ * @typeParam S - The field selection
75
+ *
76
+ * @param Model - The Edinburgh model class
77
+ * @param selection - Field selection: `true` for simple fields, nested object for linked models
78
+ * @returns Stream type class to instantiate in API functions
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * ⁣@E.registerModel
83
+ * class Person extends Model {
84
+ * name = field(string);
85
+ * age = field(number);
86
+ * password = field(string);
87
+ * friends = field(array(link(Person)));
88
+ * }
89
+ *
90
+ * // Exclude password, include friends' names
91
+ * const PersonStream = createStreamType(Person, {
92
+ * name: true,
93
+ * age: true,
94
+ * friends: { name: true }
95
+ * });
96
+ *
97
+ * export function streamPerson() {
98
+ * const person = Person.byName.get('Alice')!;
99
+ * return new PersonStream(person);
100
+ * }
101
+ * ```
102
+ */
103
+ export function createStreamType(Model, selection) {
104
+ let streamTypes = streamTypesPerModel.get(Model);
105
+ if (!streamTypes)
106
+ streamTypesPerModel.set(Model, streamTypes = []);
107
+ const streamTypeId = getIdForData("streamType", Model.tableName, selection);
108
+ const fields = {};
109
+ for (const prop of Array.from(Object.keys(selection)).sort()) {
110
+ if (!Model.fields.hasOwnProperty(prop)) {
111
+ throw new Error(`Property ${prop} does not exist in model ${Model.name}`);
112
+ }
113
+ const LinkedModel = Model.fields[prop].type.getLinkedModel();
114
+ if (selection[prop] === true) {
115
+ if (LinkedModel)
116
+ throw new Error(`Property ${prop} is a link; must specify sub-selection`);
117
+ fields[prop] = true; // Include field without tracking links
118
+ }
119
+ else {
120
+ if (!LinkedModel)
121
+ throw new Error(`Property ${prop} is not a link; cannot specify sub-selection`);
122
+ const SubStreamType = createStreamType(LinkedModel, selection[prop]);
123
+ fields[prop] = SubStreamType.id;
124
+ }
125
+ }
126
+ class StreamType extends StreamTypeBase {
127
+ static fields = fields;
128
+ static id = streamTypeId;
129
+ }
130
+ streamTypes.push(StreamType);
131
+ return StreamType;
132
+ }
133
+ /** Writes `value` to `pack`, replacing Model instances with XOR'd hash refs. */
134
+ function writeModelField(pack, value, streamTypeId) {
135
+ if (typeof value !== 'object' || value == null) {
136
+ pack.write(value);
137
+ }
138
+ else if (value instanceof E.Model) {
139
+ pack.writeCustom('model', value.getPrimaryKeyHash() + streamTypeId);
140
+ }
141
+ else if (Array.isArray(value)) {
142
+ pack.writeCollection('array', () => {
143
+ for (const item of value)
144
+ writeModelField(pack, item, streamTypeId);
145
+ });
146
+ }
147
+ else {
148
+ pack.writeCollection('object', () => {
149
+ for (const key of Object.keys(value)) {
150
+ pack.write(key);
151
+ writeModelField(pack, value[key], streamTypeId);
152
+ }
153
+ });
154
+ }
155
+ }
156
+ /** Tracks link deltas for subscription management. */
157
+ function updateLinkDeltas(value, linkDeltas, streamTypeId, delta) {
158
+ if (typeof value !== 'object' || value == null)
159
+ return;
160
+ if (Array.isArray(value)) {
161
+ for (const item of value)
162
+ updateLinkDeltas(item, linkDeltas, streamTypeId, delta);
163
+ }
164
+ else if (value instanceof E.Model) {
165
+ let map = linkDeltas.get(value);
166
+ if (!map)
167
+ linkDeltas.set(value, map = new Map());
168
+ const v = (map.get(streamTypeId) || 0) + delta;
169
+ if (v)
170
+ map.set(streamTypeId, v);
171
+ else
172
+ map.delete(streamTypeId);
173
+ }
174
+ else {
175
+ for (const key of Object.keys(value)) {
176
+ updateLinkDeltas(value[key], linkDeltas, streamTypeId, delta);
177
+ }
178
+ }
179
+ }
180
+ E.setOnSaveCallback((commitId, items) => {
181
+ if (logLevel >= 3)
182
+ console.log('[lowlander] onSave', commitId);
183
+ for (const [model, changed] of items.entries()) {
184
+ const streamTypes = streamTypesPerModel.get(model.constructor);
185
+ if (logLevel >= 3)
186
+ console.log('[lowlander] Model changed:', model, changed, `streams=${streamTypes?.length}`);
187
+ if (!streamTypes)
188
+ continue;
189
+ for (const StreamType of streamTypes) {
190
+ const channelName = DataPack.createUint8Array(CHANNEL_TYPE_MODEL, model.getPrimaryKeyHash() + StreamType.id);
191
+ if (logLevel >= 3)
192
+ console.log('[lowlander] Processing stream type', StreamType.name, 'channel', channelName);
193
+ // Don't bother constructing a change message if nobody is listening
194
+ if (!warpsocket.hasSubscriptions(channelName))
195
+ continue;
196
+ // When an instance is first created, we can't possibly have any references to it yet, so we don't need to emit it.
197
+ if (changed !== 'created') {
198
+ sendModel(channelName, model, commitId, StreamType, changed);
199
+ }
200
+ }
201
+ }
202
+ });
203
+ /**
204
+ * Sends (updated) data for `model` to `target`.
205
+ * `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets.
206
+ */
207
+ export function sendModel(target, model, commitId, StreamType, changed) {
208
+ let pack = new DataPack();
209
+ pack.write(model.getPrimaryKeyHash() + StreamType.id);
210
+ pack.write(commitId);
211
+ let mustSend = false;
212
+ if (changed === 'deleted') {
213
+ pack.write(null);
214
+ mustSend = true;
215
+ }
216
+ else { // changed is an object or 'created'
217
+ const linkDeltas = new Map();
218
+ pack.writeCollection('object', (addRecord) => {
219
+ for (const fieldName in StreamType.fields) {
220
+ if (typeof changed === 'object' && !changed.hasOwnProperty(fieldName))
221
+ continue;
222
+ let streamIndex = StreamType.fields[fieldName];
223
+ const fieldValue = model[fieldName];
224
+ mustSend = true;
225
+ if (typeof streamIndex === 'number') {
226
+ pack.write(fieldName);
227
+ writeModelField(pack, fieldValue, streamIndex);
228
+ updateLinkDeltas(fieldValue, linkDeltas, streamIndex, 1);
229
+ if (typeof changed === 'object')
230
+ updateLinkDeltas(changed[fieldName], linkDeltas, streamIndex, -1);
231
+ }
232
+ else {
233
+ addRecord(fieldName, fieldValue);
234
+ }
235
+ }
236
+ });
237
+ for (const linkedModel of linkDeltas.keys()) {
238
+ let streamIndexMap = linkDeltas.get(linkedModel);
239
+ const subStreamTypes = streamTypesPerModel.get(linkedModel.constructor);
240
+ for (const subStreamType of subStreamTypes) {
241
+ const delta = streamIndexMap.get(subStreamType.id);
242
+ if (delta) { // Only in case delta is set and non-zero
243
+ pushModel(target, linkedModel, commitId, subStreamType, delta);
244
+ }
245
+ }
246
+ }
247
+ }
248
+ // else: Do nothing in case of changed=="created", as there can't be any subscribers yet at this time.
249
+ // If at least one field was updated, send the packet
250
+ if (mustSend) {
251
+ warpsocket.send(target, pack.toUint8Array(false));
252
+ }
253
+ }
254
+ /**
255
+ * Subscribes `target` to this model, and sends initial data.
256
+ * `target` is a virtual socket with a requestId+'d' user prefix, or a channel that subscribes such virtual sockets.
257
+ */
258
+ export function pushModel(target, model, commitId, SubStreamType, delta) {
259
+ const subChannel = DataPack.createUint8Array(CHANNEL_TYPE_MODEL, model.getPrimaryKeyHash() + SubStreamType.id);
260
+ let changedSocketIds = warpsocket.subscribe(target, subChannel, delta);
261
+ if (changedSocketIds.length > 0) {
262
+ sendModel(changedSocketIds, model, commitId, SubStreamType, delta > 0 ? 'created' : 'deleted');
263
+ }
264
+ }
265
+ /**
266
+ * Wraps a server-side API object to create a stateful, type-safe proxy accessible from clients.
267
+ * Use for authentication, sessions, or any stateful context that persists across RPC calls.
268
+ *
269
+ * @typeParam API - The server-side API object type
270
+ * @typeParam RETURN - The value type returned to the client
271
+ *
272
+ * @example
273
+ * ```ts
274
+ * export class UserAPI {
275
+ * constructor(public user: User) {}
276
+ * getSecret() { return this.user.secret; }
277
+ * }
278
+ *
279
+ * export async function authenticate(token: string) {
280
+ * const user = await validateToken(token);
281
+ * return new ServerProxy(new UserAPI(user), user.name);
282
+ * }
283
+ *
284
+ * // Client: auth.value is user name, auth.serverProxy.getSecret() calls UserAPI method
285
+ * ```
286
+ */
287
+ export class ServerProxy {
288
+ api;
289
+ value;
290
+ /**
291
+ * @param api - Server-side API object exposed to the client
292
+ * @param value - Value returned immediately to the client
293
+ */
294
+ constructor(api, value) {
295
+ this.api = api;
296
+ this.value = value;
297
+ }
298
+ toString() {
299
+ return `{ServerProxy proxy=${this.api.constructor?.name} value=${this.value}}`;
300
+ }
301
+ }
302
+ /**
303
+ * Server-side socket for pushing data to a client. Server functions with `Socket<T>` parameters
304
+ * receive client callbacks on the client side.
305
+ *
306
+ * @typeParam T - Data type sent through the socket
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * // Server
311
+ * export function streamNumbers(socket: Socket<number>) {
312
+ * setInterval(() => {
313
+ * if (!socket.send(Math.random())) clearInterval(interval);
314
+ * }, 1000);
315
+ * }
316
+ *
317
+ * // Client
318
+ * api.streamNumbers(num => console.log(num));
319
+ * ```
320
+ */
321
+ export class Socket {
322
+ virtualSocketId;
323
+ /** @internal */
324
+ constructor(virtualSocketId) {
325
+ this.virtualSocketId = virtualSocketId;
326
+ }
327
+ /**
328
+ * Sends data to the client.
329
+ * @param data - Data to send (automatically serialized)
330
+ * @returns `true` if sent, `false` if socket is closed
331
+ */
332
+ send(data) {
333
+ const buffer = data instanceof Uint8Array ? data : new DataPack().write(data).toUint8Array();
334
+ return warpsocket.send(this.virtualSocketId, buffer);
335
+ }
336
+ /** @internal */
337
+ subscribe(channel, delta = 1) {
338
+ if (!(channel instanceof Uint8Array)) {
339
+ channel = new DataPack().write(channel).toUint8Array();
340
+ }
341
+ warpsocket.subscribe(this.virtualSocketId, channel, delta);
342
+ }
343
+ toString() {
344
+ return `{Socket id=${this.virtualSocketId}}`;
345
+ }
346
+ [Symbol.for('nodejs.util.inspect.custom')]() {
347
+ return this.toString();
348
+ }
349
+ }
350
+ /**
351
+ * Starts the Lowlander WebSocket server.
352
+ *
353
+ * @param mainApiFile - Absolute path to the compiled API file exporting server functions
354
+ * @param opts.bind - Address and port (default: '0.0.0.0:8080')
355
+ * @param opts.threads - Worker thread count (default: auto)
356
+ * @param opts.injectWarpSocket - For testing: inject a custom WarpSocket implementation (e.g. FakeWarpSocket)
357
+ *
358
+ * @example
359
+ * ```ts
360
+ * import { start } from 'lowlander/server';
361
+ * import { fileURLToPath } from 'url';
362
+ * import { resolve, dirname } from 'path';
363
+ *
364
+ * const API_FILE = resolve(dirname(fileURLToPath(import.meta.url)), 'api.js');
365
+ * start(API_FILE, { bind: '0.0.0.0:8080' });
366
+ * ```
367
+ */
368
+ export async function start(mainApiFile, opts = {}) {
369
+ if (opts.injectWarpSocket) {
370
+ warpsocket = opts.injectWarpSocket;
371
+ }
372
+ await warpsocket.start({
373
+ bind: opts.bind || '0.0.0.0:8080',
374
+ threads: opts.threads,
375
+ workerPath: WSHANDLER_FILE,
376
+ workerArg: mainApiFile,
377
+ });
378
+ }
379
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../server/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare const socketProxies: Map<number, Map<number, any>>;
2
+ export interface Request {
3
+ socketId: number;
4
+ requestId: number;
5
+ token: Uint8Array;
6
+ }
7
+ export declare function handleOpen(socketId: number, ip: string): void;
8
+ export declare function handleStart(apiFile: any): Promise<void>;
9
+ export declare function handleBinaryMessage(message: Uint8Array, socketId: number): Promise<void>;
10
+ export declare function handleClose(socketId: number): void;
11
+ //# sourceMappingURL=wshandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wshandler.d.ts","sourceRoot":"","sources":["../../server/wshandler.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,aAAa,+BAAsC,CAAC;AAEjE,MAAM,WAAW,OAAO;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,UAAU,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAEtD;AAWD,wBAAsB,WAAW,CAAC,OAAO,EAAE,GAAG,iBAG7C;AAGD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAkG9E;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,QAG3C"}
@@ -0,0 +1,126 @@
1
+ import DataPack from 'edinburgh/datapack';
2
+ import { warpsocket, Socket, StreamTypeBase, pushModel, ServerProxy, logLevel } from './server.js';
3
+ import { SERVER_MESSAGES, CLIENT_MESSAGES } from './protocol.js';
4
+ import * as E from 'edinburgh';
5
+ let mainApi;
6
+ export const socketProxies = new Map(); // {socketId: {proxyId: proxyObject}}
7
+ export function handleOpen(socketId, ip) {
8
+ if (logLevel >= 1)
9
+ console.log('[lowlander] Client connected', socketId, ip);
10
+ }
11
+ function send(socketIdOrChannel, ...data) {
12
+ warpsocket.send(socketIdOrChannel, DataPack.createUint8Array(...data));
13
+ }
14
+ function sendError(socketId, requestId, message) {
15
+ console.warn('Sending error', message);
16
+ send(socketId, requestId, SERVER_MESSAGES.error, message);
17
+ }
18
+ export async function handleStart(apiFile) {
19
+ if (logLevel >= 1)
20
+ console.log('[lowlander] Worker started, loading', apiFile);
21
+ mainApi = await import(apiFile);
22
+ }
23
+ export async function handleBinaryMessage(message, socketId) {
24
+ const pack = new DataPack(message);
25
+ const requestId = pack.readPositiveInt();
26
+ const type = pack.readNumber();
27
+ if (type === CLIENT_MESSAGES.cancel) {
28
+ // Delete server proxy object, if any
29
+ const cancelRequestId = pack.readPositiveInt();
30
+ const proxies = socketProxies.get(socketId);
31
+ if (proxies)
32
+ proxies.delete(cancelRequestId);
33
+ // Delete any virtual sockets created for this request
34
+ for (const virtualSocketId of pack.read() || []) {
35
+ // The second argument makes sure we're not deleting virtual
36
+ // sockets created by other requests
37
+ warpsocket.deleteVirtualSocket(virtualSocketId, socketId);
38
+ }
39
+ }
40
+ else if (type === CLIENT_MESSAGES.call) {
41
+ const proxyId = pack.read();
42
+ let api;
43
+ if (typeof proxyId === 'number') {
44
+ const proxies = socketProxies.get(socketId);
45
+ api = proxies?.get(proxyId);
46
+ if (!api) {
47
+ return sendError(socketId, requestId, `Proxy ${proxyId} not found`);
48
+ }
49
+ }
50
+ else if (proxyId === undefined) {
51
+ if (!mainApi) {
52
+ return sendError(socketId, requestId, 'Server not ready');
53
+ }
54
+ api = mainApi;
55
+ }
56
+ else {
57
+ return sendError(socketId, requestId, 'Invalid proxyId');
58
+ }
59
+ // Obtain function reference
60
+ const methodName = pack.readString();
61
+ let func = api[methodName];
62
+ if (typeof func !== 'function' || methodName.startsWith('_')) {
63
+ return sendError(socketId, requestId, `Method not found: ${methodName}`);
64
+ }
65
+ // Parse args
66
+ const virtualSocketIds = [];
67
+ const params = pack.read({
68
+ cb: function (callbackIndex) {
69
+ const virtualSocketId = warpsocket.createVirtualSocket(socketId, DataPack.createUint8Array(requestId, callbackIndex));
70
+ virtualSocketIds.push(virtualSocketId);
71
+ return new Socket(virtualSocketId);
72
+ },
73
+ });
74
+ if (!Array.isArray(params)) {
75
+ return sendError(socketId, requestId, `Params must be an array`);
76
+ }
77
+ try {
78
+ let pendingSend;
79
+ await E.transact(async () => {
80
+ let response = await func.apply(api, params);
81
+ if (logLevel >= 2)
82
+ console.log('[lowlander] Called', methodName, 'with', params, '->', typeof response === 'object' && response ? response.toString() : JSON.stringify(response));
83
+ // Result processing/sending should be within the transaction, as it may involve (lazy) loading models
84
+ if (response instanceof ServerProxy) {
85
+ let proxies = socketProxies.get(socketId);
86
+ if (!proxies)
87
+ socketProxies.set(socketId, proxies = new Map());
88
+ if (logLevel >= 3)
89
+ console.log('[lowlander] Setting proxy id', requestId, 'for socket', socketId);
90
+ proxies.set(requestId, response.api);
91
+ pendingSend = () => send(socketId, requestId, SERVER_MESSAGES.response_proxy, response.value, virtualSocketIds);
92
+ }
93
+ else if (response instanceof StreamTypeBase) {
94
+ const StreamType = response.constructor;
95
+ const instance = response._instance;
96
+ // Create a virtual socket for the model updates, prefixed by requestId + 'd'
97
+ const virtualSocketId = warpsocket.createVirtualSocket(socketId, DataPack.createUint8Array(requestId, SERVER_MESSAGES.model_data));
98
+ virtualSocketIds.push(virtualSocketId);
99
+ // Push the model (and any linked models) to the client
100
+ pushModel(virtualSocketId, instance, 0, StreamType, 1);
101
+ // Then respond, indicating which row should be top level
102
+ pendingSend = () => send(socketId, requestId, SERVER_MESSAGES.response_model, virtualSocketIds, instance.getPrimaryKeyHash() + StreamType.id);
103
+ }
104
+ else {
105
+ // A regular result
106
+ pendingSend = () => send(socketId, requestId, SERVER_MESSAGES.response, response, virtualSocketIds);
107
+ }
108
+ });
109
+ // Send response after transaction has committed
110
+ pendingSend();
111
+ }
112
+ catch (error) {
113
+ console.error('RPC error', error);
114
+ sendError(socketId, requestId, error.message || 'Internal error');
115
+ }
116
+ }
117
+ else {
118
+ sendError(socketId, requestId, `Unknown message type: ${type}`);
119
+ }
120
+ }
121
+ export function handleClose(socketId) {
122
+ if (logLevel >= 1)
123
+ console.log('[lowlander] Client disconnected', socketId);
124
+ socketProxies.delete(socketId);
125
+ }
126
+ //# sourceMappingURL=wshandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wshandler.js","sourceRoot":"","sources":["../../server/wshandler.ts"],"names":[],"mappings":"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"}