blodemd 0.0.13 → 0.0.14

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 (136) hide show
  1. package/README.md +1 -1
  2. package/dev-server/lib/local-runtime.tsx +12 -15
  3. package/dev-server/package.json +5 -1
  4. package/dist/cli.mjs +1193 -978
  5. package/dist/cli.mjs.map +1 -1
  6. package/docs/app/globals.css +1 -1
  7. package/docs/components/api/api-playground.tsx +2 -5
  8. package/docs/components/api/api-reference.tsx +29 -3
  9. package/docs/components/docs/contextual-menu.tsx +37 -33
  10. package/docs/components/docs/copy-page-menu.tsx +18 -0
  11. package/docs/components/docs/doc-header.tsx +4 -1
  12. package/docs/components/docs/doc-shell.tsx +48 -18
  13. package/docs/components/docs/doc-sidebar.tsx +131 -89
  14. package/docs/components/docs/doc-toc.tsx +1 -0
  15. package/docs/components/docs/mobile-nav.tsx +72 -68
  16. package/docs/components/docs/sidebar-active-highlight.tsx +34 -0
  17. package/docs/components/docs/sidebar-scroll-area.tsx +9 -4
  18. package/docs/components/git/repo-picker.tsx +5 -2
  19. package/docs/components/mdx/index.tsx +31 -21
  20. package/docs/components/posthog-provider.tsx +42 -0
  21. package/docs/components/tenant-analytics.tsx +49 -0
  22. package/docs/components/third-parties.tsx +4 -1
  23. package/docs/components/ui/copy-button.tsx +16 -2
  24. package/docs/components/ui/search-dialog.tsx +431 -0
  25. package/docs/components/ui/search.tsx +44 -427
  26. package/docs/components/web-mcp.tsx +115 -0
  27. package/docs/lib/agent-skills.ts +48 -0
  28. package/docs/lib/config.ts +4 -5
  29. package/docs/lib/docs-collection.ts +7 -22
  30. package/docs/lib/docs-runtime.tsx +160 -10
  31. package/docs/lib/llms-full.ts +82 -0
  32. package/docs/lib/marketing-markdown.ts +79 -0
  33. package/docs/lib/marketing-site.ts +31 -0
  34. package/docs/lib/mdx.ts +17 -6
  35. package/docs/lib/routes.ts +19 -3
  36. package/docs/lib/shiki.ts +4 -0
  37. package/docs/lib/tenancy.ts +15 -2
  38. package/docs/lib/tenant-headers.ts +29 -0
  39. package/docs/lib/tenant-static.ts +73 -99
  40. package/package.json +8 -5
  41. package/packages/@repo/common/package.json +1 -1
  42. package/packages/@repo/contracts/dist/analytics.d.ts +21 -0
  43. package/packages/@repo/contracts/dist/analytics.d.ts.map +1 -0
  44. package/packages/@repo/contracts/dist/analytics.js +18 -0
  45. package/packages/@repo/contracts/dist/deployment.js +1 -1
  46. package/packages/@repo/contracts/dist/git.js +2 -2
  47. package/packages/@repo/contracts/dist/ids.d.ts.map +1 -1
  48. package/packages/@repo/contracts/dist/ids.js +2 -1
  49. package/packages/@repo/contracts/dist/index.d.ts +1 -0
  50. package/packages/@repo/contracts/dist/index.d.ts.map +1 -1
  51. package/packages/@repo/contracts/dist/index.js +1 -0
  52. package/packages/@repo/contracts/dist/project.d.ts +18 -1
  53. package/packages/@repo/contracts/dist/project.d.ts.map +1 -1
  54. package/packages/@repo/contracts/dist/project.js +3 -1
  55. package/packages/@repo/contracts/dist/tenant.d.ts +36 -0
  56. package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -1
  57. package/packages/@repo/contracts/dist/tenant.js +2 -0
  58. package/packages/@repo/contracts/package.json +1 -1
  59. package/packages/@repo/contracts/src/analytics.ts +33 -0
  60. package/packages/@repo/contracts/src/deployment.ts +1 -1
  61. package/packages/@repo/contracts/src/git.ts +2 -2
  62. package/packages/@repo/contracts/src/ids.ts +2 -1
  63. package/packages/@repo/contracts/src/index.ts +1 -0
  64. package/packages/@repo/contracts/src/project.ts +3 -1
  65. package/packages/@repo/contracts/src/tenant.ts +2 -0
  66. package/packages/@repo/models/dist/docs-config.d.ts +0 -198
  67. package/packages/@repo/models/dist/docs-config.d.ts.map +1 -1
  68. package/packages/@repo/models/dist/docs-config.js +3 -2
  69. package/packages/@repo/models/dist/tenant.d.ts +12 -0
  70. package/packages/@repo/models/dist/tenant.d.ts.map +1 -1
  71. package/packages/@repo/models/package.json +1 -1
  72. package/packages/@repo/models/src/docs-config.ts +3 -3
  73. package/packages/@repo/models/src/tenant.ts +15 -0
  74. package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -1
  75. package/packages/@repo/prebuild/dist/openapi.js +32 -4
  76. package/packages/@repo/prebuild/package.json +1 -1
  77. package/packages/@repo/prebuild/src/openapi.ts +42 -4
  78. package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -1
  79. package/packages/@repo/previewing/dist/blob-source.js +18 -5
  80. package/packages/@repo/previewing/dist/config-loader.d.ts +134 -0
  81. package/packages/@repo/previewing/dist/config-loader.d.ts.map +1 -0
  82. package/packages/@repo/previewing/dist/config-loader.js +231 -0
  83. package/packages/@repo/previewing/dist/constants.d.ts +15 -0
  84. package/packages/@repo/previewing/dist/constants.d.ts.map +1 -0
  85. package/packages/@repo/previewing/dist/constants.js +14 -0
  86. package/packages/@repo/previewing/dist/content-index.d.ts +7 -0
  87. package/packages/@repo/previewing/dist/content-index.d.ts.map +1 -0
  88. package/packages/@repo/previewing/dist/content-index.js +291 -0
  89. package/packages/@repo/previewing/dist/index.d.ts +13 -121
  90. package/packages/@repo/previewing/dist/index.d.ts.map +1 -1
  91. package/packages/@repo/previewing/dist/index.js +11 -1003
  92. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +3 -0
  93. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +1 -0
  94. package/packages/@repo/previewing/dist/markdown/agent-markdown.js +176 -0
  95. package/packages/@repo/previewing/dist/markdown/format.d.ts +8 -0
  96. package/packages/@repo/previewing/dist/markdown/format.d.ts.map +1 -0
  97. package/packages/@repo/previewing/dist/markdown/format.js +43 -0
  98. package/packages/@repo/previewing/dist/markdown/links.d.ts +3 -0
  99. package/packages/@repo/previewing/dist/markdown/links.d.ts.map +1 -0
  100. package/packages/@repo/previewing/dist/markdown/links.js +31 -0
  101. package/packages/@repo/previewing/dist/openapi-pages.d.ts +7 -0
  102. package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +1 -0
  103. package/packages/@repo/previewing/dist/openapi-pages.js +200 -0
  104. package/packages/@repo/previewing/dist/search-index.d.ts +4 -0
  105. package/packages/@repo/previewing/dist/search-index.d.ts.map +1 -0
  106. package/packages/@repo/previewing/dist/search-index.js +23 -0
  107. package/packages/@repo/previewing/dist/serialization.d.ts +13 -0
  108. package/packages/@repo/previewing/dist/serialization.d.ts.map +1 -0
  109. package/packages/@repo/previewing/dist/serialization.js +108 -0
  110. package/packages/@repo/previewing/dist/toc-index.d.ts +5 -0
  111. package/packages/@repo/previewing/dist/toc-index.d.ts.map +1 -0
  112. package/packages/@repo/previewing/dist/toc-index.js +53 -0
  113. package/packages/@repo/previewing/dist/types.d.ts +92 -0
  114. package/packages/@repo/previewing/dist/types.d.ts.map +1 -0
  115. package/packages/@repo/previewing/dist/types.js +1 -0
  116. package/packages/@repo/previewing/dist/utility-index.d.ts +7 -0
  117. package/packages/@repo/previewing/dist/utility-index.d.ts.map +1 -0
  118. package/packages/@repo/previewing/dist/utility-index.js +201 -0
  119. package/packages/@repo/previewing/package.json +1 -1
  120. package/packages/@repo/previewing/src/blob-source.ts +20 -5
  121. package/packages/@repo/previewing/src/config-loader.ts +316 -0
  122. package/packages/@repo/previewing/src/constants.ts +16 -0
  123. package/packages/@repo/previewing/src/content-index.ts +384 -0
  124. package/packages/@repo/previewing/src/index.ts +69 -1515
  125. package/packages/@repo/previewing/src/markdown/agent-markdown.ts +254 -0
  126. package/packages/@repo/previewing/src/markdown/format.ts +63 -0
  127. package/packages/@repo/previewing/src/markdown/links.ts +46 -0
  128. package/packages/@repo/previewing/src/openapi-pages.ts +319 -0
  129. package/packages/@repo/previewing/src/search-index.ts +38 -0
  130. package/packages/@repo/previewing/src/serialization.ts +191 -0
  131. package/packages/@repo/previewing/src/toc-index.ts +72 -0
  132. package/packages/@repo/previewing/src/types.ts +105 -0
  133. package/packages/@repo/previewing/src/utility-index.ts +304 -0
  134. package/packages/@repo/validation/package.json +1 -1
  135. package/scripts/repo-packages.mjs +8 -0
  136. package/docs/components/ui/site-footer.tsx +0 -41
