{"_id":"@arex95/phalanx","_rev":"2-49b332b50537a354e0684e1d470a129f","name":"@arex95/phalanx","dist-tags":{"latest":"6.1.0"},"versions":{"6.0.0":{"name":"@arex95/phalanx","version":"6.0.0","keywords":["vue","vue3","admin","admin-panel","typescript","rest-api","tanstack-query","authentication","realtime","sse","encryption","csrf","axios","jwt"],"author":{"name":"Arturo Rafael Serrano Girón"},"license":"MIT","_id":"@arex95/phalanx@6.0.0","maintainers":[{"name":"arex95","email":"arturorafaelonce@gmail.com"}],"homepage":"https://github.com/Arex95/phalanx#readme","bugs":{"url":"https://github.com/Arex95/phalanx/issues"},"dist":{"shasum":"905d4f1be4a45ee9033d30023e8d74ffd29870ae","tarball":"https://registry.npmjs.org/@arex95/phalanx/-/phalanx-6.0.0.tgz","fileCount":77,"integrity":"sha512-9CPQK2k785/A2kakMQigsSwxMJWsK8nyPT4cblXYj5sswnerdLVjO8j/sJt9hGZGHFVi35FspNjiaRwOfWRw3A==","signatures":[{"sig":"MEUCIQDOQQu01Vwp1sABry0BMoD5b9vkBf8TtNLLXOAlDmz6uQIgDOVd6/qj0BW0i+4DmLrn7eR1vQUdl8DyC1mp/AXi6wQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183382},"main":"dist/index.mjs","type":"module","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=15"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"},"./package.json":"./package.json"},"gitHead":"c051c26a12dbef3e7fa1d4170800c2f3418d2848","scripts":{"dev":"rollup -c -w","lint":"eslint .","test":"vitest run","build":"npm run clean && rollup -c && node scripts/fix-dts-aliases.mjs","clean":"node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"","release":"git push --follow-tags && npm publish --access public","typecheck":"vue-tsc --noEmit","release:major":"npm version major -m \"chore(release): %s\"","release:minor":"npm version minor -m \"chore(release): %s\"","release:patch":"npm version patch -m \"chore(release): %s\"","prepublishOnly":"npm run typecheck && npm run typecheck:test && npm run lint && npm run test && npm run build","typecheck:test":"tsc --noEmit -p tsconfig.test.json"},"_npmUser":{"name":"arex95","email":"arturorafaelonce@gmail.com"},"repository":{"url":"git+https://github.com/Arex95/phalanx.git","type":"git"},"_npmVersion":"11.13.0","description":"Headless framework for admin panels on Vue: typed REST services with derived TanStack queries and mutations, declarative actions, session handling with an HttpOnly refresh cookie, resilient realtime connections, encrypted browser storage and typed errors.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","_hasShrinkwrap":false,"devDependencies":{"axios":"^1.18.1","tslib":"^2.8.1","eslint":"^9.23.0","rollup":"^4.35.0","vitest":"^4.1.11","globals":"^16.0.0","ts-node":"^10.9.2","vue-tsc":"^3.3.11","happy-dom":"^20.11.1","@eslint/js":"^9.23.0","typescript":"^5.8.2","@types/node":"^22.13.10","fake-indexeddb":"^6.2.5","@vue/test-utils":"^2.4.11","eslint-plugin-vue":"^10.0.0","typescript-eslint":"^8.28.0","@rollup/plugin-json":"^6.1.0","@tanstack/vue-query":"^5.102.6","@vitest/coverage-v8":"^4.1.11","@rollup/plugin-commonjs":"^28.0.3","@rollup/plugin-typescript":"^12.1.2","@rollup/plugin-node-resolve":"^16.0.0"},"peerDependencies":{"vue":">=3.0.0","axios":">=1.15.2","jwt-decode":"^4.0.0","@tanstack/vue-query":">=5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/phalanx_6.0.0_1788534688616_0.9675297895743467","host":"s3://npm-registry-packages-npm-production"}},"6.1.0":{"name":"@arex95/phalanx","version":"6.1.0","description":"Headless framework for admin panels on Vue: typed REST services with derived TanStack queries and mutations, declarative actions, session handling with an HttpOnly refresh cookie, resilient realtime connections, encrypted browser storage and typed errors.","main":"dist/index.mjs","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"},"./package.json":"./package.json"},"types":"dist/index.d.ts","type":"module","sideEffects":false,"scripts":{"clean":"node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"","build":"npm run clean && rollup -c && node scripts/fix-dts-aliases.mjs","dev":"rollup -c -w","test":"vitest run","typecheck":"vue-tsc --noEmit","typecheck:test":"tsc --noEmit -p tsconfig.test.json","lint":"eslint .","prepublishOnly":"npm run typecheck && npm run typecheck:test && npm run lint && npm run test && npm run build && npm run check:docs","release":"git push --follow-tags && npm publish --access public","release:major":"npm version major -m \"chore(release): %s\"","release:minor":"npm version minor -m \"chore(release): %s\"","release:patch":"npm version patch -m \"chore(release): %s\"","check:docs":"node scripts/check-docs-examples.mjs"},"repository":{"type":"git","url":"git+https://github.com/Arex95/phalanx.git"},"keywords":["vue","vue3","admin","admin-panel","typescript","rest-api","tanstack-query","authentication","realtime","sse","encryption","csrf","axios","jwt"],"author":{"name":"Arturo Rafael Serrano Girón"},"license":"MIT","peerDependencies":{"@tanstack/vue-query":">=5.0.0","axios":">=1.15.2","jwt-decode":"^4.0.0","vue":">=3.0.0"},"devDependencies":{"@eslint/js":"^9.23.0","@rollup/plugin-commonjs":"^28.0.3","@rollup/plugin-json":"^6.1.0","@rollup/plugin-node-resolve":"^16.0.0","@rollup/plugin-typescript":"^12.1.2","@tanstack/vue-query":"^5.102.6","@types/node":"^22.13.10","@vitest/coverage-v8":"^4.1.11","@vue/test-utils":"^2.4.11","axios":"^1.18.1","eslint":"^9.23.0","eslint-plugin-vue":"^10.0.0","fake-indexeddb":"^6.2.5","globals":"^16.0.0","happy-dom":"^20.11.1","rollup":"^4.35.0","ts-node":"^10.9.2","tslib":"^2.8.1","typescript":"^5.8.2","typescript-eslint":"^8.28.0","vitest":"^4.1.11","vue-tsc":"^3.3.11"},"engines":{"node":">=15"},"homepage":"https://github.com/Arex95/phalanx#readme","bugs":{"url":"https://github.com/Arex95/phalanx/issues"},"gitHead":"4a1152c0fe3a0c7ae862a1f74d7f44015bf19348","_id":"@arex95/phalanx@6.1.0","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-99gbPMkPr0OXgxdjSbtMGlaXvY5KSzjQwYkzrO+QID7/jL5KvZcFt+KOL402kKFXmdbaG9fBEWxoo6N5tNeKgg==","shasum":"a7e07354e9720cc6eb43532f85da8221aa4ff483","tarball":"https://registry.npmjs.org/@arex95/phalanx/-/phalanx-6.1.0.tgz","fileCount":79,"unpackedSize":193506,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG9sgJIm3oJOJobIl/9kCaekj4deNiUxNHCgXmdDttWNAiEA6zP/uWMfi5buMN0pfIdQYrwjdI1Ihy4S2koKOByvba4="}]},"_npmUser":{"name":"arex95","email":"arturorafaelonce@gmail.com"},"directories":{},"maintainers":[{"name":"arex95","email":"arturorafaelonce@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/phalanx_6.1.0_1788738738453_0.8406977265415303"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-04T15:11:28.341Z","modified":"2026-09-06T23:52:18.733Z","6.0.0":"2026-09-04T15:11:28.745Z","6.1.0":"2026-09-06T23:52:18.593Z"},"bugs":{"url":"https://github.com/Arex95/phalanx/issues"},"author":{"name":"Arturo Rafael Serrano Girón"},"license":"MIT","homepage":"https://github.com/Arex95/phalanx#readme","keywords":["vue","vue3","admin","admin-panel","typescript","rest-api","tanstack-query","authentication","realtime","sse","encryption","csrf","axios","jwt"],"repository":{"type":"git","url":"git+https://github.com/Arex95/phalanx.git"},"description":"Headless framework for admin panels on Vue: typed REST services with derived TanStack queries and mutations, declarative actions, session handling with an HttpOnly refresh cookie, resilient realtime connections, encrypted browser storage and typed errors.","maintainers":[{"name":"arex95","email":"arturorafaelonce@gmail.com"}],"readme":"# Phalanx\n\n**The headless framework for admin panels.**\n\nEverything an admin panel needs below the interface. Define a resource once and\nget its service, TanStack queries and mutations, and its custom operations —\nwith sessions, realtime, encrypted storage and typed errors already decided.\n\nHeadless: it ships no components and no styles, so the interface stays yours.\n\n📖 **[Documentation](https://arex95.github.io/phalanx/)** ·\n[Getting started](https://arex95.github.io/phalanx/guide/getting-started) ·\n[Server requirements](https://arex95.github.io/phalanx/concepts/server-requirements) ·\n[Migrating from vue-core](https://arex95.github.io/phalanx/reference/migration)\n\n```bash\npnpm add @arex95/phalanx\npnpm add vue axios @tanstack/vue-query jwt-decode\n```\n\n## Example\n\n```ts\nimport {\n    RestStd, defineAction, createDomainQueries, createDomainMutations, createModelKeys\n} from '@arex95/phalanx';\n\nclass UserService extends RestStd {\n    static resource = 'users';\n\n    static suspend = defineAction(\n        (id: string) => this.customRequest<User>({\n            method: 'POST',\n            url: `users/${id}/suspend`\n        }),\n        { permission: 'users.suspend', requiresConfirmation: true, invalidate: ['users'] }\n    );\n}\n\nconst userKeys = createModelKeys('admin:user');\nexport const userQueries = createDomainQueries({ service: UserService, keys: userKeys });\nexport const userMutations = createDomainMutations({ service: UserService, keys: userKeys });\n```\n\n```vue\n<script setup lang=\"ts\">\nconst { data, isPending } = userQueries.getAll({ params: filters });\nconst { suspend } = userMutations;\n</script>\n\n<template>\n  <button :disabled=\"!suspend.isAuthorized.value\" @click=\"suspend.mutate(id)\">\n    Suspend\n  </button>\n</template>\n```\n\n`suspend` is a typed mutation that checks the permission, asks for\nconfirmation, reports the result and invalidates the list.\n\n## What it covers\n\n- **Services.** One class per resource, eleven inherited methods, custom\n  operations alongside them.\n- **Composables.** TanStack queries and mutations generated from the service,\n  including custom methods with their inferred types.\n- **Actions.** Permission, confirmation, notification and invalidation declared\n  as metadata rather than repeated in each view.\n- **Session.** Access token in memory, refresh token in an `HttpOnly` cookie,\n  one refresh in flight with concurrent 401s queued behind it.\n- **Errors.** `AuthError`, `ValidationError`, `ServerError`, `NetworkError` from\n  every call, with validation issues normalised across four common API shapes.\n- **Realtime.** A reconnection state machine with backoff, a circuit breaker and\n  a token refresh when the stream rejects one. The transport is injected, so it\n  runs over SSE, a WebSocket or anything else.\n- **Encryption.** Browser storage encrypted under a non-extractable key, and\n  hybrid field encryption for data that should only be readable by the server.\n- **The small things.** Idempotency keys, contextual headers, a shared signal\n  for when the API is unreachable.\n\nIt ships no components and no styles: the screen stays yours.\n\n## Requirements\n\n| Peer dependency | Version |\n|---|---|\n| `vue` | `>=3.0.0` |\n| `axios` | `>=1.15.2` |\n| `@tanstack/vue-query` | `>=5.0.0` |\n| `jwt-decode` | `^4.0.0` |\n\nESM only. Node 15+ to build against it.\n\nThe refresh cookie is set by your API:\n\n```http\nSet-Cookie: refresh_token=…; HttpOnly; Secure; SameSite=None; Path=/auth/refresh\n```\n\nFull list, including the CORS pair for cross-origin setups:\n[Server requirements](https://arex95.github.io/phalanx/concepts/server-requirements).\n\n## Development\n\n```bash\npnpm install\npnpm test         # unit tests\npnpm typecheck\npnpm lint\npnpm build\npnpm -C docs dev  # documentation site\n```\n\n`prepublishOnly` runs typecheck, lint, tests and build. The same five steps run\non every push and pull request — see `.github/workflows/test.yml`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}