@objectstack/plugin-hono-server 4.0.2 → 4.0.4

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/hono-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './hono-plugin';\nexport * from './adapter';\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Export IHttpServer from core\nexport * from '@objectstack/core';\n\nimport { \n IHttpServer, \n RouteHandler, \n Middleware \n} from '@objectstack/core';\nimport { Hono } from 'hono';\nimport { serve } from '@hono/node-server';\nimport { serveStatic } from '@hono/node-server/serve-static';\n\n/**\n * Hono Implementation of IHttpServer\n */\nexport class HonoHttpServer implements IHttpServer {\n private app: Hono;\n private server: any;\n private listeningPort: number | undefined;\n\n constructor(\n private port: number = 3000,\n private staticRoot?: string\n ) {\n this.app = new Hono();\n }\n\n // internal helper to convert standard handler to Hono handler\n private wrap(handler: RouteHandler) {\n return async (c: any) => {\n let body: any = {};\n\n // Try to parse JSON body first if content-type is JSON\n if (c.req.header('content-type')?.includes('application/json')) {\n try {\n body = await c.req.json();\n } catch(e) {\n // If JSON parsing fails, try parseBody\n try {\n body = await c.req.parseBody();\n } catch(e2) {}\n }\n } else {\n // For non-JSON content types, use parseBody\n try {\n body = await c.req.parseBody();\n } catch(e) {}\n }\n\n const req = {\n params: c.req.param(),\n query: c.req.query(),\n body,\n headers: c.req.header(),\n method: c.req.method,\n path: c.req.path\n };\n\n let capturedResponse: any;\n let streamController: ReadableStreamDefaultController | null = null;\n let streamEncoder: TextEncoder | null = null;\n let streamHeaders: Record<string, string> = {};\n let isStreaming = false;\n\n const res = {\n json: (data: any) => { capturedResponse = c.json(data); },\n send: (data: string) => { capturedResponse = c.html(data); },\n status: (code: number) => { c.status(code); return res; },\n header: (name: string, value: string) => {\n c.header(name, value);\n streamHeaders[name] = value;\n return res;\n },\n write: (chunk: string | Uint8Array) => {\n isStreaming = true;\n if (streamController && streamEncoder) {\n const data = typeof chunk === 'string' ? streamEncoder.encode(chunk) : chunk;\n streamController.enqueue(data);\n }\n },\n end: () => {\n if (streamController) {\n streamController.close();\n }\n },\n };\n\n // Create a streaming response wrapper — if handler calls res.write(),\n // we return a ReadableStream; otherwise fall back to capturedResponse.\n const streamPromise = new Promise<Response | null>((resolve) => {\n const stream = new ReadableStream({\n start(controller) {\n streamController = controller;\n streamEncoder = new TextEncoder();\n },\n });\n\n // Run the handler; once it's done, check if streaming was used\n const result = handler(req as any, res as any);\n const done = result instanceof Promise ? result : Promise.resolve(result);\n done.then(() => {\n if (isStreaming) {\n resolve(new Response(stream, {\n status: 200,\n headers: streamHeaders,\n }));\n } else {\n // Not streaming — close the unused stream and return null\n streamController?.close();\n resolve(null);\n }\n }).catch(() => {\n streamController?.close();\n resolve(null);\n });\n });\n\n const streamResponse = await streamPromise;\n return streamResponse ?? capturedResponse;\n };\n }\n\n get(path: string, handler: RouteHandler) {\n this.app.get(path, this.wrap(handler));\n }\n post(path: string, handler: RouteHandler) {\n this.app.post(path, this.wrap(handler));\n }\n put(path: string, handler: RouteHandler) {\n this.app.put(path, this.wrap(handler));\n }\n delete(path: string, handler: RouteHandler) {\n this.app.delete(path, this.wrap(handler));\n }\n patch(path: string, handler: RouteHandler) {\n this.app.patch(path, this.wrap(handler));\n }\n \n use(pathOrHandler: string | Middleware, handler?: Middleware) {\n if (typeof pathOrHandler === 'string' && handler) {\n // Path based middleware\n // Hono middleware signature is different (c, next) => ...\n this.app.use(pathOrHandler, async (c, next) => {\n // Simplistic conversion\n await handler({} as any, {} as any, next);\n });\n } else if (typeof pathOrHandler === 'function') {\n // Global middleware\n this.app.use('*', async (c, next) => {\n await pathOrHandler({} as any, {} as any, next);\n });\n }\n }\n\n /**\n * Mount a sub-application or router\n */\n mount(path: string, subApp: Hono) {\n this.app.route(path, subApp);\n }\n\n\n async listen(port: number) {\n if (this.staticRoot) {\n this.app.get('/*', serveStatic({ root: this.staticRoot }));\n }\n\n const targetPort = port || this.port;\n const maxRetries = 20;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n const tryPort = targetPort + attempt;\n try {\n await this.tryListen(tryPort);\n return;\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < maxRetries - 1) {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n continue;\n }\n throw err;\n }\n }\n }\n\n private tryListen(port: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = serve({\n fetch: this.app.fetch,\n port\n }, (info) => {\n this.listeningPort = info.port;\n resolve();\n });\n this.server = server;\n server.on('error', (err: any) => {\n reject(err);\n });\n });\n }\n\n getPort() {\n return this.listeningPort || this.port;\n }\n\n // Expose raw app for scenarios where standard interface is not enough\n getRawApp() {\n return this.app;\n }\n\n async close() {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n }\n\n\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport {\n RestServerConfig,\n} from '@objectstack/spec/api';\nimport { HonoHttpServer } from './adapter';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface StaticMount {\n root: string;\n path?: string;\n rewrite?: boolean;\n spa?: boolean;\n}\n\nexport interface HonoPluginOptions {\n port?: number;\n staticRoot?: string;\n /**\n * Multiple static resource mounts\n */\n staticMounts?: StaticMount[];\n /**\n * REST server configuration\n * Controls automatic endpoint generation and API behavior\n */\n restConfig?: RestServerConfig;\n /**\n * Whether to register standard ObjectStack CRUD endpoints\n * @default true\n */\n registerStandardEndpoints?: boolean;\n /**\n * Whether to load endpoints from API Registry\n * @default true\n */\n useApiRegistry?: boolean;\n\n /**\n * Whether to enable SPA fallback\n * If true, returns index.html for non-API 404s\n * @default false\n */\n spaFallback?: boolean;\n}\n\n/**\n * Hono Server Plugin\n * \n * Provides HTTP server capabilities using Hono framework.\n * Registers the IHttpServer service so other plugins can register routes.\n * \n * Route registration is handled by plugins:\n * - `@objectstack/rest` → CRUD, metadata, discovery, UI, batch\n * - `createDispatcherPlugin()` → auth, graphql, analytics, packages, etc.\n */\nexport class HonoServerPlugin implements Plugin {\n name = 'com.objectstack.server.hono';\n type = 'server';\n version = '0.9.0';\n \n // Constants\n private static readonly DEFAULT_ENDPOINT_PRIORITY = 100;\n private static readonly CORE_ENDPOINT_PRIORITY = 950;\n private static readonly DISCOVERY_ENDPOINT_PRIORITY = 900;\n \n private options: HonoPluginOptions;\n private server: HonoHttpServer;\n\n constructor(options: HonoPluginOptions = {}) {\n this.options = { \n port: 3000,\n registerStandardEndpoints: true,\n useApiRegistry: true,\n spaFallback: false,\n ...options\n };\n // We handle static root manually in start() to support SPA fallback\n this.server = new HonoHttpServer(this.options.port);\n }\n\n /**\n * Init phase - Setup HTTP server and register as service\n */\n init = async (ctx: PluginContext) => {\n ctx.logger.debug('Initializing Hono server plugin', { \n port: this.options.port,\n staticRoot: this.options.staticRoot \n });\n \n // Register HTTP server service as IHttpServer\n // Register as 'http.server' to match core requirements\n ctx.registerService('http.server', this.server);\n // Alias 'http-server' for backward compatibility\n ctx.registerService('http-server', this.server);\n ctx.logger.debug('HTTP server service registered', { serviceName: 'http.server' });\n }\n\n /**\n * Start phase - Configure static files and start listening\n */\n start = async (ctx: PluginContext) => {\n ctx.logger.debug('Starting Hono server plugin');\n\n // Configure Static Files & SPA Fallback\n const mounts: StaticMount[] = this.options.staticMounts || [];\n\n // Auto-discover UI Plugins\n try {\n const rawKernel = ctx.getKernel() as any;\n if (rawKernel.plugins) {\n const loadedPlugins = rawKernel.plugins instanceof Map \n ? Array.from(rawKernel.plugins.values()) \n : Array.isArray(rawKernel.plugins) ? rawKernel.plugins : Object.values(rawKernel.plugins);\n\n for (const plugin of (loadedPlugins as any[])) {\n // Check for UI Plugin signature\n // Support legacy 'ui-plugin' and new 'ui' type\n if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath) {\n // Derive base route from name: @org/console -> console\n const slug = plugin.slug || plugin.name.split('/').pop();\n const baseRoute = `/${slug}`;\n \n ctx.logger.debug(`Auto-mounting UI Plugin: ${plugin.name}`, { \n path: baseRoute, \n root: plugin.staticPath \n });\n\n mounts.push({\n root: plugin.staticPath,\n path: baseRoute,\n rewrite: true, // Strip prefix: /console/assets/x -> /assets/x\n spa: true\n });\n\n // Handle Default Plugin Redirect\n if (plugin.default || plugin.isDefault) {\n const rawApp = this.server.getRawApp();\n rawApp.get('/', (c) => c.redirect(baseRoute));\n ctx.logger.debug(`Set default UI redirect: / -> ${baseRoute}`);\n }\n }\n }\n }\n } catch (err: any) {\n ctx.logger.warn('Failed to auto-discover UI plugins', { error: err.message || err });\n }\n\n // Backward compatibility for staticRoot\n if (this.options.staticRoot) {\n mounts.push({\n root: this.options.staticRoot,\n path: '/',\n rewrite: false,\n spa: this.options.spaFallback\n });\n }\n\n if (mounts.length > 0) {\n const rawApp = this.server.getRawApp();\n \n for (const mount of mounts) {\n const mountRoot = path.resolve(process.cwd(), mount.root);\n\n if (!fs.existsSync(mountRoot)) {\n ctx.logger.warn(`Static mount root not found: ${mountRoot}. Skipping.`);\n continue;\n }\n\n const mountPath = mount.path || '/';\n const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;\n const routePattern = normalizedPath === '/' ? '/*' : `${normalizedPath.replace(/\\/$/, '')}/*`;\n \n // Routes to register: both /mount and /mount/*\n const routes = normalizedPath === '/' ? [routePattern] : [normalizedPath, routePattern];\n\n ctx.logger.debug('Mounting static files', { \n to: routes, \n from: mountRoot, \n rewrite: mount.rewrite, \n spa: mount.spa \n });\n\n routes.forEach(route => {\n // 1. Serve Static Files\n rawApp.get(\n route, \n serveStatic({ \n root: mount.root,\n rewriteRequestPath: (reqPath) => {\n if (mount.rewrite && normalizedPath !== '/') {\n // /console/assets/style.css -> /assets/style.css\n if (reqPath.startsWith(normalizedPath)) {\n return reqPath.substring(normalizedPath.length) || '/';\n }\n }\n return reqPath;\n }\n })\n );\n\n // 2. SPA Fallback (Scoped)\n if (mount.spa) {\n rawApp.get(route, async (c, next) => {\n // Skip if API path check\n const config = this.options.restConfig || {};\n const basePath = config.api?.basePath || '/api';\n \n if (c.req.path.startsWith(basePath)) {\n return next();\n }\n\n return serveStatic({ \n root: mount.root,\n rewriteRequestPath: () => 'index.html'\n })(c, next);\n });\n }\n });\n }\n }\n\n // Start server on kernel:ready hook\n ctx.hook('kernel:ready', async () => {\n // Register standard endpoints before starting to listen\n if (this.options.registerStandardEndpoints) {\n this.registerDiscoveryAndCrudEndpoints(ctx);\n }\n\n const port = this.options.port ?? 3000;\n ctx.logger.debug('Starting HTTP server', { port });\n \n await this.server.listen(port);\n\n const actualPort = this.server.getPort();\n if (actualPort !== port) {\n ctx.logger.warn(`Port ${port} is in use, using port ${actualPort} instead`);\n }\n ctx.logger.info('HTTP server started successfully', {\n port: actualPort,\n url: `http://localhost:${actualPort}`\n });\n });\n }\n\n /**\n * Register discovery and basic CRUD endpoints.\n * Called when `registerStandardEndpoints` is true, before the server starts listening.\n */\n private registerDiscoveryAndCrudEndpoints(ctx: PluginContext) {\n const rawApp = this.server.getRawApp();\n const prefix = '/api/v1';\n\n // Build the standard discovery response\n const discovery = {\n version: 'v1',\n apiName: 'ObjectStack API',\n routes: {\n data: `${prefix}/data`,\n metadata: `${prefix}/meta`,\n auth: `${prefix}/auth`,\n packages: `${prefix}/packages`,\n analytics: `${prefix}/analytics`,\n realtime: `${prefix}/realtime`,\n workflow: `${prefix}/workflow`,\n automation: `${prefix}/automation`,\n ai: `${prefix}/ai`,\n notifications: `${prefix}/notifications`,\n i18n: `${prefix}/i18n`,\n storage: `${prefix}/storage`,\n ui: `${prefix}/ui`,\n },\n };\n\n // Discovery endpoints\n rawApp.get('/.well-known/objectstack', (c: any) => c.redirect(`${prefix}/discovery`));\n rawApp.get(`${prefix}/discovery`, (c: any) => c.json({ data: discovery }));\n\n ctx.logger.info('Registered discovery endpoints', { prefix });\n\n // Basic CRUD data endpoints — delegate to kernel.broker when available\n const getBroker = () => (ctx.getKernel() as any).broker;\n\n // Create\n rawApp.post(`${prefix}/data/:object`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const data = await c.req.json().catch(() => ({}));\n const result = await broker.call('data.create', { object, data }, {});\n return c.json(result);\n });\n\n // Get by ID\n rawApp.get(`${prefix}/data/:object/:id`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const id = c.req.param('id');\n const result = await broker.call('data.get', { object, id }, {});\n return result ? c.json(result) : c.json({ error: 'Not found' }, 404);\n });\n\n // Find / List\n rawApp.get(`${prefix}/data/:object`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const filters = c.req.query();\n const result = await broker.call('data.find', { object, filters }, {});\n return c.json(result);\n });\n\n ctx.logger.debug('Registered standard CRUD data endpoints', { prefix });\n }\n\n /**\n * Destroy phase - Stop server\n */\n async destroy() {\n this.server.close();\n // Note: Can't use ctx.logger here since we're in destroy\n console.log('[HonoServerPlugin] Server stopped');\n }\n}\n"],"mappings":"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","names":["resolve","path","import_serve_static"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/hono-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './hono-plugin';\nexport * from './adapter';\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Export IHttpServer from core\nexport * from '@objectstack/core';\n\nimport {\n IHttpServer,\n RouteHandler,\n Middleware\n} from '@objectstack/core';\nimport { Hono } from 'hono';\nimport { serve } from '@hono/node-server';\nimport { serveStatic } from '@hono/node-server/serve-static';\n\nexport interface HonoCorsOptions {\n enabled?: boolean;\n origins?: string | string[];\n methods?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\n/**\n * Hono Implementation of IHttpServer\n */\nexport class HonoHttpServer implements IHttpServer {\n private app: Hono;\n private server: any;\n private listeningPort: number | undefined;\n\n constructor(\n private port: number = 3000,\n private staticRoot?: string\n ) {\n this.app = new Hono();\n }\n\n // internal helper to convert standard handler to Hono handler\n private wrap(handler: RouteHandler) {\n return async (c: any) => {\n let body: any = {};\n\n // Try to parse JSON body first if content-type is JSON\n if (c.req.header('content-type')?.includes('application/json')) {\n try {\n body = await c.req.json();\n } catch(e) {\n // If JSON parsing fails, try parseBody\n try {\n body = await c.req.parseBody();\n } catch(e2) {}\n }\n } else {\n // For non-JSON content types, use parseBody\n try {\n body = await c.req.parseBody();\n } catch(e) {}\n }\n\n const req = {\n params: c.req.param(),\n query: c.req.query(),\n body,\n headers: c.req.header(),\n method: c.req.method,\n path: c.req.path\n };\n\n let capturedResponse: any;\n let streamController: ReadableStreamDefaultController | null = null;\n let streamEncoder: TextEncoder | null = null;\n let streamHeaders: Record<string, string> = {};\n let isStreaming = false;\n\n const res = {\n json: (data: any) => { capturedResponse = c.json(data); },\n send: (data: string) => { capturedResponse = c.html(data); },\n status: (code: number) => { c.status(code); return res; },\n header: (name: string, value: string) => {\n c.header(name, value);\n streamHeaders[name] = value;\n return res;\n },\n write: (chunk: string | Uint8Array) => {\n isStreaming = true;\n if (streamController && streamEncoder) {\n const data = typeof chunk === 'string' ? streamEncoder.encode(chunk) : chunk;\n streamController.enqueue(data);\n }\n },\n end: () => {\n if (streamController) {\n streamController.close();\n }\n },\n };\n\n // Create a streaming response wrapper — if handler calls res.write(),\n // we return a ReadableStream; otherwise fall back to capturedResponse.\n const streamPromise = new Promise<Response | null>((resolve) => {\n const stream = new ReadableStream({\n start(controller) {\n streamController = controller;\n streamEncoder = new TextEncoder();\n },\n });\n\n // Run the handler; once it's done, check if streaming was used\n const result = handler(req as any, res as any);\n const done = result instanceof Promise ? result : Promise.resolve(result);\n done.then(() => {\n if (isStreaming) {\n resolve(new Response(stream, {\n status: 200,\n headers: streamHeaders,\n }));\n } else {\n // Not streaming — close the unused stream and return null\n streamController?.close();\n resolve(null);\n }\n }).catch(() => {\n streamController?.close();\n resolve(null);\n });\n });\n\n const streamResponse = await streamPromise;\n return streamResponse ?? capturedResponse;\n };\n }\n\n get(path: string, handler: RouteHandler) {\n this.app.get(path, this.wrap(handler));\n }\n post(path: string, handler: RouteHandler) {\n this.app.post(path, this.wrap(handler));\n }\n put(path: string, handler: RouteHandler) {\n this.app.put(path, this.wrap(handler));\n }\n delete(path: string, handler: RouteHandler) {\n this.app.delete(path, this.wrap(handler));\n }\n patch(path: string, handler: RouteHandler) {\n this.app.patch(path, this.wrap(handler));\n }\n\n use(pathOrHandler: string | Middleware, handler?: Middleware) {\n if (typeof pathOrHandler === 'string' && handler) {\n // Path based middleware\n // Hono middleware signature is different (c, next) => ...\n this.app.use(pathOrHandler, async (c, next) => {\n // Simplistic conversion\n await handler({} as any, {} as any, next);\n });\n } else if (typeof pathOrHandler === 'function') {\n // Global middleware\n this.app.use('*', async (c, next) => {\n await pathOrHandler({} as any, {} as any, next);\n });\n }\n }\n\n /**\n * Mount a sub-application or router\n */\n mount(path: string, subApp: Hono) {\n this.app.route(path, subApp);\n }\n\n\n async listen(port: number) {\n if (this.staticRoot) {\n this.app.get('/*', serveStatic({ root: this.staticRoot }));\n }\n\n const targetPort = port || this.port;\n const maxRetries = 20;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n const tryPort = targetPort + attempt;\n try {\n await this.tryListen(tryPort);\n return;\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < maxRetries - 1) {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n continue;\n }\n throw err;\n }\n }\n }\n\n private tryListen(port: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = serve({\n fetch: this.app.fetch,\n port\n }, (info) => {\n this.listeningPort = info.port;\n resolve();\n });\n this.server = server;\n server.on('error', (err: any) => {\n reject(err);\n });\n });\n }\n\n getPort() {\n return this.listeningPort || this.port;\n }\n\n // Expose raw app for scenarios where standard interface is not enough\n getRawApp() {\n return this.app;\n }\n\n async close() {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer, IDataEngine } from '@objectstack/core';\nimport {\n RestServerConfig,\n} from '@objectstack/spec/api';\nimport { HonoHttpServer, HonoCorsOptions } from './adapter';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface StaticMount {\n root: string;\n path?: string;\n rewrite?: boolean;\n spa?: boolean;\n}\n\nexport interface HonoPluginOptions {\n port?: number;\n staticRoot?: string;\n /**\n * Multiple static resource mounts\n */\n staticMounts?: StaticMount[];\n /**\n * REST server configuration\n * Controls automatic endpoint generation and API behavior\n */\n restConfig?: RestServerConfig;\n /**\n * Whether to register standard ObjectStack CRUD endpoints\n * @default true\n */\n registerStandardEndpoints?: boolean;\n /**\n * Whether to load endpoints from API Registry\n * @default true\n */\n useApiRegistry?: boolean;\n\n /**\n * Whether to enable SPA fallback\n * If true, returns index.html for non-API 404s\n * @default false\n */\n spaFallback?: boolean;\n\n /**\n * CORS configuration. Set to `false` to disable entirely.\n * Enabled by default with origin '*'.\n * Can also be controlled via environment variables:\n * CORS_ENABLED, CORS_ORIGIN, CORS_CREDENTIALS, CORS_MAX_AGE\n */\n cors?: HonoCorsOptions | false;\n}\n\n/**\n * Hono Server Plugin\n *\n * Provides HTTP server capabilities using Hono framework.\n * Registers the IHttpServer service so other plugins can register routes.\n *\n * Route registration is handled by plugins:\n * - `@objectstack/rest` → CRUD, metadata, discovery, UI, batch\n * - `createDispatcherPlugin()` → auth, graphql, analytics, packages, etc.\n */\n/**\n * Check if an origin matches a pattern with wildcards.\n * Supports patterns like:\n * - \"https://*.example.com\" - matches any subdomain\n * - \"http://localhost:*\" - matches any port\n * - \"https://*.objectui.org,https://*.objectstack.ai\" - comma-separated patterns\n *\n * @param origin The origin to check (e.g., \"https://app.example.com\")\n * @param pattern The pattern to match against (supports * wildcard)\n * @returns true if origin matches the pattern\n */\nfunction matchOriginPattern(origin: string, pattern: string): boolean {\n if (pattern === '*') return true;\n if (pattern === origin) return true;\n\n // Convert wildcard pattern to regex\n // Escape special regex characters except *\n const regexPattern = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special chars\n .replace(/\\*/g, '.*'); // Convert * to .*\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(origin);\n}\n\n/**\n * Create a CORS origin matcher function that supports wildcard patterns.\n *\n * @param patterns Single pattern, array of patterns, or comma-separated patterns\n * @returns Function that returns the origin if it matches, or null/undefined\n */\nfunction createOriginMatcher(\n patterns: string | string[]\n): (origin: string) => string | undefined | null {\n // Normalize to array\n let patternList: string[];\n if (typeof patterns === 'string') {\n // Handle comma-separated patterns\n patternList = patterns.includes(',')\n ? patterns.split(',').map(s => s.trim()).filter(Boolean)\n : [patterns];\n } else {\n patternList = patterns;\n }\n\n // Return matcher function\n return (requestOrigin: string) => {\n for (const pattern of patternList) {\n if (matchOriginPattern(requestOrigin, pattern)) {\n return requestOrigin;\n }\n }\n return null;\n };\n}\n\nexport class HonoServerPlugin implements Plugin {\n name = 'com.objectstack.server.hono';\n type = 'server';\n version = '0.9.0';\n\n // Constants\n private static readonly DEFAULT_ENDPOINT_PRIORITY = 100;\n private static readonly CORE_ENDPOINT_PRIORITY = 950;\n private static readonly DISCOVERY_ENDPOINT_PRIORITY = 900;\n\n private options: HonoPluginOptions;\n private server: HonoHttpServer;\n\n constructor(options: HonoPluginOptions = {}) {\n this.options = {\n port: 3000,\n registerStandardEndpoints: true,\n useApiRegistry: true,\n spaFallback: false,\n ...options\n };\n // We handle static root manually in start() to support SPA fallback\n this.server = new HonoHttpServer(this.options.port);\n }\n\n /**\n * Init phase - Setup HTTP server and register as service\n */\n init = async (ctx: PluginContext) => {\n ctx.logger.debug('Initializing Hono server plugin', {\n port: this.options.port,\n staticRoot: this.options.staticRoot\n });\n\n // Register HTTP server service as IHttpServer\n // Register as 'http.server' to match core requirements\n ctx.registerService('http.server', this.server);\n // Alias 'http-server' for backward compatibility\n ctx.registerService('http-server', this.server);\n ctx.logger.debug('HTTP server service registered', { serviceName: 'http.server' });\n\n // ─── CORS Middleware ──────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables.\n const corsDisabledByEnv = process.env.CORS_ENABLED === 'false';\n if (this.options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof this.options.cors === 'object' ? this.options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n let configuredOrigin: string | string[];\n if (corsOpts.origins) {\n configuredOrigin = corsOpts.origins;\n } else if (process.env.CORS_ORIGIN) {\n const envOrigin = process.env.CORS_ORIGIN.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (process.env.CORS_CREDENTIALS !== 'false');\n const maxAge = corsOpts.maxAge ?? (process.env.CORS_MAX_AGE ? parseInt(process.env.CORS_MAX_AGE, 10) : 86400);\n\n // Determine origin handler based on configuration\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n\n // Check if patterns contain wildcards (*, subdomain patterns, port patterns)\n const hasWildcard = (patterns: string | string[]): boolean => {\n const list = Array.isArray(patterns) ? patterns : [patterns];\n return list.some(p => p.includes('*'));\n };\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\"), always use a matcher function.\n // For exact origins, we can pass them directly as string/array.\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' - reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcard(configuredOrigin)) {\n // Wildcard patterns (including better-auth style patterns like \"https://*.objectui.org\")\n // Use pattern matcher to support subdomain and port wildcards\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) - pass through as-is\n origin = configuredOrigin;\n }\n\n const rawApp = this.server.getRawApp();\n rawApp.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],\n exposeHeaders: [],\n credentials,\n maxAge,\n }));\n\n ctx.logger.debug('CORS middleware enabled', { origin: configuredOrigin, credentials });\n }\n }\n }\n\n /**\n * Start phase - Configure static files and start listening\n */\n start = async (ctx: PluginContext) => {\n ctx.logger.debug('Starting Hono server plugin');\n\n // Configure Static Files & SPA Fallback\n const mounts: StaticMount[] = this.options.staticMounts || [];\n\n // Auto-discover UI Plugins\n try {\n const rawKernel = ctx.getKernel() as any;\n if (rawKernel.plugins) {\n const loadedPlugins = rawKernel.plugins instanceof Map\n ? Array.from(rawKernel.plugins.values())\n : Array.isArray(rawKernel.plugins) ? rawKernel.plugins : Object.values(rawKernel.plugins);\n\n for (const plugin of (loadedPlugins as any[])) {\n // Check for UI Plugin signature\n // Support legacy 'ui-plugin' and new 'ui' type\n if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath) {\n // Derive base route from name: @org/console -> console\n const slug = plugin.slug || plugin.name.split('/').pop();\n const baseRoute = `/${slug}`;\n\n ctx.logger.debug(`Auto-mounting UI Plugin: ${plugin.name}`, {\n path: baseRoute,\n root: plugin.staticPath\n });\n\n mounts.push({\n root: plugin.staticPath,\n path: baseRoute,\n rewrite: true, // Strip prefix: /console/assets/x -> /assets/x\n spa: true\n });\n\n // Handle Default Plugin Redirect\n if (plugin.default || plugin.isDefault) {\n const rawApp = this.server.getRawApp();\n rawApp.get('/', (c) => c.redirect(baseRoute));\n ctx.logger.debug(`Set default UI redirect: / -> ${baseRoute}`);\n }\n }\n }\n }\n } catch (err: any) {\n ctx.logger.warn('Failed to auto-discover UI plugins', { error: err.message || err });\n }\n\n // Backward compatibility for staticRoot\n if (this.options.staticRoot) {\n mounts.push({\n root: this.options.staticRoot,\n path: '/',\n rewrite: false,\n spa: this.options.spaFallback\n });\n }\n\n if (mounts.length > 0) {\n const rawApp = this.server.getRawApp();\n\n for (const mount of mounts) {\n const mountRoot = path.resolve(process.cwd(), mount.root);\n\n if (!fs.existsSync(mountRoot)) {\n ctx.logger.warn(`Static mount root not found: ${mountRoot}. Skipping.`);\n continue;\n }\n\n const mountPath = mount.path || '/';\n const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;\n const routePattern = normalizedPath === '/' ? '/*' : `${normalizedPath.replace(/\\/$/, '')}/*`;\n\n // Routes to register: both /mount and /mount/*\n const routes = normalizedPath === '/' ? [routePattern] : [normalizedPath, routePattern];\n\n ctx.logger.debug('Mounting static files', {\n to: routes,\n from: mountRoot,\n rewrite: mount.rewrite,\n spa: mount.spa\n });\n\n routes.forEach(route => {\n // 1. Serve Static Files\n rawApp.get(\n route,\n serveStatic({\n root: mount.root,\n rewriteRequestPath: (reqPath) => {\n if (mount.rewrite && normalizedPath !== '/') {\n // /console/assets/style.css -> /assets/style.css\n if (reqPath.startsWith(normalizedPath)) {\n return reqPath.substring(normalizedPath.length) || '/';\n }\n }\n return reqPath;\n }\n })\n );\n\n // 2. SPA Fallback (Scoped)\n if (mount.spa) {\n rawApp.get(route, async (c, next) => {\n // Skip if API path check\n const config = this.options.restConfig || {};\n const basePath = config.api?.basePath || '/api';\n\n if (c.req.path.startsWith(basePath)) {\n return next();\n }\n\n return serveStatic({\n root: mount.root,\n rewriteRequestPath: () => 'index.html'\n })(c, next);\n });\n }\n });\n }\n }\n\n // Start server on kernel:ready hook\n ctx.hook('kernel:ready', async () => {\n // Register standard endpoints before starting to listen\n if (this.options.registerStandardEndpoints) {\n this.registerDiscoveryAndCrudEndpoints(ctx);\n }\n\n const port = this.options.port ?? 3000;\n ctx.logger.debug('Starting HTTP server', { port });\n\n await this.server.listen(port);\n\n const actualPort = this.server.getPort();\n if (actualPort !== port) {\n ctx.logger.warn(`Port ${port} is in use, using port ${actualPort} instead`);\n }\n ctx.logger.info('HTTP server started successfully', {\n port: actualPort,\n url: `http://localhost:${actualPort}`\n });\n });\n }\n\n /**\n * Register discovery and basic CRUD endpoints.\n * Called when `registerStandardEndpoints` is true, before the server starts listening.\n */\n private registerDiscoveryAndCrudEndpoints(ctx: PluginContext) {\n const rawApp = this.server.getRawApp();\n const prefix = '/api/v1';\n\n // Build the standard discovery response\n const discovery = {\n version: 'v1',\n apiName: 'ObjectStack API',\n routes: {\n data: `${prefix}/data`,\n metadata: `${prefix}/meta`,\n auth: `${prefix}/auth`,\n packages: `${prefix}/packages`,\n analytics: `${prefix}/analytics`,\n realtime: `${prefix}/realtime`,\n workflow: `${prefix}/workflow`,\n automation: `${prefix}/automation`,\n ai: `${prefix}/ai`,\n notifications: `${prefix}/notifications`,\n i18n: `${prefix}/i18n`,\n storage: `${prefix}/storage`,\n ui: `${prefix}/ui`,\n },\n };\n\n // Discovery endpoints\n rawApp.get('/.well-known/objectstack', (c: any) => c.redirect(`${prefix}/discovery`));\n rawApp.get(`${prefix}/discovery`, (c: any) => c.json({ data: discovery }));\n\n ctx.logger.info('Registered discovery endpoints', { prefix });\n\n // Basic CRUD data endpoints — delegate to ObjectQL service directly\n const getObjectQL = () => ctx.getService<IDataEngine>('objectql');\n\n // Create\n rawApp.post(`${prefix}/data/:object`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n const data = await c.req.json().catch(() => ({}));\n const res = await ql.insert(object, data);\n const record = { ...data, ...res };\n return c.json({ object, id: record.id, record });\n });\n\n // Get by ID\n rawApp.get(`${prefix}/data/:object/:id`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n const id = c.req.param('id');\n let all = await ql.find(object);\n if (!all) all = [];\n const match = all.find((i: any) => i.id === id);\n return match ? c.json({ object, id, record: match }) : c.json({ error: 'Not found' }, 404);\n });\n\n // Find / List\n rawApp.get(`${prefix}/data/:object`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n let all = await ql.find(object);\n if (!Array.isArray(all) && all && (all as any).value) all = (all as any).value;\n if (!all) all = [];\n return c.json({ object, records: all, total: all.length });\n });\n\n ctx.logger.debug('Registered standard CRUD data endpoints', { prefix });\n }\n\n /**\n * Destroy phase - Stop server\n */\n async destroy() {\n this.server.close();\n // Note: Can't use ctx.logger here since we're in destroy\n console.log('[HonoServerPlugin] Server stopped');\n }\n}\n"],"mappings":"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","names":["resolve","path","import_serve_static"]}
package/dist/index.mjs CHANGED
@@ -37,8 +37,8 @@ import { serve } from "@hono/node-server";
37
37
  import { serveStatic } from "@hono/node-server/serve-static";
38
38
  var HonoHttpServer = class {
39
39
  constructor(port = 3e3, staticRoot) {
40
- this.port = port;
41
- this.staticRoot = staticRoot;
40
+ __publicField(this, "port", port);
41
+ __publicField(this, "staticRoot", staticRoot);
42
42
  __publicField(this, "app");
43
43
  __publicField(this, "server");
44
44
  __publicField(this, "listeningPort");
@@ -217,9 +217,33 @@ var HonoHttpServer = class {
217
217
  };
218
218
 
219
219
  // src/hono-plugin.ts
220
+ import { cors } from "hono/cors";
220
221
  import { serveStatic as serveStatic2 } from "@hono/node-server/serve-static";
221
222
  import * as fs from "fs";
222
223
  import * as path from "path";
224
+ function matchOriginPattern(origin, pattern) {
225
+ if (pattern === "*") return true;
226
+ if (pattern === origin) return true;
227
+ const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
228
+ const regex = new RegExp(`^${regexPattern}$`);
229
+ return regex.test(origin);
230
+ }
231
+ function createOriginMatcher(patterns) {
232
+ let patternList;
233
+ if (typeof patterns === "string") {
234
+ patternList = patterns.includes(",") ? patterns.split(",").map((s) => s.trim()).filter(Boolean) : [patterns];
235
+ } else {
236
+ patternList = patterns;
237
+ }
238
+ return (requestOrigin) => {
239
+ for (const pattern of patternList) {
240
+ if (matchOriginPattern(requestOrigin, pattern)) {
241
+ return requestOrigin;
242
+ }
243
+ }
244
+ return null;
245
+ };
246
+ }
223
247
  var HonoServerPlugin = class {
224
248
  constructor(options = {}) {
225
249
  __publicField(this, "name", "com.objectstack.server.hono");
@@ -238,6 +262,46 @@ var HonoServerPlugin = class {
238
262
  ctx.registerService("http.server", this.server);
239
263
  ctx.registerService("http-server", this.server);
240
264
  ctx.logger.debug("HTTP server service registered", { serviceName: "http.server" });
265
+ const corsDisabledByEnv = process.env.CORS_ENABLED === "false";
266
+ if (this.options.cors !== false && !corsDisabledByEnv) {
267
+ const corsOpts = typeof this.options.cors === "object" ? this.options.cors : {};
268
+ const enabled = corsOpts.enabled ?? true;
269
+ if (enabled) {
270
+ let configuredOrigin;
271
+ if (corsOpts.origins) {
272
+ configuredOrigin = corsOpts.origins;
273
+ } else if (process.env.CORS_ORIGIN) {
274
+ const envOrigin = process.env.CORS_ORIGIN.trim();
275
+ configuredOrigin = envOrigin.includes(",") ? envOrigin.split(",").map((s) => s.trim()) : envOrigin;
276
+ } else {
277
+ configuredOrigin = "*";
278
+ }
279
+ const credentials = corsOpts.credentials ?? process.env.CORS_CREDENTIALS !== "false";
280
+ const maxAge = corsOpts.maxAge ?? (process.env.CORS_MAX_AGE ? parseInt(process.env.CORS_MAX_AGE, 10) : 86400);
281
+ let origin;
282
+ const hasWildcard = (patterns) => {
283
+ const list = Array.isArray(patterns) ? patterns : [patterns];
284
+ return list.some((p) => p.includes("*"));
285
+ };
286
+ if (configuredOrigin === "*" && credentials) {
287
+ origin = (requestOrigin) => requestOrigin || "*";
288
+ } else if (hasWildcard(configuredOrigin)) {
289
+ origin = createOriginMatcher(configuredOrigin);
290
+ } else {
291
+ origin = configuredOrigin;
292
+ }
293
+ const rawApp = this.server.getRawApp();
294
+ rawApp.use("*", cors({
295
+ origin,
296
+ allowMethods: corsOpts.methods || ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"],
297
+ allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
298
+ exposeHeaders: [],
299
+ credentials,
300
+ maxAge
301
+ }));
302
+ ctx.logger.debug("CORS middleware enabled", { origin: configuredOrigin, credentials });
303
+ }
304
+ }
241
305
  });
242
306
  /**
243
307
  * Start phase - Configure static files and start listening
@@ -387,30 +451,34 @@ var HonoServerPlugin = class {
387
451
  rawApp.get("/.well-known/objectstack", (c) => c.redirect(`${prefix}/discovery`));
388
452
  rawApp.get(`${prefix}/discovery`, (c) => c.json({ data: discovery }));
389
453
  ctx.logger.info("Registered discovery endpoints", { prefix });
390
- const getBroker = () => ctx.getKernel().broker;
454
+ const getObjectQL = () => ctx.getService("objectql");
391
455
  rawApp.post(`${prefix}/data/:object`, async (c) => {
392
- const broker = getBroker();
393
- if (!broker) return c.json({ error: "Broker not available" }, 500);
456
+ const ql = getObjectQL();
457
+ if (!ql) return c.json({ error: "Data service not available" }, 503);
394
458
  const object = c.req.param("object");
395
459
  const data = await c.req.json().catch(() => ({}));
396
- const result = await broker.call("data.create", { object, data }, {});
397
- return c.json(result);
460
+ const res = await ql.insert(object, data);
461
+ const record = { ...data, ...res };
462
+ return c.json({ object, id: record.id, record });
398
463
  });
399
464
  rawApp.get(`${prefix}/data/:object/:id`, async (c) => {
400
- const broker = getBroker();
401
- if (!broker) return c.json({ error: "Broker not available" }, 500);
465
+ const ql = getObjectQL();
466
+ if (!ql) return c.json({ error: "Data service not available" }, 503);
402
467
  const object = c.req.param("object");
403
468
  const id = c.req.param("id");
404
- const result = await broker.call("data.get", { object, id }, {});
405
- return result ? c.json(result) : c.json({ error: "Not found" }, 404);
469
+ let all = await ql.find(object);
470
+ if (!all) all = [];
471
+ const match = all.find((i) => i.id === id);
472
+ return match ? c.json({ object, id, record: match }) : c.json({ error: "Not found" }, 404);
406
473
  });
407
474
  rawApp.get(`${prefix}/data/:object`, async (c) => {
408
- const broker = getBroker();
409
- if (!broker) return c.json({ error: "Broker not available" }, 500);
475
+ const ql = getObjectQL();
476
+ if (!ql) return c.json({ error: "Data service not available" }, 503);
410
477
  const object = c.req.param("object");
411
- const filters = c.req.query();
412
- const result = await broker.call("data.find", { object, filters }, {});
413
- return c.json(result);
478
+ let all = await ql.find(object);
479
+ if (!Array.isArray(all) && all && all.value) all = all.value;
480
+ if (!all) all = [];
481
+ return c.json({ object, records: all, total: all.length });
414
482
  });
415
483
  ctx.logger.debug("Registered standard CRUD data endpoints", { prefix });
416
484
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/hono-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './hono-plugin';\nexport * from './adapter';\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Export IHttpServer from core\nexport * from '@objectstack/core';\n\nimport { \n IHttpServer, \n RouteHandler, \n Middleware \n} from '@objectstack/core';\nimport { Hono } from 'hono';\nimport { serve } from '@hono/node-server';\nimport { serveStatic } from '@hono/node-server/serve-static';\n\n/**\n * Hono Implementation of IHttpServer\n */\nexport class HonoHttpServer implements IHttpServer {\n private app: Hono;\n private server: any;\n private listeningPort: number | undefined;\n\n constructor(\n private port: number = 3000,\n private staticRoot?: string\n ) {\n this.app = new Hono();\n }\n\n // internal helper to convert standard handler to Hono handler\n private wrap(handler: RouteHandler) {\n return async (c: any) => {\n let body: any = {};\n\n // Try to parse JSON body first if content-type is JSON\n if (c.req.header('content-type')?.includes('application/json')) {\n try {\n body = await c.req.json();\n } catch(e) {\n // If JSON parsing fails, try parseBody\n try {\n body = await c.req.parseBody();\n } catch(e2) {}\n }\n } else {\n // For non-JSON content types, use parseBody\n try {\n body = await c.req.parseBody();\n } catch(e) {}\n }\n\n const req = {\n params: c.req.param(),\n query: c.req.query(),\n body,\n headers: c.req.header(),\n method: c.req.method,\n path: c.req.path\n };\n\n let capturedResponse: any;\n let streamController: ReadableStreamDefaultController | null = null;\n let streamEncoder: TextEncoder | null = null;\n let streamHeaders: Record<string, string> = {};\n let isStreaming = false;\n\n const res = {\n json: (data: any) => { capturedResponse = c.json(data); },\n send: (data: string) => { capturedResponse = c.html(data); },\n status: (code: number) => { c.status(code); return res; },\n header: (name: string, value: string) => {\n c.header(name, value);\n streamHeaders[name] = value;\n return res;\n },\n write: (chunk: string | Uint8Array) => {\n isStreaming = true;\n if (streamController && streamEncoder) {\n const data = typeof chunk === 'string' ? streamEncoder.encode(chunk) : chunk;\n streamController.enqueue(data);\n }\n },\n end: () => {\n if (streamController) {\n streamController.close();\n }\n },\n };\n\n // Create a streaming response wrapper — if handler calls res.write(),\n // we return a ReadableStream; otherwise fall back to capturedResponse.\n const streamPromise = new Promise<Response | null>((resolve) => {\n const stream = new ReadableStream({\n start(controller) {\n streamController = controller;\n streamEncoder = new TextEncoder();\n },\n });\n\n // Run the handler; once it's done, check if streaming was used\n const result = handler(req as any, res as any);\n const done = result instanceof Promise ? result : Promise.resolve(result);\n done.then(() => {\n if (isStreaming) {\n resolve(new Response(stream, {\n status: 200,\n headers: streamHeaders,\n }));\n } else {\n // Not streaming — close the unused stream and return null\n streamController?.close();\n resolve(null);\n }\n }).catch(() => {\n streamController?.close();\n resolve(null);\n });\n });\n\n const streamResponse = await streamPromise;\n return streamResponse ?? capturedResponse;\n };\n }\n\n get(path: string, handler: RouteHandler) {\n this.app.get(path, this.wrap(handler));\n }\n post(path: string, handler: RouteHandler) {\n this.app.post(path, this.wrap(handler));\n }\n put(path: string, handler: RouteHandler) {\n this.app.put(path, this.wrap(handler));\n }\n delete(path: string, handler: RouteHandler) {\n this.app.delete(path, this.wrap(handler));\n }\n patch(path: string, handler: RouteHandler) {\n this.app.patch(path, this.wrap(handler));\n }\n \n use(pathOrHandler: string | Middleware, handler?: Middleware) {\n if (typeof pathOrHandler === 'string' && handler) {\n // Path based middleware\n // Hono middleware signature is different (c, next) => ...\n this.app.use(pathOrHandler, async (c, next) => {\n // Simplistic conversion\n await handler({} as any, {} as any, next);\n });\n } else if (typeof pathOrHandler === 'function') {\n // Global middleware\n this.app.use('*', async (c, next) => {\n await pathOrHandler({} as any, {} as any, next);\n });\n }\n }\n\n /**\n * Mount a sub-application or router\n */\n mount(path: string, subApp: Hono) {\n this.app.route(path, subApp);\n }\n\n\n async listen(port: number) {\n if (this.staticRoot) {\n this.app.get('/*', serveStatic({ root: this.staticRoot }));\n }\n\n const targetPort = port || this.port;\n const maxRetries = 20;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n const tryPort = targetPort + attempt;\n try {\n await this.tryListen(tryPort);\n return;\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < maxRetries - 1) {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n continue;\n }\n throw err;\n }\n }\n }\n\n private tryListen(port: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = serve({\n fetch: this.app.fetch,\n port\n }, (info) => {\n this.listeningPort = info.port;\n resolve();\n });\n this.server = server;\n server.on('error', (err: any) => {\n reject(err);\n });\n });\n }\n\n getPort() {\n return this.listeningPort || this.port;\n }\n\n // Expose raw app for scenarios where standard interface is not enough\n getRawApp() {\n return this.app;\n }\n\n async close() {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n }\n\n\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer } from '@objectstack/core';\nimport {\n RestServerConfig,\n} from '@objectstack/spec/api';\nimport { HonoHttpServer } from './adapter';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface StaticMount {\n root: string;\n path?: string;\n rewrite?: boolean;\n spa?: boolean;\n}\n\nexport interface HonoPluginOptions {\n port?: number;\n staticRoot?: string;\n /**\n * Multiple static resource mounts\n */\n staticMounts?: StaticMount[];\n /**\n * REST server configuration\n * Controls automatic endpoint generation and API behavior\n */\n restConfig?: RestServerConfig;\n /**\n * Whether to register standard ObjectStack CRUD endpoints\n * @default true\n */\n registerStandardEndpoints?: boolean;\n /**\n * Whether to load endpoints from API Registry\n * @default true\n */\n useApiRegistry?: boolean;\n\n /**\n * Whether to enable SPA fallback\n * If true, returns index.html for non-API 404s\n * @default false\n */\n spaFallback?: boolean;\n}\n\n/**\n * Hono Server Plugin\n * \n * Provides HTTP server capabilities using Hono framework.\n * Registers the IHttpServer service so other plugins can register routes.\n * \n * Route registration is handled by plugins:\n * - `@objectstack/rest` → CRUD, metadata, discovery, UI, batch\n * - `createDispatcherPlugin()` → auth, graphql, analytics, packages, etc.\n */\nexport class HonoServerPlugin implements Plugin {\n name = 'com.objectstack.server.hono';\n type = 'server';\n version = '0.9.0';\n \n // Constants\n private static readonly DEFAULT_ENDPOINT_PRIORITY = 100;\n private static readonly CORE_ENDPOINT_PRIORITY = 950;\n private static readonly DISCOVERY_ENDPOINT_PRIORITY = 900;\n \n private options: HonoPluginOptions;\n private server: HonoHttpServer;\n\n constructor(options: HonoPluginOptions = {}) {\n this.options = { \n port: 3000,\n registerStandardEndpoints: true,\n useApiRegistry: true,\n spaFallback: false,\n ...options\n };\n // We handle static root manually in start() to support SPA fallback\n this.server = new HonoHttpServer(this.options.port);\n }\n\n /**\n * Init phase - Setup HTTP server and register as service\n */\n init = async (ctx: PluginContext) => {\n ctx.logger.debug('Initializing Hono server plugin', { \n port: this.options.port,\n staticRoot: this.options.staticRoot \n });\n \n // Register HTTP server service as IHttpServer\n // Register as 'http.server' to match core requirements\n ctx.registerService('http.server', this.server);\n // Alias 'http-server' for backward compatibility\n ctx.registerService('http-server', this.server);\n ctx.logger.debug('HTTP server service registered', { serviceName: 'http.server' });\n }\n\n /**\n * Start phase - Configure static files and start listening\n */\n start = async (ctx: PluginContext) => {\n ctx.logger.debug('Starting Hono server plugin');\n\n // Configure Static Files & SPA Fallback\n const mounts: StaticMount[] = this.options.staticMounts || [];\n\n // Auto-discover UI Plugins\n try {\n const rawKernel = ctx.getKernel() as any;\n if (rawKernel.plugins) {\n const loadedPlugins = rawKernel.plugins instanceof Map \n ? Array.from(rawKernel.plugins.values()) \n : Array.isArray(rawKernel.plugins) ? rawKernel.plugins : Object.values(rawKernel.plugins);\n\n for (const plugin of (loadedPlugins as any[])) {\n // Check for UI Plugin signature\n // Support legacy 'ui-plugin' and new 'ui' type\n if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath) {\n // Derive base route from name: @org/console -> console\n const slug = plugin.slug || plugin.name.split('/').pop();\n const baseRoute = `/${slug}`;\n \n ctx.logger.debug(`Auto-mounting UI Plugin: ${plugin.name}`, { \n path: baseRoute, \n root: plugin.staticPath \n });\n\n mounts.push({\n root: plugin.staticPath,\n path: baseRoute,\n rewrite: true, // Strip prefix: /console/assets/x -> /assets/x\n spa: true\n });\n\n // Handle Default Plugin Redirect\n if (plugin.default || plugin.isDefault) {\n const rawApp = this.server.getRawApp();\n rawApp.get('/', (c) => c.redirect(baseRoute));\n ctx.logger.debug(`Set default UI redirect: / -> ${baseRoute}`);\n }\n }\n }\n }\n } catch (err: any) {\n ctx.logger.warn('Failed to auto-discover UI plugins', { error: err.message || err });\n }\n\n // Backward compatibility for staticRoot\n if (this.options.staticRoot) {\n mounts.push({\n root: this.options.staticRoot,\n path: '/',\n rewrite: false,\n spa: this.options.spaFallback\n });\n }\n\n if (mounts.length > 0) {\n const rawApp = this.server.getRawApp();\n \n for (const mount of mounts) {\n const mountRoot = path.resolve(process.cwd(), mount.root);\n\n if (!fs.existsSync(mountRoot)) {\n ctx.logger.warn(`Static mount root not found: ${mountRoot}. Skipping.`);\n continue;\n }\n\n const mountPath = mount.path || '/';\n const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;\n const routePattern = normalizedPath === '/' ? '/*' : `${normalizedPath.replace(/\\/$/, '')}/*`;\n \n // Routes to register: both /mount and /mount/*\n const routes = normalizedPath === '/' ? [routePattern] : [normalizedPath, routePattern];\n\n ctx.logger.debug('Mounting static files', { \n to: routes, \n from: mountRoot, \n rewrite: mount.rewrite, \n spa: mount.spa \n });\n\n routes.forEach(route => {\n // 1. Serve Static Files\n rawApp.get(\n route, \n serveStatic({ \n root: mount.root,\n rewriteRequestPath: (reqPath) => {\n if (mount.rewrite && normalizedPath !== '/') {\n // /console/assets/style.css -> /assets/style.css\n if (reqPath.startsWith(normalizedPath)) {\n return reqPath.substring(normalizedPath.length) || '/';\n }\n }\n return reqPath;\n }\n })\n );\n\n // 2. SPA Fallback (Scoped)\n if (mount.spa) {\n rawApp.get(route, async (c, next) => {\n // Skip if API path check\n const config = this.options.restConfig || {};\n const basePath = config.api?.basePath || '/api';\n \n if (c.req.path.startsWith(basePath)) {\n return next();\n }\n\n return serveStatic({ \n root: mount.root,\n rewriteRequestPath: () => 'index.html'\n })(c, next);\n });\n }\n });\n }\n }\n\n // Start server on kernel:ready hook\n ctx.hook('kernel:ready', async () => {\n // Register standard endpoints before starting to listen\n if (this.options.registerStandardEndpoints) {\n this.registerDiscoveryAndCrudEndpoints(ctx);\n }\n\n const port = this.options.port ?? 3000;\n ctx.logger.debug('Starting HTTP server', { port });\n \n await this.server.listen(port);\n\n const actualPort = this.server.getPort();\n if (actualPort !== port) {\n ctx.logger.warn(`Port ${port} is in use, using port ${actualPort} instead`);\n }\n ctx.logger.info('HTTP server started successfully', {\n port: actualPort,\n url: `http://localhost:${actualPort}`\n });\n });\n }\n\n /**\n * Register discovery and basic CRUD endpoints.\n * Called when `registerStandardEndpoints` is true, before the server starts listening.\n */\n private registerDiscoveryAndCrudEndpoints(ctx: PluginContext) {\n const rawApp = this.server.getRawApp();\n const prefix = '/api/v1';\n\n // Build the standard discovery response\n const discovery = {\n version: 'v1',\n apiName: 'ObjectStack API',\n routes: {\n data: `${prefix}/data`,\n metadata: `${prefix}/meta`,\n auth: `${prefix}/auth`,\n packages: `${prefix}/packages`,\n analytics: `${prefix}/analytics`,\n realtime: `${prefix}/realtime`,\n workflow: `${prefix}/workflow`,\n automation: `${prefix}/automation`,\n ai: `${prefix}/ai`,\n notifications: `${prefix}/notifications`,\n i18n: `${prefix}/i18n`,\n storage: `${prefix}/storage`,\n ui: `${prefix}/ui`,\n },\n };\n\n // Discovery endpoints\n rawApp.get('/.well-known/objectstack', (c: any) => c.redirect(`${prefix}/discovery`));\n rawApp.get(`${prefix}/discovery`, (c: any) => c.json({ data: discovery }));\n\n ctx.logger.info('Registered discovery endpoints', { prefix });\n\n // Basic CRUD data endpoints — delegate to kernel.broker when available\n const getBroker = () => (ctx.getKernel() as any).broker;\n\n // Create\n rawApp.post(`${prefix}/data/:object`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const data = await c.req.json().catch(() => ({}));\n const result = await broker.call('data.create', { object, data }, {});\n return c.json(result);\n });\n\n // Get by ID\n rawApp.get(`${prefix}/data/:object/:id`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const id = c.req.param('id');\n const result = await broker.call('data.get', { object, id }, {});\n return result ? c.json(result) : c.json({ error: 'Not found' }, 404);\n });\n\n // Find / List\n rawApp.get(`${prefix}/data/:object`, async (c: any) => {\n const broker = getBroker();\n if (!broker) return c.json({ error: 'Broker not available' }, 500);\n const object = c.req.param('object');\n const filters = c.req.query();\n const result = await broker.call('data.find', { object, filters }, {});\n return c.json(result);\n });\n\n ctx.logger.debug('Registered standard CRUD data endpoints', { prefix });\n }\n\n /**\n * Destroy phase - Stop server\n */\n async destroy() {\n this.server.close();\n // Note: Can't use ctx.logger here since we're in destroy\n console.log('[HonoServerPlugin] Server stopped');\n }\n}\n"],"mappings":"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","names":["resolve","path","serveStatic","serveStatic"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/hono-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nexport * from './hono-plugin';\nexport * from './adapter';\n\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n// Export IHttpServer from core\nexport * from '@objectstack/core';\n\nimport {\n IHttpServer,\n RouteHandler,\n Middleware\n} from '@objectstack/core';\nimport { Hono } from 'hono';\nimport { serve } from '@hono/node-server';\nimport { serveStatic } from '@hono/node-server/serve-static';\n\nexport interface HonoCorsOptions {\n enabled?: boolean;\n origins?: string | string[];\n methods?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\n/**\n * Hono Implementation of IHttpServer\n */\nexport class HonoHttpServer implements IHttpServer {\n private app: Hono;\n private server: any;\n private listeningPort: number | undefined;\n\n constructor(\n private port: number = 3000,\n private staticRoot?: string\n ) {\n this.app = new Hono();\n }\n\n // internal helper to convert standard handler to Hono handler\n private wrap(handler: RouteHandler) {\n return async (c: any) => {\n let body: any = {};\n\n // Try to parse JSON body first if content-type is JSON\n if (c.req.header('content-type')?.includes('application/json')) {\n try {\n body = await c.req.json();\n } catch(e) {\n // If JSON parsing fails, try parseBody\n try {\n body = await c.req.parseBody();\n } catch(e2) {}\n }\n } else {\n // For non-JSON content types, use parseBody\n try {\n body = await c.req.parseBody();\n } catch(e) {}\n }\n\n const req = {\n params: c.req.param(),\n query: c.req.query(),\n body,\n headers: c.req.header(),\n method: c.req.method,\n path: c.req.path\n };\n\n let capturedResponse: any;\n let streamController: ReadableStreamDefaultController | null = null;\n let streamEncoder: TextEncoder | null = null;\n let streamHeaders: Record<string, string> = {};\n let isStreaming = false;\n\n const res = {\n json: (data: any) => { capturedResponse = c.json(data); },\n send: (data: string) => { capturedResponse = c.html(data); },\n status: (code: number) => { c.status(code); return res; },\n header: (name: string, value: string) => {\n c.header(name, value);\n streamHeaders[name] = value;\n return res;\n },\n write: (chunk: string | Uint8Array) => {\n isStreaming = true;\n if (streamController && streamEncoder) {\n const data = typeof chunk === 'string' ? streamEncoder.encode(chunk) : chunk;\n streamController.enqueue(data);\n }\n },\n end: () => {\n if (streamController) {\n streamController.close();\n }\n },\n };\n\n // Create a streaming response wrapper — if handler calls res.write(),\n // we return a ReadableStream; otherwise fall back to capturedResponse.\n const streamPromise = new Promise<Response | null>((resolve) => {\n const stream = new ReadableStream({\n start(controller) {\n streamController = controller;\n streamEncoder = new TextEncoder();\n },\n });\n\n // Run the handler; once it's done, check if streaming was used\n const result = handler(req as any, res as any);\n const done = result instanceof Promise ? result : Promise.resolve(result);\n done.then(() => {\n if (isStreaming) {\n resolve(new Response(stream, {\n status: 200,\n headers: streamHeaders,\n }));\n } else {\n // Not streaming — close the unused stream and return null\n streamController?.close();\n resolve(null);\n }\n }).catch(() => {\n streamController?.close();\n resolve(null);\n });\n });\n\n const streamResponse = await streamPromise;\n return streamResponse ?? capturedResponse;\n };\n }\n\n get(path: string, handler: RouteHandler) {\n this.app.get(path, this.wrap(handler));\n }\n post(path: string, handler: RouteHandler) {\n this.app.post(path, this.wrap(handler));\n }\n put(path: string, handler: RouteHandler) {\n this.app.put(path, this.wrap(handler));\n }\n delete(path: string, handler: RouteHandler) {\n this.app.delete(path, this.wrap(handler));\n }\n patch(path: string, handler: RouteHandler) {\n this.app.patch(path, this.wrap(handler));\n }\n\n use(pathOrHandler: string | Middleware, handler?: Middleware) {\n if (typeof pathOrHandler === 'string' && handler) {\n // Path based middleware\n // Hono middleware signature is different (c, next) => ...\n this.app.use(pathOrHandler, async (c, next) => {\n // Simplistic conversion\n await handler({} as any, {} as any, next);\n });\n } else if (typeof pathOrHandler === 'function') {\n // Global middleware\n this.app.use('*', async (c, next) => {\n await pathOrHandler({} as any, {} as any, next);\n });\n }\n }\n\n /**\n * Mount a sub-application or router\n */\n mount(path: string, subApp: Hono) {\n this.app.route(path, subApp);\n }\n\n\n async listen(port: number) {\n if (this.staticRoot) {\n this.app.get('/*', serveStatic({ root: this.staticRoot }));\n }\n\n const targetPort = port || this.port;\n const maxRetries = 20;\n\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n const tryPort = targetPort + attempt;\n try {\n await this.tryListen(tryPort);\n return;\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < maxRetries - 1) {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n continue;\n }\n throw err;\n }\n }\n }\n\n private tryListen(port: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = serve({\n fetch: this.app.fetch,\n port\n }, (info) => {\n this.listeningPort = info.port;\n resolve();\n });\n this.server = server;\n server.on('error', (err: any) => {\n reject(err);\n });\n });\n }\n\n getPort() {\n return this.listeningPort || this.port;\n }\n\n // Expose raw app for scenarios where standard interface is not enough\n getRawApp() {\n return this.app;\n }\n\n async close() {\n if (this.server && typeof this.server.close === 'function') {\n this.server.close();\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext, IHttpServer, IDataEngine } from '@objectstack/core';\nimport {\n RestServerConfig,\n} from '@objectstack/spec/api';\nimport { HonoHttpServer, HonoCorsOptions } from './adapter';\nimport { cors } from 'hono/cors';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface StaticMount {\n root: string;\n path?: string;\n rewrite?: boolean;\n spa?: boolean;\n}\n\nexport interface HonoPluginOptions {\n port?: number;\n staticRoot?: string;\n /**\n * Multiple static resource mounts\n */\n staticMounts?: StaticMount[];\n /**\n * REST server configuration\n * Controls automatic endpoint generation and API behavior\n */\n restConfig?: RestServerConfig;\n /**\n * Whether to register standard ObjectStack CRUD endpoints\n * @default true\n */\n registerStandardEndpoints?: boolean;\n /**\n * Whether to load endpoints from API Registry\n * @default true\n */\n useApiRegistry?: boolean;\n\n /**\n * Whether to enable SPA fallback\n * If true, returns index.html for non-API 404s\n * @default false\n */\n spaFallback?: boolean;\n\n /**\n * CORS configuration. Set to `false` to disable entirely.\n * Enabled by default with origin '*'.\n * Can also be controlled via environment variables:\n * CORS_ENABLED, CORS_ORIGIN, CORS_CREDENTIALS, CORS_MAX_AGE\n */\n cors?: HonoCorsOptions | false;\n}\n\n/**\n * Hono Server Plugin\n *\n * Provides HTTP server capabilities using Hono framework.\n * Registers the IHttpServer service so other plugins can register routes.\n *\n * Route registration is handled by plugins:\n * - `@objectstack/rest` → CRUD, metadata, discovery, UI, batch\n * - `createDispatcherPlugin()` → auth, graphql, analytics, packages, etc.\n */\n/**\n * Check if an origin matches a pattern with wildcards.\n * Supports patterns like:\n * - \"https://*.example.com\" - matches any subdomain\n * - \"http://localhost:*\" - matches any port\n * - \"https://*.objectui.org,https://*.objectstack.ai\" - comma-separated patterns\n *\n * @param origin The origin to check (e.g., \"https://app.example.com\")\n * @param pattern The pattern to match against (supports * wildcard)\n * @returns true if origin matches the pattern\n */\nfunction matchOriginPattern(origin: string, pattern: string): boolean {\n if (pattern === '*') return true;\n if (pattern === origin) return true;\n\n // Convert wildcard pattern to regex\n // Escape special regex characters except *\n const regexPattern = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special chars\n .replace(/\\*/g, '.*'); // Convert * to .*\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(origin);\n}\n\n/**\n * Create a CORS origin matcher function that supports wildcard patterns.\n *\n * @param patterns Single pattern, array of patterns, or comma-separated patterns\n * @returns Function that returns the origin if it matches, or null/undefined\n */\nfunction createOriginMatcher(\n patterns: string | string[]\n): (origin: string) => string | undefined | null {\n // Normalize to array\n let patternList: string[];\n if (typeof patterns === 'string') {\n // Handle comma-separated patterns\n patternList = patterns.includes(',')\n ? patterns.split(',').map(s => s.trim()).filter(Boolean)\n : [patterns];\n } else {\n patternList = patterns;\n }\n\n // Return matcher function\n return (requestOrigin: string) => {\n for (const pattern of patternList) {\n if (matchOriginPattern(requestOrigin, pattern)) {\n return requestOrigin;\n }\n }\n return null;\n };\n}\n\nexport class HonoServerPlugin implements Plugin {\n name = 'com.objectstack.server.hono';\n type = 'server';\n version = '0.9.0';\n\n // Constants\n private static readonly DEFAULT_ENDPOINT_PRIORITY = 100;\n private static readonly CORE_ENDPOINT_PRIORITY = 950;\n private static readonly DISCOVERY_ENDPOINT_PRIORITY = 900;\n\n private options: HonoPluginOptions;\n private server: HonoHttpServer;\n\n constructor(options: HonoPluginOptions = {}) {\n this.options = {\n port: 3000,\n registerStandardEndpoints: true,\n useApiRegistry: true,\n spaFallback: false,\n ...options\n };\n // We handle static root manually in start() to support SPA fallback\n this.server = new HonoHttpServer(this.options.port);\n }\n\n /**\n * Init phase - Setup HTTP server and register as service\n */\n init = async (ctx: PluginContext) => {\n ctx.logger.debug('Initializing Hono server plugin', {\n port: this.options.port,\n staticRoot: this.options.staticRoot\n });\n\n // Register HTTP server service as IHttpServer\n // Register as 'http.server' to match core requirements\n ctx.registerService('http.server', this.server);\n // Alias 'http-server' for backward compatibility\n ctx.registerService('http-server', this.server);\n ctx.logger.debug('HTTP server service registered', { serviceName: 'http.server' });\n\n // ─── CORS Middleware ──────────────────────────────────────────────────\n // Enabled by default. Controlled via options.cors or environment variables.\n const corsDisabledByEnv = process.env.CORS_ENABLED === 'false';\n if (this.options.cors !== false && !corsDisabledByEnv) {\n const corsOpts = typeof this.options.cors === 'object' ? this.options.cors : {};\n const enabled = corsOpts.enabled ?? true;\n\n if (enabled) {\n let configuredOrigin: string | string[];\n if (corsOpts.origins) {\n configuredOrigin = corsOpts.origins;\n } else if (process.env.CORS_ORIGIN) {\n const envOrigin = process.env.CORS_ORIGIN.trim();\n configuredOrigin = envOrigin.includes(',') ? envOrigin.split(',').map(s => s.trim()) : envOrigin;\n } else {\n configuredOrigin = '*';\n }\n\n const credentials = corsOpts.credentials ?? (process.env.CORS_CREDENTIALS !== 'false');\n const maxAge = corsOpts.maxAge ?? (process.env.CORS_MAX_AGE ? parseInt(process.env.CORS_MAX_AGE, 10) : 86400);\n\n // Determine origin handler based on configuration\n let origin: string | string[] | ((origin: string) => string | undefined | null);\n\n // Check if patterns contain wildcards (*, subdomain patterns, port patterns)\n const hasWildcard = (patterns: string | string[]): boolean => {\n const list = Array.isArray(patterns) ? patterns : [patterns];\n return list.some(p => p.includes('*'));\n };\n\n // When credentials is true, browsers reject wildcard '*' for Access-Control-Allow-Origin.\n // For wildcard patterns (like \"https://*.example.com\"), always use a matcher function.\n // For exact origins, we can pass them directly as string/array.\n if (configuredOrigin === '*' && credentials) {\n // Credentials mode with '*' - reflect the request origin\n origin = (requestOrigin: string) => requestOrigin || '*';\n } else if (hasWildcard(configuredOrigin)) {\n // Wildcard patterns (including better-auth style patterns like \"https://*.objectui.org\")\n // Use pattern matcher to support subdomain and port wildcards\n origin = createOriginMatcher(configuredOrigin);\n } else {\n // Exact origin(s) - pass through as-is\n origin = configuredOrigin;\n }\n\n const rawApp = this.server.getRawApp();\n rawApp.use('*', cors({\n origin: origin as any,\n allowMethods: corsOpts.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],\n exposeHeaders: [],\n credentials,\n maxAge,\n }));\n\n ctx.logger.debug('CORS middleware enabled', { origin: configuredOrigin, credentials });\n }\n }\n }\n\n /**\n * Start phase - Configure static files and start listening\n */\n start = async (ctx: PluginContext) => {\n ctx.logger.debug('Starting Hono server plugin');\n\n // Configure Static Files & SPA Fallback\n const mounts: StaticMount[] = this.options.staticMounts || [];\n\n // Auto-discover UI Plugins\n try {\n const rawKernel = ctx.getKernel() as any;\n if (rawKernel.plugins) {\n const loadedPlugins = rawKernel.plugins instanceof Map\n ? Array.from(rawKernel.plugins.values())\n : Array.isArray(rawKernel.plugins) ? rawKernel.plugins : Object.values(rawKernel.plugins);\n\n for (const plugin of (loadedPlugins as any[])) {\n // Check for UI Plugin signature\n // Support legacy 'ui-plugin' and new 'ui' type\n if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath) {\n // Derive base route from name: @org/console -> console\n const slug = plugin.slug || plugin.name.split('/').pop();\n const baseRoute = `/${slug}`;\n\n ctx.logger.debug(`Auto-mounting UI Plugin: ${plugin.name}`, {\n path: baseRoute,\n root: plugin.staticPath\n });\n\n mounts.push({\n root: plugin.staticPath,\n path: baseRoute,\n rewrite: true, // Strip prefix: /console/assets/x -> /assets/x\n spa: true\n });\n\n // Handle Default Plugin Redirect\n if (plugin.default || plugin.isDefault) {\n const rawApp = this.server.getRawApp();\n rawApp.get('/', (c) => c.redirect(baseRoute));\n ctx.logger.debug(`Set default UI redirect: / -> ${baseRoute}`);\n }\n }\n }\n }\n } catch (err: any) {\n ctx.logger.warn('Failed to auto-discover UI plugins', { error: err.message || err });\n }\n\n // Backward compatibility for staticRoot\n if (this.options.staticRoot) {\n mounts.push({\n root: this.options.staticRoot,\n path: '/',\n rewrite: false,\n spa: this.options.spaFallback\n });\n }\n\n if (mounts.length > 0) {\n const rawApp = this.server.getRawApp();\n\n for (const mount of mounts) {\n const mountRoot = path.resolve(process.cwd(), mount.root);\n\n if (!fs.existsSync(mountRoot)) {\n ctx.logger.warn(`Static mount root not found: ${mountRoot}. Skipping.`);\n continue;\n }\n\n const mountPath = mount.path || '/';\n const normalizedPath = mountPath.startsWith('/') ? mountPath : `/${mountPath}`;\n const routePattern = normalizedPath === '/' ? '/*' : `${normalizedPath.replace(/\\/$/, '')}/*`;\n\n // Routes to register: both /mount and /mount/*\n const routes = normalizedPath === '/' ? [routePattern] : [normalizedPath, routePattern];\n\n ctx.logger.debug('Mounting static files', {\n to: routes,\n from: mountRoot,\n rewrite: mount.rewrite,\n spa: mount.spa\n });\n\n routes.forEach(route => {\n // 1. Serve Static Files\n rawApp.get(\n route,\n serveStatic({\n root: mount.root,\n rewriteRequestPath: (reqPath) => {\n if (mount.rewrite && normalizedPath !== '/') {\n // /console/assets/style.css -> /assets/style.css\n if (reqPath.startsWith(normalizedPath)) {\n return reqPath.substring(normalizedPath.length) || '/';\n }\n }\n return reqPath;\n }\n })\n );\n\n // 2. SPA Fallback (Scoped)\n if (mount.spa) {\n rawApp.get(route, async (c, next) => {\n // Skip if API path check\n const config = this.options.restConfig || {};\n const basePath = config.api?.basePath || '/api';\n\n if (c.req.path.startsWith(basePath)) {\n return next();\n }\n\n return serveStatic({\n root: mount.root,\n rewriteRequestPath: () => 'index.html'\n })(c, next);\n });\n }\n });\n }\n }\n\n // Start server on kernel:ready hook\n ctx.hook('kernel:ready', async () => {\n // Register standard endpoints before starting to listen\n if (this.options.registerStandardEndpoints) {\n this.registerDiscoveryAndCrudEndpoints(ctx);\n }\n\n const port = this.options.port ?? 3000;\n ctx.logger.debug('Starting HTTP server', { port });\n\n await this.server.listen(port);\n\n const actualPort = this.server.getPort();\n if (actualPort !== port) {\n ctx.logger.warn(`Port ${port} is in use, using port ${actualPort} instead`);\n }\n ctx.logger.info('HTTP server started successfully', {\n port: actualPort,\n url: `http://localhost:${actualPort}`\n });\n });\n }\n\n /**\n * Register discovery and basic CRUD endpoints.\n * Called when `registerStandardEndpoints` is true, before the server starts listening.\n */\n private registerDiscoveryAndCrudEndpoints(ctx: PluginContext) {\n const rawApp = this.server.getRawApp();\n const prefix = '/api/v1';\n\n // Build the standard discovery response\n const discovery = {\n version: 'v1',\n apiName: 'ObjectStack API',\n routes: {\n data: `${prefix}/data`,\n metadata: `${prefix}/meta`,\n auth: `${prefix}/auth`,\n packages: `${prefix}/packages`,\n analytics: `${prefix}/analytics`,\n realtime: `${prefix}/realtime`,\n workflow: `${prefix}/workflow`,\n automation: `${prefix}/automation`,\n ai: `${prefix}/ai`,\n notifications: `${prefix}/notifications`,\n i18n: `${prefix}/i18n`,\n storage: `${prefix}/storage`,\n ui: `${prefix}/ui`,\n },\n };\n\n // Discovery endpoints\n rawApp.get('/.well-known/objectstack', (c: any) => c.redirect(`${prefix}/discovery`));\n rawApp.get(`${prefix}/discovery`, (c: any) => c.json({ data: discovery }));\n\n ctx.logger.info('Registered discovery endpoints', { prefix });\n\n // Basic CRUD data endpoints — delegate to ObjectQL service directly\n const getObjectQL = () => ctx.getService<IDataEngine>('objectql');\n\n // Create\n rawApp.post(`${prefix}/data/:object`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n const data = await c.req.json().catch(() => ({}));\n const res = await ql.insert(object, data);\n const record = { ...data, ...res };\n return c.json({ object, id: record.id, record });\n });\n\n // Get by ID\n rawApp.get(`${prefix}/data/:object/:id`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n const id = c.req.param('id');\n let all = await ql.find(object);\n if (!all) all = [];\n const match = all.find((i: any) => i.id === id);\n return match ? c.json({ object, id, record: match }) : c.json({ error: 'Not found' }, 404);\n });\n\n // Find / List\n rawApp.get(`${prefix}/data/:object`, async (c: any) => {\n const ql = getObjectQL();\n if (!ql) return c.json({ error: 'Data service not available' }, 503);\n const object = c.req.param('object');\n let all = await ql.find(object);\n if (!Array.isArray(all) && all && (all as any).value) all = (all as any).value;\n if (!all) all = [];\n return c.json({ object, records: all, total: all.length });\n });\n\n ctx.logger.debug('Registered standard CRUD data endpoints', { prefix });\n }\n\n /**\n * Destroy phase - Stop server\n */\n async destroy() {\n this.server.close();\n // Note: Can't use ctx.logger here since we're in destroy\n console.log('[HonoServerPlugin] Server stopped');\n }\n}\n"],"mappings":"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","names":["resolve","path","serveStatic","serveStatic"]}
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@objectstack/plugin-hono-server",
3
- "version": "4.0.2",
3
+ "version": "4.0.4",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Standard Hono Server Adapter for ObjectStack Runtime",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "dependencies": {
9
- "@hono/node-server": "^1.19.12",
10
- "hono": "^4.12.10",
11
- "@objectstack/core": "4.0.2",
12
- "@objectstack/spec": "4.0.2"
9
+ "@hono/node-server": "^1.19.14",
10
+ "hono": "^4.12.12",
11
+ "@objectstack/core": "4.0.4",
12
+ "@objectstack/spec": "4.0.4"
13
13
  },
14
14
  "devDependencies": {
15
- "@types/node": "^25.5.2",
15
+ "@types/node": "^25.6.0",
16
16
  "typescript": "^6.0.2",
17
- "vitest": "^4.1.2"
17
+ "vitest": "^4.1.4"
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tsup --config ../../../tsup.config.ts",
package/src/adapter.ts CHANGED
@@ -3,15 +3,23 @@
3
3
  // Export IHttpServer from core
4
4
  export * from '@objectstack/core';
5
5
 
6
- import {
7
- IHttpServer,
8
- RouteHandler,
9
- Middleware
6
+ import {
7
+ IHttpServer,
8
+ RouteHandler,
9
+ Middleware
10
10
  } from '@objectstack/core';
11
11
  import { Hono } from 'hono';
12
12
  import { serve } from '@hono/node-server';
13
13
  import { serveStatic } from '@hono/node-server/serve-static';
14
14
 
15
+ export interface HonoCorsOptions {
16
+ enabled?: boolean;
17
+ origins?: string | string[];
18
+ methods?: string[];
19
+ credentials?: boolean;
20
+ maxAge?: number;
21
+ }
22
+
15
23
  /**
16
24
  * Hono Implementation of IHttpServer
17
25
  */
@@ -137,7 +145,7 @@ export class HonoHttpServer implements IHttpServer {
137
145
  patch(path: string, handler: RouteHandler) {
138
146
  this.app.patch(path, this.wrap(handler));
139
147
  }
140
-
148
+
141
149
  use(pathOrHandler: string | Middleware, handler?: Middleware) {
142
150
  if (typeof pathOrHandler === 'string' && handler) {
143
151
  // Path based middleware
@@ -217,6 +225,4 @@ export class HonoHttpServer implements IHttpServer {
217
225
  this.server.close();
218
226
  }
219
227
  }
220
-
221
-
222
228
  }