{"_id":"@anydbinc/anydb-migrate","_rev":"2-42d10c3687c639f5bf066770d0f21589","name":"@anydbinc/anydb-migrate","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@anydbinc/anydb-migrate","version":"0.1.0","keywords":["anydb","cli","csv","excel","migration"],"_id":"@anydbinc/anydb-migrate@0.1.0","maintainers":[{"name":"anydbinc","email":"anis@anydb.com"}],"homepage":"https://github.com/HumanlyInc/anydb-migrate-tool#readme","bugs":{"url":"https://github.com/HumanlyInc/anydb-migrate-tool/issues"},"bin":{"anydb-migrate":"dist/cli.js"},"dist":{"shasum":"c6417c86b26c841971cb02cb79b82039b47a7ca3","tarball":"https://registry.npmjs.org/@anydbinc/anydb-migrate/-/anydb-migrate-0.1.0.tgz","fileCount":57,"integrity":"sha512-LLbYkv3fhhD/YmdjJ4YW1Y4SftXG3g5Kc8F/9lKmF0H9zGDsvi4ztOBS9D/+TS44PZLhf6d8q+yuh0dfzZH6JA==","signatures":[{"sig":"MEQCIApZxJzeWGxL+fYChVjwDh2vH3LHYp9wvCuo554NRHLcAiA3C0mh4ryOnVufN1OsmCmZxd8Bckz+5u1yf6dszChTvA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":97417},"type":"module","engines":{"node":">=20"},"gitHead":"f17419cf78fb0d8c4bef8022676734955a374d6b","scripts":{"dev":"tsx src/cli.ts","test":"tsx --test src/source/sourceReaders.test.ts src/migration/matching.test.ts src/migration/MigrationEngine.test.ts src/config/schema.test.ts src/config/validateRemote.test.ts src/anydb/RequestLimiter.test.ts","build":"tsc -p tsconfig.json","prepack":"npm test && npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"anydbinc","email":"anis@anydb.com"},"repository":{"url":"git+https://github.com/HumanlyInc/anydb-migrate-tool.git","type":"git"},"_npmVersion":"10.8.2","description":"Minimal spreadsheet migration CLI for AnyDB","directories":{},"_nodeVersion":"20.19.4","dependencies":{"yaml":"^2.8.1","exceljs":"^4.4.0","commander":"^14.0.0","csv-parse":"^6.1.0","anydb-api-sdk-ts":"^1.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.3","typescript":"^5.9.2","@types/node":"^24.2.1"},"_npmOperationalInternal":{"tmp":"tmp/anydb-migrate_0.1.0_1786624046570_0.7845298558013112","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package renamed to anydb-migrate-spreadsheet. Install that package instead."}},"time":{"created":"2026-08-13T12:27:26.400Z","modified":"2026-08-13T12:30:22.184Z","0.1.0":"2026-08-13T12:27:26.717Z"},"bugs":{"url":"https://github.com/HumanlyInc/anydb-migrate-tool/issues"},"homepage":"https://github.com/HumanlyInc/anydb-migrate-tool#readme","keywords":["anydb","cli","csv","excel","migration"],"repository":{"url":"git+https://github.com/HumanlyInc/anydb-migrate-tool.git","type":"git"},"description":"Minimal spreadsheet migration CLI for AnyDB","maintainers":[{"name":"anydbinc","email":"anis@anydb.com"}],"readme":"# AnyDB Migrate Tool\n\n[AnyDB](https://www.anydb.com/) is an object-based platform for organizing business data and operations. It models real-world things—such as items, locations, vendors, and shipments so they are structured records that can be connected to one another.\n\nAnyDB Migrate is a small local CLI for moving spreadsheet data into that connected model. Rather than importing every source row as one flat record, it can map a row into multiple AnyDB objects, look up or update existing records, create missing records, and link the results together. Objects are processed in YAML order, so each object can reference records resolved earlier for the same row.\n\n## Supported formats\n\n- **CSV (`.csv`)** as a source, with the first row used as column headers.\n- **Excel (`.xlsx`)** as a source, with optional worksheet selection.\n- **YAML (`.yaml` or `.yml`)** for describing how source columns map to AnyDB objects, fields, matches, and references.\n\n## One record, multiple objects\n\nFor example, this spreadsheet row:\n\n```text\nSKU  | Name          | Location | Quantity\nA100 | Safety Gloves | Austin   | 24\n```\n\ncan become three connected AnyDB objects:\n\n```text\nItem\n  SKU: A100\n  Item Name: Safety Gloves\n\nLocation\n  Location Name: Austin\n\nInventory Item\n  Quantity On Hand: 24\n  Item Ref: -> Item (A100)\n  Location Ref: -> Location (Austin)\n```\n\nThe `Item` can be created or updated, the `Location` can be looked up, and the `Inventory Item` can then reference both. The mapping and behavior for each object are declared in the migration's YAML configuration.\n\n## Setup\n\nRequires Node.js 20 or newer. Install the CLI globally from npm:\n\n```bash\nnpm install --global @anydbinc/anydb-migrate\nanydb-migrate --help\n```\n\nAlternatively, run it without a global installation:\n\n```bash\nnpx @anydbinc/anydb-migrate --help\n```\n\nFor local development, install dependencies and build from this repository:\n\n```bash\nnpm install\nnpm run build\n```\n\nDuring development, run the TypeScript entry point directly:\n\n```bash\nnpm run dev -- validate migration.yaml\nnpm run dev -- run migration.yaml --dry-run\n```\n\nAfter building:\n\n```bash\nnode dist/cli.js validate migration.yaml\nnode dist/cli.js run migration.yaml\n```\n\n## Credentials\n\nSet these environment variables:\n\n```text\nANYDB_API_KEY\nANYDB_USER_EMAIL\nANYDB_TEAM_ID\nANYDB_ADB_ID\nANYDB_BASE_URL        # optional; defaults to the SDK default\nANYDB_REQUESTS_PER_MINUTE  # optional; defaults to 100\n```\n\nFor example, in PowerShell:\n\n```powershell\n$env:ANYDB_API_KEY=\"your-api-key\"\n$env:ANYDB_USER_EMAIL=\"you@example.com\"\n$env:ANYDB_TEAM_ID=\"your-team-id\"\n$env:ANYDB_ADB_ID=\"your-database-id\"\n\n# Optional when using a non-default AnyDB server:\n$env:ANYDB_BASE_URL=\"https://your-anydb-server/api\"\n```\n\nThese values last for the current PowerShell session. After setting them, you can run:\n\n```powershell\nnpm run dev -- validate migration.yaml\nnpm run dev -- run migration.yaml --dry-run\n```\n\n`teamId`, `databaseId`, and `baseUrl` may instead be placed under `anydb` in YAML. Keep the API key and user email in environment variables so secrets are not accidentally committed to Git.\n\n## Configuration\n\nSee [`example.inventory.yaml`](./example.inventory.yaml) for a complete inventory migration. The source path is relative to the YAML file. XLSX sources may select a worksheet with `source.sheet`; CSV sources must omit it.\n\n### Example configuration\n\nSuppose the `Inventory` worksheet starts with these column headers:\n\n```text\nSKU | Name | Location | Quantity\n```\n\nA migration configuration could look like this:\n\n```yaml\nname: inventory-import\n\nsource:\n  file: ./inventory.xlsx\n  sheet: Inventory\n\nobjects:\n  - name: item\n    type: Item\n    mode: upsert\n    match:\n      field: SKU\n      column: SKU\n    fields:\n      SKU: SKU\n      Item Name: Name\n\n  - name: location\n    type: Location\n    mode: lookup\n    match:\n      field: Location Name\n      column: Location\n\n  - name: inventoryItem\n    type: Inventory Item\n    mode: upsert\n    match:\n      fields:\n        Item Ref:\n          object: item\n        Location Ref:\n          object: location\n    fields:\n      Quantity On Hand: Quantity\n      Status:\n        value: Active\n    references:\n      Item Ref:\n        object: item\n      Location Ref:\n        object: location\n```\n\nThe important parts are:\n\n- `name` at the top names the migration for output and reporting.\n- `source.file` is resolved relative to the YAML file. `source.sheet` selects an XLSX worksheet.\n- Each entry under `objects` runs in the order shown.\n- An object's local `name`, such as `item`, identifies its result so later objects can reference it.\n- `type` is the exact AnyDB type name, such as `Item` or `Inventory Item`.\n- `mode` controls behavior: `lookup` only finds, `upsert` finds then updates or creates, and `create` always creates.\n- In a single-field `match`, `field` is the AnyDB field and `column` is the spreadsheet header. Therefore, `field: SKU` and `column: SKU` compare the AnyDB `SKU` field with the current row's `SKU` cell.\n- Under `fields`, the left side is the AnyDB field and the right side is the spreadsheet header. For example, `Item Name: Name` copies the spreadsheet's `Name` value into AnyDB's `Item Name` field.\n- `{ value: Active }` supplies a fixed literal instead of reading a spreadsheet column.\n- `{ object: item }` uses the AnyDB record ID resolved for the earlier local object named `item` in the same source row.\n- `references` writes those earlier record IDs into AnyDB reference fields. References must point to objects listed earlier in the YAML.\n\nFor each spreadsheet row, this example finds or writes an `Item`, looks up its `Location`, and then finds or writes the `Inventory Item` linking those two records.\n\nEach object has a local `name`, an AnyDB template name in `type`, and one of three modes:\n\n- `lookup`: find a record or fail the row; never writes.\n- `upsert`: update a match or create a missing record.\n- `create`: always create; no match is needed.\n\nFields map as `AnyDB field: Source column`. A `{ value: ... }` mapping supplies a literal. Matches can use one source column or a `fields` map. `{ object: item }` and `references` use the record ID resolved by an earlier object in the same row.\n\nBefore a run, the CLI uses the SDK's type APIs to confirm that every configured type and field exists. It also verifies that fields under `references` are AnyDB reference fields. The fetched type definition supplies real cell positions for writes, so validation and creation no longer depend on an existing record of that type. The optional `template` setting remains available as an explicit template ADOID override; otherwise creation uses the configured type name.\n\n## Commands\n\nValidate YAML, source existence, worksheet selection, modes, matches, unique names, reference order, source columns, and live AnyDB type definitions:\n\n```bash\nanydb-migrate validate migration.yaml\n```\n\n`validate` is authenticated and read-only, so the AnyDB credentials above must be available.\n\nRun the import:\n\n```bash\nanydb-migrate run migration.yaml\nanydb-migrate run migration.yaml --dry-run\nanydb-migrate run migration.yaml --limit 10 --fail-fast --verbose\nanydb-migrate run migration.yaml --requests-per-minute 100\n```\n\nDry runs read the source and perform AnyDB lookups but never call create or update. Row failures are reported and processing continues unless `--fail-fast` is used.\n\nAll API calls share a rate limiter that defaults to 100 requests per minute, leaving headroom below AnyDB's typical 120-request limit. Override it with `--requests-per-minute` or `ANYDB_REQUESTS_PER_MINUTE`. If AnyDB still returns HTTP 429, the CLI honors `Retry-After` when available, waits, and retries up to five times. The wait is displayed in the console.\n\nDuring `run` and `--dry-run`, the CLI prints progress after every 10 completed source rows and once more at completion, for example:\n\n```text\nStarting migration: 100 rows\nProgress: 10/100 rows (10%)\nProgress: 20/100 rows (20%)\n...\nProgress: 100/100 rows (100%)\n```\n\nThe initial AnyDB cache load also reports record discovery and hydration progress for each configured type:\n\n```text\nLoading Item cache: discovering records...\nLoading Item cache: discovered 655 records\nLoading Item cache: 10/655 records (2%)\n...\nLoading Item cache: ready (655 records)\n```\n","readmeFilename":"README.md"}