{"_id":"@business-swift/gst-engine","_rev":"7-34260811d8fc224939f52ae7e0cb2b6a","name":"@business-swift/gst-engine","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.1":{"name":"@business-swift/gst-engine","version":"1.0.1","keywords":["gst","india","tax","invoice","gstin","b2b","b2c","sez","export","typescript"],"author":{"url":"https://businessswift.in","name":"Business Swift","email":"legal@businessswift.in"},"license":"MIT","_id":"@business-swift/gst-engine@1.0.1","maintainers":[{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"}],"homepage":"https://github.com/businessswift/gst-engine#readme","bugs":{"url":"https://github.com/businessswift/gst-engine/issues"},"dist":{"shasum":"7b1017055c0c0328375583f04dc57a094893686c","tarball":"https://registry.npmjs.org/@business-swift/gst-engine/-/gst-engine-1.0.1.tgz","fileCount":34,"integrity":"sha512-/bE8LsEFE6NjmfA7RA178dLrmwMn3Mtmc7RUMEUycZmtF8Zl5XPi013jrDuDNKVj8oUcP6CyA7jw8tQJUE22jA==","signatures":[{"sig":"MEUCIQCrfG+iuZ5OUWzGkQSj7+iyNhddgKgEuL4XM7PoofSEbgIgJQL2GXjsTEjv6uCdu4FAiQ5jXBoXJ6uniThRIbF+y2s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":150754},"jest":{"roots":["<rootDir>/src"],"preset":"ts-jest","testEnvironment":"node"},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/esm/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/index.js"}},"gitHead":"9d8d0741c6eb0137fef043e38e769727e1d8c1e1","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc && tsc -p tsconfig.esm.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},"repository":{"url":"git+https://github.com/businessswift/gst-engine.git","type":"git"},"_npmVersion":"11.6.0","description":"A TypeScript-first GST engine for India — developed by Business Swift, Made in India 🇮🇳.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","ts-jest":"^29.1.4","typescript":"^5.4.5","@types/jest":"^29.5.12","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/gst-engine_1.0.1_1778686665064_0.9794080737426232","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@business-swift/gst-engine","version":"1.0.2","keywords":["gst","india","tax","invoice","gstin","b2b","b2c","sez","export","typescript"],"author":{"url":"https://businessswift.in","name":"Business Swift","email":"legal@businessswift.in"},"license":"MIT","_id":"@business-swift/gst-engine@1.0.2","maintainers":[{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"}],"homepage":"https://github.com/businessswift/gst-engine#readme","bugs":{"url":"https://github.com/businessswift/gst-engine/issues"},"dist":{"shasum":"c7fed90b95c6adf9680d1c261cbc7f49a98561b3","tarball":"https://registry.npmjs.org/@business-swift/gst-engine/-/gst-engine-1.0.2.tgz","fileCount":34,"integrity":"sha512-bTstaA9v6YDOTNhRLLVPJuAl9TQf966OLCgnS7DRIdwt6uuvy2bflij7ozqJpon9wdeb1EJfZJpEhcD5NZrLuQ==","signatures":[{"sig":"MEUCIQDD4OwiWDuVfC497Qu8wlAvLDOgSEG3XyYJ6O18/8MujQIgSnjCUaFE6lVnG1GtBpPCtSQYnFB3NcYfkUm/I0wGACY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":154439},"jest":{"roots":["<rootDir>/src"],"preset":"ts-jest","testEnvironment":"node"},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/esm/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/index.js"}},"gitHead":"fc4a947671fd1c0cf74324889b1f98eefbfa708f","scripts":{"lint":"eslint src --ext .ts","test":"jest","build":"tsc && tsc -p tsconfig.esm.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},"repository":{"url":"git+https://github.com/businessswift/gst-engine.git","type":"git"},"_npmVersion":"11.6.0","description":"A TypeScript-first GST engine for India — developed by Business Swift, Made in India 🇮🇳.","directories":{},"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","ts-jest":"^29.1.4","typescript":"^5.4.5","@types/jest":"^29.5.12","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/gst-engine_1.0.2_1778841998309_0.9981451454877044","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@business-swift/gst-engine","version":"1.1.0","keywords":["gst","hsn","sac","india","tax","invoice","gstin","b2b","b2c","sez","export","typescript"],"author":{"url":"https://businessswift.in","name":"Business Swift","email":"legal@businessswift.in"},"license":"MIT","_id":"@business-swift/gst-engine@1.1.0","maintainers":[{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},{"name":"saumya1209","email":"saumyaparikh129007@gmail.com"}],"homepage":"https://github.com/businessswift/gst-engine#readme","bugs":{"url":"https://github.com/businessswift/gst-engine/issues"},"dist":{"shasum":"7b8088ba5e80e5b4c9ead3b8331dc10767744201","tarball":"https://registry.npmjs.org/@business-swift/gst-engine/-/gst-engine-1.1.0.tgz","fileCount":56,"integrity":"sha512-yj4FBIx8fcCTYUnOPUqMlnhFeCSe6k56O8NkqMTKCsxYyWdIgFGqpIHLIGxERsOrW5Ai/dLOq+B8jdmvnorWyg==","signatures":[{"sig":"MEUCIQDsLzG/uHoSqON3L9O4GQRODltz66qU0DtFV8V464ynMAIgEeT7xQ+1w4Rk/23kCofuVTJfb1zGHCfoynMo3Ou2omU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":18470533},"jest":{"roots":["<rootDir>/src"],"preset":"ts-jest","testEnvironment":"node"},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/esm/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/index.js"}},"gitHead":"5638375bf69f8359247c11d6b6547dcbd40289be","scripts":{"lint":"eslint src --ext .ts","test":"vitest run","build":"tsc && tsc -p tsconfig.esm.json && npm run copy-resources","test:watch":"vitest","test:legacy":"jest","copy-resources":"cp -r src/resources dist/ && cp -r src/resources dist/esm/","prepublishOnly":"npm run build"},"_npmUser":{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},"repository":{"url":"git+https://github.com/businessswift/gst-engine.git","type":"git"},"_npmVersion":"11.6.0","description":"A TypeScript-first GST engine for India — developed and maintained by Business Swift, Made in India 🇮🇳.","directories":{},"sideEffects":false,"_nodeVersion":"22.12.0","dependencies":{"flexsearch":"^0.7.43"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","vitest":"^4.1.8","ts-jest":"^29.1.4","typescript":"^5.4.5","@types/jest":"^29.5.12","@types/node":"^20.12.12"},"_npmOperationalInternal":{"tmp":"tmp/gst-engine_1.1.0_1780399755785_0.7543570307446708","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"_id":"@business-swift/gst-engine@1.2.0","bugs":{"url":"https://github.com/businessswift/gst-engine/issues"},"dist":{"shasum":"5b5cad2f0693ecdfe4ad5a5700312d6a03ef891f","tarball":"https://registry.npmjs.org/@business-swift/gst-engine/-/gst-engine-1.2.0.tgz","fileCount":56,"integrity":"sha512-0Oqf80CcaWht8TeS0jK9sofjnjM+1EplGSovH++yK5uZuPmgE9DRp0KyVoqdm+FEcCdoUJmZ76LJgjV7h/jBwQ==","signatures":[{"sig":"MEYCIQDfHRafw06qb/SgIuJAjlZZmKCPIMTb+vBBrQ8pjQBOTAIhALKVYbPUb2fnUt0vQKkzsuoh8U/1AIrkDq+lKjLBHdZo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBnBDu0YG0ZelCKLRztV+SIbDInsZvfWhwmLqZVXADiDAiAuZug1+2MyDowMtl78osbPkTbibhQ2u4SGoK0LeOPipA=="}],"unpackedSize":18483006},"jest":{"roots":["<rootDir>/src"],"preset":"ts-jest","testEnvironment":"node"},"main":"dist/index.js","name":"@business-swift/gst-engine","types":"dist/index.d.ts","author":{"url":"https://businessswift.in","name":"Business Swift","email":"legal@businessswift.in"},"module":"dist/esm/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/esm/index.js","require":"./dist/index.js"}},"gitHead":"2b5f04fc22513f3626b7b9641b80a07fdf261cb9","license":"MIT","scripts":{"lint":"eslint src --ext .ts","test":"vitest run","build":"tsc && tsc -p tsconfig.esm.json && npm run copy-resources","test:watch":"vitest","test:legacy":"jest","copy-resources":"cp -r src/resources dist/ && cp -r src/resources dist/esm/","prepublishOnly":"npm run build"},"version":"1.2.0","_npmUser":{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},"homepage":"https://github.com/businessswift/gst-engine#readme","keywords":["gst","hsn","sac","india","tax","invoice","gstin","b2b","b2c","sez","export","typescript"],"repository":{"url":"git+https://github.com/businessswift/gst-engine.git","type":"git"},"_npmVersion":"10.9.4","description":"A TypeScript-first GST engine for India — developed and maintained by Business Swift, Made in India 🇮🇳.","directories":{},"maintainers":[{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},{"name":"saumya1209","email":"saumyaparikh129007@gmail.com"}],"sideEffects":false,"_nodeVersion":"22.22.1","dependencies":{"flexsearch":"^0.7.43"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","vitest":"^4.1.8","ts-jest":"^29.1.4","typescript":"^5.4.5","@types/jest":"^29.5.12","@types/node":"^20.12.12"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gst-engine_1.2.0_1789746872522_0.6151054172556829"}}},"time":{"created":"2026-05-13T15:37:44.972Z","modified":"2026-09-18T15:54:32.868Z","1.0.0":"2026-05-13T15:04:24.067Z","1.0.1":"2026-05-13T15:37:45.289Z","1.0.2":"2026-05-15T10:46:38.492Z","1.1.0":"2026-06-02T11:29:15.974Z","1.2.0":"2026-09-18T15:54:32.645Z"},"bugs":{"url":"https://github.com/businessswift/gst-engine/issues"},"author":{"url":"https://businessswift.in","name":"Business Swift","email":"legal@businessswift.in"},"license":"MIT","homepage":"https://github.com/businessswift/gst-engine#readme","keywords":["gst","hsn","sac","india","tax","invoice","gstin","b2b","b2c","sez","export","typescript"],"repository":{"url":"git+https://github.com/businessswift/gst-engine.git","type":"git"},"description":"A TypeScript-first GST engine for India — developed and maintained by Business Swift, Made in India 🇮🇳.","maintainers":[{"name":"aman.kishore32","email":"aman.kishore32@gmail.com"},{"name":"business-swift-tech","email":"businessswift.aman@gmail.com"},{"name":"saumya1209","email":"saumyaparikh129007@gmail.com"}],"readme":"# @business-swift/gst-engine\n\n> A TypeScript-first GST (Goods & Services Tax) engine for India 🇮🇳.\n\nDetermines transaction category, supply type, applicable tax heads, e-invoice applicability, and e-way bill requirement for any supplier–customer pair — automatically resolving Place of Supply from **billing and shipping addresses**.\n\n[![npm version](https://badge.fury.io/js/@business-swift%2Fgst-engine.svg)](https://badge.fury.io/js/@business-swift%2Fgst-engine)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![Made in India](https://img.shields.io/badge/Made%20in-India%20🇮🇳-orange.svg)](https://businessswift.in)\n\n---\n\n> **Developed by [Business Swift](https://businessswift.in)** — open-sourced as part of their broader vision to give back to society and push India forward in the field of technology.\n>\n> _\"We believe that great developer tooling should be freely available to every developer, startup, and researcher. gst-engine is our contribution to that belief.\"_\n\n---\n\n## Features\n\n- ✅ Full **GST Category** classification: B2B, B2C Small/Large, SEZ, Export, Deemed Export, Nil, Exempt, Non-GST\n- ✅ Separate **billing and shipping address** inputs — Place of Supply resolved automatically\n- ✅ **Bill-to / Ship-to** (triangular transaction) auto-detection\n- ✅ **Goods vs Services** rule: shipping drives PoS for goods, billing for services\n- ✅ **Inter-state vs Intra-state** from GSTIN or `address.stateCode` (GSTIN optional for supplier)\n- ✅ **IGST / CGST+SGST / None** tax head determination\n- ✅ **Overseas export** detection from address `countryCode`\n- ✅ **GSTIN validation** (format + checksum)\n- ✅ **Tax computation** with CGST, SGST, IGST, and Cess breakdown\n- ✅ **E-invoice** applicability (₹5 Cr turnover threshold)\n- ✅ **E-way bill** requirement check (₹50,000 goods threshold)\n- ✅ Human-readable **rationale** for every decision (audit trails / UI tooltips)\n- ✅ Zero runtime dependencies\n- ✅ Full TypeScript types + JavaScript compatible\n\n---\n\n## Installation\n\n```bash\nnpm install @business-swift/gst-engine\n# or\nyarn add @business-swift/gst-engine\n```\n\n---\n\n## Quick Start\n\n```typescript\nimport { getGSTTreatment } from \"@business-swift/gst-engine\";\n\nconst result = getGSTTreatment({\n  supplier: {\n    gstin: \"27AAAPL1234C1Z5\", // Maharashtra\n  },\n  customer: {\n    gstin: \"29BBBPL5678D1Z3\", // Karnataka\n    billingAddress: { stateCode: \"29\", city: \"Bengaluru\", countryCode: \"IN\" },\n    shippingAddress: { stateCode: \"29\", city: \"Bengaluru\", countryCode: \"IN\" },\n  },\n  invoice: { taxableValue: 100_000 },\n});\n\nconsole.log(result.category); // \"B2B\"\nconsole.log(result.supplyType); // \"INTER_STATE\"\nconsole.log(result.taxType); // \"IGST\"\nconsole.log(result.placeOfSupplyStateCode); // \"29\"\nconsole.log(result.placeOfSupplySource); // \"shipping\"\nconsole.log(result.isBillToShipTo); // false\nconsole.log(result.rationale); // \"B2B supply to registered taxpayer…\"\n```\n\n---\n\n## How Billing & Shipping Drive Taxation\n\nThe engine follows the GST Place of Supply (PoS) rules automatically:\n\n| Supply type                    | `isGoods` | Place of Supply used                                     |\n| ------------------------------ | --------- | -------------------------------------------------------- |\n| Goods                          | `true`    | **Shipping address** state                               |\n| Services                       | `false`   | **Billing address** state                                |\n| Services (registered customer) | `false`   | **GSTIN-embedded state** (priority over billing address) |\n\nThe PoS state code is then compared to the **supplier's GSTIN state** to determine inter-state vs intra-state — and therefore IGST vs CGST+SGST.\n\n### Bill-to / Ship-to (Triangular Transactions)\n\nWhen `billingAddress.stateCode ≠ shippingAddress.stateCode`, the engine automatically sets `isBillToShipTo: true` and applies the correct PoS rule (shipping for goods, billing for services). No extra configuration needed.\n\n### Overseas / Export Detection\n\nIf `billingAddress.countryCode` or `shippingAddress.countryCode` is any value other than `\"IN\"`, the supply is treated as an **export** — regardless of any GSTIN or registration type.\n\n---\n\n## API Reference\n\n### `getGSTTreatment(input, options?)`\n\n#### `GSTTreatmentInput`\n\n| Field              | Type           | Required | Description                                    |\n| ------------------ | -------------- | -------- | ---------------------------------------------- |\n| `supplier`         | `SupplierInfo` | ✅       | Supplier GSTIN + optional address              |\n| `customer`         | `CustomerInfo` | ✅       | Customer with billing & shipping addresses     |\n| `invoice`          | `InvoiceValue` | ✅       | Taxable value                                  |\n| `supplyNature`     | `SupplyNature` | ❌       | Default: `TAXABLE`                             |\n| `withPaymentOfTax` | `boolean`      | ❌       | SEZ/Export: pay IGST upfront? Default: `false` |\n\n---\n\n#### `SupplierInfo`\n\n| Field              | Type               | Required | Description                                                                                   |\n| ------------------ | ------------------ | -------- | --------------------------------------------------------------------------------------------- |\n| `gstin`            | `string?`          | ❌       | 15-char GSTIN. State code auto-extracted. Optional — see `address.stateCode` below.           |\n| `registrationType` | `RegistrationType` | ❌       | Defaults to `REGULAR`                                                                         |\n| `address`          | `Address`          | ⚠️       | `address.stateCode` is **required when `gstin` is absent** so inter/intra-state can be determined. |\n\n> **Rule:** provide either `gstin` **or** `address.stateCode` (or both). The engine throws at runtime if neither is present.\n\n---\n\n#### `CustomerInfo`\n\n| Field                    | Type                | Description                                                                |\n| ------------------------ | ------------------- | -------------------------------------------------------------------------- |\n| `gstin`                  | `string?`           | Present → B2B. Absent → B2C.                                               |\n| `registrationType`       | `RegistrationType?` | Must be set for `SEZ_UNIT`, `SEZ_DEVELOPER`, `DEEMED_EXPORTER`, `OVERSEAS` |\n| `billingAddress`         | `Address`           | **Required.** PoS for services.                                            |\n| `shippingAddress`        | `Address?`          | PoS for goods. Falls back to `billingAddress` if omitted.                  |\n| `placeOfSupplyStateCode` | `string?`           | Hard override for PoS state. Wins over all address logic.                  |\n\n---\n\n#### `Address`\n\n| Field         | Type      | Description                                                           |\n| ------------- | --------- | --------------------------------------------------------------------- |\n| `line1`       | `string?` | Street / building                                                     |\n| `line2`       | `string?` | Area / locality                                                       |\n| `city`        | `string?` | City or town                                                          |\n| `stateCode`   | `string?` | 2-digit Indian state code (e.g. `\"27\"` for Maharashtra)               |\n| `pincode`     | `string?` | 6-digit PIN code                                                      |\n| `countryCode` | `string?` | ISO 3166-1 alpha-2. Defaults to `\"IN\"`. Non-`\"IN\"` → overseas/export. |\n\n---\n\n#### `GSTEngineOptions`\n\n| Field                | Type       | Description                                                        |\n| -------------------- | ---------- | ------------------------------------------------------------------ |\n| `supplierTurnoverCr` | `number?`  | Annual turnover in ₹ crores for e-invoice check (threshold: ₹5 Cr) |\n| `isGoods`            | `boolean?` | `true` (default) = goods; `false` = services                       |\n\n---\n\n#### `GSTTreatmentResult`\n\n| Field                    | Type                                                         | Description                    |\n| ------------------------ | ------------------------------------------------------------ | ------------------------------ |\n| `category`               | `GSTCategory`                                                | GST filing category            |\n| `supplyType`             | `SupplyType`                                                 | `INTER_STATE` or `INTRA_STATE` |\n| `taxType`                | `TaxType`                                                    | `IGST`, `CGST_SGST`, or `NONE` |\n| `placeOfSupplyStateCode` | `string \\| undefined`                                        | Resolved PoS state code        |\n| `placeOfSupplySource`    | `\"billing\" \\| \"shipping\" \\| \"gstin\" \\| \"override\" \\| \"none\"` | What determined the PoS        |\n| `isBillToShipTo`         | `boolean`                                                    | Billing state ≠ shipping state |\n| `rationale`              | `string`                                                     | Human-readable explanation     |\n| `eInvoiceApplicable`     | `boolean`                                                    | Is IRN generation mandatory?   |\n| `eWayBillRequired`       | `boolean`                                                    | Is e-way bill required?        |\n| `supplierGstin`          | `string \\| undefined`                                        | Normalised supplier GSTIN      |\n| `customerGstin`          | `string \\| undefined`                                        | Normalised customer GSTIN      |\n\n---\n\n## Enums\n\n### `GSTCategory`\n\n| Value                    | Description                                                 |\n| ------------------------ | ----------------------------------------------------------- |\n| `B2B`                    | Supply to a registered taxpayer                             |\n| `B2C_SMALL`              | Unregistered customer — intra-state, or inter-state ≤ ₹2.5L |\n| `B2C_LARGE`              | Inter-state, unregistered, > ₹2.5L (invoice-wise GSTR-1)    |\n| `SEZ_WITH_PAYMENT`       | SEZ supply with IGST                                        |\n| `SEZ_WITHOUT_PAYMENT`    | SEZ supply zero-rated under LUT                             |\n| `EXPORT_WITH_PAYMENT`    | Export with IGST payment                                    |\n| `EXPORT_WITHOUT_PAYMENT` | Export zero-rated under LUT                                 |\n| `DEEMED_EXPORT`          | Supply to EOU/EPCG/AA holder                                |\n| `NIL_RATED`              | 0% GST by law                                               |\n| `EXEMPTED`               | Exempt from GST                                             |\n| `NON_GST`                | Outside GST scope (petroleum, alcohol, etc.)                |\n| `UNREGISTERED_SUPPLIER`  | Supplier has no GSTIN — cannot collect GST (no tax)         |\n| `COMPOSITION`            | Composition-scheme supplier — bill of supply (no tax)       |\n\n### `RegistrationType`\n\n| Value             | Description                  |\n| ----------------- | ---------------------------- |\n| `REGULAR`         | Regular GST taxpayer         |\n| `COMPOSITION`     | Composition scheme           |\n| `UNREGISTERED`    | No GST registration          |\n| `SEZ_UNIT`        | SEZ unit                     |\n| `SEZ_DEVELOPER`   | SEZ developer                |\n| `DEEMED_EXPORTER` | EOU / EPCG / AA holder       |\n| `OVERSEAS`        | Foreign / export customer    |\n| `UIN`             | Unique Identification Number |\n\n---\n\n## Examples\n\n### Standard B2B — goods, inter-state, bill-to/ship-to\n\n```typescript\nimport { getGSTTreatment } from \"@business-swift/gst-engine\";\n\n// Supplier in Maharashtra; customer billed in Karnataka but goods ship to Gujarat\nconst result = getGSTTreatment(\n  {\n    supplier: { gstin: \"27AAAPL1234C1Z5\" },\n    customer: {\n      gstin: \"29BBBPL5678D1Z3\",\n      billingAddress: { stateCode: \"29\", city: \"Bengaluru\", countryCode: \"IN\" },\n      shippingAddress: { stateCode: \"24\", city: \"Surat\", countryCode: \"IN\" },\n    },\n    invoice: { taxableValue: 80_000 },\n  },\n  { isGoods: true },\n);\n\n// category:               \"B2B\"\n// supplyType:             \"INTER_STATE\"  (supplier=27, PoS=24)\n// taxType:                \"IGST\"\n// placeOfSupplyStateCode: \"24\"           (Gujarat — shipping address)\n// placeOfSupplySource:    \"shipping\"\n// isBillToShipTo:         true           (KA billing ≠ GJ shipping)\n// eWayBillRequired:       true           (goods > ₹50,000)\n```\n\n### Services — PoS from customer GSTIN\n\n```typescript\nimport { getGSTTreatment } from \"@business-swift/gst-engine\";\n\n// Supplier MH, Customer has KA GSTIN, but billing/shipping addresses are both MH\nconst result = getGSTTreatment(\n  {\n    supplier: { gstin: \"27AAAPL1234C1Z5\" },\n    customer: {\n      gstin: \"29BBBPL5678D1Z3\", // KA\n      billingAddress: { stateCode: \"27\" }, // MH (ignored for services with GSTIN)\n      shippingAddress: { stateCode: \"27\" }, // MH (ignored for services)\n    },\n    invoice: { taxableValue: 50_000 },\n  },\n  { isGoods: false }, // ← services\n);\n\n// placeOfSupplySource: \"gstin\"   (KA from customer GSTIN)\n// supplyType:          \"INTER_STATE\"\n// taxType:             \"IGST\"\n```\n\n### Export — overseas shipping address\n\n```typescript\nconst result = getGSTTreatment({\n  supplier: { gstin: \"27AAAPL1234C1Z5\" },\n  customer: {\n    billingAddress: { stateCode: \"27\", countryCode: \"IN\" }, // domestic billing\n    shippingAddress: { city: \"Dubai\", countryCode: \"AE\" }, // overseas delivery\n  },\n  invoice: { taxableValue: 500_000 },\n  withPaymentOfTax: false,\n});\n// category: \"EXPORT_WITHOUT_PAYMENT\"\n// taxType:  \"NONE\"\n// eInvoiceApplicable: false\n```\n\n### Supplier without GSTIN — `address.stateCode` as fallback\n\nWhen the supplier's GSTIN is not available (e.g. composition dealer or pre-registration scenario), pass `address.stateCode` instead:\n\n```typescript\nimport { getGSTTreatment } from \"@business-swift/gst-engine\";\n\n// Supplier in Maharashtra (no GSTIN), customer in Karnataka\nconst result = getGSTTreatment({\n  supplier: {\n    address: { stateCode: \"27\" }, // ← required when gstin is absent\n  },\n  customer: {\n    gstin: \"29BBBPL5678D1Z3\",\n    billingAddress: { stateCode: \"29\", city: \"Bengaluru\", countryCode: \"IN\" },\n  },\n  invoice: { taxableValue: 80_000 },\n});\n// category:       \"B2B\"\n// supplyType:     \"INTER_STATE\"  (MH supplier ≠ KA customer)\n// taxType:        \"IGST\"\n// supplierGstin:  undefined      (none was provided)\n```\n\n> Omitting both `gstin` and `address.stateCode` throws:\n> `SupplierInfo: 'address.stateCode' is required when 'gstin' is not provided.`\n\n---\n\n### SEZ — zero-rated (LUT), with e-invoice\n\n```typescript\nimport { getGSTTreatment, RegistrationType } from \"@business-swift/gst-engine\";\n\nconst result = getGSTTreatment(\n  {\n    supplier: { gstin: \"27AAAPL1234C1Z5\" },\n    customer: {\n      gstin: \"24DDDPL3456F1Z6\",\n      registrationType: RegistrationType.SEZ_UNIT,\n      billingAddress: { stateCode: \"24\", countryCode: \"IN\" },\n      shippingAddress: { stateCode: \"24\", countryCode: \"IN\" },\n    },\n    invoice: { taxableValue: 200_000 },\n    withPaymentOfTax: false,\n  },\n  { supplierTurnoverCr: 10 }, // ≥ ₹5 Cr → e-invoice required\n);\n// category:            \"SEZ_WITHOUT_PAYMENT\"\n// taxType:             \"NONE\"\n// eInvoiceApplicable:  true\n```\n\n### Intra-state B2C — CGST + SGST\n\n```typescript\nconst result = getGSTTreatment({\n  supplier: { gstin: \"27AAAPL1234C1Z5\" },\n  customer: {\n    // No GSTIN → unregistered\n    billingAddress: { stateCode: \"27\", city: \"Pune\", countryCode: \"IN\" },\n  },\n  invoice: { taxableValue: 15_000 },\n});\n// category:   \"B2C_SMALL\"\n// supplyType: \"INTRA_STATE\"\n// taxType:    \"CGST_SGST\"\n```\n\n---\n\n## Tax Computation\n\n```typescript\nimport { computeTax, TaxType } from \"@business-swift/gst-engine\";\n\n// IGST @ 18%\nconst t = computeTax(100_000, 18, TaxType.IGST);\n// { taxableValue: 100000, igst: 18000, cgst: 0, sgst: 0,\n//   cess: 0, totalTax: 18000, grandTotal: 118000 }\n\n// CGST + SGST @ 18%\nconst t2 = computeTax(100_000, 18, TaxType.CGST_SGST);\n// { cgst: 9000, sgst: 9000, igst: 0, totalTax: 18000, grandTotal: 118000 }\n\n// 28% + 22% Cess (luxury vehicles)\nconst t3 = computeTax(100_000, 28, TaxType.IGST, 22);\n// { igst: 28000, cess: 22000, totalTax: 50000, grandTotal: 150000 }\n```\n\n---\n\n## GSTIN Utilities\n\n```typescript\nimport { isValidGSTIN, getStateCodeFromGSTIN, getStateName } from \"@business-swift/gst-engine\";\n\nisValidGSTIN(\"29AABCU9603R1ZP\"); // true/false (format + checksum)\ngetStateCodeFromGSTIN(\"27AAAPL1234C1Z5\"); // \"27\"\ngetStateName(\"27\"); // \"Maharashtra\"\ngetStateName(\"29\"); // \"Karnataka\"\ngetStateName(\"07\"); // \"Delhi\"\n```\n\n---\n\n## When the Supplier Cannot Charge GST\n\nTwo supplier states make the invoice untaxable regardless of anything else —\ncustomer type, states involved, invoice value, or export status:\n\n| Supplier state                             | Category                | Tax    |\n| ------------------------------------------ | ----------------------- | ------ |\n| No `gstin`                                 | `UNREGISTERED_SUPPLIER` | `NONE` |\n| `registrationType: COMPOSITION`            | `COMPOSITION`           | `NONE` |\n\nOnly a registered person may collect GST (CGST s.32(1)), and a composition\ntaxpayer pays out of pocket and issues a **bill of supply**, not a tax invoice\n(CGST s.10(4)). In both cases `taxType` is `NONE`, so any rate passed to\n`computeTax` yields zero:\n\n```typescript\nconst treatment = getGSTTreatment({\n  supplier: { address: { stateCode: \"27\" } }, // no GSTIN\n  customer: { gstin: \"29BBBPL5678D1Z3\", billingAddress: { stateCode: \"29\" } },\n  invoice: { taxableValue: 100000 },\n});\n\ntreatment.category; // \"UNREGISTERED_SUPPLIER\"\ntreatment.taxType;  // \"NONE\"\n\n// Even at an 18% slab, every head is zero:\ncomputeTax(100000, 18, treatment.taxType);\n// → { cgst: 0, sgst: 0, igst: 0, cess: 0, totalTax: 0, grandTotal: 100000 }\n```\n\nPlace of supply and `supplyType` are still resolved — they drive GSTR-1\nreporting and the e-way bill, which apply even when no tax does.\n\n> **Note:** `NIL_RATED`, `EXEMPTED` and `NON_GST` supply natures keep their own\n> category. They are equally untaxed and describe the supply itself, which is\n> the more specific answer.\n\n---\n\n## Full Decision Tree\n\n```\nGSTTreatmentInput\n       │\n       ├─ supplyNature = NON_GST          → NON_GST        (no tax)\n       ├─ supplyNature = NIL_RATED        → NIL_RATED       (no tax)\n       ├─ supplyNature = EXEMPTED         → EXEMPTED        (no tax)\n       │\n       ├─ supplier has NO GSTIN?          → UNREGISTERED_SUPPLIER (no tax)\n       ├─ supplier is COMPOSITION?        → COMPOSITION           (no tax)\n       │    Both short-circuit every branch below — an unregistered or\n       │    composition supplier charges no tax on any supply.\n       │\n       ├─ customer overseas?              ──────────────────────────────┐\n       │    (countryCode ≠ \"IN\" on         withPaymentOfTax=true  → EXPORT_WITH_PAYMENT  (IGST)\n       │     billing OR shipping)          withPaymentOfTax=false → EXPORT_WITHOUT_PAYMENT (none)\n       │\n       ├─ registrationType = SEZ_*        ──────────────────────────────┐\n       │                                   withPaymentOfTax=true  → SEZ_WITH_PAYMENT    (IGST)\n       │                                   withPaymentOfTax=false → SEZ_WITHOUT_PAYMENT (none)\n       │                                   Always INTER_STATE\n       │\n       ├─ registrationType = DEEMED_EXPORTER → DEEMED_EXPORT (IGST, INTER_STATE)\n       │\n       ├─ Resolve Place of Supply ─────────────────────────────────────────────\n       │    isGoods=true   → shippingAddress.stateCode\n       │    isGoods=false  → customer GSTIN state (if registered), else billingAddress.stateCode\n       │    placeOfSupplyStateCode set → use override (wins all)\n       │\n       │    supplierState == posState → INTRA_STATE → CGST+SGST\n       │    supplierState != posState → INTER_STATE → IGST\n       │\n       ├─ customer registered (GSTIN)?\n       │    yes → B2B\n       │\n       └─ customer unregistered\n            INTER_STATE + value > ₹2,50,000 → B2C_LARGE\n            otherwise                       → B2C_SMALL\n```\n\n---\n\n## Legal Disclaimer\n\nThis package is provided for informational and development purposes only. GST rules, thresholds, and notifications are subject to change by the Government of India. Always consult a qualified CA or tax advisor and refer to the official [GSTN portal](https://www.gst.gov.in) for compliance decisions.\n\n---\n\n## About Business Swift\n\n**gst-engine** has been developed by **Business Swift** as part of their internal project, and has been open-sourced as part of their broader and longer vision to give back to society and push **India forward in the field of technology**.\n\nBusiness Swift believes that foundational developer tools — especially those tied to India's tax and compliance infrastructure — should be freely available to every Indian developer, startup, researcher, and student.\n\n---\n\n---\n\n## HSN / SAC Search Engine\n\n`@business-swift/gst-engine` includes a fully client-side, FlexSearch-powered HSN & SAC code lookup engine. It lazy-loads ~25,000 records on first use and provides sub-10ms typeahead in the browser.\n\n### Installation\n\n```bash\nnpm install @business-swift/gst-engine\n```\n\n### Quick start\n\n```typescript\nimport { hydrate, search, getByCode, parseCode } from \"@business-swift/gst-engine\";\n\n// Call once (e.g. on search-bar focus) — subsequent calls are instant\nawait hydrate();\n\n// Typeahead — returns up to 10 matches\nconst results = await search(\"laptop\");\nconsole.log(results[0]);\n// {\n//   code: \"8471\",\n//   type: \"HSN\",\n//   name: \"AUTOMATIC DATA PROCESSING MACHINES AND UNITS THEREOF\",\n//   currentRate: \"18%\",\n//   rates: [{ pct: \"18\", desc: \"...\", from: \"01/07/2017\", isCurrent: true }],\n//   chapter: { number: \"84\", name: \"Nuclear reactors, boilers, machinery...\" },\n//   seo: { slug: \"chapter-84-...\", metaTitle: \"GST Rate & HSN Code for...\", ... },\n//   matchedOn: \"keywords\",\n//   updatedAt: \"2025-08-19T16:17:32.749\"\n// }\n\n// Exact lookup\nconst item = await getByCode(\"8471\");\n\n// Parse a code into its hierarchy\nconst h = parseCode(\"84713010\");\n// { level: 4, chapter: \"84\", heading: \"8471\", subheading: \"847130\", tariff: \"84713010\" }\n```\n\n### Search options\n\n```typescript\n// Filter by type\nconst sacResults = await search(\"software\", { type: \"SAC\" });\n\n// Filter by chapter\nconst oils = await search(\"oil\", { chapter: \"15\", limit: 20 });\n\n// Custom limit (max 50)\nconst top5 = await search(\"motor\", { limit: 5 });\n```\n\n### Synchronous SEO helpers\n\nThese work without calling `hydrate()` and load only the 98-chapter metadata file (~20 KB):\n\n```typescript\nimport { getChapterSeo, getChapterName } from \"@business-swift/gst-engine\";\n\nconst seo = getChapterSeo(\"84\");\n// { name: \"Nuclear reactors...\", slug: \"chapter-84-...\", metaTitle: \"...\", metaDescription: \"...\" }\n\nconst name = getChapterName(\"01\");\n// \"Live Animals; Animal products\"\n```\n\n### Next.js integration example\n\n```tsx\n// app/hsn-sac/page.tsx\n\"use client\";\nimport { useState, useCallback } from \"react\";\nimport { hydrate, search, SearchResult } from \"@business-swift/gst-engine\";\n\nlet hydrated = false;\n\nexport default function HsnSearchPage() {\n  const [results, setResults] = useState<SearchResult[]>([]);\n\n  const handleFocus = useCallback(async () => {\n    if (!hydrated) {\n      await hydrate();\n      hydrated = true;\n    }\n  }, []);\n\n  const handleChange = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {\n    const q = e.target.value.trim();\n    if (q.length < 2) { setResults([]); return; }\n    setResults(await search(q, { limit: 10 }));\n  }, []);\n\n  return (\n    <div>\n      <input onFocus={handleFocus} onChange={handleChange} placeholder=\"Search HSN / SAC code…\" />\n      <ul>\n        {results.map((r) => (\n          <li key={r.code}>\n            <a href={`/hsn-sac/${r.code}`}>\n              <strong>{r.code}</strong> — {r.name} <em>({r.currentRate})</em>\n            </a>\n          </li>\n        ))}\n      </ul>\n    </div>\n  );\n}\n```\n\n### HSN API reference\n\n| Function | Signature | Description |\n|---|---|---|\n| `hydrate` | `() => Promise<void>` | Lazy-loads index. Idempotent, concurrent-safe. |\n| `search` | `(query, opts?) => Promise<SearchResult[]>` | Full-text typeahead. |\n| `getByCode` | `(code) => Promise<SearchResult \\| null>` | Exact code lookup. |\n| `parseCode` | `(code) => CodeHierarchy` | Parses code into chapter/heading/subheading/tariff. |\n| `getChapterSeo` | `(ch) => ChapterSeo \\| null` | SEO metadata for a chapter. Synchronous. |\n| `getChapterName` | `(ch) => string \\| null` | Chapter name. Synchronous. |\n\n#### `SearchOptions`\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `limit` | `number` | `10` | Max results (capped at 50). |\n| `type` | `\"HSN\" \\| \"SAC\"` | — | Filter by code type. |\n| `chapter` | `string` | — | 2-digit chapter filter, e.g. `\"15\"`. |\n\n#### `SearchResult`\n\n| Field | Type | Description |\n|---|---|---|\n| `code` | `string` | HSN / SAC code. |\n| `type` | `\"HSN\" \\| \"SAC\"` | Derived: ch `\"99\"` → SAC. |\n| `name` | `string` | Short product name. |\n| `currentRate` | `string` | Latest effective GST rate, e.g. `\"18%\"`. |\n| `rates` | `Rate[]` | All historical + current rates, newest-first. |\n| `chapter.number` | `string` | 2-digit chapter. |\n| `chapter.name` | `string` | Chapter name. |\n| `seo` | `ChapterSeo` | Chapter SEO metadata for detail pages. |\n| `matchedOn` | `\"code\" \\| \"name\" \\| \"keywords\" \\| \"description\"` | Which field produced the hit. |\n| `updatedAt` | `string` | ISO date of last data update. |\n\n---\n\n## License\n\n**MIT License** — Copyright (c) 2026 Business Swift. Made in India 🇮🇳\n\n|     |                                                      |\n| --- | ---------------------------------------------------- |\n| ✅  | Use freely in any project — commercial or personal   |\n| ✅  | Modify and build upon it                             |\n| ✅  | Integrate into SaaS, apps, internal tooling          |\n| ✅  | Distribute as part of a larger work                  |\n| ❌  | Directly resell this package as a standalone product |\n\nSee the full [LICENSE](./LICENSE) file for complete terms.\n\n---\n\n_Developed by Business Swift | Made in India 🇮🇳_\n","readmeFilename":"README.md"}