@@ -3,16 +3,24 @@ import type { TenantResolution } from "@repo/contracts";
3
3
  import type { Tenant } from "@repo/models";
4
4
  import type { UtilityIndex } from "@repo/previewing";
5
5
  import {
6
+ absolutiseInternalLinks,
6
7
  buildContentIndex,
7
8
  buildPageMetadataMap,
9
+ formatMarkdownPage,
10
+ formatMarkdownPageSection,
11
+ formatOpenApiPageContent,
8
12
  getPrebuiltUtilityLlmPagePath,
9
- loadContentSource,
10
13
  loadPrebuiltContentIndex,
11
14
  loadPrebuiltUtilityIndex,
12
15
  loadSiteConfig,
13
16
  PREBUILT_UTILITY_LLMS_FULL_PATH,
14
17
  PREBUILT_UTILITY_LLMS_PATH,
18
+ PREBUILT_UTILITY_LLMS_SEGMENT_PREFIX,
15
19
  PREBUILT_UTILITY_SITEMAP_PATH,
20
+ prepareLlmsFullContent,
21
+ sanitizePlaceholderUrls,
22
+ stripFrontmatter,
23
+ toAgentMarkdown,
16
24
  UTILITY_DOCS_ROOT_TOKEN,
17
25
  } from "@repo/previewing";
