@objectstack/nuxt 3.3.1 → 4.0.0

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/nuxt@3.3.1 build /home/runner/work/spec/spec/packages/adapters/nuxt
2
+ > @objectstack/nuxt@4.0.0 build /home/runner/work/spec/spec/packages/adapters/nuxt
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
- CJS dist/index.js 6.90 KB
14
- CJS dist/index.js.map 12.03 KB
15
- CJS ⚡️ Build success in 81ms
16
- ESM dist/index.mjs 5.71 KB
17
- ESM dist/index.mjs.map 12.06 KB
18
- ESM ⚡️ Build success in 91ms
13
+ CJS dist/index.js 6.89 KB
14
+ CJS dist/index.js.map 12.02 KB
15
+ CJS ⚡️ Build success in 42ms
16
+ ESM dist/index.mjs 5.70 KB
17
+ ESM dist/index.mjs.map 12.04 KB
18
+ ESM ⚡️ Build success in 44ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 12660ms
20
+ DTS ⚡️ Build success in 13541ms
21
21
  DTS dist/index.d.mts 1015.00 B
22
22
  DTS dist/index.d.ts 1015.00 B
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @objectstack/nuxt
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - f08ffc3: Fix discovery API endpoint routing and protocol consistency.
8
+
9
+ **Discovery route standardization:**
10
+
11
+ - All adapters (Express, Fastify, Hono, NestJS, Next.js, Nuxt, SvelteKit) now mount the discovery endpoint at `{prefix}/discovery` instead of `{prefix}` root.
12
+ - `.well-known/objectstack` redirects now point to `{prefix}/discovery`.
13
+ - Client `connect()` fallback URL changed from `/api/v1` to `/api/v1/discovery`.
14
+ - Runtime dispatcher handles both `/discovery` (standard) and `/` (legacy) for backward compatibility.
15
+
16
+ **Schema & route alignment:**
17
+
18
+ - Added `storage` (service: `file-storage`) and `feed` (service: `data`) routes to `DEFAULT_DISPATCHER_ROUTES`.
19
+ - Added `feed` and `discovery` fields to `ApiRoutesSchema`.
20
+ - Unified `GetDiscoveryResponseSchema` with `DiscoverySchema` as single source of truth.
21
+ - Client `getRoute('feed')` fallback updated from `/api/v1/data` to `/api/v1/feed`.
22
+
23
+ **Type safety:**
24
+
25
+ - Extracted `ApiRouteType` from `ApiRoutes` keys for type-safe client route resolution.
26
+ - Removed `as any` type casting in client route access.
27
+
28
+ - Updated dependencies [f08ffc3]
29
+ - Updated dependencies [e0b0a78]
30
+ - @objectstack/runtime@4.0.0
31
+
3
32
  ## 3.3.1
4
33
 
5
34
  ### Patch Changes
package/dist/index.js CHANGED
@@ -63,7 +63,7 @@ function createH3Router(options) {
63
63
  return errorJson(event, "Not Found", 404);
64
64
  };
