@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.
Files changed (65) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +56 -0
  3. package/dist/ai/index.cjs +474 -0
  4. package/dist/ai/index.cjs.map +1 -0
  5. package/dist/ai/index.d.cts +117 -0
  6. package/dist/ai/index.d.ts +117 -0
  7. package/dist/ai/index.js +447 -0
  8. package/dist/ai/index.js.map +1 -0
  9. package/dist/domain-CZ-L-ntu.d.ts +163 -0
  10. package/dist/domain-Dc1wSTkf.d.cts +163 -0
  11. package/dist/errors-Bw97z_4m.d.cts +12 -0
  12. package/dist/errors-Bw97z_4m.d.ts +12 -0
  13. package/dist/generate/index.cjs +222 -0
  14. package/dist/generate/index.cjs.map +1 -0
  15. package/dist/generate/index.d.cts +140 -0
  16. package/dist/generate/index.d.ts +140 -0
  17. package/dist/generate/index.js +220 -0
  18. package/dist/generate/index.js.map +1 -0
  19. package/dist/geocoding/index.cjs +90 -0
  20. package/dist/geocoding/index.cjs.map +1 -0
  21. package/dist/geocoding/index.d.cts +36 -0
  22. package/dist/geocoding/index.d.ts +36 -0
  23. package/dist/geocoding/index.js +86 -0
  24. package/dist/geocoding/index.js.map +1 -0
  25. package/dist/index.cjs +546 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +5 -0
  28. package/dist/index.d.ts +5 -0
  29. package/dist/index.js +469 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/parser-CzXzpmVv.d.cts +111 -0
  32. package/dist/parser-N7-fNxeu.d.ts +111 -0
  33. package/dist/react/index.cjs +394 -0
  34. package/dist/react/index.cjs.map +1 -0
  35. package/dist/react/index.js +383 -0
  36. package/dist/react/index.js.map +1 -0
  37. package/dist/schemas-Dy5coqXo.d.cts +484 -0
  38. package/dist/schemas-Dy5coqXo.d.ts +484 -0
  39. package/dist/scrape/index.cjs +133 -0
  40. package/dist/scrape/index.cjs.map +1 -0
  41. package/dist/scrape/index.d.cts +60 -0
  42. package/dist/scrape/index.d.ts +60 -0
  43. package/dist/scrape/index.js +125 -0
  44. package/dist/scrape/index.js.map +1 -0
  45. package/dist/search/index.cjs +76 -0
  46. package/dist/search/index.cjs.map +1 -0
  47. package/dist/search/index.d.cts +75 -0
  48. package/dist/search/index.d.ts +75 -0
  49. package/dist/search/index.js +71 -0
  50. package/dist/search/index.js.map +1 -0
  51. package/dist/types/index.cjs +215 -0
  52. package/dist/types/index.cjs.map +1 -0
  53. package/dist/types/index.d.cts +4 -0
  54. package/dist/types/index.d.ts +4 -0
  55. package/dist/types/index.js +171 -0
  56. package/dist/types/index.js.map +1 -0
  57. package/dist/types-BhqKlq0k.d.ts +31 -0
  58. package/dist/types-rFjK5YcJ.d.cts +31 -0
  59. package/dist/utils/index.cjs +335 -0
  60. package/dist/utils/index.cjs.map +1 -0
  61. package/dist/utils/index.d.cts +363 -0
  62. package/dist/utils/index.d.ts +363 -0
  63. package/dist/utils/index.js +301 -0
  64. package/dist/utils/index.js.map +1 -0
  65. package/package.json +150 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/schemas.ts","../../src/generate/generator.ts"],"names":["z"],"mappings":"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","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"]}