18
26
 
@@ -25,6 +33,7 @@ import {
25
33
  getDocsCollectionWithNavigation,
26
34
  getDocsNavigation,
27
35
  } from "@/lib/docs-collection";
36
+ import { capLlmsFullContent } from "@/lib/llms-full";
28
37
  import {
29
38
  buildNavigation,
30
39
  enrichNavWithMetadata,
@@ -39,6 +48,10 @@ import { createTimedPromiseCache } from "@/lib/server-cache";
39
48
  import { getRequestProtocol } from "@/lib/tenancy";
40
49
  import type { TenantRequestContext } from "@/lib/tenant-utility-context";
41
50
 
51
+ // Re-exported so tenant-static.unit.test.ts continues to guard the shared
52
+ // implementation now living in @repo/previewing.
53
+ export { absolutiseInternalLinks, sanitizePlaceholderUrls };
54
+
42
55
  const TENANT_STATIC_CACHE_TTL_MS = 30 * 60 * 1000;
43
56
 
44
57
  const getTenantStaticCacheKey = (tenant: Tenant) =>
@@ -218,37 +231,6 @@ const loadTenantUrlData = async (tenant: Tenant) =>
218
231
  async () => await buildTenantUrlData(tenant)
219
232
  );
220
233
 
221
- const formatOpenApiPageText = (entry: OpenApiEntry): string => {
222
- const parts = [
223
- `Method: ${entry.operation.method}`,
224
- `Path: ${entry.operation.path}`,
225
- ];
226
-
227
- if (entry.operation.description) {
228
- parts.push(entry.operation.description);
229
- }
230
- if (entry.operation.tags.length) {
231
- parts.push(`Tags: ${entry.operation.tags.join(", ")}`);
232
- }
233
- if (entry.operation.parameters.length) {
234
- parts.push(
235
- `Parameters:\n${JSON.stringify(entry.operation.parameters, null, 2)}`
236
- );
237
- }
238
- if (entry.operation.requestBody) {
239
- parts.push(
240
- `Request Body:\n${JSON.stringify(entry.operation.requestBody, null, 2)}`
241
- );
242
- }
243
- if (entry.operation.responses) {
244
- parts.push(
245
- `Responses:\n${JSON.stringify(entry.operation.responses, null, 2)}`
246
- );
247
- }
248
-
249
- return parts.join("\n\n");
250
- };
251
-
252
234
  const resolveLlmPages = (
253
235
  data: Awaited<ReturnType<typeof loadTenantUrlData>>
254
236
  ): (
@@ -300,49 +282,6 @@ const resolveLlmPages = (
300
282
  })
301
283
  .filter((page) => page !== null);
302
284
 
