@zorgo/next 1.0.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 (64) hide show
  1. package/README.md +19 -0
  2. package/dist/cli.d.mts +5 -0
  3. package/dist/cli.d.ts +5 -0
  4. package/dist/cli.js +2 -0
  5. package/dist/cli.mjs +2 -0
  6. package/dist/components.d.mts +337 -0
  7. package/dist/components.d.ts +337 -0
  8. package/dist/components.js +1996 -0
  9. package/dist/components.js.map +1 -0
  10. package/dist/components.mjs +1962 -0
  11. package/dist/components.mjs.map +1 -0
  12. package/dist/index.d.mts +305 -0
  13. package/dist/index.d.ts +305 -0
  14. package/dist/index.js +2 -0
  15. package/dist/index.mjs +2 -0
  16. package/dist/seo.d.mts +30 -0
  17. package/dist/seo.d.ts +30 -0
  18. package/dist/seo.js +82 -0
  19. package/dist/seo.js.map +1 -0
  20. package/dist/seo.mjs +56 -0
  21. package/dist/seo.mjs.map +1 -0
  22. package/dist/slugs.d.mts +1 -0
  23. package/dist/slugs.d.ts +1 -0
  24. package/dist/slugs.js +47 -0
  25. package/dist/slugs.js.map +1 -0
  26. package/dist/slugs.mjs +19 -0
  27. package/dist/slugs.mjs.map +1 -0
  28. package/dist/tree/.env.gen.ts +27 -0
  29. package/dist/tree/README.md +0 -0
  30. package/dist/tree/app/api/zorgo-token/route.ts +11 -0
  31. package/dist/tree/app/apple-icon.tsx.gen.ts +54 -0
  32. package/dist/tree/app/checkout/page.tsx +10 -0
  33. package/dist/tree/app/components/Footer.tsx +50 -0
  34. package/dist/tree/app/components/Header.tsx +128 -0
  35. package/dist/tree/app/components/ModalHost.tsx +56 -0
  36. package/dist/tree/app/components/ModalRegistry.tsx +113 -0
  37. package/dist/tree/app/components/TestCard.tsx +35 -0
  38. package/dist/tree/app/components/index.ts +3 -0
  39. package/dist/tree/app/error.tsx +10 -0
  40. package/dist/tree/app/global-error.tsx +12 -0
  41. package/dist/tree/app/globals.css.gen.ts +123 -0
  42. package/dist/tree/app/icon.tsx.gen.ts +87 -0
  43. package/dist/tree/app/layout.tsx.gen.ts +55 -0
  44. package/dist/tree/app/locations/page.tsx +30 -0
  45. package/dist/tree/app/manifest.ts.gen.ts +39 -0
  46. package/dist/tree/app/menu/[slug]/ItemCustomizationClient.tsx +18 -0
  47. package/dist/tree/app/menu/[slug]/page.tsx +78 -0
  48. package/dist/tree/app/menu/page.tsx +36 -0
  49. package/dist/tree/app/not-found.tsx +8 -0
  50. package/dist/tree/app/opengraph-image.tsx.gen.ts +82 -0
  51. package/dist/tree/app/page.tsx +19 -0
  52. package/dist/tree/app/privacy/page.tsx.gen.ts +15 -0
  53. package/dist/tree/app/robots.ts +9 -0
  54. package/dist/tree/app/sitemap.ts +26 -0
  55. package/dist/tree/app/terms/page.tsx.gen.ts +16 -0
  56. package/dist/tree/gitignore +44 -0
  57. package/dist/tree/lib/zorgoSiteToken.ts +20 -0
  58. package/dist/tree/next.config.ts +14 -0
  59. package/dist/tree/open-next.config.ts +4 -0
  60. package/dist/tree/package.json.gen.ts +24 -0
  61. package/dist/tree/postcss.config.mjs +7 -0
  62. package/dist/tree/scripts/prebuild.ts +448 -0
  63. package/dist/tree/tsconfig.json +35 -0
  64. package/package.json +72 -0
