void 0.7.4 → 0.7.5
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/dist/{better-auth-shared-BrfZ78iY.mjs → better-auth-shared-CjnJZFC0.mjs} +3 -7
- package/dist/pages/client.d.mts +4 -3
- package/dist/pages/client.mjs +18 -6
- package/dist/pages/protocol.d.mts +1 -1
- package/dist/pages/protocol.mjs +5 -0
- package/dist/{protocol-CK4OFwfR.d.mts → protocol-DxGzKEz2.d.mts} +1 -0
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/package.json +2 -2
- package/skills/void/docs/guide/pages-routing/overview.md +11 -0
- package/skills/void/docs/reference/api.md +8 -4
|
@@ -26,9 +26,6 @@ const SCRYPT_OPTIONS = {
|
|
|
26
26
|
p: 1,
|
|
27
27
|
r: 16
|
|
28
28
|
};
|
|
29
|
-
function toHex(bytes) {
|
|
30
|
-
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
31
|
-
}
|
|
32
29
|
function derivePasswordKey(password, salt) {
|
|
33
30
|
return new Promise((resolve, reject) => {
|
|
34
31
|
scrypt(password.normalize("NFKC"), salt, SCRYPT_KEY_LENGTH, SCRYPT_OPTIONS, (error, key) => {
|
|
@@ -42,16 +39,15 @@ function derivePasswordKey(password, salt) {
|
|
|
42
39
|
}
|
|
43
40
|
const voidAuthPassword = {
|
|
44
41
|
async hash(password) {
|
|
45
|
-
const salt =
|
|
42
|
+
const salt = randomBytes(PASSWORD_SALT_LENGTH).toString("hex");
|
|
46
43
|
return `${salt}:${(await derivePasswordKey(password, salt)).toString("hex")}`;
|
|
47
44
|
},
|
|
48
45
|
async verify({ hash, password }) {
|
|
49
46
|
const [salt, key, ...extra] = hash.split(":");
|
|
50
47
|
if (!salt || !key || extra.length > 0) return false;
|
|
51
|
-
const targetKey = await derivePasswordKey(password, salt);
|
|
52
48
|
const storedKey = Buffer.from(key, "hex");
|
|
53
|
-
if (
|
|
54
|
-
return timingSafeEqual(
|
|
49
|
+
if (key.length !== SCRYPT_KEY_LENGTH * 2 || storedKey.length !== SCRYPT_KEY_LENGTH) return false;
|
|
50
|
+
return timingSafeEqual(await derivePasswordKey(password, salt), storedKey);
|
|
55
51
|
}
|
|
56
52
|
};
|
|
57
53
|
function resolveEmailAndPassword(configuredProviders) {
|
package/dist/pages/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as PageObject } from "../protocol-
|
|
1
|
+
import { t as PageObject } from "../protocol-DxGzKEz2.mjs";
|
|
2
2
|
import { CacheForInput, CacheForResult } from "./prefetch.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/pages/action-result.d.ts
|
|
@@ -147,6 +147,7 @@ interface VoidRouter {
|
|
|
147
147
|
readonly url: URL;
|
|
148
148
|
readonly path: string;
|
|
149
149
|
readonly query: URLSearchParams;
|
|
150
|
+
readonly params: Record<string, string>;
|
|
150
151
|
visit(url: string | URL, options?: VisitOptions): Promise<unknown>;
|
|
151
152
|
refresh(options?: VisitOptions): Promise<unknown>;
|
|
152
153
|
prefetch(url: string | URL, options?: PrefetchOptions): Promise<unknown>;
|
|
@@ -178,8 +179,8 @@ interface VoidRouterConfig {
|
|
|
178
179
|
onNavigationChange?(navigation: NavigationState): void;
|
|
179
180
|
}
|
|
180
181
|
declare function idleNavigationState(): NavigationState;
|
|
181
|
-
declare function createRouterFacade(router: VoidRouter, getCurrentUrl: () => string): VoidRouter;
|
|
182
|
-
declare function createSsrRouter(url?: string): VoidRouter;
|
|
182
|
+
declare function createRouterFacade(router: VoidRouter, getCurrentUrl: () => string, getCurrentParams?: () => Record<string, string>): VoidRouter;
|
|
183
|
+
declare function createSsrRouter(url?: string, params?: Record<string, string>): VoidRouter;
|
|
183
184
|
declare function isFile(value: unknown): boolean;
|
|
184
185
|
declare function hasFiles(data: unknown): boolean;
|
|
185
186
|
declare function objectToFormData(source: Record<string, unknown>, form?: FormData, parentKey?: string): FormData;
|
package/dist/pages/client.mjs
CHANGED
|
@@ -756,7 +756,7 @@ function idleNavigationState() {
|
|
|
756
756
|
method: null
|
|
757
757
|
};
|
|
758
758
|
}
|
|
759
|
-
function createRouterFacade(router, getCurrentUrl) {
|
|
759
|
+
function createRouterFacade(router, getCurrentUrl, getCurrentParams = () => router.params) {
|
|
760
760
|
return {
|
|
761
761
|
get _hoverDelay() {
|
|
762
762
|
return router._hoverDelay;
|
|
@@ -770,6 +770,9 @@ function createRouterFacade(router, getCurrentUrl) {
|
|
|
770
770
|
get query() {
|
|
771
771
|
return this.url.searchParams;
|
|
772
772
|
},
|
|
773
|
+
get params() {
|
|
774
|
+
return getCurrentParams();
|
|
775
|
+
},
|
|
773
776
|
visit(url, options = {}) {
|
|
774
777
|
return router.visit(url, options);
|
|
775
778
|
},
|
|
@@ -787,7 +790,7 @@ function createRouterFacade(router, getCurrentUrl) {
|
|
|
787
790
|
}
|
|
788
791
|
};
|
|
789
792
|
}
|
|
790
|
-
function createSsrRouter(url = "/") {
|
|
793
|
+
function createSsrRouter(url = "/", params = {}) {
|
|
791
794
|
return {
|
|
792
795
|
_hoverDelay: 75,
|
|
793
796
|
get url() {
|
|
@@ -799,6 +802,9 @@ function createSsrRouter(url = "/") {
|
|
|
799
802
|
get query() {
|
|
800
803
|
return this.url.searchParams;
|
|
801
804
|
},
|
|
805
|
+
get params() {
|
|
806
|
+
return params;
|
|
807
|
+
},
|
|
802
808
|
visit() {
|
|
803
809
|
throw new Error("Void Router: visit() is not available during SSR.");
|
|
804
810
|
},
|
|
@@ -870,9 +876,11 @@ async function createVoidRouter(config) {
|
|
|
870
876
|
{
|
|
871
877
|
const engine = await createPageNavigationEngine(config);
|
|
872
878
|
let routeUrl = currentUrl();
|
|
879
|
+
let routeParams = engine.initialPageData.params ?? {};
|
|
873
880
|
let activeNavigationId = null;
|
|
874
|
-
const
|
|
881
|
+
const setRouteState = (url, params = routeParams) => {
|
|
875
882
|
routeUrl = url;
|
|
883
|
+
routeParams = params;
|
|
876
884
|
config.onRouteChange?.(url);
|
|
877
885
|
};
|
|
878
886
|
const setNavigation = (navigation) => {
|
|
@@ -884,11 +892,12 @@ async function createVoidRouter(config) {
|
|
|
884
892
|
try {
|
|
885
893
|
const result = await resource.shell;
|
|
886
894
|
if (!result) return;
|
|
895
|
+
setRouteState(result.pageData.url || resource.fetchUrl + resource.hash, result.pageData.params ?? {});
|
|
887
896
|
const applyUpdate = () => config.adapter.applyUpdate(result.pageData, result.component, result.layouts);
|
|
888
897
|
if ((resource.options.viewTransition ?? config.viewTransitions) && document.startViewTransition) await document.startViewTransition(() => applyUpdate()).updateCallbackDone;
|
|
889
898
|
else await applyUpdate();
|
|
890
899
|
await resource.commit();
|
|
891
|
-
if (activeNavigationId === resource.id)
|
|
900
|
+
if (activeNavigationId === resource.id) setRouteState(currentUrl(), result.pageData.params ?? {});
|
|
892
901
|
return result.pageData;
|
|
893
902
|
} catch (error) {
|
|
894
903
|
if (resource.method.toUpperCase() === "GET" && !resource.options._resolveOnShell && isAbortError(error)) return;
|
|
@@ -896,7 +905,7 @@ async function createVoidRouter(config) {
|
|
|
896
905
|
} finally {
|
|
897
906
|
if (activeNavigationId === resource.id) {
|
|
898
907
|
activeNavigationId = null;
|
|
899
|
-
|
|
908
|
+
setRouteState(currentUrl());
|
|
900
909
|
setNavigation(idleNavigationState());
|
|
901
910
|
}
|
|
902
911
|
}
|
|
@@ -912,6 +921,9 @@ async function createVoidRouter(config) {
|
|
|
912
921
|
get query() {
|
|
913
922
|
return this.url.searchParams;
|
|
914
923
|
},
|
|
924
|
+
get params() {
|
|
925
|
+
return routeParams;
|
|
926
|
+
},
|
|
915
927
|
visit(url, options = {}) {
|
|
916
928
|
return applyNavigationResource(engine.prepareVisit(normalizeUrl(url), options));
|
|
917
929
|
},
|
|
@@ -932,7 +944,7 @@ async function createVoidRouter(config) {
|
|
|
932
944
|
engine.flushAll();
|
|
933
945
|
}
|
|
934
946
|
};
|
|
935
|
-
const router = createRouterFacade(rawRouter, () => routeUrl);
|
|
947
|
+
const router = createRouterFacade(rawRouter, () => routeUrl, () => routeParams);
|
|
936
948
|
engine.setPopStateHandler((url, options) => {
|
|
937
949
|
router.visit(url, options);
|
|
938
950
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { S as ValidationError } from "../handler-dKQWyF-G.mjs";
|
|
2
|
-
import { a as handlePageMutation, i as handlePageGet, n as PageRenderResult, o as safeJsonStringify, r as flattenValidationErrors, t as PageObject } from "../protocol-
|
|
2
|
+
import { a as handlePageMutation, i as handlePageGet, n as PageRenderResult, o as safeJsonStringify, r as flattenValidationErrors, t as PageObject } from "../protocol-DxGzKEz2.mjs";
|
|
3
3
|
export { PageObject, PageRenderResult, ValidationError, flattenValidationErrors, handlePageGet, handlePageMutation, safeJsonStringify };
|
package/dist/pages/protocol.mjs
CHANGED
|
@@ -25,6 +25,9 @@ function pageJsonResponse(c, pageObj) {
|
|
|
25
25
|
function requestPathWithSearch(c) {
|
|
26
26
|
return c.req.path + new URL(c.req.url).search;
|
|
27
27
|
}
|
|
28
|
+
function requestParams(c) {
|
|
29
|
+
return c.req.param();
|
|
30
|
+
}
|
|
28
31
|
/** Extract props from a handler result, handling Response wrapping from withValidator */
|
|
29
32
|
async function extractProps(result) {
|
|
30
33
|
if (result instanceof Response) {
|
|
@@ -107,6 +110,7 @@ async function handlePageGet(handler, headFn, c, componentId, renderFn, getAsset
|
|
|
107
110
|
const pageObj = {
|
|
108
111
|
component: componentId,
|
|
109
112
|
props: immediateProps,
|
|
113
|
+
params: requestParams(c),
|
|
110
114
|
shared,
|
|
111
115
|
url: requestPathWithSearch(c),
|
|
112
116
|
errors: null,
|
|
@@ -159,6 +163,7 @@ async function handlePageMutation(mutationHandler, getHandler, headFn, c, compon
|
|
|
159
163
|
return {
|
|
160
164
|
component: componentId,
|
|
161
165
|
props,
|
|
166
|
+
params: requestParams(c),
|
|
162
167
|
shared,
|
|
163
168
|
url: requestPathWithSearch(c),
|
|
164
169
|
errors,
|
|
@@ -7,6 +7,7 @@ declare function safeJsonStringify(value: unknown): string;
|
|
|
7
7
|
interface PageObject {
|
|
8
8
|
component: string;
|
|
9
9
|
props: Record<string, unknown>;
|
|
10
|
+
params: Record<string, string>;
|
|
10
11
|
shared: Record<string, unknown>;
|
|
11
12
|
url: string;
|
|
12
13
|
errors: Record<string, string> | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as applyPgAuthMigrations } from "../auth-migrations-BwLPwRgH.mjs";
|
|
2
|
-
import { t as createVoidAuthRuntime } from "../better-auth-shared-
|
|
2
|
+
import { t as createVoidAuthRuntime } from "../better-auth-shared-CjnJZFC0.mjs";
|
|
3
3
|
//#region src/runtime/better-auth-pg.ts
|
|
4
4
|
function resolveConnectionString(env) {
|
|
5
5
|
const connectionString = typeof env.DATABASE_URL === "string" && env.DATABASE_URL.length > 0 ? env.DATABASE_URL : typeof env.HYPERDRIVE?.connectionString === "string" && env.HYPERDRIVE.connectionString.length > 0 ? env.HYPERDRIVE.connectionString : void 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as applySqliteAuthMigrations } from "../auth-migrations-BwLPwRgH.mjs";
|
|
2
|
-
import { t as createVoidAuthRuntime } from "../better-auth-shared-
|
|
2
|
+
import { t as createVoidAuthRuntime } from "../better-auth-shared-CjnJZFC0.mjs";
|
|
3
3
|
//#region src/runtime/better-auth.ts
|
|
4
4
|
async function resolveDatabase(env) {
|
|
5
5
|
if (!env.DB) throw new Error("auth: Better Auth requires the \"DB\" D1 binding for sqlite apps.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "void",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/voidzero-dev/void.git",
|
|
@@ -332,7 +332,7 @@
|
|
|
332
332
|
"valibot": ">=1.0.0-beta.7",
|
|
333
333
|
"vite": "^8.0.0",
|
|
334
334
|
"zod": "^3.25.0 || ^4.0.0",
|
|
335
|
-
"@void/md": "0.7.
|
|
335
|
+
"@void/md": "0.7.5"
|
|
336
336
|
},
|
|
337
337
|
"peerDependenciesMeta": {
|
|
338
338
|
"@void/md": {
|
|
@@ -195,6 +195,17 @@ router.refresh(); // re-fetch current page props
|
|
|
195
195
|
router.visit('/logout', { method: 'POST' }); // non-GET navigation
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
For dynamic route params, use `useParams()` from the same adapter package:
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
import { useParams } from '@void/react';
|
|
202
|
+
|
|
203
|
+
export default function PostPage() {
|
|
204
|
+
const { id } = useParams<{ id: string }>();
|
|
205
|
+
return <h1>Post {id}</h1>;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
198
209
|
## Scroll Restoration
|
|
199
210
|
|
|
200
211
|
The Void Router automatically saves and restores scroll position during client-side navigation:
|
|
@@ -742,7 +742,8 @@ Imported from `"@void/vue"`.
|
|
|
742
742
|
| Export | Description |
|
|
743
743
|
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
744
744
|
| `Link` | Vue component for SPA navigation. Renders `<a>` for GET, `<button>` for non-GET methods. Props: `href`, `method`, `data`, `prefetch`, `cacheFor`, `preserveScroll`, `preserveState`, `replace`, `reloadDocument`, `viewTransition`, `onNavigate`. |
|
|
745
|
-
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`.
|
|
745
|
+
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`, `params`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`. |
|
|
746
|
+
| `useParams()` | Returns dynamic route params for the page currently being rendered. |
|
|
746
747
|
| `useNavigation()` | Returns pending navigation state: `{ state, location, method }`, where `state` is `"idle"`, `"loading"`, or `"submitting"` and `location` is the pending destination. |
|
|
747
748
|
| `useForm(url, defaults, options?)` | Typed reactive form helper bound to a page action URL. Returns `{ data, post, put, patch, delete, pending, errors, error, hasChanges, wasSuccessful, recentlySuccessful, reset, clearErrors, clearError }`. |
|
|
748
749
|
| `useShared()` | Returns shared data injected by middleware via `c.set("shared", {...})`. |
|
|
@@ -789,7 +790,8 @@ Imported from `"@void/react"`.
|
|
|
789
790
|
| Export | Description |
|
|
790
791
|
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
791
792
|
| `Link` | React component for SPA navigation. Renders `<a>` for GET, `<button>` for non-GET methods. Props: `href`, `method`, `data`, `prefetch`, `cacheFor`, `preserveScroll`, `preserveState`, `replace`, `reloadDocument`, `viewTransition`, `onNavigate`. |
|
|
792
|
-
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`. React navigations are scheduled as transitions.
|
|
793
|
+
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`, `params`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`. React navigations are scheduled as transitions. |
|
|
794
|
+
| `useParams()` | Returns dynamic route params for the page currently being rendered. |
|
|
793
795
|
| `useNavigation()` | Returns pending navigation state: `{ state, location, method }`, where `state` is `"idle"`, `"loading"`, or `"submitting"` and `location` is the pending destination. |
|
|
794
796
|
| `useForm(url, defaults, options?)` | Form helper hook. Returns `{ data, setData, post, put, patch, delete, pending, errors, error, hasChanges, wasSuccessful, recentlySuccessful, reset, clearErrors, clearError }`. |
|
|
795
797
|
| `action(url, options?)` | Awaitable one-shot page action helper. Uses `POST` by default and accepts `{ data, method, params }`, where `method` can be `"PUT"`, `"PATCH"`, or `"DELETE"`. Returns an `ActionResult`. |
|
|
@@ -845,7 +847,8 @@ Imported from `"@void/svelte"`.
|
|
|
845
847
|
| `Link` | Svelte component for SPA navigation. Renders `<a>` for GET, `<button>` for non-GET methods. Props: `href`, `method`, `data`, `prefetch`, `cacheFor`, `preserveScroll`, `preserveState`, `replace`, `reloadDocument`, `viewTransition`, `onNavigate`. |
|
|
846
848
|
| `useForm(url, defaults, options?)` | Form helper using Svelte 5 runes. Returns `{ data, post, put, patch, delete, pending, errors, error, hasChanges, wasSuccessful, recentlySuccessful, reset, clearErrors, clearError }`. |
|
|
847
849
|
| `useShared()` | Returns shared data injected by middleware via `c.set("shared", {...})`. |
|
|
848
|
-
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`.
|
|
850
|
+
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`, `params`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`. |
|
|
851
|
+
| `useParams()` | Returns dynamic route params for the page currently being rendered. |
|
|
849
852
|
| `useNavigation()` | Returns pending navigation state: `{ state, location, method }`, where `state` is `"idle"`, `"loading"`, or `"submitting"` and `location` is the pending destination. |
|
|
850
853
|
|
|
851
854
|
Svelte `Link` GET `data` is merged into the rendered `href` query string. Primitive values are serialized with `String(value)`, arrays become repeated keys, `null` and `undefined` are omitted, and nested objects throw. `prefetch` and `reloadDocument` are GET-only and throw for mutation links.
|
|
@@ -888,7 +891,8 @@ Imported from `"@void/solid"`.
|
|
|
888
891
|
| `Link` | Solid component for SPA navigation. Renders `<a>` for GET, `<button>` for non-GET methods. Props: `href`, `method`, `data`, `prefetch`, `cacheFor`, `preserveScroll`, `preserveState`, `replace`, `reloadDocument`, `viewTransition`, `onNavigate`. |
|
|
889
892
|
| `useForm(url, defaults, options?)` | Form helper using Solid stores. Returns `{ data, setData, post, put, patch, delete, pending, errors, error, hasChanges, wasSuccessful, recentlySuccessful, reset, clearErrors, clearError }`. |
|
|
890
893
|
| `useShared()` | Returns shared data injected by middleware via `c.set("shared", {...})`. |
|
|
891
|
-
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`.
|
|
894
|
+
| `useRouter()` | Returns the Void Router with current route state (`url`, `path`, `query`, `params`) and navigation methods: `visit`, `refresh`, awaitable `prefetch`, `flush`, `flushAll`. |
|
|
895
|
+
| `useParams()` | Returns dynamic route params for the page currently being rendered. |
|
|
892
896
|
| `useNavigation()` | Returns pending navigation state: `{ state, location, method }`, where `state` is `"idle"`, `"loading"`, or `"submitting"` and `location` is the pending destination. |
|
|
893
897
|
|
|
894
898
|
Solid `Link` GET `data` is merged into the rendered `href` query string. Primitive values are serialized with `String(value)`, arrays become repeated keys, `null` and `undefined` are omitted, and nested objects throw. `prefetch` and `reloadDocument` are GET-only and throw for mutation links.
|