@contractspec/example.saas-boilerplate 3.7.6 → 3.7.7

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 (114) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/AGENTS.md +50 -27
  3. package/README.md +64 -144
  4. package/dist/billing/billing.event.js +1 -1
  5. package/dist/billing/index.d.ts +6 -6
  6. package/dist/billing/index.js +1 -1
  7. package/dist/browser/billing/billing.event.js +1 -1
  8. package/dist/browser/billing/index.js +1 -1
  9. package/dist/browser/index.js +931 -932
  10. package/dist/browser/project/index.js +209 -209
  11. package/dist/browser/project/project.event.js +1 -1
  12. package/dist/browser/ui/SaasDashboard.js +45 -45
  13. package/dist/browser/ui/SaasProjectList.js +7 -7
  14. package/dist/browser/ui/SaasSettingsPanel.js +12 -12
  15. package/dist/browser/ui/hooks/index.js +2 -2
  16. package/dist/browser/ui/hooks/useProjectList.js +1 -1
  17. package/dist/browser/ui/hooks/useProjectMutations.js +1 -1
  18. package/dist/browser/ui/index.js +483 -484
  19. package/dist/browser/ui/modals/CreateProjectModal.js +10 -10
  20. package/dist/browser/ui/modals/ProjectActionsModal.js +13 -13
  21. package/dist/browser/ui/modals/index.js +23 -23
  22. package/dist/browser/ui/renderers/index.js +112 -112
  23. package/dist/browser/ui/renderers/project-list.renderer.js +7 -7
  24. package/dist/handlers/index.d.ts +2 -2
  25. package/dist/index.d.ts +4 -4
  26. package/dist/index.js +931 -932
  27. package/dist/node/billing/billing.event.js +1 -1
  28. package/dist/node/billing/index.js +1 -1
  29. package/dist/node/index.js +931 -932
  30. package/dist/node/project/index.js +209 -209
  31. package/dist/node/project/project.event.js +1 -1
  32. package/dist/node/ui/SaasDashboard.js +45 -45
  33. package/dist/node/ui/SaasProjectList.js +7 -7
  34. package/dist/node/ui/SaasSettingsPanel.js +12 -12
  35. package/dist/node/ui/hooks/index.js +2 -2
  36. package/dist/node/ui/hooks/useProjectList.js +1 -1
  37. package/dist/node/ui/hooks/useProjectMutations.js +1 -1
  38. package/dist/node/ui/index.js +483 -484
  39. package/dist/node/ui/modals/CreateProjectModal.js +10 -10
  40. package/dist/node/ui/modals/ProjectActionsModal.js +13 -13
  41. package/dist/node/ui/modals/index.js +23 -23
  42. package/dist/node/ui/renderers/index.js +112 -112
  43. package/dist/node/ui/renderers/project-list.renderer.js +7 -7
  44. package/dist/presentations/index.d.ts +1 -1
  45. package/dist/project/index.d.ts +7 -7
  46. package/dist/project/index.js +209 -209
  47. package/dist/project/project.event.js +1 -1
  48. package/dist/settings/index.d.ts +1 -1
  49. package/dist/ui/SaasDashboard.js +45 -45
  50. package/dist/ui/SaasProjectList.js +7 -7
  51. package/dist/ui/SaasSettingsPanel.js +12 -12
  52. package/dist/ui/hooks/index.d.ts +2 -2
  53. package/dist/ui/hooks/index.js +2 -2
  54. package/dist/ui/hooks/useProjectList.d.ts +5 -0
  55. package/dist/ui/hooks/useProjectList.js +1 -1
  56. package/dist/ui/hooks/useProjectMutations.d.ts +8 -0
  57. package/dist/ui/hooks/useProjectMutations.js +1 -1
  58. package/dist/ui/index.d.ts +4 -4
  59. package/dist/ui/index.js +483 -484
  60. package/dist/ui/modals/CreateProjectModal.js +10 -10
  61. package/dist/ui/modals/ProjectActionsModal.js +13 -13
  62. package/dist/ui/modals/index.js +23 -23
  63. package/dist/ui/renderers/index.d.ts +1 -1
  64. package/dist/ui/renderers/index.js +112 -112
  65. package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
  66. package/dist/ui/renderers/project-list.renderer.js +7 -7
  67. package/package.json +10 -10
  68. package/src/billing/billing.entity.ts +132 -132
  69. package/src/billing/billing.enum.ts +9 -9
  70. package/src/billing/billing.event.ts +71 -71
  71. package/src/billing/billing.handler.ts +87 -87
  72. package/src/billing/billing.operations.ts +158 -158
  73. package/src/billing/billing.presentation.ts +45 -45
  74. package/src/billing/billing.schema.ts +76 -76
  75. package/src/billing/index.ts +43 -48
  76. package/src/dashboard/dashboard.presentation.ts +45 -45
  77. package/src/dashboard/index.ts +2 -2
  78. package/src/docs/saas-boilerplate.docblock.ts +43 -43
  79. package/src/example.ts +32 -32
  80. package/src/handlers/index.ts +9 -9
  81. package/src/handlers/saas.handlers.ts +250 -249
  82. package/src/index.ts +40 -41
  83. package/src/presentations/index.ts +18 -20
  84. package/src/project/index.ts +45 -50
  85. package/src/project/project.entity.ts +68 -68
  86. package/src/project/project.enum.ts +8 -8
  87. package/src/project/project.event.ts +79 -79
  88. package/src/project/project.handler.ts +103 -103
  89. package/src/project/project.operations.ts +236 -236
  90. package/src/project/project.presentation.ts +46 -46
  91. package/src/project/project.schema.ts +90 -90
  92. package/src/saas-boilerplate.feature.ts +100 -100
  93. package/src/seeders/index.ts +20 -20
  94. package/src/settings/index.ts +2 -3
  95. package/src/settings/settings.entity.ts +65 -65
  96. package/src/settings/settings.enum.ts +4 -4
  97. package/src/shared/mock-data.ts +92 -92
  98. package/src/shared/overlay-types.ts +23 -23
  99. package/src/tests/operations.test-spec.ts +96 -96
  100. package/src/ui/SaasDashboard.tsx +270 -270
  101. package/src/ui/SaasProjectList.tsx +90 -90
  102. package/src/ui/SaasSettingsPanel.tsx +84 -84
  103. package/src/ui/hooks/index.ts +3 -3
  104. package/src/ui/hooks/useProjectList.ts +69 -68
  105. package/src/ui/hooks/useProjectMutations.ts +144 -143
  106. package/src/ui/index.ts +8 -12
  107. package/src/ui/modals/CreateProjectModal.tsx +154 -154
  108. package/src/ui/modals/ProjectActionsModal.tsx +321 -321
  109. package/src/ui/overlays/demo-overlays.ts +49 -49
  110. package/src/ui/renderers/index.ts +5 -4
  111. package/src/ui/renderers/project-list.markdown.ts +204 -204
  112. package/src/ui/renderers/project-list.renderer.tsx +14 -13
  113. package/tsconfig.json +7 -8
  114. package/tsdown.config.js +7 -3
package/dist/ui/index.js CHANGED
@@ -346,8 +346,8 @@ function createSaasHandlers(db) {
346
346
  };
347
347
  }
348
348
  // src/ui/hooks/useProjectList.ts
