{"_id":"@truto/sqlite-builder","_rev":"37-1c71e7d76eda80c582e001f6566d6a61","name":"@truto/sqlite-builder","dist-tags":{"latest":"2.0.1"},"versions":{"1.0.0":{"name":"@truto/sqlite-builder","version":"1.0.0","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":"Truto <eng@truto.com>","license":"MIT","_id":"@truto/sqlite-builder@1.0.0","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/truto/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/truto/truto-sqlite-builder/issues"},"dist":{"shasum":"3974ab5e743d5c2477c85265882c32ffe9668e03","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-1.0.0.tgz","fileCount":11,"integrity":"sha512-vBYKcR2PcLSvOmVVTFxCyCE75SsGHMEP2ZSkdFA/r7uSrxsHPWRNqPQ9dOBaKQB9VxgyS6emJOoKD3Q5DUlLVA==","signatures":[{"sig":"MEYCIQDdND7Nyb0GOUYvEipHPaZzjTfGLRftjDAHANs7lF2EMQIhAN+3C/9PTjm9oIUz9v0q8AhYs8ELSgnXaSKT4rY5bnYN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":47426},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","shasum":"3974ab5e743d5c2477c85265882c32ffe9668e03","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","actor":{"name":"truto","type":"user","email":"eng@truto.one"},"email":"eng@truto.one"},"_integrity":"sha512-vBYKcR2PcLSvOmVVTFxCyCE75SsGHMEP2ZSkdFA/r7uSrxsHPWRNqPQ9dOBaKQB9VxgyS6emJOoKD3Q5DUlLVA==","repository":{"url":"https://github.com/truto/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.8.3","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"22.6.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_1.0.0_1750491370785_0.8065832983674548","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@truto/sqlite-builder","version":"1.0.1","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":{"name":"Truto","email":"eng@truto.com"},"license":"MIT","_id":"@truto/sqlite-builder@1.0.1","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/truto/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/truto/truto-sqlite-builder/issues"},"dist":{"shasum":"e35e9b17dcc2f21470389af0b8225b03ea59120b","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-1.0.1.tgz","fileCount":11,"integrity":"sha512-GetGGta6X0YJ6az92gmmhhYQrN7hg386tcbVmis5I31UI0rV/5XkdtgsgW5d9GNt4NIRZQmmEyM/Hs3ZfCBc7w==","signatures":[{"sig":"MEYCIQDrzA4/hGpzoeqi0Lqbp3JB0JIRJZYcP0nCrv9pttBbWAIhALiFmh4GTMxrkPnfyZVJgYfIdsdvUs7glckZSH6xxB/a","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37285},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2d56c6aedacc0d204bd68ef55aca36fb47baa266","scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","actor":{"name":"truto","type":"user","email":"eng@truto.one"},"email":"eng@truto.one"},"repository":{"url":"git+https://github.com/truto/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.8.2","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"20.19.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_1.0.1_1750493719730_0.33767977022895623","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@truto/sqlite-builder","version":"1.0.2","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":{"name":"Truto","email":"eng@truto.com"},"license":"MIT","_id":"@truto/sqlite-builder@1.0.2","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/truto/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/truto/truto-sqlite-builder/issues"},"dist":{"shasum":"2b9f1547a32d8f9ba2fa38edc6d68483239c0639","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-1.0.2.tgz","fileCount":13,"integrity":"sha512-dC9T+Jm7o9Lp6rBFjkDiaunwyziZWSJy0LGSeV05ZoGY/sj13+CkyCUsg7JGiOMwxLR4tJqtSV68h7d7wPMrNg==","signatures":[{"sig":"MEUCIQDqcT9zY99NVf8reiR8uosPgaj4Uvb7hSFtfY4fFy3d6wIgE0An5Fz/almPogv6MI0zzRqoMoD58Ms3w4+YhCfZ0mw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":73777},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ef1310ef1f04e0e27e0fc2ca58a6c0d3e88f6c44","scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","actor":{"name":"truto","type":"user","email":"eng@truto.one"},"email":"eng@truto.one"},"repository":{"url":"git+https://github.com/truto/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.8.2","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"20.19.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_1.0.2_1750676791161_0.0042227190009827","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@truto/sqlite-builder","version":"1.0.3","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":{"name":"Truto","email":"eng@truto.one"},"license":"MIT","_id":"@truto/sqlite-builder@1.0.3","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/trutohq/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/trutohq/truto-sqlite-builder/issues"},"dist":{"shasum":"edacbc87d83e77075705bb2e3d8f676c556703b5","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-1.0.3.tgz","fileCount":13,"integrity":"sha512-mt2iI2D/tULXDS+YjhP0oENihfamrI3iUTafBjHWVDIkmDCEiiXsUfbPVtliF4UAZKWPi8tK6uH/9u3Z4mulPw==","signatures":[{"sig":"MEQCIA0ULnIF8aHyJlNTT92hlYs8RdB8KL+TW8Ogc5VsZPNqAiArLn5tX2Ddf/yQpsuVm1ZWCy3iTMGtTMaJm5jycEMDQA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75741},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"83532ecdea668524ffaf7077fb2527000e35c115","scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","actor":{"name":"truto","type":"user","email":"eng@truto.one"},"email":"eng@truto.one"},"repository":{"url":"git+https://github.com/trutohq/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.8.2","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"20.19.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_1.0.3_1750687855707_0.31903835885526277","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@truto/sqlite-builder","version":"1.0.4","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":{"name":"Truto","email":"eng@truto.one"},"license":"MIT","_id":"@truto/sqlite-builder@1.0.4","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/trutohq/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/trutohq/truto-sqlite-builder/issues"},"dist":{"shasum":"41279c854567d698ff040f871035f9888bc9857c","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-1.0.4.tgz","fileCount":15,"integrity":"sha512-EcvmzX34tQA5CBxC6pSnXVLVxRfFthAuyTncR4sAtKSdFq5ES98ga4uD415+S6/P2dQ2soiO1q0C3KcocWTRww==","signatures":[{"sig":"MEUCIFaynKkWP9vcUyb9NpgOVeInInjecyX9Hnp+pLNaCpbiAiEApPsPdJY1gO8l+GhwLDRJQzy+7emiEHvwlt9/ngB9QUY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83835},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e98d6c5530f96f0a4a192729743c4981ea0dfd16","scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","actor":{"name":"truto","type":"user","email":"eng@truto.one"},"email":"eng@truto.one"},"repository":{"url":"git+https://github.com/trutohq/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.8.2","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"20.19.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_1.0.4_1750693567271_0.7366717290766176","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.0":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.0","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.0","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"5e40d323f5a44ca66bcf7b0303b00b4603d02df2","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.0.tgz","fileCount":2,"integrity":"sha512-Sck6ISKaHvZK2ep3YO9v7yV1aAyFcJ0hlcy7IVVbxW6HJzWPrspWlhNcpt4KBnuC5AvbRKSjn8E0wESZ4f9bAg==","signatures":[{"sig":"MEYCIQDS7io84oQ8y/DEWfsefaLgJ5cIP2r6UY8GSYXeeEjq2wIhAO3k29OhMC3P08BqFLirlISiilX3EdeuCPz+xDroCFDN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.0_1781182041566_0.38653907154942924","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.3":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.3","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.3","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"c5f52ad7970bb22cfcbda2f03d9200f18488c2ac","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.3.tgz","fileCount":15,"integrity":"sha512-eb2XLyWhG/NJaWuyzaz98ytnMoHCyH5pUuPs0Mi34QTENu49w24DCMk/GqNZTAS2N9o7YbOCP2u6GD0Lp1zIBQ==","signatures":[{"sig":"MEQCIGbS9l0ckjX+mw4evngGIAJPA4doxTlRMC/7LikdfBrLAiAuyu89R7sX/5idvh7gnudmw9OD4w1kZQ4CQuOWO93wkA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70125},"main":"dist/index.js","types":"./dist/index.d.ts","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.3_1781182205304_0.902242702893876","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.10":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.10","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.10","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"5b00feffa100712b81d01a055cc737044a81dbd7","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.10.tgz","fileCount":3,"integrity":"sha512-CkC4OH49IDv1dyBQxDreDOHf5EhHE42Z2kCFdqqLUjs7vz1xlymEdpDdUZ5WQ4/CXky1O4GRLecpIng0glLgoQ==","signatures":[{"sig":"MEYCIQDfpZMEws7ROLAKBNexrnSRBYMpa8ONsJUeDokslnrNPgIhAJhUeJFT0Lxn94jYlCkMIDIULMalNNLkU8cEF9Uh0p31","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":9218},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.10_1781182384510_0.5287655376704223","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.11":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.11","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.11","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"1e2b7dc456accb96fb3dcc73b21530066fdfe70a","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.11.tgz","fileCount":3,"integrity":"sha512-bwuVIMVs+EirndTrNs9He64AR0FLc6/t+63a0kP1gtKvT2QCAcB2riHt35+b1DTSmORjIqsWHlGuB1Uau6dNFQ==","signatures":[{"sig":"MEQCIBTjvJX4tHpV8GyIetv2elna0alAYtJ6/hHV7T8mlCWxAiA5uyIfISLEq5yFUcNsp9NohSLEH8T6eM6cYJlf3iAcVg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":7915},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.11_1781182385882_0.2646471521123308","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.13":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.13","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.13","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"f062daebe863c1664f501c9a9d99711ce768f57e","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.13.tgz","fileCount":3,"integrity":"sha512-ZwI8cdyqOdzbuRlSPvg0yXyYICJDiRqNXK82SXHHc+Oi5XGPRf8e8LRxtklwaKo2D9IIfr/WbPFWAUazr4jv9A==","signatures":[{"sig":"MEUCIBI5htJAqB9Avex4GZnStBtPHf3RHEWoo6sBZjQSyNbtAiEAwCLNXwfeQL2aD/dIQ4iMSyU1lQjzvFK1O8xHyZUca/c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6561},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.13_1781182387529_0.3300250215697611","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.20":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.20","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.20","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"283e045ca4ccc7a1aeb40dded9c51ef830aa5290","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.20.tgz","fileCount":3,"integrity":"sha512-WtmoYmoXKQaCXoIoqRFMWsoWMV1G2TV4fGm+BEqVvU+XXv+jQyCBW2u23PvFEVtIDq9idwyaGtNABymVVyTIkw==","signatures":[{"sig":"MEYCIQD1mCNBBkjYShT2aKWvK6dHcZuu9bg2jX2GW/s8rvknKQIhAP8n2g70cbG2wPcOeAS81AOxo4KM5EMdlmRCEk7V1+0N","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":762},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.20_1781182531197_0.8312047152119157","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.21":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.21","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.21","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"a087c9962b2f75e570bb17efda6efb40fd3fc4b8","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.21.tgz","fileCount":3,"integrity":"sha512-4ABr3LPHUGv4KD9HPT0BRfwYuSkczx5q3tcj5Ic2KrAmr0Zag+qvcJXZMA1OB/Tqk6baSqLwQwDuY3Jy+wkqhw==","signatures":[{"sig":"MEUCIBfPj8BITuwurHPoIbfmJ3Btk5PlfQSzb29JqoWdeWZ3AiEA4iqCk/Y6AiYCzMIZUnceaM9hKRogBVnq2p4cOdCq99M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":916},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.21_1781182532482_0.9734613731543249","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.22":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.22","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.22","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"566d6cba6af278bd6b0db9c27c241890a0b12833","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.22.tgz","fileCount":3,"integrity":"sha512-aYgO+/ZADgpXosuA/6W3f1ELi7HRFkO/TKm4NouH9R9vFL+pEZPwhKEYHqXYO6H0Yyq4Mc2kTz+NYZlu0kaIgA==","signatures":[{"sig":"MEUCIQCHHn1n7I96iCtIS/9biFwUtq3LvNMXYOc4amwG5cM28gIgLJZYPkMMZZQSfPosfZSkFv2XJkLXHCwpT0nJAOnnl7M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":762},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.22_1781182533858_0.8515820800667855","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.24":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.24","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.24","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"57c61bba3b39af0d2e2e56af7a85e139d7f6b0c1","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.24.tgz","fileCount":3,"integrity":"sha512-NTIqpU4IuZBpc2lAdiubhevl3JdpQ+nNoulfeudnM6OEBM0MJ/V3WfGwjef1yOiLyKMGY/9WsG+Xf7yQq5iJPQ==","signatures":[{"sig":"MEQCIBrhmtGj2IiaMB3A6wZiw2/Tak2peb+c12gIpBgNs2XzAiA8NBbWz3Tu9gvFD3hW3BrhKUcOHQrusr4o3QlteZotdQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1678},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.24_1781182535495_0.33018566131827276","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.25":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.25","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.25","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"e6d48e7bec3e6385478cd7909170bf0b84ec550b","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.25.tgz","fileCount":3,"integrity":"sha512-nODOLrNEYFNGENC2nAnmSwO88VQ3yB81ey0n/TL+dv+jRZ3iYT5b8/ywcc9tCs/2P6JblBQurS6Ujm5bNYyltQ==","signatures":[{"sig":"MEUCIAcCkYKkAGzOKdrhQCLHMbXDcG5NrsTAdORx9CHVlTTfAiEAmh2c7pU7Re5VJgaZPtjMocrbkSXx4slw6vuW9/bCRtk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1243},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.25_1781182536790_0.3049742192307823","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.26":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.26","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.26","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"447e81de4c35b82bc1b2cd03708303acc10435c0","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.26.tgz","fileCount":3,"integrity":"sha512-KFewB18IGfJen6m9lVOOEu2zFBcVup6K89hvZhb4euahaT/cx75R1YKS9F0cWiEp4e5NUce9AuLitupzyFwYxg==","signatures":[{"sig":"MEUCIQDu8HOdAfKipdA5U9BVewO1S3jL+XDd3fRMfByFgva0GAIgV1iHZNF64pcZD/ZPj8yrYOiXU1h4yZN9x5z0DdO/L4g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":874},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.26_1781182537986_0.6997354416723118","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.27":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.27","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.27","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"af0df49761c42b749744501f782fd179d48dc557","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.27.tgz","fileCount":3,"integrity":"sha512-7KzuTc/VT1p1yz8YpjncZbniH4afvhh5Z+ZeqEl5EpHn58us4fOHMNAfTyojuRaiy/vhg9bG+iEMdKWEkXeVHg==","signatures":[{"sig":"MEQCIHGFvgdXu+mYVSQ8PwGzBwwf6tHeHS9Mz2zaqb7eDs8pAiBj2W14T9IHl9dSnnSZvKc2ViXwliHLXpOb0wr8nKB+lw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":746},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.27_1781182539213_0.5736135850356874","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.28":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.28","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.28","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"0110b4dd63f2f1f2063cf01988571f0fee3443dc","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.28.tgz","fileCount":3,"integrity":"sha512-fr21i5ykitx2Wr1L4hWVP0PwvuOLIDJI1b7NE4c+5ZyQ+NqcyWQ2a82KbPnwoDE8dyBvtmFK0Q7wJb5FxppLhg==","signatures":[{"sig":"MEQCIFLfai4zjM9LxfiB1ENiSKBLGu6+POYYShsp+Ggp079aAiAQclo0lH9REfT9f0uB9ZNPL4VeRwyUHoFCsF/1uQ6Txw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":146},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.28_1781182540475_0.1590889077663571","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.31":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.31","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.31","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"510689bdde78d8aa37b47d4fc443b6a61e351941","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.31.tgz","fileCount":3,"integrity":"sha512-jw43abGO5C60qzC2+wb9J04cGdqzQE/wdsbFl5m4rYMEPfW4oPl6w5FqkhTKeUHl1E3Qw6wohfEjAlDqF2tIjA==","signatures":[{"sig":"MEQCICi2vOsVhsFf9ScNy4CJKSCwvgHa1HgcIAxC9hfuij6QAiB6ORJrnoCsbe2msOP/fqYOO6SbvPLWTtTD5Giy8jSjSw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30470},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"deprecated":"debug artifact - do not use","_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.31_1781182720188_0.5330778956748459","host":"s3://npm-registry-packages-npm-production"}},"2.0.2-canary.32":{"name":"@truto/sqlite-builder","version":"2.0.2-canary.32","license":"MIT","_id":"@truto/sqlite-builder@2.0.2-canary.32","maintainers":[{"name":"truto","email":"eng@truto.one"}],"dist":{"shasum":"b818754960486b6340e54ba339cfcfd387544661","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.2-canary.32.tgz","fileCount":3,"integrity":"sha512-b+/6Ziualf+r1iTyfXb6G0+zoi8+F6AYDfIBtxSQpT4PF7lULd0Xo7mvc5bjm8eC4wF2V46qmQ3r3MNcc1X2rA==","signatures":[{"sig":"MEQCICCVSxK4HocTGj8BlOHt9nFkBnCHrSTDuGN8agQ5vsGqAiAWZrwgFfFseH9y/bYqpRbUse2r8zf28otOF+ElpDzXew==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1233},"main":"index.js","_npmUser":{"name":"truto","email":"eng@truto.one"},"_npmVersion":"10.9.8","description":"debug canary","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.2-canary.32_1781182721527_0.9528949875172703","host":"s3://npm-registry-packages-npm-production"},"deprecated":"debug artifact - do not use"},"2.0.1":{"name":"@truto/sqlite-builder","version":"2.0.1","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"author":{"name":"Truto","email":"eng@truto.one"},"license":"MIT","_id":"@truto/sqlite-builder@2.0.1","maintainers":[{"name":"truto","email":"eng@truto.one"}],"homepage":"https://github.com/trutohq/truto-sqlite-builder#readme","bugs":{"url":"https://github.com/trutohq/truto-sqlite-builder/issues"},"dist":{"shasum":"6070b70bb27f38a35151ae5c7547249f587aec20","tarball":"https://registry.npmjs.org/@truto/sqlite-builder/-/sqlite-builder-2.0.1.tgz","fileCount":17,"integrity":"sha512-CZeCtr0O2RWiwq3wWic0H48WFRqV/YNkQSqWSqxHqh8Pf9B1yM0j2DP+3FUzHRWxr8qlFWR/QxcArihdvADb+Q==","signatures":[{"sig":"MEUCIQCkRp34g+/lk4xyFAe8wW8zqF/gqIB1JQxxrwBoNzp9AAIgZnJLNCezoj5pDdBro72gLLY7rVqgcybkCHWtaPpoYLo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@truto%2fsqlite-builder@2.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":103715},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"bun":">=1.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"fc4276a8b7bd9dffa55b9cefe13770236ebadbd0","scripts":{"dev":"vitest --watch","lint":"eslint","test":"vitest","build":"bun build src/index.ts --outdir dist --sourcemap=linked && tsc --emitDeclarationOnly","format":"prettier --write .","test:ui":"vitest --ui","lint:fix":"eslint --fix","typecheck":"tsc --noEmit","format:check":"prettier --check .","test:coverage":"vitest --coverage","prepublishOnly":"bun run typecheck && bun run lint && bun test && bun run build","build:declaration":"tsc --emitDeclarationOnly"},"_npmUser":{"name":"truto","email":"eng@truto.one"},"repository":{"url":"git+https://github.com/trutohq/truto-sqlite-builder.git","type":"git"},"_npmVersion":"10.9.8","description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","directories":{},"lint-staged":{"*.{ts,tsx}":["bun run eslint --fix"],"*.{json,md,yml,yaml}":["bun run prettier --write"]},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"husky":"9.1.7","eslint":"9.29.0","vitest":"3.2.4","globals":"16.2.0","prettier":"3.5.3","@eslint/js":"9.29.0","@types/bun":"latest","@vitest/ui":"3.2.4","typescript":"5.8.3","lint-staged":"16.1.2","@changesets/cli":"2.29.5","@vitest/coverage-v8":"3.2.4","eslint-config-prettier":"10.1.5","eslint-plugin-prettier":"5.5.0","eslint-plugin-security":"3.0.1","@typescript-eslint/parser":"8.34.1","prettier-plugin-packagejson":"2.5.15","@typescript-eslint/eslint-plugin":"8.34.1"},"_npmOperationalInternal":{"tmp":"tmp/sqlite-builder_2.0.1_1781182853421_0.3330861504893703","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2025-06-21T07:36:10.687Z","modified":"2026-06-11T13:07:01.867Z","1.0.0":"2025-06-21T07:36:10.962Z","1.0.1":"2025-06-21T08:15:19.928Z","1.0.2":"2025-06-23T11:06:31.361Z","1.0.3":"2025-06-23T14:10:55.903Z","1.0.4":"2025-06-23T15:46:07.467Z","2.0.2-canary.0":"2026-06-11T12:47:21.684Z","2.0.2-canary.3":"2026-06-11T12:50:05.433Z","2.0.2-canary.10":"2026-06-11T12:53:04.679Z","2.0.2-canary.11":"2026-06-11T12:53:06.004Z","2.0.2-canary.13":"2026-06-11T12:53:07.673Z","2.0.2-canary.20":"2026-06-11T12:55:31.322Z","2.0.2-canary.21":"2026-06-11T12:55:32.601Z","2.0.2-canary.22":"2026-06-11T12:55:33.995Z","2.0.2-canary.24":"2026-06-11T12:55:35.647Z","2.0.2-canary.25":"2026-06-11T12:55:36.899Z","2.0.2-canary.26":"2026-06-11T12:55:38.129Z","2.0.2-canary.27":"2026-06-11T12:55:39.349Z","2.0.2-canary.28":"2026-06-11T12:55:40.629Z","2.0.2-canary.31":"2026-06-11T12:58:40.326Z","2.0.2-canary.32":"2026-06-11T12:58:41.648Z","2.0.1":"2026-06-11T13:00:53.589Z"},"bugs":{"url":"https://github.com/trutohq/truto-sqlite-builder/issues"},"author":{"name":"Truto","email":"eng@truto.one"},"license":"MIT","homepage":"https://github.com/trutohq/truto-sqlite-builder#readme","keywords":["sqlite","tagged template","sql","injection-safe","javascript","typescript","template-literal","database","query-builder"],"repository":{"url":"git+https://github.com/trutohq/truto-sqlite-builder.git","type":"git"},"description":"Safe, zero-dependency template-literal tag for SQLite queries in any JS environment","maintainers":[{"name":"truto","email":"eng@truto.one"}],"readme":"# 🏗️ truto-sqlite-builder\n\n[![npm version](https://badge.fury.io/js/%40truto%2Fsqlite-builder.svg)](https://badge.fury.io/js/%40truto%2Fsqlite-builder)\n[![CI](https://github.com/trutohq/truto-sqlite-builder/actions/workflows/ci.yml/badge.svg)](https://github.com/trutohq/truto-sqlite-builder/actions/workflows/ci.yml)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n**Safe, zero-dependency template-literal tag for SQLite queries in any JS environment.**\n\n`@truto/sqlite-builder` provides a secure and ergonomic way to build SQLite queries using tagged template literals. It prevents SQL injection attacks through parameterized queries while offering convenient helper functions for common SQL patterns.\n\n## ✨ Features\n\n- 🔒 **Injection-safe**: All values are parameterized, preventing SQL injection\n- 🚫 **Defense in depth**: Multiple security layers including stacked query detection\n- 🪶 **Zero dependencies**: Pure TypeScript/JavaScript with no runtime dependencies\n- 🌍 **Universal**: Works in Bun, Node.js, Deno, and modern browsers\n- 🎯 **TypeScript-first**: Full type safety with excellent IDE support\n- 🔧 **Helper functions**: Built-in utilities for identifiers, IN clauses, and more\n- 🔍 **JSON Filter Language**: MongoDB-style JSON filters for WHERE clauses\n- 🔗 **Qualified Filters**: Table/alias scoping for complex JOINs using `$alias` blocks\n- ⚡ **Lightweight**: Minimal bundle size with tree-shaking support\n\n## 📦 Installation\n\n```bash\nbun add @truto/sqlite-builder\n```\n\n```bash\nnpm install @truto/sqlite-builder\n```\n\n```bash\nyarn add @truto/sqlite-builder\n```\n\n```bash\npnpm add @truto/sqlite-builder\n```\n\n## 🚀 Quick Start\n\n```typescript\nimport sqlite3 from 'better-sqlite3'\nimport { sql, compileFilter } from '@truto/sqlite-builder'\n\nconst db = new sqlite3('database.db')\n\n// Simple query\nconst name = 'Alice'\nconst { text, values } = sql`SELECT * FROM users WHERE name = ${name}`\nconst users = db.prepare(text).all(...values)\n\n// JSON Filter queries\nconst filter = {\n  name: { like: 'John%' },\n  age: { gte: 18, lt: 65 },\n  or: [{ email: { regex: '.*@example.com$' } }, { phone: { exists: false } }],\n}\n\n// Interpolate the compiled filter directly: its placeholders and values are\n// collected automatically, so query.values is always correctly aligned.\nconst query = sql`\n  SELECT * FROM users\n  WHERE ${compileFilter(filter)}\n`\n\nconst results = db.prepare(query.text).all(...query.values)\n\n// Qualified filters for JOINs with alias blocks\nconst joinFilter = {\n  status: 'ACTIVE', // Main table\n  $profiles: {\n    // Profile table alias\n    verified: true,\n    'settings.theme': 'dark', // JSON path in profile\n  },\n  $orders: {\n    // Orders table alias\n    total: { gt: 100 },\n  },\n}\n\nconst joinQuery = sql`\n  SELECT u.name, p.verified, o.total\n  FROM users u\n  JOIN profiles p ON u.id = p.user_id\n  JOIN orders o ON u.id = o.user_id  \n  WHERE ${compileFilter(joinFilter)}\n`\n```\n\n## 📖 API Reference\n\n### `sql` Tagged Template\n\nThe main function for building SQL queries.\n\n```typescript\nconst query = sql`SELECT * FROM users WHERE id = ${userId}`\n// Returns: { text: \"SELECT * FROM users WHERE id = ?\", values: [userId] }\n```\n\n**Parameters:**\n\n- Template strings and interpolated values\n- Returns a frozen `SqlQuery` object with `text` and `values` properties\n\n### `sql.ident(identifier: string | readonly (string | SqlFragment)[])`\n\nSafely quotes SQL identifiers (table names, column names, etc.). Accepts single identifiers, arrays of identifiers, or mixed arrays containing both identifiers and SQL fragments.\n\n```typescript\n// Single identifier\nconst table = 'users'\nconst query = sql`SELECT * FROM ${sql.ident(table)}`\n// Returns: { text: 'SELECT * FROM \"users\"', values: [] }\n\n// Qualified identifiers (table.column)\nconst qualifiedQuery = sql`SELECT ${sql.ident('u.name')}, ${sql.ident('u.email')} FROM users u`\n// Returns: { text: 'SELECT \"u\".\"name\", \"u\".\"email\" FROM users u', values: [] }\n\n// Array of identifiers (useful for column lists)\nconst columns = ['name', 'email', 'created_at']\nconst selectQuery = sql`SELECT ${sql.ident(columns)} FROM users`\n// Returns: { text: 'SELECT \"name\", \"email\", \"created_at\" FROM users', values: [] }\n\n// Mixed arrays with qualified and simple identifiers\nconst mixedColumns = ['u.id', 'name', 'u.email', 'p.title']\nconst joinQuery = sql`SELECT ${sql.ident(mixedColumns)} FROM users u JOIN posts p ON u.id = p.user_id`\n// Returns: { text: 'SELECT \"u\".\"id\", \"name\", \"u\".\"email\", \"p\".\"title\" FROM users u JOIN posts p ON u.id = p.user_id', values: [] }\n\n// Mixed arrays with identifiers and SQL fragments\nconst mixedColumns = ['id', 'name', sql.raw('UPPER(email) as email_upper')]\nconst mixedQuery = sql`SELECT ${sql.ident(mixedColumns)} FROM users`\n// Returns: { text: 'SELECT \"id\", \"name\", UPPER(email) as email_upper FROM users', values: [] }\n\n// Mixed arrays with parameterized fragments\nconst status = 'premium'\nconst dynamicColumns = [\n  'id',\n  'name',\n  sql`CASE WHEN status = ${status} THEN 'Premium' ELSE 'Regular' END as user_type`,\n]\nconst dynamicQuery = sql`SELECT ${sql.ident(dynamicColumns)} FROM users`\n// Returns: { text: 'SELECT \"id\", \"name\", CASE WHEN status = ? THEN \\'Premium\\' ELSE \\'Regular\\' END as user_type FROM users', values: ['premium'] }\n\n// In INSERT statements\nconst insertColumns = ['name', 'email', 'age']\nconst insertQuery = sql`\n  INSERT INTO users (${sql.ident(insertColumns)}) \n  VALUES (${name}, ${email}, ${age})\n`\n// Returns: { text: 'INSERT INTO users (\"name\", \"email\", \"age\") VALUES (?, ?, ?)', values: [name, email, age] }\n```\n\n**Security:** Only accepts valid ANSI identifiers (simple: `name`, qualified: `table.column`) for string elements, each capped at 255 characters. SQL fragments are passed through as-is, but **only fragments minted by this library** (e.g. `sql.raw`, nested `sql\\`\\``) are accepted — a plain `{ text, values }`object (for example from`JSON.parse`) is rejected, so untrusted data can never masquerade as raw SQL.\n\n### `sql.in(array: readonly unknown[])`\n\nCreates parameterized IN clauses from arrays.\n\n```typescript\nconst ids = [1, 2, 3]\nconst query = sql`SELECT * FROM users WHERE id IN ${sql.in(ids)}`\n// Returns: { text: \"SELECT * FROM users WHERE id IN (?,?,?)\", values: [1, 2, 3] }\n```\n\n**Features:**\n\n- Rejects empty arrays (would create invalid SQL)\n- Warns for arrays with >1000 items (performance consideration)\n\n### `sql.raw(rawSql: string)`\n\nEmbeds raw SQL without parameterization. **⚠️ Use with extreme caution!**\n\n```typescript\nconst query = sql`SELECT * FROM users WHERE created_at > ${sql.raw('datetime(\"now\", \"-1 day\")')}`\n// Returns: { text: 'SELECT * FROM users WHERE created_at > datetime(\"now\", \"-1 day\")', values: [] }\n```\n\n**⚠️ Warning:** `sql.raw()` is the library's single, explicit trust boundary — its argument becomes SQL verbatim. Never pass user input to it. For dynamic WHERE clauses use `compileFilter()`; for identifiers use `sql.ident()`. As a safety net, the `sql` tag verifies that the number of `?` placeholders in the final query exactly matches the number of bound values, so a raw fragment that smuggles a stray `?` (or forgets to carry its value) throws instead of producing a misaligned query.\n\n### `sql.join(fragments: SqlFragment[], separator?: string | SqlFragment)`\n\nJoins multiple SQL fragments with a separator.\n\n```typescript\nconst conditions = [\n  sql`name = ${'John'}`,\n  sql`age = ${30}`,\n  sql`active = ${true}`,\n]\n\nconst query = sql`SELECT * FROM users WHERE ${sql.join(conditions, ' AND ')}`\n// Returns: { text: \"SELECT * FROM users WHERE name = ? AND age = ? AND active = ?\", values: ['John', 30, true] }\n```\n\n**Fragments** must be library-minted fragments (forged `{ text, values }` objects are rejected).\n\n**Separators** support any structural connector safely:\n\n- A **string** separator (e.g. `', '`, `' AND '`, `' UNION ALL '`) is validated to be a pure connector. Separators containing string/identifier quotes (`'`, `\"`, `` ` ``, `[`, `]`), statement terminators (`;`), comment markers (`--`, `/*`, `*/`), `NUL`, backslashes, or unbalanced parentheses are rejected — so even an untrusted separator cannot break out of the expression.\n- A **`SqlFragment`** separator (e.g. `sql\\` OR weight = ${w} OR \\``) lets you parameterize the connector itself; its values are interleaved between fragments automatically.\n\n## 🔍 JSON Filter Language\n\nBuild complex WHERE clauses using MongoDB-style JSON filters. Perfect for APIs and dynamic queries.\n\n### `compileFilter(filter: JsonFilter): FilterResult`\n\nCompiles a JSON filter object into a parameterized SQL WHERE clause.\n\n```typescript\nimport { compileFilter } from '@truto/sqlite-builder'\n\nconst filter = {\n  status: 'ACTIVE',\n  age: { gte: 18, lt: 65 },\n}\n\nconst result = compileFilter(filter)\n// Returns a branded SQL fragment: { text: '((\"status\" = ?) AND (\"age\" >= ?) AND (\"age\" < ?))', values: ['ACTIVE', 18, 65] }\n\n// Interpolate it directly into a sql template — no sql.raw() needed. The\n// filter's placeholders and values are collected automatically and stay aligned.\nconst query = sql`\n  SELECT * FROM users\n  WHERE ${result}\n`\n```\n\n### Supported Operators\n\n| Operator Family           | JSON Form                             | SQL Fragment                             | Description                         |\n| ------------------------- | ------------------------------------- | ---------------------------------------- | ----------------------------------- |\n| **Equality**              | `\"field\": value`                      | `\"field\" = ?`                            | Direct value comparison             |\n| **Inequality**            | `\"field\": { \"ne\": value }`            | `\"field\" <> ?`                           | Not equal comparison                |\n| **Comparison**            | `\"field\": { \"gt\": value }`            | `\"field\" > ?`                            | Greater than, gte, lt, lte          |\n| **Set Membership**        | `\"field\": { \"in\": [1, 2, 3] }`        | `\"field\" IN (?,?,?)`                     | Value in array                      |\n| **Negative Set**          | `\"field\": { \"nin\": [1, 2] }`          | `\"field\" NOT IN (?,?)`                   | Value not in array                  |\n| **NULL Checks**           | `\"field\": { \"exists\": false }`        | `\"field\" IS NULL`                        | Check for NULL/NOT NULL             |\n| **LIKE Patterns**         | `\"field\": { \"like\": \"john%\" }`        | `\"field\" LIKE ?`                         | Pattern matching                    |\n| **Case-insensitive LIKE** | `\"field\": { \"ilike\": \"%DOE%\" }`       | `\"field\" LIKE ? COLLATE NOCASE`          | Case-insensitive patterns           |\n| **Regular Expressions**   | `\"field\": { \"regex\": \"^[A-Z]+\" }`     | `\"field\" REGEXP ?`                       | Regex patterns (requires extension) |\n| **Logical AND**           | `\"and\": [filter1, filter2]`           | `(filter1 AND filter2)`                  | All conditions must match           |\n| **Logical OR**            | `\"or\": [filter1, filter2]`            | `(filter1 OR filter2)`                   | Any condition must match            |\n| **JSON Path**             | `\"profile.email\": \"test@example.com\"` | `json_extract(\"profile\", '$.email') = ?` | Query JSON column fields            |\n| **Alias Blocks**          | `\"$alias\": { \"field\": value }`        | `alias.\"field\" = ?`                      | Table/alias qualified fields        |\n\n### Filter Examples\n\n#### Basic Operations\n\n```typescript\n// Equality and comparison\nconst filter1 = {\n  status: 'ACTIVE',\n  age: { gte: 18, lt: 65 },\n  score: { gt: 80, lte: 100 },\n}\n// SQL: ((\"status\" = ? AND \"age\" >= ? AND \"age\" < ? AND \"score\" > ? AND \"score\" <= ?))\n\n// Set membership\nconst filter2 = {\n  role: { in: ['ADMIN', 'EDITOR'] },\n  department: { nin: ['ARCHIVED', 'DELETED'] },\n}\n// SQL: ((\"role\" IN (?,?) AND \"department\" NOT IN (?,?)))\n\n// NULL checks\nconst filter3 = {\n  email: { exists: true }, // IS NOT NULL\n  deleted_at: { exists: false }, // IS NULL\n}\n// SQL: ((\"email\" IS NOT NULL AND \"deleted_at\" IS NULL))\n```\n\n#### Pattern Matching\n\n```typescript\n// LIKE patterns\nconst filter4 = {\n  username: { like: 'john%' }, // Starts with 'john'\n  email: { ilike: '%@EXAMPLE.COM%' }, // Case-insensitive contains\n}\n// SQL: ((\"username\" LIKE ? AND \"email\" LIKE ? COLLATE NOCASE))\n\n// Regular expressions (requires REGEXP extension)\nconst filter5 = {\n  email: { regex: '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}$' },\n  phone: { regex: '^\\\\+1[0-9]{10}$' },\n}\n// SQL: ((\"email\" REGEXP ? AND \"phone\" REGEXP ?))\n```\n\n#### Logical Operators\n\n```typescript\n// AND operator (explicit)\nconst filter6 = {\n  and: [\n    { status: 'ACTIVE' },\n    { age: { gte: 18 } },\n    { country: { in: ['US', 'CA', 'GB'] } },\n  ],\n}\n// SQL: (((\"status\" = ?) AND (\"age\" >= ?) AND (\"country\" IN (?,?,?))))\n\n// OR operator\nconst filter7 = {\n  or: [\n    { age: { lt: 18 } }, // Minors\n    { age: { gte: 65 } }, // Seniors\n  ],\n}\n// SQL: (((\"age\" < ?) OR (\"age\" >= ?)))\n\n// Mixed AND/OR logic\nconst filter8 = {\n  status: 'ACTIVE', // Implicit AND\n  or: [{ tags: { ilike: '%urgent%' } }, { priority: { gte: 8 } }],\n}\n// SQL: ((((\"tags\" LIKE ? COLLATE NOCASE) OR (\"priority\" >= ?)) AND (\"status\" = ?)))\n```\n\n#### JSON Path Querying\n\nFor SQLite JSON columns, use dot notation to query nested fields:\n\n```typescript\n// Query JSON fields\nconst filter9 = {\n  'profile.email': { regex: '.*@example\\\\.org$' },\n  'profile.age': { gte: 21 },\n  'settings.theme': { in: ['dark', 'light'] },\n  'metadata.tags': { exists: true },\n}\n// SQL: ((json_extract(\"profile\", '$.email') REGEXP ? AND\n//        json_extract(\"profile\", '$.age') >= ? AND\n//        json_extract(\"settings\", '$.theme') IN (?,?) AND\n//        json_extract(\"metadata\", '$.tags') IS NOT NULL))\n\n// Complex nested JSON query\nconst filter10 = {\n  and: [\n    { 'user.profile.email': { regex: '.*@company\\\\.com$' } },\n    { or: [{ 'user.role': 'ADMIN' }, { 'user.permissions.canEdit': true }] },\n  ],\n}\n```\n\n#### Qualified Filters for JOINs\n\nFor complex queries involving multiple tables or aliases, use **alias blocks** with keys starting with `$`:\n\n```typescript\n// Basic alias usage\nconst joinFilter = {\n  // Main table fields (no prefix)\n  status: 'ACTIVE',\n  age: { gte: 18, lt: 65 },\n\n  // Table alias 't2'\n  $t2: {\n    column_in_table_2: { gte: 100 },\n    'stats.avg': { lt: 10 }, // JSON path in aliased table\n  },\n\n  // Table alias 'orders'\n  $orders: {\n    amount: { gt: 500 },\n    status: { in: ['completed', 'shipped'] },\n  },\n}\n\nconst result = compileFilter(joinFilter)\n// SQL: (((\"status\" = ?) AND (\"age\" >= ? AND \"age\" < ?) AND\n//        ((t2.\"column_in_table_2\" >= ?) AND (json_extract(t2.\"stats\", '$.avg') < ?)) AND\n//        ((orders.\"amount\" > ?) AND (orders.\"status\" IN (?,?)))))\n```\n\n**Alias Block Rules:**\n\n- **Alias names**: Must be valid SQL identifiers (`[A-Za-z_][A-Za-z0-9_]*`)\n- **Prefixing**: All fields in alias blocks get prefixed with `alias.`\n- **JSON paths**: Work seamlessly with aliases: `json_extract(alias.\"column\", '$.path')`\n- **Combination**: Alias blocks are AND-combined with root fields and each other\n- **Order**: Regular fields processed first, then alias blocks\n\n```typescript\n// Complex alias example with logical operators\nconst complexJoinFilter = {\n  // Primary table conditions\n  user_status: 'ACTIVE',\n\n  // User profile table\n  $profile: {\n    verified: true,\n    'preferences.notifications': { ne: false },\n    or: [{ subscription_type: 'premium' }, { credits: { gte: 100 } }],\n  },\n\n  // Orders table with complex conditions\n  $orders: {\n    and: [\n      { created_at: { gte: '2024-01-01' } },\n      { or: [{ total_amount: { gt: 1000 } }, { item_count: { gte: 5 } }] },\n    ],\n  },\n}\n\n// Use in JOIN queries\nconst query = sql`\n  SELECT u.id, u.name, p.subscription_type, o.total_amount\n  FROM users u\n  JOIN profiles p ON u.id = p.user_id  \n  JOIN orders o ON u.id = o.user_id\n  WHERE ${compileFilter(complexJoinFilter)}\n`\n```\n\n**Security & Validation:**\n\n```typescript\n// ✅ Valid alias identifiers\n$users: { name: 'John' }        // Simple identifier\n$user_profiles: { age: 25 }     // Underscore allowed\n$_temp: { status: 'active' }    // Starting underscore allowed\n\n// ❌ Invalid alias identifiers (will throw SyntaxError)\n$123invalid: { ... }            // Cannot start with number\n$'invalid-alias': { ... }       // Hyphens not allowed\n$'table.alias': { ... }         // Dots not allowed in alias name\n```\n\n**Integration with Complex Queries:**\n\n```typescript\n// Real-world JOIN example\nconst userOrderFilter = {\n  // Users table\n  active: true,\n  email: { exists: true },\n\n  // User profiles\n  $profiles: {\n    'settings.email_notifications': true,\n    verified_at: { exists: true },\n  },\n\n  // Recent orders\n  $recent_orders: {\n    created_at: { gte: '2024-01-01' },\n    status: { in: ['completed', 'shipped'] },\n    total: { gt: 50 },\n  },\n}\n\nconst complexQuery = sql`\n  SELECT \n    u.id,\n    u.name,\n    u.email,\n    p.verified_at,\n    COUNT(ro.id) as recent_order_count,\n    SUM(ro.total) as recent_order_total\n  FROM users u\n  JOIN profiles p ON u.id = p.user_id\n  JOIN orders ro ON u.id = ro.user_id \n  WHERE ${compileFilter(userOrderFilter)}\n  GROUP BY u.id, u.name, u.email, p.verified_at\n  HAVING recent_order_count > 0\n  ORDER BY recent_order_total DESC\n`\n\nconst results = db.prepare(complexQuery.text).all(...complexQuery.values)\n```\n\n#### Kitchen Sink Examples\n\nReal-world complex filters:\n\n```typescript\n// Active users in specific regions, either minors/seniors or VIP\nconst complexFilter = {\n  and: [\n    { status: 'ACTIVE' },\n    { or: [{ age: { lt: 18 } }, { age: { gte: 65 } }, { membership: 'VIP' }] },\n    { country: { in: ['US', 'CA', 'GB'] } },\n    { email: { exists: true } },\n    { 'profile.verified': true },\n  ],\n}\n\n// Content filtering with multiple criteria\nconst contentFilter = {\n  name: { like: 'Project%' },\n  category: { nin: ['ARCHIVED', 'DELETED', 'SPAM'] },\n  created_at: { exists: true },\n  or: [\n    { tags: { ilike: '%important%' } },\n    { priority: { gte: 8 } },\n    { 'metadata.featured': true },\n  ],\n}\n```\n\n### Integration with SQL Template\n\n```typescript\nimport { sql, compileFilter } from '@truto/sqlite-builder'\n\n// Build the WHERE clause\nconst filter = {\n  status: 'ACTIVE',\n  age: { gte: 18 },\n  role: { in: ['USER', 'ADMIN'] },\n}\n\n// Use in complete query — the filter fragment and the LIMIT value are\n// collected in order, so query.values lines up with the placeholders.\nconst query = sql`\n  SELECT id, name, email, created_at\n  FROM users\n  WHERE ${compileFilter(filter)}\n  ORDER BY created_at DESC\n  LIMIT ${limit}\n`\n\n// Execute with driver\nconst results = db.prepare(query.text).all(...query.values)\n```\n\n### Security & Validation\n\nThe JSON filter compiler includes comprehensive security measures:\n\n- **Operator validation**: Only known operators are allowed\n- **Identifier safety**: Field names are validated using the same rules as `sql.ident()`\n- **Array limits**: IN/NIN arrays limited to 999 items (SQLite limitation)\n- **DoS protection**: Nesting depth ≤ 10, total operators ≤ 100\n- **Type validation**: Strict type checking for all operator values\n- **SQL injection prevention**: All values are parameterized\n\n```typescript\n// ❌ These will throw errors\ncompileFilter({ age: { unknown: 18 } }) // Unknown operator\ncompileFilter({ 'user;--': 'value' }) // Invalid identifier (contains ';')\ncompileFilter({ role: { in: [] } }) // Empty array\ncompileFilter({ role: { in: new Array(1000).fill('x') } }) // Too large array\n\n// ✅ These are safe and valid\ncompileFilter({ age: { gte: 18, lte: 65 } }) // Multiple operators\ncompileFilter({ 'profile.email': { exists: true } }) // JSON path\ncompileFilter({ or: [{ x: 1 }, { y: 2 }] }) // Logical operators\n```\n\n### REGEXP Extension\n\nTo use the `regex` operator, you need to load a REGEXP extension in SQLite:\n\n```typescript\n// With better-sqlite3\nimport sqlite3 from 'better-sqlite3'\n\nconst db = new sqlite3('database.db')\n\n// Load REGEXP extension (varies by implementation)\n// This is implementation-specific - check your SQLite setup\ndb.loadExtension('regexp') // Example - actual method may vary\n\n// Now regex filters work\nconst filter = {\n  email: { regex: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$' },\n}\n```\n\n## 🛡️ Security Model\n\n### What's Protected\n\n- **SQL Injection**: All interpolated values are parameterized\n- **Unforgeable fragments**: Only fragments created by this library can contribute raw SQL text. A plain `{ text, values }` object (e.g. from `JSON.parse` or a request body) is treated as a value, never as SQL, closing the structural duck-typing bypass\n- **Placeholder integrity**: The `sql` tag rejects any query whose `?` count does not match its bound-value count, catching raw fragments that smuggle or drop placeholders\n- **Safe `sql.join()` separators**: String separators are validated so they cannot introduce string literals, comments, statement terminators, or unbalanced parentheses; use a `SqlFragment` separator to parameterize the connector itself\n- **Stacked Queries**: Queries containing `;` followed by additional SQL are rejected (detection ignores semicolons inside string literals and comments)\n- **Identifier Safety**: `sql.ident()` validates against ANSI identifier rules and caps each part at 255 characters\n- **Length Limits**: Queries exceeding 100KB are rejected; `compileFilter()` enforces the same cap on its output\n- **Pattern Limits**: `like`/`ilike`/`regex` patterns are capped at 1024 characters to bound matching cost at the SQLite layer\n- **Filter Security**: JSON filters validate operators, identifiers, and enforce limits\n\n### What's Your Responsibility\n\n- **Never use `sql.raw()` with user input**\n- **Validate identifiers before using `sql.ident()`** (though it has built-in validation)\n- **Use `sql.in()` instead of string concatenation** for arrays\n- **Keep your SQLite driver updated**\n- **Load REGEXP extension safely** if using regex filters\n\n### Supported Value Types\n\n```typescript\n// ✅ Safe types (automatically parameterized)\nconst query = sql`\n  INSERT INTO users (name, age, active, created_at, data, deleted_at)\n  VALUES (\n    ${'John'},           // string\n    ${30},               // number  \n    ${true},             // boolean\n    ${new Date()},       // Date → 'YYYY-MM-DD HH:MM:SS'\n    ${null},             // null\n    ${undefined}         // undefined → null\n  )\n`\n\n// ❌ Unsafe types (will throw TypeError)\nsql`SELECT * FROM users WHERE data = ${Buffer.from('test')}` // Use sql.raw() for buffers\nsql`SELECT * FROM users WHERE id = ${Symbol('test')}` // Unsupported type\n```\n\n## 📋 Examples\n\n### Basic CRUD Operations\n\n```typescript\nimport { sql } from '@truto/sqlite-builder'\n\n// CREATE with array identifiers\nconst insertColumns = ['name', 'email', 'age']\nconst insertUser = sql`\n  INSERT INTO users (${sql.ident(insertColumns)})\n  VALUES (${name}, ${email}, ${age})\n`\n\n// READ with specific columns\nconst selectColumns = ['id', 'name', 'email', 'created_at']\nconst getUser = sql`\n  SELECT ${sql.ident(selectColumns)} FROM users \n  WHERE id = ${userId}\n`\n\n// UPDATE\nconst updateUser = sql`\n  UPDATE users \n  SET name = ${newName}, updated_at = ${new Date()}\n  WHERE id = ${userId}\n`\n\n// DELETE\nconst deleteUser = sql`\n  DELETE FROM users \n  WHERE id = ${userId}\n`\n```\n\n### Dynamic Queries\n\n```typescript\n// Dynamic WHERE conditions\nconst filters = []\nif (name) filters.push(sql`name = ${name}`)\nif (minAge) filters.push(sql`age >= ${minAge}`)\nif (isActive !== undefined) filters.push(sql`active = ${isActive}`)\n\nconst whereClause =\n  filters.length > 0 ? sql.join(filters, ' AND ') : sql.raw('1=1')\n\nconst query = sql`\n  SELECT * FROM users \n  WHERE ${whereClause}\n  ORDER BY created_at DESC\n`\n\n// Dynamic column selection (simplified with array support)\nconst columns = ['id', 'name', 'email']\nconst selectQuery = sql`SELECT ${sql.ident(columns)} FROM users`\n\n// Alternative approach for more complex column expressions\nconst complexColumns = [\n  sql.ident('id'),\n  sql.ident('name'),\n  sql.raw('UPPER(email) as email_upper'),\n]\nconst complexQuery = sql`SELECT ${sql.join(complexColumns)} FROM users`\n```\n\n### Dynamic Queries with JSON Filters\n\n```typescript\nimport { sql, compileFilter } from '@truto/sqlite-builder'\n\n// API endpoint that accepts JSON filter\napp.get('/api/users', (req, res) => {\n  // User sends filter as JSON\n  const filter = req.body.filter || {}\n\n  // Safely compile to SQL and interpolate directly. Filter values and the\n  // LIMIT value are collected in order into query.values.\n  const query = sql`\n    SELECT id, name, email, created_at\n    FROM users\n    WHERE ${compileFilter(filter)}\n    ORDER BY created_at DESC\n    LIMIT ${req.query.limit || 20}\n  `\n\n  const users = db.prepare(query.text).all(...query.values)\n  res.json(users)\n})\n\n// Example API calls:\n// POST /api/users { \"filter\": { \"status\": \"ACTIVE\", \"age\": { \"gte\": 18 } } }\n// POST /api/users { \"filter\": { \"or\": [{ \"role\": \"ADMIN\" }, { \"verified\": true }] } }\n```\n\n### Array Identifiers & Qualified Identifiers\n\nThe `sql.ident()` function supports simple identifiers, qualified identifiers (table.column), arrays, and mixed arrays with SQL fragments:\n\n```typescript\n// ✅ Simple identifiers\nconst table = 'users'\nconst column = 'name'\nconst simpleQuery = sql`SELECT ${sql.ident(column)} FROM ${sql.ident(table)}`\n// Result: SELECT \"name\" FROM \"users\"\n\n// ✅ Qualified identifiers (table.column)\nconst qualifiedQuery = sql`SELECT ${sql.ident('u.name')}, ${sql.ident('p.title')} FROM users u JOIN posts p ON u.id = p.user_id`\n// Result: SELECT \"u\".\"name\", \"p\".\"title\" FROM users u JOIN posts p ON u.id = p.user_id\n\n// ✅ Pure identifier arrays (clean and concise)\nconst columns = ['id', 'name', 'email', 'created_at']\nconst arrayQuery = sql`SELECT ${sql.ident(columns)} FROM users`\n// Result: SELECT \"id\", \"name\", \"email\", \"created_at\" FROM users\n\n// ✅ Mixed qualified and simple identifiers in arrays\nconst mixedColumns = ['u.id', 'name', 'u.email', 'p.title', 'created_at']\nconst mixedQuery = sql`SELECT ${sql.ident(mixedColumns)} FROM users u LEFT JOIN posts p ON u.id = p.user_id`\n// Result: SELECT \"u\".\"id\", \"name\", \"u\".\"email\", \"p\".\"title\", \"created_at\" FROM users u LEFT JOIN posts p ON u.id = p.user_id\n\n// ✅ NEW: Mixed arrays with identifiers and SQL fragments\nconst mixedColumns = [\n  'id',\n  'name',\n  sql.raw('UPPER(email) as email_upper'),\n  sql.raw('COUNT(*) as total'),\n]\nconst mixedQuery = sql`SELECT ${sql.ident(mixedColumns)} FROM users GROUP BY id, name, email`\n// Result: SELECT \"id\", \"name\", UPPER(email) as email_upper, COUNT(*) as total FROM users GROUP BY id, name, email\n\n// ✅ Mixed arrays with parameterized fragments\nconst status = 'premium'\nconst dynamicColumns = [\n  'id',\n  'name',\n  sql`CASE WHEN status = ${status} THEN 'Premium User' ELSE 'Regular User' END as user_type`,\n  sql.raw('created_at'),\n]\nconst parameterizedQuery = sql`SELECT ${sql.ident(dynamicColumns)} FROM users WHERE active = ${true}`\n// Combines identifiers, raw SQL, and parameterized values seamlessly\n\n// ✅ Works great for INSERT statements\nconst insertData = { name: 'John', email: 'john@example.com', age: 30 }\nconst insertColumns = Object.keys(insertData)\nconst insertValues = Object.values(insertData)\nconst insertQuery = sql`\n  INSERT INTO users (${sql.ident(insertColumns)}) \n  VALUES (${insertValues[0]}, ${insertValues[1]}, ${insertValues[2]})\n`\n\n// ✅ Dynamic column selection\nconst userFields = ['name', 'email']\nconst includeTimestamps = true\nif (includeTimestamps) {\n  userFields.push('created_at', 'updated_at')\n}\nconst dynamicQuery = sql`SELECT ${sql.ident(userFields)} FROM users`\n\n// 🆚 OLD: Manual joining approach (still works, but much more verbose)\nconst oldWay = sql`SELECT ${sql.join([\n  sql.ident('id'),\n  sql.ident('name'),\n  sql.raw('UPPER(email) as email_upper'),\n])} FROM users`\n```\n\n### Complex Joins\n\n```typescript\nconst getUsersWithPosts = sql`\n  SELECT \n    ${sql.ident('u')}.id,\n    ${sql.ident('u')}.name,\n    COUNT(${sql.ident('p')}.id) as post_count\n  FROM ${sql.ident('users')} u\n  LEFT JOIN ${sql.ident('posts')} p ON u.id = p.user_id\n  WHERE u.created_at > ${startDate}\n    AND u.status IN ${sql.in(['active', 'premium'])}\n  GROUP BY u.id\n  HAVING post_count > ${minPosts}\n  ORDER BY post_count DESC\n  LIMIT ${limit}\n`\n\n// For simpler cases, you can use array identifiers directly\nconst getUsers = sql`\n  SELECT ${sql.ident(['id', 'name', 'email', 'created_at'])}\n  FROM ${sql.ident('users')}\n  WHERE status = ${'active'}\n`\n```\n\n### Transactions\n\n```typescript\n// Works great with better-sqlite3 transactions\nconst insertUsers = db.transaction((users) => {\n  const stmt = db.prepare(\n    sql`\n    INSERT INTO users (name, email) \n    VALUES (?, ?)\n  `.text,\n  )\n\n  for (const user of users) {\n    const { values } = sql`${user.name}, ${user.email}`\n    stmt.run(...values)\n  }\n})\n\ninsertUsers([\n  { name: 'Alice', email: 'alice@example.com' },\n  { name: 'Bob', email: 'bob@example.com' },\n])\n```\n\n## 🧪 Testing\n\n```bash\n# Run tests\nbun run test\n\n# Run tests in watch mode\nbun run dev\n\n# Run tests with coverage\nbun run test:coverage\n\n# Run tests with UI\nbun run test:ui\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Setup\n\n```bash\ngit clone https://github.com/truto/truto-sqlite-builder.git\ncd truto-sqlite-builder\nbun install\nbun run dev  # Start tests in watch mode\n```\n\n### Release Process\n\nWe use [changesets](https://github.com/changesets/changesets) for version management:\n\n```bash\n# Add a changeset\nbunx changeset\n\n# Release\nbunx changeset version\nbun run build\ngit commit -am \"Release\"\ngit push --follow-tags\n```\n\n## 🔒 Security Policy\n\nIf you discover a security vulnerability, please email eng@truto.one or create an issue.\n\n## 📄 License\n\nMIT © [Truto](https://github.com/trutohq)\n\n## 💡 Inspiration\n\nThis library was inspired by:\n\n- [sql-template-strings](https://github.com/felixfbecker/sql-template-strings)\n- [slonik](https://github.com/gajus/slonik)\n- [Postgres.js](https://github.com/porsager/postgres)\n\nBuilt with ❤️ for the SQLite community.\n","readmeFilename":"README.md"}