303
- const FRONTMATTER_REGEX = /^---\s*\n[\s\S]*?\n---\s*\n?/;
304
- const LEADING_H1_REGEX = /^#\s+([^\r\n]+)(?:\r?\n(?:\r?\n)?)?/;
305
-
306
- const stripFrontmatter = (source: string) =>
307
- source.replace(FRONTMATTER_REGEX, "").trim();
308
-
309
- const stripMatchingLeadingH1 = (source: string, title: string) => {
310
- const trimmed = source.trimStart();
311
- const match = LEADING_H1_REGEX.exec(trimmed);
312
- if (!match) {
313
- return trimmed.trim();
314
- }
315
-
316
- const [headingLine = "", headingTitle = ""] = match;
317
- if (slugify(headingTitle) !== slugify(title)) {
318
- return trimmed.trim();
319
- }
320
-
321
- return trimmed.slice(headingLine.length).trim();
322
- };
323
-
324
- const formatMarkdownPage = (title: string, source: string) => {
325
- const content = stripMatchingLeadingH1(source, title);
326
- if (!content) {
327
- return `# ${title}`;
328
- }
329
-
330
- return `# ${title}\n\n${content}`;
331
- };
332
-
333
- const formatMarkdownPageSection = (
334
- title: string,
335
- url: string,
336
- source: string
337
- ) => {
338
- const content = stripMatchingLeadingH1(source, title);
339
- if (!content) {
340
- return `# ${title} (${url})`;
341
- }
342
-
343
- return `# ${title} (${url})\n\n${content}`;
344
- };
345
-
346
285
  const buildRuntimeUtilityIndex = async (
347
286
  tenant: Tenant
348
287
  ): Promise<UtilityIndex> => {
@@ -351,19 +290,16 @@ const buildRuntimeUtilityIndex = async (
351
290
  resolveLlmPages(data).map(async (page) => {
352
291
  if (page.kind === "openapi") {
353
292
  return {
354
- content: formatOpenApiPageText(page.entry),
293
+ content: formatOpenApiPageContent(page.entry.operation),
355
294
  description: page.description,
356
295
  slug: page.slug,
357
296
  title: page.title,
358
297
  };
359
298
  }
360
299
 
361
- const raw = await loadContentSource(
362
- data.contentSource,
363
- page.relativePath
364
- );
300
+ const raw = await data.contentSource.readFile(page.relativePath);
365
301
  return {
366
- content: stripFrontmatter(raw),
302
+ content: toAgentMarkdown(stripFrontmatter(raw)),
367
303
  description: page.description,
368
304
  slug: page.slug,
369
305
  title: page.title,
@@ -378,7 +314,7 @@ const buildRuntimeUtilityIndex = async (
378
314
  };
379
315
  };
380
316
 
381
- const loadTenantUtilityIndex = async (tenant: Tenant) =>
317
+ export const loadTenantUtilityIndex = async (tenant: Tenant) =>
382
318
  await tenantUtilityIndexCache.getOrCreate(
383
319
  getTenantStaticCacheKey(tenant),
384
320
  async () => {
@@ -449,15 +385,17 @@ export const buildTenantRobotsTxt = (
449
385
  const basePath = getCanonicalDocBasePath(tenant, context);
450
386
  return `User-agent: *
451
387
  Allow: /
452
- Sitemap: ${origin}${toDocHref("sitemap.xml", basePath)}
388
+ Content-Signal: ai-train=no, search=yes, ai-input=yes
453
389
 
454
390
  # LLM-friendly content
455
- # ${origin}${toDocHref("llms.txt", basePath)} - Index of all documentation pages
456
- # ${origin}${toDocHref("llms-full.txt", basePath)} - Full documentation content
457
391
  # Append .md to any page URL for raw markdown
392
+ # ${origin}${toDocHref("llms-full.txt", basePath)} - Full documentation content
393
+ # ${origin}${toDocHref("llms.txt", basePath)} - Index of all documentation pages
394
+
395
+ Sitemap: ${origin}${toDocHref("sitemap.xml", basePath)}
458
396
 
459
397
  # Agent Skills
460
- # ${origin}/.well-known/skills/index.json - Discover installable agent skills`;
398
+ # ${origin}${toDocHref(".well-known/skills/index.json", basePath)} - Discover installable agent skills`;
461
399
  };
462
400
 
463
401
  const getNavGroupSegments = (
@@ -514,7 +452,7 @@ export const buildTenantLlmsTxt = async (
514
452
  "",
515
453
  `Sitemap: ${origin}${toDocHref("sitemap.xml", basePath)}`,
516
454
  `Full content: ${origin}${toDocHref("llms-full.txt", basePath)}`,
517
- `Skills: ${origin}/.well-known/skills/index.json`,
455
+ `Skills: ${origin}${toDocHref(".well-known/skills/index.json", basePath)}`,
518
456
  ...segmentLines,
519
457
  "",
520
458
  "## Docs",
@@ -532,26 +470,42 @@ export const buildTenantLlmsFullTxt = async (
532
470
  tenant: Tenant,
533
471
  context: TenantRequestContext = {}
534
472
  ) => {
473
+ const origin = getCanonicalOrigin(tenant, context);
474
+ const basePath = getCanonicalDocBasePath(tenant, context);
475
+ const indexUrl = `${origin}${toDocHref("llms.txt", basePath)}`;
476
+
535
477
  const prebuilt = await loadTenantUtilityTemplate(
536
478
  tenant,
537
479
  PREBUILT_UTILITY_LLMS_FULL_PATH
538
480
  );
539
481
  if (prebuilt) {
540
- return renderUtilityTemplate(prebuilt, tenant, context);
482
+ const rendered = renderUtilityTemplate(prebuilt, tenant, context);
483
+ return capLlmsFullContent(
484
+ prepareLlmsFullContent(rendered, origin, basePath),
485
+ indexUrl
486
+ );
541
487
  }
542
488
 
543
489
  const data = await loadTenantUtilityIndex(tenant);
544
- const origin = getCanonicalOrigin(tenant, context);
545
- const basePath = getCanonicalDocBasePath(tenant, context);
546
490
  const parts = data.pages.map((page) => {
547
491
  const url = `${origin}${toDocHref(page.slug, basePath)}`;
548
- return formatMarkdownPageSection(page.title, url, page.content);
492
+ const content = prepareLlmsFullContent(page.content, origin, basePath);
493
+ return formatMarkdownPageSection(
494
+ page.title,
495
+ url,
496
+ content,
497
+ page.description
498
+ );
549
499
  });
550
500
 
551
- return parts.join("\n\n");
501
+ return capLlmsFullContent(parts.join("\n\n"), indexUrl);
552
502
  };
553
503
 
554
- export const getLlmPageText = async (tenant: Tenant, slug: string) => {
504
+ export const getLlmPageText = async (
505
+ tenant: Tenant,
506
+ slug: string,
507
+ _context: TenantRequestContext = {}
508
+ ) => {
555
509
  const prebuilt = await loadTenantUtilityTemplate(
556
510
  tenant,
557
511
  getPrebuiltUtilityLlmPagePath(slug)
@@ -567,7 +521,11 @@ export const getLlmPageText = async (tenant: Tenant, slug: string) => {
567
521
  if (!page) {
568
522
  return null;
569
523
  }
570
- return formatMarkdownPage(page.title, page.content);
524
+ return formatMarkdownPage(
525
+ page.title,
526
+ toAgentMarkdown(page.content),
527
+ page.description
528
+ );
571
529
  };
572
530
 
573
531
  export const buildTenantSkillsIndex = async (
@@ -639,6 +597,14 @@ export const buildTenantLlmsSegment = async (
639
597
  segmentName: string,
640
598
  context: TenantRequestContext = {}
641
599
  ): Promise<string | null> => {
600
+ const prebuilt = await loadTenantUtilityTemplate(
601
+ tenant,
602
+ `${PREBUILT_UTILITY_LLMS_SEGMENT_PREFIX}${segmentName}.txt`
603
+ );
604
+ if (prebuilt) {
605
+ return renderUtilityTemplate(prebuilt, tenant, context);
606
+ }
607
+
642
608
  const data = await loadTenantUrlData(tenant);
643
609
  const segments = getNavGroupSegments(data);
644
610
  const segmentSlugs = segments.get(segmentName);
@@ -665,7 +631,13 @@ export const buildTenantLlmsSegment = async (
665
631
 
666
632
  const parts = segmentPages.map((page) => {
667
633
  const url = `${origin}${toDocHref(page.slug, basePath)}`;
668
- return formatMarkdownPageSection(page.title, url, page.content);
634
+ const content = prepareLlmsFullContent(page.content, origin, basePath);
635
+ return formatMarkdownPageSection(
636
+ page.title,
637
+ url,
638
+ content,
639
+ page.description
640
+ );
669
641
  });
670
642
 
671
643
  return [
@@ -685,7 +657,8 @@ export const listTenantLlmsSegments = async (
685
657
 
686
658
  export const getPageJson = async (
687
659
  tenant: Tenant,
688
- slug: string
660
+ slug: string,
661
+ context: TenantRequestContext = {}
689
662
  ): Promise<Record<string, unknown> | null> => {
690
663
  const data = await loadTenantUrlData(tenant);
691
664
  const contentEntry = data.contentIndex.bySlug.get(slug);
@@ -693,9 +666,10 @@ export const getPageJson = async (
693
666
  return null;
694
667
  }
695
668
 
696
- const basePath = tenant.pathPrefix ? `/${tenant.pathPrefix}` : "";
697
- const url = `https://${tenant.primaryDomain}${toDocHref(slug, basePath)}`;
698
- const markdownUrl = `https://${tenant.primaryDomain}${toMarkdownDocHref(slug, basePath)}`;
669
+ const origin = getCanonicalOrigin(tenant, context);
670
+ const basePath = getCanonicalDocBasePath(tenant, context);
671
+ const url = `${origin}${toDocHref(slug, basePath)}`;
672
+ const markdownUrl = `${origin}${toMarkdownDocHref(slug, basePath)}`;
699
673
 
700
674
  const result: Record<string, unknown> = {
701
675
  "@context": "https://schema.org",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blodemd",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Blode.md CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,8 @@
14
14
  "dev-server",
15
15
  "docs",
16
16
  "packages",
17
- "scripts/prepare-package.mjs"
17
+ "scripts/prepare-package.mjs",
18
+ "scripts/repo-packages.mjs"
18
19
  ],
19
20
  "type": "module",
20
21
  "main": "./dist/index.mjs",
@@ -34,7 +35,7 @@
34
35
  "lint:fix": "oxlint --fix .",
35
36
  "format": "oxfmt --write .",
36
37
  "format:check": "oxfmt .",
37
- "test:unit": "vitest run --root ../.. --config vitest.unit.config.ts apps/cli/src"
38
+ "test:unit": "sh -c 'cd ../.. && vitest run --config vitest.config.ts --project unit apps/cli/src'"
38
39
  },
39
40
  "dependencies": {
40
41
  "@base-ui/react": "^1.3.0",
@@ -42,7 +43,7 @@
42
43
  "@mdx-js/mdx": "^3.1.1",
43
44
  "@shikijs/rehype": "^4.0.2",
44
45
  "@tailwindcss/postcss": "^4.2.2",
45
- "@types/node": "^22.19.15",
46
+ "@types/node": "^24.12.2",
46
47
  "@types/react": "19.2.14",
47
48
  "@types/react-dom": "19.2.3",
48
49
  "blode-icons-react": "^0.3.10",
@@ -76,6 +77,8 @@
76
77
  },
77
78
  "devDependencies": {
78
79
  "@repo/common": "*",
80
+ "@repo/contracts": "*",
81
+ "@repo/models": "*",
79
82
  "@repo/previewing": "*",
80
83
  "@repo/typescript-config": "*",
81
84
  "oxfmt": "^0.42.0",
@@ -84,6 +87,6 @@
84
87
  "ultracite": "^7.3.2"
85
88
  },
86
89
  "engines": {
87
- "node": ">=20.17.0"
90
+ "node": "24.x"
88
91
  }
89
92
  }
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "@repo/typescript-config": "*",
28
- "@types/node": "^22.19.15",
28
+ "@types/node": "^24.12.2",
29
29
  "oxfmt": "^0.42.0",
30
30
  "oxlint": "^1.57.0",
31
31
  "typescript": "6.0.2",
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ export declare const ProjectAnalyticsGa4Schema: z.ZodObject<{
3
+ measurementId: z.ZodString;
4
+ }, z.core.$strip>;
5
+ export type ProjectAnalyticsGa4 = z.infer<typeof ProjectAnalyticsGa4Schema>;
6
+ export declare const ProjectAnalyticsPosthogSchema: z.ZodObject<{
7
+ host: z.ZodOptional<z.ZodString>;
8
+ projectKey: z.ZodString;
9
+ }, z.core.$strip>;
10
+ export type ProjectAnalyticsPosthog = z.infer<typeof ProjectAnalyticsPosthogSchema>;
11
+ export declare const ProjectAnalyticsSchema: z.ZodObject<{
12
+ ga4: z.ZodOptional<z.ZodObject<{
13
+ measurementId: z.ZodString;
14
+ }, z.core.$strip>>;
15
+ posthog: z.ZodOptional<z.ZodObject<{
16
+ host: z.ZodOptional<z.ZodString>;
17
+ projectKey: z.ZodString;
18
+ }, z.core.$strip>>;
19
+ }, z.core.$strip>;
20
+ export type ProjectAnalytics = z.infer<typeof ProjectAnalyticsSchema>;
21
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,yBAAyB;;iBAOpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,6BAA6B;;;iBAQxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;iBAGjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ const GA4_MEASUREMENT_ID_REGEX = /^G-[A-Z0-9]{4,20}$/;
3
+ const POSTHOG_PROJECT_KEY_REGEX = /^phc_[A-Za-z0-9]{20,}$/;
4
+ export const ProjectAnalyticsGa4Schema = z.object({
5
+ measurementId: z
6
+ .string()
7
+ .regex(GA4_MEASUREMENT_ID_REGEX, "GA4 measurement IDs look like G-XXXXXXXXXX."),
8
+ });
9
+ export const ProjectAnalyticsPosthogSchema = z.object({
10
+ host: z.string().url().optional(),
11
+ projectKey: z
12
+ .string()
13
+ .regex(POSTHOG_PROJECT_KEY_REGEX, "PostHog project keys start with phc_. Personal API keys (phx_) are not supported."),
14
+ });
15
+ export const ProjectAnalyticsSchema = z.object({
16
+ ga4: ProjectAnalyticsGa4Schema.optional(),
17
+ posthog: ProjectAnalyticsPosthogSchema.optional(),
18
+ });
@@ -30,7 +30,7 @@ export const PublishDeploymentCreateSchema = z.object({
30
30
  environment: DeploymentEnvironmentSchema.optional(),
31
31
  });
32
32
  export const PublishDeploymentFileSchema = z.object({
33
- contentBase64: z.string().min(1),
33
+ contentBase64: z.string().base64(),
34
34
  contentType: z.string().min(1).optional(),
35
35
  path: z.string().min(1),
36
36
  });
@@ -8,7 +8,7 @@ export const GitConnectionSchema = z.object({
8
8
  createdAt: IsoDateSchema,
9
9
  docsPath: z.string().min(1),
10
10
  id: IdSchema,
11
- installationId: z.number().int().positive(),
11
+ installationId: z.number().int().positive().safe(),
12
12
  projectId: IdSchema,
13
13
  provider: GitProviderSchema,
14
14
  repository: z.string().min(1),
@@ -17,7 +17,7 @@ export const GitConnectionSchema = z.object({
17
17
  export const GitConnectionBindSchema = z.object({
18
18
  branch: z.string().min(1).default("main"),
19
19
  docsPath: z.string().min(1).default("docs"),
20
- installationId: z.number().int().positive(),
20
+ installationId: z.number().int().positive().safe(),
21
21
  repository: z.string().regex(/^[\w.-]+\/[\w.-]+$/, {
22
22
  message: "Repository must be in the format owner/repo.",
23
23
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,QAAQ,aAAoB,CAAC;AAC1C,MAAM,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAE1C,eAAO,MAAM,UAAU,aAGC,CAAC;AACzB,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,WAAW,aAAqB,CAAC;AAC9C,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,SAAS,aAAmB,CAAC;AAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,cAAc,aAAoB,CAAC;AAChD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,UAAU,aAAoB,CAAC;AAC5C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,QAAQ,aAAoB,CAAC;AAC1C,MAAM,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAE1C,eAAO,MAAM,UAAU,aAI2B,CAAC;AACnD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,WAAW,aAAqB,CAAC;AAC9C,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,SAAS,aAAmB,CAAC;AAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,cAAc,aAAoB,CAAC;AAChD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,UAAU,aAAoB,CAAC;AAC5C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
@@ -3,7 +3,8 @@ export const IdSchema = z.string().uuid();
3
3
  export const SlugSchema = z
4
4
  .string()
5
5
  .min(1)
6
- .regex(/^[a-z0-9-]+$/);
6
+ .max(63)
7
+ .regex(/^(?!-)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/);
7
8
  export const EmailSchema = z.string().email();
8
9
  export const UrlSchema = z.string().url();
9
10
  export const HostnameSchema = z.string().min(1);
@@ -1,3 +1,4 @@
1
+ export * from "./analytics.js";
1
2
  export * from "./dates.js";
2
3
  export * from "./deployment.js";
3
4
  export * from "./domain.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC"}
@@ -1,5 +1,6 @@
1
1
  // biome-ignore lint/performance/noBarrelFile: This is the main entry point for the package
2
2
  // eslint-disable-next-line no-barrel-file
3
+ export * from "./analytics.js";
3
4
  export * from "./dates.js";
4
5
  export * from "./deployment.js";
5
6
  export * from "./domain.js";
@@ -1,5 +1,14 @@
1
1
  import { z } from "zod";
2
2
  export declare const ProjectSchema: z.ZodObject<{
3
+ analytics: z.ZodOptional<z.ZodNullable<z.ZodObject<{
4
+ ga4: z.ZodOptional<z.ZodObject<{
5
+ measurementId: z.ZodString;
6
+ }, z.core.$strip>>;
7
+ posthog: z.ZodOptional<z.ZodObject<{
8
+ host: z.ZodOptional<z.ZodString>;
9
+ projectKey: z.ZodString;
10
+ }, z.core.$strip>>;
11
+ }, z.core.$strip>>>;
3
12
  createdAt: z.ZodString;
4
13
  deploymentName: z.ZodString;
5
14
  description: z.ZodOptional<z.ZodString>;
@@ -10,13 +19,21 @@ export declare const ProjectSchema: z.ZodObject<{
10
19
  }, z.core.$strip>;
11
20
  export type Project = z.infer<typeof ProjectSchema>;
12
21
  export declare const ProjectCreateSchema: z.ZodObject<{
13
- deploymentName: z.ZodString;
14
22
  description: z.ZodOptional<z.ZodString>;
15
23
  name: z.ZodString;
16
24
  slug: z.ZodString;
17
25
  }, z.core.$strip>;
18
26
  export type ProjectCreateInput = z.infer<typeof ProjectCreateSchema>;
19
27
  export declare const ProjectUpdateSchema: z.ZodObject<{
28
+ analytics: z.ZodOptional<z.ZodNullable<z.ZodObject<{
29
+ ga4: z.ZodOptional<z.ZodObject<{
30
+ measurementId: z.ZodString;
31
+ }, z.core.$strip>>;
32
+ posthog: z.ZodOptional<z.ZodObject<{
33
+ host: z.ZodOptional<z.ZodString>;
34
+ projectKey: z.ZodString;
35
+ }, z.core.$strip>>;
36
+ }, z.core.$strip>>>;
20
37
  deploymentName: z.ZodOptional<z.ZodString>;
21
38
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
39
  name: z.ZodOptional<z.ZodString>;
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,aAAa;;;;;;;;iBAQxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB;;;;;iBAK9B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAErE,eAAO,MAAM,mBAAmB;;;;iBAI9B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;iBASxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB;;;;iBAI9B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAErE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;iBAK9B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import { z } from "zod";
2
+ import { ProjectAnalyticsSchema } from "./analytics.js";
2
3
  import { IsoDateSchema } from "./dates.js";
3
4
  import { IdSchema, SlugSchema } from "./ids.js";
4
5
  export const ProjectSchema = z.object({
6
+ analytics: ProjectAnalyticsSchema.nullable().optional(),
5
7
  createdAt: IsoDateSchema,
6
8
  deploymentName: z.string().min(1),
7
9
  description: z.string().optional(),
@@ -11,12 +13,12 @@ export const ProjectSchema = z.object({
11
13
  updatedAt: IsoDateSchema,
12
14
  });
13
15
  export const ProjectCreateSchema = z.object({
14
- deploymentName: z.string().min(1),
15
16
  description: z.string().optional(),
16
17
  name: z.string().min(1),
17
18
  slug: SlugSchema,
18
19
  });
19
20
  export const ProjectUpdateSchema = z.object({
21
+ analytics: ProjectAnalyticsSchema.nullable().optional(),
20
22
  deploymentName: z.string().min(1).optional(),
21
23
  description: z.string().nullable().optional(),
22
24
  name: z.string().min(1).optional(),
@@ -7,6 +7,15 @@ export type TenantStatus = z.infer<typeof TenantStatusSchema>;
7
7
  export declare const TenantSchema: z.ZodObject<{
8
8
  activeDeploymentId: z.ZodOptional<z.ZodString>;
9
9
  activeDeploymentManifestUrl: z.ZodOptional<z.ZodString>;
10
+ analytics: z.ZodOptional<z.ZodObject<{
11
+ ga4: z.ZodOptional<z.ZodObject<{
12
+ measurementId: z.ZodString;
13
+ }, z.core.$strip>>;
14
+ posthog: z.ZodOptional<z.ZodObject<{
15
+ host: z.ZodOptional<z.ZodString>;
16
+ projectKey: z.ZodString;
17
+ }, z.core.$strip>>;
18
+ }, z.core.$strip>>;
10
19
  customDomains: z.ZodArray<z.ZodString>;
11
20
  description: z.ZodOptional<z.ZodString>;
12
21
  id: z.ZodString;
@@ -34,6 +43,15 @@ export declare const TenantResolutionSchema: z.ZodObject<{
34
43
  tenant: z.ZodObject<{
35
44
  activeDeploymentId: z.ZodOptional<z.ZodString>;
36
45
  activeDeploymentManifestUrl: z.ZodOptional<z.ZodString>;
46
+ analytics: z.ZodOptional<z.ZodObject<{
47
+ ga4: z.ZodOptional<z.ZodObject<{
48
+ measurementId: z.ZodString;
49
+ }, z.core.$strip>>;
50
+ posthog: z.ZodOptional<z.ZodObject<{
51
+ host: z.ZodOptional<z.ZodString>;
52
+ projectKey: z.ZodString;
53
+ }, z.core.$strip>>;
54
+ }, z.core.$strip>>;
37
55
  customDomains: z.ZodArray<z.ZodString>;
38
56
  description: z.ZodOptional<z.ZodString>;
39
57
  id: z.ZodString;
@@ -59,6 +77,15 @@ export declare const TenantEdgeHostRecordSchema: z.ZodObject<{
59
77
  tenant: z.ZodObject<{
60
78
  activeDeploymentId: z.ZodOptional<z.ZodString>;
61
79
  activeDeploymentManifestUrl: z.ZodOptional<z.ZodString>;
80
+ analytics: z.ZodOptional<z.ZodObject<{
81
+ ga4: z.ZodOptional<z.ZodObject<{
82
+ measurementId: z.ZodString;
83
+ }, z.core.$strip>>;
84
+ posthog: z.ZodOptional<z.ZodObject<{
85
+ host: z.ZodOptional<z.ZodString>;
86
+ projectKey: z.ZodString;
87
+ }, z.core.$strip>>;
88
+ }, z.core.$strip>>;
62
89
  customDomains: z.ZodArray<z.ZodString>;
63
90
  description: z.ZodOptional<z.ZodString>;
64
91
  id: z.ZodString;
@@ -80,6 +107,15 @@ export declare const TenantEdgeSlugRecordSchema: z.ZodObject<{
80
107
  tenant: z.ZodObject<{
81
108
  activeDeploymentId: z.ZodOptional<z.ZodString>;
82
109
  activeDeploymentManifestUrl: z.ZodOptional<z.ZodString>;
110
+ analytics: z.ZodOptional<z.ZodObject<{
111
+ ga4: z.ZodOptional<z.ZodObject<{
112
+ measurementId: z.ZodString;
113
+ }, z.core.$strip>>;
114
+ posthog: z.ZodOptional<z.ZodObject<{
115
+ host: z.ZodOptional<z.ZodString>;
116
+ projectKey: z.ZodString;
117
+ }, z.core.$strip>>;
118
+ }, z.core.$strip>>;
83
119
  customDomains: z.ZodArray<z.ZodString>;
84
120
  description: z.ZodOptional<z.ZodString>;
85
121
  id: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../src/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,eAAO,MAAM,kBAAkB;;;EAAiC,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;iBAYvB,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;iBAMrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,kCAAkC,iBAAiB,CAAC;AACjE,eAAO,MAAM,kCAAkC,iBAAiB,CAAC;AAEjE,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,WACJ,CAAC;AAEjD,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,WACzB,CAAC;AAO5B,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,WACc,CAAC;AAEhE,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,WACc,CAAC;AAEhE,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WACkB,CAAC;AAE1E,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WACkB,CAAC;AAE1E,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,aAGjD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,aAGjD,CAAC"}
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../src/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,kBAAkB;;;EAAiC,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;iBAavB,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,kCAAkC,iBAAiB,CAAC;AACjE,eAAO,MAAM,kCAAkC,iBAAiB,CAAC;AAEjE,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,WACJ,CAAC;AAEjD,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,WACzB,CAAC;AAO5B,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,WACc,CAAC;AAEhE,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,WACc,CAAC;AAEhE,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WACkB,CAAC;AAE1E,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,WACkB,CAAC;AAE1E,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,aAGjD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,aAGjD,CAAC"}
@@ -1,9 +1,11 @@
1
1
  import { z } from "zod";
2
+ import { ProjectAnalyticsSchema } from "./analytics.js";
2
3
  import { HostnameSchema, IdSchema, PathSchema, SlugSchema, UrlSchema, } from "./ids.js";
3
4
  export const TenantStatusSchema = z.enum(["active", "disabled"]);
4
5
  export const TenantSchema = z.object({
5
6
  activeDeploymentId: IdSchema.optional(),
6
7
  activeDeploymentManifestUrl: UrlSchema.optional(),
8
+ analytics: ProjectAnalyticsSchema.optional(),
7
9
  customDomains: z.array(HostnameSchema),
8
10
  description: z.string().optional(),
9
11
  id: IdSchema,
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@repo/typescript-config": "*",
31
- "@types/node": "^22.19.15",
31
+ "@types/node": "^24.12.2",
32
32
  "oxfmt": "^0.42.0",
33
33
  "oxlint": "^1.57.0",
34
34
  "typescript": "6.0.2",