65
65
  router.get(
66
- `${prefix}`,
66
+ prefix,
67
67
  (0, import_h3.defineEventHandler)(async () => {
68
68
  return { data: await dispatcher.getDiscoveryInfo(prefix) };
69
69
  })
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 {\n createRouter,\n defineEventHandler,\n getQuery,\n readBody,\n sendRedirect,\n setResponseHeader,\n setResponseStatus,\n type H3Event,\n type Router,\n} from 'h3';\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface NuxtAdapterOptions {\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 * Creates an h3 router with all ObjectStack route dispatchers.\n * Designed for use in Nuxt server routes or standalone h3 apps.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * file upload, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes are handled by a catch-all that delegates to\n * `HttpDispatcher.dispatch()`, making the adapter automatically support\n * new routes added to the dispatcher.\n *\n * @example\n * ```ts\n * // server/api/[...].ts\n * import { createH3Router } from '@objectstack/nuxt';\n * import { kernel } from '../kernel';\n *\n * const router = createH3Router({ kernel });\n * export default defineEventHandler(router.handler);\n * ```\n */\nexport function createH3Router(options: NuxtAdapterOptions): Router {\n const router = createRouter();\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (event: H3Event, message: string, code: number = 500) => {\n setResponseStatus(event, code);\n return { success: false, error: { message, code } };\n };\n\n const toResponse = (event: H3Event, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n setResponseStatus(event, result.response.status);\n return result.response.body;\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return sendRedirect(event, res.url);\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n return res.stream;\n }\n return res;\n }\n }\n return errorJson(event, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n router.get(\n `${prefix}`,\n defineEventHandler(async () => {\n return { data: await dispatcher.getDiscoveryInfo(prefix) };\n }),\n );\n\n // --- .well-known ---\n router.get(\n '/.well-known/objectstack',\n defineEventHandler((event) => {\n return sendRedirect(event, prefix);\n }),\n );\n\n // --- Auth (needs auth service integration) ---\n router.use(\n `${prefix}/auth/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = event.path || event.node.req.url || '';\n const path = urlPath.substring(`${prefix}/auth/`.length).split('?')[0];\n const method = event.method;\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 const host = event.node.req.headers.host || 'localhost';\n const protocol = (event.node.req.socket as any)?.encrypted ? 'https' : 'http';\n const url = `${protocol}://${host}${urlPath}`;\n const headers = new Headers();\n if (event.node.req.headers) {\n Object.entries(event.node.req.headers).forEach(([k, v]) => {\n if (typeof v === 'string') headers.set(k, v);\n else if (Array.isArray(v)) headers.set(k, v.join(', '));\n });\n }\n const init: RequestInit = { method, headers };\n if (method !== 'GET' && method !== 'HEAD') {\n const body = await readBody(event);\n if (body) {\n init.body = typeof body === 'string' ? body : JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n }\n }\n const webRequest = new Request(url, init);\n const response = await authService.handleRequest(webRequest);\n setResponseStatus(event, response.status);\n response.headers.forEach((v: string, k: string) => setResponseHeader(event, k, v));\n return await response.text();\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await readBody(event).catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n router.post(\n `${prefix}/graphql`,\n defineEventHandler(async (event) => {\n try {\n const body = await readBody(event);\n const result = await dispatcher.handleGraphQL(body, { request: event.node.req });\n return result;\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- Storage (needs multipart form parsing) ---\n router.use(\n `${prefix}/storage/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(`${prefix}/storage`.length);\n const method = event.method;\n const file = undefined; // File upload requires multipart parsing (e.g., formidable)\n const result = await dispatcher.handleStorage(subPath, method, file, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // ─── Catch-all: delegate to dispatcher.dispatch() ─────────────────────────\n // Handles meta, data, packages, analytics, automation, i18n, ui, openapi,\n // custom API endpoints, and any future routes added to HttpDispatcher.\n router.use(\n `${prefix}/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(prefix.length);\n const method = event.method;\n const body = (method === 'POST' || method === 'PUT' || method === 'PATCH')\n ? await readBody(event)\n : undefined;\n const query = getQuery(event);\n const result = await dispatcher.dispatch(method, subPath, body, query, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n return router;\n}\n"],"mappings":"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","names":["body"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport {\n createRouter,\n defineEventHandler,\n getQuery,\n readBody,\n sendRedirect,\n setResponseHeader,\n setResponseStatus,\n type H3Event,\n type Router,\n} from 'h3';\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface NuxtAdapterOptions {\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 * Creates an h3 router with all ObjectStack route dispatchers.\n * Designed for use in Nuxt server routes or standalone h3 apps.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * file upload, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes are handled by a catch-all that delegates to\n * `HttpDispatcher.dispatch()`, making the adapter automatically support\n * new routes added to the dispatcher.\n *\n * @example\n * ```ts\n * // server/api/[...].ts\n * import { createH3Router } from '@objectstack/nuxt';\n * import { kernel } from '../kernel';\n *\n * const router = createH3Router({ kernel });\n * export default defineEventHandler(router.handler);\n * ```\n */\nexport function createH3Router(options: NuxtAdapterOptions): Router {\n const router = createRouter();\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (event: H3Event, message: string, code: number = 500) => {\n setResponseStatus(event, code);\n return { success: false, error: { message, code } };\n };\n\n const toResponse = (event: H3Event, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n setResponseStatus(event, result.response.status);\n return result.response.body;\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return sendRedirect(event, res.url);\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n return res.stream;\n }\n return res;\n }\n }\n return errorJson(event, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n router.get(\n prefix,\n defineEventHandler(async () => {\n return { data: await dispatcher.getDiscoveryInfo(prefix) };\n }),\n );\n\n // --- .well-known ---\n router.get(\n '/.well-known/objectstack',\n defineEventHandler((event) => {\n return sendRedirect(event, prefix);\n }),\n );\n\n // --- Auth (needs auth service integration) ---\n router.use(\n `${prefix}/auth/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = event.path || event.node.req.url || '';\n const path = urlPath.substring(`${prefix}/auth/`.length).split('?')[0];\n const method = event.method;\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 const host = event.node.req.headers.host || 'localhost';\n const protocol = (event.node.req.socket as any)?.encrypted ? 'https' : 'http';\n const url = `${protocol}://${host}${urlPath}`;\n const headers = new Headers();\n if (event.node.req.headers) {\n Object.entries(event.node.req.headers).forEach(([k, v]) => {\n if (typeof v === 'string') headers.set(k, v);\n else if (Array.isArray(v)) headers.set(k, v.join(', '));\n });\n }\n const init: RequestInit = { method, headers };\n if (method !== 'GET' && method !== 'HEAD') {\n const body = await readBody(event);\n if (body) {\n init.body = typeof body === 'string' ? body : JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n }\n }\n const webRequest = new Request(url, init);\n const response = await authService.handleRequest(webRequest);\n setResponseStatus(event, response.status);\n response.headers.forEach((v: string, k: string) => setResponseHeader(event, k, v));\n return await response.text();\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await readBody(event).catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n router.post(\n `${prefix}/graphql`,\n defineEventHandler(async (event) => {\n try {\n const body = await readBody(event);\n const result = await dispatcher.handleGraphQL(body, { request: event.node.req });\n return result;\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- Storage (needs multipart form parsing) ---\n router.use(\n `${prefix}/storage/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(`${prefix}/storage`.length);\n const method = event.method;\n const file = undefined; // File upload requires multipart parsing (e.g., formidable)\n const result = await dispatcher.handleStorage(subPath, method, file, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // ─── Catch-all: delegate to dispatcher.dispatch() ─────────────────────────\n // Handles meta, data, packages, analytics, automation, i18n, ui, openapi,\n // custom API endpoints, and any future routes added to HttpDispatcher.\n router.use(\n `${prefix}/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(prefix.length);\n const method = event.method;\n const body = (method === 'POST' || method === 'PUT' || method === 'PATCH')\n ? await readBody(event)\n : undefined;\n const query = getQuery(event);\n const result = await dispatcher.dispatch(method, subPath, body, query, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n return router;\n}\n"],"mappings":"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","names":["body"]}
package/dist/index.mjs CHANGED
@@ -47,7 +47,7 @@ function createH3Router(options) {
47
47
  return errorJson(event, "Not Found", 404);
48
48
  };
49
49
  router.get(
50
- `${prefix}`,
50
+ prefix,
51
51
  defineEventHandler(async () => {
52
52
  return { data: await dispatcher.getDiscoveryInfo(prefix) };
53
53
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport {\n createRouter,\n defineEventHandler,\n getQuery,\n readBody,\n sendRedirect,\n setResponseHeader,\n setResponseStatus,\n type H3Event,\n type Router,\n} from 'h3';\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface NuxtAdapterOptions {\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 * Creates an h3 router with all ObjectStack route dispatchers.\n * Designed for use in Nuxt server routes or standalone h3 apps.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * file upload, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes are handled by a catch-all that delegates to\n * `HttpDispatcher.dispatch()`, making the adapter automatically support\n * new routes added to the dispatcher.\n *\n * @example\n * ```ts\n * // server/api/[...].ts\n * import { createH3Router } from '@objectstack/nuxt';\n * import { kernel } from '../kernel';\n *\n * const router = createH3Router({ kernel });\n * export default defineEventHandler(router.handler);\n * ```\n */\nexport function createH3Router(options: NuxtAdapterOptions): Router {\n const router = createRouter();\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (event: H3Event, message: string, code: number = 500) => {\n setResponseStatus(event, code);\n return { success: false, error: { message, code } };\n };\n\n const toResponse = (event: H3Event, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n setResponseStatus(event, result.response.status);\n return result.response.body;\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return sendRedirect(event, res.url);\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n return res.stream;\n }\n return res;\n }\n }\n return errorJson(event, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n router.get(\n `${prefix}`,\n defineEventHandler(async () => {\n return { data: await dispatcher.getDiscoveryInfo(prefix) };\n }),\n );\n\n // --- .well-known ---\n router.get(\n '/.well-known/objectstack',\n defineEventHandler((event) => {\n return sendRedirect(event, prefix);\n }),\n );\n\n // --- Auth (needs auth service integration) ---\n router.use(\n `${prefix}/auth/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = event.path || event.node.req.url || '';\n const path = urlPath.substring(`${prefix}/auth/`.length).split('?')[0];\n const method = event.method;\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 const host = event.node.req.headers.host || 'localhost';\n const protocol = (event.node.req.socket as any)?.encrypted ? 'https' : 'http';\n const url = `${protocol}://${host}${urlPath}`;\n const headers = new Headers();\n if (event.node.req.headers) {\n Object.entries(event.node.req.headers).forEach(([k, v]) => {\n if (typeof v === 'string') headers.set(k, v);\n else if (Array.isArray(v)) headers.set(k, v.join(', '));\n });\n }\n const init: RequestInit = { method, headers };\n if (method !== 'GET' && method !== 'HEAD') {\n const body = await readBody(event);\n if (body) {\n init.body = typeof body === 'string' ? body : JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n }\n }\n const webRequest = new Request(url, init);\n const response = await authService.handleRequest(webRequest);\n setResponseStatus(event, response.status);\n response.headers.forEach((v: string, k: string) => setResponseHeader(event, k, v));\n return await response.text();\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await readBody(event).catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n router.post(\n `${prefix}/graphql`,\n defineEventHandler(async (event) => {\n try {\n const body = await readBody(event);\n const result = await dispatcher.handleGraphQL(body, { request: event.node.req });\n return result;\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- Storage (needs multipart form parsing) ---\n router.use(\n `${prefix}/storage/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(`${prefix}/storage`.length);\n const method = event.method;\n const file = undefined; // File upload requires multipart parsing (e.g., formidable)\n const result = await dispatcher.handleStorage(subPath, method, file, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // ─── Catch-all: delegate to dispatcher.dispatch() ─────────────────────────\n // Handles meta, data, packages, analytics, automation, i18n, ui, openapi,\n // custom API endpoints, and any future routes added to HttpDispatcher.\n router.use(\n `${prefix}/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(prefix.length);\n const method = event.method;\n const body = (method === 'POST' || method === 'PUT' || method === 'PATCH')\n ? await readBody(event)\n : undefined;\n const query = getQuery(event);\n const result = await dispatcher.dispatch(method, subPath, body, query, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n return router;\n}\n"],"mappings":"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","names":["body"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport {\n createRouter,\n defineEventHandler,\n getQuery,\n readBody,\n sendRedirect,\n setResponseHeader,\n setResponseStatus,\n type H3Event,\n type Router,\n} from 'h3';\nimport { type ObjectKernel, HttpDispatcher, HttpDispatcherResult } from '@objectstack/runtime';\n\nexport interface NuxtAdapterOptions {\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 * Creates an h3 router with all ObjectStack route dispatchers.\n * Designed for use in Nuxt server routes or standalone h3 apps.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * file upload, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes are handled by a catch-all that delegates to\n * `HttpDispatcher.dispatch()`, making the adapter automatically support\n * new routes added to the dispatcher.\n *\n * @example\n * ```ts\n * // server/api/[...].ts\n * import { createH3Router } from '@objectstack/nuxt';\n * import { kernel } from '../kernel';\n *\n * const router = createH3Router({ kernel });\n * export default defineEventHandler(router.handler);\n * ```\n */\nexport function createH3Router(options: NuxtAdapterOptions): Router {\n const router = createRouter();\n const dispatcher = new HttpDispatcher(options.kernel);\n const prefix = options.prefix || '/api';\n\n const errorJson = (event: H3Event, message: string, code: number = 500) => {\n setResponseStatus(event, code);\n return { success: false, error: { message, code } };\n };\n\n const toResponse = (event: H3Event, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n setResponseStatus(event, result.response.status);\n return result.response.body;\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return sendRedirect(event, res.url);\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) =>\n setResponseHeader(event, k, v as string),\n );\n }\n return res.stream;\n }\n return res;\n }\n }\n return errorJson(event, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n router.get(\n prefix,\n defineEventHandler(async () => {\n return { data: await dispatcher.getDiscoveryInfo(prefix) };\n }),\n );\n\n // --- .well-known ---\n router.get(\n '/.well-known/objectstack',\n defineEventHandler((event) => {\n return sendRedirect(event, prefix);\n }),\n );\n\n // --- Auth (needs auth service integration) ---\n router.use(\n `${prefix}/auth/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = event.path || event.node.req.url || '';\n const path = urlPath.substring(`${prefix}/auth/`.length).split('?')[0];\n const method = event.method;\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 const host = event.node.req.headers.host || 'localhost';\n const protocol = (event.node.req.socket as any)?.encrypted ? 'https' : 'http';\n const url = `${protocol}://${host}${urlPath}`;\n const headers = new Headers();\n if (event.node.req.headers) {\n Object.entries(event.node.req.headers).forEach(([k, v]) => {\n if (typeof v === 'string') headers.set(k, v);\n else if (Array.isArray(v)) headers.set(k, v.join(', '));\n });\n }\n const init: RequestInit = { method, headers };\n if (method !== 'GET' && method !== 'HEAD') {\n const body = await readBody(event);\n if (body) {\n init.body = typeof body === 'string' ? body : JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n }\n }\n const webRequest = new Request(url, init);\n const response = await authService.handleRequest(webRequest);\n setResponseStatus(event, response.status);\n response.headers.forEach((v: string, k: string) => setResponseHeader(event, k, v));\n return await response.text();\n }\n\n // Fallback to dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await readBody(event).catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n router.post(\n `${prefix}/graphql`,\n defineEventHandler(async (event) => {\n try {\n const body = await readBody(event);\n const result = await dispatcher.handleGraphQL(body, { request: event.node.req });\n return result;\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // --- Storage (needs multipart form parsing) ---\n router.use(\n `${prefix}/storage/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(`${prefix}/storage`.length);\n const method = event.method;\n const file = undefined; // File upload requires multipart parsing (e.g., formidable)\n const result = await dispatcher.handleStorage(subPath, method, file, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n // ─── Catch-all: delegate to dispatcher.dispatch() ─────────────────────────\n // Handles meta, data, packages, analytics, automation, i18n, ui, openapi,\n // custom API endpoints, and any future routes added to HttpDispatcher.\n router.use(\n `${prefix}/**`,\n defineEventHandler(async (event) => {\n try {\n const urlPath = (event.path || event.node.req.url || '').split('?')[0];\n const subPath = urlPath.substring(prefix.length);\n const method = event.method;\n const body = (method === 'POST' || method === 'PUT' || method === 'PATCH')\n ? await readBody(event)\n : undefined;\n const query = getQuery(event);\n const result = await dispatcher.dispatch(method, subPath, body, query, { request: event.node.req });\n return toResponse(event, result);\n } catch (err: any) {\n return errorJson(event, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n }),\n );\n\n return router;\n}\n"],"mappings":"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","names":["body"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/nuxt",
3
- "version": "3.3.1",
3
+ "version": "4.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,13 +13,13 @@
13
13
  },
14
14
  "peerDependencies": {
15
15
  "h3": "^1.15.10",
16
- "@objectstack/runtime": "^3.3.1"
16
+ "@objectstack/runtime": "^4.0.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "h3": "^1.15.10",
20
- "typescript": "^5.0.0",
21
- "vitest": "^4.1.0",
22
- "@objectstack/runtime": "3.3.1"
20
+ "typescript": "^6.0.2",
21
+ "vitest": "^4.1.2",
22
+ "@objectstack/runtime": "4.0.0"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup --config ../../../tsup.config.ts",
package/src/index.ts CHANGED
@@ -89,7 +89,7 @@ export function createH3Router(options: NuxtAdapterOptions): Router {
89
89
 
90
90
  // --- Discovery ---
91
91
  router.get(
92
- `${prefix}`,
92
+ prefix,
93
93
  defineEventHandler(async () => {
94
94
  return { data: await dispatcher.getDiscoveryInfo(prefix) };
95
95
  }),
package/tsconfig.json CHANGED
@@ -6,8 +6,21 @@
6
6
  "module": "NodeNext",
7
7
  "moduleResolution": "NodeNext",
8
8
  "esModuleInterop": true,
9
- "skipLibCheck": true
9
+ "skipLibCheck": true,
10
+ "lib": [
11
+ "ES2020",
12
+ "DOM",
13
+ "DOM.Iterable"
14
+ ],
15
+ "types": [
16
+ "node"
17
+ ]
10
18
  },
11
- "include": ["src/**/*"],
12
- "exclude": ["node_modules", "dist"]
19
+ "include": [
20
+ "src/**/*"
21
+ ],
22
+ "exclude": [
23
+ "node_modules",
24
+ "dist"
25
+ ]
13
26
  }