@dromney/mapthis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +56 -0
- package/dist/ai/index.cjs +474 -0
- package/dist/ai/index.cjs.map +1 -0
- package/dist/ai/index.d.cts +117 -0
- package/dist/ai/index.d.ts +117 -0
- package/dist/ai/index.js +447 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/domain-CZ-L-ntu.d.ts +163 -0
- package/dist/domain-Dc1wSTkf.d.cts +163 -0
- package/dist/errors-Bw97z_4m.d.cts +12 -0
- package/dist/errors-Bw97z_4m.d.ts +12 -0
- package/dist/generate/index.cjs +222 -0
- package/dist/generate/index.cjs.map +1 -0
- package/dist/generate/index.d.cts +140 -0
- package/dist/generate/index.d.ts +140 -0
- package/dist/generate/index.js +220 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/geocoding/index.cjs +90 -0
- package/dist/geocoding/index.cjs.map +1 -0
- package/dist/geocoding/index.d.cts +36 -0
- package/dist/geocoding/index.d.ts +36 -0
- package/dist/geocoding/index.js +86 -0
- package/dist/geocoding/index.js.map +1 -0
- package/dist/index.cjs +546 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +469 -0
- package/dist/index.js.map +1 -0
- package/dist/parser-CzXzpmVv.d.cts +111 -0
- package/dist/parser-N7-fNxeu.d.ts +111 -0
- package/dist/react/index.cjs +394 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.js +383 -0
- package/dist/react/index.js.map +1 -0
- package/dist/schemas-Dy5coqXo.d.cts +484 -0
- package/dist/schemas-Dy5coqXo.d.ts +484 -0
- package/dist/scrape/index.cjs +133 -0
- package/dist/scrape/index.cjs.map +1 -0
- package/dist/scrape/index.d.cts +60 -0
- package/dist/scrape/index.d.ts +60 -0
- package/dist/scrape/index.js +125 -0
- package/dist/scrape/index.js.map +1 -0
- package/dist/search/index.cjs +76 -0
- package/dist/search/index.cjs.map +1 -0
- package/dist/search/index.d.cts +75 -0
- package/dist/search/index.d.ts +75 -0
- package/dist/search/index.js +71 -0
- package/dist/search/index.js.map +1 -0
- package/dist/types/index.cjs +215 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +4 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +171 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types-BhqKlq0k.d.ts +31 -0
- package/dist/types-rFjK5YcJ.d.cts +31 -0
- package/dist/utils/index.cjs +335 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +363 -0
- package/dist/utils/index.d.ts +363 -0
- package/dist/utils/index.js +301 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +150 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/schemas.ts","../../src/generate/generator.ts"],"names":["z"],"mappings":";;;;;AAY2BA,KAAA,CAAE,OAAA,CAAQ,QAAQ;AAGhBA,KAAA,CAAE,KAAA,CAAM,CAACA,KAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA,EAAGA,KAAA,CAAE,OAAA,CAAQ,YAAY,CAAC,CAAC;AAG5E,IAAM,oBAAA,GAAuBA,MAAE,KAAA,CAAM;AAAA,EACxCA,KAAA,CAAE,QAAQ,OAAO,CAAA;AAAA,EACjBA,KAAA,CAAE,QAAQ,cAAc,CAAA;AAAA,EACxBA,KAAA,CAAE,QAAQ,KAAK,CAAA;AAAA,EACfA,KAAA,CAAE,QAAQ,MAAM,CAAA;AAAA,EAChBA,KAAA,CAAE,QAAQ,MAAM;AACpB,CAAC,CAAA;AAKM,IAAM,QAAA,GAAWA,KAAA,CAAE,MAAA,CAAO,MAAA,EAAO,CAAE,GAAA,CAAI,GAAA,EAAK,qBAAqB,CAAA,CAAE,GAAA,CAAI,EAAA,EAAI,oBAAoB,CAAA;AAC/F,IAAM,SAAA,GAAYA,KAAA,CAAE,MAAA,CAAO,MAAA,EAAO,CAAE,GAAA,CAAI,IAAA,EAAM,uBAAuB,CAAA,CAAE,GAAA,CAAI,GAAA,EAAK,sBAAsB,CAAA;AAElFA,MAAE,MAAA,CAAO;AAAA,EAChC,GAAA,EAAK,QAAA;AAAA,EACL,GAAA,EAAK;AACT,CAAC;AAKM,IAAM,aAAA,GAAgBA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,EAAE,OAAA,EAAS,aAAA,EAAe,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,IAAI,IAAI,CAAA;AAEhF,IAAM,iBAAiBA,KAAA,CACzB,UAAA;AAAA,EACG,CAAC,MACG,MAAA,CAAO,CAAC,EACH,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,CAAC,IAAA,KAAS,KAAK,IAAA,EAAM,CAAA,CACzB,MAAA,CAAO,CAAC,IAAA,KAAS,CAAC,CAAC,IAAI,CAAA,CACvB,IAAA,CAAK,IAAI,CAAA;AAAA,EAClBA,KAAA,CAAE,QAAO,CAAE,GAAA,CAAI,GAAG,+BAA+B,CAAA,CAAE,GAAA,CAAI,GAAA,EAAM,eAAe;AAChF,CAAA,CACC,MAAA;AAAA,EACG,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAAA,EACpD;AACJ,CAAA;AAEG,IAAM,cAAA,GAAiBA,KAAA,CACzB,MAAA,EAAO,CACP,GAAA,CAAI,GAAG,+BAA+B,CAAA,CACtC,GAAA,CAAI,GAAA,EAAM,sBAAsB,CAAA;AAI9B,IAAM,aAAA,GAAgBA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,GAAG,CAAA;AAC/C,IAAM,WAAWA,KAAA,CACnB,MAAA,EAAO,CACP,GAAA,CAAI,GAAG,EAAE,OAAA,EAAS,qCAAA,EAAuC,EACzD,GAAA,CAAI,GAAA,EAAK,EAAE,OAAA,EAAS,wCAAwC,CAAA;AAC1D,IAAM,cAAA,GAAiBA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAA,EAAM,EAAE,OAAA,EAAS,0BAAA,EAA4B,CAAA;AACnF,IAAM,gBAAA,GAAmBA,KAAA,CAC3B,MAAA,EAAO,CACP,GAAA,CAAI,IAAI,kCAAkC,CAAA,CAC1C,GAAA,CAAI,GAAA,EAAK,wBAAwB,CAAA;AAI/B,IAAM,YAAYA,KAAA,CACpB,MAAA,EAAO,CACP,GAAA,CAAI,GAAG,EAAE,OAAA,EAAS,oCAAA,EAAsC,EACxD,GAAA,CAAI,GAAA,EAAK,EAAE,OAAA,EAAS,uCAAuC,CAAA;AACzD,IAAM,gBAAA,GAAmBA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAA,EAAK,EAAE,OAAA,EAAS,yBAAA,EAA2B,CAAA;AACnF,IAAM,UAAA,GAAaA,MAAE,MAAA,EAAO,CAAE,WAAW,GAAG,CAAA,CAAE,OAAO,CAAC,CAAA;AAItD,IAAM,YAAYA,KAAA,CACpB,MAAA,EAAO,CACP,GAAA,CAAI,GAAG,EAAE,OAAA,EAAS,oCAAA,EAAsC,EACxD,GAAA,CAAI,GAAA,EAAK,EAAE,OAAA,EAAS,uCAAuC,CAAA;AACzD,IAAM,gBAAA,GAAmBA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAA,EAAK,EAAE,OAAA,EAAS,yBAAA,EAA2B,CAAA;AAInF,IAAM,aAAA,GAAgBA,MAAE,MAAA,CAAO;AAAA,EAClC,KAAA,EAAO,SAAS,QAAA,EAAS;AAAA,EACzB,WAAA,EAAa,eAAe,QAAA,EAAS;AAAA,EACrC,UAAA,EAAY,cAAc,QAAA;AAC9B,CAAC,CAAA;AAE8B,cAAc,MAAA,CAAO;AAAA,EAChD,UAAA,EAAY,oBAAA;AAAA,EACZ,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACvB,CAAC;AAIqC,cAAc,MAAA,CAAO;AAAA,EACvD,GAAA,EAAK;AACT,CAAC;AACsC,cAAc,MAAA,CAAO;AAAA,EACxD,IAAA,EAAM;AACV,CAAC;AACsC,cAAc,MAAA,CAAO;AAAA,EACxD,IAAA,EAAM;AACV,CAAC;AAC4C,cAAc,MAAA,CAAO;AAAA,EAC9D,YAAYA,KAAA,CAAE,KAAA,CAAM,CAAC,gBAAA,EAAkB,aAAa,CAAC;AACzD,CAAC;AAIM,IAAM,mBAAA,GAAsBA,MAAE,MAAA,CAAO;AAAA,EACxC,UAAA,EAAY,oBAAA;AAAA,EACZ,MAAA,EAAQA,MAAE,MAAA;AACd,CAAC,CAAA;AAEwC,oBAAoB,MAAA,CAAO;AAAA,EAChE,KAAA,EAAOA,MAAE,MAAA,EAAO;AAAA,EAChB,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACxB,CAAC;AAEqCA,MAAE,MAAA,CAAO;AAAA,EAC3C,GAAA,EAAK;AACT,CAAC;AACsCA,MAAE,MAAA,CAAO;AAAA,EAC5C,IAAA,EAAM;AACV,CAAC;AACsCA,MAAE,MAAA,CAAO;AAAA,EAC5C,IAAA,EAAM;AACV,CAAC;AAEM,IAAM,yBAAA,GAA4BA,MAAE,MAAA,CAAO;AAAA,EAC9C,KAAA,EAAOA,MAAE,MAAA,EAAO;AAAA,EAChB,QAAA,EAAUA,KAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA;AAAA,EAC5B,UAAA,EAAYA,MAAE,MAAA,EAAO;AAAA,EACrB,IAAA,EAAMA,MAAE,MAAA,EAAO;AAAA,EACf,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,OAAA,EAASA,MAAE,MAAA,EAAO;AAAA,EAClB,GAAA,EAAKA,MAAE,MAAA,EAAO,CAAE,IAAI,GAAG,CAAA,CAAE,IAAI,EAAE,CAAA;AAAA,EAC/B,GAAA,EAAKA,MAAE,MAAA,EAAO,CAAE,IAAI,IAAI,CAAA,CAAE,IAAI,GAAG;AACrC,CAAC,CAAA;AAGoD,0BAA0B,MAAA,CAAO;AAAA,EAClF,KAAA,EAAOA,MAAE,MAAA,EAAO;AAAA,EAChB,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACxB,CAAC;AAI8BA,MAAE,MAAA,CAAO;AAAA,EACpC,KAAA,EAAO,QAAA;AAAA,EACP,WAAA,EAAa,eAAe,QAAA,EAAS;AAAA,EACrC,UAAA,EAAYA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACjC,aAAA,EAAeA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACpC,GAAA,EAAKA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA;AACrC,CAAC;AAE+BA,MAAE,MAAA,CAAO;AAAA,EACrC,QAAQA,KAAA,CAAE,KAAA;AAAA,IACNA,MAAE,MAAA,CAAO;AAAA,MACL,IAAIA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAA,GAAO,QAAA,EAAS;AAAA,MAC/B,QAAA,EAAUA,MAAE,MAAA;AAAO,KACtB;AAAA,GACL;AAAA,EACA,QAAQA,KAAA,CAAE,KAAA;AAAA,IACNA,MAAE,MAAA,CAAO;AAAA,MACL,EAAA,EAAIA,MAAE,MAAA,EAAO;AAAA,MACb,SAASA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAA,GAAO,QAAA,EAAS;AAAA,MACpC,QAAA,EAAUA,MAAE,MAAA;AAAO,KACtB;AAAA;AAET,CAAC;AAEoCA,MAAE,MAAA,CAAO;AAAA,EAC1C,EAAA,EAAIA,MAAE,MAAA,EAAO;AAAA,EACb,IAAA,EAAM,SAAA;AAAA,EACN,WAAA,EAAa,iBAAiB,QAAA,EAAS;AAAA,EACvC,MAAA,EAAQA,MAAE,OAAA;AACd,CAAC;AAE2BA,MAAE,MAAA,CAAO;AAAA,EACjC,KAAA,EAAO;AACX,CAAC;AAEgCA,MAAE,MAAA,CAAO;AAAA,EACtC,IAAA,EAAM,SAAA;AAAA,EACN,WAAA,EAAa,iBAAiB,QAAA,EAAS;AAAA,EACvC,aAAA,EAAeA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACnC,KAAA,EAAO,WAAW,QAAA;AACtB,CAAC;AAE8BA,MAAE,MAAA,CAAO;AAAA,EACpC,EAAA,EAAIA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAA,EAAK;AAAA,EACpB,KAAA,EAAO,WAAW,QAAA,EAAS;AAAA,EAC3B,MAAA,EAAQA,MAAE,OAAA,EAAQ;AAAA,EAClB,IAAA,EAAM,SAAA;AAAA,EACN,WAAA,EAAa,iBAAiB,QAAA;AAClC,CAAC;AAIM,IAAM,SAAA,GAAYA,MAAE,MAAA,CAAO;AAAA,EAC9B,EAAA,EAAIA,MAAE,MAAA,EAAO;AAAA,EACb,SAAA,EAAWA,KAAA,CAAE,MAAA,CAAO,IAAA,EAAK;AAAA,EACzB,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,QAAA,EAAUA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,KAAA,EAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACrB,CAAC,CAAA;AAGkC,UAAU,MAAA,CAAO;AAAA,EAChD,QAAA,EAAUA,MAAE,MAAA;AAChB,CAAC;AAGgC,UAAU,MAAA,CAAO;AAAA,EAC9C,GAAA,EAAKA,MAAE,MAAA,EAAO;AAAA,EACd,GAAA,EAAKA,MAAE,MAAA,EAAO;AAAA,EACd,KAAA,EAAOA,MAAE,IAAA;AACb,CAAC;;;AC3ND,IAAM,cAAA,GAA0E;AAAA,EAC5E,GAAA,EAAK,eAAA;AAAA,EACL,IAAA,EAAM,eAAA;AAAA,EACN,IAAA,EAAM;AACV,CAAA;AAEA,SAAS,QAAQ,CAAA,EAAmC;AAChD,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,GAAG,MAAK,GAAI,CAAA;AACrC,EAAA,OAAO,IAAA;AACX;AA+CO,SAAS,mBAAmB,MAAA,EAA0C;AACzE,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,MAAA;AAE7B,EAAA,OAAO;AAAA,IACH,MAAM,mBACF,OAAA,EACiC;AACjC,MAAA,IAAI,aAA+B,EAAC;AACpC,MAAA,IAAI,KAAA,GAAgB,cAAA,CAAe,OAAA,CAAQ,UAAU,CAAA;AACrD,MAAA,IAAI,KAAA,GAA8B,MAAA;AAClC,MAAA,IAAI,qBAAA,GAA4C,MAAA;AAChD,MAAA,IAAI,oBAAA,GAA2C,MAAA;AAE/C,MAAA,QAAQ,QAAQ,UAAA;AAAY,QACxB,KAAK,KAAA,EAAO;AACR,UAAA,MAAM,GAAA,GAAM,aAAA,CAAc,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AAC9C,UAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,qBAAA,CAAsB,GAAG,CAAA;AAClD,UAAA,UAAA,GAAa,IAAI,MAAA,CAAO,SAAA;AACxB,UAAA,IAAI,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,KAAA,GAAQ,IAAI,MAAA,CAAO,KAAA;AACzC,UAAA,qBAAA,GAAwB,GAAA,CAAI,qBAAA;AAC5B,UAAA,oBAAA,GAAuB,GAAA,CAAI,oBAAA;AAC3B,UAAA,KAAA,GAAQ,QAAQ,GAAG,CAAA;AACnB,UAAA;AAAA,QACJ;AAAA,QACA,KAAK,MAAA,EAAQ;AACT,UAAA,MAAM,IAAA,GAAO,cAAA,CAAe,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AAChD,UAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,sBAAA,CAAuB,IAAI,CAAA;AACpD,UAAA,UAAA,GAAa,IAAI,MAAA,CAAO,SAAA;AACxB,UAAA,IAAI,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,KAAA,GAAQ,IAAI,MAAA,CAAO,KAAA;AACzC,UAAA,qBAAA,GAAwB,GAAA,CAAI,qBAAA;AAC5B,UAAA,oBAAA,GAAuB,GAAA,CAAI,oBAAA;AAC3B,UAAA,KAAA,GAAQ,QAAQ,GAAG,CAAA;AACnB,UAAA;AAAA,QACJ;AAAA,QACA,KAAK,MAAA,EAAQ;AACT,UAAA,MAAM,IAAA,GAAO,cAAA,CAAe,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AAChD,UAAA,UAAA,GAAa,IAAA,CACR,IAAA,EAAK,CACL,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,CAAC,IAAA,MAAU,EAAE,OAAA,EAAS,IAAA,EAAM,WAAA,EAAa,IAAG,CAAE,CAAA;AACvD,UAAA;AAAA,QACJ;AAAA,QACA,SAAS;AACL,UAAA,MAAM,WAAA,GAAqB,OAAA;AAC3B,UAAA,MAAM,IAAI,KAAA;AAAA,YACN,CAAA,wBAAA,EAA4B,YAAuC,UAAU,CAAA;AAAA,WACjF;AAAA,QACJ;AAAA;AAGJ,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,WAAA,CAAY,UAAU,CAAA;AAEpD,MAAA,OAAO;AAAA,QACH,KAAA;AAAA,QACA,MAAA;AAAA,QACA,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,qBAAA;AAAA,QACA,oBAAA;AAAA,QACA;AAAA,OACJ;AAAA,IACJ;AAAA,GACJ;AACJ","file":"index.cjs","sourcesContent":["import { z } from \"zod\"\n\n/**\n * Runtime validation schemas and their inferred types.\n *\n * These schemas define the public contract between producers and consumers of\n * mapthis data. They are intentionally framework-agnostic — no Prisma, no\n * Next.js, no auth assumptions.\n */\n\n// --- Providers & source types ------------------------------------------------\n\nexport const llmProvider = z.literal(\"openai\") // TODO: add other LLM support\nexport type LlmProvider = z.infer<typeof llmProvider>\n\nexport const placeProvider = z.union([z.literal(\"google\"), z.literal(\"locationiq\")])\nexport type PlaceProvider = z.infer<typeof placeProvider>\n\nexport const generationSourceType = z.union([\n z.literal(\"blank\"),\n z.literal(\"autocomplete\"),\n z.literal(\"url\"),\n z.literal(\"text\"),\n z.literal(\"list\"),\n])\nexport type GenerationSourceType = z.infer<typeof generationSourceType>\n\n// --- Geographic primitives ---------------------------------------------------\n\nexport const latitude = z.coerce.number().min(-90, \"Min latitude is -90\").max(90, \"Max latitude is 90\")\nexport const longitude = z.coerce.number().min(-180, \"Min longitude is -180\").max(180, \"Max longitude is 180\")\n\nexport const coordinates = z.object({\n lat: latitude,\n lng: longitude,\n})\nexport type Coordinates = z.infer<typeof coordinates>\n\n// --- Input schemas (freeform sources) ----------------------------------------\n\nexport const placesFromUrl = z.string().url({ message: \"Invalid url\" }).min(6).max(2048)\n\nexport const placesFromList = z\n .preprocess(\n (v) =>\n String(v)\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => !!line)\n .join(\"\\n\"),\n z.string().min(6, \"Must be at least 6 characters\").max(1000, \"List too long\"),\n )\n .refine(\n (v) => !v.split(\"\\n\").find((line) => line.length < 2),\n \"All lines must be at least 2 characters\",\n )\n\nexport const placesFromText = z\n .string()\n .min(6, \"Must be at least 6 characters\")\n .max(2000, \"Over character limit\")\n\n// --- Map field schemas -------------------------------------------------------\n\nexport const mapExternalId = z.string().min(6).max(100)\nexport const mapTitle = z\n .string()\n .min(3, { message: \"Title must be at least 3 characters\" })\n .max(100, { message: \"Title must be at most 100 characters\" })\nexport const mapDescription = z.string().max(1000, { message: \"Limit is 1000 characters\" })\nexport const mapCreationQuery = z\n .string()\n .min(10, \"Minimum 10 characters for search\")\n .max(200, \"Maximum 200 characters\")\n\n// --- Group field schemas -----------------------------------------------------\n\nexport const groupName = z\n .string()\n .min(3, { message: \"Name must be at least 3 characters\" })\n .max(200, { message: \"Name must be at most 200 characters\" })\nexport const groupDescription = z.string().max(400, { message: \"Limit is 400 characters\" })\nexport const groupColor = z.string().startsWith(\"#\").length(7)\n\n// --- Place field schemas -----------------------------------------------------\n\nexport const placeName = z\n .string()\n .min(2, { message: \"Name must be at least 2 characters\" })\n .max(200, { message: \"Name must be at most 200 characters\" })\nexport const placeDescription = z.string().max(400, { message: \"Limit is 400 characters\" })\n\n// --- Map creation composites -------------------------------------------------\n\nexport const createMapBase = z.object({\n title: mapTitle.optional(),\n description: mapDescription.optional(),\n externalId: mapExternalId.optional(),\n})\n\nexport const createMapSchema = createMapBase.extend({\n sourceType: generationSourceType,\n source: z.string().optional(),\n})\n\nexport const createBlankMapSchema = createMapBase\n\nexport const createMapFromUrlSchema = createMapBase.extend({\n url: placesFromUrl,\n})\nexport const createMapFromListSchema = createMapBase.extend({\n list: placesFromList,\n})\nexport const createMapFromTextSchema = createMapBase.extend({\n text: placesFromText,\n})\nexport const createMapFromQueryOrUrlSchema = createMapBase.extend({\n queryOrUrl: z.union([mapCreationQuery, placesFromUrl]),\n})\n\n// --- Adding places -----------------------------------------------------------\n\nexport const addPlacesBaseSchema = z.object({\n sourceType: generationSourceType,\n source: z.string(),\n})\n\nexport const addPlacesFromSourceSchema = addPlacesBaseSchema.extend({\n mapId: z.string(),\n groupId: z.string().optional(),\n})\n\nexport const addPlacesFromUrlSchema = z.object({\n url: placesFromUrl,\n})\nexport const addPlacesFromListSchema = z.object({\n list: placesFromList,\n})\nexport const addPlacesFromTextSchema = z.object({\n text: placesFromText,\n})\n\nexport const providerAutocompletePlace = z.object({\n query: z.string(),\n provider: z.literal(\"google\"),\n providerId: z.string(),\n name: z.string(),\n description: z.string().optional(),\n address: z.string(),\n lat: z.number().min(-90).max(90),\n lng: z.number().min(-180).max(180),\n})\nexport type ProviderAutocompletePlace = z.infer<typeof providerAutocompletePlace>\n\nexport const addPlacesFromClientAutocompleteSchema = providerAutocompletePlace.extend({\n mapId: z.string(),\n groupId: z.string().optional(),\n})\n\n// --- Updates -----------------------------------------------------------------\n\nexport const updateMapSchema = z.object({\n title: mapTitle,\n description: mapDescription.optional(),\n userPublic: z.boolean().optional(),\n partnerPublic: z.boolean().optional(),\n url: z.string().url().nullable().optional(),\n})\n\nexport const reorderMapSchema = z.object({\n groups: z.array(\n z.object({\n id: z.string().uuid().nullable(),\n position: z.number(),\n }),\n ),\n places: z.array(\n z.object({\n id: z.string(),\n groupId: z.string().uuid().nullable(),\n position: z.number(),\n }),\n ),\n})\n\nexport const updatePlaceFormSchema = z.object({\n id: z.string(),\n name: placeName,\n description: placeDescription.optional(),\n hidden: z.boolean(),\n})\n\nexport const searchSchema = z.object({\n query: mapCreationQuery,\n})\n\nexport const createGroupSchema = z.object({\n name: groupName,\n description: groupDescription.optional(),\n parentGroupId: z.string().optional(),\n color: groupColor.optional(),\n})\n\nexport const editGroupSchema = z.object({\n id: z.string().uuid(),\n color: groupColor.nullable(),\n hidden: z.boolean(),\n name: groupName,\n description: groupDescription.optional(),\n})\n\n// --- Place metadata (lightweight projections) --------------------------------\n\nexport const placeMeta = z.object({\n id: z.string(),\n updatedAt: z.coerce.date(),\n groupId: z.string().nullable(),\n position: z.number().nullable(),\n error: z.string().nullable(),\n lat: z.number().nullable(),\n lon: z.number().nullable(),\n name: z.string().nullable(),\n})\nexport type PlaceMeta = z.infer<typeof placeMeta>\n\nexport const positionedPlaceMeta = placeMeta.extend({\n position: z.number(),\n})\nexport type PositionedPlaceMeta = z.infer<typeof positionedPlaceMeta>\n\nexport const mappablePlaceMeta = placeMeta.extend({\n lat: z.number(),\n lon: z.number(),\n error: z.null(),\n})\nexport type MappablePlaceMeta = z.infer<typeof mappablePlaceMeta>\n\n/**\n * Filter a list of place projections down to those that are mappable\n * (have coordinates and no error).\n */\nexport function getMappablePlaceMetas(\n places: (PlaceMeta | null | undefined)[],\n): MappablePlaceMeta[] {\n const good: MappablePlaceMeta[] = []\n for (const p of places) {\n const parsed = mappablePlaceMeta.safeParse(p)\n if (parsed.success) good.push(parsed.data)\n }\n return good\n}\n","import type { GetLocationsResponse } from \"../ai\"\nimport type { ParsedLocation } from \"../types/domain\"\nimport { placesFromList, placesFromText, placesFromUrl } from \"../types/schemas\"\nimport type {\n GenerateFromSourceOptions,\n GenerateFromSourceResult,\n LlmUsage,\n MapGenerator,\n MapGeneratorConfig,\n} from \"./types\"\n\n/**\n * Default titles when the LLM does not return one. These match what the\n * private app has historically used so migrated data stays consistent.\n */\nconst DEFAULT_TITLES: Record<GenerateFromSourceOptions[\"sourceType\"], string> = {\n url: \"Map from Site\",\n text: \"Map from Text\",\n list: \"Map from List\",\n}\n\nfunction toUsage(r: GetLocationsResponse): LlmUsage {\n const { output: _output, ...rest } = r\n return rest\n}\n\n/**\n * Create a {@link MapGenerator} that wires a {@link LocationParser} and\n * {@link GeocodingProvider} together.\n *\n * @example\n * ```ts\n * import { createLocationParser } from \"mapthis/ai\"\n * import { createGeocoder } from \"mapthis/geocoding\"\n * import { createMapGenerator } from \"mapthis/generate\"\n *\n * const generator = createMapGenerator({\n * parser: createLocationParser({ apiKey: process.env.OPENAI_API_KEY! }),\n * geocoder: createGeocoder({ provider: \"google\", apiKey: process.env.GOOGLE_MAPS_KEY! }),\n * })\n *\n * const result = await generator.generateFromSource({\n * sourceType: \"url\",\n * source: \"https://example.com/best-restaurants-tokyo\",\n * })\n *\n * // Persist in your own DB:\n * await db.$transaction(async (tx) => {\n * const map = await tx.map.create({ data: { title: result.title, ... } })\n * const group = await tx.placeGroup.create({ data: { mapId: map.id, ... } })\n * await tx.place.createMany({\n * data: result.places.map((p, i) => ({\n * mapId: map.id,\n * groupId: group.id,\n * position: i,\n * query: p.input.address,\n * description: p.input.description,\n * name: p.data?.name,\n * address: p.data?.address,\n * lat: p.data?.lat,\n * lon: p.data?.lng,\n * provider: p.data?.provider,\n * providerId: p.data?.providerId,\n * error: p.error,\n * locationPromptVersion: result.locationPromptVersion,\n * summaryPromptVersion: result.summaryPromptVersion,\n * })),\n * })\n * })\n * ```\n */\nexport function createMapGenerator(config: MapGeneratorConfig): MapGenerator {\n const { parser, geocoder } = config\n\n return {\n async generateFromSource(\n options: GenerateFromSourceOptions,\n ): Promise<GenerateFromSourceResult> {\n let parsedLocs: ParsedLocation[] = []\n let title: string = DEFAULT_TITLES[options.sourceType]\n let usage: LlmUsage | undefined = undefined\n let locationPromptVersion: string | undefined = undefined\n let summaryPromptVersion: string | undefined = undefined\n\n switch (options.sourceType) {\n case \"url\": {\n const url = placesFromUrl.parse(options.source)\n const llm = await parser.parseLocationsFromUrl(url)\n parsedLocs = llm.output.locations\n if (llm.output.title) title = llm.output.title\n locationPromptVersion = llm.locationPromptVersion\n summaryPromptVersion = llm.summaryPromptVersion\n usage = toUsage(llm)\n break\n }\n case \"text\": {\n const text = placesFromText.parse(options.source)\n const llm = await parser.parseLocationsFromText(text)\n parsedLocs = llm.output.locations\n if (llm.output.title) title = llm.output.title\n locationPromptVersion = llm.locationPromptVersion\n summaryPromptVersion = llm.summaryPromptVersion\n usage = toUsage(llm)\n break\n }\n case \"list\": {\n const list = placesFromList.parse(options.source)\n parsedLocs = list\n .trim()\n .split(\"\\n\")\n .map((line) => ({ address: line, description: \"\" }))\n break\n }\n default: {\n const _exhaustive: never = options\n throw new Error(\n `Unsupported sourceType: ${(_exhaustive as { sourceType: string }).sourceType}`,\n )\n }\n }\n\n const places = await geocoder.geocodeMany(parsedLocs)\n\n return {\n title,\n places,\n sourceType: options.sourceType,\n source: options.source,\n locationPromptVersion,\n summaryPromptVersion,\n usage,\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { G as GetLocationsResponse, L as LocationParser } from '../parser-CzXzpmVv.cjs';
|
|
2
|
+
import { G as GeocodingProvider } from '../types-rFjK5YcJ.cjs';
|
|
3
|
+
import { i as PlaceQueryResult } from '../domain-Dc1wSTkf.cjs';
|
|
4
|
+
import 'json-schema';
|
|
5
|
+
import '../schemas-Dy5coqXo.cjs';
|
|
6
|
+
import 'zod';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Narrow subset of {@link import("../types/schemas").GenerationSourceType}
|
|
10
|
+
* that the generator actually handles. `blank` and `autocomplete` are
|
|
11
|
+
* application concerns (blank has no source to parse; autocomplete uses a
|
|
12
|
+
* pre-resolved place from the client) and are left for the caller.
|
|
13
|
+
*/
|
|
14
|
+
type GenerateSourceType = "url" | "text" | "list";
|
|
15
|
+
/**
|
|
16
|
+
* Options for a single map-generation run. Discriminated by `sourceType`.
|
|
17
|
+
*/
|
|
18
|
+
type GenerateFromSourceOptions = {
|
|
19
|
+
sourceType: "url";
|
|
20
|
+
source: string;
|
|
21
|
+
} | {
|
|
22
|
+
sourceType: "text";
|
|
23
|
+
source: string;
|
|
24
|
+
} | {
|
|
25
|
+
sourceType: "list";
|
|
26
|
+
source: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* LLM usage metadata from a {@link GenerateFromSourceResult}, with the
|
|
30
|
+
* `output` field (the parsed locations) stripped since it is already
|
|
31
|
+
* surfaced at the top of the result as `title` and `places`.
|
|
32
|
+
*/
|
|
33
|
+
type LlmUsage = Omit<GetLocationsResponse, "output">;
|
|
34
|
+
/**
|
|
35
|
+
* The plain data structure returned by a map-generation run.
|
|
36
|
+
*
|
|
37
|
+
* The generator is deliberately persistence-free: it returns everything
|
|
38
|
+
* needed to write a Map + PlaceGroup + Places to your database, but leaves
|
|
39
|
+
* the transaction, auth, and ID assignment to the caller.
|
|
40
|
+
*/
|
|
41
|
+
interface GenerateFromSourceResult {
|
|
42
|
+
/**
|
|
43
|
+
* Title derived from the LLM output (for `url`/`text` sources) or a
|
|
44
|
+
* sensible default (for `list`).
|
|
45
|
+
*/
|
|
46
|
+
title: string;
|
|
47
|
+
/**
|
|
48
|
+
* Geocoded places, one per parsed location. Order matches the LLM's
|
|
49
|
+
* output order (or the list line order for `list` sources). Individual
|
|
50
|
+
* entries may have `data: null` if geocoding failed; the caller decides
|
|
51
|
+
* whether to persist those as error rows or drop them.
|
|
52
|
+
*/
|
|
53
|
+
places: PlaceQueryResult[];
|
|
54
|
+
/** Echo of the input, for convenience when building DB rows. */
|
|
55
|
+
sourceType: GenerateSourceType;
|
|
56
|
+
source: string;
|
|
57
|
+
/**
|
|
58
|
+
* Version tag for the location-extraction prompt that produced these
|
|
59
|
+
* results. Undefined for `list` sources (no LLM call). Persist this
|
|
60
|
+
* alongside each place so you can re-run outdated rows when you bump a
|
|
61
|
+
* prompt.
|
|
62
|
+
*/
|
|
63
|
+
locationPromptVersion: string | undefined;
|
|
64
|
+
/** Version tag for the summarization prompt. Undefined for `list`. */
|
|
65
|
+
summaryPromptVersion: string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Full token and call accounting from the LLM pipeline. Undefined for
|
|
68
|
+
* `list` sources. Use this for billing/usage tracking.
|
|
69
|
+
*/
|
|
70
|
+
usage: LlmUsage | undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Dependencies required to construct a map generator. The generator itself
|
|
74
|
+
* is stateless — it just composes these two clients.
|
|
75
|
+
*/
|
|
76
|
+
interface MapGeneratorConfig {
|
|
77
|
+
parser: LocationParser;
|
|
78
|
+
geocoder: GeocodingProvider;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A configured map-generation pipeline. Safe to hold for the lifetime of
|
|
82
|
+
* the app.
|
|
83
|
+
*/
|
|
84
|
+
interface MapGenerator {
|
|
85
|
+
/**
|
|
86
|
+
* Parse a source into locations, geocode each one, and return the
|
|
87
|
+
* combined result. Does not touch any database; the caller is
|
|
88
|
+
* responsible for persistence.
|
|
89
|
+
*/
|
|
90
|
+
generateFromSource(options: GenerateFromSourceOptions): Promise<GenerateFromSourceResult>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a {@link MapGenerator} that wires a {@link LocationParser} and
|
|
95
|
+
* {@link GeocodingProvider} together.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { createLocationParser } from "mapthis/ai"
|
|
100
|
+
* import { createGeocoder } from "mapthis/geocoding"
|
|
101
|
+
* import { createMapGenerator } from "mapthis/generate"
|
|
102
|
+
*
|
|
103
|
+
* const generator = createMapGenerator({
|
|
104
|
+
* parser: createLocationParser({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
105
|
+
* geocoder: createGeocoder({ provider: "google", apiKey: process.env.GOOGLE_MAPS_KEY! }),
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* const result = await generator.generateFromSource({
|
|
109
|
+
* sourceType: "url",
|
|
110
|
+
* source: "https://example.com/best-restaurants-tokyo",
|
|
111
|
+
* })
|
|
112
|
+
*
|
|
113
|
+
* // Persist in your own DB:
|
|
114
|
+
* await db.$transaction(async (tx) => {
|
|
115
|
+
* const map = await tx.map.create({ data: { title: result.title, ... } })
|
|
116
|
+
* const group = await tx.placeGroup.create({ data: { mapId: map.id, ... } })
|
|
117
|
+
* await tx.place.createMany({
|
|
118
|
+
* data: result.places.map((p, i) => ({
|
|
119
|
+
* mapId: map.id,
|
|
120
|
+
* groupId: group.id,
|
|
121
|
+
* position: i,
|
|
122
|
+
* query: p.input.address,
|
|
123
|
+
* description: p.input.description,
|
|
124
|
+
* name: p.data?.name,
|
|
125
|
+
* address: p.data?.address,
|
|
126
|
+
* lat: p.data?.lat,
|
|
127
|
+
* lon: p.data?.lng,
|
|
128
|
+
* provider: p.data?.provider,
|
|
129
|
+
* providerId: p.data?.providerId,
|
|
130
|
+
* error: p.error,
|
|
131
|
+
* locationPromptVersion: result.locationPromptVersion,
|
|
132
|
+
* summaryPromptVersion: result.summaryPromptVersion,
|
|
133
|
+
* })),
|
|
134
|
+
* })
|
|
135
|
+
* })
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
declare function createMapGenerator(config: MapGeneratorConfig): MapGenerator;
|
|
139
|
+
|
|
140
|
+
export { type GenerateFromSourceOptions, type GenerateFromSourceResult, type GenerateSourceType, type LlmUsage, type MapGenerator, type MapGeneratorConfig, createMapGenerator };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { G as GetLocationsResponse, L as LocationParser } from '../parser-N7-fNxeu.js';
|
|
2
|
+
import { G as GeocodingProvider } from '../types-BhqKlq0k.js';
|
|
3
|
+
import { i as PlaceQueryResult } from '../domain-CZ-L-ntu.js';
|
|
4
|
+
import 'json-schema';
|
|
5
|
+
import '../schemas-Dy5coqXo.js';
|
|
6
|
+
import 'zod';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Narrow subset of {@link import("../types/schemas").GenerationSourceType}
|
|
10
|
+
* that the generator actually handles. `blank` and `autocomplete` are
|
|
11
|
+
* application concerns (blank has no source to parse; autocomplete uses a
|
|
12
|
+
* pre-resolved place from the client) and are left for the caller.
|
|
13
|
+
*/
|
|
14
|
+
type GenerateSourceType = "url" | "text" | "list";
|
|
15
|
+
/**
|
|
16
|
+
* Options for a single map-generation run. Discriminated by `sourceType`.
|
|
17
|
+
*/
|
|
18
|
+
type GenerateFromSourceOptions = {
|
|
19
|
+
sourceType: "url";
|
|
20
|
+
source: string;
|
|
21
|
+
} | {
|
|
22
|
+
sourceType: "text";
|
|
23
|
+
source: string;
|
|
24
|
+
} | {
|
|
25
|
+
sourceType: "list";
|
|
26
|
+
source: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* LLM usage metadata from a {@link GenerateFromSourceResult}, with the
|
|
30
|
+
* `output` field (the parsed locations) stripped since it is already
|
|
31
|
+
* surfaced at the top of the result as `title` and `places`.
|
|
32
|
+
*/
|
|
33
|
+
type LlmUsage = Omit<GetLocationsResponse, "output">;
|
|
34
|
+
/**
|
|
35
|
+
* The plain data structure returned by a map-generation run.
|
|
36
|
+
*
|
|
37
|
+
* The generator is deliberately persistence-free: it returns everything
|
|
38
|
+
* needed to write a Map + PlaceGroup + Places to your database, but leaves
|
|
39
|
+
* the transaction, auth, and ID assignment to the caller.
|
|
40
|
+
*/
|
|
41
|
+
interface GenerateFromSourceResult {
|
|
42
|
+
/**
|
|
43
|
+
* Title derived from the LLM output (for `url`/`text` sources) or a
|
|
44
|
+
* sensible default (for `list`).
|
|
45
|
+
*/
|
|
46
|
+
title: string;
|
|
47
|
+
/**
|
|
48
|
+
* Geocoded places, one per parsed location. Order matches the LLM's
|
|
49
|
+
* output order (or the list line order for `list` sources). Individual
|
|
50
|
+
* entries may have `data: null` if geocoding failed; the caller decides
|
|
51
|
+
* whether to persist those as error rows or drop them.
|
|
52
|
+
*/
|
|
53
|
+
places: PlaceQueryResult[];
|
|
54
|
+
/** Echo of the input, for convenience when building DB rows. */
|
|
55
|
+
sourceType: GenerateSourceType;
|
|
56
|
+
source: string;
|
|
57
|
+
/**
|
|
58
|
+
* Version tag for the location-extraction prompt that produced these
|
|
59
|
+
* results. Undefined for `list` sources (no LLM call). Persist this
|
|
60
|
+
* alongside each place so you can re-run outdated rows when you bump a
|
|
61
|
+
* prompt.
|
|
62
|
+
*/
|
|
63
|
+
locationPromptVersion: string | undefined;
|
|
64
|
+
/** Version tag for the summarization prompt. Undefined for `list`. */
|
|
65
|
+
summaryPromptVersion: string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Full token and call accounting from the LLM pipeline. Undefined for
|
|
68
|
+
* `list` sources. Use this for billing/usage tracking.
|
|
69
|
+
*/
|
|
70
|
+
usage: LlmUsage | undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Dependencies required to construct a map generator. The generator itself
|
|
74
|
+
* is stateless — it just composes these two clients.
|
|
75
|
+
*/
|
|
76
|
+
interface MapGeneratorConfig {
|
|
77
|
+
parser: LocationParser;
|
|
78
|
+
geocoder: GeocodingProvider;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A configured map-generation pipeline. Safe to hold for the lifetime of
|
|
82
|
+
* the app.
|
|
83
|
+
*/
|
|
84
|
+
interface MapGenerator {
|
|
85
|
+
/**
|
|
86
|
+
* Parse a source into locations, geocode each one, and return the
|
|
87
|
+
* combined result. Does not touch any database; the caller is
|
|
88
|
+
* responsible for persistence.
|
|
89
|
+
*/
|
|
90
|
+
generateFromSource(options: GenerateFromSourceOptions): Promise<GenerateFromSourceResult>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a {@link MapGenerator} that wires a {@link LocationParser} and
|
|
95
|
+
* {@link GeocodingProvider} together.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { createLocationParser } from "mapthis/ai"
|
|
100
|
+
* import { createGeocoder } from "mapthis/geocoding"
|
|
101
|
+
* import { createMapGenerator } from "mapthis/generate"
|
|
102
|
+
*
|
|
103
|
+
* const generator = createMapGenerator({
|
|
104
|
+
* parser: createLocationParser({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
105
|
+
* geocoder: createGeocoder({ provider: "google", apiKey: process.env.GOOGLE_MAPS_KEY! }),
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* const result = await generator.generateFromSource({
|
|
109
|
+
* sourceType: "url",
|
|
110
|
+
* source: "https://example.com/best-restaurants-tokyo",
|
|
111
|
+
* })
|
|
112
|
+
*
|
|
113
|
+
* // Persist in your own DB:
|
|
114
|
+
* await db.$transaction(async (tx) => {
|
|
115
|
+
* const map = await tx.map.create({ data: { title: result.title, ... } })
|
|
116
|
+
* const group = await tx.placeGroup.create({ data: { mapId: map.id, ... } })
|
|
117
|
+
* await tx.place.createMany({
|
|
118
|
+
* data: result.places.map((p, i) => ({
|
|
119
|
+
* mapId: map.id,
|
|
120
|
+
* groupId: group.id,
|
|
121
|
+
* position: i,
|
|
122
|
+
* query: p.input.address,
|
|
123
|
+
* description: p.input.description,
|
|
124
|
+
* name: p.data?.name,
|
|
125
|
+
* address: p.data?.address,
|
|
126
|
+
* lat: p.data?.lat,
|
|
127
|
+
* lon: p.data?.lng,
|
|
128
|
+
* provider: p.data?.provider,
|
|
129
|
+
* providerId: p.data?.providerId,
|
|
130
|
+
* error: p.error,
|
|
131
|
+
* locationPromptVersion: result.locationPromptVersion,
|
|
132
|
+
* summaryPromptVersion: result.summaryPromptVersion,
|
|
133
|
+
* })),
|
|
134
|
+
* })
|
|
135
|
+
* })
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
declare function createMapGenerator(config: MapGeneratorConfig): MapGenerator;
|
|
139
|
+
|
|
140
|
+
export { type GenerateFromSourceOptions, type GenerateFromSourceResult, type GenerateSourceType, type LlmUsage, type MapGenerator, type MapGeneratorConfig, createMapGenerator };
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// src/types/schemas.ts
|
|
4
|
+
z.literal("openai");
|
|
5
|
+
z.union([z.literal("google"), z.literal("locationiq")]);
|
|
6
|
+
var generationSourceType = z.union([
|
|
7
|
+
z.literal("blank"),
|
|
8
|
+
z.literal("autocomplete"),
|
|
9
|
+
z.literal("url"),
|
|
10
|
+
z.literal("text"),
|
|
11
|
+
z.literal("list")
|
|
12
|
+
]);
|
|
13
|
+
var latitude = z.coerce.number().min(-90, "Min latitude is -90").max(90, "Max latitude is 90");
|
|
14
|
+
var longitude = z.coerce.number().min(-180, "Min longitude is -180").max(180, "Max longitude is 180");
|
|
15
|
+
z.object({
|
|
16
|
+
lat: latitude,
|
|
17
|
+
lng: longitude
|
|
18
|
+
});
|
|
19
|
+
var placesFromUrl = z.string().url({ message: "Invalid url" }).min(6).max(2048);
|
|
20
|
+
var placesFromList = z.preprocess(
|
|
21
|
+
(v) => String(v).split("\n").map((line) => line.trim()).filter((line) => !!line).join("\n"),
|
|
22
|
+
z.string().min(6, "Must be at least 6 characters").max(1e3, "List too long")
|
|
23
|
+
).refine(
|
|
24
|
+
(v) => !v.split("\n").find((line) => line.length < 2),
|
|
25
|
+
"All lines must be at least 2 characters"
|
|
26
|
+
);
|
|
27
|
+
var placesFromText = z.string().min(6, "Must be at least 6 characters").max(2e3, "Over character limit");
|
|
28
|
+
var mapExternalId = z.string().min(6).max(100);
|
|
29
|
+
var mapTitle = z.string().min(3, { message: "Title must be at least 3 characters" }).max(100, { message: "Title must be at most 100 characters" });
|
|
30
|
+
var mapDescription = z.string().max(1e3, { message: "Limit is 1000 characters" });
|
|
31
|
+
var mapCreationQuery = z.string().min(10, "Minimum 10 characters for search").max(200, "Maximum 200 characters");
|
|
32
|
+
var groupName = z.string().min(3, { message: "Name must be at least 3 characters" }).max(200, { message: "Name must be at most 200 characters" });
|
|
33
|
+
var groupDescription = z.string().max(400, { message: "Limit is 400 characters" });
|
|
34
|
+
var groupColor = z.string().startsWith("#").length(7);
|
|
35
|
+
var placeName = z.string().min(2, { message: "Name must be at least 2 characters" }).max(200, { message: "Name must be at most 200 characters" });
|
|
36
|
+
var placeDescription = z.string().max(400, { message: "Limit is 400 characters" });
|
|
37
|
+
var createMapBase = z.object({
|
|
38
|
+
title: mapTitle.optional(),
|
|
39
|
+
description: mapDescription.optional(),
|
|
40
|
+
externalId: mapExternalId.optional()
|
|
41
|
+
});
|
|
42
|
+
createMapBase.extend({
|
|
43
|
+
sourceType: generationSourceType,
|
|
44
|
+
source: z.string().optional()
|
|
45
|
+
});
|
|
46
|
+
createMapBase.extend({
|
|
47
|
+
url: placesFromUrl
|
|
48
|
+
});
|
|
49
|
+
createMapBase.extend({
|
|
50
|
+
list: placesFromList
|
|
51
|
+
});
|
|
52
|
+
createMapBase.extend({
|
|
53
|
+
text: placesFromText
|
|
54
|
+
});
|
|
55
|
+
createMapBase.extend({
|
|
56
|
+
queryOrUrl: z.union([mapCreationQuery, placesFromUrl])
|
|
57
|
+
});
|
|
58
|
+
var addPlacesBaseSchema = z.object({
|
|
59
|
+
sourceType: generationSourceType,
|
|
60
|
+
source: z.string()
|
|
61
|
+
});
|
|
62
|
+
addPlacesBaseSchema.extend({
|
|
63
|
+
mapId: z.string(),
|
|
64
|
+
groupId: z.string().optional()
|
|
65
|
+
});
|
|
66
|
+
z.object({
|
|
67
|
+
url: placesFromUrl
|
|
68
|
+
});
|
|
69
|
+
z.object({
|
|
70
|
+
list: placesFromList
|
|
71
|
+
});
|
|
72
|
+
z.object({
|
|
73
|
+
text: placesFromText
|
|
74
|
+
});
|
|
75
|
+
var providerAutocompletePlace = z.object({
|
|
76
|
+
query: z.string(),
|
|
77
|
+
provider: z.literal("google"),
|
|
78
|
+
providerId: z.string(),
|
|
79
|
+
name: z.string(),
|
|
80
|
+
description: z.string().optional(),
|
|
81
|
+
address: z.string(),
|
|
82
|
+
lat: z.number().min(-90).max(90),
|
|
83
|
+
lng: z.number().min(-180).max(180)
|
|
84
|
+
});
|
|
85
|
+
providerAutocompletePlace.extend({
|
|
86
|
+
mapId: z.string(),
|
|
87
|
+
groupId: z.string().optional()
|
|
88
|
+
});
|
|
89
|
+
z.object({
|
|
90
|
+
title: mapTitle,
|
|
91
|
+
description: mapDescription.optional(),
|
|
92
|
+
userPublic: z.boolean().optional(),
|
|
93
|
+
partnerPublic: z.boolean().optional(),
|
|
94
|
+
url: z.string().url().nullable().optional()
|
|
95
|
+
});
|
|
96
|
+
z.object({
|
|
97
|
+
groups: z.array(
|
|
98
|
+
z.object({
|
|
99
|
+
id: z.string().uuid().nullable(),
|
|
100
|
+
position: z.number()
|
|
101
|
+
})
|
|
102
|
+
),
|
|
103
|
+
places: z.array(
|
|
104
|
+
z.object({
|
|
105
|
+
id: z.string(),
|
|
106
|
+
groupId: z.string().uuid().nullable(),
|
|
107
|
+
position: z.number()
|
|
108
|
+
})
|
|
109
|
+
)
|
|
110
|
+
});
|
|
111
|
+
z.object({
|
|
112
|
+
id: z.string(),
|
|
113
|
+
name: placeName,
|
|
114
|
+
description: placeDescription.optional(),
|
|
115
|
+
hidden: z.boolean()
|
|
116
|
+
});
|
|
117
|
+
z.object({
|
|
118
|
+
query: mapCreationQuery
|
|
119
|
+
});
|
|
120
|
+
z.object({
|
|
121
|
+
name: groupName,
|
|
122
|
+
description: groupDescription.optional(),
|
|
123
|
+
parentGroupId: z.string().optional(),
|
|
124
|
+
color: groupColor.optional()
|
|
125
|
+
});
|
|
126
|
+
z.object({
|
|
127
|
+
id: z.string().uuid(),
|
|
128
|
+
color: groupColor.nullable(),
|
|
129
|
+
hidden: z.boolean(),
|
|
130
|
+
name: groupName,
|
|
131
|
+
description: groupDescription.optional()
|
|
132
|
+
});
|
|
133
|
+
var placeMeta = z.object({
|
|
134
|
+
id: z.string(),
|
|
135
|
+
updatedAt: z.coerce.date(),
|
|
136
|
+
groupId: z.string().nullable(),
|
|
137
|
+
position: z.number().nullable(),
|
|
138
|
+
error: z.string().nullable(),
|
|
139
|
+
lat: z.number().nullable(),
|
|
140
|
+
lon: z.number().nullable(),
|
|
141
|
+
name: z.string().nullable()
|
|
142
|
+
});
|
|
143
|
+
placeMeta.extend({
|
|
144
|
+
position: z.number()
|
|
145
|
+
});
|
|
146
|
+
placeMeta.extend({
|
|
147
|
+
lat: z.number(),
|
|
148
|
+
lon: z.number(),
|
|
149
|
+
error: z.null()
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// src/generate/generator.ts
|
|
153
|
+
var DEFAULT_TITLES = {
|
|
154
|
+
url: "Map from Site",
|
|
155
|
+
text: "Map from Text",
|
|
156
|
+
list: "Map from List"
|
|
157
|
+
};
|
|
158
|
+
function toUsage(r) {
|
|
159
|
+
const { output: _output, ...rest } = r;
|
|
160
|
+
return rest;
|
|
161
|
+
}
|
|
162
|
+
function createMapGenerator(config) {
|
|
163
|
+
const { parser, geocoder } = config;
|
|
164
|
+
return {
|
|
165
|
+
async generateFromSource(options) {
|
|
166
|
+
let parsedLocs = [];
|
|
167
|
+
let title = DEFAULT_TITLES[options.sourceType];
|
|
168
|
+
let usage = void 0;
|
|
169
|
+
let locationPromptVersion = void 0;
|
|
170
|
+
let summaryPromptVersion = void 0;
|
|
171
|
+
switch (options.sourceType) {
|
|
172
|
+
case "url": {
|
|
173
|
+
const url = placesFromUrl.parse(options.source);
|
|
174
|
+
const llm = await parser.parseLocationsFromUrl(url);
|
|
175
|
+
parsedLocs = llm.output.locations;
|
|
176
|
+
if (llm.output.title) title = llm.output.title;
|
|
177
|
+
locationPromptVersion = llm.locationPromptVersion;
|
|
178
|
+
summaryPromptVersion = llm.summaryPromptVersion;
|
|
179
|
+
usage = toUsage(llm);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "text": {
|
|
183
|
+
const text = placesFromText.parse(options.source);
|
|
184
|
+
const llm = await parser.parseLocationsFromText(text);
|
|
185
|
+
parsedLocs = llm.output.locations;
|
|
186
|
+
if (llm.output.title) title = llm.output.title;
|
|
187
|
+
locationPromptVersion = llm.locationPromptVersion;
|
|
188
|
+
summaryPromptVersion = llm.summaryPromptVersion;
|
|
189
|
+
usage = toUsage(llm);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "list": {
|
|
193
|
+
const list = placesFromList.parse(options.source);
|
|
194
|
+
parsedLocs = list.trim().split("\n").map((line) => ({ address: line, description: "" }));
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
default: {
|
|
198
|
+
const _exhaustive = options;
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Unsupported sourceType: ${_exhaustive.sourceType}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const places = await geocoder.geocodeMany(parsedLocs);
|
|
205
|
+
return {
|
|
206
|
+
title,
|
|
207
|
+
places,
|
|
208
|
+
sourceType: options.sourceType,
|
|
209
|
+
source: options.source,
|
|
210
|
+
locationPromptVersion,
|
|
211
|
+
summaryPromptVersion,
|
|
212
|
+
usage
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { createMapGenerator };
|
|
219
|
+
//# sourceMappingURL=index.js.map
|
|
220
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/schemas.ts","../../src/generate/generator.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from \"zod\"\n\n/**\n * Runtime validation schemas and their inferred types.\n *\n * These schemas define the public contract between producers and consumers of\n * mapthis data. They are intentionally framework-agnostic — no Prisma, no\n * Next.js, no auth assumptions.\n */\n\n// --- Providers & source types ------------------------------------------------\n\nexport const llmProvider = z.literal(\"openai\") // TODO: add other LLM support\nexport type LlmProvider = z.infer<typeof llmProvider>\n\nexport const placeProvider = z.union([z.literal(\"google\"), z.literal(\"locationiq\")])\nexport type PlaceProvider = z.infer<typeof placeProvider>\n\nexport const generationSourceType = z.union([\n z.literal(\"blank\"),\n z.literal(\"autocomplete\"),\n z.literal(\"url\"),\n z.literal(\"text\"),\n z.literal(\"list\"),\n])\nexport type GenerationSourceType = z.infer<typeof generationSourceType>\n\n// --- Geographic primitives ---------------------------------------------------\n\nexport const latitude = z.coerce.number().min(-90, \"Min latitude is -90\").max(90, \"Max latitude is 90\")\nexport const longitude = z.coerce.number().min(-180, \"Min longitude is -180\").max(180, \"Max longitude is 180\")\n\nexport const coordinates = z.object({\n lat: latitude,\n lng: longitude,\n})\nexport type Coordinates = z.infer<typeof coordinates>\n\n// --- Input schemas (freeform sources) ----------------------------------------\n\nexport const placesFromUrl = z.string().url({ message: \"Invalid url\" }).min(6).max(2048)\n\nexport const placesFromList = z\n .preprocess(\n (v) =>\n String(v)\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => !!line)\n .join(\"\\n\"),\n z.string().min(6, \"Must be at least 6 characters\").max(1000, \"List too long\"),\n )\n .refine(\n (v) => !v.split(\"\\n\").find((line) => line.length < 2),\n \"All lines must be at least 2 characters\",\n )\n\nexport const placesFromText = z\n .string()\n .min(6, \"Must be at least 6 characters\")\n .max(2000, \"Over character limit\")\n\n// --- Map field schemas -------------------------------------------------------\n\nexport const mapExternalId = z.string().min(6).max(100)\nexport const mapTitle = z\n .string()\n .min(3, { message: \"Title must be at least 3 characters\" })\n .max(100, { message: \"Title must be at most 100 characters\" })\nexport const mapDescription = z.string().max(1000, { message: \"Limit is 1000 characters\" })\nexport const mapCreationQuery = z\n .string()\n .min(10, \"Minimum 10 characters for search\")\n .max(200, \"Maximum 200 characters\")\n\n// --- Group field schemas -----------------------------------------------------\n\nexport const groupName = z\n .string()\n .min(3, { message: \"Name must be at least 3 characters\" })\n .max(200, { message: \"Name must be at most 200 characters\" })\nexport const groupDescription = z.string().max(400, { message: \"Limit is 400 characters\" })\nexport const groupColor = z.string().startsWith(\"#\").length(7)\n\n// --- Place field schemas -----------------------------------------------------\n\nexport const placeName = z\n .string()\n .min(2, { message: \"Name must be at least 2 characters\" })\n .max(200, { message: \"Name must be at most 200 characters\" })\nexport const placeDescription = z.string().max(400, { message: \"Limit is 400 characters\" })\n\n// --- Map creation composites -------------------------------------------------\n\nexport const createMapBase = z.object({\n title: mapTitle.optional(),\n description: mapDescription.optional(),\n externalId: mapExternalId.optional(),\n})\n\nexport const createMapSchema = createMapBase.extend({\n sourceType: generationSourceType,\n source: z.string().optional(),\n})\n\nexport const createBlankMapSchema = createMapBase\n\nexport const createMapFromUrlSchema = createMapBase.extend({\n url: placesFromUrl,\n})\nexport const createMapFromListSchema = createMapBase.extend({\n list: placesFromList,\n})\nexport const createMapFromTextSchema = createMapBase.extend({\n text: placesFromText,\n})\nexport const createMapFromQueryOrUrlSchema = createMapBase.extend({\n queryOrUrl: z.union([mapCreationQuery, placesFromUrl]),\n})\n\n// --- Adding places -----------------------------------------------------------\n\nexport const addPlacesBaseSchema = z.object({\n sourceType: generationSourceType,\n source: z.string(),\n})\n\nexport const addPlacesFromSourceSchema = addPlacesBaseSchema.extend({\n mapId: z.string(),\n groupId: z.string().optional(),\n})\n\nexport const addPlacesFromUrlSchema = z.object({\n url: placesFromUrl,\n})\nexport const addPlacesFromListSchema = z.object({\n list: placesFromList,\n})\nexport const addPlacesFromTextSchema = z.object({\n text: placesFromText,\n})\n\nexport const providerAutocompletePlace = z.object({\n query: z.string(),\n provider: z.literal(\"google\"),\n providerId: z.string(),\n name: z.string(),\n description: z.string().optional(),\n address: z.string(),\n lat: z.number().min(-90).max(90),\n lng: z.number().min(-180).max(180),\n})\nexport type ProviderAutocompletePlace = z.infer<typeof providerAutocompletePlace>\n\nexport const addPlacesFromClientAutocompleteSchema = providerAutocompletePlace.extend({\n mapId: z.string(),\n groupId: z.string().optional(),\n})\n\n// --- Updates -----------------------------------------------------------------\n\nexport const updateMapSchema = z.object({\n title: mapTitle,\n description: mapDescription.optional(),\n userPublic: z.boolean().optional(),\n partnerPublic: z.boolean().optional(),\n url: z.string().url().nullable().optional(),\n})\n\nexport const reorderMapSchema = z.object({\n groups: z.array(\n z.object({\n id: z.string().uuid().nullable(),\n position: z.number(),\n }),\n ),\n places: z.array(\n z.object({\n id: z.string(),\n groupId: z.string().uuid().nullable(),\n position: z.number(),\n }),\n ),\n})\n\nexport const updatePlaceFormSchema = z.object({\n id: z.string(),\n name: placeName,\n description: placeDescription.optional(),\n hidden: z.boolean(),\n})\n\nexport const searchSchema = z.object({\n query: mapCreationQuery,\n})\n\nexport const createGroupSchema = z.object({\n name: groupName,\n description: groupDescription.optional(),\n parentGroupId: z.string().optional(),\n color: groupColor.optional(),\n})\n\nexport const editGroupSchema = z.object({\n id: z.string().uuid(),\n color: groupColor.nullable(),\n hidden: z.boolean(),\n name: groupName,\n description: groupDescription.optional(),\n})\n\n// --- Place metadata (lightweight projections) --------------------------------\n\nexport const placeMeta = z.object({\n id: z.string(),\n updatedAt: z.coerce.date(),\n groupId: z.string().nullable(),\n position: z.number().nullable(),\n error: z.string().nullable(),\n lat: z.number().nullable(),\n lon: z.number().nullable(),\n name: z.string().nullable(),\n})\nexport type PlaceMeta = z.infer<typeof placeMeta>\n\nexport const positionedPlaceMeta = placeMeta.extend({\n position: z.number(),\n})\nexport type PositionedPlaceMeta = z.infer<typeof positionedPlaceMeta>\n\nexport const mappablePlaceMeta = placeMeta.extend({\n lat: z.number(),\n lon: z.number(),\n error: z.null(),\n})\nexport type MappablePlaceMeta = z.infer<typeof mappablePlaceMeta>\n\n/**\n * Filter a list of place projections down to those that are mappable\n * (have coordinates and no error).\n */\nexport function getMappablePlaceMetas(\n places: (PlaceMeta | null | undefined)[],\n): MappablePlaceMeta[] {\n const good: MappablePlaceMeta[] = []\n for (const p of places) {\n const parsed = mappablePlaceMeta.safeParse(p)\n if (parsed.success) good.push(parsed.data)\n }\n return good\n}\n","import type { GetLocationsResponse } from \"../ai\"\nimport type { ParsedLocation } from \"../types/domain\"\nimport { placesFromList, placesFromText, placesFromUrl } from \"../types/schemas\"\nimport type {\n GenerateFromSourceOptions,\n GenerateFromSourceResult,\n LlmUsage,\n MapGenerator,\n MapGeneratorConfig,\n} from \"./types\"\n\n/**\n * Default titles when the LLM does not return one. These match what the\n * private app has historically used so migrated data stays consistent.\n */\nconst DEFAULT_TITLES: Record<GenerateFromSourceOptions[\"sourceType\"], string> = {\n url: \"Map from Site\",\n text: \"Map from Text\",\n list: \"Map from List\",\n}\n\nfunction toUsage(r: GetLocationsResponse): LlmUsage {\n const { output: _output, ...rest } = r\n return rest\n}\n\n/**\n * Create a {@link MapGenerator} that wires a {@link LocationParser} and\n * {@link GeocodingProvider} together.\n *\n * @example\n * ```ts\n * import { createLocationParser } from \"mapthis/ai\"\n * import { createGeocoder } from \"mapthis/geocoding\"\n * import { createMapGenerator } from \"mapthis/generate\"\n *\n * const generator = createMapGenerator({\n * parser: createLocationParser({ apiKey: process.env.OPENAI_API_KEY! }),\n * geocoder: createGeocoder({ provider: \"google\", apiKey: process.env.GOOGLE_MAPS_KEY! }),\n * })\n *\n * const result = await generator.generateFromSource({\n * sourceType: \"url\",\n * source: \"https://example.com/best-restaurants-tokyo\",\n * })\n *\n * // Persist in your own DB:\n * await db.$transaction(async (tx) => {\n * const map = await tx.map.create({ data: { title: result.title, ... } })\n * const group = await tx.placeGroup.create({ data: { mapId: map.id, ... } })\n * await tx.place.createMany({\n * data: result.places.map((p, i) => ({\n * mapId: map.id,\n * groupId: group.id,\n * position: i,\n * query: p.input.address,\n * description: p.input.description,\n * name: p.data?.name,\n * address: p.data?.address,\n * lat: p.data?.lat,\n * lon: p.data?.lng,\n * provider: p.data?.provider,\n * providerId: p.data?.providerId,\n * error: p.error,\n * locationPromptVersion: result.locationPromptVersion,\n * summaryPromptVersion: result.summaryPromptVersion,\n * })),\n * })\n * })\n * ```\n */\nexport function createMapGenerator(config: MapGeneratorConfig): MapGenerator {\n const { parser, geocoder } = config\n\n return {\n async generateFromSource(\n options: GenerateFromSourceOptions,\n ): Promise<GenerateFromSourceResult> {\n let parsedLocs: ParsedLocation[] = []\n let title: string = DEFAULT_TITLES[options.sourceType]\n let usage: LlmUsage | undefined = undefined\n let locationPromptVersion: string | undefined = undefined\n let summaryPromptVersion: string | undefined = undefined\n\n switch (options.sourceType) {\n case \"url\": {\n const url = placesFromUrl.parse(options.source)\n const llm = await parser.parseLocationsFromUrl(url)\n parsedLocs = llm.output.locations\n if (llm.output.title) title = llm.output.title\n locationPromptVersion = llm.locationPromptVersion\n summaryPromptVersion = llm.summaryPromptVersion\n usage = toUsage(llm)\n break\n }\n case \"text\": {\n const text = placesFromText.parse(options.source)\n const llm = await parser.parseLocationsFromText(text)\n parsedLocs = llm.output.locations\n if (llm.output.title) title = llm.output.title\n locationPromptVersion = llm.locationPromptVersion\n summaryPromptVersion = llm.summaryPromptVersion\n usage = toUsage(llm)\n break\n }\n case \"list\": {\n const list = placesFromList.parse(options.source)\n parsedLocs = list\n .trim()\n .split(\"\\n\")\n .map((line) => ({ address: line, description: \"\" }))\n break\n }\n default: {\n const _exhaustive: never = options\n throw new Error(\n `Unsupported sourceType: ${(_exhaustive as { sourceType: string }).sourceType}`,\n )\n }\n }\n\n const places = await geocoder.geocodeMany(parsedLocs)\n\n return {\n title,\n places,\n sourceType: options.sourceType,\n source: options.source,\n locationPromptVersion,\n summaryPromptVersion,\n usage,\n }\n },\n }\n}\n"]}
|