@@ -0,0 +1,448 @@
1
+ import { writeFileSync, mkdirSync } from "fs";
2
+ import path from "path";
3
+ import { loadEnvConfig } from "@next/env";
4
+ import { Menu } from "@zorgo/next";
5
+ import { buildRestaurantJsonLd } from "@zorgo/next/seo";
6
+ import { z } from "zod";
7
+ import { fetchSiteToken } from "../lib/zorgoSiteToken";
8
+
9
+ loadEnvConfig(process.cwd());
10
+
11
+ const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:3000";
12
+
13
+ /*
14
+ todo list:
15
+ 1. bring color functions out into their own utility file
16
+ 2. clean up this file and move utilities elsewhere
17
+ 3. get rid of all references to the supabaseUrl. should be pulled thru by whichever environment is specified
18
+ */
19
+
20
+ function writeWranglerToml() {
21
+ const name = process.env.ZORGO_PROJECT_NAME ?? "zorgo-site";
22
+ const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "";
23
+ const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL ?? "";
24
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? siteUrl;
25
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
26
+
27
+ // custom_domain routes need a bare hostname; skip them if the site URL isn't
28
+ // a parseable absolute URL (e.g. a local/placeholder value).
29
+ let host: string | undefined;
30
+ try {
31
+ host = new URL(siteUrl).hostname;
32
+ } catch {
33
+ host = undefined;
34
+ }
35
+ const routes = host
36
+ ? `
37
+ [[routes]]
38
+ pattern = "${host}"
39
+ custom_domain = true
40
+
41
+ [[routes]]
42
+ pattern = "www.${host}"
43
+ custom_domain = true
44
+ `
45
+ : "";
46
+
47
+ const toml = `# AUTO-GENERATED by scripts/prebuild.ts from .env — do not edit.
48
+ name = "${name}"
49
+ main = ".open-next/worker.js"
50
+ compatibility_date = "2024-09-23"
51
+ compatibility_flags = ["nodejs_compat"]
52
+
53
+ [assets]
54
+ directory = ".open-next/assets"
55
+ binding = "ASSETS"
56
+
57
+ [vars]
58
+ NEXT_PUBLIC_SUPABASE_URL = "${supabaseUrl}"
59
+ NEXT_PUBLIC_API_BASE_URL = "${apiBaseUrl}"
60
+ NEXT_PUBLIC_SITE_URL = "${siteUrl}"
61
+ NEXT_PUBLIC_BASE_URL = "${baseUrl}"
62
+
63
+ [observability]
64
+ enabled = true
65
+
66
+ [observability.logs]
67
+ enabled = true
68
+ invocation_logs = true
69
+ ${routes}`;
70
+
71
+ writeFileSync(path.join(process.cwd(), "wrangler.toml"), toml);
72
+ }
73
+
74
+ interface FetchArgs {
75
+ franchiseId: number;
76
+ token: string;
77
+ }
78
+
79
+ const BrandingSchema = z
80
+ .object({
81
+ backgroundBase: z.string().default("#F5F5F5"),
82
+ primary: z.string().default("#3264FF"),
83
+ accent: z.string().default("#9696FF"),
84
+ fontFamily: z.string().default("Inter"), // Google Font family name
85
+ })
86
+ .prefault({});
87
+ type Branding = z.infer<typeof BrandingSchema>;
88
+
89
+ // schemas
90
+ const FranchiseSchema = z
91
+ .object({
92
+ name: z.string().default(process.env.ZORGO_PROJECT_NAME ?? "Restaurant"),
93
+ site_url: z.string().optional(),
94
+ })
95
+ .prefault({});
96
+
97
+ const HoursSchema = z.array(z.unknown()).prefault([]);
98
+
99
+ const MenuSchema = z.object({
100
+ items: z.array(z.unknown()).default([]),
101
+ categories: z.array(z.unknown()).default([]),
102
+ components: z.array(z.unknown()).default([]),
103
+ rules: z.array(z.unknown()).default([]),
104
+ });
105
+
106
+
107
+ async function fetchData<T>(
108
+ endpoint: string,
109
+ token: string,
110
+ schema: z.ZodType<T>,
111
+ ): Promise<T> {
112
+ try {
113
+ const res = await fetch(`${API_BASE_URL}${endpoint}`, {
114
+ headers: { Authorization: `Bearer ${token}` },
115
+ });
116
+ if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
117
+ const body = await res.json();
118
+ return schema.parse(body?.data ?? body);
119
+ } catch (err) {
120
+ console.error(`prebuild: ${endpoint} failed, using defaults:`, err);
121
+ return schema.parse(undefined);
122
+ }
123
+ }
124
+
125
+ // style stuff
126
+ const FONT_ON_LIGHT = "#0a0a0a";
127
+ const FONT_ON_DARK = "#f5f5f5";
128
+ /** Neutral channel delta toward white (elevated) / black (recessed). */
129
+ const BACKGROUND_SURFACE_DELTA = 15;
130
+ /**
131
+ * Max warm/cool bias via R↔B trade (full strength on light bases).
132
+ * Scaled down by luminance so darker colors shift less.
133
+ */
134
+ const BACKGROUND_TEMPERATURE_BIAS = 8;
135
+
136
+ function parseHexRgb(
137
+ background: string,
138
+ ): { r: number; g: number; b: number } | null {
139
+ const hex = background.trim().replace(/^#/, "");
140
+ const full =
141
+ hex.length === 3
142
+ ? hex
143
+ .split("")
144
+ .map((c) => c + c)
145
+ .join("")
146
+ : hex;
147
+ if (full.length !== 6 || Number.isNaN(Number.parseInt(full, 16))) {
148
+ return null;
149
+ }
150
+ return {
151
+ r: Number.parseInt(full.slice(0, 2), 16),
152
+ g: Number.parseInt(full.slice(2, 4), 16),
153
+ b: Number.parseInt(full.slice(4, 6), 16),
154
+ };
155
+ }
156
+
157
+ function toHex({ r, g, b }: { r: number; g: number; b: number }): string {
158
+ return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
159
+ }
160
+
161
+ function relativeLuminance({
162
+ r,
163
+ g,
164
+ b,
165
+ }: {
166
+ r: number;
167
+ g: number;
168
+ b: number;
169
+ }): number {
170
+ return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
171
+ }
172
+
173
+ /** Temperature bias scaled by luminance; max on light bases, near-zero on dark. */
174
+ function temperatureBiasFor({
175
+ r,
176
+ g,
177
+ b,
178
+ }: {
179
+ r: number;
180
+ g: number;
181
+ b: number;
182
+ }): number {
183
+ return Math.round(
184
+ BACKGROUND_TEMPERATURE_BIAS * relativeLuminance({ r, g, b }),
185
+ );
186
+ }
187
+
188
+ /** Off-black on light backgrounds, off-white on dark. */
189
+ function deriveFontColor(background: string): string {
190
+ const rgb = parseHexRgb(background);
191
+ if (!rgb) return FONT_ON_LIGHT;
192
+ return relativeLuminance(rgb) > 0.5 ? FONT_ON_LIGHT : FONT_ON_DARK;
193
+ }
194
+
195
+ /** Lighter, slightly warmer surface (cards, raised panels) from backgroundBase. */
196
+ function deriveElevatedBackground(background: string): string {
197
+ const rgb = parseHexRgb(background);
198
+ if (!rgb) return background;
199
+ const bias = temperatureBiasFor(rgb);
200
+ const warm = Math.round(bias / 4);
201
+ return toHex({
202
+ r: Math.min(255, rgb.r + BACKGROUND_SURFACE_DELTA + warm),
203
+ g: Math.min(255, rgb.g + BACKGROUND_SURFACE_DELTA),
204
+ b: Math.min(255, rgb.b + BACKGROUND_SURFACE_DELTA - bias),
205
+ });
206
+ }
207
+
208
+ /** Darker, slightly cooler surface (wells, inset areas) from backgroundBase. */
209
+ function deriveRecessedBackground(background: string): string {
210
+ const rgb = parseHexRgb(background);
211
+ if (!rgb) return background;
212
+ const bias = temperatureBiasFor(rgb);
213
+ const cool = Math.round(bias / 4);
214
+ return toHex({
215
+ r: Math.max(0, rgb.r - BACKGROUND_SURFACE_DELTA - cool),
216
+ g: Math.max(0, rgb.g - BACKGROUND_SURFACE_DELTA),
217
+ b: Math.max(0, rgb.b - BACKGROUND_SURFACE_DELTA + bias),
218
+ });
219
+ }
220
+
221
+ // main prebuild function
222
+ async function prebuild() {
223
+ console.log("running prebuild script...");
224
+
225
+ // regenerate deploy config from .env before any network work
226
+ writeWranglerToml();
227
+
228
+ const token = await fetchSiteToken();
229
+ if (!token) throw new Error("Missing or invalid ZORGO_SITE_SECRET env var");
230
+
231
+ const payload = JSON.parse(
232
+ Buffer.from(token.split(".")[1], "base64url").toString(),
233
+ );
234
+ const franchiseId = payload.franchise_ids[0];
235
+
236
+ // menu + franchise feed the JSON-LD; a menu failure must break the build
237
+ // loudly (it's imported for SSR), not silently ship a missing/empty menu.ts.
238
+ const [menuData] = await Promise.all([
239
+ menu({ franchiseId, token }),
240
+ logo({ franchiseId, token }).catch((err) =>
241
+ console.error("logo failed:", err),
242
+ ),
243
+ hours({ franchiseId, token }).catch((err) =>
244
+ console.error("hours failed:", err),
245
+ ),
246
+ styles({ franchiseId, token }).catch((err) =>
247
+ console.error("styles failed:", err),
248
+ ),
249
+ ]);
250
+
251
+ await jsonLd({ franchiseId, token }, menuData).catch((err) =>
252
+ console.error("jsonLd failed:", err),
253
+ );
254
+
255
+ console.log("prebuild script completed");
256
+ }
257
+
258
+ // fetches
259
+ async function logo({ franchiseId, token }: FetchArgs) {
260
+ const logoResponse = await fetch(
261
+ `${API_BASE_URL}/franchise-info/logo/${franchiseId}`,
262
+ {
263
+ headers: { Authorization: `Bearer ${token}` },
264
+ },
265
+ );
266
+
267
+ // 404 (no logo) returns a JSON body — don't persist it as logo.png, or the
268
+ // icon/OG image would render an error blob instead of falling back.
269
+ if (!logoResponse.ok) return;
270
+
271
+ const arrayBuffer = await logoResponse.arrayBuffer();
272
+ const buffer = Buffer.from(arrayBuffer);
273
+
274
+ const outDir = path.join(process.cwd(), `public/images/`);
275
+
276
+ mkdirSync(outDir, { recursive: true });
277
+
278
+ writeFileSync(path.join(outDir, "logo.png"), buffer);
279
+ writeFileSync(path.join(outDir, "logo.jpg"), buffer);
280
+ }
281
+
282
+ async function menu({ franchiseId, token }: FetchArgs): Promise<Menu> {
283
+ const menuResponse = await fetch(
284
+ `${API_BASE_URL}/franchise-info/menu/${franchiseId}`,
285
+ {
286
+ headers: { Authorization: `Bearer ${token}` },
287
+ },
288
+ );
289
+
290
+ if (!menuResponse.ok) {
291
+ throw new Error(
292
+ `menu fetch failed ${menuResponse.status}: ${await menuResponse.text()}`,
293
+ );
294
+ }
295
+
296
+ const body = await menuResponse.json();
297
+ const menu = MenuSchema.parse(body?.data ?? {}) as Menu;
298
+
299
+ // A menu is core content: an empty one is a broken storefront, so keep
300
+ // failing the build loudly rather than shipping an empty menu.ts.
301
+ if (menu.items.length === 0) {
302
+ throw new Error(
303
+ `menu response has no items: ${JSON.stringify(body).slice(0, 200)}`,
304
+ );
305
+ }
306
+
307
+ const outDir = path.join(process.cwd(), `lib/generated/`);
308
+ mkdirSync(outDir, { recursive: true });
309
+
310
+ // typed module so consumers get Menu-checked imports instead of an
311
+ // untyped runtime fetch of menu.json.
312
+ writeFileSync(
313
+ path.join(outDir, "menu.ts"),
314
+ `// AUTO-GENERATED by scripts/prebuild.ts — do not edit.\n` +
315
+ `import type { Menu } from "@zorgo/next";\n\n` +
316
+ `export const menu: Menu = ${JSON.stringify(menu, null, 2)};\n`,
317
+ );
318
+
319
+ return menu;
320
+ }
321
+
322
+ // franchise row (name, site_url) -> Restaurant JSON-LD, written as a typed
323
+ // module the layout imports and drops into <head>.
324
+ async function jsonLd({ franchiseId, token }: FetchArgs, menu: Menu) {
325
+ const franchise = await fetchData(
326
+ `/franchise-info/franchise/${franchiseId}`,
327
+ token,
328
+ FranchiseSchema,
329
+ );
330
+ const url = franchise.site_url;
331
+
332
+ const data = buildRestaurantJsonLd(menu, {
333
+ name: franchise.name,
334
+ url,
335
+ image: url ? `${url}/images/logo.png` : undefined,
336
+ });
337
+
338
+ const outDir = path.join(process.cwd(), `lib/generated/`);
339
+ mkdirSync(outDir, { recursive: true });
340
+ writeFileSync(
341
+ path.join(outDir, "jsonld.ts"),
342
+ `// AUTO-GENERATED by scripts/prebuild.ts — do not edit.\n` +
343
+ `export const restaurantJsonLd = ${JSON.stringify(data, null, 2)};\n`,
344
+ );
345
+ }
346
+
347
+ async function hours({ franchiseId, token }: FetchArgs) {
348
+ await fetchData(`/franchise-info/hours/${franchiseId}`, token, HoursSchema);
349
+ }
350
+
351
+ async function styles({ franchiseId, token }: FetchArgs) {
352
+ const brand = await fetchData(
353
+ `/franchise-info/styles/${franchiseId}`,
354
+ token,
355
+ BrandingSchema,
356
+ );
357
+
358
+ // Same derived palette globals.css uses, persisted as JSON so the build-time
359
+ // icon/OG/manifest routes stay on brand (they readFileSync this).
360
+ const branding = {
361
+ ...brand,
362
+ backgroundElevated: deriveElevatedBackground(brand.backgroundBase),
363
+ backgroundRecessed: deriveRecessedBackground(brand.backgroundBase),
364
+ foreground: deriveFontColor(brand.backgroundBase),
365
+ primaryForeground: deriveFontColor(brand.primary),
366
+ accentForeground: deriveFontColor(brand.accent),
367
+ };
368
+
369
+ const stylesDir = path.join(process.cwd(), `public/styles/`);
370
+ mkdirSync(stylesDir, { recursive: true });
371
+ writeFileSync(
372
+ path.join(stylesDir, "styles.json"),
373
+ JSON.stringify(branding, null, 2),
374
+ );
375
+
376
+ writeFileSync(
377
+ path.join(process.cwd(), "app", "globals.css"),
378
+ buildGlobalsCss(brand),
379
+ );
380
+ }
381
+
382
+ // css write
383
+ function buildGlobalsCss(branding: Branding): string {
384
+ const fontFamilyParam = branding.fontFamily.replace(/ /g, "+");
385
+ const foreground = deriveFontColor(branding.backgroundBase);
386
+ const primaryForeground = deriveFontColor(branding.primary);
387
+ const accentForeground = deriveFontColor(branding.accent);
388
+ const backgroundElevated = deriveElevatedBackground(
389
+ branding.backgroundBase,
390
+ );
391
+ const backgroundRecessed = deriveRecessedBackground(
392
+ branding.backgroundBase,
393
+ );
394
+
395
+ return `
396
+ @import url("https://fonts.googleapis.com/css2?family=${fontFamilyParam}:wght@400;700&display=swap");
397
+ @import "tailwindcss";
398
+ /* Tailwind v4 skips node_modules; @zorgo/next ships un-obfuscated components so
399
+ their class names are scannable here. */
400
+ @source "../node_modules/@zorgo/next/dist/components.mjs";
401
+
402
+ :root {
403
+ --background: ${branding.backgroundBase};
404
+ --background-elevated: ${backgroundElevated};
405
+ --background-recessed: ${backgroundRecessed};
406
+ --foreground: ${foreground};
407
+ --primary: ${branding.primary};
408
+ --primary-foreground: ${primaryForeground};
409
+ --accent: ${branding.accent};
410
+ --accent-foreground: ${accentForeground};
411
+ --font-sans: "${branding.fontFamily}", sans-serif;
412
+ }
413
+
414
+ @theme inline {
415
+ --color-background: var(--background);
416
+ --color-background-elevated: var(--background-elevated);
417
+ --color-background-recessed: var(--background-recessed);
418
+ --color-foreground: var(--foreground);
419
+ --color-primary: var(--primary);
420
+ --color-primary-foreground: var(--primary-foreground);
421
+ --color-accent: var(--accent);
422
+ --color-accent-foreground: var(--accent-foreground);
423
+ --font-sans: var(--font-sans);
424
+ }
425
+
426
+ @layer base {
427
+ button,
428
+ [type="button"],
429
+ [type="submit"],
430
+ [type="reset"] {
431
+ cursor: pointer;
432
+ }
433
+
434
+ button:disabled,
435
+ [type="button"]:disabled,
436
+ [type="submit"]:disabled,
437
+ [type="reset"]:disabled {
438
+ cursor: not-allowed;
439
+ }
440
+ }
441
+ `;
442
+ }
443
+
444
+
445
+ prebuild().catch((err: Error) => {
446
+ console.error(err);
447
+ process.exit(1);
448
+ });
@@ -0,0 +1,35 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
35
+
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@zorgo/next",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "bin": {
7
+ "zorgo": "./dist/cli.js"
8
+ },
9
+ "sideEffects": [
10
+ "./dist/index.mjs",
11
+ "./dist/index.js",
12
+ "./dist/components.mjs",
13
+ "./dist/components.js",
14
+ "./src/index.ts"
15
+ ],
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "name": "@zorgo/next",
21
+ "registry": "https://registry.npmjs.org/",
22
+ "access": "public"
23
+ },
24
+ "peerDependencies": {
25
+ "react": "*",
26
+ "react-dom": "*",
27
+ "next": "^14.x.x || ^15.x.x || ^16.x.x",
28
+ "lucide-react": "*",
29
+ "@stripe/react-stripe-js": "*"
30
+ },
31
+ "exports": {
32
+ ".": {
33
+ "import": "./dist/index.mjs",
34
+ "require": "./dist/index.js",
35
+ "types": "./dist/index.d.ts"
36
+ },
37
+ "./components": {
38
+ "import": "./dist/components.mjs",
39
+ "require": "./dist/components.js",
40
+ "types": "./dist/components.d.ts"
41
+ },
42
+ "./slugs": {
43
+ "import": "./dist/slugs.mjs",
44
+ "require": "./dist/slugs.js",
45
+ "types": "./dist/slugs.d.ts"
46
+ },
47
+ "./seo": {
48
+ "import": "./dist/seo.mjs",
49
+ "require": "./dist/seo.js",
50
+ "types": "./dist/seo.d.ts"
51
+ },
52
+ "./cli": {
53
+ "import": "./dist/cli.mjs",
54
+ "require": "./dist/cli.js",
55
+ "types": "./dist/cli.d.ts"
56
+ },
57
+ "./package.json": "./package.json"
58
+ },
59
+ "dependencies": {
60
+ "immer": "^10.0.0",
61
+ "prompts": "^2.4.2",
62
+ "zustand": "^4.x.x"
63
+ },
64
+ "scripts": {
65
+ "build": "tsup && tsx scripts/obfuscate.ts",
66
+ "release": "node scripts/publish.mjs",
67
+ "dev": "echo \"No build step. Consumers transpile TS sources.\"",
68
+ "clean": "rm -rf dist",
69
+ "generate:test": "tsup && tsx --env-file=.env scripts/test-scaffold.ts",
70
+ "env:init": "tsx scripts/init-env.ts"
71
+ }
72
+ }