dewdrop-sdk 0.3.1 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dewdrop-sdk",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Build a three.js game for Dewdrop: the Vite plugin, model calls and multiplayer.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/serve.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // The dev server's backend host, its stand-in for Dewdrop. A thread runs
2
2
  // the project's backend.js for each room the tabs join, from the room's
3
- // first tab's join to its last tab's leave, the tabs numbered from one per
4
- // room; each tab's frame of sends reaches its room's thread over the port
3
+ // first tab's join until five minutes after its last tab's leave, as on
4
+ // Dewdrop, so a tab that comes back in that time rejoins it; the tabs are
5
+ // numbered from one per room, never twice while its thread runs; each
6
+ // tab's frame of sends reaches its room's thread over the port
5
7
  // with the tab's number, and each of the thread's sends reaches the tab it
6
8
  // names, or every tab of the room, over the socket. An edit to the backend
7
9
  // restarts every room and reloads the tabs, which join afresh. A backend
@@ -14,6 +16,10 @@ import { dirname, resolve } from 'node:path';
14
16
  import { Worker } from 'node:worker_threads';
15
17
  import { label } from './net.js';
16
18
 
19
+ // How long a room's backend runs on after its last tab's leave, as on
20
+ // Dewdrop.
21
+ export const EMPTY_ROOM_MS = 5 * 60 * 1000;
22
+
17
23
  // The files an edit to which restarts the backend: the entry and what it
18
24
  // reaches through static relative imports.
19
25
  export function backendFiles(entry) {
@@ -41,14 +47,17 @@ export function createBackendHost({ entry, ws, watcher, origin = () => '', log =
41
47
  const rooms = new Map();
42
48
  const tabs = new Map();
43
49
 
44
- // One room's backend: its thread from the room's first tab's join to
45
- // its last tab's leave, its tabs by number from one.
50
+ // One room's backend: its thread from the room's first tab's join until
51
+ // EMPTY_ROOM_MS after its last tab's leave with none joining since, its
52
+ // tabs by number from one.
46
53
  function createRoom(key) {
47
54
  const name = key === '' ? 'the backend' : `the backend of room ${JSON.stringify(key)}`;
48
55
  const members = new Map();
49
56
  let worker = null;
50
57
  let next = 1;
51
58
  let broken = false;
59
+ // While the room is empty, the timer that ends it.
60
+ let idle = null;
52
61
 
53
62
  function deliver(sends) {
54
63
  for (const [client, number] of members) {
@@ -76,6 +85,8 @@ export function createBackendHost({ entry, ws, watcher, origin = () => '', log =
76
85
  function stop() {
77
86
  const ended = worker;
78
87
  worker = null;
88
+ clearTimeout(idle);
89
+ idle = null;
79
90
  for (const client of members.keys()) tabs.delete(client);
80
91
  members.clear();
81
92
  next = 1;
@@ -93,6 +104,8 @@ export function createBackendHost({ entry, ws, watcher, origin = () => '', log =
93
104
  const room = {
94
105
  join(client, player) {
95
106
  if (broken) return;
107
+ clearTimeout(idle);
108
+ idle = null;
96
109
  const number = next++;
97
110
  members.set(client, number);
98
111
  tabs.set(client, room);
@@ -105,12 +118,13 @@ export function createBackendHost({ entry, ws, watcher, origin = () => '', log =
105
118
  if (number === undefined) return;
106
119
  members.delete(client);
107
120
  tabs.delete(client);
121
+ worker.postMessage([{ kind: 'leave', client: number }]);
108
122
  if (members.size === 0) {
109
- stop();
110
- rooms.delete(key);
111
- return;
123
+ idle = setTimeout(() => {
124
+ stop();
125
+ rooms.delete(key);
126
+ }, EMPTY_ROOM_MS);
112
127
  }
113
- worker.postMessage([{ kind: 'leave', client: number }]);
114
128
  },
115
129
  receive(client, items) {
116
130
  const number = members.get(client);
package/src/vite.js CHANGED
@@ -40,6 +40,8 @@ export default function dew() {
40
40
  let dewBuild = false;
41
41
  let serving = false;
42
42
  let entry = null;
43
+ // The dev server's backend host, from the server's start to its close.
44
+ let host = null;
43
45
  return {
44
46
  name: 'dew',
45
47
  config(userConfig, env) {
@@ -120,12 +122,20 @@ export default function dew() {
120
122
  const env = loadKeys(server.config.envDir ?? server.config.root, server.config.mode);
121
123
  server.middlewares.use(DEV_ROUTE, createLlmMiddleware({ env }));
122
124
  if (entry === null) return;
123
- createBackendHost({
125
+ host = createBackendHost({
124
126
  entry,
125
127
  ws: server.ws,
126
128
  watcher: server.watcher,
127
129
  origin: () => server.resolvedUrls?.local?.[0]?.replace(/\/$/, '') ?? server.config.server?.origin ?? '',
128
130
  });
129
131
  },
132
+ // The dev server closing — in middleware mode too, which has no HTTP
133
+ // server of its own — ends every room: a backend left running for an
134
+ // empty room would hold the process open past the server it served.
135
+ // A build's close has no host to end.
136
+ closeBundle() {
137
+ host?.close();
138
+ host = null;
139
+ },
130
140
  };
131
141
  }