@contractspec/bundle.library 3.9.8 → 3.9.9
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.
- package/.turbo/turbo-build.log +222 -214
- package/CHANGELOG.md +52 -0
- package/dist/components/docs/DocsIndexPage.js +2 -2
- package/dist/components/docs/docsManifest.js +1 -1
- package/dist/components/docs/getting-started/DataViewTutorialPage.js +81 -6
- package/dist/components/docs/getting-started/index.js +94 -19
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.d.ts +6 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +176 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.d.ts +1 -0
- package/dist/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +176 -0
- package/dist/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/components/docs/guides/index.d.ts +1 -0
- package/dist/components/docs/guides/index.js +220 -46
- package/dist/components/docs/index.js +1003 -309
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.d.ts +22 -5
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.content.js +125 -37
- package/dist/components/docs/libraries/LibrariesApplicationShellPage.js +125 -37
- package/dist/components/docs/libraries/LibrariesDataViewsPage.js +120 -3
- package/dist/components/docs/libraries/LibrariesDesignSystemPage.js +101 -2
- package/dist/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.d.ts +10 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +43 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.d.ts +1 -0
- package/dist/components/docs/libraries/LibrariesTranslationRuntimePage.js +43 -0
- package/dist/components/docs/libraries/index.d.ts +1 -0
- package/dist/components/docs/libraries/index.js +496 -97
- package/dist/components/docs/specs/SpecsDataViewsPage.js +49 -3
- package/dist/components/docs/specs/index.js +60 -14
- package/dist/index.js +1014 -320
- package/dist/node/components/docs/DocsIndexPage.js +2 -2
- package/dist/node/components/docs/docsManifest.js +1 -1
- package/dist/node/components/docs/getting-started/DataViewTutorialPage.js +81 -6
- package/dist/node/components/docs/getting-started/index.js +94 -19
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.js +175 -0
- package/dist/node/components/docs/guides/GuideDataExchangeImportTemplatesPage.js +175 -0
- package/dist/node/components/docs/guides/GuidesIndexPage.js +2 -2
- package/dist/node/components/docs/guides/index.js +220 -46
- package/dist/node/components/docs/index.js +1003 -309
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.content.js +125 -37
- package/dist/node/components/docs/libraries/LibrariesApplicationShellPage.js +125 -37
- package/dist/node/components/docs/libraries/LibrariesDataViewsPage.js +120 -3
- package/dist/node/components/docs/libraries/LibrariesDesignSystemPage.js +101 -2
- package/dist/node/components/docs/libraries/LibrariesOverviewPage.js +1 -1
- package/dist/node/components/docs/libraries/LibrariesPersonalizationPage.js +58 -4
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.content.js +42 -0
- package/dist/node/components/docs/libraries/LibrariesTranslationRuntimePage.js +42 -0
- package/dist/node/components/docs/libraries/index.js +496 -97
- package/dist/node/components/docs/specs/SpecsDataViewsPage.js +49 -3
- package/dist/node/components/docs/specs/index.js +60 -14
- package/dist/node/index.js +1014 -320
- package/package.json +74 -26
- package/src/components/docs/docsManifest.test.ts +87 -0
- package/src/components/docs/docsManifest.ts +90 -3
- package/src/components/docs/generated/docs-index.notifications.json +7 -7
- package/src/components/docs/getting-started/DataViewTutorialPage.tsx +181 -50
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.content.ts +185 -0
- package/src/components/docs/guides/GuideDataExchangeImportTemplatesPage.tsx +186 -0
- package/src/components/docs/guides/GuidesIndexPage.tsx +49 -42
- package/src/components/docs/guides/index.ts +1 -0
- package/src/components/docs/libraries/LibrariesApplicationShellPage.content.ts +148 -35
- package/src/components/docs/libraries/LibrariesApplicationShellPage.tsx +38 -5
- package/src/components/docs/libraries/LibrariesDataViewsPage.tsx +267 -64
- package/src/components/docs/libraries/LibrariesDesignSystemPage.tsx +235 -0
- package/src/components/docs/libraries/LibrariesOverviewPage.tsx +8 -2
- package/src/components/docs/libraries/LibrariesPersonalizationPage.tsx +141 -31
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.content.ts +78 -0
- package/src/components/docs/libraries/LibrariesTranslationRuntimePage.tsx +137 -0
- package/src/components/docs/libraries/index.ts +1 -0
- package/src/components/docs/specs/SpecsDataViewsPage.tsx +239 -113
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var ca=Object.defineProperty;var sa=(a)=>a;function la(a,A){this[a]=sa.bind(null,A)}var Ii=(a,A)=>{for(var Ge in A)ca(a,Ge,{get:A[Ge],enumerable:!0,configurable:!0,set:la.bind(A,Ge)})};var Pi=(a,A)=>()=>(a&&(A=a(a=0)),A);import{CodeBlock as $e,InstallCommand as da}from"@contractspec/lib.design-system";import xe from"@contractspec/lib.ui-link";import{ChevronRight as pa}from"lucide-react";import{jsx as h,jsxs as k}from"react/jsx-runtime";function ma(){return k("div",{className:"space-y-8",children:[k("div",{className:"space-y-4",children:[h("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.accessibility"}),h("p",{className:"text-muted-foreground",children:"Stable exports of accessibility primitives for LSSM web apps, ensuring WCAG compliance and inclusive design."})]}),k("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Installation"}),h(da,{package:"@contractspec/lib.accessibility"})]}),k("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Exports"}),k("ul",{className:"space-y-2 text-muted-foreground",children:[k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"SkipLink"}),": A link to skip navigation, visible on focus"]}),k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"VisuallyHidden"}),": Hide content visually but keep it for screen readers"]}),k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"SRLiveRegionProvider"}),","," ",h("code",{className:"rounded bg-background/50 px-2 py-1",children:"useSRLiveRegion"}),": Manage live region announcements"]}),k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"RouteAnnouncer"}),": Announce page title/path changes on navigation"]}),k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"FocusOnRouteChange"}),": Reset focus to body or main content on navigation"]}),k("li",{children:[h("code",{className:"rounded bg-background/50 px-2 py-1",children:"useReducedMotion"}),": Detect if the user prefers reduced motion"]})]})]}),k("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Example: App Setup"}),h($e,{language:"tsx",code:`import {
|
|
3
3
|
SRLiveRegionProvider,
|
|
4
4
|
RouteAnnouncer,
|
|
5
5
|
SkipLink
|
|
@@ -19,7 +19,7 @@ export function RootLayout({ children }) {
|
|
|
19
19
|
</body>
|
|
20
20
|
</html>
|
|
21
21
|
);
|
|
22
|
-
}`})]}),
|
|
22
|
+
}`})]}),k("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Example: Live Announcements"}),h($e,{language:"tsx",code:`import { useSRLiveRegion } from '@contractspec/lib.accessibility';
|
|
23
23
|
|
|
24
24
|
export function TodoList() {
|
|
25
25
|
const { announce } = useSRLiveRegion();
|
|
@@ -30,7 +30,7 @@ export function TodoList() {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
return <button onClick={addTodo}>Add Todo</button>;
|
|
33
|
-
}`})]}),
|
|
33
|
+
}`})]}),k("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"WCAG Compliance"}),k("p",{className:"text-muted-foreground",children:["These components map directly to WCAG 2.1 Level AA requirements documented in ",h("code",{children:"docs/accessibility_wcag_compliance_specs.md"}),":"]}),k("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[h("li",{children:"2.4.1 Bypass Blocks (SkipLink)"}),h("li",{children:"4.1.3 Status Messages (LiveRegion)"}),h("li",{children:"2.4.3 Focus Order (FocusOnRouteChange)"}),h("li",{children:"2.3.3 Animation from Interactions (useReducedMotion)"})]})]}),k("div",{className:"flex items-center gap-4 pt-4",children:[h(xe,{href:"/docs/libraries/design-system",className:"btn-ghost",children:"Previous: Design System"}),k(xe,{href:"/docs/libraries",className:"btn-primary",children:["Back to Libraries ",h(pa,{size:16})]})]})]})}import{CodeBlock as je,InstallCommand as ua}from"@contractspec/lib.design-system";import et from"@contractspec/lib.ui-link";import{ChevronRight as ha}from"lucide-react";import{jsx as S,jsxs as K}from"react/jsx-runtime";function ga(){return K("div",{className:"space-y-8",children:[K("div",{className:"space-y-4",children:[S("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.ai-agent"}),S("p",{className:"text-lg text-muted-foreground",children:"Define AI agents in TypeScript, run them with deterministic tool calling, capture working memory, and route low-confidence decisions to human reviewers."})]}),K("div",{className:"space-y-4",children:[S("h2",{className:"font-bold text-2xl",children:"Installation"}),S(ua,{package:"@contractspec/lib.ai-agent"})]}),K("div",{className:"space-y-3",children:[S("h2",{className:"font-bold text-2xl",children:"Define & register"}),S(je,{language:"typescript",code:`import { defineAgent, AgentRegistry } from '@contractspec/lib.contracts-spec/agent';
|
|
34
34
|
|
|
35
35
|
const SupportBot = defineAgent({
|
|
36
36
|
meta: {
|
|
@@ -49,7 +49,7 @@ const SupportBot = defineAgent({
|
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
const registry = new AgentRegistry().register(SupportBot);`})]}),
|
|
52
|
+
const registry = new AgentRegistry().register(SupportBot);`})]}),K("div",{className:"space-y-3",children:[S("h2",{className:"font-bold text-2xl",children:"Run with approvals"}),S(je,{language:"typescript",code:`import { createUnifiedAgent, ApprovalWorkflow } from '@contractspec/lib.ai-agent';
|
|
53
53
|
|
|
54
54
|
const approvals = new ApprovalWorkflow();
|
|
55
55
|
const agent = createUnifiedAgent(SupportBot, {
|
|
@@ -59,7 +59,7 @@ const agent = createUnifiedAgent(SupportBot, {
|
|
|
59
59
|
|
|
60
60
|
const result = await agent.run(ticket.body);
|
|
61
61
|
// Route low-confidence or manual-review flows through approvals when needed.
|
|
62
|
-
`})]}),
|
|
62
|
+
`})]}),K("div",{className:"space-y-3",children:[S("h2",{className:"font-bold text-2xl",children:"What's inside"}),K("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[K("li",{children:[S("code",{children:"createUnifiedAgent"}),", ",S("code",{children:"ContractSpecAgent"}),","," ",S("code",{children:"UnifiedAgent"})]}),S("li",{children:"MCP, operation-backed, memory, and subagent tool adapters"}),K("li",{children:[S("code",{children:"InMemoryAgentMemory"})," plus interfaces for custom stores"]}),K("li",{children:[S("code",{children:"ApprovalWorkflow"})," + ",S("code",{children:"ApprovalStore"})," for human-in-the-loop reviews"]})]})]}),K("div",{className:"flex items-center gap-4 pt-4",children:[S(et,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),K(et,{href:"/docs/libraries/support-bot",className:"btn-primary",children:["Next: Support Bot ",S(ha,{size:16})]})]})]})}import{CodeBlock as Fe,InstallCommand as fa}from"@contractspec/lib.design-system";import{jsx as X,jsxs as Re}from"react/jsx-runtime";function ba(){return Re("div",{className:"space-y-8",children:[Re("div",{className:"space-y-4",children:[X("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.analytics"}),X("p",{className:"text-lg text-muted-foreground",children:"Work directly with telemetry events to understand conversion, retention, churn, and growth opportunities."})]}),Re("div",{className:"space-y-4",children:[X("h2",{className:"font-bold text-2xl",children:"Installation"}),X(fa,{package:"@contractspec/lib.analytics"})]}),Re("div",{className:"space-y-3",children:[X("h2",{className:"font-bold text-2xl",children:"Funnels in memory"}),X(Fe,{language:"typescript",code:`import { FunnelAnalyzer } from '@contractspec/lib.analytics/funnel';
|
|
63
63
|
|
|
64
64
|
const analyzer = new FunnelAnalyzer();
|
|
65
65
|
const report = analyzer.analyze(events, {
|
|
@@ -69,23 +69,24 @@ const report = analyzer.analyze(events, {
|
|
|
69
69
|
{ id: 'submit', eventName: 'signup.submit' },
|
|
70
70
|
{ id: 'verified', eventName: 'account.verified' },
|
|
71
71
|
],
|
|
72
|
-
});`})]}),
|
|
72
|
+
});`})]}),Re("div",{className:"space-y-3",children:[X("h2",{className:"font-bold text-2xl",children:"Cohorts & churn"}),X(Fe,{language:"typescript",code:`import { CohortTracker } from '@contractspec/lib.analytics/cohort';
|
|
73
73
|
import { ChurnPredictor } from '@contractspec/lib.analytics/churn';
|
|
74
74
|
|
|
75
75
|
const cohorts = new CohortTracker().analyze(events, { bucket: 'week', periods: 8 });
|
|
76
|
-
const churn = new ChurnPredictor().score(events);`})]}),
|
|
76
|
+
const churn = new ChurnPredictor().score(events);`})]}),Re("div",{className:"space-y-3",children:[X("h2",{className:"font-bold text-2xl",children:"Growth hypotheses"}),X(Fe,{language:"typescript",code:`import { GrowthHypothesisGenerator } from '@contractspec/lib.analytics/growth';
|
|
77
77
|
|
|
78
78
|
const ideas = new GrowthHypothesisGenerator().generate([
|
|
79
79
|
{ name: 'Activation rate', current: 0.42, previous: 0.55, target: 0.6 },
|
|
80
80
|
{ name: 'Expansion ARPU', current: 1.2, previous: 0.9 },
|
|
81
|
-
]);`})]})]})}var
|
|
81
|
+
]);`})]})]})}var tt=`import {
|
|
82
82
|
AppShell,
|
|
83
|
-
|
|
84
|
-
type
|
|
83
|
+
type ShellCommandGroup,
|
|
84
|
+
type ShellNavSection,
|
|
85
|
+
type ShellNotificationCenter,
|
|
85
86
|
type PageOutlineItem,
|
|
86
87
|
} from "@contractspec/lib.design-system/shell";
|
|
87
88
|
|
|
88
|
-
const navigation:
|
|
89
|
+
const navigation: ShellNavSection[] = [
|
|
89
90
|
{
|
|
90
91
|
title: "Workspace",
|
|
91
92
|
items: [
|
|
@@ -102,6 +103,16 @@ const navigation: AppShellNavigationSection[] = [
|
|
|
102
103
|
},
|
|
103
104
|
];
|
|
104
105
|
|
|
106
|
+
const commands: ShellCommandGroup[] = [
|
|
107
|
+
{
|
|
108
|
+
heading: "Quick actions",
|
|
109
|
+
items: [
|
|
110
|
+
{ id: "new-contract", label: "New contract", shortcut: "N" },
|
|
111
|
+
{ id: "import", label: "Import existing app" },
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
|
|
105
116
|
const outline: PageOutlineItem[] = [
|
|
106
117
|
{
|
|
107
118
|
id: "architecture",
|
|
@@ -114,41 +125,104 @@ const outline: PageOutlineItem[] = [
|
|
|
114
125
|
},
|
|
115
126
|
];
|
|
116
127
|
|
|
128
|
+
const notifications: ShellNotificationCenter = {
|
|
129
|
+
label: "Notifications",
|
|
130
|
+
loading: false,
|
|
131
|
+
unreadCount: 2,
|
|
132
|
+
items: [
|
|
133
|
+
{
|
|
134
|
+
id: "contract-approved",
|
|
135
|
+
title: "Contract approved",
|
|
136
|
+
body: "Billing.create is ready to publish.",
|
|
137
|
+
status: "unread",
|
|
138
|
+
createdAt: "2026-04-29T09:30:00Z",
|
|
139
|
+
actionUrl: "/contracts/billing.create",
|
|
140
|
+
category: "Review",
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
onSelect: (item) => openNotificationTarget(item),
|
|
144
|
+
onMarkRead: (item) => markNotificationRead(item.id),
|
|
145
|
+
onMarkAllRead: () => markAllNotificationsRead(),
|
|
146
|
+
};
|
|
147
|
+
|
|
117
148
|
export function WorkspacePage() {
|
|
118
149
|
return (
|
|
119
150
|
<AppShell
|
|
120
|
-
|
|
151
|
+
title="ContractSpec"
|
|
152
|
+
homeHref="/dashboard"
|
|
121
153
|
navigation={navigation}
|
|
154
|
+
commands={commands}
|
|
122
155
|
breadcrumbs={[
|
|
123
156
|
{ label: "Workspace", href: "/dashboard" },
|
|
124
157
|
{ label: "Contracts" },
|
|
125
158
|
]}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
actions: [
|
|
132
|
-
{ id: "new-contract", label: "New contract" },
|
|
133
|
-
{ id: "import", label: "Import existing app" },
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
}}
|
|
138
|
-
user={{
|
|
139
|
-
name: "Ada Lovelace",
|
|
140
|
-
email: "ada@example.com",
|
|
141
|
-
actions: [{ label: "Sign out", onSelect: () => signOut() }],
|
|
142
|
-
}}
|
|
143
|
-
pageOutline={<PageOutline items={outline} activeId="desktop" />}
|
|
159
|
+
notifications={notifications}
|
|
160
|
+
pageOutline={outline}
|
|
161
|
+
activeHref="/contracts"
|
|
162
|
+
activeOutlineId="desktop"
|
|
163
|
+
userMenu={<UserMenu onSignOut={() => signOut()} />}
|
|
144
164
|
>
|
|
145
165
|
<main>{/* route content */}</main>
|
|
146
166
|
</AppShell>
|
|
147
167
|
);
|
|
148
|
-
}`,
|
|
168
|
+
}`,at=`import {
|
|
169
|
+
ListNotificationsOutputModel,
|
|
170
|
+
MarkNotificationReadInputModel,
|
|
171
|
+
} from "@contractspec/lib.contracts-spec/notifications";
|
|
172
|
+
import {
|
|
173
|
+
notificationsSchemaContribution,
|
|
174
|
+
renderNotificationTemplate,
|
|
175
|
+
} from "@contractspec/lib.notification";
|
|
176
|
+
import type { ShellNotificationCenter } from "@contractspec/lib.design-system/shell";
|
|
177
|
+
|
|
178
|
+
type NotificationListResult = {
|
|
179
|
+
unreadCount: number;
|
|
180
|
+
notifications: Array<{
|
|
181
|
+
id: string;
|
|
182
|
+
title: string;
|
|
183
|
+
body: string;
|
|
184
|
+
type: string;
|
|
185
|
+
status: string;
|
|
186
|
+
readAt?: string | Date | null;
|
|
187
|
+
createdAt: string | Date;
|
|
188
|
+
actionUrl?: string;
|
|
189
|
+
metadata?: Record<string, unknown>;
|
|
190
|
+
}>;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export function toShellNotifications(
|
|
194
|
+
data: NotificationListResult,
|
|
195
|
+
actions: {
|
|
196
|
+
open: (id: string) => void;
|
|
197
|
+
markRead: (input: { notificationId: string }) => void;
|
|
198
|
+
markAllRead: () => void;
|
|
199
|
+
}
|
|
200
|
+
): ShellNotificationCenter {
|
|
201
|
+
return {
|
|
202
|
+
unreadCount: data.unreadCount,
|
|
203
|
+
items: data.notifications.map((notification) => ({
|
|
204
|
+
id: notification.id,
|
|
205
|
+
title: notification.title,
|
|
206
|
+
body: notification.body,
|
|
207
|
+
status: notification.status,
|
|
208
|
+
createdAt: notification.createdAt,
|
|
209
|
+
actionUrl: notification.actionUrl,
|
|
210
|
+
category: notification.type,
|
|
211
|
+
metadata: notification.metadata,
|
|
212
|
+
})),
|
|
213
|
+
onSelect: (item) => actions.open(item.id),
|
|
214
|
+
onMarkRead: (item) => actions.markRead({ notificationId: item.id }),
|
|
215
|
+
onMarkAllRead: actions.markAllRead,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
void ListNotificationsOutputModel;
|
|
220
|
+
void MarkNotificationReadInputModel;
|
|
221
|
+
void notificationsSchemaContribution;
|
|
222
|
+
void renderNotificationTemplate;`,ot=`You are implementing a modern application shell from scratch.
|
|
149
223
|
|
|
150
224
|
Goal:
|
|
151
|
-
Build a reusable application shell for a React/Next.js web app and an Expo React Native app. The shell must provide a desktop sidebar, desktop topbar, command search, breadcrumbs, nested navigation, user/auth actions, and an in-page section navigator called PageOutline.
|
|
225
|
+
Build a reusable application shell for a React/Next.js web app and an Expo React Native app. The shell must provide a desktop sidebar, desktop topbar, command search, breadcrumbs, nested navigation, user/auth actions, in-app notifications, and an in-page section navigator called PageOutline.
|
|
152
226
|
|
|
153
227
|
Use this architecture:
|
|
154
228
|
- Keep route content independent from navigation chrome.
|
|
@@ -156,29 +230,37 @@ Use this architecture:
|
|
|
156
230
|
- Create a command model with search input, grouped suggestions, quick actions, keyboard shortcut labels, empty state, and loading state.
|
|
157
231
|
- Create a breadcrumb model for the topbar.
|
|
158
232
|
- Create a PageOutline model for right-side in-page navigation with exactly three supported levels. It should render anchors, support active section state, and degrade gracefully when no sections exist.
|
|
233
|
+
- Create a ShellNotificationCenter model with render-ready items, unread count, loading and empty states, onSelect, onMarkRead, onMarkAllRead, and optional custom item rendering.
|
|
159
234
|
- Expose the system from the design system or a dedicated shell module, not from a single app route.
|
|
160
235
|
|
|
236
|
+
Notification boundary:
|
|
237
|
+
- Use @contractspec/lib.contracts-spec/notifications as the canonical source for notification contracts, operation models, and feature metadata.
|
|
238
|
+
- Use @contractspec/lib.notification for reusable notification entities, schema contribution, channels, templates, and i18n helpers.
|
|
239
|
+
- Keep persistence, polling/subscriptions, delivery providers, and optimistic mutations in the host application or notification runtime layer.
|
|
240
|
+
- Pass only render-ready ShellNotificationCenter state into AppShell so the design system does not import or own notification runtime behavior.
|
|
241
|
+
|
|
161
242
|
Desktop behavior:
|
|
162
243
|
- Persistent left sidebar with app logo/title, command trigger, grouped navigation, nested submenus, and current user/auth/logout area.
|
|
163
244
|
- Topbar with breadcrumbs and an optional command trigger.
|
|
245
|
+
- Topbar notification trigger with unread badge, loading/empty states, mark-read actions, and item selection.
|
|
164
246
|
- Content area with optional right PageOutline.
|
|
165
247
|
- Keep dimensions stable. Navigation labels must not resize layout on hover or active state.
|
|
166
248
|
|
|
167
249
|
Mobile web behavior:
|
|
168
250
|
- Use bottom navigation for the primary destinations.
|
|
169
|
-
- Put deeper navigation, command search, auth actions, and secondary actions behind a menu or drawer.
|
|
251
|
+
- Put deeper navigation, command search, notifications, auth actions, and secondary actions behind a menu or drawer when the topbar cannot safely hold them.
|
|
170
252
|
- Keep route content first and make the shell controls reachable without covering important content.
|
|
171
253
|
|
|
172
254
|
Native behavior:
|
|
173
255
|
- Add .native.tsx entrypoints for Expo/React Native.
|
|
174
|
-
- Prefer bottom tabs for primary destinations and a menu/sheet for deeper navigation and account actions.
|
|
175
|
-
- Keep the same typed navigation, command, breadcrumb, and PageOutline data contracts across web and native.
|
|
256
|
+
- Prefer bottom tabs for primary destinations and a menu/sheet for deeper navigation, notifications, and account actions.
|
|
257
|
+
- Keep the same typed navigation, command, breadcrumb, notification, and PageOutline data contracts across web and native.
|
|
176
258
|
|
|
177
259
|
Implementation constraints:
|
|
178
260
|
- Reuse the existing design-system primitives, tokens, icons, and accessibility patterns.
|
|
179
261
|
- Do not hardcode app-specific routes in the shell component.
|
|
180
262
|
- Do not introduce a new dependency unless the repo already uses it for dialogs, menus, icons, or navigation.
|
|
181
|
-
- Include tests for navigation rendering, nested items, command filtering, breadcrumbs, PageOutline level handling, active section state, and mobile/native adaptation contracts.
|
|
263
|
+
- Include tests for navigation rendering, nested items, command filtering, breadcrumbs, notification unread badge/loading/empty/callback behavior, PageOutline level handling, active section state, and mobile/native adaptation contracts.
|
|
182
264
|
- Update docs and exports so developers can import the shell from a stable public API.
|
|
183
265
|
|
|
184
266
|
Deliverables:
|
|
@@ -186,15 +268,18 @@ Deliverables:
|
|
|
186
268
|
- Web shell components.
|
|
187
269
|
- Native shell components or adapters.
|
|
188
270
|
- PageOutline component with three-level support.
|
|
271
|
+
- ShellNotifications or equivalent notification center component for web and native shell placement.
|
|
189
272
|
- Usage example.
|
|
190
|
-
- Focused tests and typecheck/build evidence.`,
|
|
273
|
+
- Focused tests and typecheck/build evidence.`,it=`You are refactoring an existing application to use the shared application shell system.
|
|
191
274
|
|
|
192
275
|
Goal:
|
|
193
|
-
Replace app-specific sidebar, topbar, breadcrumb, command palette, account menu, mobile navigation, and in-page table-of-contents code with the shared AppShell and PageOutline system.
|
|
276
|
+
Replace app-specific sidebar, topbar, breadcrumb, command palette, notification badge/inbox, account menu, mobile navigation, and in-page table-of-contents code with the shared AppShell, ShellNotifications, and PageOutline system.
|
|
194
277
|
|
|
195
278
|
Start by auditing:
|
|
196
279
|
- Current layout wrappers and route groups.
|
|
197
280
|
- Sidebar, topbar, breadcrumb, command/search, auth menu, and mobile navigation implementations.
|
|
281
|
+
- Existing notification badges, inbox panels, toasts that represent durable in-app items, unread count queries, mark-read actions, and delivery modules.
|
|
282
|
+
- Imports from @contractspec/module.notifications that should migrate to @contractspec/lib.contracts-spec/notifications or @contractspec/lib.notification.
|
|
198
283
|
- Any duplicated navigation arrays, route labels, icon maps, access-control checks, and active-state logic.
|
|
199
284
|
- Any in-page summary/table-of-contents components that should become PageOutline data.
|
|
200
285
|
- Web-only assumptions that would block Expo/React Native adaptation.
|
|
@@ -203,28 +288,31 @@ Refactor plan:
|
|
|
203
288
|
1. Define a single typed navigation source for primary nav, grouped sidebar nav, nested children, labels, icons, badges, disabled states, and permissions.
|
|
204
289
|
2. Map existing command/search behavior into grouped command actions with search text and quick actions.
|
|
205
290
|
3. Map existing route metadata into breadcrumbs.
|
|
206
|
-
4.
|
|
207
|
-
5.
|
|
208
|
-
6.
|
|
209
|
-
7.
|
|
291
|
+
4. Move canonical notification contracts to @contractspec/lib.contracts-spec/notifications and reusable helpers to @contractspec/lib.notification; keep the old module shim only for compatibility imports that still need the legacy module id.
|
|
292
|
+
5. Convert notification query results into ShellNotificationCenter items with unreadCount, loading, empty state, onSelect, onMarkRead, and onMarkAllRead callbacks.
|
|
293
|
+
6. Convert page table-of-contents or section summary data into PageOutline items with a maximum of three levels.
|
|
294
|
+
7. Wrap app routes in AppShell while keeping page content components route-local.
|
|
295
|
+
8. Move primary mobile destinations into bottom navigation and deeper/account/notification actions into a menu or drawer.
|
|
296
|
+
9. Add or preserve .native.tsx adapters when the app targets Expo.
|
|
210
297
|
|
|
211
298
|
Preserve behavior:
|
|
212
299
|
- Existing route URLs and access rules.
|
|
213
300
|
- Existing keyboard shortcuts where they are public behavior.
|
|
214
301
|
- Existing analytics or telemetry events on navigation and command actions.
|
|
302
|
+
- Existing notification delivery semantics, unread count semantics, deep links, and mark-read behavior.
|
|
215
303
|
- Existing auth/logout behavior.
|
|
216
304
|
- Existing responsive breakpoints unless there is a documented design-system breakpoint to adopt.
|
|
217
305
|
|
|
218
306
|
Quality gates:
|
|
219
307
|
- Add regression tests around current visible navigation before removing old shell code when coverage is missing.
|
|
220
|
-
- Test active nav state, nested nav expansion, command search/action invocation, breadcrumbs, auth menu, mobile bottom navigation, and PageOutline anchor behavior.
|
|
308
|
+
- Test active nav state, nested nav expansion, command search/action invocation, breadcrumbs, notification unread badge/loading/empty/callback behavior, auth menu, mobile bottom navigation, and PageOutline anchor behavior.
|
|
221
309
|
- Run lint, typecheck, and the app's relevant test/build command.
|
|
222
310
|
- Remove dead app-specific shell components only after the shared shell path is verified.
|
|
223
311
|
|
|
224
312
|
Output:
|
|
225
313
|
- List old shell files removed or simplified.
|
|
226
314
|
- List new shared shell integration points.
|
|
227
|
-
- Include before/after route coverage and verification commands.`,
|
|
315
|
+
- Include before/after route coverage and verification commands.`,rt=[{title:"Contracts stay canonical",body:"Use @contractspec/lib.contracts-spec/notifications for operation models, feature metadata, and contract-level compatibility."},{title:"Runtime helpers stay reusable",body:"Use @contractspec/lib.notification for schema contribution, channel adapters, templates, and i18n without importing the deprecated module shim in new code."},{title:"Apps own live state",body:"Fetch, subscribe, persist, mutate, and reconcile notification state in the host app or runtime layer where auth and tenancy are known."},{title:"Shell receives view state",body:"Pass AppShell a ShellNotificationCenter with render-ready items, counts, loading state, and callbacks; the design system only renders affordances."}],nt=[{title:"Sidebar",body:"Desktop owns brand, command entry, grouped navigation, nested items, and account actions in one persistent scanning area."},{title:"Topbar",body:"Breadcrumbs stay visible while the current route changes. Command search and notification affordances can live here when the sidebar is collapsed or hidden."},{title:"PageOutline",body:"The right-side in-page navigator replaces ad hoc tables of contents. It supports three levels of section anchors and active state."},{title:"Notifications",body:"The shell renders unread badges, item lists, loading/empty states, mark-read actions, and deep-link selection from host-owned notification state."},{title:"Mobile adapters",body:"Small web and native surfaces move primary destinations to bottom navigation and reserve drawers or menus for deep navigation, notifications, and account actions."}];import{CodeBlock as De,InstallCommand as va}from"@contractspec/lib.design-system";import{Box as Me,HStack as ya,VStack as ae}from"@contractspec/lib.design-system/layout";import{Code as pe,H1 as Na,H2 as ve,H3 as ct,P as me,Text as st}from"@contractspec/lib.design-system/typography";import lt from"@contractspec/lib.ui-link";import{ChevronRight as wa}from"lucide-react";import{jsx as c,jsxs as L}from"react/jsx-runtime";function ka(){return L(ae,{className:"space-y-8",children:[L(ae,{className:"space-y-4",children:[c(Na,{className:"font-bold text-4xl",children:"Application shell"}),L(me,{className:"text-lg text-muted-foreground",children:["A reusable navigation system for product apps: desktop sidebar, topbar breadcrumbs, command search, account actions, mobile adapters, and a Notion-style ",c(pe,{children:"PageOutline"})," for page sections, with prop-driven in-app notifications for web and native shells."]})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"Installation"}),c(va,{package:"@contractspec/lib.design-system"})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"What It Standardizes"}),c(Me,{className:"grid gap-4 md:grid-cols-2",children:nt.map((a)=>L(Me,{className:"card-subtle p-4",children:[c(ct,{className:"font-semibold",children:a.title}),c(me,{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"Import Surface"}),c(me,{className:"text-muted-foreground",children:"The shell is exposed as a focused design-system subpath so apps can adopt navigation chrome without pulling unrelated documentation or marketing helpers."}),c(De,{language:"tsx",filename:"app-shell-example.tsx",code:tt})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"Notification Center Boundary"}),L(me,{className:"text-muted-foreground",children:["Notifications are part of the shell experience, but the design system only renders the affordance. Contracts, runtime helpers, persistence, delivery, auth, and subscriptions stay outside the shell and feed a render-ready ",c(pe,{children:"ShellNotificationCenter"})," into"," ",c(pe,{children:"AppShell"}),"."]}),c(Me,{className:"grid gap-4 md:grid-cols-2",children:rt.map((a)=>L(Me,{className:"card-subtle p-4",children:[c(ct,{className:"font-semibold",children:a.title}),c(me,{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),c(De,{language:"tsx",filename:"notification-center-boundary.ts",code:at})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"AI Prompt: Build From Scratch"}),c(me,{className:"text-muted-foreground",children:"Use this prompt when the app does not already have a shell, command surface, page outline, or in-app notification center."}),c(De,{language:"markdown",filename:"implement-application-shell.md",code:ot})]}),L(ae,{className:"space-y-4",children:[c(ve,{className:"font-bold text-2xl",children:"AI Prompt: Refactor An App"}),c(me,{className:"text-muted-foreground",children:"Use this prompt when an app already has custom navigation chrome and notification UI that need to migrate without breaking route behavior, unread counts, or delivery semantics."}),c(De,{language:"markdown",filename:"refactor-to-application-shell.md",code:it})]}),L(ae,{className:"card-subtle space-y-3 p-6",children:[c(ve,{className:"font-bold text-2xl",children:"Naming"}),L(me,{className:"text-muted-foreground",children:["Use ",c(pe,{children:"AppShell"})," for the whole navigation frame and"," ",c(pe,{children:"PageOutline"})," for the in-page navigation helper. The latter is the product-app equivalent of a table of contents, but it is intentionally named for live page sections rather than static documentation. Use ",c(pe,{children:"ShellNotifications"})," for the notification affordance when it is rendered directly, or pass the same data contract through ",c(pe,{children:"AppShell"})," with the"," ",c(pe,{children:"notifications"})," prop."]})]}),L(ya,{className:"flex flex-wrap items-center gap-3 pt-2",children:[c(lt,{href:"/docs/libraries/cross-platform-ui",className:"btn-ghost",children:c(st,{children:"Cross-platform UI"})}),L(lt,{href:"/docs/libraries/design-system",className:"btn-primary",children:[c(st,{children:"Design System"})," ",c(wa,{size:16})]})]})]})}import{CodeBlock as Sa,InstallCommand as Ra}from"@contractspec/lib.design-system";import dt from"@contractspec/lib.ui-link";import{ChevronRight as Ca}from"lucide-react";import{jsx as G,jsxs as ue}from"react/jsx-runtime";function Ta(){return ue("div",{className:"space-y-8",children:[ue("div",{className:"space-y-4",children:[G("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.content-gen"}),G("p",{className:"text-lg text-muted-foreground",children:"Feed a single ContentBrief and produce cohesive marketing assets without touching a CMS."})]}),ue("div",{className:"space-y-4",children:[G("h2",{className:"font-bold text-2xl",children:"Installation"}),G(Ra,{package:"@contractspec/lib.content-gen"})]}),ue("div",{className:"space-y-3",children:[G("h2",{className:"font-bold text-2xl",children:"One brief, many assets"}),G(Sa,{language:"typescript",code:`import {
|
|
228
316
|
BlogGenerator,
|
|
229
317
|
LandingPageGenerator,
|
|
230
318
|
EmailCampaignGenerator,
|
|
@@ -244,7 +332,7 @@ const blog = await new BlogGenerator().generate(brief);
|
|
|
244
332
|
const landing = await new LandingPageGenerator().generate(brief);
|
|
245
333
|
const email = await new EmailCampaignGenerator().generate({ brief, variant: 'announcement' });
|
|
246
334
|
const social = await new SocialPostGenerator().generate(brief);
|
|
247
|
-
const seo = new SeoOptimizer().optimize(brief);`})]}),
|
|
335
|
+
const seo = new SeoOptimizer().optimize(brief);`})]}),ue("div",{className:"space-y-3",children:[G("h2",{className:"font-bold text-2xl",children:"When to use"}),ue("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[G("li",{children:"Ship landing page refreshes whenever specs change."}),G("li",{children:"Automate release emails + nurture sequences per vertical."}),G("li",{children:"Create social snippets that stay on-message with the same brief."}),G("li",{children:"Generate SEO metadata + Schema.org markup alongside content."})]})]}),ue("div",{className:"flex items-center gap-4 pt-4",children:[G(dt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),ue(dt,{href:"/docs/libraries/support-bot",className:"btn-primary",children:["Next: Support Bot ",G(Ca,{size:16})]})]})]})}import{CodeBlock as Aa,InstallCommand as La}from"@contractspec/lib.design-system";import _e from"@contractspec/lib.ui-link";import{ChevronRight as Ia}from"lucide-react";import{jsx as s,jsxs as l}from"react/jsx-runtime";var Pa=`import { defineDataView } from '@contractspec/lib.contracts-spec/data-views';
|
|
248
336
|
import { ListDataGridShowcaseRowsQuery } from '@contractspec/example.data-grid-showcase/contracts/data-grid-showcase.operation';
|
|
249
337
|
|
|
250
338
|
export const DataGridShowcaseDataView = defineDataView({
|
|
@@ -291,7 +379,7 @@ export const DataGridShowcaseDataView = defineDataView({
|
|
|
291
379
|
{ key: 'notes', label: 'Notes', dataPath: 'notes' },
|
|
292
380
|
],
|
|
293
381
|
},
|
|
294
|
-
});`;function
|
|
382
|
+
});`;function Oa(){return l("div",{className:"space-y-8",children:[l("div",{className:"space-y-4",children:[s("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.contracts-spec"}),s("p",{className:"text-lg text-muted-foreground",children:"The core library for defining what your application can do. Unified specifications for Operations, Events, Presentations, and Features."})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Installation"}),s(La,{package:["@contractspec/lib.contracts-spec","@contractspec/lib.schema"]})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"What lives where"}),l("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[l("li",{children:[s("strong",{children:"@contractspec/lib.contracts-spec"})," (root): The core contracts definitions (OperationSpec, PresentationSpec, Registry)."]}),l("li",{children:[s("strong",{children:"@contractspec/lib.contracts-runtime-client-react"}),": Browser-safe helpers (React renderers, client SDK). Import this for web/React Native."]}),l("li",{children:[s("strong",{children:"@contractspec/lib.contracts-runtime-server-rest"}),": HTTP/MCP adapters, registries, integrations (Node-only)."]}),l("li",{children:[s("strong",{children:"@contractspec/lib.schema"}),": Schema dictionary (SchemaModel, FieldType) for I/O definitions."]})]})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Data table contract example"}),l("p",{className:"text-muted-foreground",children:["The canonical account-grid example starts here in"," ",s("code",{children:"@contractspec/lib.contracts-spec"}),". The contract declares table execution mode, selection, pinning, resizing, row expansion, and initial state before any renderer is chosen."]}),s(Aa,{language:"typescript",code:Pa}),l("p",{className:"text-muted-foreground text-sm",children:["See the live version in"," ",s(_e,{href:"/docs/examples/data-grid-showcase",className:"text-[color:var(--rust)] underline underline-offset-4",children:"/docs/examples/data-grid-showcase"}),"."]})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Core Concepts"}),l("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[l("li",{children:[s("strong",{children:"OperationSpec"}),": Immutable description of an operation (Command or Query). Defines I/O, policy, and metadata."]}),l("li",{children:[s("strong",{children:"OperationSpecRegistry"}),": Registry of specs + handlers. Use ",s("code",{className:"font-mono text-xs",children:"installOp"})," ","to attach a handler."]}),l("li",{children:[s("strong",{children:"CapabilitySpec"}),": Canonical capability declaration (requires/provides)."]}),l("li",{children:[s("strong",{children:"PolicySpec"}),": Declarative policy rules (ABAC/ReBAC, rate limits)."]}),l("li",{children:[s("strong",{children:"TelemetrySpec"}),": Analytics definitions and privacy levels."]}),l("li",{children:[s("strong",{children:"PresentationSpec (V2)"}),": Describes how data is rendered (Web Components, Markdown, Data)."]}),l("li",{children:[s("strong",{children:"DataViewSpec"}),": Declarative list, table, grid, and detail contracts that the table showcase uses as its canonical account-grid example."]})]})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Lifecycle"}),l("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[l("li",{children:[s("strong",{children:"Define"})," the spec (I/O via SchemaModel or Zod)."]}),l("li",{children:[s("strong",{children:"Register"})," it:"," ",s("code",{className:"font-mono text-xs",children:"installOp(registry, spec, handler)"}),"."]}),l("li",{children:[s("strong",{children:"Expose"})," it via an adapter (REST, GraphQL, MCP)."]}),l("li",{children:[s("strong",{children:"Validate"})," at runtime automatically."]})]})]}),l("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Adapters"}),l("ul",{className:"space-y-2 text-muted-foreground",children:[l("li",{children:[s("code",{className:"rounded bg-background/50 px-2 py-1",children:"server/rest-next-app"}),": Next.js App Router adapter"]}),l("li",{children:[s("code",{className:"rounded bg-background/50 px-2 py-1",children:"server/provider-mcp"}),": Model Context Protocol (MCP) for AI agents"]}),l("li",{children:[s("code",{className:"rounded bg-background/50 px-2 py-1",children:"server/graphql-pothos"}),": GraphQL schema generator"]})]})]}),l("div",{className:"flex items-center gap-4 pt-4",children:[l(_e,{href:"/docs/libraries/schema",className:"btn-primary",children:["Next: Schema ",s(Ia,{size:16})]}),s(_e,{href:"/docs/specs/capabilities",className:"btn-ghost",children:"Core Concepts"})]})]})}import{CodeBlock as pt,InstallCommand as Da}from"@contractspec/lib.design-system";import mt from"@contractspec/lib.ui-link";import{ChevronRight as Ma}from"lucide-react";import{jsx as Q,jsxs as $}from"react/jsx-runtime";function Ea(){return $("div",{className:"space-y-8",children:[$("div",{className:"space-y-4",children:[Q("h1",{className:"font-bold text-4xl",children:"Cost Tracking Library"}),$("p",{className:"text-lg text-muted-foreground",children:[Q("code",{children:"@contractspec/lib.cost-tracking"})," transforms raw telemetry into dollars: DB/API/compute costs per operation, budget alerts per tenant, and actionable optimization tips."]})]}),$("div",{className:"space-y-4",children:[Q("h2",{className:"font-bold text-2xl",children:"Installation"}),Q(Da,{package:"@contractspec/lib.cost-tracking"})]}),$("div",{className:"space-y-4",children:[Q("h2",{className:"font-bold text-2xl",children:"Record Samples"}),Q(pt,{language:"typescript",code:`const tracker = new CostTracker();
|
|
295
383
|
tracker.recordSample({
|
|
296
384
|
operation: 'orders.list',
|
|
297
385
|
tenantId: 'acme',
|
|
@@ -299,12 +387,12 @@ tracker.recordSample({
|
|
|
299
387
|
dbWrites: 4,
|
|
300
388
|
computeMs: 180,
|
|
301
389
|
externalCalls: [{ provider: 'stripe', cost: 0.02 }],
|
|
302
|
-
});`})]})
|
|
390
|
+
});`})]}),$("div",{className:"space-y-4",children:[Q("h2",{className:"font-bold text-2xl",children:"Budget Alerts"}),Q(pt,{language:"typescript",code:`const budgets = new BudgetAlertManager({
|
|
303
391
|
budgets: [{ tenantId: 'acme', monthlyLimit: 150 }],
|
|
304
392
|
onAlert: ({ tenantId, total }) => notifyFinance(tenantId, total),
|
|
305
393
|
});
|
|
306
394
|
|
|
307
|
-
tracker.getTotals({ tenantId: 'acme' }).forEach((summary) => budgets.track(summary));`})]})
|
|
395
|
+
tracker.getTotals({ tenantId: 'acme' }).forEach((summary) => budgets.track(summary));`})]}),$("div",{className:"space-y-4",children:[Q("h2",{className:"font-bold text-2xl",children:"Optimization Suggestions"}),$("p",{className:"text-muted-foreground text-sm",children:["Feed summaries into ",Q("code",{children:"OptimizationRecommender"})," to surface N+1 queries, compute-heavy steps, or expensive external calls. Store the generated suggestions in the new Prisma model to power Ops playbooks."]})]}),$("div",{className:"flex items-center gap-4 pt-4",children:[Q(mt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),$(mt,{href:"/docs/libraries/slo",className:"btn-primary",children:["Next: SLO ",Q(Ma,{size:16})]})]})]})}var ut=[{title:"@contractspec/lib.presentation-runtime-core",body:"Shared state, table models, workflow logic, visualization helpers, and the alias helpers consumed by web and native builds."},{title:"@contractspec/lib.presentation-runtime-react",body:"React-facing hooks such as useContractTable, useDataViewTable, and useWorkflow. This is the shared hook surface most product code starts from."},{title:"@contractspec/lib.presentation-runtime-react-native",body:"Native entrypoint for mobile apps. It re-exports the shared table and data-view hooks so the controller API stays aligned with the React package."},{title:"@contractspec/lib.ui-kit-web",body:"Browser-first primitives and accessibility helpers. Reach for this layer when you want direct control over the web renderer."},{title:"@contractspec/lib.ui-kit",body:"Native-first primitives for Expo and React Native. Reach for this layer when the render surface should stay mobile-native."},{title:"@contractspec/lib.design-system",body:"Composed components, ThemeSpec/TranslationSpec-aware controls, token helpers, and paired web/mobile implementations that sit on top of both UI kits."}],ht=[{title:"useContractTable",body:"Use this when your rows and column definitions already live in product code and you want one headless controller for sorting, pagination, selection, visibility, pinning, sizing, and expansion."},{title:"useDataViewTable",body:"Use this when the table should stay driven by a DataViewSpec instead of hand-authored columns. It adapts the spec to the same generic controller model."},{title:"Native re-export boundary",body:"On native apps, import the same hook names from @contractspec/lib.presentation-runtime-react-native when you want the import path itself to signal a mobile boundary."}],gt=[{title:"Next.js / Turbopack",body:"Use withPresentationTurbopackAliases as the default path in current Next.js apps. It patches nextConfig.turbopack instead of mutating a webpack config object."},{title:"Next.js / Webpack fallback",body:"Use withPresentationWebpackAliases only when a Next.js app explicitly opts back into webpack via the CLI flags."},{title:"Expo / Metro",body:"Use withPresentationMetroAliases on Metro when native platforms should resolve web ui-kit /ui imports and the shared React runtime root to native implementations."}],ft=[{title:"withPlatformUI",body:"Use this lightweight adapter when a design-system surface needs one object that carries the current platform, tokens, and breakpoints."},{title:"mapTokensForPlatform",body:"Use this when resolved tokens need to be mapped into platform-specific token shapes before the final renderer consumes them."}],bt=[{title:"What Webpack remaps",items:["@contractspec/lib.ui-kit -> @contractspec/lib.ui-kit-web","@contractspec/lib.presentation-runtime-react-native -> @contractspec/lib.presentation-runtime-react","Prepends .web.js, .web.jsx, .web.ts, and .web.tsx to webpack resolve.extensions"]},{title:"What Turbopack remaps",items:["@contractspec/lib.ui-kit -> @contractspec/lib.ui-kit-web","@contractspec/lib.presentation-runtime-react-native -> @contractspec/lib.presentation-runtime-react","Initializes or merges turbopack.resolveExtensions with a web-first extension list"]},{title:"What Metro remaps",items:["@contractspec/lib.ui-kit-web/ui/* -> @contractspec/lib.ui-kit/ui/* on ios/android/native/mobile","Root @contractspec/lib.presentation-runtime-react -> @contractspec/lib.presentation-runtime-react-native","Enables package exports and expands platform resolution ordering"]}],vt=["Set gap, align, justify, and wrap explicitly in shared code because defaults are not identical between web and native.","Shared-safe subset: VStack, HStack, and Box with className, gap, align, justify, and wrap.","Web-only feature: as lets stack primitives emit semantic elements such as section, header, main, or article.","Native-only extras: spacing, width, and padding exist on the native stack primitives and should stay out of shared renderer code.","HStack and Box reverse-wrap tokens differ: wrapReverse on web, reverse on native. Prefer nowrap or wrap in shared code.","Box defaults to nowrap on web and wrap on native, so shared code should set wrap intentionally."],yt=["withPresentationNextAliases no longer exists. Use withPresentationTurbopackAliases for the default Next.js path or withPresentationWebpackAliases for explicit webpack fallback.","Prefer root runtime imports when alias helpers matter. Metro remaps the root @contractspec/lib.presentation-runtime-react package, not arbitrary deep hook subpaths.","Metro only rewrites @contractspec/lib.ui-kit-web/ui/* imports. Router-specific web packages and other web-only helpers still need platform-aware imports.","presentation-runtime-core is headless. It owns models and config helpers, not rendered React components.","design-system compatibility comes from paired .tsx / .native.tsx implementations and token helpers such as withPlatformUI and mapTokensForPlatform.","Form controls should come from @contractspec/lib.design-system when product code needs ThemeSpec or TranslationSpec support.","Stack primitives are similar across platforms, but the prop surface is not identical. Stay inside the common subset for shared renderers.","Alias helpers solve module resolution only. They do not replace app-level monorepo watchFolders, Expo Router setup, or other Next configuration."],Nt="Copy these markdown snippets into your own AGENTS.md, LLM guide, README, or engineering playbook when you want to enforce the same cross-surface rules across customer projects.",wt=`import { withPresentationTurbopackAliases } from '@contractspec/lib.presentation-runtime-core';
|
|
308
396
|
|
|
309
397
|
/** @type {import('next').NextConfig} */
|
|
310
398
|
const nextConfig = withPresentationTurbopackAliases({
|
|
@@ -315,14 +403,14 @@ const nextConfig = withPresentationTurbopackAliases({
|
|
|
315
403
|
},
|
|
316
404
|
});
|
|
317
405
|
|
|
318
|
-
export default nextConfig;`,
|
|
406
|
+
export default nextConfig;`,kt=`import { withPresentationWebpackAliases } from '@contractspec/lib.presentation-runtime-core';
|
|
319
407
|
|
|
320
408
|
/** @type {import('next').NextConfig} */
|
|
321
409
|
const nextConfig = {
|
|
322
410
|
webpack: (config) => withPresentationWebpackAliases(config),
|
|
323
411
|
};
|
|
324
412
|
|
|
325
|
-
export default nextConfig;`,
|
|
413
|
+
export default nextConfig;`,St=`const { getDefaultConfig } = require('expo/metro-config');
|
|
326
414
|
const {
|
|
327
415
|
withPresentationMetroAliases,
|
|
328
416
|
} = require('@contractspec/lib.presentation-runtime-core');
|
|
@@ -330,8 +418,8 @@ const {
|
|
|
330
418
|
const projectRoot = __dirname;
|
|
331
419
|
const config = getDefaultConfig(projectRoot);
|
|
332
420
|
|
|
333
|
-
module.exports = withPresentationMetroAliases(config);`,
|
|
334
|
-
`),
|
|
421
|
+
module.exports = withPresentationMetroAliases(config);`,Rt=["import {"," defaultTokens,"," mapTokensForPlatform,"," withPlatformUI,","} from '@contractspec/lib.design-system';","","const nativeTokens = mapTokensForPlatform('native', defaultTokens);","","const ui = withPlatformUI({"," tokens: defaultTokens,"," platform: 'web',","});","","// ui is a lightweight config object for design-system consumers.","// nativeTokens is the mapped token shape for a native renderer."].join(`
|
|
422
|
+
`),Ct=`import { Box, HStack, VStack } from '@contractspec/lib.ui-kit-web/ui/stack';
|
|
335
423
|
|
|
336
424
|
export function AccountSummaryHeader() {
|
|
337
425
|
return (
|
|
@@ -352,7 +440,7 @@ export function AccountSummaryHeader() {
|
|
|
352
440
|
// @contractspec/lib.ui-kit/ui/stack
|
|
353
441
|
//
|
|
354
442
|
// On web-only pages, VStack / HStack / Box also support:
|
|
355
|
-
// <VStack as="section">...</VStack>`,
|
|
443
|
+
// <VStack as="section">...</VStack>`,Tt=`import { DataTable as DesignSystemTable } from '@contractspec/lib.design-system';
|
|
356
444
|
import { DataTable as NativeTable } from '@contractspec/lib.ui-kit/ui/data-table';
|
|
357
445
|
import { DataTable as WebTable } from '@contractspec/lib.ui-kit-web/ui/data-table';
|
|
358
446
|
import { useContractTable } from '@contractspec/lib.presentation-runtime-react';
|
|
@@ -388,7 +476,7 @@ export function ProductAccounts({ controller }) {
|
|
|
388
476
|
}
|
|
389
477
|
|
|
390
478
|
// If the table is spec-driven instead of hand-authored,
|
|
391
|
-
// swap useContractTable for useDataViewTable.`,ot="# Cross-Surface Rendering Policy\n\n- Import runtime bundler helpers from `@contractspec/lib.presentation-runtime-core` root only.\n- Use `withPresentationTurbopackAliases` for default Next.js projects.\n- Use `withPresentationWebpackAliases` only when the app explicitly opts into webpack.\n- Use `withPresentationMetroAliases` for Expo and Metro builds.\n- Prefer `@contractspec/lib.design-system` for shared product-facing surfaces.\n- Use design-system controls when a field must respect ThemeSpec component variants or TranslationSpec messages.\n- Use `@contractspec/lib.ui-kit-web` only for web-specific primitive lanes.\n- Use `@contractspec/lib.ui-kit` only for native-specific primitive lanes.\n- Keep shared layout code inside the common `VStack` / `HStack` / `Box` subset.\n- Do not use removed `withPresentationNextAliases`.\n- Treat `.tsx` / `.native.tsx` pairs as the standard design-system compatibility boundary.",it="# Cross-Surface Rendering Checklist\n\n1. Configure the bundler aliases before sharing any UI code.\n2. Choose the controller layer:\n - use `useContractTable` for app-owned rows and columns\n - use `useDataViewTable` for DataViewSpec-driven tables\n3. Choose the renderer lane:\n - web primitive: `@contractspec/lib.ui-kit-web`\n - native primitive: `@contractspec/lib.ui-kit`\n - shared product surface: `@contractspec/lib.design-system`\n4. Verify mirrored `.tsx` / `.native.tsx` implementations where the design-system owns the surface.\n5. Wrap product surfaces in `DesignSystemThemeProvider` and `DesignSystemTranslationProvider` when ThemeSpec or TranslationSpec data is available.\n6. In shared layout code, set `gap`, `align`, `justify`, and `wrap` explicitly.\n7. Check docs and examples for root imports and current helper names before copying them into product code.";import{CodeBlock as oe}from"@contractspec/lib.design-system";import ue from"@contractspec/lib.ui-link";import{ChevronRight as ra}from"lucide-react";import{jsx as t,jsxs as f}from"react/jsx-runtime";function na(){return f("div",{className:"space-y-8",children:[f("div",{className:"space-y-4",children:[t("h1",{className:"font-bold text-4xl",children:"Cross-platform UI"}),t("p",{className:"text-lg text-muted-foreground",children:"How ContractSpec keeps React and React Native components compatible by splitting responsibility across shared runtime models, platform primitives, resolver aliases, and the composed design-system layer."})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"What cross-platform means here"}),t("p",{className:"text-muted-foreground",children:"The shared rendering story is layered: the core package owns models and resolver helpers, the React packages own hook APIs, the UI kits own raw primitives, and the design-system owns the higher-level product surfaces that pair web and mobile implementations."}),t("div",{className:"grid gap-4 md:grid-cols-2",children:qe.map((e)=>f("div",{className:"rounded-[20px] border border-border/70 p-4",children:[t("h3",{className:"font-semibold text-base",children:e.title}),t("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:e.body})]},e.title))}),t("div",{className:"grid gap-4 md:grid-cols-3",children:He.map((e)=>f("div",{className:"card-subtle p-4",children:[t("h3",{className:"font-semibold",children:e.title}),t("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:e.body})]},e.title))}),f("div",{className:"grid gap-4 lg:grid-cols-[1.1fr_0.9fr]",children:[t("div",{className:"grid gap-4 md:grid-cols-2",children:Ke.map((e)=>f("div",{className:"card-subtle p-4",children:[t("h3",{className:"font-semibold",children:e.title}),t("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:e.body})]},e.title))}),t(oe,{language:"typescript",filename:"design-system-platform.ts",code:et})]})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Resolver and alias setup"}),f("p",{className:"text-muted-foreground",children:["Teach the bundler what \u201Cweb\u201D and \u201Cnative\u201D mean before you try to share component code. These helpers are public from the root",t("code",{children:" @contractspec/lib.presentation-runtime-core "}),"entrypoint."]}),t("div",{className:"grid gap-4 md:grid-cols-2",children:Qe.map((e)=>f("div",{className:"card-subtle p-4",children:[t("h3",{className:"font-semibold",children:e.title}),t("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:e.body})]},e.title))}),f("div",{className:"grid gap-4 xl:grid-cols-3",children:[t(oe,{language:"typescript",filename:"next.config.mjs",code:$e}),t(oe,{language:"typescript",filename:"next.config.mjs",code:xe}),t(oe,{language:"javascript",filename:"metro.config.js",code:je})]})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"How the remapping works"}),t("p",{className:"text-muted-foreground",children:"The helpers are intentionally asymmetric because Turbopack patches the Next config object, Webpack mutates a resolver config, and Metro maps modules at request time for native platforms."}),t("div",{className:"grid gap-4 xl:grid-cols-3",children:Je.map((e)=>f("div",{className:"card-subtle p-4",children:[t("h3",{className:"font-semibold",children:e.title}),t("ul",{className:"mt-2 space-y-2 text-muted-foreground text-sm leading-7",children:e.items.map((S)=>t("li",{children:S},S))})]},e.title))})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Layout primitives"}),f("p",{className:"text-muted-foreground",children:[t("code",{children:"VStack"}),", ",t("code",{children:"HStack"}),", and ",t("code",{children:"Box"})," are the closest thing to a shared layout vocabulary, but their defaults and a few props still differ across the web and native packages."]}),t("div",{className:"grid gap-4 md:grid-cols-2",children:Ze.map((e)=>t("div",{className:"card-subtle p-4 text-muted-foreground text-sm leading-7",children:e},e))}),t(oe,{language:"tsx",filename:"stack-layout.tsx",code:tt})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Rendering patterns"}),t("p",{className:"text-muted-foreground",children:"Keep the controller stable, then decide whether the final surface should be a raw web primitive, a raw native primitive, or a composed design-system wrapper."}),t(oe,{language:"tsx",filename:"cross-platform-rendering.tsx",code:at}),f("div",{className:"card-subtle p-4 text-muted-foreground text-sm leading-7",children:["For higher-level shared rendering, use the design-system surfaces that already ship paired implementations such as"," ",t("code",{children:"DataViewRenderer"}),", ",t("code",{children:"ListTablePage"}),", and"," ",t("code",{children:"DataTable"}),". The web and mobile files stay separate inside the package while your app imports one design-system boundary."]})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Gotchas and boundaries"}),t("ul",{className:"space-y-2 text-muted-foreground leading-7",children:Xe.map((e)=>t("li",{children:e},e))})]}),f("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Customer markdown kit"}),t("p",{className:"text-muted-foreground",children:Ye}),f("div",{className:"grid gap-4 xl:grid-cols-2",children:[t(oe,{language:"markdown",filename:"cross-surface-policy.md",code:ot}),t(oe,{language:"markdown",filename:"cross-surface-checklist.md",code:it})]})]}),f("div",{className:"flex flex-wrap items-center gap-3 pt-2",children:[t(ue,{href:"/docs/libraries/runtime",className:"btn-ghost",children:"Runtime libraries"}),t(ue,{href:"/docs/libraries/ui-kit",className:"btn-ghost",children:"UI Kit"}),t(ue,{href:"/docs/libraries/ui-kit-web",className:"btn-ghost",children:"UI Kit Web"}),f(ue,{href:"/docs/libraries/design-system",className:"btn-primary",children:["Design System ",t(ra,{size:16})]})]})]})}import{CodeBlock as ca}from"@contractspec/lib.design-system";import rt from"@contractspec/lib.ui-link";import{ChevronRight as sa}from"lucide-react";import{jsx as w,jsxs as k}from"react/jsx-runtime";function la(){return k("div",{className:"space-y-8",children:[k("div",{className:"space-y-4",children:[w("h1",{className:"font-bold text-4xl",children:"Data & Backend"}),w("p",{className:"text-muted-foreground",children:"A collection of robust, platform-agnostic libraries for building the backend infrastructure of your LSSM applications."})]}),k("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Libraries"}),k("div",{className:"space-y-6",children:[k("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/app.cli-database"}),k("p",{className:"mt-2 text-muted-foreground text-sm",children:[w("strong",{children:"Prisma Wrapper & CLI"}),". Provides a unified way to manage database schemas, migrations, and clients. Includes seeders and factory patterns for testing."]})]}),k("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.bus"}),k("p",{className:"mt-2 text-muted-foreground text-sm",children:[w("strong",{children:"Type-Safe Event Bus"}),". Decouple your architecture with typed events. Supports in-memory dispatch for monoliths and can be extended for distributed message queues (Redis, SQS)."]})]}),k("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.logger"}),k("p",{className:"mt-2 text-muted-foreground text-sm",children:[w("strong",{children:"High-Performance Logging"}),". Optimized for Bun and structured JSON output. Includes plugins for ElysiaJS to log HTTP requests automatically."]})]}),k("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.error"}),k("p",{className:"mt-2 text-muted-foreground text-sm",children:[w("strong",{children:"Standardized Errors"}),". Use `AppError` with standard codes (NOT_FOUND, UNAUTHORIZED) to ensure consistent HTTP responses and error handling across services."]})]}),k("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.exporter"}),k("p",{className:"mt-2 text-muted-foreground text-sm",children:[w("strong",{children:"Data Export"}),". Generate CSV and XML files from your data. Platform-agnostic and streaming-friendly."]})]})]})]}),k("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Example: Unified Backend Flow"}),w(ca,{language:"typescript",code:`import { logger } from '@contractspec/lib.logger';
|
|
479
|
+
// swap useContractTable for useDataViewTable.`,At="# Cross-Surface Rendering Policy\n\n- Import runtime bundler helpers from `@contractspec/lib.presentation-runtime-core` root only.\n- Use `withPresentationTurbopackAliases` for default Next.js projects.\n- Use `withPresentationWebpackAliases` only when the app explicitly opts into webpack.\n- Use `withPresentationMetroAliases` for Expo and Metro builds.\n- Prefer `@contractspec/lib.design-system` for shared product-facing surfaces.\n- Use design-system controls when a field must respect ThemeSpec component variants or TranslationSpec messages.\n- Use `@contractspec/lib.ui-kit-web` only for web-specific primitive lanes.\n- Use `@contractspec/lib.ui-kit` only for native-specific primitive lanes.\n- Keep shared layout code inside the common `VStack` / `HStack` / `Box` subset.\n- Do not use removed `withPresentationNextAliases`.\n- Treat `.tsx` / `.native.tsx` pairs as the standard design-system compatibility boundary.",Lt="# Cross-Surface Rendering Checklist\n\n1. Configure the bundler aliases before sharing any UI code.\n2. Choose the controller layer:\n - use `useContractTable` for app-owned rows and columns\n - use `useDataViewTable` for DataViewSpec-driven tables\n3. Choose the renderer lane:\n - web primitive: `@contractspec/lib.ui-kit-web`\n - native primitive: `@contractspec/lib.ui-kit`\n - shared product surface: `@contractspec/lib.design-system`\n4. Verify mirrored `.tsx` / `.native.tsx` implementations where the design-system owns the surface.\n5. Wrap product surfaces in `DesignSystemThemeProvider` and `DesignSystemTranslationProvider` when ThemeSpec or TranslationSpec data is available.\n6. In shared layout code, set `gap`, `align`, `justify`, and `wrap` explicitly.\n7. Check docs and examples for root imports and current helper names before copying them into product code.";import{CodeBlock as he}from"@contractspec/lib.design-system";import Ee from"@contractspec/lib.ui-link";import{ChevronRight as Ba}from"lucide-react";import{jsx as i,jsxs as N}from"react/jsx-runtime";function Ua(){return N("div",{className:"space-y-8",children:[N("div",{className:"space-y-4",children:[i("h1",{className:"font-bold text-4xl",children:"Cross-platform UI"}),i("p",{className:"text-lg text-muted-foreground",children:"How ContractSpec keeps React and React Native components compatible by splitting responsibility across shared runtime models, platform primitives, resolver aliases, and the composed design-system layer."})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"What cross-platform means here"}),i("p",{className:"text-muted-foreground",children:"The shared rendering story is layered: the core package owns models and resolver helpers, the React packages own hook APIs, the UI kits own raw primitives, and the design-system owns the higher-level product surfaces that pair web and mobile implementations."}),i("div",{className:"grid gap-4 md:grid-cols-2",children:ut.map((a)=>N("div",{className:"rounded-[20px] border border-border/70 p-4",children:[i("h3",{className:"font-semibold text-base",children:a.title}),i("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),i("div",{className:"grid gap-4 md:grid-cols-3",children:ht.map((a)=>N("div",{className:"card-subtle p-4",children:[i("h3",{className:"font-semibold",children:a.title}),i("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),N("div",{className:"grid gap-4 lg:grid-cols-[1.1fr_0.9fr]",children:[i("div",{className:"grid gap-4 md:grid-cols-2",children:ft.map((a)=>N("div",{className:"card-subtle p-4",children:[i("h3",{className:"font-semibold",children:a.title}),i("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),i(he,{language:"typescript",filename:"design-system-platform.ts",code:Rt})]})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"Resolver and alias setup"}),N("p",{className:"text-muted-foreground",children:["Teach the bundler what \u201Cweb\u201D and \u201Cnative\u201D mean before you try to share component code. These helpers are public from the root",i("code",{children:" @contractspec/lib.presentation-runtime-core "}),"entrypoint."]}),i("div",{className:"grid gap-4 md:grid-cols-2",children:gt.map((a)=>N("div",{className:"card-subtle p-4",children:[i("h3",{className:"font-semibold",children:a.title}),i("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),N("div",{className:"grid gap-4 xl:grid-cols-3",children:[i(he,{language:"typescript",filename:"next.config.mjs",code:wt}),i(he,{language:"typescript",filename:"next.config.mjs",code:kt}),i(he,{language:"javascript",filename:"metro.config.js",code:St})]})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"How the remapping works"}),i("p",{className:"text-muted-foreground",children:"The helpers are intentionally asymmetric because Turbopack patches the Next config object, Webpack mutates a resolver config, and Metro maps modules at request time for native platforms."}),i("div",{className:"grid gap-4 xl:grid-cols-3",children:bt.map((a)=>N("div",{className:"card-subtle p-4",children:[i("h3",{className:"font-semibold",children:a.title}),i("ul",{className:"mt-2 space-y-2 text-muted-foreground text-sm leading-7",children:a.items.map((A)=>i("li",{children:A},A))})]},a.title))})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"Layout primitives"}),N("p",{className:"text-muted-foreground",children:[i("code",{children:"VStack"}),", ",i("code",{children:"HStack"}),", and ",i("code",{children:"Box"})," are the closest thing to a shared layout vocabulary, but their defaults and a few props still differ across the web and native packages."]}),i("div",{className:"grid gap-4 md:grid-cols-2",children:vt.map((a)=>i("div",{className:"card-subtle p-4 text-muted-foreground text-sm leading-7",children:a},a))}),i(he,{language:"tsx",filename:"stack-layout.tsx",code:Ct})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"Rendering patterns"}),i("p",{className:"text-muted-foreground",children:"Keep the controller stable, then decide whether the final surface should be a raw web primitive, a raw native primitive, or a composed design-system wrapper."}),i(he,{language:"tsx",filename:"cross-platform-rendering.tsx",code:Tt}),N("div",{className:"card-subtle p-4 text-muted-foreground text-sm leading-7",children:["For higher-level shared rendering, use the design-system surfaces that already ship paired implementations such as"," ",i("code",{children:"DataViewRenderer"}),", ",i("code",{children:"ListTablePage"}),", and"," ",i("code",{children:"DataTable"}),". The web and mobile files stay separate inside the package while your app imports one design-system boundary."]})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"Gotchas and boundaries"}),i("ul",{className:"space-y-2 text-muted-foreground leading-7",children:yt.map((a)=>i("li",{children:a},a))})]}),N("div",{className:"space-y-4",children:[i("h2",{className:"font-bold text-2xl",children:"Customer markdown kit"}),i("p",{className:"text-muted-foreground",children:Nt}),N("div",{className:"grid gap-4 xl:grid-cols-2",children:[i(he,{language:"markdown",filename:"cross-surface-policy.md",code:At}),i(he,{language:"markdown",filename:"cross-surface-checklist.md",code:Lt})]})]}),N("div",{className:"flex flex-wrap items-center gap-3 pt-2",children:[i(Ee,{href:"/docs/libraries/runtime",className:"btn-ghost",children:"Runtime libraries"}),i(Ee,{href:"/docs/libraries/ui-kit",className:"btn-ghost",children:"UI Kit"}),i(Ee,{href:"/docs/libraries/ui-kit-web",className:"btn-ghost",children:"UI Kit Web"}),N(Ee,{href:"/docs/libraries/design-system",className:"btn-primary",children:["Design System ",i(Ba,{size:16})]})]})]})}import{CodeBlock as Wa}from"@contractspec/lib.design-system";import It from"@contractspec/lib.ui-link";import{ChevronRight as za}from"lucide-react";import{jsx as R,jsxs as C}from"react/jsx-runtime";function Ga(){return C("div",{className:"space-y-8",children:[C("div",{className:"space-y-4",children:[R("h1",{className:"font-bold text-4xl",children:"Data & Backend"}),R("p",{className:"text-muted-foreground",children:"A collection of robust, platform-agnostic libraries for building the backend infrastructure of your LSSM applications."})]}),C("div",{className:"space-y-4",children:[R("h2",{className:"font-bold text-2xl",children:"Libraries"}),C("div",{className:"space-y-6",children:[C("div",{className:"card-subtle p-6",children:[R("h3",{className:"font-bold text-lg",children:"@contractspec/app.cli-database"}),C("p",{className:"mt-2 text-muted-foreground text-sm",children:[R("strong",{children:"Prisma Wrapper & CLI"}),". Provides a unified way to manage database schemas, migrations, and clients. Includes seeders and factory patterns for testing."]})]}),C("div",{className:"card-subtle p-6",children:[R("h3",{className:"font-bold text-lg",children:"@contractspec/lib.bus"}),C("p",{className:"mt-2 text-muted-foreground text-sm",children:[R("strong",{children:"Type-Safe Event Bus"}),". Decouple your architecture with typed events. Supports in-memory dispatch for monoliths and can be extended for distributed message queues (Redis, SQS)."]})]}),C("div",{className:"card-subtle p-6",children:[R("h3",{className:"font-bold text-lg",children:"@contractspec/lib.logger"}),C("p",{className:"mt-2 text-muted-foreground text-sm",children:[R("strong",{children:"High-Performance Logging"}),". Optimized for Bun and structured JSON output. Includes plugins for ElysiaJS to log HTTP requests automatically."]})]}),C("div",{className:"card-subtle p-6",children:[R("h3",{className:"font-bold text-lg",children:"@contractspec/lib.error"}),C("p",{className:"mt-2 text-muted-foreground text-sm",children:[R("strong",{children:"Standardized Errors"}),". Use `AppError` with standard codes (NOT_FOUND, UNAUTHORIZED) to ensure consistent HTTP responses and error handling across services."]})]}),C("div",{className:"card-subtle p-6",children:[R("h3",{className:"font-bold text-lg",children:"@contractspec/lib.exporter"}),C("p",{className:"mt-2 text-muted-foreground text-sm",children:[R("strong",{children:"Data Export"}),". Generate CSV and XML files from your data. Platform-agnostic and streaming-friendly."]})]})]})]}),C("div",{className:"space-y-4",children:[R("h2",{className:"font-bold text-2xl",children:"Example: Unified Backend Flow"}),R(Wa,{language:"typescript",code:`import { logger } from '@contractspec/lib.logger';
|
|
392
480
|
import { AppError } from '@contractspec/lib.error';
|
|
393
481
|
import { db } from '@contractspec/app.cli-database';
|
|
394
482
|
import { EventBus } from '@contractspec/lib.bus';
|
|
@@ -406,7 +494,124 @@ export async function createUser(email: string) {
|
|
|
406
494
|
await EventBus.publish('user.created', { userId: user.id });
|
|
407
495
|
|
|
408
496
|
return user;
|
|
409
|
-
}`})]}),
|
|
497
|
+
}`})]}),C("div",{className:"flex items-center gap-4 pt-4",children:[C(It,{href:"/docs/libraries/runtime",className:"btn-primary",children:["Next: Runtime ",R(za,{size:16})]}),R(It,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"})]})]})}import{CodeBlock as Pe,InstallCommand as Fa}from"@contractspec/lib.design-system";import{HStack as _a,VStack as ge}from"@contractspec/lib.design-system/layout";import{List as qa,ListItem as oe}from"@contractspec/lib.design-system/list";import{Code as d,H1 as Ha,H2 as Ce,H3 as Ka,P as Te,Text as J}from"@contractspec/lib.design-system/typography";import qe from"@contractspec/lib.ui-link";import{ChevronRight as Qa}from"lucide-react";import{jsx as t,jsxs as g}from"react/jsx-runtime";var Ja=`import { defineDataView } from '@contractspec/lib.contracts-spec/data-views';
|
|
498
|
+
|
|
499
|
+
export const AccountsDataView = defineDataView({
|
|
500
|
+
meta: {
|
|
501
|
+
key: 'crm.accounts',
|
|
502
|
+
version: '1.0.0',
|
|
503
|
+
title: 'Accounts',
|
|
504
|
+
description: 'Customer account workspace',
|
|
505
|
+
domain: 'crm',
|
|
506
|
+
entity: 'account',
|
|
507
|
+
owners: ['@crm'],
|
|
508
|
+
tags: ['crm', 'accounts'],
|
|
509
|
+
stability: 'stable',
|
|
510
|
+
},
|
|
511
|
+
source: {
|
|
512
|
+
primary: { key: 'crm.accounts.list', version: '1.0.0' },
|
|
513
|
+
},
|
|
514
|
+
view: {
|
|
515
|
+
kind: 'table',
|
|
516
|
+
fields: [
|
|
517
|
+
{ key: 'name', label: 'Name', dataPath: 'name', sortable: true },
|
|
518
|
+
{ key: 'owner', label: 'Owner', dataPath: 'owner' },
|
|
519
|
+
{ key: 'arr', label: 'ARR', dataPath: 'arr', format: { type: 'currency', currency: 'EUR' } },
|
|
520
|
+
{
|
|
521
|
+
key: 'internalNotes',
|
|
522
|
+
label: 'Internal notes',
|
|
523
|
+
dataPath: 'internalNotes',
|
|
524
|
+
visibility: { minDataDepth: 'detailed' },
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
columns: [
|
|
528
|
+
{ field: 'name' },
|
|
529
|
+
{ field: 'owner' },
|
|
530
|
+
{ field: 'arr' },
|
|
531
|
+
{ field: 'internalNotes' },
|
|
532
|
+
],
|
|
533
|
+
collection: {
|
|
534
|
+
viewModes: {
|
|
535
|
+
defaultMode: 'table',
|
|
536
|
+
allowedModes: ['list', 'grid', 'table'],
|
|
537
|
+
},
|
|
538
|
+
pagination: {
|
|
539
|
+
pageSize: 25,
|
|
540
|
+
pageSizeOptions: [10, 25, 50],
|
|
541
|
+
},
|
|
542
|
+
toolbar: {
|
|
543
|
+
search: true,
|
|
544
|
+
viewMode: true,
|
|
545
|
+
filters: true,
|
|
546
|
+
density: true,
|
|
547
|
+
dataDepth: true,
|
|
548
|
+
},
|
|
549
|
+
density: 'comfortable',
|
|
550
|
+
dataDepth: 'standard',
|
|
551
|
+
personalization: {
|
|
552
|
+
enabled: true,
|
|
553
|
+
persist: {
|
|
554
|
+
viewMode: true,
|
|
555
|
+
density: true,
|
|
556
|
+
dataDepth: true,
|
|
557
|
+
pageSize: true,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
});`,Za=`import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
563
|
+
import { resolveDataViewPreferences } from '@contractspec/lib.personalization/data-view-preferences';
|
|
564
|
+
|
|
565
|
+
const resolved = resolveDataViewPreferences({
|
|
566
|
+
spec: AccountsDataView,
|
|
567
|
+
preferences: profile.canonical,
|
|
568
|
+
insights,
|
|
569
|
+
record: savedDataViewPreference,
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
<DataViewRenderer
|
|
573
|
+
spec={AccountsDataView}
|
|
574
|
+
items={accounts}
|
|
575
|
+
defaultViewMode={resolved.viewMode}
|
|
576
|
+
defaultDensity={resolved.density}
|
|
577
|
+
defaultDataDepth={resolved.dataDepth}
|
|
578
|
+
pagination={{
|
|
579
|
+
page,
|
|
580
|
+
pageSize: resolved.pageSize ?? 25,
|
|
581
|
+
total,
|
|
582
|
+
}}
|
|
583
|
+
onViewModeChange={(viewMode) => {
|
|
584
|
+
tracker.trackDataViewInteraction({
|
|
585
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
586
|
+
dataViewVersion: AccountsDataView.meta.version,
|
|
587
|
+
action: 'view_mode_changed',
|
|
588
|
+
viewMode,
|
|
589
|
+
});
|
|
590
|
+
}}
|
|
591
|
+
onDensityChange={(density) => {
|
|
592
|
+
tracker.trackDataViewInteraction({
|
|
593
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
594
|
+
action: 'density_changed',
|
|
595
|
+
density,
|
|
596
|
+
});
|
|
597
|
+
}}
|
|
598
|
+
onDataDepthChange={(dataDepth) => {
|
|
599
|
+
tracker.trackDataViewInteraction({
|
|
600
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
601
|
+
action: 'data_depth_changed',
|
|
602
|
+
dataDepth,
|
|
603
|
+
});
|
|
604
|
+
}}
|
|
605
|
+
/>;
|
|
606
|
+
`,Va=`Implement a production DataView for <entity>.
|
|
607
|
+
|
|
608
|
+
Requirements:
|
|
609
|
+
- Define one canonical DataViewSpec with kind 'table', collection viewModes for list/grid/table, pagination defaults, toolbar search/filter/view mode/density/dataDepth controls, and personalization persist hints.
|
|
610
|
+
- Mark fields that should only appear in richer experiences with visibility.minDataDepth.
|
|
611
|
+
- Render it with DataViewRenderer using plain props from resolveDataViewPreferences.
|
|
612
|
+
- Track user interactions with trackDataViewInteraction for view mode, density, data depth, search, filters, sorting, and pagination.
|
|
613
|
+
- Keep @contractspec/lib.design-system independent from @contractspec/lib.personalization.
|
|
614
|
+
- Add focused tests for default resolution, invalid-mode fallback, data-depth projection, and behavior-derived preferred view mode.`;function Ya(){return g(ge,{className:"space-y-8",children:[g(ge,{className:"space-y-4",children:[t(Ha,{className:"font-bold text-4xl",children:"DataViews Runtime Library"}),g(Te,{className:"text-lg text-muted-foreground",children:["The ",t(d,{children:"@contractspec/lib.contracts-spec/data-views"})," and"," ",t(d,{children:"@contractspec/lib.design-system"})," libraries provide the runtime logic and UI components to render DataViews in your application."]})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"Installation"}),t(Fa,{package:["@contractspec/lib.contracts-spec","@contractspec/lib.design-system"]})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"DataViewRenderer"}),t(Te,{className:"text-muted-foreground",children:"The primary component for rendering any DataView. It automatically selects the correct layout (List, Table, Grid, Detail) based on the spec."}),t(Pe,{language:"tsx",code:`import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
410
615
|
import { MyUserList } from './specs/users.data-view';
|
|
411
616
|
|
|
412
617
|
export function UserPage() {
|
|
@@ -418,7 +623,7 @@ export function UserPage() {
|
|
|
418
623
|
onPageChange={(page) => fetchPage(page)}
|
|
419
624
|
/>
|
|
420
625
|
);
|
|
421
|
-
}`}),
|
|
626
|
+
}`}),t(Ka,{className:"font-semibold text-xl",children:"Props"}),g(qa,{className:"list-disc space-y-2 pl-6 text-muted-foreground",children:[t(oe,{children:g(J,{children:[t(d,{children:"spec"}),": The DataViewSpec definition."]})}),t(oe,{children:g(J,{children:[t(d,{children:"items"}),": Array of data items to render."]})}),t(oe,{children:g(J,{children:[t(d,{children:"filters"}),": Current filter state object."]})}),t(oe,{children:g(J,{children:[t(d,{children:"onFilterChange"}),": Callback when typed filters change. Renderers emit ",t(d,{children:"DataViewFilterValue"})," objects for numeric, percent, currency, temporal, duration, and boolean filters."]})}),t(oe,{children:g(J,{children:[t(d,{children:"pagination"}),": Object with ",t(d,{children:"page"}),","," ",t(d,{children:"pageSize"}),", ",t(d,{children:"total"}),"."]})}),t(oe,{children:g(J,{children:[t(d,{children:"onPageChange"}),": Callback when page changes."]})}),t(oe,{children:g(J,{children:[t(d,{children:"viewMode"})," / ",t(d,{children:"defaultViewMode"}),": Controlled or initial collection mode for specs that allow ",t(d,{children:"list"}),","," ",t(d,{children:"grid"}),", or ",t(d,{children:"table"})," projections through"," ",t(d,{children:"view.collection.viewModes"}),"."]})}),t(oe,{children:g(J,{children:[t(d,{children:"density"})," / ",t(d,{children:"defaultDensity"}),": Controlled or initial density for collection renderers. Host apps can seed this from ",t(d,{children:"@contractspec/lib.personalization"})," while specs can declare ",t(d,{children:"view.collection.density"})," and table"," ",t(d,{children:"view.density"})," defaults."]})}),t(oe,{children:g(J,{children:[t(d,{children:"dataDepth"})," / ",t(d,{children:"defaultDataDepth"}),": Controlled or initial summary/standard/detailed/exhaustive projection. Fields can declare ",t(d,{children:"visibility.minDataDepth"}),", and collection specs can opt into ",t(d,{children:"view.collection.personalization"})," ","persistence hints."]})})]})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"Collection Defaults And Data Depth"}),g(Te,{className:"text-muted-foreground",children:["Use one authored ",t(d,{children:"DataViewSpec"})," for list, grid, and table experiences. ",t(d,{children:"view.collection"})," declares allowed modes, toolbar controls, pagination defaults, density, data depth, and persistence hints. ",t(d,{children:"visibility.minDataDepth"})," lets a field appear only when the renderer is in a detailed or exhaustive mode."]}),t(Pe,{language:"typescript",code:Ja})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"Personalization Bridge"}),g(Te,{className:"text-muted-foreground",children:["Resolve user preferences in the host app, then pass ordinary renderer props into ",t(d,{children:"DataViewRenderer"}),". The bridge helper lives in"," ",t(d,{children:"@contractspec/lib.personalization"}),", so the design-system renderer stays portable for apps that do not use personalization. See the"," ",t(qe,{href:"/docs/libraries/personalization",className:"text-[color:var(--rust)] underline underline-offset-4",children:t(J,{children:"personalization library guide"})})," ","for the behavior tracker, analyzer, and DataView preference resolver."]}),t(Pe,{language:"tsx",code:Za})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"Agent Prompt"}),t(Te,{className:"text-muted-foreground",children:"Use this prompt when asking an implementation agent to add a preference-aware collection DataView without breaking package boundaries."}),t(Pe,{language:"markdown",code:Va})]}),g(ge,{className:"space-y-4",children:[t(Ce,{className:"font-bold text-2xl",children:"Query Generation"}),g(Te,{className:"text-muted-foreground",children:["The ",t(d,{children:"DataViewQueryGenerator"})," utility helps translate DataView parameters (filters, sorting, pagination) into query arguments for your backend."]}),t(Pe,{language:"typescript",code:`import { DataViewQueryGenerator } from '@contractspec/lib.contracts-spec/data-views/query-generator';
|
|
422
627
|
|
|
423
628
|
const generator = new DataViewQueryGenerator(MyUserList);
|
|
424
629
|
const params = {
|
|
@@ -433,7 +638,7 @@ const params = {
|
|
|
433
638
|
const errors = generator.validateParams(params);
|
|
434
639
|
const query = generator.generate(params);
|
|
435
640
|
|
|
436
|
-
// query.input contains skip/take plus the typed filter payloads.`})]}),
|
|
641
|
+
// query.input contains skip/take plus the typed filter payloads.`})]}),g(_a,{className:"items-center gap-4 pt-4",children:[t(qe,{href:"/docs/libraries",className:"btn-ghost",children:t(J,{children:"Back to Libraries"})}),g(qe,{href:"/docs/libraries/data-backend",className:"btn-primary",children:[t(J,{children:"Next: Data & Backend"})," ",t(Qa,{size:16})]})]})]})}import{CodeBlock as Ae,InstallCommand as Xa}from"@contractspec/lib.design-system";import Oe from"@contractspec/lib.ui-link";import{ChevronRight as $a}from"lucide-react";import{jsx as e,jsxs as o}from"react/jsx-runtime";var xa=`import { Button, DataTable } from '@contractspec/lib.design-system';
|
|
437
642
|
import { useContractTable } from '@contractspec/lib.presentation-runtime-react';
|
|
438
643
|
|
|
439
644
|
import { SHOWCASE_ROWS } from '@contractspec/example.data-grid-showcase/ui/data-grid-showcase.data';
|
|
@@ -481,7 +686,7 @@ export function AccountHealthTable() {
|
|
|
481
686
|
footer={\`Page \${controller.pageIndex + 1} of \${controller.pageCount}\`}
|
|
482
687
|
/>
|
|
483
688
|
);
|
|
484
|
-
}`,
|
|
689
|
+
}`,ja=`import {
|
|
485
690
|
DesignSystemThemeProvider,
|
|
486
691
|
resolveThemeModeTokens,
|
|
487
692
|
themeSpecToCssVariables,
|
|
@@ -511,13 +716,112 @@ export function TenantSurface({ children }: { children: React.ReactNode }) {
|
|
|
511
716
|
{children}
|
|
512
717
|
</DesignSystemThemeProvider>
|
|
513
718
|
);
|
|
514
|
-
}`,
|
|
719
|
+
}`,eo=`import { themeSpecToTailwindPreset } from '@contractspec/lib.design-system/theme';
|
|
515
720
|
import { Select } from '@contractspec/lib.design-system/controls';
|
|
516
721
|
import { FormDialog } from '@contractspec/lib.design-system/forms';
|
|
517
722
|
import { HStack } from '@contractspec/lib.design-system/layout';
|
|
723
|
+
import { AdaptivePanel } from '@contractspec/lib.design-system/components/overlays';
|
|
724
|
+
import { ObjectReferenceHandler } from '@contractspec/lib.design-system/components/object-reference';
|
|
518
725
|
|
|
519
726
|
// Root imports remain supported:
|
|
520
|
-
import { Button, DataTable } from '@contractspec/lib.design-system'
|
|
727
|
+
import { Button, DataTable } from '@contractspec/lib.design-system';`,to=`import {
|
|
728
|
+
ObjectReferenceHandler,
|
|
729
|
+
createDefaultObjectReferenceActions,
|
|
730
|
+
createMapsReferenceActions,
|
|
731
|
+
type ObjectReferenceDescriptor,
|
|
732
|
+
type ObjectReferenceOpenHrefHandler,
|
|
733
|
+
} from '@contractspec/lib.design-system';
|
|
734
|
+
|
|
735
|
+
const customerContact: ObjectReferenceDescriptor = {
|
|
736
|
+
id: 'user.amina',
|
|
737
|
+
kind: 'user',
|
|
738
|
+
label: 'Amina Laurent',
|
|
739
|
+
description: 'Customer success owner',
|
|
740
|
+
href: '/customers/acme/users/amina',
|
|
741
|
+
properties: [
|
|
742
|
+
{
|
|
743
|
+
id: 'user.amina.email',
|
|
744
|
+
kind: 'email',
|
|
745
|
+
label: 'Email',
|
|
746
|
+
value: 'amina@example.com',
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
id: 'user.amina.phone',
|
|
750
|
+
kind: 'phone',
|
|
751
|
+
label: 'Phone',
|
|
752
|
+
value: '+33 1 23 45 67 89',
|
|
753
|
+
},
|
|
754
|
+
],
|
|
755
|
+
sections: [
|
|
756
|
+
{
|
|
757
|
+
id: 'customer-site',
|
|
758
|
+
title: 'Primary site',
|
|
759
|
+
properties: [
|
|
760
|
+
{
|
|
761
|
+
id: 'customer-site.address',
|
|
762
|
+
kind: 'address',
|
|
763
|
+
label: 'Paris office',
|
|
764
|
+
value: '10 rue de Rivoli, 75001 Paris',
|
|
765
|
+
actions: createMapsReferenceActions({
|
|
766
|
+
id: 'customer-site.address',
|
|
767
|
+
kind: 'address',
|
|
768
|
+
label: 'Paris office',
|
|
769
|
+
value: '10 rue de Rivoli, 75001 Paris',
|
|
770
|
+
}),
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
},
|
|
774
|
+
],
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
const openHref: ObjectReferenceOpenHrefHandler = (href, _event, options) => {
|
|
778
|
+
if (options.target === 'new-page') {
|
|
779
|
+
window.open(href, '_blank', 'noopener,noreferrer');
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
window.location.assign(href);
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
<ObjectReferenceHandler
|
|
787
|
+
reference={customerContact}
|
|
788
|
+
actions={createDefaultObjectReferenceActions(customerContact)}
|
|
789
|
+
interactivityVisibility="icon"
|
|
790
|
+
openTarget="same-page"
|
|
791
|
+
panelMode="responsive"
|
|
792
|
+
mobilePanelMode="drawer"
|
|
793
|
+
desktopPanelMode="sheet"
|
|
794
|
+
responsiveBreakpoint="md"
|
|
795
|
+
openHref={openHref}
|
|
796
|
+
/>;`,ao=`import { AdaptivePanel } from '@contractspec/lib.design-system/components/overlays';
|
|
797
|
+
|
|
798
|
+
<AdaptivePanel
|
|
799
|
+
open={open}
|
|
800
|
+
onOpenChange={setOpen}
|
|
801
|
+
trigger={<button type="button">Edit</button>}
|
|
802
|
+
title="Edit customer"
|
|
803
|
+
description="Update contact and site details."
|
|
804
|
+
mode="responsive"
|
|
805
|
+
mobileMode="drawer"
|
|
806
|
+
desktopMode="sheet"
|
|
807
|
+
breakpoint="md"
|
|
808
|
+
sheetSide="right"
|
|
809
|
+
drawerDirection="bottom"
|
|
810
|
+
>
|
|
811
|
+
{content}
|
|
812
|
+
</AdaptivePanel>;`,oo=`Find every user-facing address, phone number, email, user, customer, file, URL, and tenant-specific object reference currently rendered as inert text.
|
|
813
|
+
|
|
814
|
+
Replace each one with ObjectReferenceHandler from @contractspec/lib.design-system. Keep descriptors data-only: id, kind, label, value, href, openTarget, properties, sections, metadata, iconKey, and ariaLabel are allowed; React callbacks belong in handler props only.
|
|
815
|
+
|
|
816
|
+
Use properties and sections for rich references. For example, a user reference can expose email, phone, address, files, and customer links in one panel instead of rendering separate disconnected strings.
|
|
817
|
+
|
|
818
|
+
Use panelMode="responsive" by default. Let desktop render a sheet and small screens render a bottom drawer through AdaptivePanel. Do not call Sheet or Drawer directly for this interaction unless a lower-level primitive is being implemented.
|
|
819
|
+
|
|
820
|
+
Use openTarget="same-page" unless product requirements explicitly require a new page. Put custom copy, navigation, analytics, permissions, or tenant-specific actions in copyHandler, openHref, actionHandlers, onAction, and onActionError.
|
|
821
|
+
|
|
822
|
+
For addresses, use createMapsReferenceActions so users can choose Google Maps, Apple Maps, or Waze. For email and phone references, prefer createDefaultObjectReferenceActions unless a product-specific action set is required.
|
|
823
|
+
|
|
824
|
+
After replacing references, verify keyboard access, visible affordance choice (none, underline, or icon), safe href behavior, mobile drawer layout, and desktop sheet layout.`;function io(){return o("div",{className:"space-y-8",children:[o("div",{className:"space-y-4",children:[e("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.design-system"}),o("p",{className:"text-muted-foreground",children:["High-level design system components, patterns, and layouts for LSSM applications. Built on top of ",e("code",{children:"@contractspec/lib.ui-kit"}),"."]})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Installation"}),e(Xa,{package:"@contractspec/lib.design-system"})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"What It Provides"}),o("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[o("li",{children:[e("strong",{children:"Composite Components"}),": Molecules and Organisms that solve common UI problems"]}),o("li",{children:[e("strong",{children:"Layouts"}),": Ready-to-use page structures for dashboards, marketing sites, and lists"]}),o("li",{children:[e("strong",{children:"Data Views"}),": Standardized renderers for lists, tables, and detail views"]}),o("li",{children:[e("strong",{children:"Forms"}),": Zod-integrated form layouts and components"]}),o("li",{children:[e("strong",{children:"Code Display"}),": Syntax-highlighted code blocks with package manager tabs"]}),o("li",{children:[e("strong",{children:"Platform Utilities"}),": Hooks for responsive and adaptive design"]}),o("li",{children:[e("strong",{children:"Object References"}),": Clickable references for addresses, phone numbers, users, customers, files, URLs, and custom objects"]}),o("li",{children:[e("strong",{children:"Adaptive Panels"}),": One panel API that resolves to a desktop sheet or mobile drawer"]}),o("li",{children:[e("strong",{children:"Theme Bridge"}),": ThemeSpec to Tailwind variables, presets, CSS text, and runtime light/dark mode"]}),o("li",{children:[e("strong",{children:"Legal Templates"}),": Compliant templates for Terms, Privacy, and GDPR"]})]})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"ThemeSpec to Tailwind"}),o("p",{className:"text-muted-foreground",children:["The theme bridge keeps ",e("code",{children:"ThemeSpec"})," as the source of truth and exposes no-generation Tailwind helpers, optional CSS text serialization, runtime CSS variables, light/dark modes, and OKLCH color pass-through."]}),e(Ae,{language:"tsx",code:ja})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Focused import surfaces"}),e("p",{className:"text-muted-foreground",children:"New code can use focused subpaths for theme, controls, forms, and layout while existing root imports remain compatible."}),e(Ae,{language:"tsx",code:eo})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Actionable object references"}),o("p",{className:"text-muted-foreground",children:["Use ",e("code",{children:"ObjectReferenceHandler"})," whenever a product surface renders an object that may need quick interaction: addresses, phone numbers, emails, users, customers, files, URLs, and tenant-specific objects. The goal is to avoid inert references while keeping the descriptor contract declarative enough for OSS consumers and future contract-generated surfaces."]}),o("div",{className:"grid gap-4 md:grid-cols-2",children:[o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Descriptor model"}),o("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[o("li",{children:["References use data-only descriptors: ",e("code",{children:"id"}),","," ",e("code",{children:"kind"}),", ",e("code",{children:"label"}),", ",e("code",{children:"value"}),","," ",e("code",{children:"href"}),", ",e("code",{children:"openTarget"}),","," ",e("code",{children:"metadata"}),", ",e("code",{children:"iconKey"}),", and"," ",e("code",{children:"ariaLabel"}),"."]}),o("li",{children:["Rich references use nested ",e("code",{children:"properties"})," and"," ",e("code",{children:"sections"}),", so one user or customer can expose email, phone, address, files, and links inside the same panel."]}),o("li",{children:["Reference kinds are ",e("code",{children:"address"}),", ",e("code",{children:"email"}),","," ",e("code",{children:"phone"}),", ",e("code",{children:"user"}),", ",e("code",{children:"customer"}),","," ",e("code",{children:"file"}),", ",e("code",{children:"url"}),", and ",e("code",{children:"custom"}),"."]})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Runtime behavior"}),o("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[o("li",{children:["Choose visibility with ",e("code",{children:"interactivityVisibility"}),":",e("code",{children:"none"}),", ",e("code",{children:"underline"}),", or ",e("code",{children:"icon"}),"."]}),o("li",{children:["Detail navigation defaults to ",e("code",{children:"same-page"}),"; set"," ",e("code",{children:'openTarget="new-page"'})," on the handler, reference, or action when a new page is required."]}),o("li",{children:["Host apps provide behavior through ",e("code",{children:"copyHandler"}),","," ",e("code",{children:"openHref"}),", ",e("code",{children:"actionHandlers"}),","," ",e("code",{children:"onAction"}),", and ",e("code",{children:"onActionError"}),"."]})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Default actions"}),o("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[o("li",{children:[e("code",{children:"createDefaultObjectReferenceActions"})," adds copy, open, email, phone, and map actions when the descriptor supports them."]}),o("li",{children:[e("code",{children:"createMapsReferenceActions"})," creates Google Maps, Apple Maps, Waze, or geo actions for address references."]}),e("li",{children:"Safe href handling allows expected app, web, email, phone, and map URLs while rejecting unsafe schemes."})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Extension points"}),o("ul",{className:"list-inside list-disc space-y-1 text-muted-foreground text-sm",children:[o("li",{children:["Use ",e("code",{children:"renderTrigger"}),", ",e("code",{children:"renderDetail"}),","," ",e("code",{children:"renderAction"}),", ",e("code",{children:"renderProperty"}),","," ",e("code",{children:"renderSection"}),", and ",e("code",{children:"iconRenderer"})," to wrap or overload presentation."]}),e("li",{children:"Keep tenant-specific permissions, analytics, and integration side effects at the host boundary through runtime handlers."})]})]})]}),e(Ae,{language:"tsx",code:to})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Adaptive panels"}),o("p",{className:"text-muted-foreground",children:[e("code",{children:"AdaptivePanel"})," is the shared overlay decision for surfaces that should feel native on both desktop and small screens. Its default responsive mode renders a sheet at the configured desktop breakpoint and a drawer below it. ",e("code",{children:"ObjectReferenceHandler"})," uses this panel contract through ",e("code",{children:"panelMode"}),","," ",e("code",{children:"mobilePanelMode"}),", ",e("code",{children:"desktopPanelMode"}),", and"," ",e("code",{children:"responsiveBreakpoint"}),"."]}),e(Ae,{language:"tsx",code:ao})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Prompt for adoption work"}),e("p",{className:"text-muted-foreground",children:"Use this prompt when asking an agent or downstream OSS consumer to replace inert references across an application."}),e(Ae,{language:"text",code:oo})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Data table example"}),o("p",{className:"text-muted-foreground",children:["This is the composed lane from the canonical"," ",e(Oe,{href:"/docs/examples/data-grid-showcase",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Data Grid Showcase"}),". The design-system wrapper owns title, description, header actions, and the opinionated card shell on top of the raw web primitive."]}),e(Ae,{language:"tsx",code:xa})]}),o("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Key Exports"}),o("div",{className:"grid gap-4 md:grid-cols-2",children:[o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Organisms"}),o("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"AppShell, PageOutline"}),e("li",{children:"AppLayout, AppHeader, AppSidebar"}),e("li",{children:"MarketingLayout, HeroSection"}),e("li",{children:"ListCardPage, ListTablePage"})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Data & Forms"}),o("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"DataTable"}),e("li",{children:"DataViewTable"}),e("li",{children:"DataViewRenderer"}),e("li",{children:"ZodForm"}),e("li",{children:"FormLayout, FormDialog"})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Code Display"}),o("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"CodeBlock (syntax highlighting)"}),e("li",{children:"CommandTabs (package manager tabs)"}),e("li",{children:"InstallCommand (convenience wrapper)"}),e("li",{children:"CopyButton"})]})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"Providers"}),e("ul",{className:"space-y-1 text-muted-foreground text-sm",children:e("li",{children:"PackageManagerProvider"})})]}),o("div",{className:"card-subtle p-4",children:[e("h3",{className:"mb-2 font-semibold",children:"References & Overlays"}),o("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[e("li",{children:"ObjectReferenceHandler"}),e("li",{children:"createDefaultObjectReferenceActions"}),e("li",{children:"createMapsReferenceActions"}),e("li",{children:"AdaptivePanel"})]})]})]})]}),o("div",{className:"card-subtle space-y-3 p-6",children:[e("h2",{className:"font-bold text-2xl",children:"Where this layer fits"}),o("p",{className:"text-muted-foreground",children:["Read"," ",e(Oe,{href:"/docs/libraries/application-shell",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Application shell"})," ","for the shared sidebar, topbar, command search, mobile navigation, and"," ",e("code",{children:"PageOutline"})," pattern. Read"," ",e(Oe,{href:"/docs/libraries/cross-platform-ui",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Cross-platform UI"})," ","for the package split between shared runtime controllers, leaf platform primitives, and this composed design-system layer."]})]}),o("div",{className:"flex items-center gap-4 pt-4",children:[e(Oe,{href:"/docs/libraries/ui-kit-web",className:"btn-ghost",children:"Previous: UI Kit Web"}),o(Oe,{href:"/docs/libraries/accessibility",className:"btn-primary",children:["Next: Accessibility ",e($a,{size:16})]})]})]})}import{CodeBlock as He,InstallCommand as ro}from"@contractspec/lib.design-system";import Pt from"@contractspec/lib.ui-link";import{ChevronRight as no}from"lucide-react";import{jsx as O,jsxs as ie}from"react/jsx-runtime";function co(){return ie("div",{className:"space-y-8",children:[ie("div",{className:"space-y-4",children:[O("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.evolution"}),O("p",{className:"text-lg text-muted-foreground",children:"Analyze production telemetry, surface anomalies, and turn them into AI-reviewed spec proposals that can be approved, rolled out, or reverted."})]}),ie("div",{className:"space-y-4",children:[O("h2",{className:"font-bold text-2xl",children:"Installation"}),O(ro,{package:"@contractspec/lib.evolution"})]}),ie("div",{className:"space-y-3",children:[O("h2",{className:"font-bold text-2xl",children:"From telemetry to intent"}),O(He,{language:"typescript",code:`import { SpecAnalyzer } from '@contractspec/lib.evolution/analyzer';
|
|
521
825
|
import { EvolutionPipeline } from '@contractspec/lib.observability';
|
|
522
826
|
|
|
523
827
|
const analyzer = new SpecAnalyzer();
|
|
@@ -532,7 +836,7 @@ pipeline.ingest({
|
|
|
532
836
|
success: false,
|
|
533
837
|
timestamp: new Date(),
|
|
534
838
|
errorCode: 'VALIDATION_FAILED',
|
|
535
|
-
});`})]})
|
|
839
|
+
});`})]}),ie("div",{className:"space-y-3",children:[O("h2",{className:"font-bold text-2xl",children:"Generate & approve suggestions"}),O(He,{language:"typescript",code:`import {
|
|
536
840
|
SpecGenerator,
|
|
537
841
|
SpecSuggestionOrchestrator,
|
|
538
842
|
InMemorySpecSuggestionRepository,
|
|
@@ -546,7 +850,7 @@ const suggestion = generator.generateFromIntent(intentPattern, {
|
|
|
546
850
|
summary: 'Add PO number requirement for acme.corp',
|
|
547
851
|
});
|
|
548
852
|
|
|
549
|
-
await orchestrator.submit(suggestion, sessionState);`})]})
|
|
853
|
+
await orchestrator.submit(suggestion, sessionState);`})]}),ie("div",{className:"space-y-3",children:[O("h2",{className:"font-bold text-2xl",children:"Write approved specs back to git"}),O(He,{language:"typescript",code:`import { FileSystemSuggestionWriter } from '@contractspec/lib.evolution/approval';
|
|
550
854
|
|
|
551
855
|
const writer = new FileSystemSuggestionWriter({
|
|
552
856
|
outputDir:
|
|
@@ -557,7 +861,7 @@ await writer.write({
|
|
|
557
861
|
...suggestion,
|
|
558
862
|
status: 'approved',
|
|
559
863
|
approvals: { reviewer: 'ops@contractspec', decidedAt: new Date() },
|
|
560
|
-
});`})]}),
|
|
864
|
+
});`})]}),O("div",{className:"grid gap-4 md:grid-cols-2",children:[{title:"Approvals by default",description:"Every suggestion flows through @contractspec/lib.ai-agent's ApprovalWorkflow. Tune auto-approval thresholds per environment."},{title:"Pluggable storage",description:"Use the Prisma repository in production, in-memory for tests, or stream serialized suggestions into your own queue."}].map((a)=>ie("div",{className:"card-subtle space-y-2 p-4",children:[O("h3",{className:"font-semibold text-lg",children:a.title}),O("p",{className:"text-muted-foreground text-sm",children:a.description})]},a.title))}),ie("div",{className:"flex items-center gap-4 pt-4",children:[O(Pt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),ie(Pt,{href:"/docs/libraries/observability",className:"btn-primary",children:["Next: Observability ",O(no,{size:16})]})]})]})}import{CodeBlock as so,InstallCommand as lo}from"@contractspec/lib.design-system";import Ot from"@contractspec/lib.ui-link";import{ChevronRight as po}from"lucide-react";import{jsx as w,jsxs as I}from"react/jsx-runtime";function mo(){return I("div",{className:"space-y-8",children:[I("div",{className:"space-y-4",children:[w("h1",{className:"font-bold text-4xl",children:"GraphQL Libraries"}),w("p",{className:"text-muted-foreground",children:"This suite of libraries enables seamless GraphQL integration, transforming your ContractSpecs into a type-safe Pothos schema, connecting with Prisma, and enabling Apollo Federation."})]}),I("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Libraries"}),I("div",{className:"grid gap-4 md:grid-cols-1",children:[I("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.graphql-core"}),w("p",{className:"mt-2 text-muted-foreground text-sm",children:"The foundation. Provides a configured Pothos builder, common scalars (JSON, DateTime), and utilities for mapping ContractSpec I/O to Pothos types."})]}),I("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.graphql-prisma"}),w("p",{className:"mt-2 text-muted-foreground text-sm",children:"Connects Pothos to Prisma. Automatically generates GraphQL types from your Prisma schema and optimizes queries to prevent N+1 issues."})]}),I("div",{className:"card-subtle p-6",children:[w("h3",{className:"font-bold text-lg",children:"@contractspec/lib.graphql-federation"}),w("p",{className:"mt-2 text-muted-foreground text-sm",children:"Adds Apollo Federation V2 support. Allows your subgraph to define keys and entities, making it ready for a supergraph."})]})]})]}),I("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Installation"}),w(lo,{package:["@contractspec/lib.graphql-core","@contractspec/lib.graphql-prisma","@contractspec/lib.graphql-federation"]})]}),I("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Usage: Building a Schema"}),w("p",{className:"text-muted-foreground",children:"Here's how to assemble a federated GraphQL schema from your specs:"}),w(so,{language:"typescript",code:`import { builder } from '@contractspec/lib.graphql-core';
|
|
561
865
|
import { registerContractsOnBuilder } from '@contractspec/lib.contracts-runtime-server-graphql/graphql-pothos';
|
|
562
866
|
import { OperationSpecRegistry } from '@contractspec/lib.contracts-spec';
|
|
563
867
|
import { MySpecs } from './specs';
|
|
@@ -571,7 +875,7 @@ registerContractsOnBuilder(builder, registry);
|
|
|
571
875
|
|
|
572
876
|
// 3. Build and print schema
|
|
573
877
|
const schema = builder.toSchema();
|
|
574
|
-
console.log(printSchema(schema));`})]}),
|
|
878
|
+
console.log(printSchema(schema));`})]}),I("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Features"}),I("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[I("li",{children:[w("strong",{children:"Code-First"}),": Define schema in TypeScript (Pothos), get SDL as artifact."]}),I("li",{children:[w("strong",{children:"Spec Integration"}),": `registerContractsOnBuilder` automatically converts Command/Query specs into Mutations/Queries."]}),I("li",{children:[w("strong",{children:"Federation Ready"}),": Just add `provider: 'federation'` to your config."]})]})]}),I("div",{className:"flex items-center gap-4 pt-4",children:[I(Ot,{href:"/docs/libraries/data-backend",className:"btn-primary",children:["Next: Data & Backend ",w(po,{size:16})]}),w(Ot,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"})]})]})}import{CodeBlock as Dt,InstallCommand as uo}from"@contractspec/lib.design-system";import Mt from"@contractspec/lib.ui-link";import{ChevronRight as ho}from"lucide-react";import{jsx as x,jsxs as ye}from"react/jsx-runtime";function go(){return ye("div",{className:"space-y-8",children:[ye("div",{className:"space-y-4",children:[x("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.growth"}),x("p",{className:"text-lg text-muted-foreground",children:"Launch experiments without third-party SDKs. Register variants, assign users deterministically, track exposures, and compute significance."})]}),ye("div",{className:"space-y-4",children:[x("h2",{className:"font-bold text-2xl",children:"Installation"}),x(uo,{package:"@contractspec/lib.growth"})]}),ye("div",{className:"space-y-3",children:[x("h2",{className:"font-bold text-2xl",children:"Register + assign"}),x(Dt,{language:"typescript",code:`import { ExperimentRegistry, ExperimentRunner } from '@contractspec/lib.growth/experiments';
|
|
575
879
|
|
|
576
880
|
const registry = new ExperimentRegistry().register({
|
|
577
881
|
key: 'pricing.cta',
|
|
@@ -585,7 +889,7 @@ const registry = new ExperimentRegistry().register({
|
|
|
585
889
|
});
|
|
586
890
|
|
|
587
891
|
const runner = new ExperimentRunner();
|
|
588
|
-
const assignment = runner.assign(registry.get('pricing.cta')!, 'user_123');`})]}),
|
|
892
|
+
const assignment = runner.assign(registry.get('pricing.cta')!, 'user_123');`})]}),ye("div",{className:"space-y-3",children:[x("h2",{className:"font-bold text-2xl",children:"Track + analyze"}),x(Dt,{language:"typescript",code:`import { ExperimentTracker } from '@contractspec/lib.growth/tracker';
|
|
589
893
|
import { StatsEngine } from '@contractspec/lib.growth/stats';
|
|
590
894
|
|
|
591
895
|
const tracker = new ExperimentTracker(new InMemoryTrackerStore());
|
|
@@ -601,11 +905,11 @@ await tracker.recordSample({
|
|
|
601
905
|
const stats = new StatsEngine().summarize(
|
|
602
906
|
await tracker.getSamples(assignment.experimentKey, 'demo_booked'),
|
|
603
907
|
'demo_booked'
|
|
604
|
-
);`})]}),
|
|
908
|
+
);`})]}),ye("div",{className:"flex items-center gap-4 pt-4",children:[x(Mt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),ye(Mt,{href:"/docs/libraries/analytics",className:"btn-primary",children:["Next: Analytics ",x(ho,{size:16})]})]})]})}import{CodeBlock as Et,InstallCommand as fo}from"@contractspec/lib.design-system";import Bt from"@contractspec/lib.ui-link";import{ChevronRight as bo}from"lucide-react";import{jsx as Z,jsxs as re}from"react/jsx-runtime";function vo(){return re("div",{className:"space-y-8",children:[re("div",{className:"space-y-4",children:[Z("h1",{className:"font-bold text-4xl",children:"Multi-Tenancy Library"}),re("p",{className:"text-lg text-muted-foreground",children:["The ",Z("code",{children:"@contractspec/lib.multi-tenancy"})," library provides the core building blocks for secure SaaS applications."]})]}),re("div",{className:"space-y-4",children:[Z("h2",{className:"font-bold text-2xl",children:"Installation"}),Z(fo,{package:"@contractspec/lib.multi-tenancy"})]}),re("div",{className:"space-y-4",children:[Z("h2",{className:"font-bold text-2xl",children:"Prisma RLS Middleware"}),re("p",{className:"text-muted-foreground",children:["Automatically injects ",Z("code",{children:"tenantId"})," into all queries."]}),Z(Et,{language:"typescript",code:`import { createRlsMiddleware } from '@contractspec/lib.multi-tenancy/rls';
|
|
605
909
|
import { prisma } from './db';
|
|
606
910
|
import { getTenantId } from './context';
|
|
607
911
|
|
|
608
|
-
prisma.$use(createRlsMiddleware(() => getTenantId()));`})]}),
|
|
912
|
+
prisma.$use(createRlsMiddleware(() => getTenantId()));`})]}),re("div",{className:"space-y-4",children:[Z("h2",{className:"font-bold text-2xl",children:"Provisioning Service"}),Z("p",{className:"text-muted-foreground",children:"Automates the creation of new tenants, including database setup and default user creation."}),Z(Et,{language:"typescript",code:`import { TenantProvisioningService } from '@contractspec/lib.multi-tenancy/provisioning';
|
|
609
913
|
|
|
610
914
|
const service = new TenantProvisioningService({ db: prisma });
|
|
611
915
|
await service.provision({
|
|
@@ -613,20 +917,20 @@ await service.provision({
|
|
|
613
917
|
name: 'Acme Corp',
|
|
614
918
|
slug: 'acme',
|
|
615
919
|
ownerEmail: 'admin@acme.com'
|
|
616
|
-
});`})]}),
|
|
920
|
+
});`})]}),re("div",{className:"flex items-center gap-4 pt-4",children:[Z(Bt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),re(Bt,{href:"/docs/libraries/progressive-delivery",className:"btn-primary",children:["Next: Progressive Delivery ",Z(bo,{size:16})]})]})]})}import{CodeBlock as Be,InstallCommand as yo}from"@contractspec/lib.design-system";import Ut from"@contractspec/lib.ui-link";import{ChevronRight as No}from"lucide-react";import{jsx as P,jsxs as j}from"react/jsx-runtime";function wo(){return j("div",{className:"space-y-8",children:[j("div",{className:"space-y-4",children:[P("h1",{className:"font-bold text-4xl",children:"Observability Library"}),j("p",{className:"text-lg text-muted-foreground",children:["The ",P("code",{children:"@contractspec/lib.observability"})," library provides a thin wrapper around OpenTelemetry to simplify instrumentation."]})]}),j("div",{className:"space-y-4",children:[P("h2",{className:"font-bold text-2xl",children:"Installation"}),P(yo,{package:"@contractspec/lib.observability"})]}),j("div",{className:"space-y-4",children:[P("h2",{className:"font-bold text-2xl",children:"Tracing"}),P(Be,{language:"typescript",code:`import { traceAsync, traceSync } from '@contractspec/lib.observability/tracing';
|
|
617
921
|
|
|
618
922
|
await traceAsync('process_order', async (span) => {
|
|
619
923
|
span.setAttribute('order_id', order.id);
|
|
620
924
|
await db.save(order);
|
|
621
|
-
});`})]}),
|
|
925
|
+
});`})]}),j("div",{className:"space-y-4",children:[P("h2",{className:"font-bold text-2xl",children:"Metrics"}),P(Be,{language:"typescript",code:`import { createCounter, createHistogram } from '@contractspec/lib.observability/metrics';
|
|
622
926
|
|
|
623
927
|
const ordersCounter = createCounter('orders_total');
|
|
624
928
|
const latencyHistogram = createHistogram('request_duration_seconds');
|
|
625
929
|
|
|
626
930
|
ordersCounter.add(1, { status: 'success' });
|
|
627
|
-
latencyHistogram.record(0.123);`})]}),
|
|
931
|
+
latencyHistogram.record(0.123);`})]}),j("div",{className:"space-y-4",children:[P("h2",{className:"font-bold text-2xl",children:"Middleware"}),P("p",{className:"text-muted-foreground",children:"Automatically instrument your HTTP handlers:"}),P(Be,{language:"typescript",code:`import { createTracingMiddleware } from '@contractspec/lib.observability/tracing/middleware';
|
|
628
932
|
|
|
629
|
-
app.use(createTracingMiddleware());`})]}),
|
|
933
|
+
app.use(createTracingMiddleware());`})]}),j("div",{className:"space-y-4",children:[P("h2",{className:"font-bold text-2xl",children:"Anomaly Detection"}),P("p",{className:"text-muted-foreground text-sm",children:"Includes baseline calculation and anomaly detection helpers for auto-rollback without writing custom math."}),P(Be,{language:"typescript",code:`import { AnomalyDetector, RootCauseAnalyzer, AlertManager } from '@contractspec/lib.observability';
|
|
630
934
|
|
|
631
935
|
const detector = new AnomalyDetector({ errorRateDelta: 0.4 });
|
|
632
936
|
const analyzer = new RootCauseAnalyzer();
|
|
@@ -636,7 +940,7 @@ const signals = detector.evaluate(point);
|
|
|
636
940
|
signals.forEach((signal) => {
|
|
637
941
|
const analysis = analyzer.analyze(signal, recentDeployments);
|
|
638
942
|
alertManager.notify(signal, analysis);
|
|
639
|
-
});`})]}),
|
|
943
|
+
});`})]}),j("div",{className:"flex items-center gap-4 pt-4",children:[P(Ut,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),j(Ut,{href:"/docs/libraries/slo",className:"btn-primary",children:["Next: SLO ",P(No,{size:16})]})]})]})}import{CodeBlock as Ke,InstallCommand as ko}from"@contractspec/lib.design-system";import Wt from"@contractspec/lib.ui-link";import{ChevronRight as So}from"lucide-react";import{jsx as W,jsxs as fe}from"react/jsx-runtime";function Ro(){return fe("div",{className:"space-y-8",children:[fe("div",{className:"space-y-4",children:[W("h1",{className:"font-bold text-4xl",children:"Overlay Engine"}),W("p",{className:"text-lg text-muted-foreground",children:"`@contractspec/lib.overlay-engine` keeps OverlaySpecs typed, signed, and auditable across tenants, roles, users, and devices."})]}),fe("div",{className:"space-y-4",children:[W("h2",{className:"font-bold text-2xl",children:"Installation"}),W(ko,{package:"@contractspec/lib.overlay-engine"})]}),fe("div",{className:"space-y-4",children:[W("h2",{className:"font-bold text-2xl",children:"Define + Sign"}),W(Ke,{language:"typescript",code:`import { defineOverlay } from '@contractspec/lib.overlay-engine/spec';
|
|
640
944
|
import { signOverlay } from '@contractspec/lib.overlay-engine/signer';
|
|
641
945
|
|
|
642
946
|
const overlay = defineOverlay({
|
|
@@ -646,7 +950,7 @@ const overlay = defineOverlay({
|
|
|
646
950
|
modifications: [{ type: 'hideField', field: 'internalNotes' }],
|
|
647
951
|
});
|
|
648
952
|
|
|
649
|
-
const signed = await signOverlay(overlay, privateKeyPem);`})]}),
|
|
953
|
+
const signed = await signOverlay(overlay, privateKeyPem);`})]}),fe("div",{className:"space-y-4",children:[W("h2",{className:"font-bold text-2xl",children:"Runtime"}),W("p",{className:"text-muted-foreground",children:"`OverlayRegistry` stores signed overlays with specificity scoring. `OverlayEngine` merges modifications and emits audit events."}),W(Ke,{language:"typescript",code:`const registry = new OverlayRegistry();
|
|
650
954
|
registry.register(signed);
|
|
651
955
|
|
|
652
956
|
const engine = new OverlayEngine({
|
|
@@ -658,13 +962,61 @@ const result = engine.apply({
|
|
|
658
962
|
target: { fields },
|
|
659
963
|
capability: 'billing.createOrder',
|
|
660
964
|
tenantId: 'acme',
|
|
661
|
-
});`})]}),
|
|
965
|
+
});`})]}),fe("div",{className:"space-y-4",children:[W("h2",{className:"font-bold text-2xl",children:"React Hooks"}),W("p",{className:"text-muted-foreground",children:"Render overlays in React/React Native via `useOverlay`."}),W(Ke,{language:"typescript",code:`import { useOverlay } from '@contractspec/lib.overlay-engine/react';
|
|
662
966
|
|
|
663
967
|
const { target } = useOverlay(engine, {
|
|
664
968
|
target: { fields },
|
|
665
969
|
capability: 'billing.createOrder',
|
|
666
970
|
tenantId: 'acme',
|
|
667
|
-
});`})]}),
|
|
971
|
+
});`})]}),fe("div",{className:"flex items-center gap-4 pt-4",children:[W(Wt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),fe(Wt,{href:"/docs/libraries/workflow-composer",className:"btn-primary",children:["Next: Workflow Composer ",W(So,{size:16})]})]})]})}import Co from"@contractspec/lib.ui-link";import{ChevronRight as To}from"lucide-react";import{jsx as F,jsxs as be}from"react/jsx-runtime";var Ao=[{title:"Contract and schema foundation",body:"Use these packages to define explicit contracts, schemas, and generated artifacts without inventing a new platform-specific language.",items:[{title:"@contractspec/lib.contracts-spec",description:"Define operations, events, policies, and generated surfaces in TypeScript.",href:"/docs/libraries/contracts"},{title:"@contractspec/lib.schema",description:"Share type-safe schema definitions across validation, clients, and runtime adapters.",href:"/docs/libraries/schema"}]},{title:"Runtime and surface libraries",body:"These packages execute the contract model across UI, data, observability, workflows, and generated runtime behavior.",items:[{title:"@contractspec/lib.runtime",description:"Run typed capability surfaces, execute policies, and connect runtime adapters.",href:"/docs/libraries/runtime"},{title:"@contractspec/lib.translation-runtime",description:"Resolve ContractSpec TranslationSpec catalogs with ICU formatting, SSR snapshots, BCP 47 locales, overrides, and optional i18next projection.",href:"/docs/libraries/translation-runtime"},{title:"@contractspec/lib.ui-kit",description:"Render shared surfaces across web and React Native without forking the contract layer.",href:"/docs/libraries/ui-kit"},{title:"@contractspec/lib.ui-kit-web",description:"Use the raw web primitive layer directly when you want the browser table, accessibility, and interaction model without the design-system shell.",href:"/docs/libraries/ui-kit-web"},{title:"@contractspec/lib.design-system",description:"Build higher-level product surfaces, actionable object references, adaptive panels, and documented marketing/docs primitives on top of the web and native UI packages.",href:"/docs/libraries/design-system"},{title:"Application shell",description:"Adopt the shared sidebar, topbar, command search, notifications, mobile navigation, and PageOutline patterns for product apps.",href:"/docs/libraries/application-shell"},{title:"Cross-platform UI",description:"See how the presentation runtimes, ui-kit-web, ui-kit, and design-system stay compatible across React and React Native.",href:"/docs/libraries/cross-platform-ui"},{title:"@contractspec/lib.data-views",description:"Generate and render list/detail style surfaces that stay aligned with data contracts.",href:"/docs/libraries/data-views"}]},{title:"Operator and system packages",body:"These packages matter once the system is live and you need governance, resilience, and observability.",items:[{title:"@contractspec/lib.observability",description:"Trace, log, and measure contract execution using the same system boundaries.",href:"/docs/libraries/observability"},{title:"@contractspec/lib.resilience",description:"Add circuit breakers, retries, and failure controls without hiding the integration model.",href:"/docs/libraries/resilience"},{title:"@contractspec/lib.multi-tenancy",description:"Keep tenant-specific config, policy, and surface resolution explicit.",href:"/docs/libraries/multi-tenancy"},{title:"@contractspec/lib.workflow-composer",description:"Compose and extend workflows without smearing orchestration concerns across apps.",href:"/docs/libraries/workflow-composer"}]}];function Lo(){return be("div",{className:"space-y-10",children:[be("div",{className:"space-y-3",children:[F("p",{className:"editorial-kicker",children:"Build"}),F("h1",{className:"font-serif text-4xl tracking-[-0.04em] md:text-5xl",children:"The OSS foundation is a library system, not a closed platform."}),F("p",{className:"max-w-3xl text-lg text-muted-foreground leading-8",children:"ContractSpec is assembled from libraries that remain useful on their own and stronger together. Start with the contract and schema foundation, then add runtime, UI, integration, and operator packages as your system grows."})]}),be("div",{className:"editorial-proof-strip",children:[be("div",{className:"editorial-stat",children:[F("span",{className:"editorial-label",children:"Layering rule"}),F("span",{className:"editorial-stat-value",children:"libs \u2192 bundles \u2192 apps"})]}),F("p",{className:"max-w-2xl text-muted-foreground text-sm leading-7",children:"Keep reusable behavior in libraries, compose it into bundle-level surfaces, and reserve app packages for concrete delivery shells."})]}),F("div",{className:"space-y-6",children:Ao.map((a)=>be("section",{className:"editorial-panel space-y-5",children:[be("div",{className:"space-y-2",children:[F("h2",{className:"font-serif text-3xl tracking-[-0.03em]",children:a.title}),F("p",{className:"text-muted-foreground text-sm leading-7",children:a.body})]}),F("div",{className:"grid gap-4 md:grid-cols-2",children:a.items.map((A)=>be(Co,{href:A.href,className:"rounded-[24px] border border-border/75 bg-background/70 p-5 transition-colors hover:border-[color:rgb(162_79_42_/_0.45)]",children:[F("h3",{className:"font-semibold text-lg",children:A.title}),F("p",{className:"mt-2 text-muted-foreground text-sm leading-7",children:A.description}),be("div",{className:"mt-3 flex items-center gap-2 text-[color:var(--rust)] text-sm",children:["Learn more ",F(To,{size:14})]})]},A.title))})]},a.title))})]})}import{CodeBlock as Le,InstallCommand as Io}from"@contractspec/lib.design-system";import{HStack as Po,VStack as ne}from"@contractspec/lib.design-system/layout";import{Code as zt,H1 as Oo,H2 as Ne,P as we,Text as Qe}from"@contractspec/lib.design-system/typography";import Je from"@contractspec/lib.ui-link";import{ChevronRight as Do}from"lucide-react";import{jsx as u,jsxs as _}from"react/jsx-runtime";var Mo=`import { DataViewRenderer } from '@contractspec/lib.design-system';
|
|
972
|
+
import { resolveDataViewPreferences } from '@contractspec/lib.personalization/data-view-preferences';
|
|
973
|
+
|
|
974
|
+
const resolved = resolveDataViewPreferences({
|
|
975
|
+
spec: AccountsDataView,
|
|
976
|
+
preferences: profile.canonical,
|
|
977
|
+
insights,
|
|
978
|
+
record: savedAccountViewPreference,
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
return (
|
|
982
|
+
<DataViewRenderer
|
|
983
|
+
spec={AccountsDataView}
|
|
984
|
+
items={accounts}
|
|
985
|
+
defaultViewMode={resolved.viewMode}
|
|
986
|
+
defaultDensity={resolved.density}
|
|
987
|
+
defaultDataDepth={resolved.dataDepth}
|
|
988
|
+
pagination={{
|
|
989
|
+
page,
|
|
990
|
+
pageSize: resolved.pageSize ?? 25,
|
|
991
|
+
total,
|
|
992
|
+
}}
|
|
993
|
+
/>
|
|
994
|
+
);`,Eo=`tracker.trackDataViewInteraction({
|
|
995
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
996
|
+
dataViewVersion: AccountsDataView.meta.version,
|
|
997
|
+
action: 'view_mode_changed',
|
|
998
|
+
viewMode: 'grid',
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
tracker.trackDataViewInteraction({
|
|
1002
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
1003
|
+
action: 'data_depth_changed',
|
|
1004
|
+
dataDepth: 'detailed',
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
tracker.trackDataViewInteraction({
|
|
1008
|
+
dataViewKey: AccountsDataView.meta.key,
|
|
1009
|
+
action: 'filter_changed',
|
|
1010
|
+
filterKey: 'status',
|
|
1011
|
+
});`,Bo=`Add DataView personalization for <screen>.
|
|
1012
|
+
|
|
1013
|
+
Acceptance criteria:
|
|
1014
|
+
- Resolve viewMode, density, dataDepth, and pageSize with resolveDataViewPreferences.
|
|
1015
|
+
- Apply resolved values to DataViewRenderer as default or controlled props.
|
|
1016
|
+
- Track opened, view_mode_changed, density_changed, data_depth_changed, search_changed, filter_changed, sort_changed, and page_changed actions with trackDataViewInteraction.
|
|
1017
|
+
- Persist only the dimensions allowed by view.collection.personalization.persist.
|
|
1018
|
+
- Ignore behavior-derived modes that are not allowed by view.collection.viewModes.allowedModes.
|
|
1019
|
+
- Do not import React or design-system code into @contractspec/lib.personalization helpers.`;function Uo(){return _(ne,{className:"space-y-8",children:[_(ne,{className:"space-y-4",children:[u(Oo,{className:"font-bold text-4xl",children:"@contractspec/lib.personalization"}),u(we,{className:"text-lg text-muted-foreground",children:"Track field/feature/workflow usage, analyze drop-offs, and convert insights into OverlaySpecs or workflow tweaks."})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"Installation"}),u(Io,{package:"@contractspec/lib.personalization"})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"Tracker"}),u(we,{className:"text-muted-foreground",children:"Buffer events per tenant/user and emit OpenTelemetry counters automatically."}),u(Le,{language:"typescript",code:`import { createBehaviorTracker } from '@contractspec/lib.personalization';
|
|
668
1020
|
|
|
669
1021
|
const tracker = createBehaviorTracker({
|
|
670
1022
|
store,
|
|
@@ -672,17 +1024,23 @@ const tracker = createBehaviorTracker({
|
|
|
672
1024
|
});
|
|
673
1025
|
|
|
674
1026
|
tracker.trackFieldAccess({ operation: 'billing.createOrder', field: 'items' });
|
|
675
|
-
tracker.trackWorkflowStep({ workflow: 'invoice', step: 'review', status: 'entered' });`})]}),ne("
|
|
1027
|
+
tracker.trackWorkflowStep({ workflow: 'invoice', step: 'review', status: 'entered' });`})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"DataView Preferences"}),_(we,{className:"text-muted-foreground",children:["Use ",u(zt,{children:"resolveDataViewPreferences"})," when a collection DataView should honor a user's preferred list/grid/table mode, compact or comfortable density, data depth, and page size. The helper returns plain values that can be passed into the renderer without coupling the design-system package to personalization. Start from the"," ",u(Je,{href:"/docs/libraries/data-views",className:"text-[color:var(--rust)] underline underline-offset-4",children:u(Qe,{children:"DataViews runtime guide"})})," ","when you need the contract and renderer shape."]}),u(Le,{language:"tsx",code:Mo})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"DataView Interaction Events"}),_(we,{className:"text-muted-foreground",children:["Track ",u(zt,{children:"data_view_interaction"})," events for view mode, density, data depth, search, filters, sorting, and pagination. The in-memory store summarizes those events, and the analyzer can derive a scoped preferred collection mode from valid interaction counts."]}),u(Le,{language:"typescript",code:Eo})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"Analyzer"}),u(we,{className:"text-muted-foreground",children:"Summarize events and highlight unused UI, frequent fields, and workflow bottlenecks."}),u(Le,{language:"typescript",code:`import { BehaviorAnalyzer } from '@contractspec/lib.personalization/analyzer';
|
|
676
1028
|
|
|
677
1029
|
const analyzer = new BehaviorAnalyzer(store);
|
|
678
1030
|
const insights = await analyzer.analyze({ tenantId: 'acme', userId: 'ops-42' });
|
|
679
|
-
// {
|
|
1031
|
+
// {
|
|
1032
|
+
// unusedFields: ['internalNotes'],
|
|
1033
|
+
// workflowBottlenecks: [...],
|
|
1034
|
+
// dataViewPreferences: {
|
|
1035
|
+
// 'crm.accounts': { preferredViewMode: 'grid' }
|
|
1036
|
+
// }
|
|
1037
|
+
// }`})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"Adapter"}),u(we,{className:"text-muted-foreground",children:"Convert insights into overlays or workflow extension hints."}),u(Le,{language:"typescript",code:`import { insightsToOverlaySuggestion } from '@contractspec/lib.personalization/adapter';
|
|
680
1038
|
|
|
681
1039
|
const overlay = insightsToOverlaySuggestion(insights, {
|
|
682
1040
|
overlayId: 'acme-order-form',
|
|
683
1041
|
tenantId: 'acme',
|
|
684
1042
|
capability: 'billing.createOrder',
|
|
685
|
-
});`})]}),ne("
|
|
1043
|
+
});`})]}),_(ne,{className:"space-y-4",children:[u(Ne,{className:"font-bold text-2xl",children:"Agent Prompt"}),u(we,{className:"text-muted-foreground",children:"Use this when asking an agent to wire DataView preferences while preserving the personalization/design-system boundary."}),u(Le,{language:"markdown",code:Bo})]}),_(Po,{className:"items-center gap-4 pt-4",children:[u(Je,{href:"/docs/libraries",className:"btn-ghost",children:u(Qe,{children:"Back to Libraries"})}),_(Je,{href:"/docs/libraries/overlay-engine",className:"btn-primary",children:[u(Qe,{children:"Next: Overlay Engine"})," ",u(Do,{size:16})]})]})]})}import{CodeBlock as Gt,InstallCommand as Wo}from"@contractspec/lib.design-system";import Ft from"@contractspec/lib.ui-link";import{ChevronRight as zo}from"lucide-react";import{jsx as D,jsxs as V}from"react/jsx-runtime";function Go(){return V("div",{className:"space-y-8",children:[V("div",{className:"space-y-4",children:[D("h1",{className:"font-bold text-4xl",children:"Progressive Delivery Library"}),V("p",{className:"text-lg text-muted-foreground",children:["The ",D("code",{children:"@contractspec/lib.progressive-delivery"})," package helps you ship new specs with confidence: canary + blue-green strategies, metric guardrails, and rollback hooks in one place."]})]}),V("div",{className:"space-y-4",children:[D("h2",{className:"font-bold text-2xl",children:"Installation"}),D(Wo,{package:"@contractspec/lib.progressive-delivery"})]}),V("div",{className:"space-y-4",children:[D("h2",{className:"font-bold text-2xl",children:"Define a Strategy"}),D(Gt,{language:"typescript",code:`import { DeploymentCoordinator, createDefaultCanaryController, TrafficShifter, RollbackManager } from '@contractspec/lib.progressive-delivery';
|
|
686
1044
|
|
|
687
1045
|
const strategy = {
|
|
688
1046
|
target: { name: 'billing.createInvoice', version: 7 },
|
|
@@ -692,7 +1050,7 @@ const strategy = {
|
|
|
692
1050
|
latencyP99: 500,
|
|
693
1051
|
latencyP95: 250,
|
|
694
1052
|
},
|
|
695
|
-
};`})]}),
|
|
1053
|
+
};`})]}),V("div",{className:"space-y-4",children:[D("h2",{className:"font-bold text-2xl",children:"Run the Coordinator"}),D(Gt,{language:"typescript",code:`const eventBus = new DeploymentEventBus();
|
|
696
1054
|
const controller = createDefaultCanaryController(strategy, fetchMetrics, eventBus);
|
|
697
1055
|
const coordinator = new DeploymentCoordinator({
|
|
698
1056
|
strategy,
|
|
@@ -703,7 +1061,7 @@ const coordinator = new DeploymentCoordinator({
|
|
|
703
1061
|
eventBus,
|
|
704
1062
|
});
|
|
705
1063
|
|
|
706
|
-
const result = await coordinator.run();`}),
|
|
1064
|
+
const result = await coordinator.run();`}),V("p",{className:"text-muted-foreground text-sm",children:["The coordinator emits ",D("code",{children:"stage_started"}),","," ",D("code",{children:"stage_failed"}),", and ",D("code",{children:"rolled_back"})," events, making it easy to power dashboards or alerting workflows."]})]}),V("div",{className:"space-y-4",children:[D("h2",{className:"font-bold text-2xl",children:"Blue-Green Swap"}),V("p",{className:"text-muted-foreground text-sm",children:["Switch to ",D("code",{children:"mode: 'blue-green'"})," to warm up the new stack in parallel and cut over once smoke tests pass. The same guardrails apply before the final swap."]})]}),V("div",{className:"flex items-center gap-4 pt-4",children:[D(Ft,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),V(Ft,{href:"/docs/libraries/resilience",className:"btn-primary",children:["Next: Resilience ",D(zo,{size:16})]})]})]})}import{CodeBlock as Ze,InstallCommand as Fo}from"@contractspec/lib.design-system";import _t from"@contractspec/lib.ui-link";import{ChevronRight as _o}from"lucide-react";import{jsx as M,jsxs as ce}from"react/jsx-runtime";function qo(){return ce("div",{className:"space-y-8",children:[ce("div",{className:"space-y-4",children:[M("h1",{className:"font-bold text-4xl",children:"Resilience Library"}),ce("p",{className:"text-lg text-muted-foreground",children:["The ",M("code",{children:"@contractspec/lib.resilience"})," library provides primitives to handle failures gracefully."]})]}),ce("div",{className:"space-y-4",children:[M("h2",{className:"font-bold text-2xl",children:"Installation"}),M(Fo,{package:"@contractspec/lib.resilience"})]}),ce("div",{className:"space-y-4",children:[M("h2",{className:"font-bold text-2xl",children:"Circuit Breaker"}),M("p",{className:"text-muted-foreground",children:"Prevent cascading failures by stopping calls to a failing dependency."}),M(Ze,{language:"typescript",code:`import { CircuitBreaker } from '@contractspec/lib.resilience/circuit-breaker';
|
|
707
1065
|
|
|
708
1066
|
const breaker = new CircuitBreaker({
|
|
709
1067
|
failureThreshold: 5,
|
|
@@ -712,19 +1070,19 @@ const breaker = new CircuitBreaker({
|
|
|
712
1070
|
|
|
713
1071
|
const result = await breaker.execute(async () => {
|
|
714
1072
|
return await fetch('https://api.stripe.com/v1/charges');
|
|
715
|
-
});`})]}),
|
|
1073
|
+
});`})]}),ce("div",{className:"space-y-4",children:[M("h2",{className:"font-bold text-2xl",children:"Retry"}),M("p",{className:"text-muted-foreground",children:"Automatically retry transient failures with exponential backoff."}),M(Ze,{language:"typescript",code:`import { retry } from '@contractspec/lib.resilience/retry';
|
|
716
1074
|
|
|
717
1075
|
const result = await retry(
|
|
718
1076
|
async () => fetchUser(id),
|
|
719
1077
|
3, // retries
|
|
720
1078
|
1000, // initial delay
|
|
721
1079
|
true // backoff
|
|
722
|
-
);`})]}),
|
|
1080
|
+
);`})]}),ce("div",{className:"space-y-4",children:[M("h2",{className:"font-bold text-2xl",children:"Timeout & Fallback"}),M("p",{className:"text-muted-foreground",children:"Set hard limits on execution time and provide default values on failure."}),M(Ze,{language:"typescript",code:`import { timeout, fallback } from '@contractspec/lib.resilience';
|
|
723
1081
|
|
|
724
1082
|
const result = await fallback(
|
|
725
1083
|
() => timeout(slowOperation, 5000),
|
|
726
1084
|
defaultValue
|
|
727
|
-
);`})]}),
|
|
1085
|
+
);`})]}),ce("div",{className:"flex items-center gap-4 pt-4",children:[M(_t,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),ce(_t,{href:"/docs/libraries/testing",className:"btn-primary",children:["Next: Testing ",M(_o,{size:16})]})]})]})}import{CodeBlock as Ho,InstallCommand as Ko}from"@contractspec/lib.design-system";import Ve from"@contractspec/lib.ui-link";import{ChevronRight as Qo}from"lucide-react";import{jsx as f,jsxs as v}from"react/jsx-runtime";function Jo(){return v("div",{className:"space-y-8",children:[v("div",{className:"space-y-4",children:[f("h1",{className:"font-bold text-4xl",children:"Runtime Libraries"}),f("p",{className:"text-muted-foreground",children:"The presentation runtime libraries provide the engine for rendering ContractSpec-defined UIs. They handle state management, validation, step navigation, and component rendering for Workflows and DataViews."})]}),v("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Installation"}),f(Ko,{package:"@contractspec/lib.presentation-runtime-react"})]}),v("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Libraries"}),v("div",{className:"space-y-6",children:[v("div",{className:"card-subtle p-6",children:[f("h3",{className:"font-bold text-lg",children:"@contractspec/lib.presentation-runtime-core"}),v("p",{className:"mt-2 text-muted-foreground text-sm",children:[f("strong",{children:"Framework-Agnostic Core"}),". Contains the state machines, validation logic, and navigation rules for workflows. Can be used to build renderers for any platform (Vue, Svelte, CLI)."]})]}),v("div",{className:"card-subtle p-6",children:[f("h3",{className:"font-bold text-lg",children:"@contractspec/lib.presentation-runtime-react"}),v("p",{className:"mt-2 text-muted-foreground text-sm",children:[f("strong",{children:"React Bindings"}),". Hooks (`useWorkflow`) and components (`WorkflowStepper`, `WorkflowStepRenderer`) for React Web applications. Integrates with `ui-kit-web`."]})]}),v("div",{className:"card-subtle p-6",children:[f("h3",{className:"font-bold text-lg",children:"@contractspec/lib.presentation-runtime-react-native"}),v("p",{className:"mt-2 text-muted-foreground text-sm",children:[f("strong",{children:"React Native Bindings"}),". Optimized for mobile experiences. Handles native navigation integration and uses universal components from `ui-kit`."]})]})]})]}),v("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Example: React Workflow"}),f(Ho,{language:"tsx",code:`import { useWorkflow, WorkflowStepRenderer } from '@contractspec/lib.presentation-runtime-react';
|
|
728
1086
|
import { OnboardingFlow } from './specs/onboarding';
|
|
729
1087
|
|
|
730
1088
|
export function OnboardingPage() {
|
|
@@ -764,7 +1122,7 @@ export function OnboardingPage() {
|
|
|
764
1122
|
</div>
|
|
765
1123
|
</div>
|
|
766
1124
|
);
|
|
767
|
-
}`})]}),
|
|
1125
|
+
}`})]}),v("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Architecture"}),f("p",{className:"text-muted-foreground",children:'The runtime follows a "render-loop" pattern:'}),v("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[v("li",{children:[f("strong",{children:"Spec"}),": Defines the flow, fields, and validation rules."]}),v("li",{children:[f("strong",{children:"Core"}),": Tracks current step, data state, and validation errors."]}),v("li",{children:[f("strong",{children:"Renderer"}),": Maps spec fields to UI components (Input, Select, etc.)."]}),v("li",{children:[f("strong",{children:"User"}),": Interacts with components, updating core state."]}),v("li",{children:[f("strong",{children:"Policy"}),": (Optional) Re-evaluates visibility on every change."]})]})]}),v("div",{className:"card-subtle space-y-3 p-6",children:[f("h2",{className:"font-bold text-2xl",children:"Related reading"}),v("p",{className:"text-muted-foreground",children:["For the full React and React Native layering story across runtime, primitives, and composed components, read"," ",f(Ve,{href:"/docs/libraries/cross-platform-ui",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Cross-platform UI"}),"."]})]}),v("div",{className:"flex items-center gap-4 pt-4",children:[f(Ve,{href:"/docs/libraries/data-backend",className:"btn-ghost",children:"Previous: Data & Backend"}),v(Ve,{href:"/docs/libraries",className:"btn-primary",children:["Back to Libraries ",f(Qo,{size:16})]})]})]})}import{CodeBlock as qt,InstallCommand as Zo}from"@contractspec/lib.design-system";import Ht from"@contractspec/lib.ui-link";import{ChevronRight as Vo}from"lucide-react";import{jsx as r,jsxs as y}from"react/jsx-runtime";function Yo(){return y("div",{className:"space-y-8",children:[y("div",{className:"space-y-4",children:[r("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.schema"}),r("p",{className:"text-muted-foreground",children:"A small schema dictionary to describe operation I/O once and export to Zod (runtime validation), Pothos (GraphQL type refs), and JSON Schema."})]}),y("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Installation"}),r(Zo,{package:"@contractspec/lib.schema"})]}),y("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Core Exports"}),y("ul",{className:"space-y-2 text-muted-foreground",children:[y("li",{children:[r("code",{className:"rounded bg-background/50 px-2 py-1",children:"SchemaModel"}),": Compose fields into typed object models"]}),y("li",{children:[r("code",{className:"rounded bg-background/50 px-2 py-1",children:"ScalarTypeEnum"}),": Common scalar types (NonEmptyString, Email, DateTime, etc.)"]}),y("li",{children:[r("code",{className:"rounded bg-background/50 px-2 py-1",children:"defineEnum"}),": Create type-safe enums"]}),y("li",{children:[r("code",{className:"rounded bg-background/50 px-2 py-1",children:"FieldType"}),": Wrap scalars with Zod/GraphQL/JSON Schema"]})]})]}),y("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Example: Basic Schema"}),r(qt,{language:"typescript",code:`import { SchemaModel, ScalarTypeEnum } from '@contractspec/lib.schema';
|
|
768
1126
|
|
|
769
1127
|
export const CreateSpotInput = new SchemaModel({
|
|
770
1128
|
name: 'CreateSpotInput',
|
|
@@ -782,7 +1140,7 @@ const zodSchema = CreateSpotInput.getZod();
|
|
|
782
1140
|
const pothosName = CreateSpotInput.getPothosInput();
|
|
783
1141
|
|
|
784
1142
|
// Get JSON Schema
|
|
785
|
-
const jsonSchema = CreateSpotInput.getJsonSchema();`})]}),
|
|
1143
|
+
const jsonSchema = CreateSpotInput.getJsonSchema();`})]}),y("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Example: Enums"}),r(qt,{language:"typescript",code:`import { defineEnum, SchemaModel } from '@contractspec/lib.schema';
|
|
786
1144
|
|
|
787
1145
|
const Weekday = defineEnum('Weekday', [
|
|
788
1146
|
'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU',
|
|
@@ -797,19 +1155,19 @@ const RecurrenceRule = new SchemaModel({
|
|
|
797
1155
|
},
|
|
798
1156
|
byWeekday: { type: Weekday, isOptional: true, isArray: true },
|
|
799
1157
|
},
|
|
800
|
-
});`})]}),
|
|
1158
|
+
});`})]}),y("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Available Scalars"}),y("div",{className:"grid gap-4 md:grid-cols-2",children:[y("div",{className:"card-subtle p-4",children:[r("h3",{className:"mb-2 font-semibold",children:"Strings"}),y("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[r("li",{children:r("code",{children:"NonEmptyString()"})}),r("li",{children:r("code",{children:"Email()"})}),r("li",{children:r("code",{children:"PhoneNumber()"})}),r("li",{children:r("code",{children:"CountryCode()"})}),r("li",{children:r("code",{children:"Locale()"})}),r("li",{children:r("code",{children:"TimeZone()"})})]})]}),y("div",{className:"card-subtle p-4",children:[r("h3",{className:"mb-2 font-semibold",children:"Numbers"}),y("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[r("li",{children:r("code",{children:"PositiveNumber()"})}),r("li",{children:r("code",{children:"Latitude()"})}),r("li",{children:r("code",{children:"Longitude()"})})]})]}),y("div",{className:"card-subtle p-4",children:[r("h3",{className:"mb-2 font-semibold",children:"Dates & Times"}),y("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[r("li",{children:r("code",{children:"Date()"})}),r("li",{children:r("code",{children:"DateTime()"})})]})]}),y("div",{className:"card-subtle p-4",children:[r("h3",{className:"mb-2 font-semibold",children:"Generic"}),y("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[r("li",{children:r("code",{children:"String()"})}),r("li",{children:r("code",{children:"JSON()"})})]})]})]})]}),y("div",{className:"flex items-center gap-4 pt-4",children:[r(Ht,{href:"/docs/libraries/contracts",className:"btn-ghost",children:"Previous: Contracts"}),y(Ht,{href:"/docs/libraries/ui-kit",className:"btn-primary",children:["Next: UI Kit ",r(Vo,{size:16})]})]})]})}import{CodeBlock as Kt,InstallCommand as Xo}from"@contractspec/lib.design-system";import Qt from"@contractspec/lib.ui-link";import{ChevronRight as $o}from"lucide-react";import{jsx as q,jsxs as ee}from"react/jsx-runtime";function xo(){return ee("div",{className:"space-y-8",children:[ee("div",{className:"space-y-4",children:[q("h1",{className:"font-bold text-4xl",children:"SLO Library"}),ee("p",{className:"text-lg text-muted-foreground",children:[q("code",{children:"@contractspec/lib.slo"})," keeps service level objectives front and center\u2014declarative definitions, rolling snapshots, burn-rate math, and automated incidents."]})]}),ee("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Installation"}),q(Xo,{package:"@contractspec/lib.slo"})]}),ee("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Define Targets"}),q(Kt,{language:"typescript",code:`const definition: SLODefinition = {
|
|
801
1159
|
id: 'billing.createInvoice.availability',
|
|
802
1160
|
targetAvailability: 0.999,
|
|
803
1161
|
latencyP99TargetMs: 500,
|
|
804
1162
|
rollingWindowMs: 7 * 24 * 60 * 60 * 1000,
|
|
805
1163
|
alerts: { fastBurnThreshold: 14, slowBurnThreshold: 6 },
|
|
806
|
-
};`})]}),
|
|
1164
|
+
};`})]}),ee("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Monitor Burn Rate"}),q(Kt,{language:"typescript",code:`const monitor = new SLOMonitor({ definition, incidentManager });
|
|
807
1165
|
const { snapshot, burnRate } = monitor.recordWindow({
|
|
808
1166
|
good: 12500,
|
|
809
1167
|
bad: 3,
|
|
810
1168
|
latencyP99: 420,
|
|
811
1169
|
latencyP95: 210,
|
|
812
|
-
});`}),
|
|
1170
|
+
});`}),ee("p",{className:"text-muted-foreground text-sm",children:["When burn rate exceeds the configured thresholds the monitor calls your",q("code",{children:"IncidentManager"}),", providing the snapshot that triggered the alert."]})]}),ee("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"History & Reporting"}),q("p",{className:"text-muted-foreground text-sm",children:"`SLOTracker.getHistory()` returns the latest snapshots so dashboards can show trends without hitting a warehouse. Prisma models persist everything for long-term audits."})]}),ee("div",{className:"flex items-center gap-4 pt-4",children:[q(Qt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),ee(Qt,{href:"/docs/libraries/cost-tracking",className:"btn-primary",children:["Next: Cost Tracking ",q($o,{size:16})]})]})]})}import{CodeBlock as Jt,InstallCommand as jo}from"@contractspec/lib.design-system";import Zt from"@contractspec/lib.ui-link";import{ChevronRight as ei}from"lucide-react";import{jsx as E,jsxs as H}from"react/jsx-runtime";function ti(){return H("div",{className:"space-y-8",children:[H("div",{className:"space-y-4",children:[E("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.support-bot"}),E("p",{className:"text-lg text-muted-foreground",children:"Build AI-first support flows using drop-in classifiers, knowledge-grounded resolvers, and tone-aware responders\u2014all wired into the agent runner."})]}),H("div",{className:"space-y-4",children:[E("h2",{className:"font-bold text-2xl",children:"Installation"}),E(jo,{package:"@contractspec/lib.support-bot"})]}),H("div",{className:"space-y-3",children:[E("h2",{className:"font-bold text-2xl",children:"Wire the primitives"}),E(Jt,{language:"typescript",code:`import { TicketClassifier, TicketResolver, AutoResponder } from '@contractspec/lib.support-bot';
|
|
813
1171
|
|
|
814
1172
|
const classifier = new TicketClassifier();
|
|
815
1173
|
const resolver = new TicketResolver({ knowledge });
|
|
@@ -817,10 +1175,10 @@ const responder = new AutoResponder();
|
|
|
817
1175
|
|
|
818
1176
|
const classification = await classifier.classify(ticket);
|
|
819
1177
|
const resolution = await resolver.resolve(ticket);
|
|
820
|
-
const draft = await responder.draft(ticket, resolution, classification);`})]}),
|
|
1178
|
+
const draft = await responder.draft(ticket, resolution, classification);`})]}),H("div",{className:"space-y-3",children:[E("h2",{className:"font-bold text-2xl",children:"Expose as agent tools"}),E(Jt,{language:"typescript",code:`import { createSupportTools } from '@contractspec/lib.support-bot/bot';
|
|
821
1179
|
|
|
822
1180
|
const tools = createSupportTools({ resolver, classifier, responder });
|
|
823
|
-
// Pass these tools into your host runtime or agent adapter.`})]}),
|
|
1181
|
+
// Pass these tools into your host runtime or agent adapter.`})]}),H("div",{className:"space-y-3",children:[E("h2",{className:"font-bold text-2xl",children:"Included modules"}),H("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[H("li",{children:[E("strong",{children:"TicketClassifier"}),": heuristics + optional LLM validation for category/priority."]}),H("li",{children:[E("strong",{children:"TicketResolver"}),": RAG resolver that can plug into any knowledge retriever."]}),H("li",{children:[E("strong",{children:"AutoResponder"}),": generates drafts, citations, and tone-aware copy."]}),H("li",{children:[E("strong",{children:"SupportFeedbackLoop"}),": track auto-resolution rates and sentiment trends."]})]})]}),H("div",{className:"flex items-center gap-4 pt-4",children:[E(Zt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),H(Zt,{href:"/docs/libraries/growth",className:"btn-primary",children:["Next: Growth ",E(ei,{size:16})]})]})]})}import{CodeBlock as Ye,InstallCommand as ai}from"@contractspec/lib.design-system";import Vt from"@contractspec/lib.ui-link";import{ChevronRight as oi}from"lucide-react";import{jsx as B,jsxs as se}from"react/jsx-runtime";function ii(){return se("div",{className:"space-y-8",children:[se("div",{className:"space-y-4",children:[B("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.testing"}),B("p",{className:"text-lg text-muted-foreground",children:"Golden tests ensure new rollouts behave exactly like the traffic that inspired them. Record requests in production, replay them locally, and ship with confidence."})]}),se("div",{className:"space-y-4",children:[B("h2",{className:"font-bold text-2xl",children:"Installation"}),B(ai,{package:"@contractspec/lib.testing"})]}),se("div",{className:"space-y-3",children:[B("h2",{className:"font-bold text-2xl",children:"Record traffic"}),B(Ye,{language:"typescript",code:`import {
|
|
824
1182
|
TrafficRecorder,
|
|
825
1183
|
InMemoryTrafficStore,
|
|
826
1184
|
} from '@contractspec/lib.testing/recorder';
|
|
@@ -840,7 +1198,7 @@ await recorder.record({
|
|
|
840
1198
|
output,
|
|
841
1199
|
success: true,
|
|
842
1200
|
tenantId: ctx.organizationId ?? undefined,
|
|
843
|
-
});`})]}),
|
|
1201
|
+
});`})]}),se("div",{className:"space-y-3",children:[B("h2",{className:"font-bold text-2xl",children:"Generate suites"}),B(Ye,{language:"typescript",code:`import { GoldenTestGenerator } from '@contractspec/lib.testing';
|
|
844
1202
|
|
|
845
1203
|
const generator = new GoldenTestGenerator();
|
|
846
1204
|
const code = generator.generate(snapshots, {
|
|
@@ -848,7 +1206,48 @@ const code = generator.generate(snapshots, {
|
|
|
848
1206
|
runnerImport: './tests/run-operation',
|
|
849
1207
|
runnerFunction: 'runOrdersCommand',
|
|
850
1208
|
framework: 'vitest',
|
|
851
|
-
});`})]}),
|
|
1209
|
+
});`})]}),se("div",{className:"space-y-3",children:[B("h2",{className:"font-bold text-2xl",children:"CLI workflow"}),B(Ye,{language:"bash",code:"contractspec test generate \\\n --operation orders.create \\\n --output tests/orders.create.golden.test.ts \\\n --runner-import ./tests/run-operation \\\n --runner-fn runOrdersCommand \\\n --from-production \\\n --days 7 \\\n --sample-rate 0.05"})]}),B("div",{className:"grid gap-4 md:grid-cols-2",children:[{title:"Framework agnostic",description:"Vitest by default, Jest via `generateJestSuite`, or call `runGoldenTests` manually inside CI."},{title:"Sanitize & sample",description:"Scrub payloads before persistence and control sample rates per operation to stay within compliance limits."}].map((a)=>se("div",{className:"card-subtle space-y-2 p-4",children:[B("h3",{className:"font-semibold text-lg",children:a.title}),B("p",{className:"text-muted-foreground text-sm",children:a.description})]},a.title))}),se("div",{className:"flex items-center gap-4 pt-4",children:[B(Vt,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),se(Vt,{href:"/docs/libraries/resilience",className:"btn-primary",children:["Next: Resilience ",B(oi,{size:16})]})]})]})}var Yt=["@contractspec/lib.contracts-spec","@contractspec/lib.translation-runtime"],Xt=`import { createTranslationRuntime } from '@contractspec/lib.translation-runtime';
|
|
1210
|
+
import { checkoutMessages } from './translations/checkout.messages';
|
|
1211
|
+
|
|
1212
|
+
const runtime = createTranslationRuntime({
|
|
1213
|
+
catalogs: [checkoutMessages],
|
|
1214
|
+
locale: 'fr-FR',
|
|
1215
|
+
fallbackLocales: ['fr', 'en-US'],
|
|
1216
|
+
onDiagnostic: (diagnostic) => reportTranslationIssue(diagnostic),
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
const label = runtime.t('checkout.pay', {
|
|
1220
|
+
amount: 4200,
|
|
1221
|
+
currency: 'EUR',
|
|
1222
|
+
});`,$t=`import { createInstance } from 'i18next';
|
|
1223
|
+
import {
|
|
1224
|
+
createI18nextInitOptions,
|
|
1225
|
+
exportContractSpecToI18next,
|
|
1226
|
+
} from '@contractspec/lib.translation-runtime/i18next';
|
|
1227
|
+
|
|
1228
|
+
const exported = exportContractSpecToI18next([checkoutMessages], {
|
|
1229
|
+
locale: 'en-US',
|
|
1230
|
+
assumeIcuFormatter: true,
|
|
1231
|
+
});
|
|
1232
|
+
const { options, diagnostics } = createI18nextInitOptions(exported, {
|
|
1233
|
+
lng: 'en-US',
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
const i18next = createInstance();
|
|
1237
|
+
await i18next.init(options);
|
|
1238
|
+
reportAdapterDiagnostics(diagnostics);`,xt=`// Server: negotiate once, preload catalogs, and serialize the runtime snapshot.
|
|
1239
|
+
const runtime = createTranslationRuntime({
|
|
1240
|
+
catalogs,
|
|
1241
|
+
locale: negotiatedLocale,
|
|
1242
|
+
fallbackLocales,
|
|
1243
|
+
});
|
|
1244
|
+
const snapshot = runtime.createSnapshot();
|
|
1245
|
+
|
|
1246
|
+
// Client: hydrate from the same snapshot so locale, resources, and fallback state match.
|
|
1247
|
+
const hydratedRuntime = createTranslationRuntime({ snapshot });`,jt=["Keep TranslationSpec as the source of truth; do not flatten metadata into i18next JSON as the canonical model.","Keep stable bundle identity in TranslationSpec.meta.key and keep BCP 47 language tags in TranslationSpec.locale.","Use ICU messages for plural, select, selectordinal, number, date, currency, list, and relative-time formatting.","Create one runtime per SSR request when tenant, project, or user overrides are involved.","Serialize the same runtime snapshot or exported adapter resources used by the server for hydration.","Configure an ICU-capable i18next formatter plugin when rendering ContractSpec ICU messages through i18next.","Treat adapter diagnostics as release blockers in production pipelines instead of silently rendering raw keys."],ea=`You are integrating ContractSpec translations into a production app.
|
|
1248
|
+
Use @contractspec/lib.contracts-spec/translations as the canonical contract layer and @contractspec/lib.translation-runtime as the runtime layer.
|
|
1249
|
+
Keep locale variants separate from stable bundle keys, support BCP 47 tags, preserve ICU plural/select/selectordinal messages, and use request-scoped runtime instances for SSR.
|
|
1250
|
+
If the app already uses i18next, use @contractspec/lib.translation-runtime/i18next only as a downstream adapter. Do not make i18next the canonical translation model. Include diagnostics, fallback behavior, tenant/user override isolation, and hydration snapshot handling in the implementation and tests.`,ta=[{title:"Spec layer",body:"TranslationSpec owns keys, locales, domains, versions, owners, fallback declarations, direction, and validation metadata."},{title:"Runtime layer",body:"Runtime instances negotiate locales, apply fallback chains, resolve overrides, cache compiled messages, report diagnostics, and serialize SSR snapshots."},{title:"Adapter layer",body:"The i18next adapter projects ContractSpec specs or snapshots to resources and manifests for caller-owned i18next instances."}];import{CodeBlock as Ue,InstallCommand as ri}from"@contractspec/lib.design-system";import{HStack as aa,VStack as le}from"@contractspec/lib.design-system/layout";import{List as ni,ListItem as ci}from"@contractspec/lib.design-system/list";import{Code as Xe,H1 as si,H2 as Ie,H3 as li,P as ke,Text as de}from"@contractspec/lib.design-system/typography";import oa from"@contractspec/lib.ui-link";import{ChevronRight as di}from"lucide-react";import{jsx as p,jsxs as T}from"react/jsx-runtime";function pi(){return T(le,{className:"space-y-8",children:[T(le,{className:"space-y-4",children:[p(de,{className:"editorial-kicker",children:"Runtime and adapters"}),p(si,{className:"font-serif text-4xl tracking-[-0.04em] md:text-5xl",children:"Translation runtime and i18next adapter"}),p(ke,{className:"max-w-3xl text-lg text-muted-foreground leading-8",children:"Use ContractSpec as the canonical translation contract layer, then resolve and format messages through a framework-independent runtime. i18next is supported as an optional downstream adapter, not as the source of truth."})]}),T(le,{className:"space-y-4",children:[p(Ie,{className:"font-bold text-2xl",children:"Install the runtime"}),p(ri,{package:Yt}),T(ke,{className:"text-muted-foreground",children:[p(de,{children:"Add "}),p(Xe,{children:"i18next"}),T(de,{children:[" ","only when an app imports the adapter subpath. Core server, React, React Native, CLI, and test code can use the runtime without loading i18next."]})]})]}),p(aa,{className:"grid gap-4 md:grid-cols-3",children:ta.map((a)=>T(le,{className:"card-subtle space-y-2 p-5",children:[p(li,{className:"font-semibold text-lg",children:a.title}),p(ke,{className:"text-muted-foreground text-sm leading-7",children:a.body})]},a.title))}),T(le,{className:"space-y-4",children:[p(Ie,{className:"font-bold text-2xl",children:"Use the ContractSpec runtime"}),T(ke,{className:"text-muted-foreground",children:[p(de,{children:"The runtime consumes canonical "}),p(Xe,{children:"TranslationSpec[]"}),T(de,{children:[" ","catalogs, supports BCP 47 tags such as en-US, ar-EG, and zh-Hans, and delegates ICU parsing/formatting to a mature formatter engine instead of a custom parser."]})]}),p(Ue,{language:"typescript",code:Xt})]}),T(le,{className:"space-y-4",children:[p(Ie,{className:"font-bold text-2xl",children:"Project to i18next when needed"}),T(ke,{className:"text-muted-foreground",children:[p(de,{children:"Import from "}),p(Xe,{children:"@contractspec/lib.translation-runtime/i18next"}),T(de,{children:[" ","to export resources by locale, namespace, and message key. The namespace defaults to the stable bundle key, dotted message keys stay flat with keySeparator false, and metadata remains in a sidecar manifest."]})]}),p(Ue,{language:"typescript",code:$t})]}),T(le,{className:"space-y-4",children:[p(Ie,{className:"font-bold text-2xl",children:"SSR, streaming, and hydration"}),p(ke,{className:"text-muted-foreground",children:"Negotiate locale on the server, preload catalogs needed for streamed content, and hydrate the client from the same serialized state. Never let client-only language detection choose a different locale after the server has rendered."}),p(Ue,{language:"typescript",code:xt})]}),T(le,{className:"space-y-4",children:[p(Ie,{className:"font-bold text-2xl",children:"Production checklist"}),p(ni,{className:"list-disc space-y-2 pl-6 text-muted-foreground",children:jt.map((a)=>p(ci,{children:a},a))})]}),T(le,{className:"space-y-4 rounded-xl border border-border p-6",children:[p(Ie,{className:"font-bold text-2xl",children:"Agent implementation prompt"}),p(ke,{className:"text-muted-foreground",children:"Use this prompt when asking an agent to wire translations into a web, server, or React Native surface without losing ContractSpec ownership."}),p(Ue,{language:"markdown",code:ea})]}),T(aa,{className:"flex flex-wrap items-center gap-4 pt-4",children:[p(oa,{href:"/docs/libraries/contracts",className:"btn-ghost",children:p(de,{children:"Translation contracts"})}),T(oa,{href:"/docs/libraries/design-system",className:"btn-primary",children:[p(de,{children:"Design-system integration"}),p(di,{size:16})]})]})]})}import{CodeBlock as mi,InstallCommand as ui}from"@contractspec/lib.design-system";import We from"@contractspec/lib.ui-link";import{ChevronRight as hi}from"lucide-react";import{jsx as n,jsxs as b}from"react/jsx-runtime";var gi=`import { DataTable } from '@contractspec/lib.ui-kit/ui/data-table';
|
|
852
1251
|
import { useContractTable } from '@contractspec/lib.presentation-runtime-react';
|
|
853
1252
|
|
|
854
1253
|
import { SHOWCASE_ROWS } from '@contractspec/example.data-grid-showcase/ui/data-grid-showcase.data';
|
|
@@ -892,7 +1291,7 @@ export function NativeAccountGrid() {
|
|
|
892
1291
|
footer={\`Rows \${controller.rows.length}\`}
|
|
893
1292
|
/>
|
|
894
1293
|
);
|
|
895
|
-
}`;function
|
|
1294
|
+
}`;function fi(){return b("div",{className:"space-y-8",children:[b("div",{className:"space-y-4",children:[n("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.ui-kit"}),b("p",{className:"text-muted-foreground",children:["Universal UI components for React Native and Web, built on top of",n("code",{children:"nativewind"})," and ",n("code",{children:"@rn-primitives"}),"."]})]}),b("div",{className:"space-y-4",children:[n("h2",{className:"font-bold text-2xl",children:"Installation"}),n(ui,{package:"@contractspec/lib.ui-kit"})]}),b("div",{className:"space-y-4",children:[n("h2",{className:"font-bold text-2xl",children:"Key Features"}),b("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[b("li",{children:[n("strong",{children:"Universal"}),": Components render natively on iOS/Android and as standard HTML on web"]}),b("li",{children:[n("strong",{children:"Styled with NativeWind"}),": Uses Tailwind CSS classes for styling"]}),b("li",{children:[n("strong",{children:"Accessible"}),": Leverages ",n("code",{children:"@rn-primitives"})," ","(Radix UI for Native)"]}),b("li",{children:[n("strong",{children:"Atomic Design"}),": Exports atoms, molecules, and organisms"]})]})]}),b("div",{className:"space-y-4",children:[n("h2",{className:"font-bold text-2xl",children:"Data table example"}),b("p",{className:"text-muted-foreground",children:["The canonical"," ",n(We,{href:"/docs/examples/data-grid-showcase",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Data Grid Showcase"})," ","uses ",n("code",{children:"@contractspec/lib.ui-kit/ui/data-table"})," as the native-first primitive lane. It shares the same controller model as the web renderer while keeping the React Native / Expo surface explicit."]}),n(mi,{language:"tsx",code:gi})]}),b("div",{className:"space-y-4",children:[n("h2",{className:"font-bold text-2xl",children:"Core Components"}),b("div",{className:"grid gap-4 md:grid-cols-3",children:[b("div",{className:"card-subtle p-4",children:[n("h3",{className:"mb-2 font-semibold",children:"Form Controls"}),b("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[n("li",{children:"Button"}),n("li",{children:"Input"}),n("li",{children:"Checkbox"}),n("li",{children:"Switch"}),n("li",{children:"Select"})]})]}),b("div",{className:"card-subtle p-4",children:[n("h3",{className:"mb-2 font-semibold",children:"Layout"}),b("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[n("li",{children:"Card"}),n("li",{children:"Stack"}),n("li",{children:"Separator"}),n("li",{children:"Sheet"})]})]}),b("div",{className:"card-subtle p-4",children:[n("h3",{className:"mb-2 font-semibold",children:"Feedback"}),b("ul",{className:"space-y-1 text-muted-foreground text-sm",children:[n("li",{children:"Alert"}),n("li",{children:"Skeleton"}),n("li",{children:"Progress"}),n("li",{children:"Tooltip"})]})]})]})]}),b("div",{className:"card-subtle space-y-3 p-6",children:[n("h2",{className:"font-bold text-2xl",children:"Where this layer fits"}),b("p",{className:"text-muted-foreground",children:["Read"," ",n(We,{href:"/docs/libraries/cross-platform-ui",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Cross-platform UI"})," ","for the full React and React Native compatibility model around this native-first primitive lane."]})]}),b("div",{className:"flex items-center gap-4 pt-4",children:[n(We,{href:"/docs/libraries/schema",className:"btn-ghost",children:"Previous: Schema"}),b(We,{href:"/docs/libraries/ui-kit-web",className:"btn-primary",children:["Next: UI Kit Web ",n(hi,{size:16})]})]})]})}import{CodeBlock as bi,InstallCommand as vi}from"@contractspec/lib.design-system";import ze from"@contractspec/lib.ui-link";import{ChevronRight as yi}from"lucide-react";import{jsx as U,jsxs as Y}from"react/jsx-runtime";var Ni=`import { DataTable } from '@contractspec/lib.ui-kit-web/ui/data-table';
|
|
896
1295
|
import { useContractTable } from '@contractspec/lib.presentation-runtime-react';
|
|
897
1296
|
|
|
898
1297
|
import { SHOWCASE_ROWS } from '@contractspec/example.data-grid-showcase/ui/data-grid-showcase.data';
|
|
@@ -937,7 +1336,7 @@ export function WebAccountGrid() {
|
|
|
937
1336
|
footer={\`Rows \${controller.totalItems}\`}
|
|
938
1337
|
/>
|
|
939
1338
|
);
|
|
940
|
-
}`;function
|
|
1339
|
+
}`;function wi(){return Y("div",{className:"space-y-8",children:[Y("div",{className:"space-y-4",children:[U("h1",{className:"font-bold text-4xl",children:"@contractspec/lib.ui-kit-web"}),U("p",{className:"text-muted-foreground",children:"Web-first React and Next primitives for ContractSpec. The canonical data-table example uses this package to render the raw browser table layer directly, without the design-system shell on top."})]}),Y("div",{className:"space-y-4",children:[U("h2",{className:"font-bold text-2xl",children:"Installation"}),U(vi,{package:"@contractspec/lib.ui-kit-web"})]}),Y("div",{className:"space-y-4",children:[U("h2",{className:"font-bold text-2xl",children:"Data table example"}),Y("p",{className:"text-muted-foreground",children:["This is the raw browser lane from the canonical"," ",U(ze,{href:"/docs/examples/data-grid-showcase",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Data Grid Showcase"}),". It demonstrates the primitive renderer with sorting, pagination, single selection, column visibility, column resizing, left/right pinning, row expansion, loading, and empty-state slots."]}),U(bi,{language:"tsx",filename:"web-account-grid.tsx",code:Ni})]}),Y("div",{className:"space-y-4",children:[U("h2",{className:"font-bold text-2xl",children:"What this layer owns"}),Y("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[U("li",{children:"The raw table renderer and browser interaction model."}),U("li",{children:"Pagination, column visibility menus, pin menus, resize handles, and empty/loading states."}),U("li",{children:"Accessibility helpers and other web-specific primitives that stay outside the native-first package."})]})]}),Y("div",{className:"card-subtle space-y-3 p-6",children:[U("h2",{className:"font-bold text-2xl",children:"Where this layer fits"}),Y("p",{className:"text-muted-foreground",children:["Read"," ",U(ze,{href:"/docs/libraries/cross-platform-ui",className:"text-[color:var(--rust)] underline underline-offset-4",children:"Cross-platform UI"})," ","for the shared runtime story behind the web and native render lanes."]})]}),Y("div",{className:"flex items-center gap-4 pt-4",children:[U(ze,{href:"/docs/libraries/ui-kit",className:"btn-ghost",children:"Previous: UI Kit"}),Y(ze,{href:"/docs/libraries/design-system",className:"btn-primary",children:["Next: Design System ",U(yi,{size:16})]})]})]})}import{CodeBlock as ia,InstallCommand as ki}from"@contractspec/lib.design-system";import ra from"@contractspec/lib.ui-link";import{ChevronRight as Si}from"lucide-react";import{jsx as te,jsxs as Se}from"react/jsx-runtime";function Ri(){return Se("div",{className:"space-y-8",children:[Se("div",{className:"space-y-4",children:[te("h1",{className:"font-bold text-4xl",children:"Workflow Composer"}),te("p",{className:"text-lg text-muted-foreground",children:"`@contractspec/lib.workflow-composer` injects tenant-/role-/device-specific steps into base WorkflowSpecs and keeps transitions valid."})]}),Se("div",{className:"space-y-4",children:[te("h2",{className:"font-bold text-2xl",children:"Installation"}),te(ki,{package:"@contractspec/lib.workflow-composer"})]}),Se("div",{className:"space-y-4",children:[te("h2",{className:"font-bold text-2xl",children:"Register extensions"}),te(ia,{language:"typescript",code:`const composer = new WorkflowComposer();
|
|
941
1340
|
|
|
942
1341
|
composer.register({
|
|
943
1342
|
workflow: 'billing.invoiceApproval',
|
|
@@ -954,12 +1353,12 @@ composer.register({
|
|
|
954
1353
|
},
|
|
955
1354
|
],
|
|
956
1355
|
hiddenSteps: ['internal-audit'],
|
|
957
|
-
});`})]}),
|
|
1356
|
+
});`})]}),Se("div",{className:"space-y-4",children:[te("h2",{className:"font-bold text-2xl",children:"Compose at runtime"}),te(ia,{language:"typescript",code:`const tenantWorkflow = composer.compose({
|
|
958
1357
|
base: BaseInvoiceWorkflow,
|
|
959
1358
|
tenantId: 'acme',
|
|
960
1359
|
});
|
|
961
1360
|
|
|
962
|
-
workflowRunner.execute(tenantWorkflow, ctx);`})]}),
|
|
1361
|
+
workflowRunner.execute(tenantWorkflow, ctx);`})]}),Se("div",{className:"flex items-center gap-4 pt-4",children:[te(ra,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),Se(ra,{href:"/docs/libraries/workflows",className:"btn-primary",children:["Next: Workflow Runtime ",te(Si,{size:16})]})]})]})}import{CodeBlock as Ci,InstallCommand as Ti}from"@contractspec/lib.design-system";import na from"@contractspec/lib.ui-link";import{ChevronRight as Ai}from"lucide-react";import{jsx as m,jsxs as z}from"react/jsx-runtime";function Li(){return z("div",{className:"space-y-8",children:[z("div",{className:"space-y-4",children:[m("h1",{className:"font-bold text-4xl",children:"Workflow Runtime Library"}),z("p",{className:"text-lg text-muted-foreground",children:["The ",m("code",{children:"@contractspec/lib.contracts-spec/workflow"})," library provides the core ",m("code",{children:"WorkflowRunner"})," for executing stateful, durable workflows."]})]}),z("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Installation"}),m(Ti,{package:"@contractspec/lib.contracts-spec"})]}),z("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"WorkflowRunner"}),m("p",{className:"text-muted-foreground",children:"The runner manages execution state, step transitions, retries, and compensation."}),m(Ci,{language:"typescript",code:`import { WorkflowRunner } from '@contractspec/lib.contracts-spec/workflow/runner';
|
|
963
1362
|
import { InMemoryStateStore } from '@contractspec/lib.contracts-spec/workflow/adapters/memory-store';
|
|
964
1363
|
import { WorkflowRegistry } from '@contractspec/lib.contracts-spec/workflow/spec';
|
|
965
1364
|
|
|
@@ -979,4 +1378,4 @@ const runner = new WorkflowRunner({
|
|
|
979
1378
|
const workflowId = await runner.start('my.workflow', 1, { userId: '123' });
|
|
980
1379
|
|
|
981
1380
|
// Execute next step (usually called by a worker or queue consumer)
|
|
982
|
-
await runner.executeStep(workflowId);`})]}),
|
|
1381
|
+
await runner.executeStep(workflowId);`})]}),z("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"State Persistence"}),z("p",{className:"text-muted-foreground",children:["The runner relies on a ",m("code",{children:"StateStore"})," to persist workflow execution history. ContractSpec ships with:"]}),z("ul",{className:"list-disc space-y-2 pl-6 text-muted-foreground",children:[z("li",{children:[m("code",{children:"InMemoryStateStore"})," - for testing and development."]}),z("li",{children:[m("code",{children:"PrismaStateStore"})," - for production using Prisma ORM."]})]})]}),z("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Events"}),m("p",{className:"text-muted-foreground",children:"The runner emits events that you can subscribe to for monitoring:"}),z("ul",{className:"list-disc space-y-2 pl-6 text-muted-foreground",children:[m("li",{children:m("code",{children:"workflow.started"})}),m("li",{children:m("code",{children:"workflow.step_completed"})}),m("li",{children:m("code",{children:"workflow.step_failed"})}),m("li",{children:m("code",{children:"workflow.step_retrying"})}),m("li",{children:m("code",{children:"workflow.completed"})}),m("li",{children:m("code",{children:"workflow.cancelled"})}),m("li",{children:m("code",{children:"workflow.compensation_step_completed"})})]})]}),z("div",{className:"flex items-center gap-4 pt-4",children:[m(na,{href:"/docs/libraries",className:"btn-ghost",children:"Back to Libraries"}),z(na,{href:"/docs/libraries/data-views",className:"btn-primary",children:["Next: Data Views ",m(Ai,{size:16})]})]})]})}export{Li as LibrariesWorkflowsPage,Ri as LibrariesWorkflowComposerPage,wi as LibrariesUIKitWebPage,fi as LibrariesUIKitPage,pi as LibrariesTranslationRuntimePage,ii as LibrariesTestingPage,ti as LibrariesSupportBotPage,Yo as LibrariesSchemaPage,xo as LibrariesSLOPage,Jo as LibrariesRuntimePage,qo as LibrariesResiliencePage,Go as LibrariesProgressiveDeliveryPage,Uo as LibrariesPersonalizationPage,Lo as LibrariesOverviewPage,Ro as LibrariesOverlayEnginePage,wo as LibrariesObservabilityPage,vo as LibrariesMultiTenancyPage,go as LibrariesGrowthPage,mo as LibrariesGraphQLPage,co as LibrariesEvolutionPage,io as LibrariesDesignSystemPage,Ya as LibrariesDataViewsPage,Ga as LibrariesDataBackendPage,Ua as LibrariesCrossPlatformUIPage,Ea as LibrariesCostTrackingPage,Oa as LibrariesContractsPage,Ta as LibrariesContentGenPage,ka as LibrariesApplicationShellPage,ba as LibrariesAnalyticsPage,ga as LibrariesAiAgentPage,ma as LibrariesAccessibilityPage};
|