arcway 0.1.25 → 0.1.27
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/client/fetcher.js +4 -1
- package/client/hooks/swr-compat.js +27 -0
- package/client/hooks/use-api-paginated.js +74 -0
- package/client/hooks/use-api.js +1 -4
- package/client/hooks/use-graphql.js +1 -2
- package/client/hooks/use-mutation.js +1 -1
- package/client/hooks/web/use-local-storage.js +54 -16
- package/client/index.js +16 -55
- package/client/router.js +51 -29
- package/client/ui/index.js +62 -380
- package/package.json +4 -3
- package/server/bin/commands/build.js +3 -0
- package/server/boot/index.js +12 -6
- package/server/build.js +63 -5
- package/server/cache/index.js +12 -2
- package/server/cache/ttl.js +24 -0
- package/server/config/duration.js +49 -0
- package/server/config/modules/cache.js +7 -1
- package/server/config/modules/jobs.js +14 -1
- package/server/config/modules/mail.js +16 -1
- package/server/config/modules/pages.js +3 -2
- package/server/config/modules/queue.js +7 -1
- package/server/config/modules/server.js +13 -1
- package/server/config/modules/websocket.js +8 -0
- package/server/context.js +61 -2
- package/server/db/index.js +6 -1
- package/server/events/drivers/memory.js +22 -4
- package/server/events/drivers/redis.js +20 -5
- package/server/events/handler.js +21 -7
- package/server/events/index.js +2 -2
- package/server/index.js +7 -33
- package/server/jobs/runner.js +3 -2
- package/server/jobs/worker-config.js +58 -0
- package/server/jobs/worker-entry.js +7 -12
- package/server/meta.js +106 -0
- package/server/pages/build-client.js +1 -1
- package/server/pages/build-plugins.js +2 -1
- package/server/pages/chunk-graph.js +1 -0
- package/server/pages/fonts.js +14 -1
- package/server/pages/handler.js +25 -7
- package/server/pages/lazy-context.js +2 -2
- package/server/pages/out-dir.js +104 -3
- package/server/pages/pages-router.js +3 -2
- package/server/pages/ssr.js +55 -18
- package/server/pages/vite-dev.js +38 -3
- package/server/router/api-router.js +71 -2
- package/server/router/ratelimit.js +50 -0
- package/server/router/routes.js +10 -0
- package/server/server.js +13 -1
- package/server/session/index.js +5 -1
- package/server/static/index.js +5 -2
- package/server/web-server.js +3 -3
- package/server/ws/realtime.js +24 -8
- package/server/ws/ws-router.js +24 -8
- package/client/hooks/use-form.js +0 -86
package/server/ws/ws-router.js
CHANGED
|
@@ -5,6 +5,19 @@ import { parseCookies, resolveSession, flattenHeaders } from '../session/helpers
|
|
|
5
5
|
import { getMiddlewareForRoute } from '../router/middleware.js';
|
|
6
6
|
import { toErrorMessage } from '../helpers.js';
|
|
7
7
|
|
|
8
|
+
function normalizeWsMsg(wsMsg) {
|
|
9
|
+
const rawPath = wsMsg.path;
|
|
10
|
+
const url = new URL(rawPath, 'http://localhost');
|
|
11
|
+
const query = Object.fromEntries(url.searchParams.entries());
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
...wsMsg,
|
|
15
|
+
path: rawPath,
|
|
16
|
+
pathname: url.pathname,
|
|
17
|
+
query: { ...query, ...(wsMsg.query ?? {}) },
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
8
21
|
class WsRouter {
|
|
9
22
|
_apiRouter;
|
|
10
23
|
_log;
|
|
@@ -149,16 +162,17 @@ class WsRouter {
|
|
|
149
162
|
return;
|
|
150
163
|
}
|
|
151
164
|
|
|
152
|
-
const
|
|
165
|
+
const normalized = normalizeWsMsg(parsed);
|
|
166
|
+
const method = normalized.method.toUpperCase();
|
|
153
167
|
if (method === 'SUBSCRIBE') {
|
|
154
|
-
await this._handleSubscribe(client, { ...
|
|
168
|
+
await this._handleSubscribe(client, { ...normalized, method });
|
|
155
169
|
} else if (method === 'UNSUBSCRIBE') {
|
|
156
|
-
await this._handleUnsubscribe(client, { ...
|
|
170
|
+
await this._handleUnsubscribe(client, { ...normalized, method });
|
|
157
171
|
} else if (['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
|
|
158
|
-
await this._handleMethodCall(client, { ...
|
|
172
|
+
await this._handleMethodCall(client, { ...normalized, method });
|
|
159
173
|
} else {
|
|
160
174
|
this._send(client, {
|
|
161
|
-
path:
|
|
175
|
+
path: normalized.path,
|
|
162
176
|
error: { code: 'INVALID_METHOD', message: `Unsupported method: ${method}` },
|
|
163
177
|
});
|
|
164
178
|
}
|
|
@@ -167,6 +181,7 @@ class WsRouter {
|
|
|
167
181
|
// ── Subscribe / Unsubscribe ──
|
|
168
182
|
|
|
169
183
|
async _handleSubscribe(client, wsMsg) {
|
|
184
|
+
wsMsg = wsMsg.pathname ? wsMsg : normalizeWsMsg(wsMsg);
|
|
170
185
|
const msgPath = wsMsg.path;
|
|
171
186
|
if (client.subscriptions.has(msgPath)) {
|
|
172
187
|
this._send(client, {
|
|
@@ -176,7 +191,7 @@ class WsRouter {
|
|
|
176
191
|
return;
|
|
177
192
|
}
|
|
178
193
|
|
|
179
|
-
const matched = this._apiRouter.findRoute('GET',
|
|
194
|
+
const matched = this._apiRouter.findRoute('GET', wsMsg.pathname);
|
|
180
195
|
if (!matched) {
|
|
181
196
|
this._send(client, {
|
|
182
197
|
path: msgPath,
|
|
@@ -296,8 +311,9 @@ class WsRouter {
|
|
|
296
311
|
// ── Method calls (GET/POST/PUT/PATCH/DELETE) ──
|
|
297
312
|
|
|
298
313
|
async _handleMethodCall(client, wsMsg) {
|
|
314
|
+
wsMsg = wsMsg.pathname ? wsMsg : normalizeWsMsg(wsMsg);
|
|
299
315
|
const { path: msgPath, method } = wsMsg;
|
|
300
|
-
const matched = this._apiRouter.findRoute(method,
|
|
316
|
+
const matched = this._apiRouter.findRoute(method, wsMsg.pathname);
|
|
301
317
|
|
|
302
318
|
if (!matched) {
|
|
303
319
|
this._send(client, {
|
|
@@ -330,7 +346,7 @@ class WsRouter {
|
|
|
330
346
|
return {
|
|
331
347
|
id: randomUUID(),
|
|
332
348
|
method: wsMsg.method,
|
|
333
|
-
path: wsMsg.path,
|
|
349
|
+
path: wsMsg.pathname ?? wsMsg.path,
|
|
334
350
|
query: { ...(wsMsg.query ?? {}), ...params },
|
|
335
351
|
body: wsMsg.body,
|
|
336
352
|
headers: client.headers,
|
package/client/hooks/use-form.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from 'react';
|
|
2
|
-
import { ArkErrors } from 'arktype';
|
|
3
|
-
|
|
4
|
-
export default function useForm(options) {
|
|
5
|
-
const [values, setValues] = useState(options.initialValues);
|
|
6
|
-
const [errors, setErrors] = useState({});
|
|
7
|
-
const [touched, setTouched] = useState({});
|
|
8
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
9
|
-
|
|
10
|
-
const initialRef = useRef(options.initialValues);
|
|
11
|
-
const schemaRef = useRef(options.schema);
|
|
12
|
-
schemaRef.current = options.schema;
|
|
13
|
-
const onSubmitRef = useRef(options.onSubmit);
|
|
14
|
-
onSubmitRef.current = options.onSubmit;
|
|
15
|
-
const valuesRef = useRef(values);
|
|
16
|
-
valuesRef.current = values;
|
|
17
|
-
|
|
18
|
-
const isDirty = Object.keys(initialRef.current).some(
|
|
19
|
-
(key) => values[key] !== initialRef.current[key],
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
function setField(name, value) {
|
|
23
|
-
setValues((prev) => ({ ...prev, [name]: value }));
|
|
24
|
-
setTouched((prev) => ({ ...prev, [name]: true }));
|
|
25
|
-
setErrors((prev) => {
|
|
26
|
-
if (!prev[name]) return prev;
|
|
27
|
-
const next = { ...prev };
|
|
28
|
-
delete next[name];
|
|
29
|
-
return next;
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const setError = useCallback((name, message) => {
|
|
34
|
-
setErrors((prev) => ({ ...prev, [name]: message }));
|
|
35
|
-
}, []);
|
|
36
|
-
|
|
37
|
-
const handleSubmit = useCallback(async (e) => {
|
|
38
|
-
e?.preventDefault?.();
|
|
39
|
-
const currentValues = valuesRef.current;
|
|
40
|
-
const schema = schemaRef.current;
|
|
41
|
-
|
|
42
|
-
if (schema) {
|
|
43
|
-
const result = schema(currentValues);
|
|
44
|
-
if (result instanceof ArkErrors) {
|
|
45
|
-
const fieldErrors = {};
|
|
46
|
-
for (const err of result) {
|
|
47
|
-
const key = String(err.path[0]);
|
|
48
|
-
if (key && !fieldErrors[key]) {
|
|
49
|
-
fieldErrors[key] = err.message;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
setErrors(fieldErrors);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
setErrors({});
|
|
58
|
-
setIsSubmitting(true);
|
|
59
|
-
try {
|
|
60
|
-
await onSubmitRef.current(currentValues);
|
|
61
|
-
} finally {
|
|
62
|
-
setIsSubmitting(false);
|
|
63
|
-
}
|
|
64
|
-
}, []);
|
|
65
|
-
|
|
66
|
-
const reset = useCallback((newValues) => {
|
|
67
|
-
const resetTo = newValues ?? initialRef.current;
|
|
68
|
-
if (newValues) initialRef.current = newValues;
|
|
69
|
-
setValues(resetTo);
|
|
70
|
-
setErrors({});
|
|
71
|
-
setTouched({});
|
|
72
|
-
setIsSubmitting(false);
|
|
73
|
-
}, []);
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
values,
|
|
77
|
-
errors,
|
|
78
|
-
touched,
|
|
79
|
-
isDirty,
|
|
80
|
-
isSubmitting,
|
|
81
|
-
setField,
|
|
82
|
-
setError,
|
|
83
|
-
handleSubmit,
|
|
84
|
-
reset,
|
|
85
|
-
};
|
|
86
|
-
}
|