{"_id":"@eldrin-project/eldrin-app-core","_rev":"5-fd2ddb40d3797ada4f067135f8ca4c13","name":"@eldrin-project/eldrin-app-core","dist-tags":{"latest":"0.0.5"},"versions":{"0.0.1":{"name":"@eldrin-project/eldrin-app-core","version":"0.0.1","keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"author":{"name":"Eldrin Team"},"license":"MIT","_id":"@eldrin-project/eldrin-app-core@0.0.1","maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"bin":{"eldrin-submit":"dist/cli/submit.js","eldrin-release":"dist/cli/release.js"},"dist":{"shasum":"85ebfd77c8393395cab305c507bebfdfebc8ccda","tarball":"https://registry.npmjs.org/@eldrin-project/eldrin-app-core/-/eldrin-app-core-0.0.1.tgz","fileCount":21,"integrity":"sha512-nmW827bivzbi2KMPHCNpd3grAC/AwGtentqiXZRUn8e//mtdDy0hUdVJh+WN+TBOOirgrtq4bwL2gtHM7Mzcaw==","signatures":[{"sig":"MEYCIQCj95ndFb/5tIu5gQlACxNCOfRJMxh4HhhQ8ympvpvquAIhAI9oVjuiyfDWKQ+74S+lbV2XWwTEl0Za4SMsNUKp5T8N","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":311552},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./vite":{"import":{"types":"./dist/vite.d.ts","default":"./dist/vite.js"},"require":{"types":"./dist/vite.d.cts","default":"./dist/vite.cjs"}},"./submit":{"import":{"types":"./dist/cli/submit.d.ts","default":"./dist/cli/submit.js"}},"./vite-env":{"types":"./dist/vite-env.d.ts"}},"gitHead":"ea0fc5c142d90ab74c7f00660b16614265fcdfee","scripts":{"dev":"tsup --watch","lint":"eslint src","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"tiborkiray","email":"tibor.kiray@gmail.com"},"repository":{"url":"git+https://github.com/eldrin-project/eldrin-app-core.git","type":"git"},"_npmVersion":"10.9.2","description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","directories":{},"_nodeVersion":"22.14.0","dependencies":{"dotenv":"^17.2.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^7.1.2","react":"^19.0.0","eslint":"^9.39.2","vitest":"^2.0.0","globals":"^16.5.0","react-dom":"^19.0.0","@eslint/js":"^9.39.2","typescript":"^5.8.0","@types/node":"^22.0.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","typescript-eslint":"^8.50.1","@cloudflare/workers-types":"^4.20251216.0"},"peerDependencies":{"vite":"^6.0.0 || ^7.0.0","react":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eldrin-app-core_0.0.1_1766788765822_0.3550547001762261","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@eldrin-project/eldrin-app-core","version":"0.0.2","keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"author":{"name":"Eldrin Team"},"license":"MIT","_id":"@eldrin-project/eldrin-app-core@0.0.2","maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"bin":{"eldrin-submit":"dist/cli/submit.js","eldrin-release":"dist/cli/release.js"},"dist":{"shasum":"6ff943389171e31b74a049d0b2a706548958c89b","tarball":"https://registry.npmjs.org/@eldrin-project/eldrin-app-core/-/eldrin-app-core-0.0.2.tgz","fileCount":21,"integrity":"sha512-Fm883yA0v+ph+ECd9KMedMi6my6FVMhhTeyjLefUTs3APJDS7/hVNOzmDa9d4zX0J8kuZvgdBmcDJV8WpL+DXA==","signatures":[{"sig":"MEQCIEhYPZQkXtRGfturFOCGQwmil+3cGYufgrTwHxmPq4W3AiBx9xILB60HRjZ/SXMZRa60y3ratGGYxOulb58w5KAd1w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":442219},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./vite":{"import":{"types":"./dist/vite.d.ts","default":"./dist/vite.js"},"require":{"types":"./dist/vite.d.cts","default":"./dist/vite.cjs"}},"./submit":{"import":{"types":"./dist/cli/submit.d.ts","default":"./dist/cli/submit.js"}},"./vite-env":{"types":"./dist/vite-env.d.ts"}},"gitHead":"8e7a3d27ddbd5f9d98e9dc4b47afd7de3adf7515","scripts":{"dev":"tsup --watch","lint":"eslint src","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"tiborkiray","email":"tibor.kiray@gmail.com"},"repository":{"url":"git+https://github.com/eldrin-project/eldrin-app-core.git","type":"git"},"_npmVersion":"10.9.2","description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","directories":{},"_nodeVersion":"22.14.0","dependencies":{"dotenv":"^17.2.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^7.1.2","react":"^19.0.0","eslint":"^9.39.2","vitest":"^2.0.0","globals":"^16.5.0","react-dom":"^19.0.0","@eslint/js":"^9.39.2","typescript":"^5.8.0","@types/node":"^22.0.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","typescript-eslint":"^8.50.1","@cloudflare/workers-types":"^4.20251216.0"},"peerDependencies":{"vite":"^6.0.0 || ^7.0.0","react":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eldrin-app-core_0.0.2_1767117103372_0.6565408470020586","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@eldrin-project/eldrin-app-core","version":"0.0.3","keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"author":{"name":"Eldrin Team"},"license":"MIT","_id":"@eldrin-project/eldrin-app-core@0.0.3","maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"bin":{"eldrin-submit":"dist/cli/submit.js","eldrin-release":"dist/cli/release.js"},"dist":{"shasum":"e120e9090fe6d7ffb38daa4477f8851a7a2f8d44","tarball":"https://registry.npmjs.org/@eldrin-project/eldrin-app-core/-/eldrin-app-core-0.0.3.tgz","fileCount":21,"integrity":"sha512-sly+NEWncJGqHKDNrqXpM/ASOgtj0lBT+2ZgXahvi+qlZ/QImQmoe/QQWUNZ6ddXVZfX3JV0lGdi/aGRpn7WXA==","signatures":[{"sig":"MEUCIQCqd3AJ0QCYSDaY+Mwa3FWMh0u3RHs2KQJt9sndrBTMHQIgV436rCs2acAuuIXDNcUY4/SH9yt9vZU7mB6C7DR9ePo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":507923},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./vite":{"import":{"types":"./dist/vite.d.ts","default":"./dist/vite.js"},"require":{"types":"./dist/vite.d.cts","default":"./dist/vite.cjs"}},"./submit":{"import":{"types":"./dist/cli/submit.d.ts","default":"./dist/cli/submit.js"}},"./vite-env":{"types":"./dist/vite-env.d.ts"}},"gitHead":"f5bad7b378c32d8b9550dc7f8fb8a4aeea23a225","scripts":{"dev":"tsup --watch","lint":"eslint src","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"tiborkiray","email":"tibor.kiray@gmail.com"},"repository":{"url":"git+https://github.com/eldrin-project/eldrin-app-core.git","type":"git"},"_npmVersion":"10.9.2","description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","directories":{},"_nodeVersion":"22.14.0","dependencies":{"dotenv":"^17.2.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^7.1.2","react":"^19.0.0","eslint":"^9.39.2","vitest":"^2.0.0","globals":"^16.5.0","react-dom":"^19.0.0","@eslint/js":"^9.39.2","typescript":"^5.8.0","@types/node":"^22.0.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","typescript-eslint":"^8.50.1","@cloudflare/workers-types":"^4.20251216.0"},"peerDependencies":{"vite":"^6.0.0 || ^7.0.0","react":"^18.0.0 || ^19.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eldrin-app-core_0.0.3_1767178754419_0.7257439160107615","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@eldrin-project/eldrin-app-core","version":"0.0.4","keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"author":{"name":"Eldrin Team"},"license":"MIT","_id":"@eldrin-project/eldrin-app-core@0.0.4","maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"bin":{"eldrin-submit":"dist/cli/submit.js","eldrin-release":"dist/cli/release.js"},"dist":{"shasum":"a41c0900df043a2d6e3f7c527af9d7d42f9ae104","tarball":"https://registry.npmjs.org/@eldrin-project/eldrin-app-core/-/eldrin-app-core-0.0.4.tgz","fileCount":21,"integrity":"sha512-2TDjlAao0p1WHrmTTNk8BNxieJwQq0dW/Z4axKKKSgQR+6PFwLi37OrE+wJWW4roEzX+PEkzRo2muiZdY7rwpw==","signatures":[{"sig":"MEQCIByu2F/FSUqWf0PYkPMhS7tWbdahT4ZhXwMjes2lVP/zAiAXMV3cjTvbwVDTi3lxJ5Yj0l0WaylnaJJi9PV53PGcpg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":466781},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./vite":{"import":{"types":"./dist/vite.d.ts","default":"./dist/vite.js"},"require":{"types":"./dist/vite.d.cts","default":"./dist/vite.cjs"}},"./submit":{"import":{"types":"./dist/cli/submit.d.ts","default":"./dist/cli/submit.js"}},"./vite-env":{"types":"./dist/vite-env.d.ts"}},"gitHead":"4d5749afe27511f62d5fc0f554256ecad6115a4f","scripts":{"dev":"tsup --watch","lint":"eslint src","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"tiborkiray","email":"tibor.kiray@gmail.com"},"repository":{"url":"git+https://github.com/eldrin-project/eldrin-app-core.git","type":"git"},"_npmVersion":"10.9.2","description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","directories":{},"_nodeVersion":"22.14.0","dependencies":{"dotenv":"^17.2.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vite":"^7.1.2","eslint":"^9.39.2","vitest":"^2.0.0","globals":"^16.5.0","@eslint/js":"^9.39.2","typescript":"^5.8.0","@types/node":"^22.0.0","typescript-eslint":"^8.50.1","@cloudflare/workers-types":"^4.20251216.0"},"peerDependencies":{"vite":"^6.0.0 || ^7.0.0"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/eldrin-app-core_0.0.4_1767316625290_0.6390427571590902","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@eldrin-project/eldrin-app-core","version":"0.0.5","description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","publishConfig":{"access":"public"},"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","bin":{"eldrin-submit":"dist/cli/submit.js","eldrin-release":"dist/cli/release.js"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./node":{"import":{"types":"./dist/node.d.ts","default":"./dist/node.js"},"require":{"types":"./dist/node.d.cts","default":"./dist/node.cjs"}},"./vite":{"import":{"types":"./dist/vite.d.ts","default":"./dist/vite.js"},"require":{"types":"./dist/vite.d.cts","default":"./dist/vite.cjs"}},"./vite-env":{"types":"./dist/vite-env.d.ts"},"./submit":{"import":{"types":"./dist/cli/submit.d.ts","default":"./dist/cli/submit.js"}}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest","test:run":"vitest run","typecheck":"tsc --noEmit","lint":"eslint src","prepublishOnly":"npm run build"},"keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"author":{"name":"Eldrin Team"},"license":"MIT","peerDependencies":{"vite":"^6.0.0 || ^7.0.0"},"peerDependenciesMeta":{"vite":{"optional":true}},"devDependencies":{"@cloudflare/workers-types":"^4.20251216.0","@eslint/js":"^9.39.2","@types/node":"^22.0.0","eslint":"^9.39.2","globals":"^16.5.0","tsup":"^8.0.0","typescript":"^5.8.0","typescript-eslint":"^8.50.1","vite":"^7.1.2","vitest":"^2.0.0"},"repository":{"type":"git","url":"git+https://github.com/eldrin-project/eldrin-app-core.git"},"bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","engines":{"node":">=18.0.0"},"dependencies":{"dotenv":"^17.2.3"},"_id":"@eldrin-project/eldrin-app-core@0.0.5","gitHead":"f21ee7ba93838273fd01f156fc35c7361d2446c3","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-2NbxLPsK+7qkMgV3emy3BVfABe7dso9L7zGGcMMSEGCbRcsKjD3c7IxOqNTYVnTdDS2YCmSni17nHHeqTghH5w==","shasum":"3440e18517d70567dbcacc32b5ad2405979e3b96","tarball":"https://registry.npmjs.org/@eldrin-project/eldrin-app-core/-/eldrin-app-core-0.0.5.tgz","fileCount":27,"unpackedSize":493817,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFzFYbD7PDBXLdkOY/ySNt4w+WIrvfYuMztTbAokLjEsAiALZ51/8kN6aQ0YBGeg7GNelp2FNUjuoW3zRQ+lFnfn4g=="}]},"_npmUser":{"name":"tiborkiray","email":"tibor.kiray@gmail.com"},"directories":{},"maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eldrin-app-core_0.0.5_1767418445475_0.0024823735378340928"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-26T22:39:25.726Z","modified":"2026-01-03T05:34:05.848Z","0.0.1":"2025-12-26T22:39:26.022Z","0.0.2":"2025-12-30T17:51:43.516Z","0.0.3":"2025-12-31T10:59:14.575Z","0.0.4":"2026-01-02T01:17:05.454Z","0.0.5":"2026-01-03T05:34:05.632Z"},"bugs":{"url":"https://github.com/eldrin-project/eldrin-app-core/issues"},"author":{"name":"Eldrin Team"},"license":"MIT","homepage":"https://github.com/eldrin-project/eldrin-app-core#readme","keywords":["eldrin","cloudflare","d1","migrations","single-spa"],"repository":{"type":"git","url":"git+https://github.com/eldrin-project/eldrin-app-core.git"},"description":"Standard library for Eldrin apps providing database migrations, storage isolation, event communication, and common utilities","maintainers":[{"name":"tiborkiray","email":"tibor.kiray@gmail.com"}],"readme":"# @eldrin-project/eldrin-app-core\n\n[![npm version](https://img.shields.io/npm/v/@eldrin-project/eldrin-app-core.svg)](https://www.npmjs.com/package/@eldrin-project/eldrin-app-core)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\nFramework-agnostic core library for building Eldrin marketplace apps on Cloudflare Workers with D1 databases.\n\n## Overview\n\nThis package is the **foundation layer** of the Eldrin ecosystem:\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                     Your App                                │\n├─────────────────────────────────────────────────────────────┤\n│              Framework Adapter (choose one)                 │\n│  • @eldrin-project/eldrin-app-angular                       │\n│  • @eldrin-project/eldrin-app-react                         │\n│  • @eldrin-project/eldrin-app-vue                           │\n├─────────────────────────────────────────────────────────────┤\n│              @eldrin-project/eldrin-app-core                │\n│  • Database migrations with checksum verification           │\n│  • JWT authentication & permission checking                 │\n│  • Permission middleware for API routes                     │\n│  • Event system for inter-app communication                 │\n│  • Vite plugin for build-time SQL loading                   │\n│  • CLI tools for marketplace release/submission             │\n├─────────────────────────────────────────────────────────────┤\n│              Cloudflare Workers + D1 Database               │\n└─────────────────────────────────────────────────────────────┘\n```\n\n## Installation\n\n```bash\nnpm install @eldrin-project/eldrin-app-core\n```\n\n## Features\n\n### 1. Database Migrations\n\nRun SQL migrations against Cloudflare D1 with automatic tracking, checksum verification, and rollback support.\n\n```typescript\nimport { runMigrations, getMigrationStatus } from '@eldrin-project/eldrin-app-core';\n\n// Run pending migrations\nconst result = await runMigrations(db, {\n  migrations: [\n    { name: '20250101120000-create-users.sql', content: 'CREATE TABLE users...' },\n    { name: '20250102100000-add-email.sql', content: 'ALTER TABLE users...' },\n  ],\n  onLog: (msg, level) => console.log(`[${level}] ${msg}`),\n});\n\nif (result.success) {\n  console.log(`Executed ${result.executed} migrations`);\n} else {\n  console.error(`Failed at ${result.error?.migration}: ${result.error?.message}`);\n}\n\n// Check migration status\nconst status = await getMigrationStatus(db, migrations);\nconsole.log('Pending:', status.pending);\nconsole.log('Executed:', status.executed.length);\n```\n\n**Migration file naming:** `YYYYMMDDHHMMSS-description.sql`\n\nMigrations are tracked in `_eldrin_migrations` table with SHA-256 checksums to detect tampering.\n\n### 2. Authentication & Authorization\n\nVerify JWT tokens and check permissions in your Cloudflare Worker:\n\n```typescript\nimport {\n  verifyJWT,\n  requireJWTAuth,\n  requireJWTPermission,\n  hasPermission,\n  isPlatformAdmin,\n} from '@eldrin-project/eldrin-app-core';\n\nexport default {\n  async fetch(request: Request, env: Env) {\n    // Option 1: Manual verification\n    const result = await verifyJWT(request, {\n      secret: env.JWT_SECRET,\n      appId: 'my-app',\n    });\n\n    if (!result.success) {\n      return Response.json({ error: result.error }, { status: 401 });\n    }\n\n    const { auth } = result;\n    console.log('User:', auth.email);\n    console.log('Permissions:', auth.permissions);\n\n    // Option 2: Require auth (returns Response on failure)\n    const auth = await requireJWTAuth(request, {\n      secret: env.JWT_SECRET,\n      appId: 'my-app',\n    });\n\n    if (auth instanceof Response) return auth; // 401\n\n    // Option 3: Require specific permission\n    const auth = await requireJWTPermission(\n      request,\n      { secret: env.JWT_SECRET, appId: 'my-app' },\n      'invoices',\n      'write'\n    );\n\n    if (auth instanceof Response) return auth; // 401 or 403\n\n    // Check permissions manually\n    if (hasPermission(auth, 'invoices', 'delete')) {\n      // User can delete invoices\n    }\n\n    if (isPlatformAdmin(auth)) {\n      // User is platform admin (has all permissions)\n    }\n  },\n};\n```\n\n### 3. Permission Middleware\n\nManifest-driven middleware that automatically enforces route permissions:\n\n```typescript\nimport { createPermissionMiddleware } from '@eldrin-project/eldrin-app-core';\nimport manifest from './eldrin-app.manifest.json';\n\nconst middleware = createPermissionMiddleware<Env>({\n  manifest,\n  getSecret: (env) => env.JWT_SECRET,\n  cors: {\n    allowOrigin: '*',\n    allowMethods: 'GET, POST, PUT, DELETE, OPTIONS',\n    allowHeaders: 'Content-Type, Authorization',\n  },\n});\n\nexport default {\n  async fetch(request: Request, env: Env): Promise<Response> {\n    const result = await middleware.handle(request, env);\n\n    // Rejected request (401, 403, or CORS preflight)\n    if (result.response) {\n      return result.response;\n    }\n\n    // Authorized - access auth context and route params\n    const { auth, url, params } = result;\n    console.log('User:', auth.email);\n    console.log('Route params:', params); // e.g., { id: '123' }\n\n    // Handle the request...\n  },\n};\n```\n\n**Manifest API configuration:**\n\n```json\n{\n  \"id\": \"my-app\",\n  \"developer_id\": \"acme\",\n  \"api\": {\n    \"defaultPolicy\": \"deny\",\n    \"publicRoutes\": [\"/api/health\"],\n    \"routes\": [\n      { \"method\": \"GET\", \"path\": \"/api/items\", \"permission\": \"items:read\" },\n      { \"method\": \"POST\", \"path\": \"/api/items\", \"permission\": \"items:write\" },\n      { \"method\": \"GET\", \"path\": \"/api/items/:id\", \"permission\": \"items:read\" },\n      { \"method\": \"DELETE\", \"path\": \"/api/items/:id\", \"permission\": \"items:delete\" }\n    ]\n  }\n}\n```\n\n### 4. Event System\n\nPublish/subscribe events for inter-app communication:\n\n```typescript\nimport { createEventClient } from '@eldrin-project/eldrin-app-core';\n\nexport default {\n  async fetch(request: Request, env: Env) {\n    const events = createEventClient(env, 'invoicing');\n\n    // Emit an event\n    await events.emit('invoice.created', {\n      invoiceId: 'inv_123',\n      customerId: 'cust_456',\n      total: 1500,\n    });\n\n    // Poll for events (in a scheduled worker)\n    const pending = await events.poll({ limit: 10 });\n\n    for (const delivery of pending.events) {\n      try {\n        await processEvent(delivery.event);\n        await events.ack(delivery.id);\n      } catch (error) {\n        await events.nack(delivery.id, error.message);\n      }\n    }\n  },\n};\n```\n\n**Declare events in manifest:**\n\n```json\n{\n  \"events\": {\n    \"emits\": [\"invoice.created\", \"invoice.paid\"],\n    \"subscribes\": [\"payment.received\", \"customer.updated\"]\n  }\n}\n```\n\n### 5. Vite Plugin\n\nLoad SQL migrations at build time (Workers have no filesystem access at runtime):\n\n```typescript\n// vite.config.ts\nimport { defineConfig } from 'vite';\nimport { eldrinPlugin } from '@eldrin-project/eldrin-app-core/vite';\n\nexport default defineConfig({\n  plugins: [\n    eldrinPlugin({\n      migrationsDir: './migrations',\n      seedsDir: './seeds',\n    }),\n  ],\n});\n```\n\n```typescript\n// Add type declarations\n// src/vite-env.d.ts\n/// <reference types=\"@eldrin-project/eldrin-app-core/vite-env\" />\n```\n\n```typescript\n// Import migrations in your code\nimport migrations from 'virtual:eldrin/migrations';\nimport seeds from 'virtual:eldrin/seeds';\n```\n\n## Package Exports\n\n| Export | Environment | Description |\n|--------|-------------|-------------|\n| `@eldrin-project/eldrin-app-core` | Browser/Worker | Main exports (migrations, auth, events, middleware) |\n| `@eldrin-project/eldrin-app-core/node` | Node.js only | Marketplace utilities (generateMigrationManifest) |\n| `@eldrin-project/eldrin-app-core/vite` | Node.js only | Vite plugin for loading SQL files |\n| `@eldrin-project/eldrin-app-core/vite-env` | Types only | TypeScript declarations for virtual modules |\n\n## CLI Tools\n\n### eldrin-release\n\nPrepares your app for marketplace submission:\n\n```bash\nnpx eldrin-release [options]\n\nOptions:\n  -t, --type <type>      Bump version: patch, minor, or major\n  -v, --version <ver>    Set explicit version\n  --skip-build           Skip the build step\n  -m, --manifest <path>  Path to manifest file\n  -o, --output <path>    Output directory\n```\n\nCreates a release package at `dist/release/{developerId}/{appId}/v{version}/`:\n\n```\ndist/release/acme/invoicing/\n├── migrations/                    # Shared across versions\n│   ├── index.json                 # Manifest with checksums\n│   └── *.sql                      # Migration files\n└── v1.0.0/\n    ├── eldrin-app.manifest.json   # App metadata\n    ├── bundle.js                  # Worker bundle\n    └── deploy-bundle.json         # Worker + client assets\n```\n\n### eldrin-submit\n\nSubmits a release to the Eldrin marketplace:\n\n```bash\nnpx eldrin-submit -d ./dist/release/acme/invoicing/v1.0.0\n\nOptions:\n  -d, --release-dir <dir>  Release directory to submit\n  -k, --api-key <key>      Developer API key\n  --developer-id <id>      Developer ID\n  --dry-run                Preview without submitting\n```\n\n**Environment variables:**\n- `ELDRIN_API_KEY` - Your developer API key\n- `ELDRIN_DEVELOPER_ID` - Your developer ID\n- `ELDRIN_MARKETPLACE_URL` - Marketplace URL (default: https://eldrin.io)\n\n## Configuration\n\nCreate `.eldrinrc.json` in your project root:\n\n```json\n{\n  \"developerId\": \"acme\",\n  \"marketplaceUrl\": \"https://eldrin.io\",\n  \"manifestPath\": \"./public/eldrin-app.manifest.json\",\n  \"migrationsDir\": \"./migrations\",\n  \"buildCommand\": \"npm run build\",\n  \"clientDir\": \"dist/client\",\n  \"workerEntry\": \"dist/worker/index.js\"\n}\n```\n\n## App Manifest\n\nCreate `eldrin-app.manifest.json`:\n\n```json\n{\n  \"id\": \"invoicing\",\n  \"name\": \"Invoicing App\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Create and manage invoices\",\n  \"developer_id\": \"acme\",\n  \"permissions\": [\n    { \"resource\": \"invoices\", \"actions\": [\"read\", \"write\", \"delete\"] },\n    { \"resource\": \"customers\", \"actions\": [\"read\"] }\n  ],\n  \"groups\": [\n    {\n      \"id\": \"admin\",\n      \"name\": \"Invoice Admin\",\n      \"permissions\": [\"invoices:*\", \"customers:read\"]\n    },\n    {\n      \"id\": \"viewer\",\n      \"name\": \"Viewer\",\n      \"permissions\": [\"invoices:read\", \"customers:read\"]\n    }\n  ],\n  \"events\": {\n    \"emits\": [\"invoice.created\", \"invoice.paid\"],\n    \"subscribes\": [\"payment.received\"]\n  },\n  \"api\": {\n    \"defaultPolicy\": \"deny\",\n    \"publicRoutes\": [\"/api/health\"],\n    \"routes\": [\n      { \"method\": \"GET\", \"path\": \"/api/invoices\", \"permission\": \"invoices:read\" },\n      { \"method\": \"POST\", \"path\": \"/api/invoices\", \"permission\": \"invoices:write\" }\n    ]\n  }\n}\n```\n\n## Framework Adapters\n\nThis core package is framework-agnostic. Use these adapters for framework-specific integrations:\n\n| Framework | Package | Features |\n|-----------|---------|----------|\n| Angular | `@eldrin-project/eldrin-app-angular` | InjectionTokens, providers, single-spa lifecycle |\n| React | `@eldrin-project/eldrin-app-react` | Hooks (useDatabase), Context, single-spa lifecycle |\n| Vue | `@eldrin-project/eldrin-app-vue` | Composables, provide/inject, single-spa lifecycle |\n\n## API Reference\n\n### Migrations\n\n| Function | Description |\n|----------|-------------|\n| `runMigrations(db, options)` | Execute pending migrations |\n| `getMigrationStatus(db, migrations)` | Get pending/executed/orphaned migrations |\n| `rollbackMigrations(db, options)` | Rollback migrations (with .rollback.sql files) |\n| `calculateChecksum(content)` | Calculate SHA-256 checksum of migration content |\n| `verifyChecksum(content, checksum)` | Verify content matches stored checksum |\n\n### Auth\n\n| Function | Description |\n|----------|-------------|\n| `verifyJWT(request, options)` | Verify JWT and extract auth context |\n| `getAuthContextFromJWT(request, options)` | Get auth context (JWT or proxy headers) |\n| `requireJWTAuth(request, options)` | Require valid JWT (returns Response on failure) |\n| `requireJWTPermission(request, options, resource, action)` | Require specific permission |\n| `hasPermission(auth, resource, action)` | Check if auth has permission |\n| `isPlatformAdmin(auth)` | Check if auth is platform admin |\n\n### Middleware\n\n| Function | Description |\n|----------|-------------|\n| `createPermissionMiddleware(config)` | Create manifest-driven permission middleware |\n| `compileRoutes(routes, prefix)` | Pre-compile route patterns for matching |\n| `matchRoute(method, path, routes)` | Match request against compiled routes |\n\n### Events\n\n| Class/Function | Description |\n|----------------|-------------|\n| `EldrinEventClient` | Client for pub/sub event communication |\n| `createEventClient(env, appId)` | Create event client from worker env |\n| `client.emit(type, payload)` | Emit an event |\n| `client.poll(options)` | Poll for pending events |\n| `client.ack(deliveryId)` | Acknowledge successful processing |\n| `client.nack(deliveryId, error)` | Negative acknowledge (retry later) |\n\n## Requirements\n\n- Node.js 18.0.0 or later\n- Vite 6.x or 7.x (optional, for Vite plugin)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}