{"_id":"@agile-nuxt/backend","_rev":"2-01389425b77517b57a63bb25aad86612","name":"@agile-nuxt/backend","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@agile-nuxt/backend","version":"0.1.0","keywords":["nuxt","nuxt-module","nitro","backend","crud","auth","typescript","cpanel","fullstack"],"author":{"name":"Agile Nuxt contributors"},"license":"MIT","_id":"@agile-nuxt/backend@0.1.0","maintainers":[{"name":"tfive","email":"Pooyan.tfive@ymail.com"}],"homepage":"https://github.com/agile-nuxt/agile-nuxt-edge-backend#readme","bugs":{"url":"https://github.com/agile-nuxt/agile-nuxt-edge-backend/issues"},"dist":{"shasum":"b6f9159fc4392f874f7ef7d37ac17b49da064267","tarball":"https://registry.npmjs.org/@agile-nuxt/backend/-/backend-0.1.0.tgz","fileCount":185,"integrity":"sha512-Lgba+UNE98RPxuM+8twcKgt0rdyuyNI8rm+i2KJENEgUC2GIDVm/Pzs+LFGPIuh5DtdwcNrk3aR7IB2P+OQ5dA==","signatures":[{"sig":"MEUCIQDjRGq3gc2t6RYntON22oxNDWMcCDnIlQbb1s8+/Zx2rQIgI46T/WXIr0Xs0u+xkHLPC2LxdhCouqXa+SCj1SFWYNM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1256321},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./module":{"types":"./dist/module.d.ts","import":"./dist/module.mjs","require":"./dist/module.cjs"},"./server":{"types":"./dist/runtime/server/utils.d.ts","import":"./dist/runtime/server/utils.mjs","require":"./dist/runtime/server/utils.cjs"}},"gitHead":"26a2e60f16c1fabb850e6a611d15c5febbf95849","scripts":{"lint":"eslint src tests tsup.config.ts","test":"vitest run","build":"tsup","clean":"rm -rf dist coverage","typecheck":"tsc --noEmit","pack:check":"tsx ../../scripts/check-package.ts --package backend --pack"},"_npmUser":{"name":"tfive","email":"Pooyan.tfive@ymail.com"},"repository":{"url":"git+https://github.com/agile-nuxt/agile-nuxt-edge-backend.git","type":"git","directory":"packages/backend"},"_npmVersion":"10.9.3","description":"A secure Nuxt and Nitro backend service module with CRUD, filters, optional auth, permissions, and field security.","directories":{},"sideEffects":false,"_nodeVersion":"22.20.0","dependencies":{"h3":"^1.15.3","ofetch":"^1.4.1","@agile-nuxt/edge-db":"workspace:*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.13","nuxt":"^4.0.0","tsup":"^8.4.0","vitest":"^3.1.2","@nuxt/kit":"^4.0.0","typescript":"^5.8.3","@types/node":"^22.15.3","@nuxt/schema":"^4.0.0"},"peerDependencies":{"nuxt":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/backend_0.1.0_1782305119156_0.3005232834456202","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@agile-nuxt/backend","version":"0.2.0","description":"A secure Nuxt and Nitro backend service module with CRUD, filters, optional auth, permissions, and field security.","type":"module","license":"MIT","author":{"name":"Agile Nuxt contributors"},"homepage":"https://github.com/agile-nuxt/agile-nuxt-edge-backend#readme","repository":{"type":"git","url":"git+https://github.com/agile-nuxt/agile-nuxt-edge-backend.git","directory":"packages/backend"},"bugs":{"url":"https://github.com/agile-nuxt/agile-nuxt-edge-backend/issues"},"keywords":["nuxt","nuxt-module","nitro","backend","crud","auth","typescript","cpanel","fullstack"],"engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"},"./module":{"types":"./dist/module.d.ts","import":"./dist/module.mjs","require":"./dist/module.cjs"},"./config":{"types":"./dist/config.d.ts","import":"./dist/config.mjs","require":"./dist/config.cjs"},"./server":{"types":"./dist/runtime/server/utils.d.ts","import":"./dist/runtime/server/utils.mjs","require":"./dist/runtime/server/utils.cjs"}},"main":"./dist/index.cjs","module":"./dist/index.mjs","types":"./dist/index.d.ts","scripts":{"build":"tsup","test":"vitest run","typecheck":"tsc --noEmit","lint":"eslint src tests tsup.config.ts","pack:check":"tsx ../../scripts/check-package.ts --package backend --pack","clean":"rm -rf dist coverage"},"dependencies":{"@agile-nuxt/edge-db":"workspace:*","h3":"^1.15.3","ofetch":"^1.4.1"},"peerDependencies":{"nuxt":"^4.0.0"},"publishConfig":{"access":"public"},"sideEffects":["./src/nuxt.ts","./dist/index.mjs","./dist/index.cjs"],"devDependencies":{"@nuxt/kit":"^4.0.0","@nuxt/schema":"^4.0.0","@types/node":"^22.15.3","nuxt":"^4.0.0","tsup":"^8.4.0","typescript":"^5.8.3","vitest":"^3.1.2","vue":"^3.5.13"},"_id":"@agile-nuxt/backend@0.2.0","gitHead":"a3be71c3a5572114021602e7ba9be8e95ac1ef58","_nodeVersion":"22.1.0","_npmVersion":"10.7.0","dist":{"integrity":"sha512-C2vlGno+tzJS/SaQB8eSsUtG3HiDiejPowNnld18VZXx9upNBMjrEUHPxDKWHEOceiIF46Gy2DEbW5fBntadSg==","shasum":"a505f205fb8d32a0244b2aeac8f01d4ee086a404","tarball":"https://registry.npmjs.org/@agile-nuxt/backend/-/backend-0.2.0.tgz","fileCount":227,"unpackedSize":2391616,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEazVpGp/CGeJUIDR55p65foSvPRXa8ZNQSzGX+ilnJUAiA6A0sbB9dtYJ4vH30NMiU6K5ApleZgz4FefDeUaX18Kw=="}]},"_npmUser":{"name":"tfive","email":"Pooyan.tfive@ymail.com"},"directories":{},"maintainers":[{"name":"tfive","email":"Pooyan.tfive@ymail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/backend_0.2.0_1782394658215_0.5016829023324758"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-24T12:45:19.025Z","modified":"2026-06-25T13:37:38.490Z","0.1.0":"2026-06-24T12:45:19.308Z","0.2.0":"2026-06-25T13:37:38.364Z"},"bugs":{"url":"https://github.com/agile-nuxt/agile-nuxt-edge-backend/issues"},"author":{"name":"Agile Nuxt contributors"},"license":"MIT","homepage":"https://github.com/agile-nuxt/agile-nuxt-edge-backend#readme","keywords":["nuxt","nuxt-module","nitro","backend","crud","auth","typescript","cpanel","fullstack"],"repository":{"type":"git","url":"git+https://github.com/agile-nuxt/agile-nuxt-edge-backend.git","directory":"packages/backend"},"description":"A secure Nuxt and Nitro backend service module with CRUD, filters, optional auth, permissions, and field security.","maintainers":[{"name":"tfive","email":"Pooyan.tfive@ymail.com"}],"readme":"# `@agile-nuxt/backend`\n\nA secure Nuxt 4 and Nitro backend service module powered by\n`@agile-nuxt/edge-db`.\n\nCurrent release: `0.2.0`.\n\n## Installation\n\n```bash\npnpm add @agile-nuxt/edge-db @agile-nuxt/backend\n```\n\n## Nuxt Setup\n\n```ts\n// server/backend.config.ts\nimport { defineBackendConfig } from '@agile-nuxt/backend/config'\n\nexport default defineBackendConfig({\n  auth: false,\n  db: {\n    path: process.env.EDGE_DB_PATH || './storage/edge-db'\n  },\n  entities: {}\n})\n```\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@agile-nuxt/backend'],\n  nitro: { preset: 'node-server' },\n  backend: {\n    configFile: './server/backend.config.ts'\n  }\n})\n```\n\nWritable deployments require a persistent filesystem and one writable Node\nprocess per database path.\n\nInline serializable configuration remains supported. Hooks and adapters belong in\nthe server config file; functions in `nuxt.config.ts` are rejected rather than\nserialized with `Function.toString()`.\n\n## Auth Disabled Mode\n\n```ts\nbackend: {\n  auth: false,\n  db: { path: './storage/edge-db' },\n  entities: {\n    products: {\n      fields: {\n        id: 'id',\n        title: 'text',\n        price: 'integer',\n        status: 'text.default:active',\n        createdAt: 'datetime',\n        updatedAt: 'datetime'\n      },\n      indexes: ['status', 'createdAt'],\n      timestamps: true,\n      api: true,\n      permissions: {\n        list: 'public',\n        read: 'public',\n        create: 'disabled',\n        update: 'disabled',\n        delete: 'disabled'\n      }\n    }\n  }\n}\n```\n\nAuth endpoints return `404` when auth is disabled. Permissions are still enforced,\nand unspecified actions default to disabled.\n\n## Auth Enabled Mode\n\n```ts\nbackend: {\n  auth: {\n    enabled: true,\n    strategy: 'jwt',\n    userEntity: 'users',\n    accessTokenSecret: process.env.ACCESS_TOKEN_SECRET!,\n    refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,\n    accessTokenMaxAge: '15m',\n    refreshTokenMaxAge: '30d',\n    cookieMode: true\n  },\n  db: { path: './storage/edge-db' },\n  entities: {\n    users: {\n      fields: {\n        id: 'id',\n        email: 'text.unique',\n        passwordHash: 'text.private',\n        role: 'text.default:user',\n        isActive: 'boolean.default:true',\n        createdAt: 'datetime',\n        updatedAt: 'datetime'\n      },\n      indexes: ['email', 'role'],\n      unique: ['email'],\n      timestamps: true,\n      api: true,\n      publicFields: ['id', 'email', 'role', 'isActive'],\n      permissions: {\n        list: ['admin'],\n        read: ['admin', 'self'],\n        create: ['admin'],\n        update: ['admin', 'self'],\n        delete: ['admin']\n      }\n    }\n  }\n}\n```\n\nSecrets shorter than 32 bytes are rejected. Passwords use Node `scrypt`. Refresh\ntokens are opaque, hashed at rest, revoked on use, and rotated. Cookie mode uses\nHTTP-only, `SameSite=Strict` cookies plus CSRF validation.\n\nRefresh tokens form revocable families. Reuse of a rotated token revokes the\nentire family. Cookie names, domain, and path are configurable.\n\n## Entity Configuration\n\n- `fields`: schema whitelist and field metadata.\n- `indexes` and `unique`: query and uniqueness constraints.\n- `timestamps` and `softDelete`: lifecycle behavior.\n- `api: true`: required before any generated route exposes the entity.\n- `publicFields`: optional output allowlist.\n- `writableFields`: optional public write allowlist.\n- `permissions`: per-action authorization rules.\n- `hooks`: before/after CRUD extension points.\n\nUnknown and private fields are blocked from public writes. Private fields are\nremoved from API output.\n\n## Generated Routes\n\nCRUD:\n\n- `GET /api/backend/:entity`\n- `POST /api/backend/:entity`\n- `POST /api/backend/:entity/query`\n- `GET /api/backend/:entity/:id`\n- `PATCH /api/backend/:entity/:id`\n- `DELETE /api/backend/:entity/:id`\n- `POST /api/backend/:entity/:id/restore`\n\nWhen auth is enabled:\n\n- `POST /api/auth/register`\n- `POST /api/auth/login`\n- `POST /api/auth/refresh`\n- `POST /api/auth/logout`\n- `POST /api/auth/logout-all`\n- `GET /api/auth/me`\n\nThe diagnostics endpoint is registered only when explicitly enabled and requires\nthe admin role when auth is active.\n\n## Permissions\n\nRules support:\n\n- `public`\n- `disabled`\n- role arrays such as `['admin', 'staff']`\n- `self`\n- async policy functions\n\n```ts\npermissions: {\n  read: ({ user, record }) =>\n    user?.role === 'admin' || record.userId === user?.id,\n  update: ['admin', 'self'],\n  delete: ['admin']\n}\n```\n\nRecord-level read, update, delete, and restore policies run after lookup.\n\n## Field Security\n\n- Only configured entities exist through generated CRUD.\n- Only schema fields may be filtered, sorted, selected, or written.\n- Private fields are never returned by normal API reads.\n- Private and non-writable fields are rejected on public writes.\n- Body size, query size, `in` filters, and request rates are bounded.\n- Bodies are bounded while streaming; malformed JSON and encoded query filters\n  return stable `400` responses.\n\n## Hooks\n\n```ts\nhooks: {\n  beforeCreate: async ({ user, data }) => ({\n    ...data,\n    createdBy: user?.id\n  }),\n  afterCreate: async ({ record }) => {\n    // Trigger an application-specific side effect.\n  },\n  beforeUpdate: async ({ patch }) => patch,\n  afterDelete: async ({ record }) => {\n    // Audit the deleted record.\n  }\n}\n```\n\n## Frontend Composables\n\n```ts\nconst products = useBackendEntity('products')\n\nconst page = await products.list({\n  where: { status: 'active' },\n  orderBy: { createdAt: 'desc' },\n  limit: 20\n})\n\nawait products.create({ title: 'Plan', price: 120 })\nawait products.update(id, { price: 150 })\nawait products.remove(id)\n```\n\n```ts\nconst auth = useBackendAuth()\nawait auth.login({ email, password })\nawait auth.me()\nawait auth.logout()\n```\n\nFor end-to-end inference:\n\n```ts\nimport type backendConfig from '~/server/backend.config'\n\nconst backend = createBackendClient<typeof backendConfig>()\nconst products = backend.entity('products')\n```\n\nEntity names, filters, create/update inputs, and public records are inferred.\nPrivate fields are excluded from public client input and output types.\n\n## WebSockets\n\n```ts\nwebsocket: {\n  enabled: true,\n  allowedEntities: ['products'],\n  allowedOrigins: ['https://app.example.com'],\n  maxSubscriptions: 20,\n  adapter: redisRealtimeAdapter\n}\n```\n\nConnect to `/api/backend/ws` and send\n`{\"type\":\"subscribe\",\"entity\":\"products\"}`. Authorized clients receive\nmetadata-only `entity.changed` messages and refetch through normal HTTP routes.\nCookie or bearer authentication, origin validation, entity permissions, message\nlimits, and subscription limits apply. `useBackendRealtime()` provides the browser\nclient. A realtime adapter can distribute events across backend servers.\n\n## Permission-Safe Includes\n\nRelation names must be explicitly listed on the source entity:\n\n```ts\nposts: {\n  // fields and relations...\n  includes: ['author']\n}\n```\n\nEvery included target record is checked against its own `read` permission and\n`publicFields`. Arbitrary and recursive joins remain unsupported.\n\n## Server Utilities\n\nFor domain workflows that do not fit generic CRUD:\n\n```ts\nimport {\n  defineBackendHandler,\n  requireAuth,\n  useBackendDb\n} from '@agile-nuxt/backend/server'\n\nexport default defineBackendHandler(async (event) => {\n  const user = await requireAuth(event)\n  const db = await useBackendDb()\n\n  return db.transaction(async (tx) => {\n    // Implement a domain-specific operation.\n  })\n})\n```\n\nAlso available: `getCurrentUser`, `requirePermission`, and\n`publishBackendEvent`.\n\n## Deployment\n\n- Use Nitro's `node-server` preset.\n- Use a writable persistent path outside `.output`.\n- Run one writable process by default, or configure a strong external\n  `DatabaseCoordinator` for one active writer across servers on shared storage.\n- Configure a realtime adapter when WebSocket clients connect to multiple servers.\n- Use strong, separate auth secrets and HTTPS.\n- Run `edge-db doctor` under the production Node user.\n- Use `edge-db backup`; never copy live storage during writes.\n\n## API Reference\n\nMain exports:\n\n- Nuxt module default export\n- `BackendService`\n- `createBackendRuntime`\n- `hashPassword` and `verifyPassword`\n- `signAccessToken` and `verifyAccessToken`\n- `RateLimiter`\n- `InMemoryRateLimitAdapter`\n- `defineBackendConfig`\n- `createBackendClient`\n- backend entity, auth, user, permission, hook, and module option types\n\nServer export:\n\n- `useBackendDb`\n- `getCurrentUser`\n- `requireAuth`\n- `requirePermission`\n- `defineBackendHandler`\n- `publishBackendEvent`\n\n## Limitations\n\nVersion 0.2 supports multi-server adaptation through external writer-lease and\nrealtime adapters. It remains a single-active-writer filesystem database, not a\nsimultaneous multi-writer or distributed consensus database, analytical engine,\narbitrary SQL interface, or PostgreSQL-style relational query layer.\n\nSee the [root documentation](../../README.md) and the private\n[fullstack quickstart](../../templates/agile-nuxt-fullstack).\n","readmeFilename":"README.md"}