@mauroandre/velojs 0.0.52 → 0.0.54
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 +44 -2
- package/agent/skills/velojs-event-streams/SKILL.md +28 -0
- package/agent/skills/velojs-sockets/SKILL.md +16 -0
- package/agent/skills/velojs-testing/SKILL.md +35 -4
- package/dist/hooks.d.ts +12 -0
- package/dist/hooks.js +22 -22
- package/dist/server.d.ts +15 -0
- package/dist/server.js +42 -37
- package/dist/testing/createTestApp.d.ts +8 -0
- package/dist/testing/index.js +432 -386
- package/dist/testing/types.d.ts +30 -0
- package/package.json +3 -1
package/dist/testing/index.js
CHANGED
|
@@ -1,651 +1,697 @@
|
|
|
1
1
|
import { getRegisteredStreams as D } from "../events.js";
|
|
2
|
-
import { trackSocketSession as U, getAppSockets as
|
|
3
|
-
import { createIsolatedContext as
|
|
4
|
-
function
|
|
2
|
+
import { trackSocketSession as U, getAppSockets as $, injectWebSocketServer as V, abortAllSocketSessions as L } from "../sockets.js";
|
|
3
|
+
import { createIsolatedContext as W, withAppContext as B } from "../app-context.js";
|
|
4
|
+
function P(e) {
|
|
5
5
|
if (!e) return;
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
8
|
-
return
|
|
6
|
+
const n = Object.entries(e);
|
|
7
|
+
if (n.length !== 0)
|
|
8
|
+
return n.map(([t, c]) => `${encodeURIComponent(t)}=${encodeURIComponent(c)}`).join("; ");
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
const
|
|
12
|
-
for (const
|
|
13
|
-
const
|
|
14
|
-
if (
|
|
15
|
-
const
|
|
16
|
-
|
|
10
|
+
function F(e) {
|
|
11
|
+
const n = {}, t = e.getSetCookie?.() ?? [];
|
|
12
|
+
for (const c of t) {
|
|
13
|
+
const u = c.indexOf(";"), l = u === -1 ? c : c.slice(0, u), f = l.indexOf("=");
|
|
14
|
+
if (f === -1) continue;
|
|
15
|
+
const h = l.slice(0, f).trim(), r = l.slice(f + 1).trim();
|
|
16
|
+
h && (n[h] = decodeURIComponent(r));
|
|
17
17
|
}
|
|
18
|
-
return
|
|
18
|
+
return n;
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function I(e) {
|
|
21
21
|
if (!e) return "";
|
|
22
|
-
const
|
|
23
|
-
for (const [
|
|
24
|
-
if (Array.isArray(
|
|
25
|
-
for (const
|
|
22
|
+
const n = new URLSearchParams();
|
|
23
|
+
for (const [c, u] of Object.entries(e))
|
|
24
|
+
if (Array.isArray(u))
|
|
25
|
+
for (const l of u) n.append(c, l);
|
|
26
26
|
else
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
return
|
|
27
|
+
n.set(c, u);
|
|
28
|
+
const t = n.toString();
|
|
29
|
+
return t ? `?${t}` : "";
|
|
30
30
|
}
|
|
31
31
|
function z(e) {
|
|
32
|
-
const
|
|
33
|
-
return e.forEach((
|
|
34
|
-
|
|
35
|
-
}),
|
|
32
|
+
const n = {};
|
|
33
|
+
return e.forEach((t, c) => {
|
|
34
|
+
n[c] = t;
|
|
35
|
+
}), n;
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
function G(e) {
|
|
38
38
|
return e == null ? { body: null, contentType: null } : typeof e == "string" || e instanceof FormData || e instanceof URLSearchParams || e instanceof Blob || e instanceof ArrayBuffer || ArrayBuffer.isView(e) ? { body: e, contentType: null } : {
|
|
39
39
|
body: JSON.stringify(e),
|
|
40
40
|
contentType: "application/json"
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
function
|
|
45
|
-
const
|
|
46
|
-
return e.startsWith("http://") || e.startsWith("https://") ? e +
|
|
43
|
+
const N = "http://velojs.test";
|
|
44
|
+
function q(e, n) {
|
|
45
|
+
const t = I(n);
|
|
46
|
+
return e.startsWith("http://") || e.startsWith("https://") ? e + t : (e.startsWith("/") || (e = "/" + e), N + e + t);
|
|
47
47
|
}
|
|
48
48
|
function J(e = {}) {
|
|
49
|
-
const { user:
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
method:
|
|
53
|
-
headers:
|
|
49
|
+
const { user: n, params: t = {}, query: c = {}, body: u, headers: l = {}, cookies: f } = e, h = P(f), r = new Headers(l);
|
|
50
|
+
h && !r.has("cookie") && r.set("cookie", h);
|
|
51
|
+
const o = N + "/_mock" + I(c), i = {
|
|
52
|
+
method: u == null ? "GET" : "POST",
|
|
53
|
+
headers: r
|
|
54
54
|
};
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
return
|
|
55
|
+
u != null && (typeof u == "string" || u instanceof FormData || u instanceof Blob ? i.body = u : (i.body = JSON.stringify(u), r.has("content-type") || r.set("content-type", "application/json")));
|
|
56
|
+
const w = new Request(o, i), d = /* @__PURE__ */ new Map();
|
|
57
|
+
return n !== void 0 && d.set("user", n), {
|
|
58
58
|
req: {
|
|
59
|
-
raw:
|
|
60
|
-
url:
|
|
61
|
-
method:
|
|
62
|
-
param(
|
|
63
|
-
return
|
|
59
|
+
raw: w,
|
|
60
|
+
url: w.url,
|
|
61
|
+
method: w.method,
|
|
62
|
+
param(s) {
|
|
63
|
+
return s === void 0 ? t : t[s];
|
|
64
64
|
},
|
|
65
|
-
query(
|
|
66
|
-
if (
|
|
67
|
-
const
|
|
68
|
-
for (const [
|
|
69
|
-
|
|
70
|
-
return
|
|
65
|
+
query(s) {
|
|
66
|
+
if (s === void 0) {
|
|
67
|
+
const a = {};
|
|
68
|
+
for (const [y, v] of Object.entries(c))
|
|
69
|
+
a[y] = String(v);
|
|
70
|
+
return a;
|
|
71
71
|
}
|
|
72
|
-
return
|
|
72
|
+
return c[s];
|
|
73
73
|
},
|
|
74
|
-
queries(
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
return Array.isArray(
|
|
74
|
+
queries(s) {
|
|
75
|
+
const a = c[s];
|
|
76
|
+
if (a !== void 0)
|
|
77
|
+
return Array.isArray(a) ? a : [a];
|
|
78
78
|
},
|
|
79
|
-
header(
|
|
80
|
-
if (
|
|
81
|
-
const
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
}),
|
|
79
|
+
header(s) {
|
|
80
|
+
if (s === void 0) {
|
|
81
|
+
const a = {};
|
|
82
|
+
return r.forEach((y, v) => {
|
|
83
|
+
a[v] = y;
|
|
84
|
+
}), a;
|
|
85
85
|
}
|
|
86
|
-
return
|
|
86
|
+
return r.get(s) ?? void 0;
|
|
87
87
|
},
|
|
88
88
|
async json() {
|
|
89
|
-
return
|
|
89
|
+
return u == null ? null : typeof u == "object" ? u : JSON.parse(String(u));
|
|
90
90
|
},
|
|
91
91
|
async text() {
|
|
92
|
-
return
|
|
92
|
+
return u == null ? "" : typeof u == "string" ? u : JSON.stringify(u);
|
|
93
93
|
},
|
|
94
94
|
async parseBody() {
|
|
95
|
-
return
|
|
95
|
+
return u ?? {};
|
|
96
96
|
},
|
|
97
97
|
path: "/_mock"
|
|
98
98
|
},
|
|
99
99
|
res: void 0,
|
|
100
100
|
env: {},
|
|
101
101
|
finalized: !1,
|
|
102
|
-
get(
|
|
103
|
-
return
|
|
102
|
+
get(s) {
|
|
103
|
+
return d.get(s);
|
|
104
104
|
},
|
|
105
|
-
set(
|
|
106
|
-
|
|
105
|
+
set(s, a) {
|
|
106
|
+
d.set(s, a);
|
|
107
107
|
},
|
|
108
108
|
var: new Proxy({}, {
|
|
109
|
-
get(
|
|
110
|
-
return
|
|
109
|
+
get(s, a) {
|
|
110
|
+
return d.get(a);
|
|
111
111
|
}
|
|
112
112
|
}),
|
|
113
|
-
json(
|
|
114
|
-
return new Response(JSON.stringify(
|
|
115
|
-
status:
|
|
113
|
+
json(s, a = 200) {
|
|
114
|
+
return new Response(JSON.stringify(s), {
|
|
115
|
+
status: a,
|
|
116
116
|
headers: { "content-type": "application/json" }
|
|
117
117
|
});
|
|
118
118
|
},
|
|
119
|
-
text(
|
|
120
|
-
return new Response(
|
|
119
|
+
text(s, a = 200) {
|
|
120
|
+
return new Response(s, { status: a });
|
|
121
121
|
},
|
|
122
|
-
html(
|
|
123
|
-
return new Response(
|
|
124
|
-
status:
|
|
122
|
+
html(s, a = 200) {
|
|
123
|
+
return new Response(s, {
|
|
124
|
+
status: a,
|
|
125
125
|
headers: { "content-type": "text/html; charset=UTF-8" }
|
|
126
126
|
});
|
|
127
127
|
},
|
|
128
|
-
body(
|
|
129
|
-
return new Response(
|
|
128
|
+
body(s, a = 200) {
|
|
129
|
+
return new Response(s, { status: a });
|
|
130
130
|
},
|
|
131
|
-
redirect(
|
|
132
|
-
return new Response(null, { status:
|
|
131
|
+
redirect(s, a = 302) {
|
|
132
|
+
return new Response(null, { status: a, headers: { location: s } });
|
|
133
133
|
},
|
|
134
|
-
header(
|
|
134
|
+
header(s, a) {
|
|
135
135
|
},
|
|
136
|
-
status(
|
|
136
|
+
status(s) {
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
|
-
function
|
|
141
|
-
if (typeof
|
|
142
|
-
const
|
|
143
|
-
if (!
|
|
140
|
+
function Q(e, n) {
|
|
141
|
+
if (typeof n == "string") {
|
|
142
|
+
const t = $(e).get(n);
|
|
143
|
+
if (!t)
|
|
144
144
|
throw new Error(
|
|
145
|
-
`[velojs/testing] no socket handler registered at "${
|
|
145
|
+
`[velojs/testing] no socket handler registered at "${n}". Make sure the route exports a socket_* handler and routes are wired.`
|
|
146
146
|
);
|
|
147
|
-
return { handler:
|
|
147
|
+
return { handler: t.handler, path: n };
|
|
148
148
|
}
|
|
149
|
-
if (typeof
|
|
150
|
-
const
|
|
151
|
-
if (!
|
|
149
|
+
if (typeof n == "function") {
|
|
150
|
+
const t = n.__path;
|
|
151
|
+
if (!t)
|
|
152
152
|
throw new Error(
|
|
153
153
|
"[velojs/testing] socket handler has no __path. Make sure your vitest.config.ts loads veloPlugin() and your routes are registered."
|
|
154
154
|
);
|
|
155
|
-
return { handler:
|
|
155
|
+
return { handler: n, path: t };
|
|
156
156
|
}
|
|
157
|
-
if (
|
|
158
|
-
const
|
|
159
|
-
if (!
|
|
157
|
+
if (n && typeof n == "object" && typeof n.__path == "string") {
|
|
158
|
+
const t = n.__path, c = $(e).get(t);
|
|
159
|
+
if (!c)
|
|
160
160
|
throw new Error(
|
|
161
|
-
`[velojs/testing] stub with __path="${
|
|
161
|
+
`[velojs/testing] stub with __path="${t}" has no matching server handler.`
|
|
162
162
|
);
|
|
163
|
-
return { handler:
|
|
163
|
+
return { handler: c.handler, path: t };
|
|
164
164
|
}
|
|
165
165
|
throw new Error("[velojs/testing] socket(): unrecognized handler argument");
|
|
166
166
|
}
|
|
167
|
-
async function
|
|
168
|
-
const { handler:
|
|
169
|
-
params:
|
|
167
|
+
async function K(e, n, t = {}) {
|
|
168
|
+
const { handler: c, path: u } = Q(e, n), l = {
|
|
169
|
+
params: t.params ?? {},
|
|
170
170
|
query: {
|
|
171
|
-
...
|
|
172
|
-
...
|
|
171
|
+
...t.query,
|
|
172
|
+
...t.channel ? { channel: t.channel } : {}
|
|
173
173
|
}
|
|
174
174
|
};
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
let
|
|
178
|
-
const
|
|
175
|
+
t.user !== void 0 && (l.user = t.user), t.headers && (l.headers = t.headers), t.cookies && (l.cookies = t.cookies);
|
|
176
|
+
const f = J(l), h = [];
|
|
177
|
+
let r = null, o = !1;
|
|
178
|
+
const i = {
|
|
179
179
|
async *[Symbol.asyncIterator]() {
|
|
180
180
|
for (; ; ) {
|
|
181
|
-
for (;
|
|
182
|
-
yield
|
|
183
|
-
if (
|
|
184
|
-
await new Promise((
|
|
181
|
+
for (; h.length > 0; )
|
|
182
|
+
yield h.shift();
|
|
183
|
+
if (o) return;
|
|
184
|
+
await new Promise((p) => r = p), r = null;
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
},
|
|
192
|
-
let
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
for (const
|
|
187
|
+
}, w = (p) => {
|
|
188
|
+
o || (h.push(p), r?.());
|
|
189
|
+
}, d = () => {
|
|
190
|
+
o || (o = !0, r?.());
|
|
191
|
+
}, g = [];
|
|
192
|
+
let s = [];
|
|
193
|
+
const a = (p) => {
|
|
194
|
+
g.push(p);
|
|
195
|
+
const S = s;
|
|
196
|
+
s = [];
|
|
197
|
+
for (const j of S)
|
|
198
198
|
try {
|
|
199
|
-
|
|
199
|
+
j();
|
|
200
200
|
} catch {
|
|
201
201
|
}
|
|
202
|
-
},
|
|
203
|
-
let k = !1,
|
|
204
|
-
const b = (
|
|
205
|
-
|
|
206
|
-
}, C = (
|
|
202
|
+
}, y = new AbortController(), v = U(e, y);
|
|
203
|
+
let k = !1, m = !1;
|
|
204
|
+
const b = (p) => {
|
|
205
|
+
m || (typeof p == "string" || p instanceof Uint8Array ? a(p) : a(JSON.stringify(p)));
|
|
206
|
+
}, C = (p, S) => {
|
|
207
207
|
T();
|
|
208
|
-
},
|
|
208
|
+
}, H = () => {
|
|
209
209
|
k = !0;
|
|
210
210
|
}, T = () => {
|
|
211
|
-
if (
|
|
212
|
-
if (
|
|
211
|
+
if (m) return;
|
|
212
|
+
if (m = !0, !y.signal.aborted)
|
|
213
213
|
try {
|
|
214
|
-
|
|
214
|
+
y.abort();
|
|
215
215
|
} catch {
|
|
216
216
|
}
|
|
217
|
-
v(),
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
for (const
|
|
217
|
+
v(), d();
|
|
218
|
+
const p = s;
|
|
219
|
+
s = [];
|
|
220
|
+
for (const S of p)
|
|
221
221
|
try {
|
|
222
|
-
|
|
222
|
+
S();
|
|
223
223
|
} catch {
|
|
224
224
|
}
|
|
225
|
-
},
|
|
226
|
-
incoming:
|
|
225
|
+
}, O = {
|
|
226
|
+
incoming: i,
|
|
227
227
|
send: b,
|
|
228
228
|
close: C,
|
|
229
|
-
keepOpen:
|
|
230
|
-
abortSignal:
|
|
231
|
-
c:
|
|
232
|
-
params:
|
|
229
|
+
keepOpen: H,
|
|
230
|
+
abortSignal: y.signal,
|
|
231
|
+
c: f,
|
|
232
|
+
params: t.params ?? {},
|
|
233
233
|
query: {
|
|
234
|
-
...
|
|
235
|
-
...
|
|
234
|
+
...t.query ?? {},
|
|
235
|
+
...t.channel ? { channel: t.channel } : {}
|
|
236
236
|
}
|
|
237
237
|
}, A = (async () => {
|
|
238
238
|
try {
|
|
239
|
-
await
|
|
240
|
-
} catch (
|
|
241
|
-
console.error("[velojs/testing] socket handler threw:",
|
|
239
|
+
await c(O);
|
|
240
|
+
} catch (p) {
|
|
241
|
+
console.error("[velojs/testing] socket handler threw:", p);
|
|
242
242
|
}
|
|
243
243
|
k || T();
|
|
244
|
-
})(),
|
|
244
|
+
})(), R = (p) => new Promise((S, j) => {
|
|
245
245
|
const x = setTimeout(() => {
|
|
246
|
-
|
|
247
|
-
},
|
|
248
|
-
clearTimeout(x),
|
|
246
|
+
s = s.filter((M) => M !== _), j(new Error(`[velojs/testing] socket.next() timed out after ${p}ms`));
|
|
247
|
+
}, p), _ = () => {
|
|
248
|
+
clearTimeout(x), S();
|
|
249
249
|
};
|
|
250
|
-
|
|
250
|
+
s.push(_);
|
|
251
251
|
});
|
|
252
252
|
let E = 0;
|
|
253
253
|
return {
|
|
254
|
-
send(
|
|
255
|
-
|
|
254
|
+
send(p) {
|
|
255
|
+
m || (typeof p == "string" || p instanceof Uint8Array ? w(p) : w(JSON.stringify(p)));
|
|
256
256
|
},
|
|
257
257
|
get messages() {
|
|
258
|
-
return
|
|
258
|
+
return g;
|
|
259
259
|
},
|
|
260
260
|
get closed() {
|
|
261
|
-
return
|
|
261
|
+
return m;
|
|
262
262
|
},
|
|
263
|
-
async next(
|
|
264
|
-
for (; E >=
|
|
265
|
-
if (
|
|
263
|
+
async next(p) {
|
|
264
|
+
for (; E >= g.length; ) {
|
|
265
|
+
if (m)
|
|
266
266
|
throw new Error("[velojs/testing] socket closed before next()");
|
|
267
|
-
await
|
|
267
|
+
await R(p.timeoutMs);
|
|
268
268
|
}
|
|
269
|
-
return
|
|
269
|
+
return g[E++];
|
|
270
270
|
},
|
|
271
|
-
async nextN(
|
|
272
|
-
const
|
|
273
|
-
for (; x.length <
|
|
274
|
-
if (E <
|
|
275
|
-
x.push(
|
|
271
|
+
async nextN(p, S) {
|
|
272
|
+
const j = Date.now() + S.timeoutMs, x = [];
|
|
273
|
+
for (; x.length < p; ) {
|
|
274
|
+
if (E < g.length) {
|
|
275
|
+
x.push(g[E++]);
|
|
276
276
|
continue;
|
|
277
277
|
}
|
|
278
|
-
if (
|
|
278
|
+
if (m)
|
|
279
279
|
throw new Error("[velojs/testing] socket closed before nextN()");
|
|
280
|
-
const _ =
|
|
280
|
+
const _ = j - Date.now();
|
|
281
281
|
if (_ <= 0)
|
|
282
282
|
throw new Error(
|
|
283
|
-
`[velojs/testing] socket.nextN() timed out after ${
|
|
283
|
+
`[velojs/testing] socket.nextN() timed out after ${S.timeoutMs}ms`
|
|
284
284
|
);
|
|
285
|
-
await
|
|
285
|
+
await R(_);
|
|
286
286
|
}
|
|
287
287
|
return x;
|
|
288
288
|
},
|
|
289
|
-
async close(
|
|
289
|
+
async close(p, S) {
|
|
290
290
|
T(), await Promise.race([
|
|
291
291
|
A,
|
|
292
|
-
new Promise((
|
|
292
|
+
new Promise((j) => setTimeout(j, 50))
|
|
293
293
|
]);
|
|
294
294
|
},
|
|
295
295
|
done: A
|
|
296
296
|
};
|
|
297
297
|
}
|
|
298
|
-
function
|
|
299
|
-
const
|
|
300
|
-
function u
|
|
301
|
-
for (const
|
|
302
|
-
const
|
|
303
|
-
if (
|
|
304
|
-
for (const
|
|
305
|
-
if (!
|
|
306
|
-
const
|
|
307
|
-
if (typeof
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
name:
|
|
311
|
-
fn:
|
|
312
|
-
moduleId:
|
|
313
|
-
url: `/_action/${
|
|
298
|
+
function X(e) {
|
|
299
|
+
const n = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Map();
|
|
300
|
+
function c(u) {
|
|
301
|
+
for (const l of u) {
|
|
302
|
+
const f = l.module?.metadata?.moduleId, h = l.module?.metadata?.fullPath;
|
|
303
|
+
if (l.module && f) {
|
|
304
|
+
for (const o of Object.keys(l.module)) {
|
|
305
|
+
if (!o.startsWith("action_")) continue;
|
|
306
|
+
const i = l.module[o];
|
|
307
|
+
if (typeof i != "function") continue;
|
|
308
|
+
const w = o.replace("action_", "");
|
|
309
|
+
n.set(i, {
|
|
310
|
+
name: w,
|
|
311
|
+
fn: i,
|
|
312
|
+
moduleId: f,
|
|
313
|
+
url: `/_action/${f}/${w}`
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
|
-
const
|
|
317
|
-
if (typeof
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
fn:
|
|
321
|
-
moduleId:
|
|
322
|
-
paths: [
|
|
316
|
+
const r = l.module.loader;
|
|
317
|
+
if (typeof r == "function" && h) {
|
|
318
|
+
const o = t.get(r);
|
|
319
|
+
o ? o.paths.push(h) : t.set(r, {
|
|
320
|
+
fn: r,
|
|
321
|
+
moduleId: f,
|
|
322
|
+
paths: [h]
|
|
323
323
|
});
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
-
|
|
326
|
+
l.children && c(l.children);
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
|
-
return
|
|
329
|
+
return c(e), { actions: n, loaders: t };
|
|
330
330
|
}
|
|
331
|
-
function
|
|
332
|
-
if (typeof
|
|
333
|
-
const
|
|
334
|
-
if (!
|
|
331
|
+
function Y(e, n) {
|
|
332
|
+
if (typeof n == "string") return n;
|
|
333
|
+
const t = e.actions.get(n);
|
|
334
|
+
if (!t)
|
|
335
335
|
throw new Error(
|
|
336
336
|
`[velojs/testing] action_* function was not found in the route tree.
|
|
337
337
|
Make sure your Vitest config loads the VeloJS Vite plugin so that metadata is injected. See https://github.com/mauro-andre/velojs#testing`
|
|
338
338
|
);
|
|
339
|
-
return
|
|
339
|
+
return t.url;
|
|
340
340
|
}
|
|
341
|
-
function
|
|
342
|
-
if (typeof
|
|
343
|
-
const
|
|
344
|
-
if (!
|
|
341
|
+
function Z(e, n, t) {
|
|
342
|
+
if (typeof n == "string") return n;
|
|
343
|
+
const c = e.loaders.get(n);
|
|
344
|
+
if (!c)
|
|
345
345
|
throw new Error(
|
|
346
346
|
`[velojs/testing] loader function was not found in the route tree.
|
|
347
347
|
Make sure your Vitest config loads the VeloJS Vite plugin so that metadata is injected.`
|
|
348
348
|
);
|
|
349
|
-
let
|
|
350
|
-
if (
|
|
351
|
-
for (const [
|
|
352
|
-
|
|
353
|
-
return
|
|
349
|
+
let u = c.paths[0];
|
|
350
|
+
if (t)
|
|
351
|
+
for (const [l, f] of Object.entries(t))
|
|
352
|
+
u = u.replace(`:${l}`, encodeURIComponent(f));
|
|
353
|
+
return u;
|
|
354
354
|
}
|
|
355
|
-
class
|
|
355
|
+
class ee {
|
|
356
356
|
buffer = "";
|
|
357
357
|
current = {
|
|
358
358
|
event: "message",
|
|
359
359
|
data: []
|
|
360
360
|
};
|
|
361
|
-
push(
|
|
362
|
-
this.buffer +=
|
|
363
|
-
const
|
|
364
|
-
let
|
|
365
|
-
for (; (
|
|
361
|
+
push(n) {
|
|
362
|
+
this.buffer += n;
|
|
363
|
+
const t = [];
|
|
364
|
+
let c;
|
|
365
|
+
for (; (c = this.buffer.indexOf(`
|
|
366
366
|
`)) !== -1; ) {
|
|
367
|
-
const
|
|
368
|
-
if (this.buffer = this.buffer.slice(
|
|
367
|
+
const u = this.buffer.slice(0, c);
|
|
368
|
+
if (this.buffer = this.buffer.slice(c + 1), u === "") {
|
|
369
369
|
if (this.current.data.length > 0 || this.current.event !== "message") {
|
|
370
|
-
const
|
|
370
|
+
const r = {
|
|
371
371
|
event: this.current.event,
|
|
372
372
|
data: this.current.data.join(`
|
|
373
373
|
`)
|
|
374
374
|
};
|
|
375
|
-
this.current.id !== void 0 && (
|
|
375
|
+
this.current.id !== void 0 && (r.id = this.current.id), t.push(r);
|
|
376
376
|
}
|
|
377
377
|
this.current = { event: "message", data: [] };
|
|
378
378
|
continue;
|
|
379
379
|
}
|
|
380
|
-
if (
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
383
|
-
const
|
|
384
|
-
let
|
|
385
|
-
|
|
380
|
+
if (u.startsWith(":")) continue;
|
|
381
|
+
const l = u.indexOf(":");
|
|
382
|
+
if (l === -1) continue;
|
|
383
|
+
const f = u.slice(0, l);
|
|
384
|
+
let h = u.slice(l + 1);
|
|
385
|
+
h.startsWith(" ") && (h = h.slice(1)), f === "event" ? this.current.event = h : f === "data" ? this.current.data.push(h) : f === "id" && (this.current.id = h);
|
|
386
386
|
}
|
|
387
|
-
return
|
|
387
|
+
return t;
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
|
-
async function
|
|
391
|
-
const { response:
|
|
392
|
-
let
|
|
393
|
-
const
|
|
394
|
-
let
|
|
395
|
-
const
|
|
396
|
-
for (;
|
|
397
|
-
const
|
|
398
|
-
|
|
390
|
+
async function te(e) {
|
|
391
|
+
const { response: n } = e, t = n.status, c = [];
|
|
392
|
+
let u = null, l = !1, f = null;
|
|
393
|
+
const h = [];
|
|
394
|
+
let r = null, o = Promise.resolve(void 0);
|
|
395
|
+
const i = (g) => {
|
|
396
|
+
for (; h.length > 0; ) {
|
|
397
|
+
const s = h.shift();
|
|
398
|
+
g ? s.reject(g) : s.reject(new Error("[velojs/testing] subscription closed before next event"));
|
|
399
399
|
}
|
|
400
400
|
};
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
|
|
401
|
+
if (t >= 200 && t < 300 && n.body) {
|
|
402
|
+
r = n.body.getReader();
|
|
403
|
+
const g = new TextDecoder(), s = new ee();
|
|
404
|
+
o = (async () => {
|
|
405
405
|
try {
|
|
406
406
|
for (; ; ) {
|
|
407
|
-
const { value:
|
|
408
|
-
if (
|
|
409
|
-
|
|
407
|
+
const { value: a, done: y } = await r.read();
|
|
408
|
+
if (y) {
|
|
409
|
+
l || (l = !0), i();
|
|
410
410
|
return;
|
|
411
411
|
}
|
|
412
|
-
const v =
|
|
413
|
-
for (const
|
|
414
|
-
if (
|
|
412
|
+
const v = g.decode(a, { stream: !0 }), k = s.push(v);
|
|
413
|
+
for (const m of k) {
|
|
414
|
+
if (m.event === "snapshot") {
|
|
415
415
|
try {
|
|
416
|
-
|
|
416
|
+
u = JSON.parse(m.data);
|
|
417
417
|
} catch (b) {
|
|
418
|
-
|
|
418
|
+
f = b;
|
|
419
419
|
}
|
|
420
420
|
continue;
|
|
421
421
|
}
|
|
422
|
-
if (
|
|
423
|
-
|
|
422
|
+
if (m.event === "close") {
|
|
423
|
+
l = !0, i(), r.cancel().catch(() => {
|
|
424
424
|
});
|
|
425
425
|
return;
|
|
426
426
|
}
|
|
427
|
-
if (
|
|
427
|
+
if (m.event !== "heartbeat")
|
|
428
428
|
try {
|
|
429
|
-
const b = JSON.parse(
|
|
430
|
-
|
|
431
|
-
const C =
|
|
429
|
+
const b = JSON.parse(m.data);
|
|
430
|
+
c.push(b);
|
|
431
|
+
const C = h.shift();
|
|
432
432
|
C && C.resolve(b);
|
|
433
433
|
} catch (b) {
|
|
434
|
-
|
|
434
|
+
f = b;
|
|
435
435
|
}
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
|
-
} catch (
|
|
439
|
-
if (
|
|
440
|
-
|
|
438
|
+
} catch (a) {
|
|
439
|
+
if (a?.name === "AbortError") {
|
|
440
|
+
i();
|
|
441
441
|
return;
|
|
442
442
|
}
|
|
443
|
-
|
|
443
|
+
i(a);
|
|
444
444
|
}
|
|
445
445
|
})();
|
|
446
446
|
} else
|
|
447
|
-
await
|
|
448
|
-
const
|
|
447
|
+
await n.text().catch(() => ""), l = !0;
|
|
448
|
+
const w = {
|
|
449
449
|
get status() {
|
|
450
|
-
return
|
|
450
|
+
return t;
|
|
451
451
|
},
|
|
452
452
|
get events() {
|
|
453
|
-
return
|
|
453
|
+
return c;
|
|
454
454
|
},
|
|
455
455
|
get snapshot() {
|
|
456
|
-
return
|
|
456
|
+
return u;
|
|
457
457
|
},
|
|
458
458
|
get closed() {
|
|
459
|
-
return
|
|
459
|
+
return l;
|
|
460
460
|
},
|
|
461
|
-
async next({ timeoutMs:
|
|
462
|
-
if (
|
|
463
|
-
if (
|
|
464
|
-
const
|
|
465
|
-
return
|
|
461
|
+
async next({ timeoutMs: g }) {
|
|
462
|
+
if (f) throw f;
|
|
463
|
+
if (c.length > d) {
|
|
464
|
+
const s = c[d];
|
|
465
|
+
return d++, s;
|
|
466
466
|
}
|
|
467
|
-
if (
|
|
467
|
+
if (l)
|
|
468
468
|
throw new Error("[velojs/testing] subscription is closed");
|
|
469
|
-
return new Promise((
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
`[velojs/testing] timed out after ${
|
|
469
|
+
return new Promise((s, a) => {
|
|
470
|
+
const y = setTimeout(() => {
|
|
471
|
+
const m = h.findIndex((b) => b.resolve === v);
|
|
472
|
+
m !== -1 && h.splice(m, 1), a(new Error(
|
|
473
|
+
`[velojs/testing] timed out after ${g}ms waiting for next event`
|
|
474
474
|
));
|
|
475
|
-
},
|
|
476
|
-
clearTimeout(
|
|
477
|
-
}, k = (
|
|
478
|
-
clearTimeout(
|
|
475
|
+
}, g), v = (m) => {
|
|
476
|
+
clearTimeout(y), d++, s(m);
|
|
477
|
+
}, k = (m) => {
|
|
478
|
+
clearTimeout(y), a(m);
|
|
479
479
|
};
|
|
480
|
-
|
|
480
|
+
h.push({ resolve: v, reject: k });
|
|
481
481
|
});
|
|
482
482
|
},
|
|
483
|
-
async nextN(
|
|
484
|
-
const
|
|
485
|
-
for (let v = 0; v <
|
|
486
|
-
const k =
|
|
483
|
+
async nextN(g, { timeoutMs: s }) {
|
|
484
|
+
const a = Date.now(), y = [];
|
|
485
|
+
for (let v = 0; v < g; v++) {
|
|
486
|
+
const k = s - (Date.now() - a);
|
|
487
487
|
if (k <= 0)
|
|
488
488
|
throw new Error(
|
|
489
|
-
`[velojs/testing] timed out after ${
|
|
489
|
+
`[velojs/testing] timed out after ${s}ms waiting for ${g} events (got ${y.length})`
|
|
490
490
|
);
|
|
491
|
-
|
|
491
|
+
y.push(await w.next({ timeoutMs: k }));
|
|
492
492
|
}
|
|
493
|
-
return
|
|
493
|
+
return y;
|
|
494
494
|
},
|
|
495
495
|
async close() {
|
|
496
|
-
if (
|
|
496
|
+
if (r)
|
|
497
497
|
try {
|
|
498
|
-
await
|
|
498
|
+
await r.cancel();
|
|
499
499
|
} catch {
|
|
500
500
|
}
|
|
501
|
-
|
|
501
|
+
l = !0, i(), await o.catch(() => {
|
|
502
502
|
});
|
|
503
503
|
}
|
|
504
504
|
};
|
|
505
|
-
let
|
|
506
|
-
return
|
|
505
|
+
let d = 0;
|
|
506
|
+
return w;
|
|
507
507
|
}
|
|
508
|
-
async function
|
|
509
|
-
const
|
|
510
|
-
return await
|
|
508
|
+
async function fe(e) {
|
|
509
|
+
const n = W();
|
|
510
|
+
return await B(n, async () => {
|
|
511
511
|
e.bootstrap && await e.bootstrap();
|
|
512
|
-
const { createApp:
|
|
513
|
-
return
|
|
512
|
+
const { createApp: t } = await import("../server.js"), c = await t(e.routes), u = X(e.routes), l = e.port !== void 0 ? await ne(c, e.port, e.hostname) : void 0;
|
|
513
|
+
return se(c, n, u, e, void 0, l);
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
async function ne(e, n, t) {
|
|
517
|
+
const { serve: c } = await import("@hono/node-server"), { flushServerCallbacks: u, clearActiveServer: l } = await import("../server.js"), f = c({
|
|
518
|
+
fetch: e.fetch,
|
|
519
|
+
port: n,
|
|
520
|
+
...t ? { hostname: t } : {}
|
|
521
|
+
}), h = /* @__PURE__ */ new Set();
|
|
522
|
+
f.on("connection", (d) => {
|
|
523
|
+
h.add(d), d.on("close", () => h.delete(d));
|
|
524
|
+
}), await oe(f, n, t), await V(e, f), u(f);
|
|
525
|
+
const r = f.address(), o = r && typeof r == "object" ? r.port : n, i = t && t !== "0.0.0.0" && t !== "::" ? t : "localhost";
|
|
526
|
+
let w = !1;
|
|
527
|
+
return {
|
|
528
|
+
port: o,
|
|
529
|
+
url: `http://${i}:${o}`,
|
|
530
|
+
async close() {
|
|
531
|
+
if (w) return;
|
|
532
|
+
w = !0;
|
|
533
|
+
const d = new Promise((g) => {
|
|
534
|
+
f.close(() => g());
|
|
535
|
+
});
|
|
536
|
+
for (const g of h) g.destroy();
|
|
537
|
+
h.clear(), f.closeAllConnections(), await d, l(f);
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function oe(e, n, t) {
|
|
542
|
+
return e.listening ? Promise.resolve() : new Promise((c, u) => {
|
|
543
|
+
const l = `${t ?? "0.0.0.0"}:${n}`, f = () => {
|
|
544
|
+
e.off("listening", h), e.off("error", r);
|
|
545
|
+
}, h = () => {
|
|
546
|
+
f(), c();
|
|
547
|
+
}, r = (o) => {
|
|
548
|
+
f();
|
|
549
|
+
const i = o.code ? `${o.code}: ${o.message}` : o.message;
|
|
550
|
+
u(new Error(
|
|
551
|
+
`[velojs/testing] could not bind the test server on ${l} — ${i}`
|
|
552
|
+
));
|
|
553
|
+
};
|
|
554
|
+
e.once("listening", h), e.once("error", r);
|
|
514
555
|
});
|
|
515
556
|
}
|
|
516
|
-
function
|
|
517
|
-
async function
|
|
518
|
-
const d =
|
|
519
|
-
|
|
520
|
-
let
|
|
521
|
-
if (
|
|
522
|
-
const
|
|
523
|
-
|
|
557
|
+
function se(e, n, t, c, u, l) {
|
|
558
|
+
async function f(o, i, w = {}) {
|
|
559
|
+
const d = q(i, w.query), g = new Headers(w.headers ?? {}), s = { ...w.cookies ?? {} }, a = P(s);
|
|
560
|
+
a && g.set("cookie", a);
|
|
561
|
+
let y = null;
|
|
562
|
+
if (w.body !== void 0) {
|
|
563
|
+
const b = G(w.body);
|
|
564
|
+
y = b.body, b.contentType && !g.has("content-type") && g.set("content-type", b.contentType);
|
|
524
565
|
}
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
return await
|
|
566
|
+
const v = { method: o, headers: g };
|
|
567
|
+
y !== null && (v.body = y);
|
|
568
|
+
const k = new Request(d, v), m = await e.fetch(k);
|
|
569
|
+
return await re(m);
|
|
529
570
|
}
|
|
530
|
-
async function
|
|
531
|
-
const d =
|
|
532
|
-
...
|
|
533
|
-
...
|
|
534
|
-
}),
|
|
535
|
-
|
|
536
|
-
const
|
|
537
|
-
return await e.fetch(
|
|
571
|
+
async function h(o, i, w = {}) {
|
|
572
|
+
const d = q(i, {
|
|
573
|
+
...w.query ?? {},
|
|
574
|
+
...w.channel ? { channel: w.channel } : {}
|
|
575
|
+
}), g = new Headers(w.headers ?? {}), s = { ...w.cookies ?? {} }, a = P(s);
|
|
576
|
+
a && g.set("cookie", a);
|
|
577
|
+
const y = new Request(d, { method: o, headers: g });
|
|
578
|
+
return await e.fetch(y);
|
|
538
579
|
}
|
|
539
|
-
const
|
|
580
|
+
const r = {
|
|
540
581
|
hono: e,
|
|
582
|
+
// `undefined` unless `port` was passed — no listener, no behavior change.
|
|
583
|
+
port: l?.port,
|
|
584
|
+
url: l?.url,
|
|
541
585
|
// HTTP
|
|
542
|
-
get: (
|
|
543
|
-
post: (
|
|
544
|
-
put: (
|
|
545
|
-
patch: (
|
|
546
|
-
delete: (
|
|
547
|
-
async action(
|
|
548
|
-
const
|
|
549
|
-
return await
|
|
550
|
-
...
|
|
551
|
-
body:
|
|
586
|
+
get: (o, i) => f("GET", o, i ?? {}),
|
|
587
|
+
post: (o, i) => f("POST", o, i ?? {}),
|
|
588
|
+
put: (o, i) => f("PUT", o, i ?? {}),
|
|
589
|
+
patch: (o, i) => f("PATCH", o, i ?? {}),
|
|
590
|
+
delete: (o, i) => f("DELETE", o, i ?? {}),
|
|
591
|
+
async action(o, i = {}) {
|
|
592
|
+
const w = Y(t, o);
|
|
593
|
+
return await f("POST", w, {
|
|
594
|
+
...i,
|
|
595
|
+
body: i.body ?? {}
|
|
552
596
|
});
|
|
553
597
|
},
|
|
554
|
-
async loader(
|
|
555
|
-
const
|
|
556
|
-
...
|
|
557
|
-
query: { ...
|
|
598
|
+
async loader(o, i = {}) {
|
|
599
|
+
const w = Z(t, o, i.params), d = await f("GET", w, {
|
|
600
|
+
...i,
|
|
601
|
+
query: { ...i.query ?? {}, _data: "1" }
|
|
558
602
|
});
|
|
559
603
|
if (d.status >= 300 && d.status < 400 || d.status >= 400) return d;
|
|
560
|
-
const
|
|
561
|
-
return
|
|
604
|
+
const g = typeof o == "function" ? t.loaders.get(o)?.moduleId : void 0, s = await d.json();
|
|
605
|
+
return g && s && typeof s == "object" && g in s ? s[g] : s;
|
|
562
606
|
},
|
|
563
|
-
async subscribe(
|
|
564
|
-
const
|
|
565
|
-
return await
|
|
607
|
+
async subscribe(o, i = {}) {
|
|
608
|
+
const w = typeof o == "string" ? o : o.__path ?? ie(), d = await h("GET", w, i);
|
|
609
|
+
return await te({ response: d });
|
|
566
610
|
},
|
|
567
|
-
async socket(
|
|
568
|
-
return await
|
|
611
|
+
async socket(o, i = {}) {
|
|
612
|
+
return await K(e, o, i);
|
|
569
613
|
},
|
|
570
|
-
async sessionCookies({ user:
|
|
571
|
-
if (!
|
|
614
|
+
async sessionCookies({ user: o }) {
|
|
615
|
+
if (!c.getSessionCookie)
|
|
572
616
|
throw new Error(
|
|
573
617
|
"[velojs/testing] sessionCookies/as requires `getSessionCookie` in createTestApp options."
|
|
574
618
|
);
|
|
575
|
-
return await
|
|
619
|
+
return await c.getSessionCookie({ user: o });
|
|
576
620
|
},
|
|
577
|
-
as({ user:
|
|
578
|
-
if (!
|
|
621
|
+
as({ user: o }) {
|
|
622
|
+
if (!c.getSessionCookie)
|
|
579
623
|
throw new Error(
|
|
580
624
|
"[velojs/testing] app.as() requires `getSessionCookie` in createTestApp options."
|
|
581
625
|
);
|
|
582
|
-
let
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
...
|
|
586
|
-
cookies: { ...
|
|
626
|
+
let i = null;
|
|
627
|
+
const w = () => (i || (i = Promise.resolve(c.getSessionCookie({ user: o }))), i), d = (s) => (async (...a) => {
|
|
628
|
+
const y = await w(), [v, k] = a, m = {
|
|
629
|
+
...k ?? {},
|
|
630
|
+
cookies: { ...y, ...k?.cookies ?? {} }
|
|
587
631
|
};
|
|
588
|
-
return await
|
|
632
|
+
return await s.call(r, v, m);
|
|
589
633
|
});
|
|
590
634
|
return {
|
|
591
635
|
hono: e,
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
636
|
+
port: r.port,
|
|
637
|
+
url: r.url,
|
|
638
|
+
get: d(r.get),
|
|
639
|
+
post: d(r.post),
|
|
640
|
+
put: d(r.put),
|
|
641
|
+
patch: d(r.patch),
|
|
642
|
+
delete: d(r.delete),
|
|
643
|
+
action: d(r.action),
|
|
644
|
+
loader: d(r.loader),
|
|
645
|
+
subscribe: d(r.subscribe),
|
|
646
|
+
socket: d(r.socket),
|
|
647
|
+
sessionCookies: r.sessionCookies,
|
|
648
|
+
as: r.as,
|
|
603
649
|
// chaining .as.as works — last wins
|
|
604
|
-
mockContext:
|
|
605
|
-
reset:
|
|
606
|
-
close:
|
|
650
|
+
mockContext: r.mockContext,
|
|
651
|
+
reset: r.reset,
|
|
652
|
+
close: r.close
|
|
607
653
|
};
|
|
608
654
|
},
|
|
609
|
-
mockContext(
|
|
610
|
-
return J(
|
|
655
|
+
mockContext(o = {}) {
|
|
656
|
+
return J(o);
|
|
611
657
|
},
|
|
612
658
|
async reset() {
|
|
613
|
-
for (const
|
|
659
|
+
for (const o of D())
|
|
614
660
|
try {
|
|
615
|
-
|
|
616
|
-
} catch (
|
|
617
|
-
console.error("[velojs/testing] stream.__reset failed:",
|
|
661
|
+
o.__reset();
|
|
662
|
+
} catch (i) {
|
|
663
|
+
console.error("[velojs/testing] stream.__reset failed:", i);
|
|
618
664
|
}
|
|
619
665
|
},
|
|
620
666
|
async close() {
|
|
621
|
-
await
|
|
622
|
-
for (const
|
|
667
|
+
await r.reset(), L(e);
|
|
668
|
+
for (const o of n.disposers)
|
|
623
669
|
try {
|
|
624
|
-
|
|
625
|
-
} catch (
|
|
626
|
-
console.error("[velojs/testing] disposer failed:",
|
|
670
|
+
o();
|
|
671
|
+
} catch (i) {
|
|
672
|
+
console.error("[velojs/testing] disposer failed:", i);
|
|
627
673
|
}
|
|
628
|
-
|
|
674
|
+
n.disposers.clear(), await l?.close();
|
|
629
675
|
}
|
|
630
676
|
};
|
|
631
|
-
return
|
|
677
|
+
return r;
|
|
632
678
|
}
|
|
633
|
-
async function
|
|
679
|
+
async function re(e) {
|
|
634
680
|
return {
|
|
635
681
|
status: e.status,
|
|
636
682
|
headers: z(e.headers),
|
|
637
|
-
cookies:
|
|
683
|
+
cookies: F(e.headers),
|
|
638
684
|
json: () => e.clone().json(),
|
|
639
685
|
text: () => e.clone().text(),
|
|
640
686
|
blob: () => e.clone().blob(),
|
|
641
687
|
raw: e
|
|
642
688
|
};
|
|
643
689
|
}
|
|
644
|
-
function
|
|
690
|
+
function ie(e) {
|
|
645
691
|
throw new Error(
|
|
646
692
|
"[velojs/testing] subscribe(stream) — stream has no __path. If this is a stream_* declaration, make sure your routes import is processed by the VeloJS Vite plugin (your vitest.config.ts must include `veloPlugin()`)."
|
|
647
693
|
);
|
|
648
694
|
}
|
|
649
695
|
export {
|
|
650
|
-
|
|
696
|
+
fe as createTestApp
|
|
651
697
|
};
|