@zmdb/sveltekit 1.0.0-beta.1

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 ADDED
@@ -0,0 +1,87 @@
1
+ # @zmdb/sveltekit
2
+
3
+ `@zmdb/sveltekit` creates request-local generated clients from SvelteKit's `event.fetch`, provides typed server and browser load helpers, forwards only allow-listed credentials, and reuses the native
4
+ stores from `@zmdb/svelte`.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ yarn add @zmdb/client@1.0.0-beta.1 @zmdb/svelte@1.0.0-beta.1 @zmdb/sveltekit@1.0.0-beta.1 @sveltejs/kit@^2.70.3 svelte@^5.57.0
10
+ ```
11
+
12
+ > **Prerelease** (`1.0.0-beta.1`). Requires **Node.js 26+**, SvelteKit 2.70, Svelte 5, and ESM.
13
+
14
+ ## Server loads
15
+
16
+ Create one generated client for each request. Nothing is forwarded unless its name appears in the explicit allow-list:
17
+
18
+ ```ts
19
+ import { createSvelteKitServerLoad } from '@zmdb/sveltekit/server';
20
+
21
+ import { createApiClient } from '$lib/generated/api.js';
22
+ import type { PageServerLoad } from './$types.js';
23
+
24
+ export const load = createSvelteKitServerLoad({
25
+ key: 'account:current',
26
+ createClient: createApiClient,
27
+ clientOptions: {
28
+ baseUrl: '/api',
29
+ forward: {
30
+ headers: ['authorization'],
31
+ cookies: ['session'],
32
+ },
33
+ },
34
+ load: async (client, _event, signal) => ({
35
+ account: await client.getCurrentAccount({}, { signal }),
36
+ }),
37
+ }) satisfies PageServerLoad;
38
+ ```
39
+
40
+ The helper uses the current `event.fetch`, calls `depends` with the stable key, and passes `event.request.signal`. Redirects, status errors, abort reasons, and generated-client errors are never
41
+ wrapped.
42
+
43
+ ## Browser navigation
44
+
45
+ The browser entry uses the current universal `LoadEvent.fetch` and re-exports the Svelte context and store primitives:
46
+
47
+ ```ts
48
+ import { createSvelteKitClientLoad, createSvelteKitNavigationScope, createZmdbSvelte } from '@zmdb/sveltekit/client';
49
+
50
+ import { createApiClient } from '$lib/generated/api.js';
51
+
52
+ export const navigation = createSvelteKitNavigationScope();
53
+ export const zmdb = createZmdbSvelte<ReturnType<typeof createApiClient>>();
54
+
55
+ export const loadAccount = createSvelteKitClientLoad({
56
+ key: 'account:current',
57
+ navigation,
58
+ createClient: createApiClient,
59
+ clientOptions: { baseUrl: '/api' },
60
+ load: async (client, _event, signal) => ({
61
+ account: await client.getCurrentAccount({}, { signal }),
62
+ }),
63
+ });
64
+ ```
65
+
66
+ Track SvelteKit's native navigation from a mounted root layout:
67
+
68
+ ```svelte
69
+ <script lang="ts">
70
+ import { onNavigate } from '$app/navigation';
71
+ import { navigation } from '$lib/zmdb.js';
72
+
73
+ onNavigate(value => {
74
+ navigation.track(value);
75
+ });
76
+ </script>
77
+ ```
78
+
79
+ If SvelteKit rejects `navigation.complete`, active generated-client work aborts with that exact rejection as its signal reason.
80
+
81
+ ## Documentation
82
+
83
+ Full project documentation is at **https://ambasta.github.io/zmdb/**.
84
+
85
+ ## License
86
+
87
+ GNU General Public License v3.0 or later (GPL-3.0-or-later) — see [LICENSE](./LICENSE).
@@ -0,0 +1,22 @@
1
+ import type { LoadEvent, OnNavigate } from '@sveltejs/kit';
2
+ import type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
3
+ export { createMutationStore, createQueryStore, createZmdbSvelte } from '@zmdb/svelte';
4
+ export type { MutationRunner, MutationSnapshot, QueryLoader, QuerySnapshot, SvelteMutationStore, SvelteQueryStore, ZmdbSvelteBindings, } from '@zmdb/svelte';
5
+ export { SvelteKitAdapterError } from './errors.js';
6
+ export type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
7
+ export type SvelteKitClientLoadEvent = Pick<LoadEvent, 'depends' | 'fetch'>;
8
+ export interface SvelteKitNavigationScope {
9
+ readonly signal: AbortSignal | undefined;
10
+ track(navigation: Pick<OnNavigate, 'complete'>): AbortSignal;
11
+ }
12
+ export interface SvelteKitClientLoadDefinition<Client, Event extends SvelteKitClientLoadEvent, Output> {
13
+ readonly key: `${string}:${string}`;
14
+ readonly navigation: SvelteKitNavigationScope;
15
+ readonly createClient: GeneratedClientFactory<Client>;
16
+ readonly clientOptions: SvelteKitClientOptions;
17
+ readonly load: (client: Client, event: Event, signal: AbortSignal) => PromiseLike<Output>;
18
+ }
19
+ export declare function createSvelteKitBrowserClient<Client>(event: Pick<LoadEvent, 'fetch'>, createClient: GeneratedClientFactory<Client>, options: SvelteKitClientOptions): Client;
20
+ export declare function createSvelteKitNavigationScope(): SvelteKitNavigationScope;
21
+ export declare function createSvelteKitClientLoad<Client, Event extends SvelteKitClientLoadEvent, Output>(definition: SvelteKitClientLoadDefinition<Client, Event, Output>): (event: Event) => Promise<Output>;
22
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAElF,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACvF,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;AAE5E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC;CAC9D;AAED,MAAM,WAAW,6BAA6B,CAAC,MAAM,EAAE,KAAK,SAAS,wBAAwB,EAAE,MAAM;IACnG,QAAQ,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,sBAAsB,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3F;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EACjD,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAC/B,YAAY,EAAE,sBAAsB,CAAC,MAAM,CAAC,EAC5C,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAKR;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CA4BzE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,KAAK,SAAS,wBAAwB,EAAE,MAAM,EAC9F,UAAU,EAAE,6BAA6B,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAC/D,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAWnC"}
package/dist/client.js ADDED
@@ -0,0 +1,46 @@
1
+ import { createFetchTransport } from '@zmdb/client';
2
+ import { SvelteKitAdapterError } from './errors.js';
3
+ export { createMutationStore, createQueryStore, createZmdbSvelte } from '@zmdb/svelte';
4
+ export { SvelteKitAdapterError } from './errors.js';
5
+ export function createSvelteKitBrowserClient(event, createClient, options) {
6
+ return createClient({
7
+ ...options,
8
+ transport: createFetchTransport(event.fetch),
9
+ });
10
+ }
11
+ export function createSvelteKitNavigationScope() {
12
+ let current;
13
+ const clear = (selected) => {
14
+ if (Object.is(current, selected))
15
+ current = undefined;
16
+ };
17
+ const scope = {
18
+ get signal() {
19
+ return current?.signal;
20
+ },
21
+ track(navigation) {
22
+ const controller = new AbortController();
23
+ current = controller;
24
+ void navigation.complete.then(() => {
25
+ clear(controller);
26
+ }, (reason) => {
27
+ controller.abort(reason);
28
+ clear(controller);
29
+ });
30
+ return controller.signal;
31
+ },
32
+ };
33
+ return Object.freeze(scope);
34
+ }
35
+ export function createSvelteKitClientLoad(definition) {
36
+ if (!definition.key.includes(':')) {
37
+ throw new SvelteKitAdapterError('@zmdb/sveltekit client load keys must contain a namespace prefix');
38
+ }
39
+ return async (event) => {
40
+ event.depends(definition.key);
41
+ const client = createSvelteKitBrowserClient(event, definition.createClient, definition.clientOptions);
42
+ const signal = definition.navigation.signal ?? new AbortController().signal;
43
+ return definition.load(client, event, signal);
44
+ };
45
+ }
46
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAUvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAkBpD,MAAM,UAAU,4BAA4B,CAC1C,KAA+B,EAC/B,YAA4C,EAC5C,OAA+B;IAE/B,OAAO,YAAY,CAAC;QAClB,GAAG,OAAO;QACV,SAAS,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,IAAI,OAAoC,CAAC;IAEzC,MAAM,KAAK,GAAG,CAAC,QAAyB,EAAQ,EAAE;QAChD,IAAI,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;YAAE,OAAO,GAAG,SAAS,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,KAAK,GAA6B;QACtC,IAAI,MAAM;YACR,OAAO,OAAO,EAAE,MAAM,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,UAAwC;YAC5C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,OAAO,GAAG,UAAU,CAAC;YACrB,KAAK,UAAU,CAAC,QAAQ,CAAC,IAAI,CAC3B,GAAG,EAAE;gBACH,KAAK,CAAC,UAAU,CAAC,CAAC;YACpB,CAAC,EACD,CAAC,MAAe,EAAE,EAAE;gBAClB,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACzB,KAAK,CAAC,UAAU,CAAC,CAAC;YACpB,CAAC,CACF,CAAC;YACF,OAAO,UAAU,CAAC,MAAM,CAAC;QAC3B,CAAC;KACF,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,UAAgE;IAEhE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,qBAAqB,CAAC,kEAAkE,CAAC,CAAC;IACtG,CAAC;IAED,OAAO,KAAK,EAAC,KAAK,EAAC,EAAE;QACnB,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,4BAA4B,CAAC,KAAK,EAAE,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;QACtG,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM,CAAC;QAC5E,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { ClientError } from '@zmdb/client';
2
+ export declare class SvelteKitAdapterError extends ClientError {
3
+ constructor(message: string);
4
+ }
5
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,qBAAa,qBAAsB,SAAQ,WAAW;IACpD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
package/dist/errors.js ADDED
@@ -0,0 +1,8 @@
1
+ import { ClientError } from '@zmdb/client';
2
+ export class SvelteKitAdapterError extends ClientError {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'SvelteKitAdapterError';
6
+ }
7
+ }
8
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,qBAAsB,SAAQ,WAAW;IACpD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ import type { RequestEvent, ServerLoadEvent } from '@sveltejs/kit';
2
+ import type { ClientOptions } from '@zmdb/client';
3
+ import type { GeneratedClientFactory } from './shared.js';
4
+ export { SvelteKitAdapterError } from './errors.js';
5
+ export type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
6
+ export type SvelteKitRequestEvent = Pick<RequestEvent, 'cookies' | 'fetch' | 'request'>;
7
+ export type SvelteKitServerLoadEvent = SvelteKitRequestEvent & Pick<ServerLoadEvent, 'depends'>;
8
+ export interface SvelteKitForwarding {
9
+ readonly headers?: readonly string[];
10
+ readonly cookies?: readonly string[];
11
+ }
12
+ export interface SvelteKitServerClientOptions extends Omit<ClientOptions, 'transport'> {
13
+ readonly forward?: SvelteKitForwarding;
14
+ }
15
+ export interface SvelteKitServerLoadDefinition<Client, Event extends SvelteKitServerLoadEvent, Output> {
16
+ readonly key: `${string}:${string}`;
17
+ readonly createClient: GeneratedClientFactory<Client>;
18
+ readonly clientOptions: SvelteKitServerClientOptions;
19
+ readonly load: (client: Client, event: Event, signal: AbortSignal) => PromiseLike<Output>;
20
+ }
21
+ export declare function createSvelteKitServerFetch(event: SvelteKitRequestEvent, forwarding?: SvelteKitForwarding): typeof globalThis.fetch;
22
+ export declare function createSvelteKitServerClient<Client>(event: SvelteKitRequestEvent, createClient: GeneratedClientFactory<Client>, options: SvelteKitServerClientOptions): Client;
23
+ export declare function createSvelteKitServerLoad<Client, Event extends SvelteKitServerLoadEvent, Output>(definition: SvelteKitServerLoadDefinition<Client, Event, Output>): (event: Event) => Promise<Output>;
24
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAExF,MAAM,MAAM,wBAAwB,GAAG,qBAAqB,GAAG,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;AAEhG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAED,MAAM,WAAW,6BAA6B,CAAC,MAAM,EAAE,KAAK,SAAS,wBAAwB,EAAE,MAAM;IACnG,QAAQ,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,4BAA4B,CAAC;IACrD,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3F;AAgED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,qBAAqB,EAC5B,UAAU,GAAE,mBAAwB,GACnC,OAAO,UAAU,CAAC,KAAK,CAqBzB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAChD,KAAK,EAAE,qBAAqB,EAC5B,YAAY,EAAE,sBAAsB,CAAC,MAAM,CAAC,EAC5C,OAAO,EAAE,4BAA4B,GACpC,MAAM,CAMR;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,KAAK,SAAS,wBAAwB,EAAE,MAAM,EAC9F,UAAU,EAAE,6BAA6B,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAC/D,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAUnC"}
package/dist/server.js ADDED
@@ -0,0 +1,98 @@
1
+ import { createFetchTransport } from '@zmdb/client';
2
+ import { SvelteKitAdapterError } from './errors.js';
3
+ export { SvelteKitAdapterError } from './errors.js';
4
+ const COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
5
+ function uniqueHeaderNames(names) {
6
+ const selected = [];
7
+ const seen = new Set();
8
+ for (const candidate of names) {
9
+ const probe = new Headers();
10
+ probe.set(candidate, 'probe');
11
+ const name = candidate.toLowerCase();
12
+ if (name === 'cookie' || name === 'set-cookie') {
13
+ throw new SvelteKitAdapterError(`@zmdb/sveltekit forwards ${name} only through the explicit cookie allow-list`);
14
+ }
15
+ if (!seen.has(name)) {
16
+ seen.add(name);
17
+ selected.push(name);
18
+ }
19
+ }
20
+ return Object.freeze(selected);
21
+ }
22
+ function uniqueCookieNames(names) {
23
+ const selected = [];
24
+ const seen = new Set();
25
+ for (const name of names) {
26
+ if (!COOKIE_NAME.test(name)) {
27
+ throw new SvelteKitAdapterError(`@zmdb/sveltekit cannot forward invalid cookie name ${JSON.stringify(name)}`);
28
+ }
29
+ if (!seen.has(name)) {
30
+ seen.add(name);
31
+ selected.push(name);
32
+ }
33
+ }
34
+ return Object.freeze(selected);
35
+ }
36
+ function outgoingHeaders(input, init) {
37
+ const headers = new Headers(input instanceof Request ? input.headers : undefined);
38
+ if (init?.headers !== undefined) {
39
+ for (const [name, value] of new Headers(init.headers))
40
+ headers.set(name, value);
41
+ }
42
+ return headers;
43
+ }
44
+ function setForwardedHeader(headers, name, value) {
45
+ const existing = headers.get(name);
46
+ if (existing !== null && existing !== value) {
47
+ throw new SvelteKitAdapterError(`@zmdb/sveltekit refused to replace generated-client header ${name} while forwarding the request event`);
48
+ }
49
+ headers.set(name, value);
50
+ }
51
+ function selectedCookieHeader(event, names) {
52
+ const pairs = [];
53
+ for (const name of names) {
54
+ const value = event.cookies.get(name);
55
+ if (value !== undefined)
56
+ pairs.push(`${name}=${encodeURIComponent(value)}`);
57
+ }
58
+ return pairs.join('; ');
59
+ }
60
+ export function createSvelteKitServerFetch(event, forwarding = {}) {
61
+ const headerNames = uniqueHeaderNames(forwarding.headers ?? []);
62
+ const cookieNames = uniqueCookieNames(forwarding.cookies ?? []);
63
+ const fetch = async (input, init) => {
64
+ const headers = outgoingHeaders(input, init);
65
+ for (const name of headerNames) {
66
+ const value = event.request.headers.get(name);
67
+ if (value !== null)
68
+ setForwardedHeader(headers, name, value);
69
+ }
70
+ const cookie = selectedCookieHeader(event, cookieNames);
71
+ if (cookie !== '')
72
+ setForwardedHeader(headers, 'cookie', cookie);
73
+ return event.fetch(input, {
74
+ ...init,
75
+ credentials: 'omit',
76
+ headers,
77
+ });
78
+ };
79
+ return fetch;
80
+ }
81
+ export function createSvelteKitServerClient(event, createClient, options) {
82
+ const { forward, ...clientOptions } = options;
83
+ return createClient({
84
+ ...clientOptions,
85
+ transport: createFetchTransport(createSvelteKitServerFetch(event, forward)),
86
+ });
87
+ }
88
+ export function createSvelteKitServerLoad(definition) {
89
+ if (!definition.key.includes(':')) {
90
+ throw new SvelteKitAdapterError('@zmdb/sveltekit server load keys must contain a namespace prefix');
91
+ }
92
+ return async (event) => {
93
+ event.depends(definition.key);
94
+ const client = createSvelteKitServerClient(event, definition.createClient, definition.clientOptions);
95
+ return definition.load(client, event, event.request.signal);
96
+ };
97
+ }
98
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ClientOptions } from '@zmdb/client';
2
+ export type GeneratedClientFactory<Client> = (options: ClientOptions) => Client;
3
+ export type SvelteKitClientOptions = Omit<ClientOptions, 'transport'>;
4
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,MAAM,sBAAsB,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,aAAa,KAAK,MAAM,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC"}
package/dist/shared.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@zmdb/sveltekit",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Request-local SvelteKit clients, typed load helpers, explicit credential forwarding, and navigation cancellation for generated zmdb clients.",
5
+ "keywords": [
6
+ "client",
7
+ "load",
8
+ "svelte",
9
+ "sveltekit",
10
+ "typescript",
11
+ "zmdb"
12
+ ],
13
+ "homepage": "https://github.com/ambasta/zmdb#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/ambasta/zmdb/issues"
16
+ },
17
+ "license": "GPL-3.0-or-later",
18
+ "author": "zmdb contributors",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/ambasta/zmdb.git",
22
+ "directory": "packages/sveltekit"
23
+ },
24
+ "type": "module",
25
+ "sideEffects": false,
26
+ "exports": {
27
+ "./client": {
28
+ "types": "./dist/client.d.ts",
29
+ "import": "./dist/client.js"
30
+ },
31
+ "./server": {
32
+ "types": "./dist/server.d.ts",
33
+ "import": "./dist/server.js"
34
+ }
35
+ },
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "tag": "beta"
39
+ },
40
+ "scripts": {
41
+ "build": "node ../../scripts/build-package.mjs",
42
+ "test": "vitest run"
43
+ },
44
+ "dependencies": {
45
+ "@zmdb/client": "1.0.0-beta.1",
46
+ "@zmdb/svelte": "1.0.0-beta.1"
47
+ },
48
+ "peerDependencies": {
49
+ "@sveltejs/kit": ">=2.70.3 <3.0.0",
50
+ "svelte": ">=5.57.0 <6.0.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=26"
54
+ }
55
+ }
package/src/client.ts ADDED
@@ -0,0 +1,89 @@
1
+ import type { LoadEvent, OnNavigate } from '@sveltejs/kit';
2
+ import { createFetchTransport } from '@zmdb/client';
3
+
4
+ import { SvelteKitAdapterError } from './errors.js';
5
+ import type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
6
+
7
+ export { createMutationStore, createQueryStore, createZmdbSvelte } from '@zmdb/svelte';
8
+ export type {
9
+ MutationRunner,
10
+ MutationSnapshot,
11
+ QueryLoader,
12
+ QuerySnapshot,
13
+ SvelteMutationStore,
14
+ SvelteQueryStore,
15
+ ZmdbSvelteBindings,
16
+ } from '@zmdb/svelte';
17
+ export { SvelteKitAdapterError } from './errors.js';
18
+ export type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
19
+
20
+ export type SvelteKitClientLoadEvent = Pick<LoadEvent, 'depends' | 'fetch'>;
21
+
22
+ export interface SvelteKitNavigationScope {
23
+ readonly signal: AbortSignal | undefined;
24
+ track(navigation: Pick<OnNavigate, 'complete'>): AbortSignal;
25
+ }
26
+
27
+ export interface SvelteKitClientLoadDefinition<Client, Event extends SvelteKitClientLoadEvent, Output> {
28
+ readonly key: `${string}:${string}`;
29
+ readonly navigation: SvelteKitNavigationScope;
30
+ readonly createClient: GeneratedClientFactory<Client>;
31
+ readonly clientOptions: SvelteKitClientOptions;
32
+ readonly load: (client: Client, event: Event, signal: AbortSignal) => PromiseLike<Output>;
33
+ }
34
+
35
+ export function createSvelteKitBrowserClient<Client>(
36
+ event: Pick<LoadEvent, 'fetch'>,
37
+ createClient: GeneratedClientFactory<Client>,
38
+ options: SvelteKitClientOptions,
39
+ ): Client {
40
+ return createClient({
41
+ ...options,
42
+ transport: createFetchTransport(event.fetch),
43
+ });
44
+ }
45
+
46
+ export function createSvelteKitNavigationScope(): SvelteKitNavigationScope {
47
+ let current: AbortController | undefined;
48
+
49
+ const clear = (selected: AbortController): void => {
50
+ if (Object.is(current, selected)) current = undefined;
51
+ };
52
+
53
+ const scope: SvelteKitNavigationScope = {
54
+ get signal() {
55
+ return current?.signal;
56
+ },
57
+ track(navigation: Pick<OnNavigate, 'complete'>) {
58
+ const controller = new AbortController();
59
+ current = controller;
60
+ void navigation.complete.then(
61
+ () => {
62
+ clear(controller);
63
+ },
64
+ (reason: unknown) => {
65
+ controller.abort(reason);
66
+ clear(controller);
67
+ },
68
+ );
69
+ return controller.signal;
70
+ },
71
+ };
72
+
73
+ return Object.freeze(scope);
74
+ }
75
+
76
+ export function createSvelteKitClientLoad<Client, Event extends SvelteKitClientLoadEvent, Output>(
77
+ definition: SvelteKitClientLoadDefinition<Client, Event, Output>,
78
+ ): (event: Event) => Promise<Output> {
79
+ if (!definition.key.includes(':')) {
80
+ throw new SvelteKitAdapterError('@zmdb/sveltekit client load keys must contain a namespace prefix');
81
+ }
82
+
83
+ return async event => {
84
+ event.depends(definition.key);
85
+ const client = createSvelteKitBrowserClient(event, definition.createClient, definition.clientOptions);
86
+ const signal = definition.navigation.signal ?? new AbortController().signal;
87
+ return definition.load(client, event, signal);
88
+ };
89
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { ClientError } from '@zmdb/client';
2
+
3
+ export class SvelteKitAdapterError extends ClientError {
4
+ constructor(message: string) {
5
+ super(message);
6
+ this.name = 'SvelteKitAdapterError';
7
+ }
8
+ }
package/src/server.ts ADDED
@@ -0,0 +1,143 @@
1
+ import type { RequestEvent, ServerLoadEvent } from '@sveltejs/kit';
2
+ import { createFetchTransport } from '@zmdb/client';
3
+ import type { ClientOptions } from '@zmdb/client';
4
+
5
+ import { SvelteKitAdapterError } from './errors.js';
6
+ import type { GeneratedClientFactory } from './shared.js';
7
+
8
+ export { SvelteKitAdapterError } from './errors.js';
9
+ export type { GeneratedClientFactory, SvelteKitClientOptions } from './shared.js';
10
+
11
+ export type SvelteKitRequestEvent = Pick<RequestEvent, 'cookies' | 'fetch' | 'request'>;
12
+
13
+ export type SvelteKitServerLoadEvent = SvelteKitRequestEvent & Pick<ServerLoadEvent, 'depends'>;
14
+
15
+ export interface SvelteKitForwarding {
16
+ readonly headers?: readonly string[];
17
+ readonly cookies?: readonly string[];
18
+ }
19
+
20
+ export interface SvelteKitServerClientOptions extends Omit<ClientOptions, 'transport'> {
21
+ readonly forward?: SvelteKitForwarding;
22
+ }
23
+
24
+ export interface SvelteKitServerLoadDefinition<Client, Event extends SvelteKitServerLoadEvent, Output> {
25
+ readonly key: `${string}:${string}`;
26
+ readonly createClient: GeneratedClientFactory<Client>;
27
+ readonly clientOptions: SvelteKitServerClientOptions;
28
+ readonly load: (client: Client, event: Event, signal: AbortSignal) => PromiseLike<Output>;
29
+ }
30
+
31
+ const COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
32
+
33
+ function uniqueHeaderNames(names: readonly string[]): readonly string[] {
34
+ const selected: string[] = [];
35
+ const seen = new Set<string>();
36
+ for (const candidate of names) {
37
+ const probe = new Headers();
38
+ probe.set(candidate, 'probe');
39
+ const name = candidate.toLowerCase();
40
+ if (name === 'cookie' || name === 'set-cookie') {
41
+ throw new SvelteKitAdapterError(`@zmdb/sveltekit forwards ${name} only through the explicit cookie allow-list`);
42
+ }
43
+ if (!seen.has(name)) {
44
+ seen.add(name);
45
+ selected.push(name);
46
+ }
47
+ }
48
+ return Object.freeze(selected);
49
+ }
50
+
51
+ function uniqueCookieNames(names: readonly string[]): readonly string[] {
52
+ const selected: string[] = [];
53
+ const seen = new Set<string>();
54
+ for (const name of names) {
55
+ if (!COOKIE_NAME.test(name)) {
56
+ throw new SvelteKitAdapterError(`@zmdb/sveltekit cannot forward invalid cookie name ${JSON.stringify(name)}`);
57
+ }
58
+ if (!seen.has(name)) {
59
+ seen.add(name);
60
+ selected.push(name);
61
+ }
62
+ }
63
+ return Object.freeze(selected);
64
+ }
65
+
66
+ function outgoingHeaders(input: RequestInfo | URL, init: RequestInit | undefined): Headers {
67
+ const headers = new Headers(input instanceof Request ? input.headers : undefined);
68
+ if (init?.headers !== undefined) {
69
+ for (const [name, value] of new Headers(init.headers)) headers.set(name, value);
70
+ }
71
+ return headers;
72
+ }
73
+
74
+ function setForwardedHeader(headers: Headers, name: string, value: string): void {
75
+ const existing = headers.get(name);
76
+ if (existing !== null && existing !== value) {
77
+ throw new SvelteKitAdapterError(
78
+ `@zmdb/sveltekit refused to replace generated-client header ${name} while forwarding the request event`,
79
+ );
80
+ }
81
+ headers.set(name, value);
82
+ }
83
+
84
+ function selectedCookieHeader(event: SvelteKitRequestEvent, names: readonly string[]): string {
85
+ const pairs: string[] = [];
86
+ for (const name of names) {
87
+ const value = event.cookies.get(name);
88
+ if (value !== undefined) pairs.push(`${name}=${encodeURIComponent(value)}`);
89
+ }
90
+ return pairs.join('; ');
91
+ }
92
+
93
+ export function createSvelteKitServerFetch(
94
+ event: SvelteKitRequestEvent,
95
+ forwarding: SvelteKitForwarding = {},
96
+ ): typeof globalThis.fetch {
97
+ const headerNames = uniqueHeaderNames(forwarding.headers ?? []);
98
+ const cookieNames = uniqueCookieNames(forwarding.cookies ?? []);
99
+
100
+ const fetch: typeof globalThis.fetch = async (input, init) => {
101
+ const headers = outgoingHeaders(input, init);
102
+ for (const name of headerNames) {
103
+ const value = event.request.headers.get(name);
104
+ if (value !== null) setForwardedHeader(headers, name, value);
105
+ }
106
+ const cookie = selectedCookieHeader(event, cookieNames);
107
+ if (cookie !== '') setForwardedHeader(headers, 'cookie', cookie);
108
+
109
+ return event.fetch(input, {
110
+ ...init,
111
+ credentials: 'omit',
112
+ headers,
113
+ });
114
+ };
115
+
116
+ return fetch;
117
+ }
118
+
119
+ export function createSvelteKitServerClient<Client>(
120
+ event: SvelteKitRequestEvent,
121
+ createClient: GeneratedClientFactory<Client>,
122
+ options: SvelteKitServerClientOptions,
123
+ ): Client {
124
+ const { forward, ...clientOptions } = options;
125
+ return createClient({
126
+ ...clientOptions,
127
+ transport: createFetchTransport(createSvelteKitServerFetch(event, forward)),
128
+ });
129
+ }
130
+
131
+ export function createSvelteKitServerLoad<Client, Event extends SvelteKitServerLoadEvent, Output>(
132
+ definition: SvelteKitServerLoadDefinition<Client, Event, Output>,
133
+ ): (event: Event) => Promise<Output> {
134
+ if (!definition.key.includes(':')) {
135
+ throw new SvelteKitAdapterError('@zmdb/sveltekit server load keys must contain a namespace prefix');
136
+ }
137
+
138
+ return async event => {
139
+ event.depends(definition.key);
140
+ const client = createSvelteKitServerClient(event, definition.createClient, definition.clientOptions);
141
+ return definition.load(client, event, event.request.signal);
142
+ };
143
+ }
package/src/shared.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { ClientOptions } from '@zmdb/client';
2
+
3
+ export type GeneratedClientFactory<Client> = (options: ClientOptions) => Client;
4
+
5
+ export type SvelteKitClientOptions = Omit<ClientOptions, 'transport'>;