@cedros/data-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +177 -0
  3. package/dist/admin/api.d.ts +19 -0
  4. package/dist/admin/api.js +108 -0
  5. package/dist/admin/components.d.ts +36 -0
  6. package/dist/admin/components.js +22 -0
  7. package/dist/admin/history.d.ts +17 -0
  8. package/dist/admin/history.js +103 -0
  9. package/dist/admin/icons.d.ts +15 -0
  10. package/dist/admin/icons.js +18 -0
  11. package/dist/admin/index.d.ts +13 -0
  12. package/dist/admin/index.js +12 -0
  13. package/dist/admin/permissions.d.ts +4 -0
  14. package/dist/admin/permissions.js +45 -0
  15. package/dist/admin/plugin.d.ts +4 -0
  16. package/dist/admin/plugin.js +180 -0
  17. package/dist/admin/primitives/ConfirmDialog.d.ts +14 -0
  18. package/dist/admin/primitives/ConfirmDialog.js +7 -0
  19. package/dist/admin/primitives/DataTable.d.ts +14 -0
  20. package/dist/admin/primitives/DataTable.js +7 -0
  21. package/dist/admin/primitives/DiffViewer.d.ts +11 -0
  22. package/dist/admin/primitives/DiffViewer.js +8 -0
  23. package/dist/admin/primitives/FormFieldRow.d.ts +23 -0
  24. package/dist/admin/primitives/FormFieldRow.js +16 -0
  25. package/dist/admin/primitives/JsonCodeEditor.d.ts +10 -0
  26. package/dist/admin/primitives/JsonCodeEditor.js +42 -0
  27. package/dist/admin/primitives/Pagination.d.ts +8 -0
  28. package/dist/admin/primitives/Pagination.js +8 -0
  29. package/dist/admin/primitives/Toolbar.d.ts +23 -0
  30. package/dist/admin/primitives/Toolbar.js +10 -0
  31. package/dist/admin/primitives/alerts.d.ts +21 -0
  32. package/dist/admin/primitives/alerts.js +44 -0
  33. package/dist/admin/sectionIds.d.ts +20 -0
  34. package/dist/admin/sectionIds.js +33 -0
  35. package/dist/admin/sections/CollectionsSection.d.ts +2 -0
  36. package/dist/admin/sections/CollectionsSection.js +125 -0
  37. package/dist/admin/sections/ContractVerifySection.d.ts +11 -0
  38. package/dist/admin/sections/ContractVerifySection.js +98 -0
  39. package/dist/admin/sections/CustomDataSection.d.ts +2 -0
  40. package/dist/admin/sections/CustomDataSection.js +256 -0
  41. package/dist/admin/sections/DataOpsSection.d.ts +26 -0
  42. package/dist/admin/sections/DataOpsSection.js +245 -0
  43. package/dist/admin/sections/HistorySection.d.ts +2 -0
  44. package/dist/admin/sections/HistorySection.js +26 -0
  45. package/dist/admin/sections/MonetizationSection.d.ts +2 -0
  46. package/dist/admin/sections/MonetizationSection.js +140 -0
  47. package/dist/admin/sections/NavigationSection.d.ts +13 -0
  48. package/dist/admin/sections/NavigationSection.js +195 -0
  49. package/dist/admin/sections/PagesSection.d.ts +2 -0
  50. package/dist/admin/sections/PagesSection.js +157 -0
  51. package/dist/admin/sections/SchemaDesignerSection.d.ts +2 -0
  52. package/dist/admin/sections/SchemaDesignerSection.js +167 -0
  53. package/dist/admin/sections/SiteSettingsSection.d.ts +12 -0
  54. package/dist/admin/sections/SiteSettingsSection.js +122 -0
  55. package/dist/admin/sections/TippingSection.d.ts +2 -0
  56. package/dist/admin/sections/TippingSection.js +178 -0
  57. package/dist/admin/sections/media/MediaDetail.d.ts +12 -0
  58. package/dist/admin/sections/media/MediaDetail.js +74 -0
  59. package/dist/admin/sections/media/MediaGrid.d.ts +14 -0
  60. package/dist/admin/sections/media/MediaGrid.js +22 -0
  61. package/dist/admin/sections/media/MediaSection.d.ts +2 -0
  62. package/dist/admin/sections/media/MediaSection.js +97 -0
  63. package/dist/admin/sections/media/MediaUploader.d.ts +7 -0
  64. package/dist/admin/sections/media/MediaUploader.js +72 -0
  65. package/dist/admin/sections/media/types.d.ts +33 -0
  66. package/dist/admin/sections/media/types.js +1 -0
  67. package/dist/admin/styles.css +533 -0
  68. package/dist/admin/types.d.ts +85 -0
  69. package/dist/admin/types.js +1 -0
  70. package/dist/index.d.ts +4 -0
  71. package/dist/index.js +3 -0
  72. package/dist/react/CmsContent.d.ts +20 -0
  73. package/dist/react/CmsContent.js +31 -0
  74. package/dist/react/entries.d.ts +9 -0
  75. package/dist/react/entries.js +25 -0
  76. package/dist/react/fetch.d.ts +11 -0
  77. package/dist/react/fetch.js +32 -0
  78. package/dist/react/index.d.ts +10 -0
  79. package/dist/react/index.js +9 -0
  80. package/dist/react/metadata.d.ts +44 -0
  81. package/dist/react/metadata.js +142 -0
  82. package/dist/react/sanitize.d.ts +17 -0
  83. package/dist/react/sanitize.js +326 -0
  84. package/dist/react/server.d.ts +14 -0
  85. package/dist/react/server.js +13 -0
  86. package/dist/react/sitemap.d.ts +28 -0
  87. package/dist/react/sitemap.js +91 -0
  88. package/dist/react/slugs.d.ts +27 -0
  89. package/dist/react/slugs.js +52 -0
  90. package/dist/react/types.d.ts +85 -0
  91. package/dist/react/types.js +1 -0
  92. package/dist/react/visitor.d.ts +7 -0
  93. package/dist/react/visitor.js +18 -0
  94. package/dist/site-templates/BlogTemplates.d.ts +95 -0
  95. package/dist/site-templates/BlogTemplates.js +64 -0
  96. package/dist/site-templates/ContactPageTemplate.d.ts +14 -0
  97. package/dist/site-templates/ContactPageTemplate.js +5 -0
  98. package/dist/site-templates/DashboardOverviewTemplate.d.ts +29 -0
  99. package/dist/site-templates/DashboardOverviewTemplate.js +17 -0
  100. package/dist/site-templates/DashboardShell.d.ts +28 -0
  101. package/dist/site-templates/DashboardShell.js +10 -0
  102. package/dist/site-templates/DocsSidebar.d.ts +14 -0
  103. package/dist/site-templates/DocsSidebar.js +13 -0
  104. package/dist/site-templates/DocsTemplates.d.ts +60 -0
  105. package/dist/site-templates/DocsTemplates.js +47 -0
  106. package/dist/site-templates/HomePageTemplate.d.ts +15 -0
  107. package/dist/site-templates/HomePageTemplate.js +10 -0
  108. package/dist/site-templates/LegalPageTemplate.d.ts +12 -0
  109. package/dist/site-templates/LegalPageTemplate.js +6 -0
  110. package/dist/site-templates/MarkdownContent.d.ts +7 -0
  111. package/dist/site-templates/MarkdownContent.js +24 -0
  112. package/dist/site-templates/NotFoundTemplate.d.ts +9 -0
  113. package/dist/site-templates/NotFoundTemplate.js +5 -0
  114. package/dist/site-templates/SiteFooter.d.ts +13 -0
  115. package/dist/site-templates/SiteFooter.js +4 -0
  116. package/dist/site-templates/SiteLayout.d.ts +14 -0
  117. package/dist/site-templates/SiteLayout.js +6 -0
  118. package/dist/site-templates/TopNav.d.ts +10 -0
  119. package/dist/site-templates/TopNav.js +8 -0
  120. package/dist/site-templates/blogControls.d.ts +19 -0
  121. package/dist/site-templates/blogControls.js +37 -0
  122. package/dist/site-templates/codeBlock.d.ts +9 -0
  123. package/dist/site-templates/codeBlock.js +31 -0
  124. package/dist/site-templates/content-styles.css +410 -0
  125. package/dist/site-templates/contentIndex.d.ts +65 -0
  126. package/dist/site-templates/contentIndex.js +181 -0
  127. package/dist/site-templates/contentUi.d.ts +14 -0
  128. package/dist/site-templates/contentUi.js +24 -0
  129. package/dist/site-templates/docs-styles.css +259 -0
  130. package/dist/site-templates/docsNavigation.d.ts +18 -0
  131. package/dist/site-templates/docsNavigation.js +50 -0
  132. package/dist/site-templates/index.d.ts +28 -0
  133. package/dist/site-templates/index.js +25 -0
  134. package/dist/site-templates/monetization-styles.css +154 -0
  135. package/dist/site-templates/paywallControls.d.ts +22 -0
  136. package/dist/site-templates/paywallControls.js +9 -0
  137. package/dist/site-templates/routing.d.ts +12 -0
  138. package/dist/site-templates/routing.js +36 -0
  139. package/dist/site-templates/solanaAtaSetup.d.ts +11 -0
  140. package/dist/site-templates/solanaAtaSetup.js +38 -0
  141. package/dist/site-templates/solanaMicropayments.d.ts +65 -0
  142. package/dist/site-templates/solanaMicropayments.js +115 -0
  143. package/dist/site-templates/styles.css +332 -0
  144. package/dist/site-templates/tipControls.d.ts +24 -0
  145. package/dist/site-templates/tipControls.js +43 -0
  146. package/dist/site-templates/tocExtractor.d.ts +16 -0
  147. package/dist/site-templates/tocExtractor.js +58 -0
  148. package/dist/site-templates/tocScrollSpy.d.ts +16 -0
  149. package/dist/site-templates/tocScrollSpy.js +37 -0
  150. package/dist/templates.d.ts +8 -0
  151. package/dist/templates.js +20 -0
  152. package/package.json +58 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+ - `MarkdownContent` renderer based on `react-markdown` + `remark-gfm` + `rehype-slug`.
