@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/LICENSE +674 -0
- package/README.md +87 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +46 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +98 -0
- package/dist/server.js.map +1 -0
- package/dist/shared.d.ts +4 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +2 -0
- package/dist/shared.js.map +1 -0
- package/package.json +55 -0
- package/src/client.ts +89 -0
- package/src/errors.ts +8 -0
- package/src/server.ts +143 -0
- package/src/shared.ts +5 -0
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).
|
package/dist/client.d.ts
ADDED
|
@@ -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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/dist/server.d.ts
ADDED
|
@@ -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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"}
|
package/dist/shared.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
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
|
+
}
|