@olonjs/cli 3.0.129 → 3.0.131

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.
@@ -1674,7 +1674,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
1674
1674
  "@tiptap/extension-link": "^2.11.5",
1675
1675
  "@tiptap/react": "^2.11.5",
1676
1676
  "@tiptap/starter-kit": "^2.11.5",
1677
- "@olonjs/core": "^1.0.120",
1677
+ "@olonjs/core": "^1.0.122",
1678
1678
  "class-variance-authority": "^0.7.1",
1679
1679
  "clsx": "^2.1.1",
1680
1680
  "lucide-react": "^0.474.0",
@@ -2587,13 +2587,13 @@ import { JsonPagesEngine } from '@olonjs/core';
2587
2587
  import type { JsonPagesConfig, LibraryImageEntry, ProjectState } from '@olonjs/core';
2588
2588
  import { normalizeBasePath, withBasePath } from '@olonjs/core';
2589
2589
  import { ComponentRegistry } from '@/lib/ComponentRegistry';
2590
- import { SECTION_SCHEMAS } from '@/lib/schemas';
2590
+ import { SECTION_SCHEMAS, SECTION_SUBMISSION_SCHEMAS } from '@/lib/schemas';
2591
2591
  import { addSectionConfig } from '@/lib/addSectionConfig';
2592
2592
  import { getHydratedData } from '@/lib/draftStorage';
2593
2593
  import type { SiteConfig, ThemeConfig, MenuConfig, PageConfig } from '@/types';
2594
- import type { DeployPhase, StepId } from '@/types/deploy';
2595
- import { DEPLOY_STEPS } from '@/lib/deploySteps';
2596
- import { startCloudSaveStream } from '@/lib/cloudSaveStream';
2594
+ import type { DeployPhase, StepId } from '@olonjs/core';
2595
+ import { DEPLOY_STEPS } from '@olonjs/core';
2596
+ import { startCloudSaveStream } from '@olonjs/core';
2597
2597
  import siteData from '@/data/config/site.json';
2598
2598
  import themeData from '@/data/config/theme.json';
2599
2599
  import menuData from '@/data/config/menu.json';
@@ -2603,7 +2603,7 @@ import { EmptyTenantView } from '@/components/empty-tenant';
2603
2603
  import { Skeleton } from '@/components/ui/skeleton';
2604
2604
  import { ThemeProvider } from '@/components/ThemeProvider';
2605
2605
  import { useOlonForms } from '@/lib/useOlonForms';
2606
- import { OlonFormsContext } from '@/lib/OlonFormsContext';
2606
+ import { OlonFormsContext } from '@olonjs/core';
2607
2607
  import { iconMap } from '@/lib/IconResolver';
2608
2608
 
2609
2609
  import tenantCss from './index.css?inline';
@@ -2751,7 +2751,6 @@ function coerceSiteConfig(value: unknown): SiteConfig | null {
2751
2751
  }
2752
2752
  if (!isObjectRecord(input)) return null;
2753
2753
  if (!isObjectRecord(input.identity)) return null;
2754
- if (!Array.isArray(input.pages)) return null;
2755
2754
 
2756
2755
  return input as unknown as SiteConfig;
2757
2756
  }
