{"_id":"@aginix/adonis-object-id","_rev":"3-549d3271e515e018d01e09cf1d1c6bd1","name":"@aginix/adonis-object-id","dist-tags":{"beta":"0.1.0-beta.0","latest":"0.1.1"},"versions":{"0.1.0-beta.0":{"name":"@aginix/adonis-object-id","version":"0.1.0-beta.0","keywords":["adonisjs","adonis","lucid","external-id","identifier","reference","seed"],"author":{"name":"n3n"},"license":"MIT","_id":"@aginix/adonis-object-id@0.1.0-beta.0","maintainers":[{"name":"n3n","email":"nonpawit.tee@gmail.com"}],"c8":{"exclude":["tests/**"],"reporter":["text","html"]},"dist":{"shasum":"63ef62ec394a1b9f01249ab116bbfb679d400718","tarball":"https://registry.npmjs.org/@aginix/adonis-object-id/-/adonis-object-id-0.1.0-beta.0.tgz","fileCount":23,"integrity":"sha512-52XSsrEbfzM8TYPq/pqvksDy3PUoVczFM3iZJU1WPGZY4cgJq8uOAG2GKEOxzfKY5HyDSVg1rZ3uBk/Tsr4kRw==","signatures":[{"sig":"MEUCIA3dqycoGclrFJdD/f5zg7IiKU5R3MRraGR1JmOzM3n3AiEA6B2Cz5wS1K8TiEjcCTGN61rOivCu9VqkWsQ+O09DmWM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":65214},"main":"build/index.js","type":"module","types":"./build/index.d.ts","tsdown":{"dts":false,"clean":true,"entry":["./index.ts","./configure.ts","./src/types.ts","./src/object_id_helpers.ts","./src/object_id_record.ts","./src/object_id_service.ts","./src/has_object_id_mixin.ts","./providers/object_id_provider.ts"],"format":"esm","minify":"dce-only","outDir":"./build","target":"esnext","external":["@adonisjs/core","@adonisjs/core/types","@adonisjs/core/types/helpers","@adonisjs/core/commands/configure","@adonisjs/lucid","@adonisjs/lucid/orm","@adonisjs/lucid/schema","@adonisjs/lucid/types/model","luxon"],"treeshake":false,"sourcemaps":false,"fixedExtension":false},"engines":{"node":">=24.0.0"},"exports":{".":"./build/index.js","./types":"./build/src/types.js","./object_id_record":"./build/src/object_id_record.js","./object_id_helpers":"./build/src/object_id_helpers.js","./object_id_service":"./build/src/object_id_service.js","./object_id_provider":"./build/providers/object_id_provider.js","./has_object_id_mixin":"./build/src/has_object_id_mixin.js"},"scripts":{"lint":"eslint .","test":"c8 npm run quick:test","build":"npm run compile","format":"prettier --write .","compile":"tsdown && tsc --emitDeclarationOnly --declaration","pretest":"npm run lint","release":"release-it","version":"npm run build","typecheck":"tsc --noEmit","precompile":"npm run lint","quick:test":"node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts","postcompile":"npm run copy:templates","copy:templates":"copyfiles \"stubs/**/*.stub\" build","prepublishOnly":"npm run build"},"_npmUser":{"name":"n3n","email":"nonpawit.tee@gmail.com"},"prettier":"@adonisjs/prettier-config","release-it":{"git":{"push":true,"tagName":"adonis-object-id-v${version}","commitMessage":"chore(adonis-object-id): release ${version}","tagAnnotation":"adonis-object-id-v${version}","requireUpstream":true,"requireCleanWorkingDir":true},"npm":{"publish":true,"skipChecks":true},"github":{"release":true,"releaseName":"@aginix/adonis-object-id ${version}"},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"_npmVersion":"11.8.0","description":"Stable string identifiers for AdonisJS Lucid models — reference any record by a namespaced key instead of its auto-increment id","directories":{},"_nodeVersion":"24.13.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"c8":"^11.0.0","luxon":"^3.5.0","eslint":"^10.0.3","tsdown":"^0.21.0","prettier":"^3.8.1","copyfiles":"^2.4.1","cross-env":"^10.1.0","release-it":"^19.2.4","typescript":"^5.9.3","@types/node":"^25.3.5","@japa/assert":"^4.2.0","@japa/runner":"^5.3.0","@types/luxon":"^3.7.1","@adonisjs/core":"^7.0.1","@adonisjs/lucid":"^22.0.0","@poppinss/hooks":"^7.3.0","@poppinss/ts-exec":"^1.4.4","@adonisjs/tsconfig":"^2.0.0","@adonisjs/eslint-config":"^3.0.0","@adonisjs/prettier-config":"^1.4.5","@release-it/conventional-changelog":"^10.0.5"},"peerDependencies":{"luxon":"^3.0.0","@adonisjs/core":"^7.0.0","@adonisjs/lucid":"^22.0.0","@poppinss/hooks":"^7.3.0"},"_npmOperationalInternal":{"tmp":"tmp/adonis-object-id_0.1.0-beta.0_1778563405104_0.5968288549870426","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@aginix/adonis-object-id","version":"0.1.0","keywords":["adonisjs","adonis","lucid","external-id","identifier","reference","seed"],"author":{"name":"n3n"},"license":"MIT","_id":"@aginix/adonis-object-id@0.1.0","maintainers":[{"name":"n3n","email":"nonpawit.tee@gmail.com"}],"c8":{"exclude":["tests/**"],"reporter":["text","html"]},"dist":{"shasum":"f410578d5c1d7a3c79e7de57a703658b1e3dd8f4","tarball":"https://registry.npmjs.org/@aginix/adonis-object-id/-/adonis-object-id-0.1.0.tgz","fileCount":23,"integrity":"sha512-fVxXExRZ8Bs/s4+nva2MpJXvw7LF8bNhpCjik1wSh4xlNFTfzJn9L6oXn7GTg5DLTymuio17FQ1TtvkGN2LQXQ==","signatures":[{"sig":"MEUCIQDXE6Ct44X2x6T8i2/vtHN2tT22ulW2YkqRlL+c/owA8wIga60zF+E/zZBCca1OnupGvXTi71L9hLhU7+XULxH5KZU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":65446},"main":"build/index.js","type":"module","types":"./build/index.d.ts","tsdown":{"dts":false,"clean":true,"entry":["./index.ts","./configure.ts","./stubs/main.ts","./src/types.ts","./src/object_id_helpers.ts","./src/object_id_record.ts","./src/object_id_service.ts","./src/has_object_id_mixin.ts","./providers/object_id_provider.ts"],"format":"esm","minify":"dce-only","outDir":"./build","target":"esnext","external":["@adonisjs/core","@adonisjs/core/types","@adonisjs/core/types/helpers","@adonisjs/core/commands/configure","@adonisjs/lucid","@adonisjs/lucid/orm","@adonisjs/lucid/schema","@adonisjs/lucid/types/model","luxon"],"treeshake":false,"sourcemaps":false,"fixedExtension":false},"engines":{"node":">=24.0.0"},"exports":{".":"./build/index.js","./types":"./build/src/types.js","./object_id_record":"./build/src/object_id_record.js","./object_id_helpers":"./build/src/object_id_helpers.js","./object_id_service":"./build/src/object_id_service.js","./object_id_provider":"./build/providers/object_id_provider.js","./has_object_id_mixin":"./build/src/has_object_id_mixin.js"},"gitHead":"f20802008844053323d6281752fb92cedb0d5022","scripts":{"lint":"eslint .","test":"c8 npm run quick:test","build":"npm run compile","format":"prettier --write .","compile":"tsdown && tsc --emitDeclarationOnly --declaration","pretest":"npm run lint","release":"release-it","version":"npm run build","typecheck":"tsc --noEmit","precompile":"npm run lint","quick:test":"node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts","postcompile":"npm run copy:templates","copy:templates":"copyfiles \"stubs/**/*.stub\" build","prepublishOnly":"npm run build"},"_npmUser":{"name":"n3n","email":"nonpawit.tee@gmail.com"},"prettier":"@adonisjs/prettier-config","release-it":{"git":{"push":true,"tagName":"adonis-object-id-v${version}","commitMessage":"chore(adonis-object-id): release ${version}","tagAnnotation":"adonis-object-id-v${version}","requireUpstream":true,"requireCleanWorkingDir":true},"npm":{"publish":true,"skipChecks":true},"github":{"release":true,"releaseName":"@aginix/adonis-object-id ${version}"},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"_npmVersion":"11.8.0","description":"Stable string identifiers for AdonisJS Lucid models — reference any record by a namespaced key instead of its auto-increment id","directories":{},"_nodeVersion":"24.13.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"c8":"^11.0.0","luxon":"^3.5.0","eslint":"^10.0.3","tsdown":"^0.21.0","prettier":"^3.8.1","copyfiles":"^2.4.1","cross-env":"^10.1.0","release-it":"^19.2.4","typescript":"^5.9.3","@types/node":"^25.3.5","@japa/assert":"^4.2.0","@japa/runner":"^5.3.0","@types/luxon":"^3.7.1","@adonisjs/core":"^7.0.1","@adonisjs/lucid":"^22.0.0","@poppinss/hooks":"^7.3.0","@poppinss/ts-exec":"^1.4.4","@adonisjs/tsconfig":"^2.0.0","@adonisjs/eslint-config":"^3.0.0","@adonisjs/prettier-config":"^1.4.5","@release-it/conventional-changelog":"^10.0.5"},"peerDependencies":{"luxon":"^3.0.0","@adonisjs/core":"^7.0.0","@adonisjs/lucid":"^22.0.0","@poppinss/hooks":"^7.3.0"},"_npmOperationalInternal":{"tmp":"tmp/adonis-object-id_0.1.0_1778589808266_0.7012885108310258","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aginix/adonis-object-id","description":"Stable string identifiers for AdonisJS Lucid models — reference any record by a namespaced key instead of its auto-increment id","version":"0.1.1","engines":{"node":">=24.0.0"},"type":"module","main":"build/index.js","exports":{".":"./build/index.js","./types":"./build/src/types.js","./object_id_helpers":"./build/src/object_id_helpers.js","./object_id_record":"./build/src/object_id_record.js","./object_id_service":"./build/src/object_id_service.js","./has_object_id_mixin":"./build/src/has_object_id_mixin.js","./object_id_provider":"./build/providers/object_id_provider.js"},"scripts":{"copy:templates":"copyfiles \"stubs/**/*.stub\" build","typecheck":"tsc --noEmit","lint":"eslint .","format":"prettier --write .","quick:test":"node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts","pretest":"npm run lint","test":"c8 npm run quick:test","precompile":"npm run lint","compile":"tsdown && tsc --emitDeclarationOnly --declaration","postcompile":"npm run copy:templates","build":"npm run compile","release":"release-it","version":"npm run build","prepublishOnly":"npm run build"},"keywords":["adonisjs","adonis","lucid","external-id","identifier","reference","seed"],"author":{"name":"n3n"},"license":"MIT","devDependencies":{"@adonisjs/core":"^7.0.1","@adonisjs/eslint-config":"^3.0.0","@adonisjs/lucid":"^22.0.0","@adonisjs/prettier-config":"^1.4.5","@adonisjs/tsconfig":"^2.0.0","@japa/assert":"^4.2.0","@japa/runner":"^5.3.0","@poppinss/hooks":"^7.3.0","@poppinss/ts-exec":"^1.4.4","@release-it/conventional-changelog":"^10.0.5","@types/luxon":"^3.7.1","@types/node":"^25.3.5","c8":"^11.0.0","copyfiles":"^2.4.1","cross-env":"^10.1.0","eslint":"^10.0.3","luxon":"^3.5.0","prettier":"^3.8.1","release-it":"^19.2.4","tsdown":"^0.21.0","typescript":"^5.9.3"},"peerDependencies":{"@adonisjs/core":"^7.0.0","@adonisjs/lucid":"^22.0.0","@poppinss/hooks":"^7.3.0","luxon":"^3.0.0"},"publishConfig":{"access":"public"},"tsdown":{"entry":["./index.ts","./configure.ts","./stubs/main.ts","./src/types.ts","./src/object_id_helpers.ts","./src/object_id_record.ts","./src/object_id_service.ts","./src/has_object_id_mixin.ts","./providers/object_id_provider.ts"],"outDir":"./build","clean":true,"format":"esm","minify":"dce-only","fixedExtension":false,"dts":false,"treeshake":false,"sourcemaps":false,"target":"esnext","external":["@adonisjs/core","@adonisjs/core/types","@adonisjs/core/types/helpers","@adonisjs/core/commands/configure","@adonisjs/lucid","@adonisjs/lucid/orm","@adonisjs/lucid/schema","@adonisjs/lucid/services/db","@adonisjs/lucid/types/model","luxon"]},"release-it":{"git":{"requireCleanWorkingDir":true,"requireUpstream":true,"commitMessage":"chore(adonis-object-id): release ${version}","tagAnnotation":"adonis-object-id-v${version}","push":true,"tagName":"adonis-object-id-v${version}"},"github":{"release":true,"releaseName":"@aginix/adonis-object-id ${version}"},"npm":{"publish":true,"skipChecks":true},"plugins":{"@release-it/conventional-changelog":{"preset":{"name":"angular"}}}},"c8":{"reporter":["text","html"],"exclude":["tests/**"]},"prettier":"@adonisjs/prettier-config","gitHead":"83dc44d1b46f8f705b1a9c2919198e216b80a55c","types":"./build/index.d.ts","_id":"@aginix/adonis-object-id@0.1.1","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-5C4XgKFfWdF1pOMu3UtWRIAbCfE0Aq3V4WJWXaW/ccILR8dXP3yEZ0VgVOMwl1u2jYk11ZozCQdk2tClhjyY4Q==","shasum":"cfa55e77cf6b96bd6d0c53b1213743d07433be2e","tarball":"https://registry.npmjs.org/@aginix/adonis-object-id/-/adonis-object-id-0.1.1.tgz","fileCount":23,"unpackedSize":66607,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDUt75HZNCsknMp1kDoDc6eHHKCNkWw6xzaiqziebItjAIgQA9epyv2t8YQcLoMxv6afalmRirNl7D6YvyfNsP1kik="}]},"_npmUser":{"name":"n3n","email":"nonpawit.tee@gmail.com"},"directories":{},"maintainers":[{"name":"n3n","email":"nonpawit.tee@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/adonis-object-id_0.1.1_1778597467722_0.7143741868720728"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-12T05:23:25.028Z","modified":"2026-05-12T14:51:07.981Z","0.1.0-beta.0":"2026-05-12T05:23:25.253Z","0.1.0":"2026-05-12T12:43:28.459Z","0.1.1":"2026-05-12T14:51:07.849Z"},"author":{"name":"n3n"},"license":"MIT","keywords":["adonisjs","adonis","lucid","external-id","identifier","reference","seed"],"description":"Stable string identifiers for AdonisJS Lucid models — reference any record by a namespaced key instead of its auto-increment id","maintainers":[{"name":"n3n","email":"nonpawit.tee@gmail.com"}],"readme":"# @aginix/adonis-object-id\n\nStable string identifiers for AdonisJS Lucid models.\n\nMaster-data rows usually have auto-incremented IDs, which makes them hard to\nreference from code, seeders, or cross-environment imports — the ID changes\ndepending on insert order. Adding a `code` / `slug` / `reference` column to\nevery table that needs one is repetitive and rigid. This package solves the\nproblem with a single polymorphic `object_ids` table that maps a string\nreference (`\"namespace.name\"`) to a record in any model.\n\n## Features\n\n- **One table, every model.** No per-table boilerplate.\n- **Mixin** that adds object_id utilities to any Lucid model.\n- **Static service** for cross-cutting access (seeders, scripts).\n- **Cascade delete** of references when a row is removed (opt-out).\n- **Ace command** to scaffold the table migration.\n\n## Install\n\n```sh\nnpm install @aginix/adonis-object-id\nnode ace configure @aginix/adonis-object-id\nnode ace migration:run\n```\n\nThe `configure` hook registers the package's provider and drops a\ntimestamped migration into `database/migrations` that creates the\n`object_ids` table. Re-running `configure` is safe — it detects an\nexisting `*_create_object_ids_table.ts` file and skips regeneration.\n\n## Reference format\n\nReferences are strings of the form `namespace.name` (e.g. `app.admin_user`).\nThe namespace is required for clarity but defaults to `app` when omitted, so\n`\"admin_user\"` is normalized to `\"app.admin_user\"`. Only the first `.` is\ntreated as a separator — `web.editor.iframe` parses as namespace=`web`,\nname=`editor.iframe`.\n\n## Usage — `HasObjectId` mixin\n\nCompose the mixin alongside `BaseModel`:\n\n```ts\nimport { compose } from '@adonisjs/core/helpers'\nimport { BaseModel, column } from '@adonisjs/lucid/orm'\nimport { HasObjectId } from '@aginix/adonis-object-id'\n\nexport default class Faculty extends compose(BaseModel, HasObjectId) {\n  @column({ isPrimary: true })\n  declare id: number\n\n  @column()\n  declare name: string\n\n  // Optional. Defaults to the Lucid table name (\"faculties\" here).\n  // static objectIdModelKey = 'school.faculty'\n\n  // Optional. Default true — wipes orphan references on delete.\n  // static cascadeObjectIdsOnDelete = false\n}\n```\n\n### Static methods\n\n```ts\n// Create a row AND bind a reference to it atomically. Equivalent to\n// `Faculty.create({...})` + `faculty.assignObjectId('...')`, but\n// wrapped in a transaction so a duplicate-reference error rolls the\n// new row back instead of leaving it orphaned. Pass `{ client: trx }`\n// to piggyback on an existing transaction.\nconst faculty = await Faculty.createWithObjectId(\n  { name: 'Engineering' },\n  'app.engineering_faculty'\n)\n\n// Resolve a reference to a row of this model (null if missing /\n// pointing at a different model / row deleted)\nconst found = await Faculty.findByObjectId('app.engineering_faculty')\n\n// Same but throws ObjectIdNotFoundError on miss\nconst required = await Faculty.findByObjectIdOrFail('app.engineering_faculty')\n\n// Just the primary-key value — useful for FK wiring in seeders\nconst id = await Faculty.refObjectId('app.engineering_faculty')\nconst idStrict = await Faculty.refObjectIdOrFail('app.engineering_faculty')\n```\n\n### Instance methods\n\n```ts\nconst faculty = await Faculty.create({ name: 'Engineering' })\n\n// Bind a reference (upsert; idempotent if it already points here)\nawait faculty.assignObjectId('app.engineering_faculty')\n\n// Read back\nawait faculty.getObjectId() // \"app.engineering_faculty\"\nawait faculty.getObjectIds() // [\"app.engineering_faculty\"]\n\n// Add another reference (e.g. legacy alias)\nawait faculty.assignObjectId('legacy.fac_eng')\n\n// Rename a reference that points at this row\nawait faculty.renameObjectId('legacy.fac_eng', 'archive.fac_eng')\n\n// Remove a specific reference (only if it points here)\nawait faculty.removeObjectId('archive.fac_eng')\n\n// Remove every reference for this row\nawait faculty.removeAllObjectIds()\n```\n\n## Usage — `ObjectIds` service\n\nUse the static service when you don't want to mix in the model (e.g. in\nseeders, scripts, or when the model has no `HasObjectId`):\n\n```ts\nimport { ObjectIds } from '@aginix/adonis-object-id'\nimport Faculty from '#models/faculty'\n\n// Resolve a reference to its (model, recordId) target\nconst target = await ObjectIds.ref('app.engineering_faculty')\n//   => { model: 'faculties', recordId: '42' } | null\n\n// Throws on miss\nconst target2 = await ObjectIds.refOrFail('app.engineering_faculty')\n\n// Resolve directly to a row of a given model\nconst faculty = await ObjectIds.find(Faculty, 'app.engineering_faculty')\nconst facultyStrict = await ObjectIds.findOrFail(Faculty, 'app.engineering_faculty')\n\n// Assign a reference. Accepts either a Lucid row or an explicit target.\nawait ObjectIds.assign(faculty, 'app.engineering_faculty')\nawait ObjectIds.assign({ model: 'faculties', recordId: 42 }, 'app.engineering_faculty')\n\n// Remove a reference\nawait ObjectIds.remove('app.engineering_faculty')\n\n// Remove every reference for a target (called automatically by the\n// mixin's beforeDelete hook)\nawait ObjectIds.removeAllFor(faculty)\n\n// List every reference pointing at a target\nawait ObjectIds.listFor(faculty) // => [\"app.engineering_faculty\", ...]\n```\n\nAll service methods accept an optional `{ connection?, client? }` argument\nto override the database connection or piggyback on an open transaction.\n\n## Seeders\n\nObject_ids shine in seeders — bind every master record to a stable\nreference once, then look up by reference everywhere else:\n\n```ts\n// database/seeders/01_faculties.ts\nimport { BaseSeeder } from '@adonisjs/lucid/seeders'\nimport Faculty from '#models/faculty'\n\nexport default class extends BaseSeeder {\n  async run() {\n    const engineering = await Faculty.updateOrCreate(\n      { name: 'Engineering' },\n      { name: 'Engineering' }\n    )\n    await engineering.assignObjectId('seed.faculty_engineering')\n\n    const science = await Faculty.updateOrCreate({ name: 'Science' }, { name: 'Science' })\n    await science.assignObjectId('seed.faculty_science')\n  }\n}\n```\n\n```ts\n// database/seeders/02_courses.ts\nimport { BaseSeeder } from '@adonisjs/lucid/seeders'\nimport Course from '#models/course'\nimport Faculty from '#models/faculty'\n\nexport default class extends BaseSeeder {\n  async run() {\n    const facultyId = await Faculty.refObjectIdOrFail('seed.faculty_engineering')\n    await Course.create({ name: 'CS 101', facultyId: Number(facultyId) })\n  }\n}\n```\n\nThe second seeder no longer cares about insertion order or auto-IDs.\n\n## Backfilling existing data\n\nAdding object_ids to a record that already exists is a one-liner — they're\nstored in a separate table, so no schema change is needed:\n\n```ts\nconst admin = await User.findByOrFail('email', 'admin@example.com')\nawait admin.assignObjectId('app.admin_user')\n```\n\n## Model key\n\nThe `model` column in `object_ids` defaults to the consumer model's Lucid\n`table` name. This is stable across class renames but changes if you\nrename the table — override it with `static objectIdModelKey` if you want\na portable key:\n\n```ts\nclass Faculty extends compose(BaseModel, HasObjectId) {\n  static objectIdModelKey = 'school.faculty'\n}\n```\n\n## Errors\n\n- `InvalidObjectIdError` (status 400) — reference fails parsing.\n- `ObjectIdNotFoundError` (status 404) — `*OrFail` method couldn't resolve.\n\nBoth extend `Error` and expose a `status` field, so AdonisJS's default\nexception handler turns uncaught instances into appropriate HTTP responses.\n\n## License\n\nMIT — see [LICENSE.md](./LICENSE.md).\n","readmeFilename":"README.md"}