@drawnagency/primitives 0.1.0 → 0.2.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 (139) hide show
  1. package/dist/auth/index.js +26 -3
  2. package/dist/chunk-2VTPWODA.js +60 -0
  3. package/dist/chunk-CS7F6IOY.js +39 -0
  4. package/dist/chunk-HOJAF4VD.js +264 -0
  5. package/dist/chunk-IP6ODLXX.js +341 -0
  6. package/dist/chunk-T4BJ6RSB.js +58 -0
  7. package/dist/chunk-UKEVUCIZ.js +200 -0
  8. package/dist/chunk-UMSFICAC.js +36 -0
  9. package/dist/index.js +156 -4
  10. package/dist/lib/index.js +62 -12
  11. package/dist/lib/sanitize.d.ts.map +1 -1
  12. package/dist/media/index.js +36 -9
  13. package/dist/schemas/index.js +52 -7
  14. package/package.json +5 -4
  15. package/src/lib/sanitize.ts +6 -2
  16. package/dist/auth/cookies.js +0 -44
  17. package/dist/auth/errors.js +0 -10
  18. package/dist/auth/security.js +0 -48
  19. package/dist/auth/types.js +0 -1
  20. package/dist/components/brandguide/ColorSwatchSettings.js +0 -10
  21. package/dist/components/brandguide/Colors.js +0 -79
  22. package/dist/components/brandguide/DoDontList.js +0 -22
  23. package/dist/components/brandguide/DoDontMediaGrid.js +0 -5
  24. package/dist/components/editor/AudiencePicker.js +0 -24
  25. package/dist/components/editor/DeleteButton.js +0 -6
  26. package/dist/components/editor/DragHandle.js +0 -8
  27. package/dist/components/editor/InsertButton.js +0 -7
  28. package/dist/components/editor/SectionWrapper.js +0 -135
  29. package/dist/components/editor/SettingsButton.js +0 -6
  30. package/dist/components/editor/SettingsForm.js +0 -64
  31. package/dist/components/editor/StatusBadge.js +0 -10
  32. package/dist/components/editor/StatusPicker.js +0 -30
  33. package/dist/components/editor/index.js +0 -7
  34. package/dist/components/primitives/CustomParagraph.js +0 -24
  35. package/dist/components/primitives/EditableGrid.js +0 -90
  36. package/dist/components/primitives/EditableList.js +0 -54
  37. package/dist/components/primitives/EditablePlainText.js +0 -52
  38. package/dist/components/primitives/EditableRichText.js +0 -86
  39. package/dist/components/primitives/HeadingSection.js +0 -7
  40. package/dist/components/primitives/IconPicker.js +0 -21
  41. package/dist/components/primitives/LinkPopover.js +0 -48
  42. package/dist/components/primitives/MediaSettingsForms.js +0 -42
  43. package/dist/components/primitives/ResolvedMedia.js +0 -9
  44. package/dist/components/primitives/RichTextToolbar.js +0 -26
  45. package/dist/components/primitives/tiptap-presets.js +0 -44
  46. package/dist/components/primitives/useEditableCollection.js +0 -61
  47. package/dist/components/primitives/useEditablePlainText.js +0 -27
  48. package/dist/components/primitives/useEditableRichText.js +0 -52
  49. package/dist/components/sections/Button/CTAButton.js +0 -18
  50. package/dist/components/sections/Button/index.js +0 -28
  51. package/dist/components/sections/Colors/index.js +0 -34
  52. package/dist/components/sections/DoDontList/index.js +0 -33
  53. package/dist/components/sections/DoDontMediaGrid/index.js +0 -41
  54. package/dist/components/sections/IconList/IconList.js +0 -131
  55. package/dist/components/sections/IconList/IconListSettings.js +0 -22
  56. package/dist/components/sections/IconList/index.js +0 -27
  57. package/dist/components/sections/LinkHeading/index.js +0 -15
  58. package/dist/components/sections/MediaGrid/MediaGrid.js +0 -62
  59. package/dist/components/sections/MediaGrid/index.js +0 -35
  60. package/dist/components/sections/Prose/Prose.js +0 -11
  61. package/dist/components/sections/Prose/index.js +0 -15
  62. package/dist/components/sections/SectionLayout.js +0 -15
  63. package/dist/components/sections/SplitContent/SplitContent.js +0 -31
  64. package/dist/components/sections/SplitContent/SplitContentSettings.js +0 -17
  65. package/dist/components/sections/SplitContent/index.js +0 -27
  66. package/dist/components/sections/SubHeading/index.js +0 -18
  67. package/dist/components/sections/SubSubHeading/index.js +0 -18
  68. package/dist/components/sections/ViewRenderer.js +0 -13
  69. package/dist/components/sections/register-schemas.js +0 -15
  70. package/dist/components/sections/register.js +0 -15
  71. package/dist/components/shared/Button.js +0 -27
  72. package/dist/components/shared/Checkbox.js +0 -10
  73. package/dist/components/shared/ColorPicker.js +0 -5
  74. package/dist/components/shared/ErrorBoundary.js +0 -30
  75. package/dist/components/shared/FontPicker.js +0 -190
  76. package/dist/components/shared/FormLabel.js +0 -5
  77. package/dist/components/shared/IconButton.js +0 -16
  78. package/dist/components/shared/Input.js +0 -8
  79. package/dist/components/shared/Navigation.js +0 -71
  80. package/dist/components/shared/PasswordInput.js +0 -11
  81. package/dist/components/shared/Popover.js +0 -33
  82. package/dist/components/shared/PopoverItem.js +0 -6
  83. package/dist/components/shared/Select.js +0 -9
  84. package/dist/components/shared/Textarea.js +0 -8
  85. package/dist/components/shared/Toggle.js +0 -5
  86. package/dist/components/shared/Tooltip.js +0 -8
  87. package/dist/components/shared/icons.js +0 -23
  88. package/dist/components/shell/AudienceAddForm.js +0 -43
  89. package/dist/components/shell/AudienceRow.js +0 -74
  90. package/dist/components/shell/EditorContext.js +0 -24
  91. package/dist/components/shell/EditorLoginForm.js +0 -46
  92. package/dist/components/shell/EditorModal.js +0 -43
  93. package/dist/components/shell/EditorModalContext.js +0 -20
  94. package/dist/components/shell/EditorShell.js +0 -483
  95. package/dist/components/shell/MediaLibraryContext.js +0 -5
  96. package/dist/components/shell/MediaLibraryModal.js +0 -145
  97. package/dist/components/shell/ProcessingIndicator.js +0 -15
  98. package/dist/components/shell/SectionSkeleton.js +0 -22
  99. package/dist/components/shell/SectionTypePicker.js +0 -15
  100. package/dist/components/shell/SiteSettingsDisplay.js +0 -28
  101. package/dist/components/shell/SiteSettingsModal.js +0 -40
  102. package/dist/components/shell/SiteSettingsUsers.js +0 -87
  103. package/dist/components/shell/SiteSettingsViewerAccess.js +0 -94
  104. package/dist/components/shell/ViewerLoginForm.js +0 -40
  105. package/dist/data/google-fonts.json +0 -7718
  106. package/dist/hooks/index.js +0 -6
  107. package/dist/hooks/useActiveHeadings.js +0 -99
  108. package/dist/hooks/useEditorPersistence.js +0 -73
  109. package/dist/hooks/useEditorPublish.js +0 -145
  110. package/dist/hooks/useFocusTrap.js +0 -51
  111. package/dist/hooks/useMediaPipeline.js +0 -253
  112. package/dist/hooks/useResolvedMedia.js +0 -39
  113. package/dist/lib/cn.js +0 -5
  114. package/dist/lib/contrast.js +0 -11
  115. package/dist/lib/dexie.js +0 -236
  116. package/dist/lib/events.js +0 -15
  117. package/dist/lib/google-fonts.js +0 -11
  118. package/dist/lib/grid.js +0 -7
  119. package/dist/lib/icons.js +0 -27
  120. package/dist/lib/loader.js +0 -57
  121. package/dist/lib/nav.js +0 -58
  122. package/dist/lib/registry.js +0 -64
  123. package/dist/lib/safeRedirect.js +0 -11
  124. package/dist/lib/sanitize.js +0 -6
  125. package/dist/lib/timestamp.js +0 -28
  126. package/dist/media/github.js +0 -60
  127. package/dist/media/queue.js +0 -116
  128. package/dist/media/resolve.js +0 -50
  129. package/dist/media/types.js +0 -1
  130. package/dist/media/utils.js +0 -41
  131. package/dist/media/videoPoster.js +0 -44
  132. package/dist/media/worker.js +0 -73
  133. package/dist/schemas/audience.js +0 -19
  134. package/dist/schemas/auth.js +0 -22
  135. package/dist/schemas/media-grid-options.js +0 -7
  136. package/dist/schemas/media.js +0 -28
  137. package/dist/schemas/sections.js +0 -12
  138. package/dist/schemas/shared.js +0 -71
  139. package/dist/schemas/site-config.js +0 -26