@@ -3442,6 +3441,7 @@ function App() {
3442
3441
  basePath: APP_BASE_PATH,
3443
3442
  registry: ComponentRegistry as JsonPagesConfig['registry'],
3444
3443
  schemas: SECTION_SCHEMAS as unknown as JsonPagesConfig['schemas'],
3444
+ submissionSchemas: SECTION_SUBMISSION_SCHEMAS as unknown as JsonPagesConfig['submissionSchemas'],
3445
3445
  pages,
3446
3446
  siteConfig,
3447
3447
  themeConfig,
@@ -3838,7 +3838,7 @@ END_OF_FILE_CONTENT
3838
3838
  echo "Creating src/components/empty-tenant/schema.ts..."
3839
3839
  cat << 'END_OF_FILE_CONTENT' > "src/components/empty-tenant/schema.ts"
3840
3840
  import { z } from 'zod';
3841
- import { BaseSectionData } from '@/lib/base-schemas';
3841
+ import { BaseSectionData } from '@olonjs/core';
3842
3842
 
3843
3843
  export const EmptyTenantSchema = BaseSectionData.extend({
3844
3844
  title: z.string().optional().describe('ui:text'),
@@ -3861,7 +3861,7 @@ mkdir -p "src/components/form-demo"
3861
3861
  echo "Creating src/components/form-demo/View.tsx..."
3862
3862
  cat << 'END_OF_FILE_CONTENT' > "src/components/form-demo/View.tsx"
3863
3863
  import { Icon } from '@/lib/IconResolver';
3864
- import { useFormState } from '@/lib/OlonFormsContext';
3864
+ import { useFormState } from '@olonjs/core';
3865
3865
  import type { FormDemoData } from './types';
3866
3866
 
3867
3867
  type FormDemoViewProps = {
@@ -4025,7 +4025,7 @@ END_OF_FILE_CONTENT
4025
4025
  echo "Creating src/components/form-demo/schema.ts..."
4026
4026
  cat << 'END_OF_FILE_CONTENT' > "src/components/form-demo/schema.ts"
4027
4027
  import { z } from 'zod';
4028
- import { BaseSectionData, WithFormRecipient } from '@/lib/base-schemas';
4028
+ import { BaseSectionData, WithFormRecipient } from '@olonjs/core';
4029
4029
 
4030
4030
  export const FormDemoSchema = BaseSectionData.merge(WithFormRecipient).extend({
4031
4031
  icon: z.string().optional().describe('ui:icon-picker'),
@@ -4037,6 +4037,20 @@ export const FormDemoSchema = BaseSectionData.merge(WithFormRecipient).extend({
4037
4037
 
4038
4038
  export const FormDemoSettingsSchema = z.object({});
4039
4039
 
4040
+ /**
4041
+ * Submission payload schema for the `form-demo` section.
4042
+ *
4043
+ * Describes the fields actually submitted by the rendered `<form>` in View.tsx
4044
+ * (name, email, message). Exposed via `JsonPagesConfig.submissionSchemas` so that
4045
+ * MCP agents can discover the submission contract for this section type without
4046
+ * scraping the DOM. See ADR-0002 (docs/decisions/ADR-0002-form-submission-schemas.md).
4047
+ */
4048
+ export const FormDemoSubmissionSchema = z.object({
4049
+ name: z.string().min(1).describe('Full name of the person submitting the form'),
4050
+ email: z.string().email().describe('Contact email address where we will reply'),
4051
+ message: z.string().min(1).describe('Free-form message body'),
4052
+ });
4053
+
4040
4054
  END_OF_FILE_CONTENT
4041
4055
  echo "Creating src/components/form-demo/types.ts..."
4042
4056
  cat << 'END_OF_FILE_CONTENT' > "src/components/form-demo/types.ts"
@@ -4050,7 +4064,7 @@ END_OF_FILE_CONTENT
4050
4064
  mkdir -p "src/components/save-drawer"
4051
4065
  echo "Creating src/components/save-drawer/DeployConnector.tsx..."
4052
4066
  cat << 'END_OF_FILE_CONTENT' > "src/components/save-drawer/DeployConnector.tsx"
4053
- import type { StepState } from '@/types/deploy';
4067
+ import type { StepState } from '@olonjs/core';
4054
4068
 
4055
4069
  interface DeployConnectorProps {
4056
4070
  fromState: StepState;
@@ -4096,7 +4110,7 @@ END_OF_FILE_CONTENT
4096
4110
  echo "Creating src/components/save-drawer/DeployNode.tsx..."
4097
4111
  cat << 'END_OF_FILE_CONTENT' > "src/components/save-drawer/DeployNode.tsx"
4098
4112
  import type { CSSProperties } from 'react';
4099
- import type { DeployStep, StepState } from '@/types/deploy';
4113
+ import type { DeployStep, StepState } from '@olonjs/core';
4100
4114
 
4101
4115
  interface DeployNodeProps {
4102
4116
  step: DeployStep;
@@ -4184,8 +4198,8 @@ echo "Creating src/components/save-drawer/DopaDrawer.tsx..."
4184
4198
  cat << 'END_OF_FILE_CONTENT' > "src/components/save-drawer/DopaDrawer.tsx"
4185
4199
  import { useEffect, useMemo, useState } from 'react';
4186
4200
  import { createPortal } from 'react-dom';
4187
- import type { StepId, StepState } from '@/types/deploy';
4188
- import { DEPLOY_STEPS } from '@/lib/deploySteps';
4201
+ import type { StepId, StepState } from '@olonjs/core';
4202
+ import { DEPLOY_STEPS } from '@olonjs/core';
4189
4203
  import fontsCss from '@/fonts.css?inline';
4190
4204
  import saverStyleCss from './saverStyle.css?inline';
4191
4205
  import { DeployNode } from './DeployNode';
@@ -5134,7 +5148,7 @@ END_OF_FILE_CONTENT
5134
5148
  mkdir -p "src/components/ui"
5135
5149
  echo "Creating src/components/ui/OlonMark.tsx..."
5136
5150
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/OlonMark.tsx"
5137
- import { cn } from '@/lib/utils'
5151
+ import { cn } from '@olonjs/core'
5138
5152
 
5139
5153
  interface OlonMarkProps {
5140
5154
  size?: number
@@ -5224,7 +5238,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/accordion.tsx"
5224
5238
  import * as React from "react"
5225
5239
  import { Accordion as AccordionPrimitive } from "radix-ui"
5226
5240
 
5227
- import { cn } from "@/lib/utils"
5241
+ import { cn } from "@olonjs/core"
5228
5242
  import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
5229
5243
 
5230
5244
  function Accordion({
@@ -5328,7 +5342,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/avatar.tsx"
5328
5342
  import * as React from "react"
5329
5343
  import { Avatar as AvatarPrimitive } from "radix-ui"
5330
5344
 
5331
- import { cn } from "@/lib/utils"
5345
+ import { cn } from "@olonjs/core"
5332
5346
 
5333
5347
  function Avatar({
5334
5348
  className,
@@ -5443,7 +5457,7 @@ echo "Creating src/components/ui/badge.tsx..."
5443
5457
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/badge.tsx"
5444
5458
  import * as React from 'react'
5445
5459
  import { cva, type VariantProps } from 'class-variance-authority'
5446
- import { cn } from '@/lib/utils'
5460
+ import { cn } from '@olonjs/core'
5447
5461
 
5448
5462
  const badgeVariants = cva(
5449
5463
  'inline-flex items-center px-2.5 py-0.5 text-xs font-medium transition-colors',
@@ -5478,7 +5492,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/breadcrumb.tsx"
5478
5492
  import * as React from "react"
5479
5493
  import { Slot } from "radix-ui"
5480
5494
 
5481
- import { cn } from "@/lib/utils"
5495
+ import { cn } from "@olonjs/core"
5482
5496
  import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
5483
5497
 
5484
5498
  function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
@@ -5605,7 +5619,7 @@ echo "Creating src/components/ui/button.tsx..."
5605
5619
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/button.tsx"
5606
5620
  import * as React from 'react'
5607
5621
  import { cva, type VariantProps } from 'class-variance-authority'
5608
- import { cn } from '@/lib/utils'
5622
+ import { cn } from '@olonjs/core'
5609
5623
 
5610
5624
  const buttonVariants = cva(
5611
5625
  'inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 shrink-0',
@@ -5666,7 +5680,7 @@ END_OF_FILE_CONTENT
5666
5680
  echo "Creating src/components/ui/card.tsx..."
5667
5681
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/card.tsx"
5668
5682
  import * as React from 'react'
5669
- import { cn } from '@/lib/utils'
5683
+ import { cn } from '@olonjs/core'
5670
5684
 
5671
5685
  const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
5672
5686
  ({ className, ...props }, ref) => (
@@ -5725,7 +5739,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/checkbox.tsx"
5725
5739
  import * as React from "react"
5726
5740
  import { Checkbox as CheckboxPrimitive } from "radix-ui"
5727
5741
 
5728
- import { cn } from "@/lib/utils"
5742
+ import { cn } from "@olonjs/core"
5729
5743
  import { CheckIcon } from "lucide-react"
5730
5744
 
5731
5745
  function Checkbox({
@@ -5765,7 +5779,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/dialog.tsx"
5765
5779
  import * as React from "react"
5766
5780
  import { Dialog as DialogPrimitive } from "radix-ui"
5767
5781
 
5768
- import { cn } from "@/lib/utils"
5782
+ import { cn } from "@olonjs/core"
5769
5783
  import { Button } from "@/components/ui/button"
5770
5784
  import { XIcon } from "lucide-react"
5771
5785
 
@@ -5937,7 +5951,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/dropdown-menu.tsx"
5937
5951
  import * as React from "react"
5938
5952
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
5939
5953
 
5940
- import { cn } from "@/lib/utils"
5954
+ import { cn } from "@olonjs/core"
5941
5955
  import { CheckIcon, ChevronRightIcon } from "lucide-react"
5942
5956
 
5943
5957
  function DropdownMenu({
@@ -6212,7 +6226,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/hover-card.tsx"
6212
6226
  import * as React from "react"
6213
6227
  import { HoverCard as HoverCardPrimitive } from "radix-ui"
6214
6228
 
6215
- import { cn } from "@/lib/utils"
6229
+ import { cn } from "@olonjs/core"
6216
6230
 
6217
6231
  function HoverCard({
6218
6232
  ...props
@@ -6258,7 +6272,7 @@ END_OF_FILE_CONTENT
6258
6272
  echo "Creating src/components/ui/input.tsx..."
6259
6273
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/input.tsx"
6260
6274
  import * as React from 'react'
6261
- import { cn } from '@/lib/utils'
6275
+ import { cn } from '@olonjs/core'
6262
6276
 
6263
6277
  export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
6264
6278
 
@@ -6289,7 +6303,7 @@ END_OF_FILE_CONTENT
6289
6303
  echo "Creating src/components/ui/label.tsx..."
6290
6304
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/label.tsx"
6291
6305
  import * as React from 'react'
6292
- import { cn } from '@/lib/utils'
6306
+ import { cn } from '@olonjs/core'
6293
6307
 
6294
6308
  const Label = React.forwardRef<
6295
6309
  HTMLLabelElement,
@@ -6313,7 +6327,7 @@ import * as React from "react"
6313
6327
  import { cva } from "class-variance-authority"
6314
6328
  import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui"
6315
6329
 
6316
- import { cn } from "@/lib/utils"
6330
+ import { cn } from "@olonjs/core"
6317
6331
  import { ChevronDownIcon } from "lucide-react"
6318
6332
 
6319
6333
  function NavigationMenu({
@@ -6482,7 +6496,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/progress.tsx"
6482
6496
  import * as React from "react"
6483
6497
  import { Progress as ProgressPrimitive } from "radix-ui"
6484
6498
 
6485
- import { cn } from "@/lib/utils"
6499
+ import { cn } from "@olonjs/core"
6486
6500
 
6487
6501
  function Progress({
6488
6502
  className,
@@ -6517,7 +6531,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/scroll-area.tsx"
6517
6531
  import * as React from "react"
6518
6532
  import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
6519
6533
 
6520
- import { cn } from "@/lib/utils"
6534
+ import { cn } from "@olonjs/core"
6521
6535
 
6522
6536
  function ScrollArea({
6523
6537
  className,
@@ -6576,7 +6590,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/select.tsx"
6576
6590
  import * as React from "react"
6577
6591
  import { Select as SelectPrimitive } from "radix-ui"
6578
6592
 
6579
- import { cn } from "@/lib/utils"
6593
+ import { cn } from "@olonjs/core"
6580
6594
  import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
6581
6595
 
6582
6596
  function Select({
@@ -6962,7 +6976,7 @@ END_OF_FILE_CONTENT
6962
6976
  echo "Creating src/components/ui/separator.tsx..."
6963
6977
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/separator.tsx"
6964
6978
  import * as React from 'react'
6965
- import { cn } from '@/lib/utils'
6979
+ import { cn } from '@olonjs/core'
6966
6980
 
6967
6981
  const Separator = React.forwardRef<
6968
6982
  HTMLDivElement,
@@ -6991,7 +7005,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/sheet.tsx"
6991
7005
  import * as React from "react"
6992
7006
  import { Dialog as SheetPrimitive } from "radix-ui"
6993
7007
 
6994
- import { cn } from "@/lib/utils"
7008
+ import { cn } from "@olonjs/core"
6995
7009
  import { Button } from "@/components/ui/button"
6996
7010
  import { XIcon } from "lucide-react"
6997
7011
 
@@ -7139,7 +7153,7 @@ END_OF_FILE_CONTENT
7139
7153
  # SKIP: src/components/ui/sheet.tsx:Zone.Identifier is binary and cannot be embedded as text.
7140
7154
  echo "Creating src/components/ui/skeleton.tsx..."
7141
7155
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/skeleton.tsx"
7142
- import { cn } from '@/lib/utils';
7156
+ import { cn } from '@olonjs/core';
7143
7157
  import type { HTMLAttributes } from 'react';
7144
7158
 
7145
7159
  function Skeleton({
@@ -7163,7 +7177,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/switch.tsx"
7163
7177
  import * as React from "react"
7164
7178
  import { Switch as SwitchPrimitive } from "radix-ui"
7165
7179
 
7166
- import { cn } from "@/lib/utils"
7180
+ import { cn } from "@olonjs/core"
7167
7181
 
7168
7182
  function Switch({
7169
7183
  className,
@@ -7199,7 +7213,7 @@ echo "Creating src/components/ui/table.tsx..."
7199
7213
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/table.tsx"
7200
7214
  import * as React from "react"
7201
7215
 
7202
- import { cn } from "@/lib/utils"
7216
+ import { cn } from "@olonjs/core"
7203
7217
 
7204
7218
  function Table({ className, ...props }: React.ComponentProps<"table">) {
7205
7219
  return (
@@ -7323,7 +7337,7 @@ import * as React from "react"
7323
7337
  import { cva, type VariantProps } from "class-variance-authority"
7324
7338
  import { Tabs as TabsPrimitive } from "radix-ui"
7325
7339
 
7326
- import { cn } from "@/lib/utils"
7340
+ import { cn } from "@olonjs/core"
7327
7341
 
7328
7342
  function Tabs({
7329
7343
  className,
@@ -7415,7 +7429,7 @@ echo "Creating src/components/ui/textarea.tsx..."
7415
7429
  cat << 'END_OF_FILE_CONTENT' > "src/components/ui/textarea.tsx"
7416
7430
  import * as React from "react"
7417
7431
 
7418
- import { cn } from "@/lib/utils"
7432
+ import { cn } from "@olonjs/core"
7419
7433
 
7420
7434
  function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
7421
7435
  return (
@@ -7444,7 +7458,7 @@ import * as React from "react"
7444
7458
  import { type VariantProps } from "class-variance-authority"
7445
7459
  import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui"
7446
7460
 
7447
- import { cn } from "@/lib/utils"
7461
+ import { cn } from "@olonjs/core"
7448
7462
  import { toggleVariants } from "@/components/ui/toggle"
7449
7463
 
7450
7464
  const ToggleGroupContext = React.createContext<
@@ -7539,7 +7553,7 @@ import * as React from "react"
7539
7553
  import { cva, type VariantProps } from "class-variance-authority"
7540
7554
  import { Toggle as TogglePrimitive } from "radix-ui"
7541
7555
 
7542
- import { cn } from "@/lib/utils"
7556
+ import { cn } from "@olonjs/core"
7543
7557
 
7544
7558
  const toggleVariants = cva(
7545
7559
  "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
@@ -7591,7 +7605,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/components/ui/tooltip.tsx"
7591
7605
  import * as React from "react"
7592
7606
  import { Tooltip as TooltipPrimitive } from "radix-ui"
7593
7607
 
7594
- import { cn } from "@/lib/utils"
7608
+ import { cn } from "@olonjs/core"
7595
7609
 
7596
7610
  function TooltipProvider({
7597
7611
  delayDuration = 0,
@@ -7728,16 +7742,7 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
7728
7742
  "title": "OlonJS",
7729
7743
  "logoUrl": "/brand/mark/olon-mark-dark.svg"
7730
7744
  },
7731
- "pages": [
7732
- {
7733
- "slug": "home",
7734
- "label": "Home"
7735
- },
7736
- {
7737
- "slug": "design-system",
7738
- "label": "Design System"
7739
- }
7740
- ],
7745
+
7741
7746
  "header": {
7742
7747
  "id": "global-header",
7743
7748
  "type": "header",
@@ -7989,6 +7994,7 @@ END_OF_FILE_CONTENT
7989
7994
  mkdir -p "src/emails"
7990
7995
  echo "Creating src/emails/LeadNotificationEmail.tsx..."
7991
7996
  cat << 'END_OF_FILE_CONTENT' > "src/emails/LeadNotificationEmail.tsx"
7997
+ import React from "react";
7992
7998
  import {
7993
7999
  Body,
7994
8000
  Button,
@@ -8145,11 +8151,12 @@ export function LeadNotificationEmail({
8145
8151
  );
8146
8152
  }
8147
8153
 
8148
- export default LeadNotificationEmail;
8154
+ export default LeadNotificationEmail;
8149
8155
 
8150
8156
  END_OF_FILE_CONTENT
8151
8157
  echo "Creating src/emails/LeadSenderConfirmationEmail.tsx..."
8152
8158
  cat << 'END_OF_FILE_CONTENT' > "src/emails/LeadSenderConfirmationEmail.tsx"
8159
+ import React from "react";
8153
8160
  import {
8154
8161
  Body,
8155
8162
  Container,
@@ -9506,36 +9513,6 @@ export const Icon: React.FC<IconProps> = ({ name, size = 20, className }) => {
9506
9513
 
9507
9514
 
9508
9515
 
9509
- END_OF_FILE_CONTENT
9510
- echo "Creating src/lib/OlonFormsContext.ts..."
9511
- cat << 'END_OF_FILE_CONTENT' > "src/lib/OlonFormsContext.ts"
9512
- import { createContext, useContext } from 'react';
9513
-
9514
- export type FormStatus = 'idle' | 'submitting' | 'success' | 'error';
9515
-
9516
- export interface FormState {
9517
- status: FormStatus;
9518
- message: string;
9519
- }
9520
-
9521
- const DEFAULT_FORM_STATE: FormState = { status: 'idle', message: '' };
9522
-
9523
- /**
9524
- * Context holding the submission state of every olon-managed form,
9525
- * keyed by the form's id attribute (or anchorId).
9526
- * Provided by App.tsx via useOlonForms().
9527
- */
9528
- export const OlonFormsContext = createContext<Record<string, FormState>>({});
9529
-
9530
- /**
9531
- * Read the submission state for a specific form.
9532
- * @param formId - must match the id attribute on the <form> element.
9533
- */
9534
- export function useFormState(formId: string): FormState {
9535
- const states = useContext(OlonFormsContext);
9536
- return states[formId] ?? DEFAULT_FORM_STATE;
9537
- }
9538
-
9539
9516
  END_OF_FILE_CONTENT
9540
9517
  echo "Creating src/lib/addSectionConfig.ts..."
9541
9518
  cat << 'END_OF_FILE_CONTENT' > "src/lib/addSectionConfig.ts"
@@ -9574,229 +9551,6 @@ export const addSectionConfig: AddSectionConfig = {
9574
9551
  getDefaultSectionData,
9575
9552
  };
9576
9553
 
9577
- END_OF_FILE_CONTENT
9578
- echo "Creating src/lib/base-schemas.ts..."
9579
- cat << 'END_OF_FILE_CONTENT' > "src/lib/base-schemas.ts"
9580
- import { z } from 'zod';
9581
-
9582
- /**
9583
- * Image picker field: object { url, alt? } with ui:image-picker for Form Factory.
9584
- * Use in section data and resolve with resolveAssetUrl(url, tenantId) in View.
9585
- */
9586
- export const ImageSelectionSchema = z
9587
- .object({
9588
- url: z.string(),
9589
- alt: z.string().optional(),
9590
- })
9591
- .describe('ui:image-picker');
9592
-
9593
- /**
9594
- * Base schemas shared by section capsules (CIP governance).
9595
- * Capsules extend these for consistent anchorId, array items, and settings.
9596
- */
9597
- export const BaseSectionData = z.object({
9598
- id: z.string().optional(),
9599
- anchorId: z.string().optional().describe('ui:text'),
9600
- });
9601
-
9602
- export const BaseArrayItem = z.object({
9603
- id: z.string().optional(),
9604
- });
9605
-
9606
- export const BaseSectionSettingsSchema = z.object({
9607
- paddingTop: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),
9608
- paddingBottom: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),
9609
- theme: z.enum(['dark', 'light', 'accent']).default('dark').describe('ui:select'),
9610
- container: z.enum(['boxed', 'fluid']).default('boxed').describe('ui:select'),
9611
- });
9612
-
9613
- export const CtaSchema = z.object({
9614
- id: z.string().optional(),
9615
- label: z.string().describe('ui:text'),
9616
- href: z.string().describe('ui:text'),
9617
- variant: z.enum(['primary', 'secondary', 'accent']).default('primary').describe('ui:select'),
9618
- });
9619
-
9620
- /**
9621
- * Mixin for any section capsule that includes a contact form.
9622
- * Merge into the section data schema to expose recipientEmail
9623
- * as an editable field in the Studio inspector.
9624
- * The View must set data-olon-recipient={data.recipientEmail} on the <form>.
9625
- */
9626
- export const WithFormRecipient = z.object({
9627
- recipientEmail: z.string().optional().describe('ui:text'),
9628
- });
9629
-
9630
- END_OF_FILE_CONTENT
9631
- echo "Creating src/lib/cloudSaveStream.ts..."
9632
- cat << 'END_OF_FILE_CONTENT' > "src/lib/cloudSaveStream.ts"
9633
- import type { StepId } from '@/types/deploy';
9634
-
9635
- interface SaveStreamStepEvent {
9636
- id: StepId;
9637
- status: 'running' | 'done';
9638
- label?: string;
9639
- }
9640
-
9641
- interface SaveStreamLogEvent {
9642
- stepId: StepId;
9643
- message: string;
9644
- }
9645
-
9646
- interface SaveStreamDoneEvent {
9647
- deployUrl?: string;
9648
- commitSha?: string;
9649
- }
9650
-
9651
- interface SaveStreamErrorEvent {
9652
- message?: string;
9653
- }
9654
-
9655
- interface StartCloudSaveStreamInput {
9656
- apiBaseUrl: string;
9657
- apiKey: string;
9658
- path: string;
9659
- content: unknown;
9660
- message?: string;
9661
- signal?: AbortSignal;
9662
- onStep: (event: SaveStreamStepEvent) => void;
9663
- onLog?: (event: SaveStreamLogEvent) => void;
9664
- onDone: (event: SaveStreamDoneEvent) => void;
9665
- }
9666
-
9667
- function parseSseEventBlock(rawBlock: string): { event: string; data: string } | null {
9668
- const lines = rawBlock
9669
- .split('\n')
9670
- .map((line) => line.trimEnd())
9671
- .filter((line) => line.length > 0);
9672
-
9673
- if (lines.length === 0) return null;
9674
-
9675
- let eventName = 'message';
9676
- const dataLines: string[] = [];
9677
- for (const line of lines) {
9678
- if (line.startsWith('event:')) {
9679
- eventName = line.slice(6).trim();
9680
- continue;
9681
- }
9682
- if (line.startsWith('data:')) {
9683
- dataLines.push(line.slice(5).trim());
9684
- }
9685
- }
9686
- return { event: eventName, data: dataLines.join('\n') };
9687
- }
9688
-
9689
- export async function startCloudSaveStream(input: StartCloudSaveStreamInput): Promise<void> {
9690
- const response = await fetch(`${input.apiBaseUrl}/save-stream`, {
9691
- method: 'POST',
9692
- headers: {
9693
- 'Content-Type': 'application/json',
9694
- Authorization: `Bearer ${input.apiKey}`,
9695
- },
9696
- body: JSON.stringify({
9697
- path: input.path,
9698
- content: input.content,
9699
- message: input.message,
9700
- }),
9701
- signal: input.signal,
9702
- });
9703
-
9704
- if (!response.ok || !response.body) {
9705
- const body = (await response.json().catch(() => ({}))) as SaveStreamErrorEvent;
9706
- throw new Error(body.message ?? `Cloud save stream failed: ${response.status}`);
9707
- }
9708
-
9709
- const reader = response.body.getReader();
9710
- const decoder = new TextDecoder();
9711
- let buffer = '';
9712
- let receivedDone = false;
9713
-
9714
- while (true) {
9715
- const { value, done } = await reader.read();
9716
- if (!done) {
9717
- buffer += decoder.decode(value, { stream: true });
9718
- } else {
9719
- buffer += decoder.decode();
9720
- }
9721
-
9722
- const chunks = buffer.split('\n\n');
9723
- buffer = done ? '' : (chunks.pop() ?? '');
9724
-
9725
- for (const chunk of chunks) {
9726
- const parsed = parseSseEventBlock(chunk);
9727
- if (!parsed) continue;
9728
- if (!parsed.data) continue;
9729
-
9730
- if (parsed.event === 'step') {
9731
- const payload = JSON.parse(parsed.data) as SaveStreamStepEvent;
9732
- input.onStep(payload);
9733
- } else if (parsed.event === 'log') {
9734
- const payload = JSON.parse(parsed.data) as SaveStreamLogEvent;
9735
- input.onLog?.(payload);
9736
- } else if (parsed.event === 'error') {
9737
- const payload = JSON.parse(parsed.data) as SaveStreamErrorEvent;
9738
- throw new Error(payload.message ?? 'Cloud save failed.');
9739
- } else if (parsed.event === 'done') {
9740
- const payload = JSON.parse(parsed.data) as SaveStreamDoneEvent;
9741
- input.onDone(payload);
9742
- receivedDone = true;
9743
- }
9744
- }
9745
-
9746
- if (done) break;
9747
- }
9748
-
9749
- if (!receivedDone) {
9750
- throw new Error('Cloud save stream ended before completion.');
9751
- }
9752
- }
9753
-
9754
-
9755
- END_OF_FILE_CONTENT
9756
- echo "Creating src/lib/deploySteps.ts..."
9757
- cat << 'END_OF_FILE_CONTENT' > "src/lib/deploySteps.ts"
9758
- import type { DeployStep } from '@/types/deploy';
9759
-
9760
- export const DEPLOY_STEPS: readonly DeployStep[] = [
9761
- {
9762
- id: 'commit',
9763
- label: 'Commit',
9764
- verb: 'Committing',
9765
- poem: ['Crystallizing your edit', 'into permanent history.'],
9766
- color: '#60a5fa',
9767
- glyph: '◈',
9768
- duration: 2200,
9769
- },
9770
- {
9771
- id: 'push',
9772
- label: 'Push',
9773
- verb: 'Pushing',
9774
- poem: ['Sending your vision', 'across the wire.'],
9775
- color: '#a78bfa',
9776
- glyph: '◎',
9777
- duration: 2800,
9778
- },
9779
- {
9780
- id: 'build',
9781
- label: 'Build',
9782
- verb: 'Building',
9783
- poem: ['Assembling the pieces,', 'brick by digital brick.'],
9784
- color: '#f59e0b',
9785
- glyph: '⬡',
9786
- duration: 7500,
9787
- },
9788
- {
9789
- id: 'live',
9790
- label: 'Live',
9791
- verb: 'Going live',
9792
- poem: ['Your content', 'is now breathing.'],
9793
- color: '#34d399',
9794
- glyph: '✦',
9795
- duration: 1600,
9796
- },
9797
- ] as const;
9798
-
9799
-
9800
9554
  END_OF_FILE_CONTENT
9801
9555
  echo "Creating src/lib/draftStorage.ts..."
9802
9556
  cat << 'END_OF_FILE_CONTENT' > "src/lib/draftStorage.ts"
@@ -9877,13 +9631,24 @@ END_OF_FILE_CONTENT
9877
9631
  echo "Creating src/lib/schemas.ts..."
9878
9632
  cat << 'END_OF_FILE_CONTENT' > "src/lib/schemas.ts"
9879
9633
  import { EmptyTenantSchema } from '@/components/empty-tenant';
9880
- import { FormDemoSchema } from '@/components/form-demo';
9634
+ import { FormDemoSchema, FormDemoSubmissionSchema } from '@/components/form-demo';
9881
9635
 
9882
9636
  export const SECTION_SCHEMAS = {
9883
9637
  'empty-tenant': EmptyTenantSchema,
9884
9638
  'form-demo': FormDemoSchema,
9885
9639
  } as const;
9886
9640
 
9641
+ /**
9642
+ * Registry of per-section-type submission schemas. Keys MUST match a key of
9643
+ * SECTION_SCHEMAS. A section type appearing here is declaring itself as
9644
+ * MCP-submittable: the Zod schema describes the payload accepted by the form.
9645
+ *
9646
+ * See ADR-0002 (docs/decisions/ADR-0002-form-submission-schemas.md).
9647
+ */
9648
+ export const SECTION_SUBMISSION_SCHEMAS = {
9649
+ 'form-demo': FormDemoSubmissionSchema,
9650
+ } as const;
9651
+
9887
9652
  export type SectionType = keyof typeof SECTION_SCHEMAS;
9888
9653
 
9889
9654
  export {
@@ -9892,7 +9657,7 @@ export {
9892
9657
  BaseSectionSettingsSchema,
9893
9658
  CtaSchema,
9894
9659
  ImageSelectionSchema,
9895
- } from '@/lib/base-schemas';
9660
+ } from '@olonjs/core';
9896
9661
 
9897
9662
  END_OF_FILE_CONTENT
9898
9663
  echo "Creating src/lib/useFormSubmit.ts..."
@@ -9987,7 +9752,7 @@ END_OF_FILE_CONTENT
9987
9752
  echo "Creating src/lib/useOlonForms.ts..."
9988
9753
  cat << 'END_OF_FILE_CONTENT' > "src/lib/useOlonForms.ts"
9989
9754
  import { useCallback, useEffect, useState } from 'react';
9990
- import type { FormState } from './OlonFormsContext';
9755
+ import type { FormState } from '@olonjs/core';
9991
9756
 
9992
9757
  const API_BASE =
9993
9758
  (import.meta.env.VITE_OLONJS_CLOUD_URL as string | undefined) ??
@@ -10114,16 +9879,6 @@ export function useOlonForms(options?: UseOlonFormsOptions): { states: Record<st
10114
9879
  return { states };
10115
9880
  }
10116
9881
 
10117
- END_OF_FILE_CONTENT
10118
- echo "Creating src/lib/utils.ts..."
10119
- cat << 'END_OF_FILE_CONTENT' > "src/lib/utils.ts"
10120
- import { clsx, type ClassValue } from 'clsx';
10121
- import { twMerge } from 'tailwind-merge';
10122
-
10123
- export function cn(...inputs: ClassValue[]) {
10124
- return twMerge(clsx(inputs));
10125
- }
10126
-
10127
9882
  END_OF_FILE_CONTENT
10128
9883
  echo "Creating src/main.tsx..."
10129
9884
  cat << 'END_OF_FILE_CONTENT' > "src/main.tsx"
@@ -10146,7 +9901,7 @@ END_OF_FILE_CONTENT
10146
9901
  echo "Creating src/runtime.ts..."
10147
9902
  cat << 'END_OF_FILE_CONTENT' > "src/runtime.ts"
10148
9903
  import type { JsonPagesConfig, MenuConfig, PageConfig, SiteConfig, ThemeConfig } from '@/types';
10149
- import { SECTION_SCHEMAS } from '@/lib/schemas';
9904
+ import { SECTION_SCHEMAS, SECTION_SUBMISSION_SCHEMAS } from '@/lib/schemas';
10150
9905
  import { getFilePages } from '@/lib/getFilePages';
10151
9906
  import siteData from '@/data/config/site.json';
10152
9907
  import menuData from '@/data/config/menu.json';
@@ -10165,17 +9920,18 @@ export const refDocuments = {
10165
9920
  export function getWebMcpBuildState(): {
10166
9921
  pages: Record<string, PageConfig>;
10167
9922
  schemas: JsonPagesConfig['schemas'];
9923
+ submissionSchemas: JsonPagesConfig['submissionSchemas'];
10168
9924
  siteConfig: SiteConfig;
10169
9925
  } {
10170
9926
  return {
10171
9927
  pages,
10172
9928
  schemas: SECTION_SCHEMAS as unknown as JsonPagesConfig['schemas'],
9929
+ submissionSchemas: SECTION_SUBMISSION_SCHEMAS as unknown as JsonPagesConfig['submissionSchemas'],
10173
9930
  siteConfig,
10174
9931
  };
10175
9932
  }
10176
9933
 
10177
9934
  END_OF_FILE_CONTENT
10178
- mkdir -p "src/types"
10179
9935
  echo "Creating src/types.ts..."
10180
9936
  cat << 'END_OF_FILE_CONTENT' > "src/types.ts"
10181
9937
  import type { EmptyTenantData, EmptyTenantSettings } from '@/components/empty-tenant';
@@ -10199,26 +9955,6 @@ declare module '@olonjs/core' {
10199
9955
 
10200
9956
  export * from '@olonjs/core';
10201
9957
 
10202
- END_OF_FILE_CONTENT
10203
- echo "Creating src/types/deploy.ts..."
10204
- cat << 'END_OF_FILE_CONTENT' > "src/types/deploy.ts"
10205
- export type StepId = 'commit' | 'push' | 'build' | 'live';
10206
-
10207
- export type StepState = 'pending' | 'active' | 'done';
10208
-
10209
- export type DeployPhase = 'idle' | 'running' | 'done' | 'error';
10210
-
10211
- export interface DeployStep {
10212
- id: StepId;
10213
- label: string;
10214
- verb: string;
10215
- poem: [string, string];
10216
- color: string;
10217
- glyph: string;
10218
- duration: number;
10219
- }
10220
-
10221
-
10222
9958
  END_OF_FILE_CONTENT
10223
9959
  echo "Creating src/vite-env.d.ts..."
10224
9960
  cat << 'END_OF_FILE_CONTENT' > "src/vite-env.d.ts"
@@ -10410,6 +10146,7 @@ export default defineConfig({
10410
10146
  sendJson(res, 200, buildSiteManifest({
10411
10147
  pages: buildState.pages,
10412
10148
  schemas: buildState.schemas,
10149
+ submissionSchemas: buildState.submissionSchemas,
10413
10150
  siteConfig: buildState.siteConfig,
10414
10151
  }));
10415
10152
  return true;
@@ -10428,6 +10165,7 @@ export default defineConfig({
10428
10165
  slug,
10429
10166
  pageConfig,
10430
10167
  schemas: buildState.schemas,
10168
+ submissionSchemas: buildState.submissionSchemas,
10431
10169
  siteConfig: buildState.siteConfig,
10432
10170
  }));
10433
10171
  return true;
@@ -10446,6 +10184,7 @@ export default defineConfig({
10446
10184
  slug,
10447
10185
  pageConfig,
10448
10186
  schemas: buildState.schemas,
10187
+ submissionSchemas: buildState.submissionSchemas,
10449
10188
  siteConfig: buildState.siteConfig,
10450
10189
  }));
10451
10190
  return true;