7
+ - `bodyMarkdown` support in:
8
+ - `BlogPostTemplate`
9
+ - `DocArticleTemplate`
10
+ - `LegalPageTemplate`
11
+ - `allowUnsafeHtmlFallback` opt-in for legacy raw HTML rendering.
12
+ - GitBook-style docs navigation helpers and layout support (`buildDocsSidebarSections`, `withActiveDocsSidebar`).
13
+ - End-to-end example for loading markdown from `cedros-data` and rendering docs templates.
14
+
15
+ ### Changed
16
+ - `bodyHtml` is no longer the default rendering path for article/legal templates.
17
+ - Raw HTML now requires explicit `allowUnsafeHtmlFallback={true}`.
18
+
19
+ ### Migration Notes
20
+ - Before:
21
+ - `bodyHtml` as primary content input.
22
+ - After:
23
+ - use `bodyMarkdown` as primary input.
24
+ - keep `bodyHtml` only for compatibility and set `allowUnsafeHtmlFallback={true}` if absolutely required.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @cedros/data-react
2
+
3
+ `@cedros/data-react` is the frontend companion package for `cedros-data`.
4
+
5
+ It provides:
6
+ - a cedros-login `AdminShell` plugin (`cedrosDataPlugin`)
7
+ - reusable admin primitives/components
8
+ - reusable site layout components
9
+ - page templates for core/content/legal routes
10
+ - GitBook-style docs rendering with markdown support
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ cd ui
16
+ npm install
17
+ ```
18
+
19
+ ## Build and test
20
+
21
+ ```bash
22
+ npm run check
23
+ npm run build
24
+ npm test
25
+ npm run test:packaged
26
+ ```
27
+
28
+ Packaging smoke:
29
+ - `npm pack --dry-run` now runs `prepack`, which rebuilds `dist/` and verifies every exported JS/CSS/types file before the tarball is assembled
30
+
31
+ ## Package exports
32
+
33
+ - `@cedros/data-react`
34
+ - `defaultPageTemplates`
35
+ - `DefaultPageKey`, `PageTemplateContract`
36
+ - re-exports admin + site-template modules
37
+ - `@cedros/data-react/admin`
38
+ - `cedrosDataPlugin`
39
+ - section IDs/groups/types
40
+ - admin components/primitives
41
+ - `@cedros/data-react/site-templates`
42
+ - site shell/layout components
43
+ - page templates
44
+ - routing/content helpers
45
+ - `@cedros/data-react/admin/styles.css`
46
+ - `@cedros/data-react/site-templates/styles.css`
47
+
48
+ Runtime packaging note:
49
+ - the published JS entrypoints are side-effect-free so they stay importable in Node/SSR
50
+ - import `@cedros/data-react/admin/styles.css` and/or `@cedros/data-react/site-templates/styles.css` explicitly in browser apps that need the packaged styles
51
+
52
+ Publish surface:
53
+ - npm tarballs intentionally include only `dist/`, `README.md`, and `CHANGELOG.md`
54
+ - source files, tests, examples, and local task notes stay out of the published package
55
+
56
+ ## AdminShell integration
57
+
58
+ ```tsx
59
+ import { AdminShell, cedrosLoginPlugin } from "@cedros/login-react";
60
+ import { cedrosDataPlugin } from "@cedros/data-react/admin";
61
+
62
+ <AdminShell
63
+ plugins={[cedrosLoginPlugin, cedrosDataPlugin]}
64
+ hostContext={{
65
+ cedrosLogin: {
66
+ user,
67
+ getAccessToken,
68
+ serverUrl: "http://localhost:8080"
69
+ },
70
+ org: { orgId: "11111111-1111-1111-1111-111111111111", role: "owner", permissions: [] },
71
+ custom: {
72
+ cedrosData: {
73
+ serverUrl: "http://localhost:8080"
74
+ }
75
+ }
76
+ }}
77
+ />;
78
+ ```
79
+
80
+ Plugin context behavior:
81
+ - resolves `serverUrl` from `custom.cedrosData.serverUrl` or `cedrosLogin.serverUrl`
82
+ - forwards bearer token from `cedrosLogin.getAccessToken()`
83
+ - forwards `x-cedros-org-id` when `hostContext.org.orgId` is present
84
+
85
+ ## Admin sections
86
+
87
+ Content:
88
+ - `pages`
89
+ - `navigation`
90
+ - `site-settings`
91
+
92
+ Data model:
93
+ - `collections`
94
+ - `schema-designer`
95
+ - `contract-verify`
96
+ - `custom-data`
97
+
98
+ Operations:
99
+ - `data-ops`
100
+ - `history`
101
+
102
+ ## Styling and dark mode
103
+
104
+ - Admin UIs use tokenized variables aligned with cedros-login/cedros-pay conventions.
105
+ - Dark mode responds to both:
106
+ - `.cedros-dark`
107
+ - `.cedros-admin--dark`
108
+ - Direct import option:
109
+
110
+ ```ts
111
+ import "@cedros/data-react/admin/styles.css";
112
+ ```
113
+
114
+ ## Site templates and components
115
+
116
+ Layouts/navigation:
117
+ - `SiteLayout`
118
+ - `TopNav`
119
+ - `SiteFooter`
120
+ - `DashboardShell`
121
+
122
+ Core page templates:
123
+ - `HomePageTemplate`
124
+ - `ContactPageTemplate`
125
+ - `LegalPageTemplate`
126
+ - `NotFoundTemplate`
127
+ - `DashboardOverviewTemplate`
128
+
129
+ Blog templates:
130
+ - `BlogIndexTemplate`
131
+ - `BlogPostTemplate`
132
+
133
+ Docs templates:
134
+ - `DocsIndexTemplate`
135
+ - `DocArticleTemplate` (GitBook-style left nav + right TOC)
136
+
137
+ Content rendering and helpers:
138
+ - `MarkdownContent`
139
+ - `Breadcrumbs`
140
+ - `ContentPagination`
141
+ - `withActiveRouteState`
142
+ - `buildDocsSidebarSections`
143
+ - `withActiveDocsSidebar`
144
+ - `prepareBlogIndex`
145
+ - `prepareDocsIndex`
146
+ - `collectFilterValues`
147
+ - `buildContentListHref`
148
+
149
+ ## Markdown and HTML behavior
150
+
151
+ Docs/blog templates default to `bodyMarkdown`.
152
+
153
+ `bodyHtml` remains compatibility fallback and is only rendered when:
154
+ - `allowUnsafeHtmlFallback={true}`
155
+
156
+ This keeps markdown as the safe default and avoids unsafe HTML rendering by default.
157
+
158
+ ## Default page contract
159
+
160
+ The package exports the default page template contract used by server bootstrap:
161
+ - `home`
162
+ - `about`
163
+ - `contact`
164
+ - `docs`
165
+ - `blog`
166
+ - `privacy-policy`
167
+ - `terms-of-service`
168
+ - `not-found`
169
+
170
+ ## Example
171
+
172
+ End-to-end markdown integration example:
173
+ - `examples/cedros-data-markdown-e2e.tsx`
174
+ - the example reads page records from `GET /admin/pages` and uses each record's `entry_key`
175
+
176
+ See also:
177
+ - `CHANGELOG.md`
@@ -0,0 +1,19 @@
1
+ import type { PluginContext } from "./types.js";
2
+ interface RequestOptions {
3
+ method?: string;
4
+ body?: unknown;
5
+ signal?: AbortSignal;
6
+ timeoutMs?: number;
7
+ }
8
+ export declare function requestJson<T>(pluginContext: PluginContext, path: string, options?: RequestOptions): Promise<T>;
9
+ export interface LatestRequest {
10
+ signal: AbortSignal;
11
+ isCurrent: () => boolean;
12
+ }
13
+ export interface LatestRequestController {
14
+ begin: () => LatestRequest;
15
+ cancel: () => void;
16
+ }
17
+ export declare function createLatestRequestController(): LatestRequestController;
18
+ export declare function uploadFile<T>(pluginContext: PluginContext, path: string, formData: FormData): Promise<T>;
19
+ export {};
@@ -0,0 +1,108 @@
1
+ const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
2
+ export async function requestJson(pluginContext, path, options = {}) {
3
+ const token = pluginContext.getAccessToken();
4
+ const headers = {
5
+ "Content-Type": "application/json"
6
+ };
7
+ if (token) {
8
+ headers.Authorization = `Bearer ${token}`;
9
+ }
10
+ if (pluginContext.orgId) {
11
+ headers["x-cedros-org-id"] = pluginContext.orgId;
12
+ }
13
+ const baseUrl = pluginContext.serverUrl.replace(/\/+$/, "");
14
+ const requestPath = path.startsWith("/") ? path : `/${path}`;
15
+ const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
16
+ const controller = new AbortController();
17
+ const onAbort = () => controller.abort();
18
+ let timedOut = false;
19
+ let timeoutId;
20
+ if (options.signal) {
21
+ if (options.signal.aborted) {
22
+ controller.abort();
23
+ }
24
+ else {
25
+ options.signal.addEventListener("abort", onAbort, { once: true });
26
+ }
27
+ }
28
+ if (timeoutMs > 0) {
29
+ timeoutId = setTimeout(() => {
30
+ timedOut = true;
31
+ controller.abort();
32
+ }, timeoutMs);
33
+ }
34
+ try {
35
+ const response = await fetch(`${baseUrl}${requestPath}`, {
36
+ method: options.method ?? "GET",
37
+ headers,
38
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
39
+ signal: controller.signal
40
+ });
41
+ if (!response.ok) {
42
+ const text = await response.text();
43
+ throw new Error(text || `Request failed (${response.status})`);
44
+ }
45
+ return (await response.json());
46
+ }
47
+ catch (error) {
48
+ if (timedOut && isAbortError(error)) {
49
+ throw new Error(`Request timed out after ${timeoutMs}ms`);
50
+ }
51
+ throw error;
52
+ }
53
+ finally {
54
+ if (timeoutId !== undefined) {
55
+ clearTimeout(timeoutId);
56
+ }
57
+ options.signal?.removeEventListener("abort", onAbort);
58
+ }
59
+ }
60
+ export function createLatestRequestController() {
61
+ let currentToken = 0;
62
+ let currentController = null;
63
+ return {
64
+ begin() {
65
+ currentToken += 1;
66
+ currentController?.abort();
67
+ const controller = new AbortController();
68
+ currentController = controller;
69
+ const requestToken = currentToken;
70
+ return {
71
+ signal: controller.signal,
72
+ isCurrent: () => currentController === controller &&
73
+ currentToken === requestToken &&
74
+ !controller.signal.aborted
75
+ };
76
+ },
77
+ cancel() {
78
+ currentToken += 1;
79
+ currentController?.abort();
80
+ currentController = null;
81
+ }
82
+ };
83
+ }
84
+ export async function uploadFile(pluginContext, path, formData) {
85
+ const token = pluginContext.getAccessToken();
86
+ const headers = {};
87
+ if (token) {
88
+ headers.Authorization = `Bearer ${token}`;
89
+ }
90
+ if (pluginContext.orgId) {
91
+ headers["x-cedros-org-id"] = pluginContext.orgId;
92
+ }
93
+ const baseUrl = pluginContext.serverUrl.replace(/\/+$/, "");
94
+ const requestPath = path.startsWith("/") ? path : `/${path}`;
95
+ const response = await fetch(`${baseUrl}${requestPath}`, {
96
+ method: "POST",
97
+ headers,
98
+ body: formData
99
+ });
100
+ if (!response.ok) {
101
+ const text = await response.text();
102
+ throw new Error(text || `Upload failed (${response.status})`);
103
+ }
104
+ return (await response.json());
105
+ }
106
+ function isAbortError(error) {
107
+ return error instanceof Error && error.name === "AbortError";
108
+ }
@@ -0,0 +1,36 @@
1
+ import type * as React from "react";
2
+ import type { ButtonHTMLAttributes, InputHTMLAttributes, ReactNode, SelectHTMLAttributes, TextareaHTMLAttributes } from "react";
3
+ type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
4
+ type ButtonSize = "sm" | "md";
5
+ interface AdminButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
6
+ variant?: ButtonVariant;
7
+ size?: ButtonSize;
8
+ }
9
+ export declare function AdminButton({ className, variant, size, ...rest }: AdminButtonProps): React.JSX.Element;
10
+ interface CardProps {
11
+ title?: string;
12
+ subtitle?: string;
13
+ actions?: ReactNode;
14
+ children: ReactNode;
15
+ }
16
+ export declare function Card({ title, subtitle, actions, children }: CardProps): React.JSX.Element;
17
+ interface TextInputProps extends InputHTMLAttributes<HTMLInputElement> {
18
+ label?: string;
19
+ }
20
+ export declare function TextInput({ label, className, ...rest }: TextInputProps): React.JSX.Element;
21
+ interface SelectInputProps extends SelectHTMLAttributes<HTMLSelectElement> {
22
+ label?: string;
23
+ children: ReactNode;
24
+ }
25
+ export declare function SelectInput({ label, className, children, ...rest }: SelectInputProps): React.JSX.Element;
26
+ interface JsonEditorProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
27
+ label?: string;
28
+ }
29
+ export declare function JsonEditor({ label, className, ...rest }: JsonEditorProps): React.JSX.Element;
30
+ type StatusTone = "neutral" | "success" | "error";
31
+ interface StatusNoticeProps {
32
+ tone: StatusTone;
33
+ message: string;
34
+ }
35
+ export declare function StatusNotice({ tone, message }: StatusNoticeProps): React.JSX.Element;
36
+ export {};
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ function cx(...parts) {
3
+ return parts.filter(Boolean).join(" ");
4
+ }
5
+ export function AdminButton({ className, variant = "secondary", size = "md", ...rest }) {
6
+ return (_jsx("button", { className: cx("cedros-data-btn", `cedros-data-btn--${variant}`, size === "sm" ? "cedros-data-btn--sm" : undefined, className), ...rest }));
7
+ }
8
+ export function Card({ title, subtitle, actions, children }) {
9
+ return (_jsxs("section", { className: "cedros-data-card", children: [(title || subtitle || actions) && (_jsxs("header", { className: "cedros-data-card__header", children: [_jsxs("div", { children: [title && _jsx("h3", { className: "cedros-data-card__title", children: title }), subtitle && _jsx("p", { className: "cedros-data-card__subtitle", children: subtitle })] }), actions] })), _jsx("div", { className: "cedros-data-card__body", children: children })] }));
10
+ }
11
+ export function TextInput({ label, className, ...rest }) {
12
+ return (_jsxs("label", { className: "cedros-data-field", children: [label && _jsx("span", { className: "cedros-data-label", children: label }), _jsx("input", { className: cx("cedros-data-input", className), ...rest })] }));
13
+ }
14
+ export function SelectInput({ label, className, children, ...rest }) {
15
+ return (_jsxs("label", { className: "cedros-data-field", children: [label && _jsx("span", { className: "cedros-data-label", children: label }), _jsx("select", { className: cx("cedros-data-select", className), ...rest, children: children })] }));
16
+ }
17
+ export function JsonEditor({ label, className, ...rest }) {
18
+ return (_jsxs("label", { className: "cedros-data-field", children: [label && _jsx("span", { className: "cedros-data-label", children: label }), _jsx("textarea", { className: cx("cedros-data-textarea", className), ...rest })] }));
19
+ }
20
+ export function StatusNotice({ tone, message }) {
21
+ return _jsx("div", { className: cx("cedros-data-status", `cedros-data-status--${tone}`), children: message });
22
+ }
@@ -0,0 +1,17 @@
1
+ export type DataOperation = "bootstrap" | "export" | "import";
2
+ export type DataOperationStatus = "success" | "error";
3
+ export interface DataOpsHistoryRecord {
4
+ id: string;
5
+ operation: DataOperation;
6
+ status: DataOperationStatus;
7
+ message: string;
8
+ createdAt: string;
9
+ artifact?: string;
10
+ }
11
+ export interface DataOpsHistoryMutationResult {
12
+ records: DataOpsHistoryRecord[];
13
+ warning?: string;
14
+ }
15
+ export declare function readDataOpsHistory(): DataOpsHistoryRecord[];
16
+ export declare function appendDataOpsHistory(record: Omit<DataOpsHistoryRecord, "id" | "createdAt">): DataOpsHistoryMutationResult;
17
+ export declare function clearDataOpsHistory(): DataOpsHistoryMutationResult;
@@ -0,0 +1,103 @@
1
+ const STORAGE_KEY = "cedros-data:data-ops-history";
2
+ const MAX_RECORDS = 100;
3
+ const MAX_ARTIFACT_LENGTH = 2_000;
4
+ const STORAGE_WARNING = "Local history could not be saved in browser storage. The operation still completed.";
5
+ export function readDataOpsHistory() {
6
+ return readAllRecords();
7
+ }
8
+ export function appendDataOpsHistory(record) {
9
+ const entry = {
10
+ id: `${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
11
+ createdAt: new Date().toISOString(),
12
+ ...record
13
+ };
14
+ entry.artifact = sanitizeArtifact(entry.artifact);
15
+ const records = [entry, ...readAllRecords()].slice(0, MAX_RECORDS);
16
+ return {
17
+ records,
18
+ warning: writeAllRecords(records)
19
+ };
20
+ }
21
+ export function clearDataOpsHistory() {
22
+ const records = [];
23
+ return {
24
+ records,
25
+ warning: writeAllRecords(records)
26
+ };
27
+ }
28
+ function readAllRecords() {
29
+ const storage = resolveLocalStorage();
30
+ if (!storage) {
31
+ return [];
32
+ }
33
+ try {
34
+ const raw = storage.getItem(STORAGE_KEY);
35
+ if (!raw) {
36
+ return [];
37
+ }
38
+ const parsed = JSON.parse(raw);
39
+ if (!Array.isArray(parsed)) {
40
+ return [];
41
+ }
42
+ const records = parsed.filter(isHistoryRecord).map(sanitizeHistoryRecord);
43
+ void writeAllRecords(records);
44
+ return records;
45
+ }
46
+ catch (_error) {
47
+ return [];
48
+ }
49
+ }
50
+ function writeAllRecords(records) {
51
+ const storage = resolveLocalStorage();
52
+ if (!storage) {
53
+ return STORAGE_WARNING;
54
+ }
55
+ try {
56
+ storage.setItem(STORAGE_KEY, JSON.stringify(records));
57
+ return undefined;
58
+ }
59
+ catch (_error) {
60
+ return STORAGE_WARNING;
61
+ }
62
+ }
63
+ function resolveLocalStorage() {
64
+ if (typeof window === "undefined") {
65
+ return null;
66
+ }
67
+ try {
68
+ return window.localStorage;
69
+ }
70
+ catch (_error) {
71
+ return null;
72
+ }
73
+ }
74
+ function isHistoryRecord(value) {
75
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
76
+ return false;
77
+ }
78
+ const item = value;
79
+ return (typeof item.id === "string" &&
80
+ typeof item.operation === "string" &&
81
+ typeof item.status === "string" &&
82
+ typeof item.message === "string" &&
83
+ typeof item.createdAt === "string" &&
84
+ (item.artifact === undefined || typeof item.artifact === "string"));
85
+ }
86
+ function sanitizeHistoryRecord(record) {
87
+ return {
88
+ ...record,
89
+ artifact: sanitizeArtifact(record.artifact)
90
+ };
91
+ }
92
+ function sanitizeArtifact(artifact) {
93
+ if (!artifact) {
94
+ return undefined;
95
+ }
96
+ if (artifact.length <= MAX_ARTIFACT_LENGTH) {
97
+ return artifact;
98
+ }
99
+ return JSON.stringify({
100
+ note: "Legacy payload snapshot omitted from local history.",
101
+ originalLength: artifact.length
102
+ }, null, 2);
103
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from "react";
2
+ export declare const Icons: {
3
+ pages: ReactNode;
4
+ navigation: ReactNode;
5
+ siteSettings: ReactNode;
6
+ media: ReactNode;
7
+ collections: ReactNode;
8
+ schemaDesigner: ReactNode;
9
+ contractVerify: ReactNode;
10
+ customData: ReactNode;
11
+ dataOps: ReactNode;
12
+ history: ReactNode;
13
+ tipping: ReactNode;
14
+ monetization: ReactNode;
15
+ };
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ function icon(path) {
3
+ return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: path, stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
4
+ }
5
+ export const Icons = {
6
+ pages: icon("M4 5h16M4 12h16M4 19h16"),
7
+ navigation: icon("M3 6h18M3 12h10M3 18h14"),
8
+ siteSettings: icon("M12 3v4M12 17v4M3 12h4M17 12h4M5.6 5.6l2.8 2.8M15.6 15.6l2.8 2.8M18.4 5.6l-2.8 2.8M8.4 15.6l-2.8 2.8"),
9
+ media: icon("M4 5a1 1 0 011-1h14a1 1 0 011 1v14a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM8.5 10a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM20 15l-5-5L6 20"),
10
+ collections: icon("M5 4h14v4H5zM5 10h14v4H5zM5 16h14v4H5z"),
11
+ schemaDesigner: icon("M4 7h16M4 12h16M4 17h10M17 17h3"),
12
+ contractVerify: icon("M12 3l7 3v6c0 5-3.5 8-7 9-3.5-1-7-4-7-9V6l7-3z"),
13
+ customData: icon("M6 4h12M4 8h16M8 12h8M8 16h8M6 20h12"),
14
+ dataOps: icon("M4 4h16v16H4z M8 8h8 M8 12h8 M8 16h4"),
15
+ history: icon("M12 8v5l3 2M20 12a8 8 0 11-2.34-5.66"),
16
+ tipping: icon("M12 2a7 7 0 00-7 7c0 5.25 7 13 7 13s7-7.75 7-13a7 7 0 00-7-7z"),
17
+ monetization: icon("M12 1v22M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6")
18
+ };
@@ -0,0 +1,13 @@
1
+ export type { AdminPlugin, AdminSectionConfig, AdminGroupConfig, AdminSectionProps, HostContext, PluginContext, PluginRegistry, PluginId, SectionId, QualifiedSectionId, PluginPermission } from "./types.js";
2
+ export { cedrosDataPlugin, dataPlugin } from "./plugin.js";
3
+ export { default as defaultDataPlugin } from "./plugin.js";
4
+ export { CEDROS_DATA_SECTIONS, CEDROS_DATA_SECTION_IDS, CEDROS_DATA_GROUPS } from "./sectionIds.js";
5
+ export { AdminButton, Card, TextInput, SelectInput, JsonEditor, StatusNotice } from "./components.js";
6
+ export { DataTable, type DataTableProps, type DataTableColumn } from "./primitives/DataTable.js";
7
+ export { Toolbar, SearchInput, FilterChips, type FilterChipItem } from "./primitives/Toolbar.js";
8
+ export { Pagination } from "./primitives/Pagination.js";
9
+ export { JsonCodeEditor } from "./primitives/JsonCodeEditor.js";
10
+ export { DiffViewer, type DiffBlock } from "./primitives/DiffViewer.js";
11
+ export { FormFieldRow, FieldTypeSelect, type FormFieldRowValue, type FieldTypeOption } from "./primitives/FormFieldRow.js";
12
+ export { ConfirmDialog } from "./primitives/ConfirmDialog.js";
13
+ export { ToastProvider, useToast, InlineAlert, type AlertTone } from "./primitives/alerts.js";
@@ -0,0 +1,12 @@
1
+ export { cedrosDataPlugin, dataPlugin } from "./plugin.js";
2
+ export { default as defaultDataPlugin } from "./plugin.js";
3
+ export { CEDROS_DATA_SECTIONS, CEDROS_DATA_SECTION_IDS, CEDROS_DATA_GROUPS } from "./sectionIds.js";
4
+ export { AdminButton, Card, TextInput, SelectInput, JsonEditor, StatusNotice } from "./components.js";
5
+ export { DataTable } from "./primitives/DataTable.js";
6
+ export { Toolbar, SearchInput, FilterChips } from "./primitives/Toolbar.js";
7
+ export { Pagination } from "./primitives/Pagination.js";
8
+ export { JsonCodeEditor } from "./primitives/JsonCodeEditor.js";
9
+ export { DiffViewer } from "./primitives/DiffViewer.js";
10
+ export { FormFieldRow, FieldTypeSelect } from "./primitives/FormFieldRow.js";
11
+ export { ConfirmDialog } from "./primitives/ConfirmDialog.js";
12
+ export { ToastProvider, useToast, InlineAlert } from "./primitives/alerts.js";
@@ -0,0 +1,4 @@
1
+ export type CedrosDataPermission = "data:pages:read" | "data:pages:write" | "data:navigation:read" | "data:navigation:write" | "data:settings:read" | "data:settings:write" | "data:collections:read" | "data:collections:write" | "data:schema:read" | "data:schema:write" | "data:contract:read" | "data:contract:write" | "data:custom:read" | "data:custom:write" | "data:media:read" | "data:media:write" | "data:history:read" | "data:ops:write" | "data:admin";
2
+ export declare const PERMISSION_MAP: Record<CedrosDataPermission, string[]>;
3
+ export declare function readPermissionForCollection(collectionName: string): CedrosDataPermission;
4
+ export declare function writePermissionForCollection(collectionName: string): CedrosDataPermission;
@@ -0,0 +1,45 @@
1
+ export const PERMISSION_MAP = {
2
+ "data:pages:read": ["owner", "admin", "data:pages:read", "data:admin"],
3
+ "data:pages:write": ["owner", "admin", "data:pages:write", "data:admin"],
4
+ "data:navigation:read": ["owner", "admin", "data:navigation:read", "data:admin"],
5
+ "data:navigation:write": ["owner", "admin", "data:navigation:write", "data:admin"],
6
+ "data:settings:read": ["owner", "admin", "data:settings:read", "data:admin"],
7
+ "data:settings:write": ["owner", "admin", "data:settings:write", "data:admin"],
8
+ "data:collections:read": ["owner", "admin", "data:collections:read", "data:admin"],
9
+ "data:collections:write": ["owner", "admin", "data:collections:write", "data:admin"],
10
+ "data:schema:read": ["owner", "admin", "data:schema:read", "data:admin"],
11
+ "data:schema:write": ["owner", "admin", "data:schema:write", "data:admin"],
12
+ "data:contract:read": ["owner", "admin", "data:contract:read", "data:admin"],
13
+ "data:contract:write": ["owner", "admin", "data:contract:write", "data:admin"],
14
+ "data:custom:read": ["owner", "admin", "data:custom:read", "data:admin"],
15
+ "data:custom:write": ["owner", "admin", "data:custom:write", "data:admin"],
16
+ "data:media:read": ["owner", "admin", "data:media:read", "data:admin"],
17
+ "data:media:write": ["owner", "admin", "data:media:write", "data:admin"],
18
+ "data:history:read": ["owner", "admin", "data:history:read", "data:admin"],
19
+ "data:ops:write": ["owner", "admin", "data:ops:write", "data:admin"],
20
+ "data:admin": ["owner", "admin", "data:admin"]
21
+ };
22
+ export function readPermissionForCollection(collectionName) {
23
+ switch (collectionName) {
24
+ case "pages":
25
+ return "data:pages:read";
26
+ case "navigation":
27
+ return "data:navigation:read";
28
+ case "site_settings":
29
+ return "data:settings:read";
30
+ default:
31
+ return "data:custom:read";
32
+ }
33
+ }
34
+ export function writePermissionForCollection(collectionName) {
35
+ switch (collectionName) {
36
+ case "pages":
37
+ return "data:pages:write";
38
+ case "navigation":
39
+ return "data:navigation:write";
40
+ case "site_settings":
41
+ return "data:settings:write";
42
+ default:
43
+ return "data:custom:write";
44
+ }
45
+ }
@@ -0,0 +1,4 @@
1
+ import type { AdminPlugin } from "./types.js";
2
+ export declare const cedrosDataPlugin: AdminPlugin;
3
+ export { cedrosDataPlugin as dataPlugin };
4
+ export default cedrosDataPlugin;