package/dist/index.js CHANGED
@@ -1,4 +1,156 @@
1
- export * from "./schemas";
2
- export * from "./lib";
3
- export * from "./auth";
4
- export * from "./media";
1
+ import {
2
+ AudienceColorSchema,
3
+ AudienceNameSchema,
4
+ AudienceSchema,
5
+ MediaGridOptionsSchema,
6
+ RoleSchema,
7
+ SessionSchema,
8
+ SiteUserSchema,
9
+ slugifyAudienceName
10
+ } from "./chunk-T4BJ6RSB.js";
11
+ import {
12
+ buildGoogleFontsUrl,
13
+ cn,
14
+ createEvent,
15
+ curatedIcons,
16
+ darkModeEvent,
17
+ deriveContrast,
18
+ editModeEvent,
19
+ formatTimestamp,
20
+ generateNavLinks,
21
+ getIcon,
22
+ gridColsClass,
23
+ loadSiteContent,
24
+ loadStaticSiteContent,
25
+ mergeSiteContent,
26
+ navChangeEvent,
27
+ safeRedirect,
28
+ sanitizeHtml,
29
+ toSectionId
30
+ } from "./chunk-HOJAF4VD.js";
31
+ import {
32
+ ColorItemSchema,
33
+ ColorSpaceSchema,
34
+ HexColorSchema,
35
+ IndexSchema,
36
+ MediaReferenceSchema,
37
+ SectionMetaSchema,
38
+ SiteConfigSchema,
39
+ TextLineSchema,
40
+ clearRegistry,
41
+ createRegistry,
42
+ defineSection,
43
+ getAllSchemas,
44
+ getAllSections,
45
+ getSchema,
46
+ getSection,
47
+ getSectionContentSchema,
48
+ getSectionSchema,
49
+ registerSchema,
50
+ registerSection
51
+ } from "./chunk-UKEVUCIZ.js";
52
+ import {
53
+ AUDIENCE_COOKIE,
54
+ LastOwnerError,
55
+ SESSION_COOKIE,
56
+ SESSION_MAX_AGE_SECONDS,
57
+ setSessionCookie,
58
+ signSessionToken,
59
+ verifySessionToken
60
+ } from "./chunk-2VTPWODA.js";
61
+ import {
62
+ isSameOriginRequest,
63
+ requireSessionSecret,
64
+ safeNextPath
65
+ } from "./chunk-CS7F6IOY.js";
66
+ import {
67
+ EXT_TO_MIME,
68
+ MIME_TO_EXT,
69
+ ProcessingQueue,
70
+ createMediaAdapter,
71
+ displayFilenameExt,
72
+ generateVideoPoster,
73
+ hashFileBuffer,
74
+ mimeToExt,
75
+ resolveManifestReferences,
76
+ resolveMedia,
77
+ sanitizeMediaName
78
+ } from "./chunk-IP6ODLXX.js";
79
+ import {
80
+ ImageManifestSchema,
81
+ MediaConfigSchema,
82
+ MediaItemSchema,
83
+ VariantSchema
84
+ } from "./chunk-UMSFICAC.js";
85
+ export {
86
+ AUDIENCE_COOKIE,
87
+ AudienceColorSchema,
88
+ AudienceNameSchema,
89
+ AudienceSchema,
90
+ ColorItemSchema,
91
+ ColorSpaceSchema,
92
+ EXT_TO_MIME,
93
+ HexColorSchema,
94
+ ImageManifestSchema,
95
+ IndexSchema,
96
+ LastOwnerError,
97
+ MIME_TO_EXT,
98
+ MediaConfigSchema,
99
+ MediaGridOptionsSchema,
100
+ MediaItemSchema,
101
+ MediaReferenceSchema,
102
+ ProcessingQueue,
103
+ RoleSchema,
104
+ SESSION_COOKIE,
105
+ SESSION_MAX_AGE_SECONDS,
106
+ SectionMetaSchema,
107
+ SessionSchema,
108
+ SiteConfigSchema,
109
+ SiteUserSchema,
110
+ TextLineSchema,
111
+ VariantSchema,
112
+ buildGoogleFontsUrl,
113
+ clearRegistry,
114
+ cn,
115
+ createEvent,
116
+ createMediaAdapter,
117
+ createRegistry,
118
+ curatedIcons,
119
+ darkModeEvent,
120
+ defineSection,
121
+ deriveContrast,
122
+ displayFilenameExt,
123
+ editModeEvent,
124
+ formatTimestamp,
125
+ generateNavLinks,
126
+ generateVideoPoster,
127
+ getAllSchemas,
128
+ getAllSections,
129
+ getIcon,
130
+ getSchema,
131
+ getSection,
132
+ getSectionContentSchema,
133
+ getSectionSchema,
134
+ gridColsClass,
135
+ hashFileBuffer,
136
+ isSameOriginRequest,
137
+ loadSiteContent,
138
+ loadStaticSiteContent,
139
+ mergeSiteContent,
140
+ mimeToExt,
141
+ navChangeEvent,
142
+ registerSchema,
143
+ registerSection,
144
+ requireSessionSecret,
145
+ resolveManifestReferences,
146
+ resolveMedia,
147
+ safeNextPath,
148
+ safeRedirect,
149
+ sanitizeHtml,
150
+ sanitizeMediaName,
151
+ setSessionCookie,
152
+ signSessionToken,
153
+ slugifyAudienceName,
154
+ toSectionId,
155
+ verifySessionToken
156
+ };
package/dist/lib/index.js CHANGED
@@ -1,12 +1,62 @@
1
- export { cn } from "./cn";
2
- export { generateNavLinks, toSectionId } from "./nav";
3
- export { deriveContrast } from "./contrast";
4
- export { sanitizeHtml } from "./sanitize";
5
- export { gridColsClass } from "./grid";
6
- export { getIcon, curatedIcons } from "./icons";
7
- export { buildGoogleFontsUrl } from "./google-fonts";
8
- export { formatTimestamp } from "./timestamp";
9
- export { safeRedirect } from "./safeRedirect";
10
- export { createEvent, editModeEvent, navChangeEvent, darkModeEvent } from "./events";
11
- export { createRegistry, defineSection, registerSection, registerSchema, getSection, getSchema, getAllSections, getAllSchemas, clearRegistry, } from "./registry";
12
- export { mergeSiteContent, loadStaticSiteContent, loadSiteContent, } from "./loader";
1
+ import {
2
+ buildGoogleFontsUrl,
3
+ cn,
4
+ createEvent,
5
+ curatedIcons,
6
+ darkModeEvent,
7
+ deriveContrast,
8
+ editModeEvent,
9
+ formatTimestamp,
10
+ generateNavLinks,
11
+ getIcon,
12
+ gridColsClass,
13
+ loadSiteContent,
14
+ loadStaticSiteContent,
15
+ mergeSiteContent,
16
+ navChangeEvent,
17
+ safeRedirect,
18
+ sanitizeHtml,
19
+ toSectionId
20
+ } from "../chunk-HOJAF4VD.js";
21
+ import {
22
+ clearRegistry,
23
+ createRegistry,
24
+ defineSection,
25
+ getAllSchemas,
26
+ getAllSections,
27
+ getSchema,
28
+ getSection,
29
+ registerSchema,
30
+ registerSection
31
+ } from "../chunk-UKEVUCIZ.js";
32
+ import "../chunk-CS7F6IOY.js";
33
+ import "../chunk-UMSFICAC.js";
34
+ export {
35
+ buildGoogleFontsUrl,
36
+ clearRegistry,
37
+ cn,
38
+ createEvent,
39
+ createRegistry,
40
+ curatedIcons,
41
+ darkModeEvent,
42
+ defineSection,
43
+ deriveContrast,
44
+ editModeEvent,
45
+ formatTimestamp,
46
+ generateNavLinks,
47
+ getAllSchemas,
48
+ getAllSections,
49
+ getIcon,
50
+ getSchema,
51
+ getSection,
52
+ gridColsClass,
53
+ loadSiteContent,
54
+ loadStaticSiteContent,
55
+ mergeSiteContent,
56
+ navChangeEvent,
57
+ registerSchema,
58
+ registerSection,
59
+ safeRedirect,
60
+ sanitizeHtml,
61
+ toSectionId
62
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/lib/sanitize.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD"}
1
+ {"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/lib/sanitize.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD"}
@@ -1,9 +1,36 @@
1
- import { createGitHubMediaAdapter } from "./github";
2
- export * from "./types";
3
- export * from "./utils";
4
- export * from "./queue";
5
- export * from "./resolve";
6
- export { generateVideoPoster } from "./videoPoster";
7
- export function createMediaAdapter(manifest) {
8
- return createGitHubMediaAdapter(manifest);
9
- }
1
+ import {
2
+ EXT_TO_MIME,
3
+ MIME_TO_EXT,
4
+ ProcessingQueue,
5
+ createMediaAdapter,
6
+ displayFilenameExt,
7
+ generateVideoPoster,
8
+ hashFileBuffer,
9
+ mimeToExt,
10
+ resolveManifestReferences,
11
+ resolveMedia,
12
+ sanitizeMediaName
13
+ } from "../chunk-IP6ODLXX.js";
14
+ import {
15
+ ImageManifestSchema,
16
+ MediaConfigSchema,
17
+ MediaItemSchema,
18
+ VariantSchema
19
+ } from "../chunk-UMSFICAC.js";
20
+ export {
21
+ EXT_TO_MIME,
22
+ ImageManifestSchema,
23
+ MIME_TO_EXT,
24
+ MediaConfigSchema,
25
+ MediaItemSchema,
26
+ ProcessingQueue,
27
+ VariantSchema,
28
+ createMediaAdapter,
29
+ displayFilenameExt,
30
+ generateVideoPoster,
31
+ hashFileBuffer,
32
+ mimeToExt,
33
+ resolveManifestReferences,
34
+ resolveMedia,
35
+ sanitizeMediaName
36
+ };
@@ -1,7 +1,52 @@
1
- export * from "./shared";
2
- export * from "./sections";
3
- export * from "./site-config";
4
- export * from "./media";
5
- export * from "./audience";
6
- export * from "./media-grid-options";
7
- export * from "./auth";
1
+ import {
2
+ AudienceColorSchema,
3
+ AudienceNameSchema,
4
+ AudienceSchema,
5
+ MediaGridOptionsSchema,
6
+ RoleSchema,
7
+ SessionSchema,
8
+ SiteUserSchema,
9
+ slugifyAudienceName
10
+ } from "../chunk-T4BJ6RSB.js";
11
+ import {
12
+ ColorItemSchema,
13
+ ColorSpaceSchema,
14
+ HexColorSchema,
15
+ IndexSchema,
16
+ MediaReferenceSchema,
17
+ SectionMetaSchema,
18
+ SiteConfigSchema,
19
+ TextLineSchema,
20
+ getSectionContentSchema,
21
+ getSectionSchema
22
+ } from "../chunk-UKEVUCIZ.js";
23
+ import {
24
+ ImageManifestSchema,
25
+ MediaConfigSchema,
26
+ MediaItemSchema,
27
+ VariantSchema
28
+ } from "../chunk-UMSFICAC.js";
29
+ export {
30
+ AudienceColorSchema,
31
+ AudienceNameSchema,
32
+ AudienceSchema,
33
+ ColorItemSchema,
34
+ ColorSpaceSchema,
35
+ HexColorSchema,
36
+ ImageManifestSchema,
37
+ IndexSchema,
38
+ MediaConfigSchema,
39
+ MediaGridOptionsSchema,
40
+ MediaItemSchema,
41
+ MediaReferenceSchema,
42
+ RoleSchema,
43
+ SectionMetaSchema,
44
+ SessionSchema,
45
+ SiteConfigSchema,
46
+ SiteUserSchema,
47
+ TextLineSchema,
48
+ VariantSchema,
49
+ getSectionContentSchema,
50
+ getSectionSchema,
51
+ slugifyAudienceName
52
+ };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "exports": {
6
+ "./package.json": "./package.json",
6
7
  ".": {
7
8
  "types": "./dist/index.d.ts",
8
9
  "default": "./dist/index.js"
@@ -37,7 +38,7 @@
37
38
  "zod": "^4.3.6",
38
39
  "clsx": "^2.1.1",
39
40
  "tailwind-merge": "^3.5.0",
40
- "isomorphic-dompurify": "^3.10.0",
41
+ "dompurify": "^3.2.6",
41
42
  "lucide-react": "^1.7.0",
42
43
  "jose": "^6.2.2",
43
44
  "dexie": "^4.4.2",
@@ -51,7 +52,7 @@
51
52
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0"
52
53
  },
53
54
  "scripts": {
54
- "build": "tsc",
55
- "dev": "tsc --watch"
55
+ "build": "tsup && rm -f tsconfig.tsbuildinfo && tsc --emitDeclarationOnly",
56
+ "dev": "tsup --watch"
56
57
  }
57
58
  }
@@ -1,6 +1,10 @@
1
- import DOMPurify from "isomorphic-dompurify";
1
+ let purifier: { sanitize: (html: string) => string } | undefined;
2
+
3
+ if (typeof window !== "undefined") {
4
+ import("dompurify").then((m) => { purifier = m.default; });
5
+ }
2
6
 
3
7
  export function sanitizeHtml(html: string): string {
4
8
  if (!html) return "";
5
- return DOMPurify.sanitize(html);
9
+ return purifier ? purifier.sanitize(html) : html;
6
10
  }
@@ -1,44 +0,0 @@
1
- import * as jose from "jose";
2
- import { requireSessionSecret } from "./security";
3
- export const SESSION_COOKIE = "bp-session";
4
- export const AUDIENCE_COOKIE = "bp-audience";
5
- export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
6
- export async function signSessionToken(session) {
7
- return new jose.SignJWT({
8
- userId: session.userId,
9
- email: session.email,
10
- role: session.role,
11
- siteId: session.siteId,
12
- })
13
- .setProtectedHeader({ alg: "HS256" })
14
- .setExpirationTime(`${SESSION_MAX_AGE_SECONDS}s`)
15
- .setIssuedAt()
16
- .sign(requireSessionSecret());
17
- }
18
- export async function verifySessionToken(token) {
19
- const secret = requireSessionSecret(); // throws on misconfiguration, before try
20
- try {
21
- const { payload } = await jose.jwtVerify(token, secret);
22
- const role = payload.role;
23
- if (role !== "owner" && role !== "editor")
24
- return null;
25
- return {
26
- userId: payload.userId ?? null,
27
- email: payload.email ?? null,
28
- role,
29
- siteId: payload.siteId,
30
- };
31
- }
32
- catch {
33
- return null;
34
- }
35
- }
36
- export function setSessionCookie(cookies, token, isProduction) {
37
- cookies.set(SESSION_COOKIE, token, {
38
- httpOnly: true,
39
- secure: isProduction,
40
- sameSite: "lax",
41
- path: "/",
42
- maxAge: SESSION_MAX_AGE_SECONDS,
43
- });
44
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * Thrown when a mutation would leave a site with zero owners.
3
- * API routes should translate this to HTTP 409 Conflict with the message.
4
- */
5
- export class LastOwnerError extends Error {
6
- constructor(message = "Cannot remove the last owner") {
7
- super(message);
8
- this.name = "LastOwnerError";
9
- }
10
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * Shared auth security primitives: session secret loader, same-origin check,
3
- * redirect-path validator. Imported by cookies.ts, middleware, and auth API routes.
4
- */
5
- export function requireSessionSecret() {
6
- const secret = import.meta.env.SESSION_SECRET;
7
- if (!secret) {
8
- throw new Error("SESSION_SECRET is required but not set");
9
- }
10
- const bytes = new TextEncoder().encode(secret);
11
- if (bytes.byteLength < 32) {
12
- throw new Error("SESSION_SECRET must be at least 32 bytes");
13
- }
14
- return bytes;
15
- }
16
- /**
17
- * Same-origin check for CSRF protection on state-changing requests.
18
- * Combine with an HTTP-method guard at the call site — this does not
19
- * discriminate between safe (GET/HEAD) and unsafe methods.
20
- */
21
- export function isSameOriginRequest(request) {
22
- const origin = request.headers.get("Origin");
23
- const referer = request.headers.get("Referer");
24
- const source = origin ?? referer;
25
- if (!source)
26
- return false;
27
- try {
28
- const sourceOrigin = new URL(source).origin;
29
- const requestOrigin = new URL(request.url).origin;
30
- return sourceOrigin === requestOrigin;
31
- }
32
- catch {
33
- return false;
34
- }
35
- }
36
- export function safeNextPath(next) {
37
- if (!next)
38
- return null;
39
- if (!next.startsWith("/"))
40
- return null;
41
- if (next.startsWith("//"))
42
- return null;
43
- if (next.includes("\\"))
44
- return null;
45
- if (/[\x00-\x1f]/.test(next))
46
- return null;
47
- return next;
48
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,10 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Input } from "../shared/Input";
3
- export default function ColorSwatchSettings({ color, onChange }) {
4
- const space = color.spaces[0] || {};
5
- const updateSpace = (key, value) => {
6
- const newSpace = { ...space, [key]: value || undefined };
7
- onChange({ ...color, spaces: [newSpace, ...color.spaces.slice(1)] });
8
- };
9
- return (_jsxs("div", { className: "space-y-3", children: [_jsx(Input, { label: "Name", value: color.name || "", onChange: (value) => onChange({ ...color, name: value }) }), ["hex", "rgb", "cmyk", "pantone"].map((key) => (_jsx(Input, { label: key.toUpperCase(), value: space[key] || "", onChange: (value) => updateSpace(key, value) }, key)))] }));
10
- }
@@ -1,79 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
3
- import { Eye, EyeOff } from "lucide-react";
4
- import { cn } from "../../lib/cn";
5
- import { gridColsClass } from "../../lib/grid";
6
- import { EditableGrid } from "../primitives/EditableGrid";
7
- import { EditablePlainText } from "../primitives/EditablePlainText";
8
- import ColorSwatchSettings from "./ColorSwatchSettings";
9
- function getContrastClass(hex) {
10
- if (!hex)
11
- return "text-white";
12
- const h = hex.replace("#", "");
13
- if (h.length < 6)
14
- return "text-white";
15
- const r = parseInt(h.substring(0, 2), 16);
16
- const g = parseInt(h.substring(2, 4), 16);
17
- const b = parseInt(h.substring(4, 6), 16);
18
- const yiq = (r * 299 + g * 587 + b * 114) / 1000;
19
- return yiq >= 128 ? "text-black" : "text-white";
20
- }
21
- const createColorItem = () => ({
22
- name: "",
23
- spaces: [{ hex: "#cccccc" }],
24
- });
25
- function buildContent(colors, options) {
26
- const { label, columns, collapsing, showLabel } = options;
27
- return {
28
- type: "colors",
29
- content: { colors },
30
- ...(label || columns || collapsing !== undefined || showLabel !== undefined
31
- ? { options: { label, columns, collapsing, showLabel } }
32
- : {}),
33
- };
34
- }
35
- export default function Colors({ colors, columns = 3, label, collapsing, showLabel = true, onChange, openModal }) {
36
- if (onChange && openModal) {
37
- return (_jsx(ColorsEditable, { colors: colors, columns: columns, label: label, collapsing: collapsing, showLabel: showLabel, onChange: onChange, openModal: openModal }));
38
- }
39
- return _jsx(ColorsView, { colors: colors, columns: columns, label: label, collapsing: collapsing, showLabel: showLabel });
40
- }
41
- function ColorsView({ colors, columns, label, collapsing, showLabel, }) {
42
- const [expanded, setExpanded] = useState(!collapsing);
43
- const [copiedValue, setCopiedValue] = useState(null);
44
- const handleCopy = (value) => {
45
- navigator.clipboard.writeText(value);
46
- setCopiedValue(value);
47
- setTimeout(() => setCopiedValue(null), 1500);
48
- };
49
- return (_jsxs("div", { children: [(showLabel && !!label || collapsing) && (_jsxs("div", { className: "mb-4 flex items-center gap-2", children: [showLabel && !!label && (_jsx("span", { className: "text-lg font-bold", children: label })), collapsing && (_jsxs("button", { onClick: () => setExpanded(!expanded), className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast", children: [_jsx("span", { children: expanded ? "Hide Details" : "Show Details" }), expanded ? _jsx(EyeOff, { size: 16 }) : _jsx(Eye, { size: 16 })] }))] })), _jsx("div", { className: cn("grid gap-4", gridColsClass[columns] || "grid-cols-3"), children: colors.map((color, i) => {
50
- const hex = color.spaces[0]?.hex;
51
- const contrast = getContrastClass(hex);
52
- return (_jsxs("div", { className: "overflow-hidden rounded-md border border-base-200", children: [_jsx("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: color.name && _jsx("span", { className: "text-sm font-bold", children: color.name }) }), expanded && (_jsx("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map((space, j) => Object.entries(space).map(([key, value]) => value ? (_jsxs("button", { onClick: () => handleCopy(value), className: "cursor-pointer flex w-full justify-between hover:text-primary", children: [_jsx("span", { className: "font-medium uppercase", children: key }), _jsx("span", { children: copiedValue === value ? "Copied!" : value })] }, `${j}-${key}`)) : null)) }))] }, i));
53
- }) })] }));
54
- }
55
- function ColorsEditable({ colors, columns, label, collapsing, showLabel, onChange, openModal, }) {
56
- const [expanded, setExpanded] = useState(!collapsing);
57
- const options = { label, columns, collapsing, showLabel };
58
- // Sync expanded state when collapsing option changes via settings
59
- useEffect(() => {
60
- setExpanded(!collapsing);
61
- }, [collapsing]);
62
- const handleItemSettings = (index) => {
63
- const color = colors[index];
64
- openModal("Color Settings", _jsx(ColorSwatchSettings, { color: color, onChange: (updated) => {
65
- const newColors = colors.map((c, i) => (i === index ? updated : c));
66
- onChange(buildContent(newColors, options));
67
- } }));
68
- };
69
- return (_jsxs("div", { children: [(showLabel && !!label || collapsing) && (_jsxs("div", { className: "mb-4 flex items-center gap-2", children: [showLabel && !!label && (_jsx(EditablePlainText, { tag: "span", value: label, onChange: (newLabel) => onChange(buildContent(colors, { ...options, label: newLabel })), isEditMode: true, className: "text-lg font-bold" })), collapsing && (_jsxs("button", { onClick: () => setExpanded(!expanded), className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast", children: [_jsx("span", { children: expanded ? "Hide Details" : "Show Details" }), expanded ? _jsx(EyeOff, { size: 16 }) : _jsx(Eye, { size: 16 })] }))] })), _jsx(EditableGrid, { items: colors, columns: columns, onChange: (newColors) => onChange(buildContent(newColors, options)), createItem: createColorItem, isEditMode: true, onItemSettings: handleItemSettings, renderItem: (color, { index }) => (_jsx(ColorSwatchEditable, { color: color, index: index, colors: colors, options: options, onChange: onChange, expanded: expanded })) })] }));
70
- }
71
- function ColorSwatchEditable({ color, index, colors, options, onChange, expanded, }) {
72
- const hex = color.spaces[0]?.hex;
73
- const contrast = getContrastClass(hex);
74
- const updateColor = (updated) => {
75
- const newColors = colors.map((c, i) => (i === index ? updated : c));
76
- onChange(buildContent(newColors, options));
77
- };
78
- return (_jsxs("div", { className: "overflow-hidden rounded-md border border-base-200", children: [_jsx("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: _jsx(EditablePlainText, { tag: "span", value: color.name || "", onChange: (name) => updateColor({ ...color, name }), isEditMode: true, placeholder: "Color name", className: "text-sm font-bold" }) }), expanded && (_jsx("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map((space, j) => Object.entries(space).map(([key, value]) => value ? (_jsxs("div", { className: "flex w-full justify-between", children: [_jsx("span", { className: "font-medium uppercase", children: key }), _jsx("span", { children: value })] }, `${j}-${key}`)) : null)) }))] }));
79
- }
@@ -1,22 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useEffect } from "react";
3
- import IconList from "../sections/IconList/IconList";
4
- export default function DoDontList({ doItems, dontItems, showLabel = true, stackText = false, onChange, }) {
5
- const doRef = useRef(doItems);
6
- const dontRef = useRef(dontItems);
7
- useEffect(() => { doRef.current = doItems; }, [doItems]);
8
- useEffect(() => { dontRef.current = dontItems; }, [dontItems]);
9
- return (_jsxs("div", { className: "grid gap-16 lg:grid-cols-2", children: [_jsx(IconList, { items: doItems, icon: "check", showLabel: showLabel, stackText: stackText, labelClassName: "font-bold text-base-contrast", textClassName: "text-base-contrast", iconClassName: "text-green-600", onItemsChange: onChange ? (items) => {
10
- onChange({
11
- type: "do_dont",
12
- content: { doItems: items, dontItems: dontRef.current },
13
- options: { showLabel, stackText },
14
- });
15
- } : undefined }), _jsx(IconList, { items: dontItems, icon: "x", showLabel: showLabel, stackText: stackText, labelClassName: "font-bold text-base-contrast", textClassName: "text-base-contrast", iconClassName: "text-red-600", onItemsChange: onChange ? (items) => {
16
- onChange({
17
- type: "do_dont",
18
- content: { doItems: doRef.current, dontItems: items },
19
- options: { showLabel, stackText },
20
- });
21
- } : undefined })] }));
22
- }
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import MediaGrid from "../sections/MediaGrid/MediaGrid";
3
- export default function DoDontMediaGrid(props) {
4
- return _jsx(MediaGrid, { ...props, sectionType: "do_dont_grid" });
5
- }
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useState } from "react";
3
- import { Check } from "lucide-react";
4
- import { cn } from "../../lib/cn";
5
- import { Popover } from "../shared/Popover";
6
- import { PopoverItem } from "../shared/PopoverItem";
7
- export function AudiencePicker({ access, audiences, onChange }) {
8
- const [open, setOpen] = useState(false);
9
- const buttonRef = useRef(null);
10
- const selected = audiences.filter((a) => access.includes(a.name));
11
- const visibleCircles = selected.slice(0, 3);
12
- function toggle(name) {
13
- const next = access.includes(name)
14
- ? access.filter((n) => n !== name)
15
- : [...access, name];
16
- onChange(next);
17
- }
18
- return (_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: buttonRef, type: "button", onClick: () => setOpen((v) => !v), className: cn("cursor-pointer inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium", "border border-base-200 hover:bg-base-accent", selected.length === 0 && "text-base-contrast-light"), children: [selected.length === 0 && _jsx("span", { children: "No audience" }), selected.length >= 1 && (_jsx("span", { className: "flex -space-x-1.5", children: visibleCircles.map((a) => (_jsx("span", { className: "h-3 w-3 rounded-full border border-base", style: { backgroundColor: a.color ?? "#9ca3af" } }, a.name))) })), selected.length === 1 && _jsx("span", { children: selected[0].displayName }), selected.length >= 2 && _jsxs("span", { children: [selected.length, " audiences"] })] }), _jsx(Popover, { isOpen: open, onClose: () => setOpen(false), anchorRef: buttonRef, align: "end", className: "w-56", children: audiences.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-xs text-base-contrast-light", children: "No audiences configured. Add audiences in Site Settings \u2192 Viewer Access." })) : (_jsx("ul", { role: "list", className: "py-1", children: audiences.map((a) => {
19
- const checked = access.includes(a.name);
20
- return (_jsx("li", { children: _jsxs(PopoverItem, { role: "checkbox", "aria-checked": checked, onClick: () => toggle(a.name), children: [_jsx("span", { "aria-hidden": "true", className: cn("flex h-5 w-5 shrink-0 items-center justify-center rounded border transition-colors", checked
21
- ? "border-primary bg-primary text-primary-contrast"
22
- : "border-base-300 bg-base"), children: checked && _jsx(Check, { size: 14, strokeWidth: 3 }) }), _jsx("span", { className: "h-3 w-3 shrink-0 rounded-full border border-base-200", style: { backgroundColor: a.color ?? "#9ca3af" } }), _jsx("span", { className: "text-sm font-medium text-base-contrast", children: a.displayName })] }) }, a.name));
23
- }) })) })] }));
24
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { DeleteIcon } from "../shared/icons";
3
- import { IconButton } from "../shared/IconButton";
4
- export function DeleteButton({ onDelete }) {
5
- return (_jsx(IconButton, { icon: _jsx(DeleteIcon, { size: 16 }), label: "Delete section", intent: "destructive", onClick: onDelete, className: "pointer-events-auto" }));
6
- }
@@ -1,8 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { forwardRef } from "react";
3
- import { DragHandle as DragHandleIcon } from "../shared/icons";
4
- import { IconButton } from "../shared/IconButton";
5
- import { Tooltip, Kbd } from "../shared/Tooltip";
6
- export const DragHandle = forwardRef(function DragHandle(_, ref) {
7
- return (_jsx(Tooltip, { content: _jsxs(_Fragment, { children: [_jsx(Kbd, { children: "Drag" }), " to move"] }), className: "-ml-[34px]", children: _jsx(IconButton, { ref: ref, icon: _jsx(DragHandleIcon, { size: 18 }), label: "Drag to reorder section", className: "pointer-events-auto cursor-grab active:cursor-grabbing rounded-md text-base-contrast-light/80 hover:bg-base-contrast-light/10 hover:text-base-contrast", tabIndex: -1 }) }));
8
- });