@objectstack/sveltekit 3.2.7 → 3.2.9

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/sveltekit@3.2.7 build /home/runner/work/spec/spec/packages/adapters/sveltekit
2
+ > @objectstack/sveltekit@3.2.9 build /home/runner/work/spec/spec/packages/adapters/sveltekit
3
3
  > tsup --config ../../../tsup.config.ts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -10,13 +10,13 @@
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- ESM dist/index.mjs 5.10 KB
14
- ESM dist/index.mjs.map 11.00 KB
15
- ESM ⚡️ Build success in 71ms
16
- CJS dist/index.js 6.15 KB
17
- CJS dist/index.js.map 11.04 KB
18
- CJS ⚡️ Build success in 71ms
13
+ ESM dist/index.mjs 4.50 KB
14
+ ESM dist/index.mjs.map 10.35 KB
15
+ ESM ⚡️ Build success in 40ms
16
+ CJS dist/index.js 5.56 KB
17
+ CJS dist/index.js.map 10.39 KB
18
+ CJS ⚡️ Build success in 40ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 12435ms
21
- DTS dist/index.d.mts 1.50 KB
22
- DTS dist/index.d.ts 1.50 KB
20
+ DTS ⚡️ Build success in 12131ms
21
+ DTS dist/index.d.mts 1.65 KB
22
+ DTS dist/index.d.ts 1.65 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @objectstack/sveltekit
2
2
 
3
+ ## 3.2.9
4
+
5
+ ### Patch Changes
6
+
7
+ - @objectstack/runtime@3.2.9
8
+
9
+ ## 3.2.8
10
+
11
+ ### Patch Changes
12
+
13
+ - @objectstack/runtime@3.2.8
14
+
15
+ ## 3.2.8
16
+
17
+ ### Patch Changes
18
+
19
+ - fix: unified catch-all dispatch pattern — `createRequestHandler()` now delegates all non-framework-specific routes to `HttpDispatcher.dispatch()`, automatically supporting packages, analytics, automation, i18n, ui, openapi, custom endpoints, and any future routes
20
+ - Only auth (service check), storage (formData), GraphQL (raw result), and discovery (response wrapper) remain as explicit routes
21
+
3
22
  ## 3.2.7
4
23
 
