@objectstack/hono 10.3.0 → 11.1.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.
- package/README.md +0 -5
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -74,11 +74,6 @@ app.use('/api/*', objectStackMiddleware(kernel));
|
|
|
74
74
|
- ✅ Edge, serverless, and multi-runtime deployments.
|
|
75
75
|
- ✅ Projects wanting built-in CORS with wildcard patterns.
|
|
76
76
|
|
|
77
|
-
## When not to use
|
|
78
|
-
|
|
79
|
-
- ❌ Existing Express app — use [`@objectstack/express`](../express).
|
|
80
|
-
- ❌ NestJS enterprise stacks — use [`@objectstack/nestjs`](../nestjs).
|
|
81
|
-
|
|
82
77
|
## Related Packages
|
|
83
78
|
|
|
84
79
|
- [`@objectstack/plugin-hono-server`](../../plugins/plugin-hono-server) — optional plugin that hosts a Hono server inside the kernel.
|
package/dist/index.js
CHANGED
|
@@ -39,13 +39,13 @@ function createHonoApp(options) {
|
|
|
39
39
|
const app = new import_hono.Hono();
|
|
40
40
|
const prefix = options.prefix || "/api";
|
|
41
41
|
const dispatcher = new import_runtime.HttpDispatcher(options.kernel);
|
|
42
|
-
const corsDisabledByEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_ENABLED", "CORS_ENABLED") === "false";
|
|
42
|
+
const corsDisabledByEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_ENABLED", "CORS_ENABLED", { silent: true }) === "false";
|
|
43
43
|
if (options.cors !== false && !corsDisabledByEnv) {
|
|
44
44
|
const corsOpts = typeof options.cors === "object" ? options.cors : {};
|
|
45
45
|
const enabled = corsOpts.enabled ?? true;
|
|
46
46
|
if (enabled) {
|
|
47
47
|
let configuredOrigin;
|
|
48
|
-
const corsOriginEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_ORIGIN", "CORS_ORIGIN");
|
|
48
|
+
const corsOriginEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_ORIGIN", "CORS_ORIGIN", { silent: true });
|
|
49
49
|
if (corsOpts.origin) {
|
|
50
50
|
configuredOrigin = corsOpts.origin;
|
|
51
51
|
} else if (corsOriginEnv) {
|
|
@@ -54,8 +54,8 @@ function createHonoApp(options) {
|
|
|
54
54
|
} else {
|
|
55
55
|
configuredOrigin = "*";
|
|
56
56
|
}
|
|
57
|
-
const credentials = corsOpts.credentials ?? (0, import_types.readEnvWithDeprecation)("OS_CORS_CREDENTIALS", "CORS_CREDENTIALS") !== "false";
|
|
58
|
-
const maxAgeEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_MAX_AGE", "CORS_MAX_AGE");
|
|
57
|
+
const credentials = corsOpts.credentials ?? (0, import_types.readEnvWithDeprecation)("OS_CORS_CREDENTIALS", "CORS_CREDENTIALS", { silent: true }) !== "false";
|
|
58
|
+
const maxAgeEnv = (0, import_types.readEnvWithDeprecation)("OS_CORS_MAX_AGE", "CORS_MAX_AGE", { silent: true });
|
|
59
59
|
const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);
|
|
60
60
|
let origin;
|
|
61
61
|
if (configuredOrigin === "*" && credentials) {
|
|
@@ -159,6 +159,9 @@ function createHonoApp(options) {
|
|
|
159
159
|
try {
|
|
160
160
|
const config = authService.getPublicConfig?.();
|
|
161
161
|
if (config) {
|
|
162
|
+
if (config.features?.sso && typeof authService.isSsoUsable === "function") {
|
|
163
|
+
config.features.sso = await authService.isSsoUsable();
|
|
164
|
+
}
|
|
162
165
|
return c.json({
|
|
163
166
|
success: true,
|
|
164
167
|
data: config
|
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 { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport {\n type ObjectKernel,\n HttpDispatcher,\n HttpDispatcherResult,\n} from '@objectstack/runtime';\nimport { readEnvWithDeprecation } from '@objectstack/types';\n\n/**\n * Re-export the `Hono` type from the copy of `hono` this adapter owns.\n *\n * Downstream apps (e.g. the cloud control plane) only need the `Hono` TYPE to\n * annotate the app returned by {@link createHonoApp}. Importing it from here —\n * rather than adding their own `hono` dependency — guarantees there is exactly\n * ONE `hono` across the framework boundary, so the app's type matches without\n * any version-pinning / pnpm.overrides alignment dance. `hono` stays a normal\n * runtime dependency of THIS package, so standalone `os start` is unaffected.\n */\nexport type { Hono } from 'hono';\n\n/**\n * Minimal structural interface matching KernelManager from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type KernelManager = any;\n\n/**\n * Opaque reference to an EnvironmentDriverRegistry from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency. Pass an instance\n * of DefaultEnvironmentDriverRegistry from @objectstack/service-cloud at runtime.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EnvironmentDriverRegistry = any;\nimport { createOriginMatcher, hasWildcardPattern } from '@objectstack/plugin-hono-server';\n\nexport interface ObjectStackHonoCorsOptions {\n /** Enable or disable CORS. Defaults to true. */\n enabled?: boolean;\n /** Allowed origins. Defaults to env `OS_CORS_ORIGIN` (or legacy `CORS_ORIGIN`) or '*'. Comma-separated string or array. */\n origin?: string | string[];\n /** Allowed methods. */\n methods?: string[];\n /** Allow credentials (cookies, authorization headers). */\n credentials?: boolean;\n /** Preflight cache max-age in seconds. */\n maxAge?: number;\n /** Allowed headers. */\n allowHeaders?: string[];\n /** Exposed headers. */\n exposeHeaders?: string[];\n}\n\nexport interface ObjectStackHonoOptions {\n kernel: ObjectKernel;\n prefix?: string;\n /** CORS configuration. Set to `false` to disable entirely. */\n cors?: ObjectStackHonoCorsOptions | false;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Multi-tenant routing is\n * owned by the host's `KernelResolver` (registered as the\n * `kernel-resolver` kernel service); the dispatcher picks it up there.\n */\n kernelManager?: KernelManager;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Environment resolution\n * is owned by the host's `KernelResolver` (`kernel-resolver` service).\n */\n envRegistry?: EnvironmentDriverRegistry;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * Middleware mode for existing Hono apps\n */\nexport function objectStackMiddleware(kernel: ObjectKernel) {\n return async (c: any, next: any) => {\n c.set('objectStack', kernel);\n await next();\n };\n}\n\n/**\n * Creates a full-featured Hono app with all ObjectStack route dispatchers.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * formData, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes (meta, data, packages, analytics, automation, i18n, ui,\n * openapi, custom endpoints, and any future routes) are handled by a\n * catch-all that delegates to `HttpDispatcher.dispatch()`.\n *\n * This means new routes added to `HttpDispatcher` automatically work in\n * every adapter without any adapter-side code changes.\n *\n * @example\n * ```ts\n * import { createHonoApp } from '@objectstack/hono';\n * const app = createHonoApp({ kernel });\n * export default app;\n * ```\n */\nexport function createHonoApp(options: ObjectStackHonoOptions): Hono {\n const app = new Hono();\n const prefix = options.prefix || '/api';\n // ADR-0006 Phase 5: env resolution + multi-kernel routing belong to the\n // host's KernelResolver (the dispatcher resolves the `kernel-resolver`\n // service itself). The legacy envRegistry/kernelManager options are\n // accepted-but-ignored for source compatibility.\n const dispatcher = new HttpDispatcher(options.kernel);\n\n // ─── CORS Middleware ──────────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables:\n // OS_CORS_ENABLED – \"false\" to disable (default: true)\n // OS_CORS_ORIGIN – comma-separated origins or \"*\" (default: \"*\")\n // OS_CORS_CREDENTIALS – \"false\" to disallow credentials (default: true)\n // OS_CORS_MAX_AGE – preflight cache seconds (default: 86400)\n // (legacy CORS_* names still honoured with a deprecation warning)\n const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED') === 'false';\n if (options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof options.cors === 'object' ? options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n // Resolve origins: options > env > default '*'\n let configuredOrigin: string | string[];\n const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN');\n if (corsOpts.origin) {\n configuredOrigin = corsOpts.origin;\n } else if (corsOriginEnv) {\n const envOrigin = corsOriginEnv.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS') !== 'false');\n const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE');\n const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\" or \"http://localhost:*\") we must\n // use a matcher function — Hono's cors() middleware does exact-string matching only and\n // treats '*' in patterns as a literal character, so passing wildcard strings straight\n // through would silently drop the Access-Control-Allow-Origin header on every real\n // request (preflight can still succeed via apps/objectos's short-circuit, but the\n // subsequent POST/GET would be blocked by the browser).\n //\n // This mirrors `plugin-hono-server`'s CORS wiring and uses the shared pattern matcher\n // from `@objectstack/plugin-hono-server` so all Hono-based code paths stay in sync.\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' — reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcardPattern(configuredOrigin)) {\n // Wildcard patterns (e.g., \"https://*.objectui.org\", \"http://localhost:*\")\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) — pass through as-is\n origin = configuredOrigin;\n }\n\n // Always include `set-auth-token` in exposed headers so that the\n // better-auth `bearer()` plugin (registered by plugin-auth) can\n // deliver rotated session tokens to cross-origin clients. Without\n // this, browsers strip the header from every response, the client\n // never sees the new token, and cross-origin sessions silently\n // break even when preflight and the actual request both succeed.\n //\n // This mirrors `plugin-hono-server`'s CORS wiring — all three\n // Hono-based CORS sites must stay in lockstep on this default.\n const defaultExposeHeaders = ['set-auth-token'];\n const exposeHeaders = Array.from(new Set([\n ...defaultExposeHeaders,\n ...(corsOpts.exposeHeaders ?? []),\n ]));\n\n app.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: corsOpts.allowHeaders || ['Content-Type', 'Authorization', 'X-Requested-With', 'X-Tenant-ID', 'X-Environment-Id'],\n exposeHeaders,\n credentials,\n maxAge,\n }));\n }\n }\n\n const errorJson = (c: any, message: string, code: number = 500) => {\n return c.json({ success: false, error: { message, code } }, code);\n };\n\n const toResponse = (c: any, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return c.json(result.response.body, result.response.status);\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return c.redirect(res.url);\n }\n if (res.type === 'stream' && res.events) {\n // SSE / Vercel Data Stream streaming response\n const headers: Record<string, string> = {\n 'Content-Type': res.contentType || 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n ...(res.headers || {}),\n };\n const stream = new ReadableStream({\n async start(controller) {\n try {\n const encoder = new TextEncoder();\n for await (const event of res.events) {\n const chunk = res.vercelDataStream\n ? (typeof event === 'string' ? event : JSON.stringify(event) + '\\n')\n : `data: ${JSON.stringify(event)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n } catch (err) {\n // Stream error — close gracefully\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, { status: 200, headers });\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return new Response(res.stream, { status: 200 });\n }\n return c.json(res, 200);\n }\n }\n return errorJson(c, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n app.get(prefix, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n app.get(`${prefix}/discovery`, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n // --- .well-known ---\n app.get('/.well-known/objectstack', (c) => {\n return c.redirect(prefix);\n });\n\n // --- Auth (needs auth service integration) ---\n app.all(`${prefix}/auth/*`, async (c) => {\n try {\n const path = c.req.path.substring(`${prefix}/auth/`.length);\n const method = c.req.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 // Handle /auth/config endpoint specifically (not handled by better-auth)\n if (path === 'config' && method === 'GET' && authService) {\n try {\n const config = (authService as any).getPublicConfig?.();\n if (config) {\n return c.json({\n success: true,\n data: config,\n });\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return c.json({\n success: false,\n error: {\n code: 'auth_config_error',\n message: err.message,\n },\n }, 500);\n }\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n const response = await authService.handleRequest(c.req.raw);\n return new Response(response.body, {\n status: response.status,\n headers: response.headers,\n });\n }\n\n // Fallback to legacy dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await c.req.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n app.post(`${prefix}/graphql`, async (c) => {\n try {\n const body = await c.req.json();\n const result = await dispatcher.handleGraphQL(body, { request: c.req.raw });\n return c.json(result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- Storage (needs formData parsing) ---\n app.all(`${prefix}/storage/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(`${prefix}/storage`.length);\n const method = c.req.method;\n\n let file: any = undefined;\n if (method === 'POST' && subPath === '/upload') {\n const formData = await c.req.formData();\n file = formData.get('file');\n }\n\n const result = await dispatcher.handleStorage(subPath, method, file, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\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 app.all(`${prefix}/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(prefix.length);\n const method = c.req.method;\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await c.req.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n const url = new URL(c.req.url);\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request: c.req.raw }, prefix);\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n return app;\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 { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport {\n type ObjectKernel,\n HttpDispatcher,\n HttpDispatcherResult,\n} from '@objectstack/runtime';\nimport { readEnvWithDeprecation } from '@objectstack/types';\n\n/**\n * Re-export the `Hono` type from the copy of `hono` this adapter owns.\n *\n * Downstream apps (e.g. the cloud control plane) only need the `Hono` TYPE to\n * annotate the app returned by {@link createHonoApp}. Importing it from here —\n * rather than adding their own `hono` dependency — guarantees there is exactly\n * ONE `hono` across the framework boundary, so the app's type matches without\n * any version-pinning / pnpm.overrides alignment dance. `hono` stays a normal\n * runtime dependency of THIS package, so standalone `os start` is unaffected.\n */\nexport type { Hono } from 'hono';\n\n/**\n * Minimal structural interface matching KernelManager from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type KernelManager = any;\n\n/**\n * Opaque reference to an EnvironmentDriverRegistry from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency. Pass an instance\n * of DefaultEnvironmentDriverRegistry from @objectstack/service-cloud at runtime.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EnvironmentDriverRegistry = any;\nimport { createOriginMatcher, hasWildcardPattern } from '@objectstack/plugin-hono-server';\n\nexport interface ObjectStackHonoCorsOptions {\n /** Enable or disable CORS. Defaults to true. */\n enabled?: boolean;\n /** Allowed origins. Defaults to env `OS_CORS_ORIGIN` (or legacy `CORS_ORIGIN`) or '*'. Comma-separated string or array. */\n origin?: string | string[];\n /** Allowed methods. */\n methods?: string[];\n /** Allow credentials (cookies, authorization headers). */\n credentials?: boolean;\n /** Preflight cache max-age in seconds. */\n maxAge?: number;\n /** Allowed headers. */\n allowHeaders?: string[];\n /** Exposed headers. */\n exposeHeaders?: string[];\n}\n\nexport interface ObjectStackHonoOptions {\n kernel: ObjectKernel;\n prefix?: string;\n /** CORS configuration. Set to `false` to disable entirely. */\n cors?: ObjectStackHonoCorsOptions | false;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Multi-tenant routing is\n * owned by the host's `KernelResolver` (registered as the\n * `kernel-resolver` kernel service); the dispatcher picks it up there.\n */\n kernelManager?: KernelManager;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Environment resolution\n * is owned by the host's `KernelResolver` (`kernel-resolver` service).\n */\n envRegistry?: EnvironmentDriverRegistry;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * Middleware mode for existing Hono apps\n */\nexport function objectStackMiddleware(kernel: ObjectKernel) {\n return async (c: any, next: any) => {\n c.set('objectStack', kernel);\n await next();\n };\n}\n\n/**\n * Creates a full-featured Hono app with all ObjectStack route dispatchers.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * formData, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes (meta, data, packages, analytics, automation, i18n, ui,\n * openapi, custom endpoints, and any future routes) are handled by a\n * catch-all that delegates to `HttpDispatcher.dispatch()`.\n *\n * This means new routes added to `HttpDispatcher` automatically work in\n * every adapter without any adapter-side code changes.\n *\n * @example\n * ```ts\n * import { createHonoApp } from '@objectstack/hono';\n * const app = createHonoApp({ kernel });\n * export default app;\n * ```\n */\nexport function createHonoApp(options: ObjectStackHonoOptions): Hono {\n const app = new Hono();\n const prefix = options.prefix || '/api';\n // ADR-0006 Phase 5: env resolution + multi-kernel routing belong to the\n // host's KernelResolver (the dispatcher resolves the `kernel-resolver`\n // service itself). The legacy envRegistry/kernelManager options are\n // accepted-but-ignored for source compatibility.\n const dispatcher = new HttpDispatcher(options.kernel);\n\n // ─── CORS Middleware ──────────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables:\n // OS_CORS_ENABLED – \"false\" to disable (default: true)\n // OS_CORS_ORIGIN – comma-separated origins or \"*\" (default: \"*\")\n // OS_CORS_CREDENTIALS – \"false\" to disallow credentials (default: true)\n // OS_CORS_MAX_AGE – preflight cache seconds (default: 86400)\n // (legacy CORS_* names still honoured with a deprecation warning)\n const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED', { silent: true }) === 'false';\n if (options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof options.cors === 'object' ? options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n // Resolve origins: options > env > default '*'\n let configuredOrigin: string | string[];\n const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN', { silent: true });\n if (corsOpts.origin) {\n configuredOrigin = corsOpts.origin;\n } else if (corsOriginEnv) {\n const envOrigin = corsOriginEnv.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS', { silent: true }) !== 'false');\n const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE', { silent: true });\n const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\" or \"http://localhost:*\") we must\n // use a matcher function — Hono's cors() middleware does exact-string matching only and\n // treats '*' in patterns as a literal character, so passing wildcard strings straight\n // through would silently drop the Access-Control-Allow-Origin header on every real\n // request (preflight can still succeed via apps/objectos's short-circuit, but the\n // subsequent POST/GET would be blocked by the browser).\n //\n // This mirrors `plugin-hono-server`'s CORS wiring and uses the shared pattern matcher\n // from `@objectstack/plugin-hono-server` so all Hono-based code paths stay in sync.\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' — reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcardPattern(configuredOrigin)) {\n // Wildcard patterns (e.g., \"https://*.objectui.org\", \"http://localhost:*\")\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) — pass through as-is\n origin = configuredOrigin;\n }\n\n // Always include `set-auth-token` in exposed headers so that the\n // better-auth `bearer()` plugin (registered by plugin-auth) can\n // deliver rotated session tokens to cross-origin clients. Without\n // this, browsers strip the header from every response, the client\n // never sees the new token, and cross-origin sessions silently\n // break even when preflight and the actual request both succeed.\n //\n // This mirrors `plugin-hono-server`'s CORS wiring — all three\n // Hono-based CORS sites must stay in lockstep on this default.\n const defaultExposeHeaders = ['set-auth-token'];\n const exposeHeaders = Array.from(new Set([\n ...defaultExposeHeaders,\n ...(corsOpts.exposeHeaders ?? []),\n ]));\n\n app.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: corsOpts.allowHeaders || ['Content-Type', 'Authorization', 'X-Requested-With', 'X-Tenant-ID', 'X-Environment-Id'],\n exposeHeaders,\n credentials,\n maxAge,\n }));\n }\n }\n\n const errorJson = (c: any, message: string, code: number = 500) => {\n return c.json({ success: false, error: { message, code } }, code);\n };\n\n const toResponse = (c: any, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return c.json(result.response.body, result.response.status);\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return c.redirect(res.url);\n }\n if (res.type === 'stream' && res.events) {\n // SSE / Vercel Data Stream streaming response\n const headers: Record<string, string> = {\n 'Content-Type': res.contentType || 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n ...(res.headers || {}),\n };\n const stream = new ReadableStream({\n async start(controller) {\n try {\n const encoder = new TextEncoder();\n for await (const event of res.events) {\n const chunk = res.vercelDataStream\n ? (typeof event === 'string' ? event : JSON.stringify(event) + '\\n')\n : `data: ${JSON.stringify(event)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n } catch (err) {\n // Stream error — close gracefully\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, { status: 200, headers });\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return new Response(res.stream, { status: 200 });\n }\n return c.json(res, 200);\n }\n }\n return errorJson(c, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n app.get(prefix, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n app.get(`${prefix}/discovery`, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n // --- .well-known ---\n app.get('/.well-known/objectstack', (c) => {\n return c.redirect(prefix);\n });\n\n // --- Auth (needs auth service integration) ---\n app.all(`${prefix}/auth/*`, async (c) => {\n try {\n const path = c.req.path.substring(`${prefix}/auth/`.length);\n const method = c.req.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 // Handle /auth/config endpoint specifically (not handled by better-auth)\n if (path === 'config' && method === 'GET' && authService) {\n try {\n const config = (authService as any).getPublicConfig?.();\n if (config) {\n // Refine the coarse \"SSO wired\" flag to \"SSO usable\" (≥1 provider\n // configured), mirroring the plugin-auth /config route. Guarded so\n // it's a safe no-op against an auth service predating the method.\n if (config.features?.sso && typeof (authService as any).isSsoUsable === 'function') {\n config.features.sso = await (authService as any).isSsoUsable();\n }\n return c.json({\n success: true,\n data: config,\n });\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return c.json({\n success: false,\n error: {\n code: 'auth_config_error',\n message: err.message,\n },\n }, 500);\n }\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n const response = await authService.handleRequest(c.req.raw);\n return new Response(response.body, {\n status: response.status,\n headers: response.headers,\n });\n }\n\n // Fallback to legacy dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await c.req.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n app.post(`${prefix}/graphql`, async (c) => {\n try {\n const body = await c.req.json();\n const result = await dispatcher.handleGraphQL(body, { request: c.req.raw });\n return c.json(result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- Storage (needs formData parsing) ---\n app.all(`${prefix}/storage/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(`${prefix}/storage`.length);\n const method = c.req.method;\n\n let file: any = undefined;\n if (method === 'POST' && subPath === '/upload') {\n const formData = await c.req.formData();\n file = formData.get('file');\n }\n\n const result = await dispatcher.handleStorage(subPath, method, file, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\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 app.all(`${prefix}/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(prefix.length);\n const method = c.req.method;\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await c.req.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n const url = new URL(c.req.url);\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request: c.req.raw }, prefix);\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n return app;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -16,13 +16,13 @@ function createHonoApp(options) {
|
|
|
16
16
|
const app = new Hono();
|
|
17
17
|
const prefix = options.prefix || "/api";
|
|
18
18
|
const dispatcher = new HttpDispatcher(options.kernel);
|
|
19
|
-
const corsDisabledByEnv = readEnvWithDeprecation("OS_CORS_ENABLED", "CORS_ENABLED") === "false";
|
|
19
|
+
const corsDisabledByEnv = readEnvWithDeprecation("OS_CORS_ENABLED", "CORS_ENABLED", { silent: true }) === "false";
|
|
20
20
|
if (options.cors !== false && !corsDisabledByEnv) {
|
|
21
21
|
const corsOpts = typeof options.cors === "object" ? options.cors : {};
|
|
22
22
|
const enabled = corsOpts.enabled ?? true;
|
|
23
23
|
if (enabled) {
|
|
24
24
|
let configuredOrigin;
|
|
25
|
-
const corsOriginEnv = readEnvWithDeprecation("OS_CORS_ORIGIN", "CORS_ORIGIN");
|
|
25
|
+
const corsOriginEnv = readEnvWithDeprecation("OS_CORS_ORIGIN", "CORS_ORIGIN", { silent: true });
|
|
26
26
|
if (corsOpts.origin) {
|
|
27
27
|
configuredOrigin = corsOpts.origin;
|
|
28
28
|
} else if (corsOriginEnv) {
|
|
@@ -31,8 +31,8 @@ function createHonoApp(options) {
|
|
|
31
31
|
} else {
|
|
32
32
|
configuredOrigin = "*";
|
|
33
33
|
}
|
|
34
|
-
const credentials = corsOpts.credentials ?? readEnvWithDeprecation("OS_CORS_CREDENTIALS", "CORS_CREDENTIALS") !== "false";
|
|
35
|
-
const maxAgeEnv = readEnvWithDeprecation("OS_CORS_MAX_AGE", "CORS_MAX_AGE");
|
|
34
|
+
const credentials = corsOpts.credentials ?? readEnvWithDeprecation("OS_CORS_CREDENTIALS", "CORS_CREDENTIALS", { silent: true }) !== "false";
|
|
35
|
+
const maxAgeEnv = readEnvWithDeprecation("OS_CORS_MAX_AGE", "CORS_MAX_AGE", { silent: true });
|
|
36
36
|
const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);
|
|
37
37
|
let origin;
|
|
38
38
|
if (configuredOrigin === "*" && credentials) {
|
|
@@ -136,6 +136,9 @@ function createHonoApp(options) {
|
|
|
136
136
|
try {
|
|
137
137
|
const config = authService.getPublicConfig?.();
|
|
138
138
|
if (config) {
|
|
139
|
+
if (config.features?.sso && typeof authService.isSsoUsable === "function") {
|
|
140
|
+
config.features.sso = await authService.isSsoUsable();
|
|
141
|
+
}
|
|
139
142
|
return c.json({
|
|
140
143
|
success: true,
|
|
141
144
|
data: config
|
package/dist/index.mjs.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 { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport {\n type ObjectKernel,\n HttpDispatcher,\n HttpDispatcherResult,\n} from '@objectstack/runtime';\nimport { readEnvWithDeprecation } from '@objectstack/types';\n\n/**\n * Re-export the `Hono` type from the copy of `hono` this adapter owns.\n *\n * Downstream apps (e.g. the cloud control plane) only need the `Hono` TYPE to\n * annotate the app returned by {@link createHonoApp}. Importing it from here —\n * rather than adding their own `hono` dependency — guarantees there is exactly\n * ONE `hono` across the framework boundary, so the app's type matches without\n * any version-pinning / pnpm.overrides alignment dance. `hono` stays a normal\n * runtime dependency of THIS package, so standalone `os start` is unaffected.\n */\nexport type { Hono } from 'hono';\n\n/**\n * Minimal structural interface matching KernelManager from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type KernelManager = any;\n\n/**\n * Opaque reference to an EnvironmentDriverRegistry from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency. Pass an instance\n * of DefaultEnvironmentDriverRegistry from @objectstack/service-cloud at runtime.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EnvironmentDriverRegistry = any;\nimport { createOriginMatcher, hasWildcardPattern } from '@objectstack/plugin-hono-server';\n\nexport interface ObjectStackHonoCorsOptions {\n /** Enable or disable CORS. Defaults to true. */\n enabled?: boolean;\n /** Allowed origins. Defaults to env `OS_CORS_ORIGIN` (or legacy `CORS_ORIGIN`) or '*'. Comma-separated string or array. */\n origin?: string | string[];\n /** Allowed methods. */\n methods?: string[];\n /** Allow credentials (cookies, authorization headers). */\n credentials?: boolean;\n /** Preflight cache max-age in seconds. */\n maxAge?: number;\n /** Allowed headers. */\n allowHeaders?: string[];\n /** Exposed headers. */\n exposeHeaders?: string[];\n}\n\nexport interface ObjectStackHonoOptions {\n kernel: ObjectKernel;\n prefix?: string;\n /** CORS configuration. Set to `false` to disable entirely. */\n cors?: ObjectStackHonoCorsOptions | false;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Multi-tenant routing is\n * owned by the host's `KernelResolver` (registered as the\n * `kernel-resolver` kernel service); the dispatcher picks it up there.\n */\n kernelManager?: KernelManager;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Environment resolution\n * is owned by the host's `KernelResolver` (`kernel-resolver` service).\n */\n envRegistry?: EnvironmentDriverRegistry;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * Middleware mode for existing Hono apps\n */\nexport function objectStackMiddleware(kernel: ObjectKernel) {\n return async (c: any, next: any) => {\n c.set('objectStack', kernel);\n await next();\n };\n}\n\n/**\n * Creates a full-featured Hono app with all ObjectStack route dispatchers.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * formData, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes (meta, data, packages, analytics, automation, i18n, ui,\n * openapi, custom endpoints, and any future routes) are handled by a\n * catch-all that delegates to `HttpDispatcher.dispatch()`.\n *\n * This means new routes added to `HttpDispatcher` automatically work in\n * every adapter without any adapter-side code changes.\n *\n * @example\n * ```ts\n * import { createHonoApp } from '@objectstack/hono';\n * const app = createHonoApp({ kernel });\n * export default app;\n * ```\n */\nexport function createHonoApp(options: ObjectStackHonoOptions): Hono {\n const app = new Hono();\n const prefix = options.prefix || '/api';\n // ADR-0006 Phase 5: env resolution + multi-kernel routing belong to the\n // host's KernelResolver (the dispatcher resolves the `kernel-resolver`\n // service itself). The legacy envRegistry/kernelManager options are\n // accepted-but-ignored for source compatibility.\n const dispatcher = new HttpDispatcher(options.kernel);\n\n // ─── CORS Middleware ──────────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables:\n // OS_CORS_ENABLED – \"false\" to disable (default: true)\n // OS_CORS_ORIGIN – comma-separated origins or \"*\" (default: \"*\")\n // OS_CORS_CREDENTIALS – \"false\" to disallow credentials (default: true)\n // OS_CORS_MAX_AGE – preflight cache seconds (default: 86400)\n // (legacy CORS_* names still honoured with a deprecation warning)\n const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED') === 'false';\n if (options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof options.cors === 'object' ? options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n // Resolve origins: options > env > default '*'\n let configuredOrigin: string | string[];\n const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN');\n if (corsOpts.origin) {\n configuredOrigin = corsOpts.origin;\n } else if (corsOriginEnv) {\n const envOrigin = corsOriginEnv.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS') !== 'false');\n const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE');\n const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\" or \"http://localhost:*\") we must\n // use a matcher function — Hono's cors() middleware does exact-string matching only and\n // treats '*' in patterns as a literal character, so passing wildcard strings straight\n // through would silently drop the Access-Control-Allow-Origin header on every real\n // request (preflight can still succeed via apps/objectos's short-circuit, but the\n // subsequent POST/GET would be blocked by the browser).\n //\n // This mirrors `plugin-hono-server`'s CORS wiring and uses the shared pattern matcher\n // from `@objectstack/plugin-hono-server` so all Hono-based code paths stay in sync.\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' — reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcardPattern(configuredOrigin)) {\n // Wildcard patterns (e.g., \"https://*.objectui.org\", \"http://localhost:*\")\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) — pass through as-is\n origin = configuredOrigin;\n }\n\n // Always include `set-auth-token` in exposed headers so that the\n // better-auth `bearer()` plugin (registered by plugin-auth) can\n // deliver rotated session tokens to cross-origin clients. Without\n // this, browsers strip the header from every response, the client\n // never sees the new token, and cross-origin sessions silently\n // break even when preflight and the actual request both succeed.\n //\n // This mirrors `plugin-hono-server`'s CORS wiring — all three\n // Hono-based CORS sites must stay in lockstep on this default.\n const defaultExposeHeaders = ['set-auth-token'];\n const exposeHeaders = Array.from(new Set([\n ...defaultExposeHeaders,\n ...(corsOpts.exposeHeaders ?? []),\n ]));\n\n app.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: corsOpts.allowHeaders || ['Content-Type', 'Authorization', 'X-Requested-With', 'X-Tenant-ID', 'X-Environment-Id'],\n exposeHeaders,\n credentials,\n maxAge,\n }));\n }\n }\n\n const errorJson = (c: any, message: string, code: number = 500) => {\n return c.json({ success: false, error: { message, code } }, code);\n };\n\n const toResponse = (c: any, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return c.json(result.response.body, result.response.status);\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return c.redirect(res.url);\n }\n if (res.type === 'stream' && res.events) {\n // SSE / Vercel Data Stream streaming response\n const headers: Record<string, string> = {\n 'Content-Type': res.contentType || 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n ...(res.headers || {}),\n };\n const stream = new ReadableStream({\n async start(controller) {\n try {\n const encoder = new TextEncoder();\n for await (const event of res.events) {\n const chunk = res.vercelDataStream\n ? (typeof event === 'string' ? event : JSON.stringify(event) + '\\n')\n : `data: ${JSON.stringify(event)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n } catch (err) {\n // Stream error — close gracefully\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, { status: 200, headers });\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return new Response(res.stream, { status: 200 });\n }\n return c.json(res, 200);\n }\n }\n return errorJson(c, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n app.get(prefix, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n app.get(`${prefix}/discovery`, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n // --- .well-known ---\n app.get('/.well-known/objectstack', (c) => {\n return c.redirect(prefix);\n });\n\n // --- Auth (needs auth service integration) ---\n app.all(`${prefix}/auth/*`, async (c) => {\n try {\n const path = c.req.path.substring(`${prefix}/auth/`.length);\n const method = c.req.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 // Handle /auth/config endpoint specifically (not handled by better-auth)\n if (path === 'config' && method === 'GET' && authService) {\n try {\n const config = (authService as any).getPublicConfig?.();\n if (config) {\n return c.json({\n success: true,\n data: config,\n });\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return c.json({\n success: false,\n error: {\n code: 'auth_config_error',\n message: err.message,\n },\n }, 500);\n }\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n const response = await authService.handleRequest(c.req.raw);\n return new Response(response.body, {\n status: response.status,\n headers: response.headers,\n });\n }\n\n // Fallback to legacy dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await c.req.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n app.post(`${prefix}/graphql`, async (c) => {\n try {\n const body = await c.req.json();\n const result = await dispatcher.handleGraphQL(body, { request: c.req.raw });\n return c.json(result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- Storage (needs formData parsing) ---\n app.all(`${prefix}/storage/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(`${prefix}/storage`.length);\n const method = c.req.method;\n\n let file: any = undefined;\n if (method === 'POST' && subPath === '/upload') {\n const formData = await c.req.formData();\n file = formData.get('file');\n }\n\n const result = await dispatcher.handleStorage(subPath, method, file, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\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 app.all(`${prefix}/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(prefix.length);\n const method = c.req.method;\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await c.req.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n const url = new URL(c.req.url);\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request: c.req.raw }, prefix);\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n return app;\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 { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport {\n type ObjectKernel,\n HttpDispatcher,\n HttpDispatcherResult,\n} from '@objectstack/runtime';\nimport { readEnvWithDeprecation } from '@objectstack/types';\n\n/**\n * Re-export the `Hono` type from the copy of `hono` this adapter owns.\n *\n * Downstream apps (e.g. the cloud control plane) only need the `Hono` TYPE to\n * annotate the app returned by {@link createHonoApp}. Importing it from here —\n * rather than adding their own `hono` dependency — guarantees there is exactly\n * ONE `hono` across the framework boundary, so the app's type matches without\n * any version-pinning / pnpm.overrides alignment dance. `hono` stays a normal\n * runtime dependency of THIS package, so standalone `os start` is unaffected.\n */\nexport type { Hono } from 'hono';\n\n/**\n * Minimal structural interface matching KernelManager from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type KernelManager = any;\n\n/**\n * Opaque reference to an EnvironmentDriverRegistry from @objectstack/service-cloud.\n * Declared locally to avoid a circular build dependency. Pass an instance\n * of DefaultEnvironmentDriverRegistry from @objectstack/service-cloud at runtime.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EnvironmentDriverRegistry = any;\nimport { createOriginMatcher, hasWildcardPattern } from '@objectstack/plugin-hono-server';\n\nexport interface ObjectStackHonoCorsOptions {\n /** Enable or disable CORS. Defaults to true. */\n enabled?: boolean;\n /** Allowed origins. Defaults to env `OS_CORS_ORIGIN` (or legacy `CORS_ORIGIN`) or '*'. Comma-separated string or array. */\n origin?: string | string[];\n /** Allowed methods. */\n methods?: string[];\n /** Allow credentials (cookies, authorization headers). */\n credentials?: boolean;\n /** Preflight cache max-age in seconds. */\n maxAge?: number;\n /** Allowed headers. */\n allowHeaders?: string[];\n /** Exposed headers. */\n exposeHeaders?: string[];\n}\n\nexport interface ObjectStackHonoOptions {\n kernel: ObjectKernel;\n prefix?: string;\n /** CORS configuration. Set to `false` to disable entirely. */\n cors?: ObjectStackHonoCorsOptions | false;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Multi-tenant routing is\n * owned by the host's `KernelResolver` (registered as the\n * `kernel-resolver` kernel service); the dispatcher picks it up there.\n */\n kernelManager?: KernelManager;\n /**\n * @deprecated RETIRED (ADR-0006 Phase 5) — ignored. Environment resolution\n * is owned by the host's `KernelResolver` (`kernel-resolver` service).\n */\n envRegistry?: EnvironmentDriverRegistry;\n}\n\n/**\n * Auth service interface with handleRequest method\n */\ninterface AuthService {\n handleRequest(request: Request): Promise<Response>;\n}\n\n/**\n * Middleware mode for existing Hono apps\n */\nexport function objectStackMiddleware(kernel: ObjectKernel) {\n return async (c: any, next: any) => {\n c.set('objectStack', kernel);\n await next();\n };\n}\n\n/**\n * Creates a full-featured Hono app with all ObjectStack route dispatchers.\n *\n * Only routes that need framework-specific handling (auth service, storage\n * formData, GraphQL raw result, discovery wrapper) are registered explicitly.\n * All other routes (meta, data, packages, analytics, automation, i18n, ui,\n * openapi, custom endpoints, and any future routes) are handled by a\n * catch-all that delegates to `HttpDispatcher.dispatch()`.\n *\n * This means new routes added to `HttpDispatcher` automatically work in\n * every adapter without any adapter-side code changes.\n *\n * @example\n * ```ts\n * import { createHonoApp } from '@objectstack/hono';\n * const app = createHonoApp({ kernel });\n * export default app;\n * ```\n */\nexport function createHonoApp(options: ObjectStackHonoOptions): Hono {\n const app = new Hono();\n const prefix = options.prefix || '/api';\n // ADR-0006 Phase 5: env resolution + multi-kernel routing belong to the\n // host's KernelResolver (the dispatcher resolves the `kernel-resolver`\n // service itself). The legacy envRegistry/kernelManager options are\n // accepted-but-ignored for source compatibility.\n const dispatcher = new HttpDispatcher(options.kernel);\n\n // ─── CORS Middleware ──────────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables:\n // OS_CORS_ENABLED – \"false\" to disable (default: true)\n // OS_CORS_ORIGIN – comma-separated origins or \"*\" (default: \"*\")\n // OS_CORS_CREDENTIALS – \"false\" to disallow credentials (default: true)\n // OS_CORS_MAX_AGE – preflight cache seconds (default: 86400)\n // (legacy CORS_* names still honoured with a deprecation warning)\n const corsDisabledByEnv = readEnvWithDeprecation('OS_CORS_ENABLED', 'CORS_ENABLED', { silent: true }) === 'false';\n if (options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof options.cors === 'object' ? options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n // Resolve origins: options > env > default '*'\n let configuredOrigin: string | string[];\n const corsOriginEnv = readEnvWithDeprecation('OS_CORS_ORIGIN', 'CORS_ORIGIN', { silent: true });\n if (corsOpts.origin) {\n configuredOrigin = corsOpts.origin;\n } else if (corsOriginEnv) {\n const envOrigin = corsOriginEnv.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (readEnvWithDeprecation('OS_CORS_CREDENTIALS', 'CORS_CREDENTIALS', { silent: true }) !== 'false');\n const maxAgeEnv = readEnvWithDeprecation('OS_CORS_MAX_AGE', 'CORS_MAX_AGE', { silent: true });\n const maxAge = corsOpts.maxAge ?? (maxAgeEnv ? parseInt(maxAgeEnv, 10) : 86400);\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\" or \"http://localhost:*\") we must\n // use a matcher function — Hono's cors() middleware does exact-string matching only and\n // treats '*' in patterns as a literal character, so passing wildcard strings straight\n // through would silently drop the Access-Control-Allow-Origin header on every real\n // request (preflight can still succeed via apps/objectos's short-circuit, but the\n // subsequent POST/GET would be blocked by the browser).\n //\n // This mirrors `plugin-hono-server`'s CORS wiring and uses the shared pattern matcher\n // from `@objectstack/plugin-hono-server` so all Hono-based code paths stay in sync.\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' — reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcardPattern(configuredOrigin)) {\n // Wildcard patterns (e.g., \"https://*.objectui.org\", \"http://localhost:*\")\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) — pass through as-is\n origin = configuredOrigin;\n }\n\n // Always include `set-auth-token` in exposed headers so that the\n // better-auth `bearer()` plugin (registered by plugin-auth) can\n // deliver rotated session tokens to cross-origin clients. Without\n // this, browsers strip the header from every response, the client\n // never sees the new token, and cross-origin sessions silently\n // break even when preflight and the actual request both succeed.\n //\n // This mirrors `plugin-hono-server`'s CORS wiring — all three\n // Hono-based CORS sites must stay in lockstep on this default.\n const defaultExposeHeaders = ['set-auth-token'];\n const exposeHeaders = Array.from(new Set([\n ...defaultExposeHeaders,\n ...(corsOpts.exposeHeaders ?? []),\n ]));\n\n app.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: corsOpts.allowHeaders || ['Content-Type', 'Authorization', 'X-Requested-With', 'X-Tenant-ID', 'X-Environment-Id'],\n exposeHeaders,\n credentials,\n maxAge,\n }));\n }\n }\n\n const errorJson = (c: any, message: string, code: number = 500) => {\n return c.json({ success: false, error: { message, code } }, code);\n };\n\n const toResponse = (c: any, result: HttpDispatcherResult) => {\n if (result.handled) {\n if (result.response) {\n if (result.response.headers) {\n Object.entries(result.response.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return c.json(result.response.body, result.response.status);\n }\n if (result.result) {\n const res = result.result;\n if (res.type === 'redirect' && res.url) {\n return c.redirect(res.url);\n }\n if (res.type === 'stream' && res.events) {\n // SSE / Vercel Data Stream streaming response\n const headers: Record<string, string> = {\n 'Content-Type': res.contentType || 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n ...(res.headers || {}),\n };\n const stream = new ReadableStream({\n async start(controller) {\n try {\n const encoder = new TextEncoder();\n for await (const event of res.events) {\n const chunk = res.vercelDataStream\n ? (typeof event === 'string' ? event : JSON.stringify(event) + '\\n')\n : `data: ${JSON.stringify(event)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n } catch (err) {\n // Stream error — close gracefully\n } finally {\n controller.close();\n }\n },\n });\n return new Response(stream, { status: 200, headers });\n }\n if (res.type === 'stream' && res.stream) {\n if (res.headers) {\n Object.entries(res.headers).forEach(([k, v]) => c.header(k, v as string));\n }\n return new Response(res.stream, { status: 200 });\n }\n return c.json(res, 200);\n }\n }\n return errorJson(c, 'Not Found', 404);\n };\n\n // ─── Explicit routes (framework-specific handling required) ────────────────\n\n // --- Discovery ---\n app.get(prefix, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n app.get(`${prefix}/discovery`, async (c) => {\n return c.json({ data: await dispatcher.getDiscoveryInfo(prefix) });\n });\n\n // --- .well-known ---\n app.get('/.well-known/objectstack', (c) => {\n return c.redirect(prefix);\n });\n\n // --- Auth (needs auth service integration) ---\n app.all(`${prefix}/auth/*`, async (c) => {\n try {\n const path = c.req.path.substring(`${prefix}/auth/`.length);\n const method = c.req.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 // Handle /auth/config endpoint specifically (not handled by better-auth)\n if (path === 'config' && method === 'GET' && authService) {\n try {\n const config = (authService as any).getPublicConfig?.();\n if (config) {\n // Refine the coarse \"SSO wired\" flag to \"SSO usable\" (≥1 provider\n // configured), mirroring the plugin-auth /config route. Guarded so\n // it's a safe no-op against an auth service predating the method.\n if (config.features?.sso && typeof (authService as any).isSsoUsable === 'function') {\n config.features.sso = await (authService as any).isSsoUsable();\n }\n return c.json({\n success: true,\n data: config,\n });\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return c.json({\n success: false,\n error: {\n code: 'auth_config_error',\n message: err.message,\n },\n }, 500);\n }\n }\n\n if (authService && typeof authService.handleRequest === 'function') {\n const response = await authService.handleRequest(c.req.raw);\n return new Response(response.body, {\n status: response.status,\n headers: response.headers,\n });\n }\n\n // Fallback to legacy dispatcher\n const body = method === 'GET' || method === 'HEAD'\n ? {}\n : await c.req.json().catch(() => ({}));\n const result = await dispatcher.handleAuth(path, method, body, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- GraphQL (returns raw result, not HttpDispatcherResult) ---\n app.post(`${prefix}/graphql`, async (c) => {\n try {\n const body = await c.req.json();\n const result = await dispatcher.handleGraphQL(body, { request: c.req.raw });\n return c.json(result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n // --- Storage (needs formData parsing) ---\n app.all(`${prefix}/storage/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(`${prefix}/storage`.length);\n const method = c.req.method;\n\n let file: any = undefined;\n if (method === 'POST' && subPath === '/upload') {\n const formData = await c.req.formData();\n file = formData.get('file');\n }\n\n const result = await dispatcher.handleStorage(subPath, method, file, { request: c.req.raw });\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\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 app.all(`${prefix}/*`, async (c) => {\n try {\n const subPath = c.req.path.substring(prefix.length);\n const method = c.req.method;\n\n let body: any = undefined;\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n body = await c.req.json().catch(() => ({}));\n }\n\n const queryParams: Record<string, any> = {};\n const url = new URL(c.req.url);\n url.searchParams.forEach((val, key) => { queryParams[key] = val; });\n\n const result = await dispatcher.dispatch(method, subPath, body, queryParams, { request: c.req.raw }, prefix);\n return toResponse(c, result);\n } catch (err: any) {\n return errorJson(c, err.message || 'Internal Server Error', err.statusCode || 500);\n }\n });\n\n return app;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/hono",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@objectstack/plugin-hono-server": "
|
|
16
|
-
"@objectstack/types": "
|
|
17
|
-
"@objectstack/runtime": "^
|
|
15
|
+
"@objectstack/plugin-hono-server": "11.1.0",
|
|
16
|
+
"@objectstack/types": "11.1.0",
|
|
17
|
+
"@objectstack/runtime": "^11.1.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"hono": "^4.12.8"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"hono": "^4.12.26",
|
|
24
24
|
"typescript": "^6.0.3",
|
|
25
25
|
"vitest": "^4.1.9",
|
|
26
|
-
"@objectstack/runtime": "
|
|
26
|
+
"@objectstack/runtime": "11.1.0"
|
|
27
27
|
},
|
|
28
28
|
"description": "Hono adapter for ObjectStack — edge-compatible REST API server for Cloudflare Workers, Deno, Bun, and Node.",
|
|
29
29
|
"keywords": [
|