349
- import { useCallback, useEffect, useMemo, useState } from "react";
350
349
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
350
+ import { useCallback, useEffect, useMemo, useState } from "react";
351
351
  function useProjectList(options = {}) {
352
352
  const { handlers, projectId } = useTemplateRuntime();
353
353
  const { saas: saas2 } = handlers;
@@ -410,8 +410,8 @@ function useProjectList(options = {}) {
410
410
  }
411
411
 
412
412
  // src/ui/hooks/useProjectMutations.ts
413
- import { useCallback as useCallback2, useState as useState2 } from "react";
414
413
  import { useTemplateRuntime as useTemplateRuntime2 } from "@contractspec/lib.example-shared-ui";
414
+ import { useCallback as useCallback2, useState as useState2 } from "react";
415
415
  function useProjectMutations(options = {}) {
416
416
  const { handlers, projectId } = useTemplateRuntime2();
417
417
  const { saas: saas2 } = handlers;
@@ -498,9 +498,12 @@ function useProjectMutations(options = {}) {
498
498
  };
499
499
  }
500
500
 
501
+ // src/ui/hooks/index.ts
502
+ "use client";
503
+
501
504
  // src/ui/modals/CreateProjectModal.tsx
502
- import { useState as useState3 } from "react";
503
505
  import { Button, Input } from "@contractspec/lib.design-system";
506
+ import { useState as useState3 } from "react";
504
507
  import { jsxDEV } from "react/jsx-dev-runtime";
505
508
  "use client";
506
509
  var TIERS = [
@@ -545,7 +548,7 @@ function CreateProjectModal({
545
548
  className: "fixed inset-0 z-50 flex items-center justify-center",
546
549
  children: [
547
550
  /* @__PURE__ */ jsxDEV("div", {
548
- className: "bg-background/80 absolute inset-0 backdrop-blur-sm",
551
+ className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
549
552
  onClick: onClose,
550
553
  role: "button",
551
554
  tabIndex: 0,
@@ -556,10 +559,10 @@ function CreateProjectModal({
556
559
  "aria-label": "Close modal"
557
560
  }, undefined, false, undefined, this),
558
561
  /* @__PURE__ */ jsxDEV("div", {
559
- className: "bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl",
562
+ className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
560
563
  children: [
561
564
  /* @__PURE__ */ jsxDEV("h2", {
562
- className: "mb-4 text-xl font-semibold",
565
+ className: "mb-4 font-semibold text-xl",
563
566
  children: "Create New Project"
564
567
  }, undefined, false, undefined, this),
565
568
  /* @__PURE__ */ jsxDEV("form", {
@@ -570,7 +573,7 @@ function CreateProjectModal({
570
573
  children: [
571
574
  /* @__PURE__ */ jsxDEV("label", {
572
575
  htmlFor: "project-name",
573
- className: "text-muted-foreground mb-1 block text-sm font-medium",
576
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
574
577
  children: "Project Name *"
575
578
  }, undefined, false, undefined, this),
576
579
  /* @__PURE__ */ jsxDEV(Input, {
@@ -586,7 +589,7 @@ function CreateProjectModal({
586
589
  children: [
587
590
  /* @__PURE__ */ jsxDEV("label", {
588
591
  htmlFor: "project-description",
589
- className: "text-muted-foreground mb-1 block text-sm font-medium",
592
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
590
593
  children: "Description"
591
594
  }, undefined, false, undefined, this),
592
595
  /* @__PURE__ */ jsxDEV("textarea", {
@@ -596,7 +599,7 @@ function CreateProjectModal({
596
599
  placeholder: "Describe what this project is about...",
597
600
  rows: 3,
598
601
  disabled: isLoading,
599
- className: "border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50"
602
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50"
600
603
  }, undefined, false, undefined, this)
601
604
  ]
602
605
  }, undefined, true, undefined, this),
@@ -604,7 +607,7 @@ function CreateProjectModal({
604
607
  children: [
605
608
  /* @__PURE__ */ jsxDEV("label", {
606
609
  htmlFor: "project-tier",
607
- className: "text-muted-foreground mb-1 block text-sm font-medium",
610
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
608
611
  children: "Tier"
609
612
  }, undefined, false, undefined, this),
610
613
  /* @__PURE__ */ jsxDEV("select", {
@@ -612,7 +615,7 @@ function CreateProjectModal({
612
615
  value: tier,
613
616
  onChange: (e) => setTier(e.target.value),
614
617
  disabled: isLoading,
615
- className: "border-input bg-background focus:ring-ring h-10 w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50",
618
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50",
616
619
  children: TIERS.map((t) => /* @__PURE__ */ jsxDEV("option", {
617
620
  value: t.value,
618
621
  children: t.label
@@ -621,7 +624,7 @@ function CreateProjectModal({
621
624
  ]
622
625
  }, undefined, true, undefined, this),
623
626
  error && /* @__PURE__ */ jsxDEV("div", {
624
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
627
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
625
628
  children: error
626
629
  }, undefined, false, undefined, this),
627
630
  /* @__PURE__ */ jsxDEV("div", {
@@ -650,8 +653,8 @@ function CreateProjectModal({
650
653
  }
651
654
 
652
655
  // src/ui/modals/ProjectActionsModal.tsx
653
- import { useEffect as useEffect2, useState as useState4 } from "react";
654
656
  import { Button as Button2, Input as Input2 } from "@contractspec/lib.design-system";
657
+ import { useEffect as useEffect2, useState as useState4 } from "react";
655
658
  import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
656
659
  "use client";
657
660
  function ProjectActionsModal({
@@ -744,7 +747,7 @@ function ProjectActionsModal({
744
747
  className: "fixed inset-0 z-50 flex items-center justify-center",
745
748
  children: [
746
749
  /* @__PURE__ */ jsxDEV2("div", {
747
- className: "bg-background/80 absolute inset-0 backdrop-blur-sm",
750
+ className: "absolute inset-0 bg-background/80 backdrop-blur-sm",
748
751
  onClick: handleClose,
749
752
  role: "button",
750
753
  tabIndex: 0,
@@ -755,13 +758,13 @@ function ProjectActionsModal({
755
758
  "aria-label": "Close modal"
756
759
  }, undefined, false, undefined, this),
757
760
  /* @__PURE__ */ jsxDEV2("div", {
758
- className: "bg-card border-border relative z-10 w-full max-w-md rounded-xl border p-6 shadow-xl",
761
+ className: "relative z-10 w-full max-w-md rounded-xl border border-border bg-card p-6 shadow-xl",
759
762
  children: [
760
763
  /* @__PURE__ */ jsxDEV2("div", {
761
- className: "border-border mb-4 border-b pb-4",
764
+ className: "mb-4 border-border border-b pb-4",
762
765
  children: [
763
766
  /* @__PURE__ */ jsxDEV2("h2", {
764
- className: "text-xl font-semibold",
767
+ className: "font-semibold text-xl",
765
768
  children: project.name
766
769
  }, undefined, false, undefined, this),
767
770
  /* @__PURE__ */ jsxDEV2("p", {
@@ -843,7 +846,7 @@ function ProjectActionsModal({
843
846
  children: [
844
847
  /* @__PURE__ */ jsxDEV2("label", {
845
848
  htmlFor: "edit-name",
846
- className: "text-muted-foreground mb-1 block text-sm font-medium",
849
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
847
850
  children: "Project Name *"
848
851
  }, undefined, false, undefined, this),
849
852
  /* @__PURE__ */ jsxDEV2(Input2, {
@@ -858,7 +861,7 @@ function ProjectActionsModal({
858
861
  children: [
859
862
  /* @__PURE__ */ jsxDEV2("label", {
860
863
  htmlFor: "edit-description",
861
- className: "text-muted-foreground mb-1 block text-sm font-medium",
864
+ className: "mb-1 block font-medium text-muted-foreground text-sm",
862
865
  children: "Description"
863
866
  }, undefined, false, undefined, this),
864
867
  /* @__PURE__ */ jsxDEV2("textarea", {
@@ -867,12 +870,12 @@ function ProjectActionsModal({
867
870
  onChange: (e) => setDescription(e.target.value),
868
871
  rows: 3,
869
872
  disabled: isLoading,
870
- className: "border-input bg-background focus:ring-ring w-full rounded-md border px-3 py-2 text-sm focus:ring-2 focus:outline-none disabled:opacity-50"
873
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50"
871
874
  }, undefined, false, undefined, this)
872
875
  ]
873
876
  }, undefined, true, undefined, this),
874
877
  error && /* @__PURE__ */ jsxDEV2("div", {
875
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
878
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
876
879
  children: error
877
880
  }, undefined, false, undefined, this),
878
881
  /* @__PURE__ */ jsxDEV2("div", {
@@ -902,7 +905,7 @@ function ProjectActionsModal({
902
905
  "Are you sure you want to archive",
903
906
  " ",
904
907
  /* @__PURE__ */ jsxDEV2("span", {
905
- className: "text-foreground font-medium",
908
+ className: "font-medium text-foreground",
906
909
  children: project.name
907
910
  }, undefined, false, undefined, this),
908
911
  "?"
@@ -913,7 +916,7 @@ function ProjectActionsModal({
913
916
  children: "Archived projects can be restored later."
914
917
  }, undefined, false, undefined, this),
915
918
  error && /* @__PURE__ */ jsxDEV2("div", {
916
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
919
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
917
920
  children: error
918
921
  }, undefined, false, undefined, this),
919
922
  /* @__PURE__ */ jsxDEV2("div", {
@@ -943,7 +946,7 @@ function ProjectActionsModal({
943
946
  "Are you sure you want to delete",
944
947
  " ",
945
948
  /* @__PURE__ */ jsxDEV2("span", {
946
- className: "text-foreground font-medium",
949
+ className: "font-medium text-foreground",
947
950
  children: project.name
948
951
  }, undefined, false, undefined, this),
949
952
  "?"
@@ -954,7 +957,7 @@ function ProjectActionsModal({
954
957
  children: "This action cannot be undone."
955
958
  }, undefined, false, undefined, this),
956
959
  error && /* @__PURE__ */ jsxDEV2("div", {
957
- className: "bg-destructive/10 text-destructive rounded-md p-3 text-sm",
960
+ className: "rounded-md bg-destructive/10 p-3 text-destructive text-sm",
958
961
  children: error
959
962
  }, undefined, false, undefined, this),
960
963
  /* @__PURE__ */ jsxDEV2("div", {
@@ -981,18 +984,221 @@ function ProjectActionsModal({
981
984
  ]
982
985
  }, undefined, true, undefined, this);
983
986
  }
987
+ // src/ui/overlays/demo-overlays.ts
988
+ var saasFreeUserOverlay = {
989
+ overlayId: "saas-boilerplate.free-tier",
990
+ version: "1.0.0",
991
+ description: "Shows limitations for free tier users",
992
+ appliesTo: {
993
+ feature: "saas-boilerplate",
994
+ tier: "free"
995
+ },
996
+ modifications: [
997
+ {
998
+ type: "setLimit",
999
+ field: "projects",
1000
+ max: 3,
1001
+ message: "Upgrade to create more projects"
1002
+ },
1003
+ { type: "hideField", field: "advancedSettings", reason: "Pro feature" },
1004
+ {
1005
+ type: "addBadge",
1006
+ position: "header",
1007
+ label: "Free Plan",
1008
+ variant: "default"
1009
+ }
1010
+ ]
1011
+ };
1012
+ var saasDemoOverlay = {
1013
+ overlayId: "saas-boilerplate.demo-user",
1014
+ version: "1.0.0",
1015
+ description: "Demo mode for SaaS boilerplate",
1016
+ appliesTo: {
1017
+ feature: "saas-boilerplate",
1018
+ role: "demo"
1019
+ },
1020
+ modifications: [
1021
+ {
1022
+ type: "hideField",
1023
+ field: "billingSection",
1024
+ reason: "Demo users cannot access billing"
1025
+ },
1026
+ {
1027
+ type: "hideField",
1028
+ field: "deleteAccount",
1029
+ reason: "Not available in demo"
1030
+ },
1031
+ {
1032
+ type: "addBadge",
1033
+ position: "header",
1034
+ label: "Demo Mode",
1035
+ variant: "warning"
1036
+ }
1037
+ ]
1038
+ };
1039
+ var saasOverlays = [
1040
+ saasFreeUserOverlay,
1041
+ saasDemoOverlay
1042
+ ];
1043
+ // src/ui/renderers/project-list.markdown.ts
1044
+ var projectListMarkdownRenderer = {
1045
+ target: "markdown",
1046
+ render: async (desc, _ctx) => {
1047
+ if (desc.source.type !== "component" || desc.source.componentKey !== "ProjectListView") {
1048
+ throw new Error("projectListMarkdownRenderer: not ProjectListView");
1049
+ }
1050
+ const data = await mockListProjectsHandler({
1051
+ limit: 20,
1052
+ offset: 0
1053
+ });
1054
+ const items = data.projects ?? data.items ?? [];
1055
+ const lines = [
1056
+ "# Projects",
1057
+ "",
1058
+ `**Total**: ${data.total} projects`,
1059
+ ""
1060
+ ];
1061
+ if (items.length === 0) {
1062
+ lines.push("_No projects found._");
1063
+ } else {
1064
+ lines.push("| Status | Project | Description |");
1065
+ lines.push("|--------|---------|-------------|");
1066
+ for (const project of items) {
1067
+ const status = project.status === "ACTIVE" ? "\u2705" : project.status === "ARCHIVED" ? "\uD83D\uDCE6" : "\u23F8\uFE0F";
1068
+ lines.push(`| ${status} | **${project.name}** | ${project.description ?? "-"} |`);
1069
+ }
1070
+ }
1071
+ return {
1072
+ mimeType: "text/markdown",
1073
+ body: lines.join(`
1074
+ `)
1075
+ };
1076
+ }
1077
+ };
1078
+ var saasDashboardMarkdownRenderer = {
1079
+ target: "markdown",
1080
+ render: async (desc, _ctx) => {
1081
+ if (desc.source.type !== "component" || desc.source.componentKey !== "SaasDashboard") {
1082
+ throw new Error("saasDashboardMarkdownRenderer: not SaasDashboard");
1083
+ }
1084
+ const [projectsData, subscription] = await Promise.all([
1085
+ mockListProjectsHandler({ limit: 50 }),
1086
+ mockGetSubscriptionHandler()
1087
+ ]);
1088
+ const projects = projectsData.projects ?? [];
1089
+ const activeProjects = projects.filter((p) => p.status === "ACTIVE").length;
1090
+ const archivedProjects = projects.filter((p) => p.status === "ARCHIVED").length;
1091
+ const lines = [
1092
+ "# SaaS Dashboard",
1093
+ "",
1094
+ "> Organization overview and usage summary",
1095
+ "",
1096
+ "## Summary",
1097
+ "",
1098
+ "| Metric | Value |",
1099
+ "|--------|-------|",
1100
+ `| Total Projects | ${projectsData.total} |`,
1101
+ `| Active Projects | ${activeProjects} |`,
1102
+ `| Archived Projects | ${archivedProjects} |`,
1103
+ `| Subscription Plan | ${subscription.planName} |`,
1104
+ `| Subscription Status | ${subscription.status} |`,
1105
+ "",
1106
+ "## Projects",
1107
+ ""
1108
+ ];
1109
+ if (projects.length === 0) {
1110
+ lines.push("_No projects yet._");
1111
+ } else {
1112
+ lines.push("| Status | Project | Description |");
1113
+ lines.push("|--------|---------|-------------|");
1114
+ for (const project of projects.slice(0, 10)) {
1115
+ const status = project.status === "ACTIVE" ? "\u2705" : project.status === "ARCHIVED" ? "\uD83D\uDCE6" : "\u23F8\uFE0F";
1116
+ lines.push(`| ${status} | **${project.name}** | ${project.description ?? "-"} |`);
1117
+ }
1118
+ if (projects.length > 10) {
1119
+ lines.push(`| ... | ... | _${projectsData.total - 10} more projects_ |`);
1120
+ }
1121
+ }
1122
+ lines.push("");
1123
+ lines.push("## Subscription");
1124
+ lines.push("");
1125
+ lines.push(`- **Plan**: ${subscription.planName}`);
1126
+ lines.push(`- **Status**: ${subscription.status}`);
1127
+ if (subscription.currentPeriodEnd) {
1128
+ lines.push(`- **Period End**: ${new Date(subscription.currentPeriodEnd).toLocaleDateString()}`);
1129
+ }
1130
+ return {
1131
+ mimeType: "text/markdown",
1132
+ body: lines.join(`
1133
+ `)
1134
+ };
1135
+ }
1136
+ };
1137
+ var saasBillingMarkdownRenderer = {
1138
+ target: "markdown",
1139
+ render: async (desc, _ctx) => {
1140
+ if (desc.source.type !== "component" || desc.source.componentKey !== "SubscriptionView") {
1141
+ throw new Error("saasBillingMarkdownRenderer: not SubscriptionView");
1142
+ }
1143
+ const subscription = await mockGetSubscriptionHandler();
1144
+ const lines = [
1145
+ "# Billing & Subscription",
1146
+ "",
1147
+ "> Current subscription details and billing information",
1148
+ "",
1149
+ "## Subscription Details",
1150
+ "",
1151
+ "| Property | Value |",
1152
+ "|----------|-------|",
1153
+ `| Plan | ${subscription.planName} |`,
1154
+ `| Status | ${subscription.status} |`,
1155
+ `| ID | ${subscription.id} |`,
1156
+ `| Period Start | ${new Date(subscription.currentPeriodStart).toLocaleDateString()} |`,
1157
+ `| Period End | ${new Date(subscription.currentPeriodEnd).toLocaleDateString()} |`
1158
+ ];
1159
+ lines.push("");
1160
+ lines.push("## Plan Limits");
1161
+ lines.push("");
1162
+ lines.push(`- **Projects**: ${subscription.limits.projects}`);
1163
+ lines.push(`- **Users**: ${subscription.limits.users}`);
1164
+ lines.push("");
1165
+ lines.push("## Plan Features");
1166
+ lines.push("");
1167
+ if (subscription.planName.toLowerCase().includes("free")) {
1168
+ lines.push("- \u2705 Up to 3 projects");
1169
+ lines.push("- \u2705 Basic support");
1170
+ lines.push("- \u274C Priority support");
1171
+ lines.push("- \u274C Advanced analytics");
1172
+ } else if (subscription.planName.toLowerCase().includes("pro")) {
1173
+ lines.push("- \u2705 Unlimited projects");
1174
+ lines.push("- \u2705 Priority support");
1175
+ lines.push("- \u2705 Advanced analytics");
1176
+ lines.push("- \u274C Custom integrations");
1177
+ } else {
1178
+ lines.push("- \u2705 Unlimited projects");
1179
+ lines.push("- \u2705 Priority support");
1180
+ lines.push("- \u2705 Advanced analytics");
1181
+ lines.push("- \u2705 Custom integrations");
1182
+ lines.push("- \u2705 Dedicated support");
1183
+ }
1184
+ return {
1185
+ mimeType: "text/markdown",
1186
+ body: lines.join(`
1187
+ `)
1188
+ };
1189
+ }
1190
+ };
984
1191
 
985
- // src/ui/SaasDashboard.tsx
986
- import { useState as useState5, useCallback as useCallback3 } from "react";
1192
+ // src/ui/SaasProjectList.tsx
987
1193
  import {
988
- StatCard,
989
- StatCardGroup,
990
- StatusChip,
991
- EntityCard,
1194
+ Button as Button3,
992
1195
  EmptyState,
993
- LoaderBlock,
1196
+ EntityCard,
994
1197
  ErrorState,
995
- Button as Button3
1198
+ LoaderBlock,
1199
+ StatCard,
1200
+ StatCardGroup,
1201
+ StatusChip
996
1202
  } from "@contractspec/lib.design-system";
997
1203
  import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
998
1204
  "use client";
@@ -1003,58 +1209,169 @@ function getStatusTone(status) {
1003
1209
  case "DRAFT":
1004
1210
  return "neutral";
1005
1211
  case "ARCHIVED":
1006
- return "warning";
1212
+ return "danger";
1007
1213
  default:
1008
1214
  return "neutral";
1009
1215
  }
1010
1216
  }
1011
- function SaasDashboard() {
1012
- const [activeTab, setActiveTab] = useState5("projects");
1013
- const [isCreateModalOpen, setIsCreateModalOpen] = useState5(false);
1014
- const [selectedProject, setSelectedProject] = useState5(null);
1015
- const [isProjectActionsOpen, setIsProjectActionsOpen] = useState5(false);
1016
- const { data, subscription, loading, error, stats, refetch } = useProjectList();
1017
- const mutations = useProjectMutations({
1018
- onSuccess: () => {
1019
- refetch();
1020
- }
1021
- });
1022
- const handleProjectClick = useCallback3((project) => {
1023
- setSelectedProject(project);
1024
- setIsProjectActionsOpen(true);
1025
- }, []);
1026
- const tabs = [
1027
- { id: "projects", label: "Projects", icon: "\uD83D\uDCC1" },
1028
- { id: "billing", label: "Billing", icon: "\uD83D\uDCB3" },
1029
- { id: "settings", label: "Settings", icon: "\u2699\uFE0F" }
1030
- ];
1217
+ function SaasProjectList({
1218
+ onProjectClick,
1219
+ onCreateProject
1220
+ }) {
1221
+ const { data, loading, error, stats, refetch } = useProjectList();
1031
1222
  if (loading && !data) {
1032
1223
  return /* @__PURE__ */ jsxDEV3(LoaderBlock, {
1033
- label: "Loading dashboard..."
1224
+ label: "Loading projects..."
1034
1225
  }, undefined, false, undefined, this);
1035
1226
  }
1036
1227
  if (error) {
1037
1228
  return /* @__PURE__ */ jsxDEV3(ErrorState, {
1038
- title: "Failed to load dashboard",
1229
+ title: "Failed to load projects",
1039
1230
  description: error.message,
1040
1231
  onRetry: refetch,
1041
1232
  retryLabel: "Retry"
1042
1233
  }, undefined, false, undefined, this);
1043
1234
  }
1235
+ if (!data?.items.length) {
1236
+ return /* @__PURE__ */ jsxDEV3(EmptyState, {
1237
+ title: "No projects found",
1238
+ description: "Create your first project to get started.",
1239
+ primaryAction: onCreateProject ? /* @__PURE__ */ jsxDEV3(Button3, {
1240
+ onPress: onCreateProject,
1241
+ children: "Create Project"
1242
+ }, undefined, false, undefined, this) : undefined
1243
+ }, undefined, false, undefined, this);
1244
+ }
1044
1245
  return /* @__PURE__ */ jsxDEV3("div", {
1045
1246
  className: "space-y-6",
1046
1247
  children: [
1248
+ stats && /* @__PURE__ */ jsxDEV3(StatCardGroup, {
1249
+ children: [
1250
+ /* @__PURE__ */ jsxDEV3(StatCard, {
1251
+ label: "Total Projects",
1252
+ value: stats.total.toString()
1253
+ }, undefined, false, undefined, this),
1254
+ /* @__PURE__ */ jsxDEV3(StatCard, {
1255
+ label: "Active",
1256
+ value: stats.activeCount.toString()
1257
+ }, undefined, false, undefined, this),
1258
+ /* @__PURE__ */ jsxDEV3(StatCard, {
1259
+ label: "Draft",
1260
+ value: stats.draftCount.toString()
1261
+ }, undefined, false, undefined, this)
1262
+ ]
1263
+ }, undefined, true, undefined, this),
1047
1264
  /* @__PURE__ */ jsxDEV3("div", {
1265
+ className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
1266
+ children: data.items.map((project) => /* @__PURE__ */ jsxDEV3(EntityCard, {
1267
+ cardTitle: project.name,
1268
+ cardSubtitle: project.tier,
1269
+ meta: /* @__PURE__ */ jsxDEV3("p", {
1270
+ className: "text-muted-foreground text-sm",
1271
+ children: project.description
1272
+ }, undefined, false, undefined, this),
1273
+ chips: /* @__PURE__ */ jsxDEV3(StatusChip, {
1274
+ tone: getStatusTone(project.status),
1275
+ label: project.status
1276
+ }, undefined, false, undefined, this),
1277
+ footer: /* @__PURE__ */ jsxDEV3("span", {
1278
+ className: "text-muted-foreground text-xs",
1279
+ children: project.updatedAt.toLocaleDateString()
1280
+ }, undefined, false, undefined, this),
1281
+ onClick: onProjectClick ? () => onProjectClick(project.id) : undefined
1282
+ }, project.id, false, undefined, this))
1283
+ }, undefined, false, undefined, this)
1284
+ ]
1285
+ }, undefined, true, undefined, this);
1286
+ }
1287
+
1288
+ // src/ui/renderers/project-list.renderer.tsx
1289
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1290
+ var projectListReactRenderer = {
1291
+ target: "react",
1292
+ render: async (desc, _ctx) => {
1293
+ if (desc.source.type !== "component") {
1294
+ throw new Error("Invalid source type");
1295
+ }
1296
+ if (desc.source.componentKey !== "SaasProjectListView") {
1297
+ throw new Error(`Unknown component: ${desc.source.componentKey}`);
1298
+ }
1299
+ return /* @__PURE__ */ jsxDEV4(SaasProjectList, {}, undefined, false, undefined, this);
1300
+ }
1301
+ };
1302
+ // src/ui/SaasDashboard.tsx
1303
+ import {
1304
+ Button as Button4,
1305
+ EmptyState as EmptyState2,
1306
+ EntityCard as EntityCard2,
1307
+ ErrorState as ErrorState2,
1308
+ LoaderBlock as LoaderBlock2,
1309
+ StatCard as StatCard2,
1310
+ StatCardGroup as StatCardGroup2,
1311
+ StatusChip as StatusChip2
1312
+ } from "@contractspec/lib.design-system";
1313
+ import { useCallback as useCallback3, useState as useState5 } from "react";
1314
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1315
+ "use client";
1316
+ function getStatusTone2(status) {
1317
+ switch (status) {
1318
+ case "ACTIVE":
1319
+ return "success";
1320
+ case "DRAFT":
1321
+ return "neutral";
1322
+ case "ARCHIVED":
1323
+ return "warning";
1324
+ default:
1325
+ return "neutral";
1326
+ }
1327
+ }
1328
+ function SaasDashboard() {
1329
+ const [activeTab, setActiveTab] = useState5("projects");
1330
+ const [isCreateModalOpen, setIsCreateModalOpen] = useState5(false);
1331
+ const [selectedProject, setSelectedProject] = useState5(null);
1332
+ const [isProjectActionsOpen, setIsProjectActionsOpen] = useState5(false);
1333
+ const { data, subscription, loading, error, stats, refetch } = useProjectList();
1334
+ const mutations = useProjectMutations({
1335
+ onSuccess: () => {
1336
+ refetch();
1337
+ }
1338
+ });
1339
+ const handleProjectClick = useCallback3((project) => {
1340
+ setSelectedProject(project);
1341
+ setIsProjectActionsOpen(true);
1342
+ }, []);
1343
+ const tabs = [
1344
+ { id: "projects", label: "Projects", icon: "\uD83D\uDCC1" },
1345
+ { id: "billing", label: "Billing", icon: "\uD83D\uDCB3" },
1346
+ { id: "settings", label: "Settings", icon: "\u2699\uFE0F" }
1347
+ ];
1348
+ if (loading && !data) {
1349
+ return /* @__PURE__ */ jsxDEV5(LoaderBlock2, {
1350
+ label: "Loading dashboard..."
1351
+ }, undefined, false, undefined, this);
1352
+ }
1353
+ if (error) {
1354
+ return /* @__PURE__ */ jsxDEV5(ErrorState2, {
1355
+ title: "Failed to load dashboard",
1356
+ description: error.message,
1357
+ onRetry: refetch,
1358
+ retryLabel: "Retry"
1359
+ }, undefined, false, undefined, this);
1360
+ }
1361
+ return /* @__PURE__ */ jsxDEV5("div", {
1362
+ className: "space-y-6",
1363
+ children: [
1364
+ /* @__PURE__ */ jsxDEV5("div", {
1048
1365
  className: "flex items-center justify-between",
1049
1366
  children: [
1050
- /* @__PURE__ */ jsxDEV3("h2", {
1051
- className: "text-2xl font-bold",
1367
+ /* @__PURE__ */ jsxDEV5("h2", {
1368
+ className: "font-bold text-2xl",
1052
1369
  children: "SaaS Dashboard"
1053
1370
  }, undefined, false, undefined, this),
1054
- activeTab === "projects" && /* @__PURE__ */ jsxDEV3(Button3, {
1371
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV5(Button4, {
1055
1372
  onPress: () => setIsCreateModalOpen(true),
1056
1373
  children: [
1057
- /* @__PURE__ */ jsxDEV3("span", {
1374
+ /* @__PURE__ */ jsxDEV5("span", {
1058
1375
  className: "mr-2",
1059
1376
  children: "+"
1060
1377
  }, undefined, false, undefined, this),
@@ -1063,59 +1380,59 @@ function SaasDashboard() {
1063
1380
  }, undefined, true, undefined, this)
1064
1381
  ]
1065
1382
  }, undefined, true, undefined, this),
1066
- stats && subscription && /* @__PURE__ */ jsxDEV3(StatCardGroup, {
1383
+ stats && subscription && /* @__PURE__ */ jsxDEV5(StatCardGroup2, {
1067
1384
  children: [
1068
- /* @__PURE__ */ jsxDEV3(StatCard, {
1385
+ /* @__PURE__ */ jsxDEV5(StatCard2, {
1069
1386
  label: "Projects",
1070
1387
  value: stats.total.toString()
1071
1388
  }, undefined, false, undefined, this),
1072
- /* @__PURE__ */ jsxDEV3(StatCard, {
1389
+ /* @__PURE__ */ jsxDEV5(StatCard2, {
1073
1390
  label: "Active",
1074
1391
  value: stats.activeCount.toString()
1075
1392
  }, undefined, false, undefined, this),
1076
- /* @__PURE__ */ jsxDEV3(StatCard, {
1393
+ /* @__PURE__ */ jsxDEV5(StatCard2, {
1077
1394
  label: "Draft",
1078
1395
  value: stats.draftCount.toString()
1079
1396
  }, undefined, false, undefined, this),
1080
- /* @__PURE__ */ jsxDEV3(StatCard, {
1397
+ /* @__PURE__ */ jsxDEV5(StatCard2, {
1081
1398
  label: "Plan",
1082
1399
  value: subscription.plan,
1083
1400
  hint: subscription.status
1084
1401
  }, undefined, false, undefined, this)
1085
1402
  ]
1086
1403
  }, undefined, true, undefined, this),
1087
- /* @__PURE__ */ jsxDEV3("nav", {
1088
- className: "bg-muted flex gap-1 rounded-lg p-1",
1404
+ /* @__PURE__ */ jsxDEV5("nav", {
1405
+ className: "flex gap-1 rounded-lg bg-muted p-1",
1089
1406
  role: "tablist",
1090
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV3("button", {
1407
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV5("button", {
1091
1408
  type: "button",
1092
1409
  role: "tab",
1093
1410
  "aria-selected": activeTab === tab.id,
1094
1411
  onClick: () => setActiveTab(tab.id),
1095
- className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1412
+ className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1096
1413
  children: [
1097
- /* @__PURE__ */ jsxDEV3("span", {
1414
+ /* @__PURE__ */ jsxDEV5("span", {
1098
1415
  children: tab.icon
1099
1416
  }, undefined, false, undefined, this),
1100
1417
  tab.label
1101
1418
  ]
1102
1419
  }, tab.id, true, undefined, this))
1103
1420
  }, undefined, false, undefined, this),
1104
- /* @__PURE__ */ jsxDEV3("div", {
1421
+ /* @__PURE__ */ jsxDEV5("div", {
1105
1422
  className: "min-h-[400px]",
1106
1423
  role: "tabpanel",
1107
1424
  children: [
1108
- activeTab === "projects" && /* @__PURE__ */ jsxDEV3(ProjectsTab, {
1425
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV5(ProjectsTab, {
1109
1426
  data,
1110
1427
  onProjectClick: handleProjectClick
1111
1428
  }, undefined, false, undefined, this),
1112
- activeTab === "billing" && /* @__PURE__ */ jsxDEV3(BillingTab, {
1429
+ activeTab === "billing" && /* @__PURE__ */ jsxDEV5(BillingTab, {
1113
1430
  subscription
1114
1431
  }, undefined, false, undefined, this),
1115
- activeTab === "settings" && /* @__PURE__ */ jsxDEV3(SettingsTab, {}, undefined, false, undefined, this)
1432
+ activeTab === "settings" && /* @__PURE__ */ jsxDEV5(SettingsTab, {}, undefined, false, undefined, this)
1116
1433
  ]
1117
1434
  }, undefined, true, undefined, this),
1118
- /* @__PURE__ */ jsxDEV3(CreateProjectModal, {
1435
+ /* @__PURE__ */ jsxDEV5(CreateProjectModal, {
1119
1436
  isOpen: isCreateModalOpen,
1120
1437
  onClose: () => setIsCreateModalOpen(false),
1121
1438
  onSubmit: async (input) => {
@@ -1123,7 +1440,7 @@ function SaasDashboard() {
1123
1440
  },
1124
1441
  isLoading: mutations.createState.loading
1125
1442
  }, undefined, false, undefined, this),
1126
- /* @__PURE__ */ jsxDEV3(ProjectActionsModal, {
1443
+ /* @__PURE__ */ jsxDEV5(ProjectActionsModal, {
1127
1444
  isOpen: isProjectActionsOpen,
1128
1445
  project: selectedProject,
1129
1446
  onClose: () => {
@@ -1149,34 +1466,34 @@ function SaasDashboard() {
1149
1466
  }
1150
1467
  function ProjectsTab({ data, onProjectClick }) {
1151
1468
  if (!data?.items.length) {
1152
- return /* @__PURE__ */ jsxDEV3(EmptyState, {
1469
+ return /* @__PURE__ */ jsxDEV5(EmptyState2, {
1153
1470
  title: "No projects yet",
1154
1471
  description: "Create your first project to get started."
1155
1472
  }, undefined, false, undefined, this);
1156
1473
  }
1157
- return /* @__PURE__ */ jsxDEV3("div", {
1474
+ return /* @__PURE__ */ jsxDEV5("div", {
1158
1475
  className: "space-y-4",
1159
- children: /* @__PURE__ */ jsxDEV3("div", {
1476
+ children: /* @__PURE__ */ jsxDEV5("div", {
1160
1477
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
1161
- children: data.items.map((project) => /* @__PURE__ */ jsxDEV3(EntityCard, {
1478
+ children: data.items.map((project) => /* @__PURE__ */ jsxDEV5(EntityCard2, {
1162
1479
  cardTitle: project.name,
1163
1480
  cardSubtitle: project.tier,
1164
- meta: /* @__PURE__ */ jsxDEV3("p", {
1481
+ meta: /* @__PURE__ */ jsxDEV5("p", {
1165
1482
  className: "text-muted-foreground text-sm",
1166
1483
  children: project.description
1167
1484
  }, undefined, false, undefined, this),
1168
- chips: /* @__PURE__ */ jsxDEV3(StatusChip, {
1169
- tone: getStatusTone(project.status),
1485
+ chips: /* @__PURE__ */ jsxDEV5(StatusChip2, {
1486
+ tone: getStatusTone2(project.status),
1170
1487
  label: project.status
1171
1488
  }, undefined, false, undefined, this),
1172
- footer: /* @__PURE__ */ jsxDEV3("div", {
1489
+ footer: /* @__PURE__ */ jsxDEV5("div", {
1173
1490
  className: "flex w-full items-center justify-between",
1174
1491
  children: [
1175
- /* @__PURE__ */ jsxDEV3("span", {
1492
+ /* @__PURE__ */ jsxDEV5("span", {
1176
1493
  className: "text-muted-foreground text-xs",
1177
1494
  children: project.updatedAt.toLocaleDateString()
1178
1495
  }, undefined, false, undefined, this),
1179
- /* @__PURE__ */ jsxDEV3(Button3, {
1496
+ /* @__PURE__ */ jsxDEV5(Button4, {
1180
1497
  variant: "ghost",
1181
1498
  size: "sm",
1182
1499
  onPress: () => onProjectClick?.(project),
@@ -1191,25 +1508,25 @@ function ProjectsTab({ data, onProjectClick }) {
1191
1508
  function BillingTab({ subscription }) {
1192
1509
  if (!subscription)
1193
1510
  return null;
1194
- return /* @__PURE__ */ jsxDEV3("div", {
1511
+ return /* @__PURE__ */ jsxDEV5("div", {
1195
1512
  className: "space-y-6",
1196
1513
  children: [
1197
- /* @__PURE__ */ jsxDEV3("div", {
1198
- className: "border-border bg-card rounded-xl border p-6",
1514
+ /* @__PURE__ */ jsxDEV5("div", {
1515
+ className: "rounded-xl border border-border bg-card p-6",
1199
1516
  children: [
1200
- /* @__PURE__ */ jsxDEV3("div", {
1517
+ /* @__PURE__ */ jsxDEV5("div", {
1201
1518
  className: "flex items-start justify-between",
1202
1519
  children: [
1203
- /* @__PURE__ */ jsxDEV3("div", {
1520
+ /* @__PURE__ */ jsxDEV5("div", {
1204
1521
  children: [
1205
- /* @__PURE__ */ jsxDEV3("h3", {
1206
- className: "text-lg font-semibold",
1522
+ /* @__PURE__ */ jsxDEV5("h3", {
1523
+ className: "font-semibold text-lg",
1207
1524
  children: [
1208
1525
  subscription.plan,
1209
1526
  " Plan"
1210
1527
  ]
1211
1528
  }, undefined, true, undefined, this),
1212
- /* @__PURE__ */ jsxDEV3("p", {
1529
+ /* @__PURE__ */ jsxDEV5("p", {
1213
1530
  className: "text-muted-foreground text-sm",
1214
1531
  children: [
1215
1532
  "Current period:",
@@ -1220,7 +1537,7 @@ function BillingTab({ subscription }) {
1220
1537
  subscription.currentPeriodEnd.toLocaleDateString()
1221
1538
  ]
1222
1539
  }, undefined, true, undefined, this),
1223
- /* @__PURE__ */ jsxDEV3("p", {
1540
+ /* @__PURE__ */ jsxDEV5("p", {
1224
1541
  className: "text-muted-foreground text-sm",
1225
1542
  children: [
1226
1543
  "Billing cycle: ",
@@ -1229,21 +1546,21 @@ function BillingTab({ subscription }) {
1229
1546
  }, undefined, true, undefined, this)
1230
1547
  ]
1231
1548
  }, undefined, true, undefined, this),
1232
- /* @__PURE__ */ jsxDEV3(StatusChip, {
1549
+ /* @__PURE__ */ jsxDEV5(StatusChip2, {
1233
1550
  tone: "success",
1234
1551
  label: subscription.status
1235
1552
  }, undefined, false, undefined, this)
1236
1553
  ]
1237
1554
  }, undefined, true, undefined, this),
1238
- /* @__PURE__ */ jsxDEV3("div", {
1555
+ /* @__PURE__ */ jsxDEV5("div", {
1239
1556
  className: "mt-4 flex gap-3",
1240
1557
  children: [
1241
- /* @__PURE__ */ jsxDEV3(Button3, {
1558
+ /* @__PURE__ */ jsxDEV5(Button4, {
1242
1559
  variant: "outline",
1243
1560
  onPress: () => alert("Upgrade clicked!"),
1244
1561
  children: "Upgrade Plan"
1245
1562
  }, undefined, false, undefined, this),
1246
- /* @__PURE__ */ jsxDEV3(Button3, {
1563
+ /* @__PURE__ */ jsxDEV5(Button4, {
1247
1564
  variant: "ghost",
1248
1565
  onPress: () => alert("Manage Billing clicked!"),
1249
1566
  children: "Manage Billing"
@@ -1252,10 +1569,10 @@ function BillingTab({ subscription }) {
1252
1569
  }, undefined, true, undefined, this)
1253
1570
  ]
1254
1571
  }, undefined, true, undefined, this),
1255
- subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV3("div", {
1256
- className: "border-border bg-destructive/10 text-destructive rounded-xl border p-4",
1257
- children: /* @__PURE__ */ jsxDEV3("p", {
1258
- className: "text-sm font-medium",
1572
+ subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV5("div", {
1573
+ className: "rounded-xl border border-border bg-destructive/10 p-4 text-destructive",
1574
+ children: /* @__PURE__ */ jsxDEV5("p", {
1575
+ className: "font-medium text-sm",
1259
1576
  children: "\u26A0\uFE0F Your subscription will be cancelled at the end of the current period."
1260
1577
  }, undefined, false, undefined, this)
1261
1578
  }, undefined, false, undefined, this)
@@ -1263,63 +1580,63 @@ function BillingTab({ subscription }) {
1263
1580
  }, undefined, true, undefined, this);
1264
1581
  }
1265
1582
  function SettingsTab() {
1266
- return /* @__PURE__ */ jsxDEV3("div", {
1583
+ return /* @__PURE__ */ jsxDEV5("div", {
1267
1584
  className: "space-y-6",
1268
- children: /* @__PURE__ */ jsxDEV3("div", {
1269
- className: "border-border bg-card rounded-xl border p-6",
1585
+ children: /* @__PURE__ */ jsxDEV5("div", {
1586
+ className: "rounded-xl border border-border bg-card p-6",
1270
1587
  children: [
1271
- /* @__PURE__ */ jsxDEV3("h3", {
1272
- className: "mb-4 text-lg font-semibold",
1588
+ /* @__PURE__ */ jsxDEV5("h3", {
1589
+ className: "mb-4 font-semibold text-lg",
1273
1590
  children: "Organization Settings"
1274
1591
  }, undefined, false, undefined, this),
1275
- /* @__PURE__ */ jsxDEV3("div", {
1592
+ /* @__PURE__ */ jsxDEV5("div", {
1276
1593
  className: "space-y-4",
1277
1594
  children: [
1278
- /* @__PURE__ */ jsxDEV3("div", {
1595
+ /* @__PURE__ */ jsxDEV5("div", {
1279
1596
  children: [
1280
- /* @__PURE__ */ jsxDEV3("label", {
1597
+ /* @__PURE__ */ jsxDEV5("label", {
1281
1598
  htmlFor: "org-name",
1282
- className: "text-sm font-medium",
1599
+ className: "font-medium text-sm",
1283
1600
  children: "Organization Name"
1284
1601
  }, undefined, false, undefined, this),
1285
- /* @__PURE__ */ jsxDEV3("input", {
1602
+ /* @__PURE__ */ jsxDEV5("input", {
1286
1603
  id: "org-name",
1287
1604
  type: "text",
1288
1605
  defaultValue: "Demo Organization",
1289
- className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2"
1606
+ className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2"
1290
1607
  }, undefined, false, undefined, this)
1291
1608
  ]
1292
1609
  }, undefined, true, undefined, this),
1293
- /* @__PURE__ */ jsxDEV3("div", {
1610
+ /* @__PURE__ */ jsxDEV5("div", {
1294
1611
  children: [
1295
- /* @__PURE__ */ jsxDEV3("label", {
1612
+ /* @__PURE__ */ jsxDEV5("label", {
1296
1613
  htmlFor: "timezone",
1297
- className: "text-sm font-medium",
1614
+ className: "font-medium text-sm",
1298
1615
  children: "Default Timezone"
1299
1616
  }, undefined, false, undefined, this),
1300
- /* @__PURE__ */ jsxDEV3("select", {
1617
+ /* @__PURE__ */ jsxDEV5("select", {
1301
1618
  id: "timezone",
1302
- className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2",
1619
+ className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1303
1620
  children: [
1304
- /* @__PURE__ */ jsxDEV3("option", {
1621
+ /* @__PURE__ */ jsxDEV5("option", {
1305
1622
  children: "UTC"
1306
1623
  }, undefined, false, undefined, this),
1307
- /* @__PURE__ */ jsxDEV3("option", {
1624
+ /* @__PURE__ */ jsxDEV5("option", {
1308
1625
  children: "America/New_York"
1309
1626
  }, undefined, false, undefined, this),
1310
- /* @__PURE__ */ jsxDEV3("option", {
1627
+ /* @__PURE__ */ jsxDEV5("option", {
1311
1628
  children: "Europe/London"
1312
1629
  }, undefined, false, undefined, this),
1313
- /* @__PURE__ */ jsxDEV3("option", {
1630
+ /* @__PURE__ */ jsxDEV5("option", {
1314
1631
  children: "Asia/Tokyo"
1315
1632
  }, undefined, false, undefined, this)
1316
1633
  ]
1317
1634
  }, undefined, true, undefined, this)
1318
1635
  ]
1319
1636
  }, undefined, true, undefined, this),
1320
- /* @__PURE__ */ jsxDEV3("div", {
1637
+ /* @__PURE__ */ jsxDEV5("div", {
1321
1638
  className: "pt-2",
1322
- children: /* @__PURE__ */ jsxDEV3(Button3, {
1639
+ children: /* @__PURE__ */ jsxDEV5(Button4, {
1323
1640
  onPress: () => alert("Settings saved!"),
1324
1641
  children: "Save Settings"
1325
1642
  }, undefined, false, undefined, this)
@@ -1331,165 +1648,69 @@ function SettingsTab() {
1331
1648
  }, undefined, false, undefined, this);
1332
1649
  }
1333
1650
 
1334
- // src/ui/SaasProjectList.tsx
1335
- import {
1336
- StatCard as StatCard2,
1337
- StatCardGroup as StatCardGroup2,
1338
- StatusChip as StatusChip2,
1339
- EntityCard as EntityCard2,
1340
- EmptyState as EmptyState2,
1341
- LoaderBlock as LoaderBlock2,
1342
- ErrorState as ErrorState2,
1343
- Button as Button4
1344
- } from "@contractspec/lib.design-system";
1345
- import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1346
- "use client";
1347
- function getStatusTone2(status) {
1348
- switch (status) {
1349
- case "ACTIVE":
1350
- return "success";
1351
- case "DRAFT":
1352
- return "neutral";
1353
- case "ARCHIVED":
1354
- return "danger";
1355
- default:
1356
- return "neutral";
1357
- }
1358
- }
1359
- function SaasProjectList({
1360
- onProjectClick,
1361
- onCreateProject
1362
- }) {
1363
- const { data, loading, error, stats, refetch } = useProjectList();
1364
- if (loading && !data) {
1365
- return /* @__PURE__ */ jsxDEV4(LoaderBlock2, {
1366
- label: "Loading projects..."
1367
- }, undefined, false, undefined, this);
1368
- }
1369
- if (error) {
1370
- return /* @__PURE__ */ jsxDEV4(ErrorState2, {
1371
- title: "Failed to load projects",
1372
- description: error.message,
1373
- onRetry: refetch,
1374
- retryLabel: "Retry"
1375
- }, undefined, false, undefined, this);
1376
- }
1377
- if (!data?.items.length) {
1378
- return /* @__PURE__ */ jsxDEV4(EmptyState2, {
1379
- title: "No projects found",
1380
- description: "Create your first project to get started.",
1381
- primaryAction: onCreateProject ? /* @__PURE__ */ jsxDEV4(Button4, {
1382
- onPress: onCreateProject,
1383
- children: "Create Project"
1384
- }, undefined, false, undefined, this) : undefined
1385
- }, undefined, false, undefined, this);
1386
- }
1387
- return /* @__PURE__ */ jsxDEV4("div", {
1388
- className: "space-y-6",
1389
- children: [
1390
- stats && /* @__PURE__ */ jsxDEV4(StatCardGroup2, {
1391
- children: [
1392
- /* @__PURE__ */ jsxDEV4(StatCard2, {
1393
- label: "Total Projects",
1394
- value: stats.total.toString()
1395
- }, undefined, false, undefined, this),
1396
- /* @__PURE__ */ jsxDEV4(StatCard2, {
1397
- label: "Active",
1398
- value: stats.activeCount.toString()
1399
- }, undefined, false, undefined, this),
1400
- /* @__PURE__ */ jsxDEV4(StatCard2, {
1401
- label: "Draft",
1402
- value: stats.draftCount.toString()
1403
- }, undefined, false, undefined, this)
1404
- ]
1405
- }, undefined, true, undefined, this),
1406
- /* @__PURE__ */ jsxDEV4("div", {
1407
- className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
1408
- children: data.items.map((project) => /* @__PURE__ */ jsxDEV4(EntityCard2, {
1409
- cardTitle: project.name,
1410
- cardSubtitle: project.tier,
1411
- meta: /* @__PURE__ */ jsxDEV4("p", {
1412
- className: "text-muted-foreground text-sm",
1413
- children: project.description
1414
- }, undefined, false, undefined, this),
1415
- chips: /* @__PURE__ */ jsxDEV4(StatusChip2, {
1416
- tone: getStatusTone2(project.status),
1417
- label: project.status
1418
- }, undefined, false, undefined, this),
1419
- footer: /* @__PURE__ */ jsxDEV4("span", {
1420
- className: "text-muted-foreground text-xs",
1421
- children: project.updatedAt.toLocaleDateString()
1422
- }, undefined, false, undefined, this),
1423
- onClick: onProjectClick ? () => onProjectClick(project.id) : undefined
1424
- }, project.id, false, undefined, this))
1425
- }, undefined, false, undefined, this)
1426
- ]
1427
- }, undefined, true, undefined, this);
1428
- }
1429
-
1430
1651
  // src/ui/SaasSettingsPanel.tsx
1431
- import { useState as useState6 } from "react";
1432
1652
  import { Button as Button5 } from "@contractspec/lib.design-system";
1433
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1653
+ import { useState as useState6 } from "react";
1654
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1434
1655
  "use client";
1435
1656
  function SaasSettingsPanel() {
1436
1657
  const [orgName, setOrgName] = useState6("Demo Organization");
1437
1658
  const [timezone, setTimezone] = useState6("UTC");
1438
- return /* @__PURE__ */ jsxDEV5("div", {
1659
+ return /* @__PURE__ */ jsxDEV6("div", {
1439
1660
  className: "space-y-6",
1440
1661
  children: [
1441
- /* @__PURE__ */ jsxDEV5("div", {
1442
- className: "border-border bg-card rounded-xl border p-6",
1662
+ /* @__PURE__ */ jsxDEV6("div", {
1663
+ className: "rounded-xl border border-border bg-card p-6",
1443
1664
  children: [
1444
- /* @__PURE__ */ jsxDEV5("h3", {
1445
- className: "mb-4 text-lg font-semibold",
1665
+ /* @__PURE__ */ jsxDEV6("h3", {
1666
+ className: "mb-4 font-semibold text-lg",
1446
1667
  children: "Organization Settings"
1447
1668
  }, undefined, false, undefined, this),
1448
- /* @__PURE__ */ jsxDEV5("div", {
1669
+ /* @__PURE__ */ jsxDEV6("div", {
1449
1670
  className: "space-y-4",
1450
1671
  children: [
1451
- /* @__PURE__ */ jsxDEV5("div", {
1672
+ /* @__PURE__ */ jsxDEV6("div", {
1452
1673
  children: [
1453
- /* @__PURE__ */ jsxDEV5("label", {
1674
+ /* @__PURE__ */ jsxDEV6("label", {
1454
1675
  htmlFor: "setting-org-name",
1455
- className: "block text-sm font-medium",
1676
+ className: "block font-medium text-sm",
1456
1677
  children: "Organization Name"
1457
1678
  }, undefined, false, undefined, this),
1458
- /* @__PURE__ */ jsxDEV5("input", {
1679
+ /* @__PURE__ */ jsxDEV6("input", {
1459
1680
  id: "setting-org-name",
1460
1681
  type: "text",
1461
1682
  value: orgName,
1462
1683
  onChange: (e) => setOrgName(e.target.value),
1463
- className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2"
1684
+ className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2"
1464
1685
  }, undefined, false, undefined, this)
1465
1686
  ]
1466
1687
  }, undefined, true, undefined, this),
1467
- /* @__PURE__ */ jsxDEV5("div", {
1688
+ /* @__PURE__ */ jsxDEV6("div", {
1468
1689
  children: [
1469
- /* @__PURE__ */ jsxDEV5("label", {
1690
+ /* @__PURE__ */ jsxDEV6("label", {
1470
1691
  htmlFor: "setting-timezone",
1471
- className: "block text-sm font-medium",
1692
+ className: "block font-medium text-sm",
1472
1693
  children: "Default Timezone"
1473
1694
  }, undefined, false, undefined, this),
1474
- /* @__PURE__ */ jsxDEV5("select", {
1695
+ /* @__PURE__ */ jsxDEV6("select", {
1475
1696
  id: "setting-timezone",
1476
1697
  value: timezone,
1477
1698
  onChange: (e) => setTimezone(e.target.value),
1478
- className: "border-input bg-background mt-1 block w-full rounded-md border px-3 py-2",
1699
+ className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1479
1700
  children: [
1480
- /* @__PURE__ */ jsxDEV5("option", {
1701
+ /* @__PURE__ */ jsxDEV6("option", {
1481
1702
  value: "UTC",
1482
1703
  children: "UTC"
1483
1704
  }, undefined, false, undefined, this),
1484
- /* @__PURE__ */ jsxDEV5("option", {
1705
+ /* @__PURE__ */ jsxDEV6("option", {
1485
1706
  value: "America/New_York",
1486
1707
  children: "America/New_York"
1487
1708
  }, undefined, false, undefined, this),
1488
- /* @__PURE__ */ jsxDEV5("option", {
1709
+ /* @__PURE__ */ jsxDEV6("option", {
1489
1710
  value: "Europe/London",
1490
1711
  children: "Europe/London"
1491
1712
  }, undefined, false, undefined, this),
1492
- /* @__PURE__ */ jsxDEV5("option", {
1713
+ /* @__PURE__ */ jsxDEV6("option", {
1493
1714
  value: "Asia/Tokyo",
1494
1715
  children: "Asia/Tokyo"
1495
1716
  }, undefined, false, undefined, this)
@@ -1499,37 +1720,37 @@ function SaasSettingsPanel() {
1499
1720
  }, undefined, true, undefined, this)
1500
1721
  ]
1501
1722
  }, undefined, true, undefined, this),
1502
- /* @__PURE__ */ jsxDEV5("div", {
1723
+ /* @__PURE__ */ jsxDEV6("div", {
1503
1724
  className: "mt-6",
1504
- children: /* @__PURE__ */ jsxDEV5(Button5, {
1725
+ children: /* @__PURE__ */ jsxDEV6(Button5, {
1505
1726
  variant: "default",
1506
1727
  children: "Save Changes"
1507
1728
  }, undefined, false, undefined, this)
1508
1729
  }, undefined, false, undefined, this)
1509
1730
  ]
1510
1731
  }, undefined, true, undefined, this),
1511
- /* @__PURE__ */ jsxDEV5("div", {
1512
- className: "border-border bg-card rounded-xl border p-6",
1732
+ /* @__PURE__ */ jsxDEV6("div", {
1733
+ className: "rounded-xl border border-border bg-card p-6",
1513
1734
  children: [
1514
- /* @__PURE__ */ jsxDEV5("h3", {
1515
- className: "mb-4 text-lg font-semibold",
1735
+ /* @__PURE__ */ jsxDEV6("h3", {
1736
+ className: "mb-4 font-semibold text-lg",
1516
1737
  children: "Notifications"
1517
1738
  }, undefined, false, undefined, this),
1518
- /* @__PURE__ */ jsxDEV5("div", {
1739
+ /* @__PURE__ */ jsxDEV6("div", {
1519
1740
  className: "space-y-3",
1520
1741
  children: [
1521
1742
  { label: "Email notifications", defaultChecked: true },
1522
1743
  { label: "Usage alerts", defaultChecked: true },
1523
1744
  { label: "Weekly digest", defaultChecked: false }
1524
- ].map((item) => /* @__PURE__ */ jsxDEV5("label", {
1745
+ ].map((item) => /* @__PURE__ */ jsxDEV6("label", {
1525
1746
  className: "flex items-center gap-3",
1526
1747
  children: [
1527
- /* @__PURE__ */ jsxDEV5("input", {
1748
+ /* @__PURE__ */ jsxDEV6("input", {
1528
1749
  type: "checkbox",
1529
1750
  defaultChecked: item.defaultChecked,
1530
- className: "border-input h-4 w-4 rounded"
1751
+ className: "h-4 w-4 rounded border-input"
1531
1752
  }, undefined, false, undefined, this),
1532
- /* @__PURE__ */ jsxDEV5("span", {
1753
+ /* @__PURE__ */ jsxDEV6("span", {
1533
1754
  className: "text-sm",
1534
1755
  children: item.label
1535
1756
  }, undefined, false, undefined, this)
@@ -1538,26 +1759,26 @@ function SaasSettingsPanel() {
1538
1759
  }, undefined, false, undefined, this)
1539
1760
  ]
1540
1761
  }, undefined, true, undefined, this),
1541
- /* @__PURE__ */ jsxDEV5("div", {
1762
+ /* @__PURE__ */ jsxDEV6("div", {
1542
1763
  className: "rounded-xl border border-red-200 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950/20",
1543
1764
  children: [
1544
- /* @__PURE__ */ jsxDEV5("h3", {
1545
- className: "mb-2 text-lg font-semibold text-red-700 dark:text-red-400",
1765
+ /* @__PURE__ */ jsxDEV6("h3", {
1766
+ className: "mb-2 font-semibold text-lg text-red-700 dark:text-red-400",
1546
1767
  children: "Danger Zone"
1547
1768
  }, undefined, false, undefined, this),
1548
- /* @__PURE__ */ jsxDEV5("p", {
1549
- className: "mb-4 text-sm text-red-600 dark:text-red-300",
1769
+ /* @__PURE__ */ jsxDEV6("p", {
1770
+ className: "mb-4 text-red-600 text-sm dark:text-red-300",
1550
1771
  children: "These actions are irreversible. Please proceed with caution."
1551
1772
  }, undefined, false, undefined, this),
1552
- /* @__PURE__ */ jsxDEV5("div", {
1773
+ /* @__PURE__ */ jsxDEV6("div", {
1553
1774
  className: "flex gap-3",
1554
1775
  children: [
1555
- /* @__PURE__ */ jsxDEV5(Button5, {
1776
+ /* @__PURE__ */ jsxDEV6(Button5, {
1556
1777
  variant: "secondary",
1557
1778
  size: "sm",
1558
1779
  children: "Export Data"
1559
1780
  }, undefined, false, undefined, this),
1560
- /* @__PURE__ */ jsxDEV5(Button5, {
1781
+ /* @__PURE__ */ jsxDEV6(Button5, {
1561
1782
  variant: "secondary",
1562
1783
  size: "sm",
1563
1784
  children: "Delete Organization"
@@ -1569,228 +1790,6 @@ function SaasSettingsPanel() {
1569
1790
  ]
1570
1791
  }, undefined, true, undefined, this);
1571
1792
  }
1572
- // src/ui/hooks/index.ts
1573
- "use client";
1574
-
1575
- // src/ui/renderers/project-list.renderer.tsx
1576
- import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1577
- var projectListReactRenderer = {
1578
- target: "react",
1579
- render: async (desc, _ctx) => {
1580
- if (desc.source.type !== "component") {
1581
- throw new Error("Invalid source type");
1582
- }
1583
- if (desc.source.componentKey !== "SaasProjectListView") {
1584
- throw new Error(`Unknown component: ${desc.source.componentKey}`);
1585
- }
1586
- return /* @__PURE__ */ jsxDEV6(SaasProjectList, {}, undefined, false, undefined, this);
1587
- }
1588
- };
1589
-
1590
- // src/ui/renderers/project-list.markdown.ts
1591
- var projectListMarkdownRenderer = {
1592
- target: "markdown",
1593
- render: async (desc, _ctx) => {
1594
- if (desc.source.type !== "component" || desc.source.componentKey !== "ProjectListView") {
1595
- throw new Error("projectListMarkdownRenderer: not ProjectListView");
1596
- }
1597
- const data = await mockListProjectsHandler({
1598
- limit: 20,
1599
- offset: 0
1600
- });
1601
- const items = data.projects ?? data.items ?? [];
1602
- const lines = [
1603
- "# Projects",
1604
- "",
1605
- `**Total**: ${data.total} projects`,
1606
- ""
1607
- ];
1608
- if (items.length === 0) {
1609
- lines.push("_No projects found._");
1610
- } else {
1611
- lines.push("| Status | Project | Description |");
1612
- lines.push("|--------|---------|-------------|");
1613
- for (const project of items) {
1614
- const status = project.status === "ACTIVE" ? "\u2705" : project.status === "ARCHIVED" ? "\uD83D\uDCE6" : "\u23F8\uFE0F";
1615
- lines.push(`| ${status} | **${project.name}** | ${project.description ?? "-"} |`);
1616
- }
1617
- }
1618
- return {
1619
- mimeType: "text/markdown",
1620
- body: lines.join(`
1621
- `)
1622
- };
1623
- }
1624
- };
1625
- var saasDashboardMarkdownRenderer = {
1626
- target: "markdown",
1627
- render: async (desc, _ctx) => {
1628
- if (desc.source.type !== "component" || desc.source.componentKey !== "SaasDashboard") {
1629
- throw new Error("saasDashboardMarkdownRenderer: not SaasDashboard");
1630
- }
1631
- const [projectsData, subscription] = await Promise.all([
1632
- mockListProjectsHandler({ limit: 50 }),
1633
- mockGetSubscriptionHandler()
1634
- ]);
1635
- const projects = projectsData.projects ?? [];
1636
- const activeProjects = projects.filter((p) => p.status === "ACTIVE").length;
1637
- const archivedProjects = projects.filter((p) => p.status === "ARCHIVED").length;
1638
- const lines = [
1639
- "# SaaS Dashboard",
1640
- "",
1641
- "> Organization overview and usage summary",
1642
- "",
1643
- "## Summary",
1644
- "",
1645
- "| Metric | Value |",
1646
- "|--------|-------|",
1647
- `| Total Projects | ${projectsData.total} |`,
1648
- `| Active Projects | ${activeProjects} |`,
1649
- `| Archived Projects | ${archivedProjects} |`,
1650
- `| Subscription Plan | ${subscription.planName} |`,
1651
- `| Subscription Status | ${subscription.status} |`,
1652
- "",
1653
- "## Projects",
1654
- ""
1655
- ];
1656
- if (projects.length === 0) {
1657
- lines.push("_No projects yet._");
1658
- } else {
1659
- lines.push("| Status | Project | Description |");
1660
- lines.push("|--------|---------|-------------|");
1661
- for (const project of projects.slice(0, 10)) {
1662
- const status = project.status === "ACTIVE" ? "\u2705" : project.status === "ARCHIVED" ? "\uD83D\uDCE6" : "\u23F8\uFE0F";
1663
- lines.push(`| ${status} | **${project.name}** | ${project.description ?? "-"} |`);
1664
- }
1665
- if (projects.length > 10) {
1666
- lines.push(`| ... | ... | _${projectsData.total - 10} more projects_ |`);
1667
- }
1668
- }
1669
- lines.push("");
1670
- lines.push("## Subscription");
1671
- lines.push("");
1672
- lines.push(`- **Plan**: ${subscription.planName}`);
1673
- lines.push(`- **Status**: ${subscription.status}`);
1674
- if (subscription.currentPeriodEnd) {
1675
- lines.push(`- **Period End**: ${new Date(subscription.currentPeriodEnd).toLocaleDateString()}`);
1676
- }
1677
- return {
1678
- mimeType: "text/markdown",
1679
- body: lines.join(`
1680
- `)
1681
- };
1682
- }
1683
- };
1684
- var saasBillingMarkdownRenderer = {
1685
- target: "markdown",
1686
- render: async (desc, _ctx) => {
1687
- if (desc.source.type !== "component" || desc.source.componentKey !== "SubscriptionView") {
1688
- throw new Error("saasBillingMarkdownRenderer: not SubscriptionView");
1689
- }
1690
- const subscription = await mockGetSubscriptionHandler();
1691
- const lines = [
1692
- "# Billing & Subscription",
1693
- "",
1694
- "> Current subscription details and billing information",
1695
- "",
1696
- "## Subscription Details",
1697
- "",
1698
- "| Property | Value |",
1699
- "|----------|-------|",
1700
- `| Plan | ${subscription.planName} |`,
1701
- `| Status | ${subscription.status} |`,
1702
- `| ID | ${subscription.id} |`,
1703
- `| Period Start | ${new Date(subscription.currentPeriodStart).toLocaleDateString()} |`,
1704
- `| Period End | ${new Date(subscription.currentPeriodEnd).toLocaleDateString()} |`
1705
- ];
1706
- lines.push("");
1707
- lines.push("## Plan Limits");
1708
- lines.push("");
1709
- lines.push(`- **Projects**: ${subscription.limits.projects}`);
1710
- lines.push(`- **Users**: ${subscription.limits.users}`);
1711
- lines.push("");
1712
- lines.push("## Plan Features");
1713
- lines.push("");
1714
- if (subscription.planName.toLowerCase().includes("free")) {
1715
- lines.push("- \u2705 Up to 3 projects");
1716
- lines.push("- \u2705 Basic support");
1717
- lines.push("- \u274C Priority support");
1718
- lines.push("- \u274C Advanced analytics");
1719
- } else if (subscription.planName.toLowerCase().includes("pro")) {
1720
- lines.push("- \u2705 Unlimited projects");
1721
- lines.push("- \u2705 Priority support");
1722
- lines.push("- \u2705 Advanced analytics");
1723
- lines.push("- \u274C Custom integrations");
1724
- } else {
1725
- lines.push("- \u2705 Unlimited projects");
1726
- lines.push("- \u2705 Priority support");
1727
- lines.push("- \u2705 Advanced analytics");
1728
- lines.push("- \u2705 Custom integrations");
1729
- lines.push("- \u2705 Dedicated support");
1730
- }
1731
- return {
1732
- mimeType: "text/markdown",
1733
- body: lines.join(`
1734
- `)
1735
- };
1736
- }
1737
- };
1738
- // src/ui/overlays/demo-overlays.ts
1739
- var saasFreeUserOverlay = {
1740
- overlayId: "saas-boilerplate.free-tier",
1741
- version: "1.0.0",
1742
- description: "Shows limitations for free tier users",
1743
- appliesTo: {
1744
- feature: "saas-boilerplate",
1745
- tier: "free"
1746
- },
1747
- modifications: [
1748
- {
1749
- type: "setLimit",
1750
- field: "projects",
1751
- max: 3,
1752
- message: "Upgrade to create more projects"
1753
- },
1754
- { type: "hideField", field: "advancedSettings", reason: "Pro feature" },
1755
- {
1756
- type: "addBadge",
1757
- position: "header",
1758
- label: "Free Plan",
1759
- variant: "default"
1760
- }
1761
- ]
1762
- };
1763
- var saasDemoOverlay = {
1764
- overlayId: "saas-boilerplate.demo-user",
1765
- version: "1.0.0",
1766
- description: "Demo mode for SaaS boilerplate",
1767
- appliesTo: {
1768
- feature: "saas-boilerplate",
1769
- role: "demo"
1770
- },
1771
- modifications: [
1772
- {
1773
- type: "hideField",
1774
- field: "billingSection",
1775
- reason: "Demo users cannot access billing"
1776
- },
1777
- {
1778
- type: "hideField",
1779
- field: "deleteAccount",
1780
- reason: "Not available in demo"
1781
- },
1782
- {
1783
- type: "addBadge",
1784
- position: "header",
1785
- label: "Demo Mode",
1786
- variant: "warning"
1787
- }
1788
- ]
1789
- };
1790
- var saasOverlays = [
1791
- saasFreeUserOverlay,
1792
- saasDemoOverlay
1793
- ];
1794
1793
  export {
1795
1794
  useProjectMutations,
1796
1795
  useProjectList,