5
24
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -16,6 +16,9 @@ interface RequestEvent {
16
16
  * Creates a SvelteKit request handler for ObjectStack API routes.
17
17
  * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.
18
18
  *
19
+ * Only auth, GraphQL, storage, and discovery need explicit handling.
20
+ * All other routes delegate to `HttpDispatcher.dispatch()` automatically.
21
+ *
19
22
  * @example
20
23
  * ```ts
21
24
  * // src/routes/api/[...path]/+server.ts
package/dist/index.d.ts CHANGED
@@ -16,6 +16,9 @@ interface RequestEvent {
16
16
  * Creates a SvelteKit request handler for ObjectStack API routes.
17
17
  * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.
18
18
  *
19
+ * Only auth, GraphQL, storage, and discovery need explicit handling.
20
+ * All other routes delegate to `HttpDispatcher.dispatch()` automatically.
21
+ *
19
22
  * @example
20
23
  * ```ts
21
24
  * // src/routes/api/[...path]/+server.ts
package/dist/index.js CHANGED
@@ -82,7 +82,7 @@ function createRequestHandler(options) {
82
82
  }
83
83
  try {
84
84
  if (segments[0] === "auth") {
85
- const subPath = segments.slice(1).join("/");
85
+ const subPath2 = segments.slice(1).join("/");
86
86
  let authService = null;
87
87
  try {
88
88
  if (typeof options.kernel.getServiceAsync === "function") {
@@ -96,67 +96,44 @@ function createRequestHandler(options) {
96
96
  if (authService && typeof authService.handleRequest === "function") {
97
97
  return await authService.handleRequest(request);
98
98
  }
99
- const body = method === "GET" || method === "HEAD" ? {} : await request.json().catch(() => ({}));
100
- const result = await dispatcher.handleAuth(subPath, method, body, { request });
101
- return toResponse(result);
99
+ const body2 = method === "GET" || method === "HEAD" ? {} : await request.json().catch(() => ({}));
100
+ const result2 = await dispatcher.handleAuth(subPath2, method, body2, { request });
101
+ return toResponse(result2);
102
102
  }
103
103
  if (segments[0] === "graphql" && method === "POST") {
104
- const body = await request.json();
105
- const result = await dispatcher.handleGraphQL(body, { request });
106
- return new Response(JSON.stringify(result), {
104
+ const body2 = await request.json();
105
+ const result2 = await dispatcher.handleGraphQL(body2, { request });
106
+ return new Response(JSON.stringify(result2), {
107
107
  status: 200,
108
108
  headers: { "Content-Type": "application/json" }
109
109
  });
110
110
  }
111
- if (segments[0] === "meta") {
112
- const subPath = segments.slice(1).join("/");
113
- let body = void 0;
114
- if (method === "PUT" || method === "POST") {
115
- body = await request.json().catch(() => ({}));
116
- }
117
- const result = await dispatcher.handleMetadata(
118
- subPath ? `/${subPath}` : "",
119
- { request },
120
- method,
121
- body
122
- );
123
- return toResponse(result);
124
- }
125
- if (segments[0] === "data") {
126
- const subPath = segments.slice(1).join("/");
127
- let body = {};
128
- if (method === "POST" || method === "PATCH") {
129
- body = await request.json().catch(() => ({}));
130
- }
131
- const queryParams = {};
132
- url.searchParams.forEach((val, key) => {
133
- queryParams[key] = val;
134
- });
135
- const result = await dispatcher.handleData(
136
- subPath ? `/${subPath}` : "",
137
- method,
138
- body,
139
- queryParams,
140
- { request }
141
- );
142
- return toResponse(result);
143
- }
144
111
  if (segments[0] === "storage") {
145
- const subPath = segments.slice(1).join("/");
112
+ const subPath2 = segments.slice(1).join("/");
146
113
  let file = void 0;
147
- if (method === "POST" && subPath === "upload") {
114
+ if (method === "POST" && subPath2 === "upload") {
148
115
  const formData = await request.formData();
149
116
  file = formData.get("file");
150
117
  }
151
- const result = await dispatcher.handleStorage(
152
- subPath ? `/${subPath}` : "",
118
+ const result2 = await dispatcher.handleStorage(
119
+ subPath2 ? `/${subPath2}` : "",
153
120
  method,
154
121
  file,
155
122
  { request }
156
123
  );
157
- return toResponse(result);
124
+ return toResponse(result2);
125
+ }
126
+ const subPath = path || "";
127
+ let body = void 0;
128
+ if (method === "POST" || method === "PUT" || method === "PATCH") {
129
+ body = await request.json().catch(() => ({}));
158
130
  }
159
- return errorJson("Not Found", 404);
131
+ const queryParams = {};
132
+ url.searchParams.forEach((val, key) => {
133
+ queryParams[key] = val;
134
+ });
135
+ const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request });
136
+ return toResponse(result);
160
137
  } catch (err) {
161
138
  return errorJson(err.message || "Internal Server Error", err.statusCode || 500);
162
139
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface SvelteKitAdapterOptions {\n kernel: ObjectKernel;\n prefix?: string;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * SvelteKit request event type (minimal interface to avoid hard dependency on @sveltejs/kit types at runtime)\n */\ninterface RequestEvent {\n request: Request;\n url: URL;\n params: Record<string, string>;\n}\n\n/**\n * Creates a SvelteKit request handler for ObjectStack API routes.\n * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { createRequestHandler } from '@objectstack/sveltekit';\n * import { kernel } from '$lib/kernel';\n *\n * const handler = createRequestHandler({ kernel });\n *\n * export const GET = handler;\n * export const POST = handler;\n * export const PUT = handler;\n * export const PATCH = handler;\n * export const DELETE = handler;\n * ```\n */\nexport function createRequestHandler(options: SvelteKitAdapterOptions) {\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (message: string, code: number = 500) => {\n return new Response(JSON.stringify({ success: false, error: { message, code } }), {\n status: code,\n headers: { 'Content-Type': 'application/json' },\n });\n };\n\n const toResponse = (result: HttpDispatcherResult): Response => {\n if (result.handled) {\n if (result.response) {\n const headers = new Headers({ 'Content-Type': 'application/json' });\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(JSON.stringify(result.response.body), {\n status: result.response.status,\n headers,\n });\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return new Response(null, {\n status: 302,\n headers: { Location: res.url },\n });\n }\n if (res.type === 'stream' && res.stream) {\n const headers = new Headers();\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(res.stream, { status: 200, headers });\n }\n return new Response(JSON.stringify(res), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n }\n return errorJson('Not Found', 404);\n };\n\n return async function handler(event: RequestEvent): Promise<Response> {\n const { request, url } = event;\n const method = request.method;\n const path = url.pathname.substring(prefix.length);\n const segments = path.split('/').filter(Boolean);\n\n // --- Discovery ---\n if (segments.length === 0 && method === 'GET') {\n return new Response(JSON.stringify({ data: await dispatcher.getDiscoveryInfo(prefix) }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n try {\n // --- Auth ---\n if (segments[0] === 'auth') {\n const subPath = segments.slice(1).join('/');\n\n // Try AuthPlugin service first (prefer async to support factory-based services)\n let authService: AuthService | null = null;\n try {\n if (typeof options.kernel.getServiceAsync === 'function') {\n authService = await options.kernel.getServiceAsync<AuthService>('auth');\n } else if (typeof options.kernel.getService === 'function') {\n authService = options.kernel.getService<AuthService>('auth');\n }\n } catch {\n // Service not registered — fall through to dispatcher\n authService = null;\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n return await authService.handleRequest(request);\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await request.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(subPath, method, body, { request });\n return toResponse(result);\n }\n\n // --- GraphQL ---\n if (segments[0] === 'graphql' && method === 'POST') {\n const body = await request.json() as { query: string; variables?: any };\n const result = await dispatcher.handleGraphQL(body, { request });\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // --- Metadata ---\n if (segments[0] === 'meta') {\n const subPath = segments.slice(1).join('/');\n let body: any = undefined;\n if (method === 'PUT' || method === 'POST') {\n body = await request.json().catch(() => ({}));\n }\n const result = await dispatcher.handleMetadata(\n subPath ? `/${subPath}` : '',\n { request },\n method,\n body,\n );\n return toResponse(result);\n }\n\n // --- Data ---\n if (segments[0] === 'data') {\n const subPath = segments.slice(1).join('/');\n let body: any = {};\n if (method === 'POST' || method === 'PATCH') {\n body = await request.json().catch(() => ({}));\n }\n const queryParams: Record<string, any> = {};\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.handleData(\n subPath ? `/${subPath}` : '',\n method,\n body,\n queryParams,\n { request },\n );\n return toResponse(result);\n }\n\n // --- Storage ---\n if (segments[0] === 'storage') {\n const subPath = segments.slice(1).join('/');\n let file: any = undefined;\n if (method === 'POST' && subPath === 'upload') {\n const formData = await request.formData();\n file = formData.get('file');\n }\n const result = await dispatcher.handleStorage(\n subPath ? `/${subPath}` : '',\n method,\n file,\n { request },\n );\n return toResponse(result);\n }\n\n return errorJson('Not Found', 404);\n } catch (err: any) {\n return errorJson(err.message || 'Internal Server Error', err.statusCode || 500);\n }\n };\n}\n\n/**\n * Creates a SvelteKit handle hook that attaches the kernel to event.locals.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { createHandle } from '@objectstack/sveltekit';\n * export const handle = createHandle({ kernel });\n * ```\n */\nexport function createHandle(options: SvelteKitAdapterOptions) {\n return async function handle({ event, resolve }: { event: any; resolve: (event: any) => Promise<Response> }) {\n event.locals.objectStack = options.kernel;\n return resolve(event);\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface SvelteKitAdapterOptions {\n kernel: ObjectKernel;\n prefix?: string;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * SvelteKit request event type (minimal interface to avoid hard dependency on @sveltejs/kit types at runtime)\n */\ninterface RequestEvent {\n request: Request;\n url: URL;\n params: Record<string, string>;\n}\n\n/**\n * Creates a SvelteKit request handler for ObjectStack API routes.\n * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.\n *\n * Only auth, GraphQL, storage, and discovery need explicit handling.\n * All other routes delegate to `HttpDispatcher.dispatch()` automatically.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { createRequestHandler } from '@objectstack/sveltekit';\n * import { kernel } from '$lib/kernel';\n *\n * const handler = createRequestHandler({ kernel });\n *\n * export const GET = handler;\n * export const POST = handler;\n * export const PUT = handler;\n * export const PATCH = handler;\n * export const DELETE = handler;\n * ```\n */\nexport function createRequestHandler(options: SvelteKitAdapterOptions) {\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (message: string, code: number = 500) => {\n return new Response(JSON.stringify({ success: false, error: { message, code } }), {\n status: code,\n headers: { 'Content-Type': 'application/json' },\n });\n };\n\n const toResponse = (result: HttpDispatcherResult): Response => {\n if (result.handled) {\n if (result.response) {\n const headers = new Headers({ 'Content-Type': 'application/json' });\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(JSON.stringify(result.response.body), {\n status: result.response.status,\n headers,\n });\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return new Response(null, {\n status: 302,\n headers: { Location: res.url },\n });\n }\n if (res.type === 'stream' && res.stream) {\n const headers = new Headers();\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(res.stream, { status: 200, headers });\n }\n return new Response(JSON.stringify(res), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n }\n return errorJson('Not Found', 404);\n };\n\n return async function handler(event: RequestEvent): Promise<Response> {\n const { request, url } = event;\n const method = request.method;\n const path = url.pathname.substring(prefix.length);\n const segments = path.split('/').filter(Boolean);\n\n // --- Discovery ---\n if (segments.length === 0 && method === 'GET') {\n return new Response(JSON.stringify({ data: await dispatcher.getDiscoveryInfo(prefix) }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n try {\n // --- Auth (needs auth service integration) ---\n if (segments[0] === 'auth') {\n const subPath = segments.slice(1).join('/');\n\n // Try AuthPlugin service first (prefer async to support factory-based services)\n let authService: AuthService | null = null;\n try {\n if (typeof options.kernel.getServiceAsync === 'function') {\n authService = await options.kernel.getServiceAsync<AuthService>('auth');\n } else if (typeof options.kernel.getService === 'function') {\n authService = options.kernel.getService<AuthService>('auth');\n }\n } catch {\n // Service not registered — fall through to dispatcher\n authService = null;\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n return await authService.handleRequest(request);\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await request.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(subPath, method, body, { request });\n return toResponse(result);\n }\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n if (segments[0] === 'graphql' && method === 'POST') {\n const body = await request.json() as { query: string; variables?: any };\n const result = await dispatcher.handleGraphQL(body, { request });\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // --- Storage (needs formData parsing) ---\n if (segments[0] === 'storage') {\n const subPath = segments.slice(1).join('/');\n let file: any = undefined;\n if (method === 'POST' && subPath === 'upload') {\n const formData = await request.formData();\n file = formData.get('file');\n }\n const result = await dispatcher.handleStorage(\n subPath ? `/${subPath}` : '',\n method,\n file,\n { request },\n );\n return toResponse(result);\n }\n\n // --- Catch-all: delegate to dispatcher.dispatch() ---\n // Handles meta, data, packages, analytics, automation, i18n, ui,\n // openapi, custom API endpoints, and any future routes.\n const subPath = path || '';\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await request.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request });\n return toResponse(result);\n } catch (err: any) {\n return errorJson(err.message || 'Internal Server Error', err.statusCode || 500);\n }\n };\n}\n\n/**\n * Creates a SvelteKit handle hook that attaches the kernel to event.locals.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { createHandle } from '@objectstack/sveltekit';\n * export const handle = createHandle({ kernel });\n * ```\n */\nexport function createHandle(options: SvelteKitAdapterOptions) {\n return async function handle({ event, resolve }: { event: any; resolve: (event: any) => Promise<Response> }) {\n event.locals.objectStack = options.kernel;\n return resolve(event);\n };\n}\n"],"mappings":"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","names":["subPath","body","result"]}
package/dist/index.mjs CHANGED
@@ -57,7 +57,7 @@ function createRequestHandler(options) {
57
57
  }
58
58
  try {
59
59
  if (segments[0] === "auth") {
60
- const subPath = segments.slice(1).join("/");
60
+ const subPath2 = segments.slice(1).join("/");
61
61
  let authService = null;
62
62
  try {
63
63
  if (typeof options.kernel.getServiceAsync === "function") {
@@ -71,67 +71,44 @@ function createRequestHandler(options) {
71
71
  if (authService && typeof authService.handleRequest === "function") {
72
72
  return await authService.handleRequest(request);
73
73
  }
74
- const body = method === "GET" || method === "HEAD" ? {} : await request.json().catch(() => ({}));
75
- const result = await dispatcher.handleAuth(subPath, method, body, { request });
76
- return toResponse(result);
74
+ const body2 = method === "GET" || method === "HEAD" ? {} : await request.json().catch(() => ({}));
75
+ const result2 = await dispatcher.handleAuth(subPath2, method, body2, { request });
76
+ return toResponse(result2);
77
77
  }
78
78
  if (segments[0] === "graphql" && method === "POST") {
79
- const body = await request.json();
80
- const result = await dispatcher.handleGraphQL(body, { request });
81
- return new Response(JSON.stringify(result), {
79
+ const body2 = await request.json();
80
+ const result2 = await dispatcher.handleGraphQL(body2, { request });
81
+ return new Response(JSON.stringify(result2), {
82
82
  status: 200,
83
83
  headers: { "Content-Type": "application/json" }
84
84
  });
85
85
  }
86
- if (segments[0] === "meta") {
87
- const subPath = segments.slice(1).join("/");
88
- let body = void 0;
89
- if (method === "PUT" || method === "POST") {
90
- body = await request.json().catch(() => ({}));
91
- }
92
- const result = await dispatcher.handleMetadata(
93
- subPath ? `/${subPath}` : "",
94
- { request },
95
- method,
96
- body
97
- );
98
- return toResponse(result);
99
- }
100
- if (segments[0] === "data") {
101
- const subPath = segments.slice(1).join("/");
102
- let body = {};
103
- if (method === "POST" || method === "PATCH") {
104
- body = await request.json().catch(() => ({}));
105
- }
106
- const queryParams = {};
107
- url.searchParams.forEach((val, key) => {
108
- queryParams[key] = val;
109
- });
110
- const result = await dispatcher.handleData(
111
- subPath ? `/${subPath}` : "",
112
- method,
113
- body,
114
- queryParams,
115
- { request }
116
- );
117
- return toResponse(result);
118
- }
119
86
  if (segments[0] === "storage") {
120
- const subPath = segments.slice(1).join("/");
87
+ const subPath2 = segments.slice(1).join("/");
121
88
  let file = void 0;
122
- if (method === "POST" && subPath === "upload") {
89
+ if (method === "POST" && subPath2 === "upload") {
123
90
  const formData = await request.formData();
124
91
  file = formData.get("file");
125
92
  }
126
- const result = await dispatcher.handleStorage(
127
- subPath ? `/${subPath}` : "",
93
+ const result2 = await dispatcher.handleStorage(
94
+ subPath2 ? `/${subPath2}` : "",
128
95
  method,
129
96
  file,
130
97
  { request }
131
98
  );
132
- return toResponse(result);
99
+ return toResponse(result2);
100
+ }
101
+ const subPath = path || "";
102
+ let body = void 0;
103
+ if (method === "POST" || method === "PUT" || method === "PATCH") {
104
+ body = await request.json().catch(() => ({}));
133
105
  }
134
- return errorJson("Not Found", 404);
106
+ const queryParams = {};
107
+ url.searchParams.forEach((val, key) => {
108
+ queryParams[key] = val;
109
+ });
110
+ const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request });
111
+ return toResponse(result);
135
112
  } catch (err) {
136
113
  return errorJson(err.message || "Internal Server Error", err.statusCode || 500);
137
114
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface SvelteKitAdapterOptions {\n kernel: ObjectKernel;\n prefix?: string;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * SvelteKit request event type (minimal interface to avoid hard dependency on @sveltejs/kit types at runtime)\n */\ninterface RequestEvent {\n request: Request;\n url: URL;\n params: Record<string, string>;\n}\n\n/**\n * Creates a SvelteKit request handler for ObjectStack API routes.\n * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { createRequestHandler } from '@objectstack/sveltekit';\n * import { kernel } from '$lib/kernel';\n *\n * const handler = createRequestHandler({ kernel });\n *\n * export const GET = handler;\n * export const POST = handler;\n * export const PUT = handler;\n * export const PATCH = handler;\n * export const DELETE = handler;\n * ```\n */\nexport function createRequestHandler(options: SvelteKitAdapterOptions) {\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (message: string, code: number = 500) => {\n return new Response(JSON.stringify({ success: false, error: { message, code } }), {\n status: code,\n headers: { 'Content-Type': 'application/json' },\n });\n };\n\n const toResponse = (result: HttpDispatcherResult): Response => {\n if (result.handled) {\n if (result.response) {\n const headers = new Headers({ 'Content-Type': 'application/json' });\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(JSON.stringify(result.response.body), {\n status: result.response.status,\n headers,\n });\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return new Response(null, {\n status: 302,\n headers: { Location: res.url },\n });\n }\n if (res.type === 'stream' && res.stream) {\n const headers = new Headers();\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(res.stream, { status: 200, headers });\n }\n return new Response(JSON.stringify(res), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n }\n return errorJson('Not Found', 404);\n };\n\n return async function handler(event: RequestEvent): Promise<Response> {\n const { request, url } = event;\n const method = request.method;\n const path = url.pathname.substring(prefix.length);\n const segments = path.split('/').filter(Boolean);\n\n // --- Discovery ---\n if (segments.length === 0 && method === 'GET') {\n return new Response(JSON.stringify({ data: await dispatcher.getDiscoveryInfo(prefix) }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n try {\n // --- Auth ---\n if (segments[0] === 'auth') {\n const subPath = segments.slice(1).join('/');\n\n // Try AuthPlugin service first (prefer async to support factory-based services)\n let authService: AuthService | null = null;\n try {\n if (typeof options.kernel.getServiceAsync === 'function') {\n authService = await options.kernel.getServiceAsync<AuthService>('auth');\n } else if (typeof options.kernel.getService === 'function') {\n authService = options.kernel.getService<AuthService>('auth');\n }\n } catch {\n // Service not registered — fall through to dispatcher\n authService = null;\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n return await authService.handleRequest(request);\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await request.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(subPath, method, body, { request });\n return toResponse(result);\n }\n\n // --- GraphQL ---\n if (segments[0] === 'graphql' && method === 'POST') {\n const body = await request.json() as { query: string; variables?: any };\n const result = await dispatcher.handleGraphQL(body, { request });\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // --- Metadata ---\n if (segments[0] === 'meta') {\n const subPath = segments.slice(1).join('/');\n let body: any = undefined;\n if (method === 'PUT' || method === 'POST') {\n body = await request.json().catch(() => ({}));\n }\n const result = await dispatcher.handleMetadata(\n subPath ? `/${subPath}` : '',\n { request },\n method,\n body,\n );\n return toResponse(result);\n }\n\n // --- Data ---\n if (segments[0] === 'data') {\n const subPath = segments.slice(1).join('/');\n let body: any = {};\n if (method === 'POST' || method === 'PATCH') {\n body = await request.json().catch(() => ({}));\n }\n const queryParams: Record<string, any> = {};\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.handleData(\n subPath ? `/${subPath}` : '',\n method,\n body,\n queryParams,\n { request },\n );\n return toResponse(result);\n }\n\n // --- Storage ---\n if (segments[0] === 'storage') {\n const subPath = segments.slice(1).join('/');\n let file: any = undefined;\n if (method === 'POST' && subPath === 'upload') {\n const formData = await request.formData();\n file = formData.get('file');\n }\n const result = await dispatcher.handleStorage(\n subPath ? `/${subPath}` : '',\n method,\n file,\n { request },\n );\n return toResponse(result);\n }\n\n return errorJson('Not Found', 404);\n } catch (err: any) {\n return errorJson(err.message || 'Internal Server Error', err.statusCode || 500);\n }\n };\n}\n\n/**\n * Creates a SvelteKit handle hook that attaches the kernel to event.locals.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { createHandle } from '@objectstack/sveltekit';\n * export const handle = createHandle({ kernel });\n * ```\n */\nexport function createHandle(options: SvelteKitAdapterOptions) {\n return async function handle({ event, resolve }: { event: any; resolve: (event: any) => Promise<Response> }) {\n event.locals.objectStack = options.kernel;\n return resolve(event);\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface SvelteKitAdapterOptions {\n kernel: ObjectKernel;\n prefix?: string;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * SvelteKit request event type (minimal interface to avoid hard dependency on @sveltejs/kit types at runtime)\n */\ninterface RequestEvent {\n request: Request;\n url: URL;\n params: Record<string, string>;\n}\n\n/**\n * Creates a SvelteKit request handler for ObjectStack API routes.\n * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.\n *\n * Only auth, GraphQL, storage, and discovery need explicit handling.\n * All other routes delegate to `HttpDispatcher.dispatch()` automatically.\n *\n * @example\n * ```ts\n * // src/routes/api/[...path]/+server.ts\n * import { createRequestHandler } from '@objectstack/sveltekit';\n * import { kernel } from '$lib/kernel';\n *\n * const handler = createRequestHandler({ kernel });\n *\n * export const GET = handler;\n * export const POST = handler;\n * export const PUT = handler;\n * export const PATCH = handler;\n * export const DELETE = handler;\n * ```\n */\nexport function createRequestHandler(options: SvelteKitAdapterOptions) {\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (message: string, code: number = 500) => {\n return new Response(JSON.stringify({ success: false, error: { message, code } }), {\n status: code,\n headers: { 'Content-Type': 'application/json' },\n });\n };\n\n const toResponse = (result: HttpDispatcherResult): Response => {\n if (result.handled) {\n if (result.response) {\n const headers = new Headers({ 'Content-Type': 'application/json' });\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(JSON.stringify(result.response.body), {\n status: result.response.status,\n headers,\n });\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return new Response(null, {\n status: 302,\n headers: { Location: res.url },\n });\n }\n if (res.type === 'stream' && res.stream) {\n const headers = new Headers();\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => headers.set(k, v as string));\n }\n return new Response(res.stream, { status: 200, headers });\n }\n return new Response(JSON.stringify(res), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n }\n return errorJson('Not Found', 404);\n };\n\n return async function handler(event: RequestEvent): Promise<Response> {\n const { request, url } = event;\n const method = request.method;\n const path = url.pathname.substring(prefix.length);\n const segments = path.split('/').filter(Boolean);\n\n // --- Discovery ---\n if (segments.length === 0 && method === 'GET') {\n return new Response(JSON.stringify({ data: await dispatcher.getDiscoveryInfo(prefix) }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n try {\n // --- Auth (needs auth service integration) ---\n if (segments[0] === 'auth') {\n const subPath = segments.slice(1).join('/');\n\n // Try AuthPlugin service first (prefer async to support factory-based services)\n let authService: AuthService | null = null;\n try {\n if (typeof options.kernel.getServiceAsync === 'function') {\n authService = await options.kernel.getServiceAsync<AuthService>('auth');\n } else if (typeof options.kernel.getService === 'function') {\n authService = options.kernel.getService<AuthService>('auth');\n }\n } catch {\n // Service not registered — fall through to dispatcher\n authService = null;\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n return await authService.handleRequest(request);\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await request.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(subPath, method, body, { request });\n return toResponse(result);\n }\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n if (segments[0] === 'graphql' && method === 'POST') {\n const body = await request.json() as { query: string; variables?: any };\n const result = await dispatcher.handleGraphQL(body, { request });\n return new Response(JSON.stringify(result), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // --- Storage (needs formData parsing) ---\n if (segments[0] === 'storage') {\n const subPath = segments.slice(1).join('/');\n let file: any = undefined;\n if (method === 'POST' && subPath === 'upload') {\n const formData = await request.formData();\n file = formData.get('file');\n }\n const result = await dispatcher.handleStorage(\n subPath ? `/${subPath}` : '',\n method,\n file,\n { request },\n );\n return toResponse(result);\n }\n\n // --- Catch-all: delegate to dispatcher.dispatch() ---\n // Handles meta, data, packages, analytics, automation, i18n, ui,\n // openapi, custom API endpoints, and any future routes.\n const subPath = path || '';\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await request.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request });\n return toResponse(result);\n } catch (err: any) {\n return errorJson(err.message || 'Internal Server Error', err.statusCode || 500);\n }\n };\n}\n\n/**\n * Creates a SvelteKit handle hook that attaches the kernel to event.locals.\n *\n * @example\n * ```ts\n * // src/hooks.server.ts\n * import { createHandle } from '@objectstack/sveltekit';\n * export const handle = createHandle({ kernel });\n * ```\n */\nexport function createHandle(options: SvelteKitAdapterOptions) {\n return async function handle({ event, resolve }: { event: any; resolve: (event: any) => Promise<Response> }) {\n event.locals.objectStack = options.kernel;\n return resolve(event);\n };\n}\n"],"mappings":"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","names":["subPath","body","result"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/sveltekit",
3
- "version": "3.2.7",
3
+ "version": "3.2.9",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,14 +12,14 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@sveltejs/kit": "^2.53.4",
16
- "@objectstack/runtime": "^3.2.7"
15
+ "@sveltejs/kit": "^2.55.0",
16
+ "@objectstack/runtime": "^3.2.9"
17
17
  },
18
18
  "devDependencies": {
19
- "@sveltejs/kit": "^2.53.4",
19
+ "@sveltejs/kit": "^2.55.0",
20
20
  "typescript": "^5.0.0",
21
- "vitest": "^4.0.18",
22
- "@objectstack/runtime": "3.2.7"
21
+ "vitest": "^4.1.0",
22
+ "@objectstack/runtime": "3.2.9"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup --config ../../../tsup.config.ts",
package/src/index.ts CHANGED
@@ -27,6 +27,9 @@ interface RequestEvent {
27
27
  * Creates a SvelteKit request handler for ObjectStack API routes.
28
28
  * Use in a catch-all `+server.ts` route like `src/routes/api/[...path]/+server.ts`.
29
29
  *
30
+ * Only auth, GraphQL, storage, and discovery need explicit handling.
31
+ * All other routes delegate to `HttpDispatcher.dispatch()` automatically.
32
+ *
30
33
  * @example
31
34
  * ```ts
32
35
  * // src/routes/api/[...path]/+server.ts
@@ -104,7 +107,7 @@ export function createRequestHandler(options: SvelteKitAdapterOptions) {
104
107
  }
105
108
 
106
109
  try {
107
- // --- Auth ---
110
+ // --- Auth (needs auth service integration) ---
108
111
  if (segments[0] === 'auth') {
109
112
  const subPath = segments.slice(1).join('/');
110
113
 
@@ -133,7 +136,7 @@ export function createRequestHandler(options: SvelteKitAdapterOptions) {
133
136
  return toResponse(result);
134
137
  }
135
138
 
136
- // --- GraphQL ---
139
+ // --- GraphQL (returns raw result, not HttpDispatcherResult) ---
137
140
  if (segments[0] === 'graphql' && method === 'POST') {
138
141
  const body = await request.json() as { query: string; variables?: any };
139
142
  const result = await dispatcher.handleGraphQL(body, { request });
@@ -143,43 +146,7 @@ export function createRequestHandler(options: SvelteKitAdapterOptions) {
143
146
  });
144
147
  }
145
148
 
146
- // --- Metadata ---
147
- if (segments[0] === 'meta') {
148
- const subPath = segments.slice(1).join('/');
149
- let body: any = undefined;
150
- if (method === 'PUT' || method === 'POST') {
151
- body = await request.json().catch(() => ({}));
152
- }
153
- const result = await dispatcher.handleMetadata(
154
- subPath ? `/${subPath}` : '',
155
- { request },
156
- method,
157
- body,
158
- );
159
- return toResponse(result);
160
- }
161
-
162
- // --- Data ---
163
- if (segments[0] === 'data') {
164
- const subPath = segments.slice(1).join('/');
165
- let body: any = {};
166
- if (method === 'POST' || method === 'PATCH') {
167
- body = await request.json().catch(() => ({}));
168
- }
169
- const queryParams: Record<string, any> = {};
170
- url.searchParams.forEach((val, key) => { queryParams[key] = val; });
171
-
172
- const result = await dispatcher.handleData(
173
- subPath ? `/${subPath}` : '',
174
- method,
175
- body,
176
- queryParams,
177
- { request },
178
- );
179
- return toResponse(result);
180
- }
181
-
182
- // --- Storage ---
149
+ // --- Storage (needs formData parsing) ---
183
150
  if (segments[0] === 'storage') {
184
151
  const subPath = segments.slice(1).join('/');
185
152
  let file: any = undefined;
@@ -196,7 +163,21 @@ export function createRequestHandler(options: SvelteKitAdapterOptions) {
196
163
  return toResponse(result);
197
164
  }
198
165
 
199
- return errorJson('Not Found', 404);
166
+ // --- Catch-all: delegate to dispatcher.dispatch() ---
167
+ // Handles meta, data, packages, analytics, automation, i18n, ui,
168
+ // openapi, custom API endpoints, and any future routes.
169
+ const subPath = path || '';
170
+
171
+ let body: any = undefined;
172
+ if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
173
+ body = await request.json().catch(() => ({}));
174
+ }
175
+
176
+ const queryParams: Record<string, any> = {};
177
+ url.searchParams.forEach((val, key) => { queryParams[key] = val; });
178
+
179
+ const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request });
180
+ return toResponse(result);
200
181
  } catch (err: any) {
201
182
  return errorJson(err.message || 'Internal Server Error', err.statusCode || 500);
202
183
  }
@@ -7,9 +7,8 @@ const mockDispatcher = {
7
7
  getDiscoveryInfo: vi.fn().mockReturnValue({ version: '1.0', endpoints: [] }),
8
8
  handleAuth: vi.fn().mockResolvedValue({ handled: true, response: { body: { ok: true }, status: 200 } }),
9
9
  handleGraphQL: vi.fn().mockResolvedValue({ data: {} }),
10
- handleMetadata: vi.fn().mockResolvedValue({ handled: true, response: { body: { objects: [] }, status: 200 } }),
11
- handleData: vi.fn().mockResolvedValue({ handled: true, response: { body: { records: [] }, status: 200 } }),
12
10
  handleStorage: vi.fn().mockResolvedValue({ handled: true, response: { body: {}, status: 200 } }),
11
+ dispatch: vi.fn().mockResolvedValue({ handled: true, response: { body: { success: true }, status: 200 } }),
13
12
  };
14
13
 
15
14
  vi.mock('@objectstack/runtime', () => {
@@ -167,27 +166,29 @@ describe('createRequestHandler', () => {
167
166
  });
168
167
 
169
168
  describe('Metadata', () => {
170
- it('GET /api/meta/objects calls handleMetadata', async () => {
169
+ it('GET /api/meta/objects delegates to dispatch()', async () => {
171
170
  const event = makeEvent('http://localhost/api/meta/objects');
172
171
  const res = await handler(event);
173
172
  expect(res.status).toBe(200);
174
- expect(mockDispatcher.handleMetadata).toHaveBeenCalledWith(
175
- '/objects',
173
+ expect(mockDispatcher.dispatch).toHaveBeenCalledWith(
174
+ 'GET',
175
+ '/meta/objects',
176
+ undefined,
177
+ expect.any(Object),
176
178
  expect.objectContaining({ request: expect.anything() }),
177
- 'GET', undefined,
178
179
  );
179
180
  });
180
181
  });
181
182
 
182
183
  describe('Data', () => {
183
- it('GET /api/data/account calls handleData', async () => {
184
+ it('GET /api/data/account delegates to dispatch()', async () => {
184
185
  const event = makeEvent('http://localhost/api/data/account');
185
186
  const res = await handler(event);
186
187
  expect(res.status).toBe(200);
187
- const json = await res.json();
188
- expect(json.records).toBeDefined();
189
- expect(mockDispatcher.handleData).toHaveBeenCalledWith(
190
- '/account', 'GET', {},
188
+ expect(mockDispatcher.dispatch).toHaveBeenCalledWith(
189
+ 'GET',
190
+ '/data/account',
191
+ undefined,
191
192
  expect.any(Object),
192
193
  expect.objectContaining({ request: expect.anything() }),
193
194
  );
@@ -198,15 +199,17 @@ describe('createRequestHandler', () => {
198
199
  const event = makeEvent('http://localhost/api/data/account', 'POST', body);
199
200
  const res = await handler(event);
200
201
  expect(res.status).toBe(200);
201
- expect(mockDispatcher.handleData).toHaveBeenCalledWith(
202
- '/account', 'POST', body,
202
+ expect(mockDispatcher.dispatch).toHaveBeenCalledWith(
203
+ 'POST',
204
+ '/data/account',
205
+ body,
203
206
  expect.any(Object),
204
207
  expect.objectContaining({ request: expect.anything() }),
205
208
  );
206
209
  });
207
210
 
208
211
  it('returns 404 when not handled', async () => {
209
- mockDispatcher.handleData.mockResolvedValueOnce({ handled: false });
212
+ mockDispatcher.dispatch.mockResolvedValueOnce({ handled: false });
210
213
  const event = makeEvent('http://localhost/api/data/missing');
211
214
  const res = await handler(event);
212
215
  expect(res.status).toBe(404);
@@ -227,13 +230,14 @@ describe('createRequestHandler', () => {
227
230
 
228
231
  describe('Error handling', () => {
229
232
  it('returns 404 for unknown routes', async () => {
233
+ mockDispatcher.dispatch.mockResolvedValueOnce({ handled: false });
230
234
  const event = makeEvent('http://localhost/api/unknown');
231
235
  const res = await handler(event);
232
236
  expect(res.status).toBe(404);
233
237
  });
234
238
 
235
239
  it('returns 500 on generic error', async () => {
236
- mockDispatcher.handleData.mockRejectedValueOnce(new Error());
240
+ mockDispatcher.dispatch.mockRejectedValueOnce(new Error());
237
241
  const event = makeEvent('http://localhost/api/data/account');
238
242
  const res = await handler(event);
239
243
  expect(res.status).toBe(500);
@@ -242,7 +246,7 @@ describe('createRequestHandler', () => {
242
246
 
243
247
  describe('toResponse', () => {
244
248
  it('handles redirect result', async () => {
245
- mockDispatcher.handleData.mockResolvedValueOnce({
249
+ mockDispatcher.dispatch.mockResolvedValueOnce({
246
250
  handled: true,
247
251
  result: { type: 'redirect', url: 'https://example.com' },
248
252
  });
@@ -253,7 +257,7 @@ describe('createRequestHandler', () => {
253
257
  });
254
258
 
255
259
  it('handles generic result objects', async () => {
256
- mockDispatcher.handleData.mockResolvedValueOnce({
260
+ mockDispatcher.dispatch.mockResolvedValueOnce({
257
261
  handled: true,
258
262
  result: { foo: 'bar' },
259
263
  });