@businessdash/sdk 0.9.60

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +899 -0
  3. package/dist/adapters-revalidate.d.ts +44 -0
  4. package/dist/adapters-revalidate.d.ts.map +1 -0
  5. package/dist/adapters-revalidate.js +68 -0
  6. package/dist/adapters-revalidate.js.map +1 -0
  7. package/dist/alpha.d.ts +21 -0
  8. package/dist/alpha.d.ts.map +1 -0
  9. package/dist/alpha.js +21 -0
  10. package/dist/alpha.js.map +1 -0
  11. package/dist/analytics-core.d.ts +34 -0
  12. package/dist/analytics-core.d.ts.map +1 -0
  13. package/dist/analytics-core.js +138 -0
  14. package/dist/analytics-core.js.map +1 -0
  15. package/dist/analytics-server.d.ts +54 -0
  16. package/dist/analytics-server.d.ts.map +1 -0
  17. package/dist/analytics-server.js +78 -0
  18. package/dist/analytics-server.js.map +1 -0
  19. package/dist/attribution-logo.d.ts +2 -0
  20. package/dist/attribution-logo.d.ts.map +1 -0
  21. package/dist/attribution-logo.js +5 -0
  22. package/dist/attribution-logo.js.map +1 -0
  23. package/dist/auth-handler.d.ts +92 -0
  24. package/dist/auth-handler.d.ts.map +1 -0
  25. package/dist/auth-handler.js +277 -0
  26. package/dist/auth-handler.js.map +1 -0
  27. package/dist/biab-forms.css +484 -0
  28. package/dist/cli.d.ts +46 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +1824 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/client.d.ts +1681 -0
  33. package/dist/client.d.ts.map +1 -0
  34. package/dist/client.js +2845 -0
  35. package/dist/client.js.map +1 -0
  36. package/dist/collections.d.ts +13 -0
  37. package/dist/collections.d.ts.map +1 -0
  38. package/dist/collections.js +13 -0
  39. package/dist/collections.js.map +1 -0
  40. package/dist/contracts.d.ts +14609 -0
  41. package/dist/contracts.d.ts.map +1 -0
  42. package/dist/contracts.js +2428 -0
  43. package/dist/contracts.js.map +1 -0
  44. package/dist/data-model-schema.d.ts +962 -0
  45. package/dist/data-model-schema.d.ts.map +1 -0
  46. package/dist/data-model-schema.js +2295 -0
  47. package/dist/data-model-schema.js.map +1 -0
  48. package/dist/distribution.d.ts +38 -0
  49. package/dist/distribution.d.ts.map +1 -0
  50. package/dist/distribution.js +61 -0
  51. package/dist/distribution.js.map +1 -0
  52. package/dist/element.d.ts +121 -0
  53. package/dist/element.d.ts.map +1 -0
  54. package/dist/element.js +276 -0
  55. package/dist/element.js.map +1 -0
  56. package/dist/enums.d.ts +25 -0
  57. package/dist/enums.d.ts.map +1 -0
  58. package/dist/enums.js +38 -0
  59. package/dist/enums.js.map +1 -0
  60. package/dist/errors.d.ts +195 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +188 -0
  63. package/dist/errors.js.map +1 -0
  64. package/dist/forms-core/autocomplete.d.ts +37 -0
  65. package/dist/forms-core/autocomplete.d.ts.map +1 -0
  66. package/dist/forms-core/autocomplete.js +82 -0
  67. package/dist/forms-core/autocomplete.js.map +1 -0
  68. package/dist/forms-core/business-function.d.ts +61 -0
  69. package/dist/forms-core/business-function.d.ts.map +1 -0
  70. package/dist/forms-core/business-function.js +149 -0
  71. package/dist/forms-core/business-function.js.map +1 -0
  72. package/dist/forms-core/calculation.d.ts +72 -0
  73. package/dist/forms-core/calculation.d.ts.map +1 -0
  74. package/dist/forms-core/calculation.js +103 -0
  75. package/dist/forms-core/calculation.js.map +1 -0
  76. package/dist/forms-core/controller.d.ts +249 -0
  77. package/dist/forms-core/controller.d.ts.map +1 -0
  78. package/dist/forms-core/controller.js +590 -0
  79. package/dist/forms-core/controller.js.map +1 -0
  80. package/dist/forms-core/elements.d.ts +44 -0
  81. package/dist/forms-core/elements.d.ts.map +1 -0
  82. package/dist/forms-core/elements.js +68 -0
  83. package/dist/forms-core/elements.js.map +1 -0
  84. package/dist/forms-core/email-domains.d.ts +10 -0
  85. package/dist/forms-core/email-domains.d.ts.map +1 -0
  86. package/dist/forms-core/email-domains.js +69 -0
  87. package/dist/forms-core/email-domains.js.map +1 -0
  88. package/dist/forms-core/file-rules.d.ts +51 -0
  89. package/dist/forms-core/file-rules.d.ts.map +1 -0
  90. package/dist/forms-core/file-rules.js +105 -0
  91. package/dist/forms-core/file-rules.js.map +1 -0
  92. package/dist/forms-core/formula.d.ts +114 -0
  93. package/dist/forms-core/formula.d.ts.map +1 -0
  94. package/dist/forms-core/formula.js +1170 -0
  95. package/dist/forms-core/formula.js.map +1 -0
  96. package/dist/forms-core/index.d.ts +24 -0
  97. package/dist/forms-core/index.d.ts.map +1 -0
  98. package/dist/forms-core/index.js +28 -0
  99. package/dist/forms-core/index.js.map +1 -0
  100. package/dist/forms-core/units.d.ts +49 -0
  101. package/dist/forms-core/units.d.ts.map +1 -0
  102. package/dist/forms-core/units.js +255 -0
  103. package/dist/forms-core/units.js.map +1 -0
  104. package/dist/forms-core/us-states.d.ts +14 -0
  105. package/dist/forms-core/us-states.d.ts.map +1 -0
  106. package/dist/forms-core/us-states.js +66 -0
  107. package/dist/forms-core/us-states.js.map +1 -0
  108. package/dist/forms-core/validation.d.ts +266 -0
  109. package/dist/forms-core/validation.d.ts.map +1 -0
  110. package/dist/forms-core/validation.js +850 -0
  111. package/dist/forms-core/validation.js.map +1 -0
  112. package/dist/forms.d.ts +19 -0
  113. package/dist/forms.d.ts.map +1 -0
  114. package/dist/forms.js +29 -0
  115. package/dist/forms.js.map +1 -0
  116. package/dist/gallery-types.d.ts +32 -0
  117. package/dist/gallery-types.d.ts.map +1 -0
  118. package/dist/gallery-types.js +2 -0
  119. package/dist/gallery-types.js.map +1 -0
  120. package/dist/graphql.d.ts +97 -0
  121. package/dist/graphql.d.ts.map +1 -0
  122. package/dist/graphql.js +212 -0
  123. package/dist/graphql.js.map +1 -0
  124. package/dist/index.cjs +19448 -0
  125. package/dist/index.d.cts +19 -0
  126. package/dist/index.d.mts +19 -0
  127. package/dist/index.d.ts +19 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +20 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/marketing-schema.d.ts +216 -0
  132. package/dist/marketing-schema.d.ts.map +1 -0
  133. package/dist/marketing-schema.js +200 -0
  134. package/dist/marketing-schema.js.map +1 -0
  135. package/dist/mcp.d.ts +42 -0
  136. package/dist/mcp.d.ts.map +1 -0
  137. package/dist/mcp.js +87 -0
  138. package/dist/mcp.js.map +1 -0
  139. package/dist/native.d.ts +45 -0
  140. package/dist/native.d.ts.map +1 -0
  141. package/dist/native.js +43 -0
  142. package/dist/native.js.map +1 -0
  143. package/dist/next-revalidate.d.ts +43 -0
  144. package/dist/next-revalidate.d.ts.map +1 -0
  145. package/dist/next-revalidate.js +84 -0
  146. package/dist/next-revalidate.js.map +1 -0
  147. package/dist/parallel-pages.d.ts +102 -0
  148. package/dist/parallel-pages.d.ts.map +1 -0
  149. package/dist/parallel-pages.js +108 -0
  150. package/dist/parallel-pages.js.map +1 -0
  151. package/dist/payment-icons.d.ts +66 -0
  152. package/dist/payment-icons.d.ts.map +1 -0
  153. package/dist/payment-icons.js +160 -0
  154. package/dist/payment-icons.js.map +1 -0
  155. package/dist/proxy.d.ts +67 -0
  156. package/dist/proxy.d.ts.map +1 -0
  157. package/dist/proxy.js +97 -0
  158. package/dist/proxy.js.map +1 -0
  159. package/dist/react-analytics.d.ts +39 -0
  160. package/dist/react-analytics.d.ts.map +1 -0
  161. package/dist/react-analytics.js +59 -0
  162. package/dist/react-analytics.js.map +1 -0
  163. package/dist/react-attribution.d.ts +99 -0
  164. package/dist/react-attribution.d.ts.map +1 -0
  165. package/dist/react-attribution.js +52 -0
  166. package/dist/react-attribution.js.map +1 -0
  167. package/dist/react-marketing.d.ts +181 -0
  168. package/dist/react-marketing.d.ts.map +1 -0
  169. package/dist/react-marketing.js +215 -0
  170. package/dist/react-marketing.js.map +1 -0
  171. package/dist/react.d.ts +727 -0
  172. package/dist/react.d.ts.map +1 -0
  173. package/dist/react.js +2418 -0
  174. package/dist/react.js.map +1 -0
  175. package/dist/reserved-paths.d.ts +24 -0
  176. package/dist/reserved-paths.d.ts.map +1 -0
  177. package/dist/reserved-paths.js +60 -0
  178. package/dist/reserved-paths.js.map +1 -0
  179. package/dist/revalidate-verify.d.ts +30 -0
  180. package/dist/revalidate-verify.d.ts.map +1 -0
  181. package/dist/revalidate-verify.js +74 -0
  182. package/dist/revalidate-verify.js.map +1 -0
  183. package/dist/sdk.d.ts +678 -0
  184. package/dist/sdk.d.ts.map +1 -0
  185. package/dist/sdk.js +801 -0
  186. package/dist/sdk.js.map +1 -0
  187. package/dist/seo.d.ts +218 -0
  188. package/dist/seo.d.ts.map +1 -0
  189. package/dist/seo.js +309 -0
  190. package/dist/seo.js.map +1 -0
  191. package/dist/socials.d.ts +47 -0
  192. package/dist/socials.d.ts.map +1 -0
  193. package/dist/socials.js +172 -0
  194. package/dist/socials.js.map +1 -0
  195. package/dist/static.d.ts +14 -0
  196. package/dist/static.d.ts.map +1 -0
  197. package/dist/static.js +14 -0
  198. package/dist/static.js.map +1 -0
  199. package/dist/url-pattern.d.ts +47 -0
  200. package/dist/url-pattern.d.ts.map +1 -0
  201. package/dist/url-pattern.js +124 -0
  202. package/dist/url-pattern.js.map +1 -0
  203. package/dist/vanilla.d.ts +77 -0
  204. package/dist/vanilla.d.ts.map +1 -0
  205. package/dist/vanilla.js +903 -0
  206. package/dist/vanilla.js.map +1 -0
  207. package/openapi.json +13779 -0
  208. package/package.json +204 -0
  209. package/src/adapters-revalidate.ts +88 -0
  210. package/src/alpha.ts +89 -0
  211. package/src/analytics-core.ts +175 -0
  212. package/src/analytics-server.ts +99 -0
  213. package/src/angular/biab-form.component.ts +1443 -0
  214. package/src/angular/index.ts +26 -0
  215. package/src/attribution-logo.ts +5 -0
  216. package/src/auth-handler.ts +352 -0
  217. package/src/cli.ts +2517 -0
  218. package/src/client.ts +3578 -0
  219. package/src/collections.ts +101 -0
  220. package/src/contracts.ts +3390 -0
  221. package/src/data-model-schema.ts +4042 -0
  222. package/src/distribution.ts +73 -0
  223. package/src/element.ts +321 -0
  224. package/src/enums.ts +65 -0
  225. package/src/errors.ts +338 -0
  226. package/src/forms-core/autocomplete.ts +97 -0
  227. package/src/forms-core/business-function.ts +209 -0
  228. package/src/forms-core/calculation.ts +167 -0
  229. package/src/forms-core/controller.ts +922 -0
  230. package/src/forms-core/elements.ts +86 -0
  231. package/src/forms-core/email-domains.ts +68 -0
  232. package/src/forms-core/file-rules.ts +123 -0
  233. package/src/forms-core/formula.ts +1339 -0
  234. package/src/forms-core/index.ts +122 -0
  235. package/src/forms-core/units.ts +308 -0
  236. package/src/forms-core/us-states.ts +68 -0
  237. package/src/forms-core/validation.ts +1037 -0
  238. package/src/forms.ts +63 -0
  239. package/src/gallery-types.ts +31 -0
  240. package/src/graphql.ts +295 -0
  241. package/src/index.ts +505 -0
  242. package/src/marketing-schema.ts +395 -0
  243. package/src/mcp.ts +108 -0
  244. package/src/native.ts +73 -0
  245. package/src/next-revalidate.ts +124 -0
  246. package/src/parallel-pages.ts +192 -0
  247. package/src/payment-icons.ts +205 -0
  248. package/src/proxy.ts +173 -0
  249. package/src/qwik.tsx +1234 -0
  250. package/src/react-analytics.tsx +76 -0
  251. package/src/react-attribution.tsx +192 -0
  252. package/src/react-marketing.tsx +338 -0
  253. package/src/react.tsx +5495 -0
  254. package/src/reserved-paths.ts +65 -0
  255. package/src/revalidate-verify.ts +98 -0
  256. package/src/sdk.ts +1671 -0
  257. package/src/seo.ts +488 -0
  258. package/src/socials.ts +230 -0
  259. package/src/solid.tsx +1466 -0
  260. package/src/static.ts +21 -0
  261. package/src/styles/biab-forms.css +484 -0
  262. package/src/svelte/BiabForm.svelte +1069 -0
  263. package/src/svelte/context.ts +57 -0
  264. package/src/svelte/index.ts +79 -0
  265. package/src/url-pattern.ts +153 -0
  266. package/src/vanilla.ts +1290 -0
  267. package/src/vue/BiabForm.vue +1538 -0
  268. package/src/vue/index.ts +119 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Code-first declaration of a programmatic-SEO ("parallel") page.
3
+ * The consumer writes:
4
+ *
5
+ * import { defineParallelPage } from "@businessdash/sdk";
6
+ *
7
+ * const repairAreaPage = defineParallelPage({
8
+ * key: "repair-area",
9
+ * routePattern: "/repair/[service]/[area]",
10
+ * variables: {
11
+ * service: {
12
+ * source: { section: "repairTypesCatalog" },
13
+ * slugField: "type",
14
+ * tokenFields: ["type", "description"],
15
+ * },
16
+ * area: {
17
+ * source: { section: "serviceAreas", path: "areas" },
18
+ * slugField: "slug",
19
+ * tokenFields: ["name", "state", "slug"],
20
+ * },
21
+ * },
22
+ * meta: {
23
+ * title: "{service.type} in {area.name} | {company.shortName}",
24
+ * description:
25
+ * "Professional {service.type} in {area.name}, {area.state}. Call {company.phone}.",
26
+ * },
27
+ * templateRef: "repairAreaTemplate",
28
+ * });
29
+ *
30
+ * `defineParallelPage` is a pure builder — no DB writes, no HTTP. It
31
+ * returns a frozen, type-checked artifact. Push to the BIAB server
32
+ * later via `biab-dev sync-parallel-pages` (or the SDK's
33
+ * `client.parallelPages.upsertDefinition()` when wired).
34
+ */
35
+
36
+ import { parseParallelPagePattern } from "./url-pattern.js";
37
+
38
+ export type ParallelPageVariableInput = {
39
+ source: {
40
+ section: string;
41
+ path?: string;
42
+ };
43
+ slugField: string;
44
+ tokenFields?: ReadonlyArray<string>;
45
+ };
46
+
47
+ export type ParallelPageMetaInput = {
48
+ title: string;
49
+ description: string;
50
+ canonical?: string;
51
+ ogImage?: string;
52
+ };
53
+
54
+ export type ParallelPageInput<
55
+ V extends Record<string, ParallelPageVariableInput>,
56
+ > = {
57
+ key: string;
58
+ routePattern: string;
59
+ variables: V;
60
+ meta: ParallelPageMetaInput;
61
+ /**
62
+ * For SDK-defined pages, a schema section key naming the body
63
+ * template. The dashboard renders the matching section's content
64
+ * for the parallel-page body. Site-builder pages use a different
65
+ * pointer scheme (`cms:<contentId>`) — set transparently by the
66
+ * dashboard.
67
+ */
68
+ templateRef: string;
69
+ /**
70
+ * Per-page robots directive. Defaults to `inherit` (defer to the
71
+ * site-wide robots config). Set `noindex` for variants that
72
+ * shouldn't appear in search (e.g. dynamic catch-alls used as
73
+ * fallbacks).
74
+ */
75
+ crawlRule?: "inherit" | "index" | "noindex";
76
+ };
77
+
78
+ export type ParallelPageDefinition<
79
+ V extends Record<string, ParallelPageVariableInput>,
80
+ > = {
81
+ readonly $kind: "biab.parallelPage";
82
+ readonly key: string;
83
+ readonly routePattern: string;
84
+ readonly variables: ReadonlyArray<{
85
+ readonly name: keyof V & string;
86
+ readonly source: { readonly section: string; readonly path?: string };
87
+ readonly slugField: string;
88
+ readonly tokenFields: ReadonlyArray<string>;
89
+ }>;
90
+ readonly meta: Readonly<ParallelPageMetaInput>;
91
+ readonly templateRef: string;
92
+ readonly crawlRule: "inherit" | "index" | "noindex";
93
+ };
94
+
95
+ /**
96
+ * Validate + freeze a parallel-page declaration. Throws on:
97
+ * - Empty / malformed `routePattern`
98
+ * - `[variable]` segments in the pattern that aren't in `variables`
99
+ * - `variables` keys that don't appear in the pattern
100
+ * - Duplicate variable names
101
+ * - Missing `slugField` on any binding
102
+ */
103
+ export function defineParallelPage<
104
+ V extends Record<string, ParallelPageVariableInput>,
105
+ >(input: ParallelPageInput<V>): ParallelPageDefinition<V> {
106
+ if (!input.key || typeof input.key !== "string") {
107
+ throw new Error("defineParallelPage: `key` is required.");
108
+ }
109
+ if (!/^[a-z][a-z0-9-]*$/.test(input.key)) {
110
+ throw new Error(
111
+ `defineParallelPage: \`key\` must be kebab-case (got "${input.key}").`,
112
+ );
113
+ }
114
+
115
+ const parsed = parseParallelPagePattern(input.routePattern);
116
+
117
+ const inputNames = new Set(Object.keys(input.variables));
118
+ const patternNames = new Set(parsed.variableNames);
119
+
120
+ for (const patternName of patternNames) {
121
+ if (!inputNames.has(patternName)) {
122
+ throw new Error(
123
+ `defineParallelPage("${input.key}"): pattern uses "[${patternName}]" ` +
124
+ `but \`variables\` has no binding for "${patternName}".`,
125
+ );
126
+ }
127
+ }
128
+ for (const inputName of inputNames) {
129
+ if (!patternNames.has(inputName)) {
130
+ throw new Error(
131
+ `defineParallelPage("${input.key}"): \`variables\` declares "${inputName}" ` +
132
+ `but the pattern "${input.routePattern}" has no "[${inputName}]" segment.`,
133
+ );
134
+ }
135
+ }
136
+
137
+ const variables: ParallelPageDefinition<V>["variables"] =
138
+ parsed.variableNames.map((name) => {
139
+ const raw = input.variables[name]!;
140
+ if (!raw.source?.section) {
141
+ throw new Error(
142
+ `defineParallelPage("${input.key}"): variable "${name}" is missing \`source.section\`.`,
143
+ );
144
+ }
145
+ if (!raw.slugField) {
146
+ throw new Error(
147
+ `defineParallelPage("${input.key}"): variable "${name}" is missing \`slugField\`.`,
148
+ );
149
+ }
150
+ const tokenFields = raw.tokenFields ?? [raw.slugField];
151
+ return Object.freeze({
152
+ name: name as keyof V & string,
153
+ source: Object.freeze({
154
+ section: raw.source.section,
155
+ ...(raw.source.path !== undefined ? { path: raw.source.path } : {}),
156
+ }),
157
+ slugField: raw.slugField,
158
+ tokenFields: Object.freeze([...tokenFields]),
159
+ });
160
+ });
161
+
162
+ if (!input.meta?.title || !input.meta?.description) {
163
+ throw new Error(
164
+ `defineParallelPage("${input.key}"): \`meta.title\` and \`meta.description\` are required.`,
165
+ );
166
+ }
167
+
168
+ return Object.freeze({
169
+ $kind: "biab.parallelPage",
170
+ key: input.key,
171
+ routePattern: input.routePattern,
172
+ variables: Object.freeze(variables),
173
+ meta: Object.freeze({ ...input.meta }),
174
+ templateRef: input.templateRef,
175
+ crawlRule: input.crawlRule ?? "inherit",
176
+ }) as ParallelPageDefinition<V>;
177
+ }
178
+
179
+ /**
180
+ * Type guard for the artifact `defineParallelPage` returns. Useful
181
+ * when consumers export a mixed array of marketing + parallel-page
182
+ * declarations from one `biab.config.ts`.
183
+ */
184
+ export function isParallelPageDefinition(
185
+ value: unknown,
186
+ ): value is ParallelPageDefinition<Record<string, ParallelPageVariableInput>> {
187
+ return (
188
+ !!value &&
189
+ typeof value === "object" &&
190
+ (value as { $kind?: unknown }).$kind === "biab.parallelPage"
191
+ );
192
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Payment-method brand icons — framework-agnostic.
3
+ *
4
+ * The SDK ships the SVG path data for every payment method a Company Profile can
5
+ * enable, plus `paymentIconSvg()`, which returns a ready-to-inject `<svg>`
6
+ * markup string. No framework dependency: drop the string into React
7
+ * (`dangerouslySetInnerHTML`), Vue (`v-html`), Svelte (`{@html}`), Angular
8
+ * (`[innerHTML]`), or the DOM (`el.innerHTML`). For full control,
9
+ * `paymentIconData()` returns the raw `{ viewBox, paths }`.
10
+ *
11
+ * Theming — the icon is "the color of the text" by default:
12
+ * - default `fill="currentColor"` → inherits the surrounding text color, so it
13
+ * adapts to light/dark automatically.
14
+ * - `theme: "light" | "dark"` → lock to a fixed neutral permanently.
15
+ * - `color`: any CSS color (e.g. "#1a1a1a") → explicit; wins over `theme`.
16
+ * - text-only is simply not calling this — render the label by itself (icons are
17
+ * additive). Unknown / custom ("additional") methods return `null` so callers
18
+ * fall back to text.
19
+ *
20
+ * Icon sources: Font Awesome Free (CC BY 4.0) and Simple Icons (CC0).
21
+ *
22
+ * GENERATED from react-icons path data — do not edit the data by hand; see
23
+ * scripts that produced PAYMENT_ICONS.
24
+ */
25
+
26
+ /** Every payment method the Company Profile can toggle on. */
27
+ export type PaymentMethodIconKey =
28
+ | "cash"
29
+ | "visa"
30
+ | "mastercard"
31
+ | "discover"
32
+ | "americanExpress"
33
+ | "personalCheck"
34
+ | "paypal"
35
+ | "venmo"
36
+ | "cashApp"
37
+ | "zelle"
38
+ | "applePay";
39
+
40
+ export type PaymentIconData = {
41
+ /** SVG viewBox, e.g. "0 0 576 512". */
42
+ viewBox: string;
43
+ /** Human-readable label, e.g. "American Express". */
44
+ label: string;
45
+ /** One or more SVG path `d` strings, drawn with the resolved fill color. */
46
+ paths: string[];
47
+ };
48
+
49
+ /** Force a fixed neutral instead of inheriting the text color. */
50
+ export type PaymentIconTheme = "light" | "dark";
51
+
52
+ export type PaymentIconOptions = {
53
+ /** Explicit CSS color (e.g. "#1a1a1a" or "var(--brand)"). Wins over `theme`. */
54
+ color?: string;
55
+ /** Lock the icon to a fixed neutral: light bg → dark icon, dark bg → light. */
56
+ theme?: PaymentIconTheme;
57
+ /** Width/height. Number → px; string → used as-is. Default "1em". */
58
+ size?: number | string;
59
+ /** Accessible label. Defaults to the method label; pass "" to hide it. */
60
+ title?: string;
61
+ };
62
+
63
+ /** Brand icon data, keyed by Company Profile payment method. */
64
+ export const PAYMENT_ICONS: Record<PaymentMethodIconKey, PaymentIconData> = {
65
+ cash: {
66
+ viewBox: "0 0 512 512",
67
+ label: "Cash",
68
+ paths: [
69
+ "M32 96v256h448V96H32zm160.5 224h-80.4c0-26.6-21.5-48.1-48.1-48.1V192c35.3 0 64-28.7 64-64h64.5c-19.9 23.5-32.5 57.8-32.5 96s12.6 72.5 32.5 96zM448 271.9c-26 0-48 21.5-48 48.1h-80.5c19.9-23.5 32.5-57.8 32.5-96s-12.6-72.5-32.5-96H384c0 35.3 28.7 64 64 64v79.9zM32 384h448v32H32z",
70
+ ],
71
+ },
72
+ visa: {
73
+ viewBox: "0 0 576 512",
74
+ label: "Visa",
75
+ paths: [
76
+ "M470.1 231.3s7.6 37.2 9.3 45H446c3.3-8.9 16-43.5 16-43.5-.2.3 3.3-9.1 5.3-14.9l2.8 13.4zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM152.5 331.2L215.7 176h-42.5l-39.3 106-4.3-21.5-14-71.4c-2.3-9.9-9.4-12.7-18.2-13.1H32.7l-.7 3.1c15.8 4 29.9 9.8 42.2 17.1l35.8 135h42.5zm94.4.2L272.1 176h-40.2l-25.1 155.4h40.1zm139.9-50.8c.2-17.7-10.6-31.2-33.7-42.3-14.1-7.1-22.7-11.9-22.7-19.2.2-6.6 7.3-13.4 23.1-13.4 13.1-.3 22.7 2.8 29.9 5.9l3.6 1.7 5.5-33.6c-7.9-3.1-20.5-6.6-36-6.6-39.7 0-67.6 21.2-67.8 51.4-.3 22.3 20 34.7 35.2 42.2 15.5 7.6 20.8 12.6 20.8 19.3-.2 10.4-12.6 15.2-24.1 15.2-16 0-24.6-2.5-37.7-8.3l-5.3-2.5-5.6 34.9c9.4 4.3 26.8 8.1 44.8 8.3 42.2.1 69.7-20.8 70-53zM528 331.4L495.6 176h-31.1c-9.6 0-16.9 2.8-21 12.9l-59.7 142.5H426s6.9-19.2 8.4-23.3H486c1.2 5.5 4.8 23.3 4.8 23.3H528z",
77
+ ],
78
+ },
79
+ mastercard: {
80
+ viewBox: "0 0 576 512",
81
+ label: "Mastercard",
82
+ paths: [
83
+ "M482.9 410.3c0 6.8-4.6 11.7-11.2 11.7-6.8 0-11.2-5.2-11.2-11.7 0-6.5 4.4-11.7 11.2-11.7 6.6 0 11.2 5.2 11.2 11.7zm-310.8-11.7c-7.1 0-11.2 5.2-11.2 11.7 0 6.5 4.1 11.7 11.2 11.7 6.5 0 10.9-4.9 10.9-11.7-.1-6.5-4.4-11.7-10.9-11.7zm117.5-.3c-5.4 0-8.7 3.5-9.5 8.7h19.1c-.9-5.7-4.4-8.7-9.6-8.7zm107.8.3c-6.8 0-10.9 5.2-10.9 11.7 0 6.5 4.1 11.7 10.9 11.7 6.8 0 11.2-4.9 11.2-11.7 0-6.5-4.4-11.7-11.2-11.7zm105.9 26.1c0 .3.3.5.3 1.1 0 .3-.3.5-.3 1.1-.3.3-.3.5-.5.8-.3.3-.5.5-1.1.5-.3.3-.5.3-1.1.3-.3 0-.5 0-1.1-.3-.3 0-.5-.3-.8-.5-.3-.3-.5-.5-.5-.8-.3-.5-.3-.8-.3-1.1 0-.5 0-.8.3-1.1 0-.5.3-.8.5-1.1.3-.3.5-.3.8-.5.5-.3.8-.3 1.1-.3.5 0 .8 0 1.1.3.5.3.8.3 1.1.5s.2.6.5 1.1zm-2.2 1.4c.5 0 .5-.3.8-.3.3-.3.3-.5.3-.8 0-.3 0-.5-.3-.8-.3 0-.5-.3-1.1-.3h-1.6v3.5h.8V426h.3l1.1 1.4h.8l-1.1-1.3zM576 81v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V81c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM64 220.6c0 76.5 62.1 138.5 138.5 138.5 27.2 0 53.9-8.2 76.5-23.1-72.9-59.3-72.4-171.2 0-230.5-22.6-15-49.3-23.1-76.5-23.1-76.4-.1-138.5 62-138.5 138.2zm224 108.8c70.5-55 70.2-162.2 0-217.5-70.2 55.3-70.5 162.6 0 217.5zm-142.3 76.3c0-8.7-5.7-14.4-14.7-14.7-4.6 0-9.5 1.4-12.8 6.5-2.4-4.1-6.5-6.5-12.2-6.5-3.8 0-7.6 1.4-10.6 5.4V392h-8.2v36.7h8.2c0-18.9-2.5-30.2 9-30.2 10.2 0 8.2 10.2 8.2 30.2h7.9c0-18.3-2.5-30.2 9-30.2 10.2 0 8.2 10 8.2 30.2h8.2v-23zm44.9-13.7h-7.9v4.4c-2.7-3.3-6.5-5.4-11.7-5.4-10.3 0-18.2 8.2-18.2 19.3 0 11.2 7.9 19.3 18.2 19.3 5.2 0 9-1.9 11.7-5.4v4.6h7.9V392zm40.5 25.6c0-15-22.9-8.2-22.9-15.2 0-5.7 11.9-4.8 18.5-1.1l3.3-6.5c-9.4-6.1-30.2-6-30.2 8.2 0 14.3 22.9 8.3 22.9 15 0 6.3-13.5 5.8-20.7.8l-3.5 6.3c11.2 7.6 32.6 6 32.6-7.5zm35.4 9.3l-2.2-6.8c-3.8 2.1-12.2 4.4-12.2-4.1v-16.6h13.1V392h-13.1v-11.2h-8.2V392h-7.6v7.3h7.6V416c0 17.6 17.3 14.4 22.6 10.9zm13.3-13.4h27.5c0-16.2-7.4-22.6-17.4-22.6-10.6 0-18.2 7.9-18.2 19.3 0 20.5 22.6 23.9 33.8 14.2l-3.8-6c-7.8 6.4-19.6 5.8-21.9-4.9zm59.1-21.5c-4.6-2-11.6-1.8-15.2 4.4V392h-8.2v36.7h8.2V408c0-11.6 9.5-10.1 12.8-8.4l2.4-7.6zm10.6 18.3c0-11.4 11.6-15.1 20.7-8.4l3.8-6.5c-11.6-9.1-32.7-4.1-32.7 15 0 19.8 22.4 23.8 32.7 15l-3.8-6.5c-9.2 6.5-20.7 2.6-20.7-8.6zm66.7-18.3H408v4.4c-8.3-11-29.9-4.8-29.9 13.9 0 19.2 22.4 24.7 29.9 13.9v4.6h8.2V392zm33.7 0c-2.4-1.2-11-2.9-15.2 4.4V392h-7.9v36.7h7.9V408c0-11 9-10.3 12.8-8.4l2.4-7.6zm40.3-14.9h-7.9v19.3c-8.2-10.9-29.9-5.1-29.9 13.9 0 19.4 22.5 24.6 29.9 13.9v4.6h7.9v-51.7zm7.6-75.1v4.6h.8V302h1.9v-.8h-4.6v.8h1.9zm6.6 123.8c0-.5 0-1.1-.3-1.6-.3-.3-.5-.8-.8-1.1-.3-.3-.8-.5-1.1-.8-.5 0-1.1-.3-1.6-.3-.3 0-.8.3-1.4.3-.5.3-.8.5-1.1.8-.5.3-.8.8-.8 1.1-.3.5-.3 1.1-.3 1.6 0 .3 0 .8.3 1.4 0 .3.3.8.8 1.1.3.3.5.5 1.1.8.5.3 1.1.3 1.4.3.5 0 1.1 0 1.6-.3.3-.3.8-.5 1.1-.8.3-.3.5-.8.8-1.1.3-.6.3-1.1.3-1.4zm3.2-124.7h-1.4l-1.6 3.5-1.6-3.5h-1.4v5.4h.8v-4.1l1.6 3.5h1.1l1.4-3.5v4.1h1.1v-5.4zm4.4-80.5c0-76.2-62.1-138.3-138.5-138.3-27.2 0-53.9 8.2-76.5 23.1 72.1 59.3 73.2 171.5 0 230.5 22.6 15 49.5 23.1 76.5 23.1 76.4.1 138.5-61.9 138.5-138.4z",
84
+ ],
85
+ },
86
+ discover: {
87
+ viewBox: "0 0 576 512",
88
+ label: "Discover",
89
+ paths: [
90
+ "M520.4 196.1c0-7.9-5.5-12.1-15.6-12.1h-4.9v24.9h4.7c10.3 0 15.8-4.4 15.8-12.8zM528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-44.1 138.9c22.6 0 52.9-4.1 52.9 24.4 0 12.6-6.6 20.7-18.7 23.2l25.8 34.4h-19.6l-22.2-32.8h-2.2v32.8h-16zm-55.9.1h45.3v14H444v18.2h28.3V217H444v22.2h29.3V253H428zm-68.7 0l21.9 55.2 22.2-55.2h17.5l-35.5 84.2h-8.6l-35-84.2zm-55.9-3c24.7 0 44.6 20 44.6 44.6 0 24.7-20 44.6-44.6 44.6-24.7 0-44.6-20-44.6-44.6 0-24.7 20-44.6 44.6-44.6zm-49.3 6.1v19c-20.1-20.1-46.8-4.7-46.8 19 0 25 27.5 38.5 46.8 19.2v19c-29.7 14.3-63.3-5.7-63.3-38.2 0-31.2 33.1-53 63.3-38zm-97.2 66.3c11.4 0 22.4-15.3-3.3-24.4-15-5.5-20.2-11.4-20.2-22.7 0-23.2 30.6-31.4 49.7-14.3l-8.4 10.8c-10.4-11.6-24.9-6.2-24.9 2.5 0 4.4 2.7 6.9 12.3 10.3 18.2 6.6 23.6 12.5 23.6 25.6 0 29.5-38.8 37.4-56.6 11.3l10.3-9.9c3.7 7.1 9.9 10.8 17.5 10.8zM55.4 253H32v-82h23.4c26.1 0 44.1 17 44.1 41.1 0 18.5-13.2 40.9-44.1 40.9zm67.5 0h-16v-82h16zM544 433c0 8.2-6.8 15-15 15H128c189.6-35.6 382.7-139.2 416-160zM74.1 191.6c-5.2-4.9-11.6-6.6-21.9-6.6H48v54.2h4.2c10.3 0 17-2 21.9-6.4 5.7-5.2 8.9-12.8 8.9-20.7s-3.2-15.5-8.9-20.5z",
91
+ ],
92
+ },
93
+ americanExpress: {
94
+ viewBox: "0 0 576 512",
95
+ label: "American Express",
96
+ paths: [
97
+ "M325.1 167.8c0-16.4-14.1-18.4-27.4-18.4l-39.1-.3v69.3H275v-25.1h18c18.4 0 14.5 10.3 14.8 25.1h16.6v-13.5c0-9.2-1.5-15.1-11-18.4 7.4-3 11.8-10.7 11.7-18.7zm-29.4 11.3H275v-15.3h21c5.1 0 10.7 1 10.7 7.4 0 6.6-5.3 7.9-11 7.9zM279 268.6h-52.7l-21 22.8-20.5-22.8h-66.5l-.1 69.3h65.4l21.3-23 20.4 23h32.2l.1-23.3c18.9 0 49.3 4.6 49.3-23.3 0-17.3-12.3-22.7-27.9-22.7zm-103.8 54.7h-40.6v-13.8h36.3v-14.1h-36.3v-12.5h41.7l17.9 20.2zm65.8 8.2l-25.3-28.1L241 276zm37.8-31h-21.2v-17.6h21.5c5.6 0 10.2 2.3 10.2 8.4 0 6.4-4.6 9.2-10.5 9.2zm-31.6-136.7v-14.6h-55.5v69.3h55.5v-14.3h-38.9v-13.8h37.8v-14.1h-37.8v-12.5zM576 255.4h-.2zm-194.6 31.9c0-16.4-14.1-18.7-27.1-18.7h-39.4l-.1 69.3h16.6l.1-25.3h17.6c11 0 14.8 2 14.8 13.8l-.1 11.5h16.6l.1-13.8c0-8.9-1.8-15.1-11-18.4 7.7-3.1 11.8-10.8 11.9-18.4zm-29.2 11.2h-20.7v-15.6h21c5.1 0 10.7 1 10.7 7.4 0 6.9-5.4 8.2-11 8.2zm-172.8-80v-69.3h-27.6l-19.7 47-21.7-47H83.3v65.7l-28.1-65.7H30.7L1 218.5h17.9l6.4-15.3h34.5l6.4 15.3H100v-54.2l24 54.2h14.6l24-54.2v54.2zM31.2 188.8l11.2-27.6 11.5 27.6zm477.4 158.9v-4.5c-10.8 5.6-3.9 4.5-156.7 4.5 0-25.2.1-23.9 0-25.2-1.7-.1-3.2-.1-9.4-.1 0 17.9-.1 6.8-.1 25.3h-39.6c0-12.1.1-15.3.1-29.2-10 6-22.8 6.4-34.3 6.2 0 14.7-.1 8.3-.1 23h-48.9c-5.1-5.7-2.7-3.1-15.4-17.4-3.2 3.5-12.8 13.9-16.1 17.4h-82v-92.3h83.1c5 5.6 2.8 3.1 15.5 17.2 3.2-3.5 12.2-13.4 15.7-17.2h58c9.8 0 18 1.9 24.3 5.6v-5.6c54.3 0 64.3-1.4 75.7 5.1v-5.1h78.2v5.2c11.4-6.9 19.6-5.2 64.9-5.2v5c10.3-5.9 16.6-5.2 54.3-5V80c0-26.5-21.5-48-48-48h-480c-26.5 0-48 21.5-48 48v109.8c9.4-21.9 19.7-46 23.1-53.9h39.7c4.3 10.1 1.6 3.7 9 21.1v-21.1h46c2.9 6.2 11.1 24 13.9 30 5.8-13.6 10.1-23.9 12.6-30h103c0-.1 11.5 0 11.6 0 43.7.2 53.6-.8 64.4 5.3v-5.3H363v9.3c7.6-6.1 17.9-9.3 30.7-9.3h27.6c0 .5 1.9.3 2.3.3H456c4.2 9.8 2.6 6 8.8 20.6v-20.6h43.3c4.9 8-1-1.8 11.2 18.4v-18.4h39.9v92h-41.6c-5.4-9-1.4-2.2-13.2-21.9v21.9h-52.8c-6.4-14.8-.1-.3-6.6-15.3h-19c-4.2 10-2.2 5.2-6.4 15.3h-26.8c-12.3 0-22.3-3-29.7-8.9v8.9h-66.5c-.3-13.9-.1-24.8-.1-24.8-1.8-.3-3.4-.2-9.8-.2v25.1H151.2v-11.4c-2.5 5.6-2.7 5.9-5.1 11.4h-29.5c-4-8.9-2.9-6.4-5.1-11.4v11.4H58.6c-4.2-10.1-2.2-5.3-6.4-15.3H33c-4.2 10-2.2 5.2-6.4 15.3H0V432c0 26.5 21.5 48 48 48h480.1c26.5 0 48-21.5 48-48v-90.4c-12.7 8.3-32.7 6.1-67.5 6.1zm36.3-64.5H575v-14.6h-32.9c-12.8 0-23.8 6.6-23.8 20.7 0 33 42.7 12.8 42.7 27.4 0 5.1-4.3 6.4-8.4 6.4h-32l-.1 14.8h32c8.4 0 17.6-1.8 22.5-8.9v-25.8c-10.5-13.8-39.3-1.3-39.3-13.5 0-5.8 4.6-6.5 9.2-6.5zm-57 39.8h-32.2l-.1 14.8h32.2c14.8 0 26.2-5.6 26.2-22 0-33.2-42.9-11.2-42.9-26.3 0-5.6 4.9-6.4 9.2-6.4h30.4v-14.6h-33.2c-12.8 0-23.5 6.6-23.5 20.7 0 33 42.7 12.5 42.7 27.4-.1 5.4-4.7 6.4-8.8 6.4zm-42.2-40.1v-14.3h-55.2l-.1 69.3h55.2l.1-14.3-38.6-.3v-13.8H445v-14.1h-37.8v-12.5zm-56.3-108.1c-.3.2-1.4 2.2-1.4 7.6 0 6 .9 7.7 1.1 7.9.2.1 1.1.5 3.4.5l7.3-16.9c-1.1 0-2.1-.1-3.1-.1-5.6 0-7 .7-7.3 1zm20.4-10.5h-.1zm-16.2-15.2c-23.5 0-34 12-34 35.3 0 22.2 10.2 34 33 34h19.2l6.4-15.3h34.3l6.6 15.3h33.7v-51.9l31.2 51.9h23.6v-69h-16.9v48.1l-29.1-48.1h-25.3v65.4l-27.9-65.4h-24.8l-23.5 54.5h-7.4c-13.3 0-16.1-8.1-16.1-19.9 0-23.8 15.7-20 33.1-19.7v-15.2zm42.1 12.1l11.2 27.6h-22.8zm-101.1-12v69.3h16.9v-69.3z",
98
+ ],
99
+ },
100
+ personalCheck: {
101
+ viewBox: "0 0 640 512",
102
+ label: "Personal Check",
103
+ paths: [
104
+ "M0 448c0 17.67 14.33 32 32 32h576c17.67 0 32-14.33 32-32V128H0v320zm448-208c0-8.84 7.16-16 16-16h96c8.84 0 16 7.16 16 16v32c0 8.84-7.16 16-16 16h-96c-8.84 0-16-7.16-16-16v-32zm0 120c0-4.42 3.58-8 8-8h112c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H456c-4.42 0-8-3.58-8-8v-16zM64 264c0-4.42 3.58-8 8-8h304c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zm0 96c0-4.42 3.58-8 8-8h176c4.42 0 8 3.58 8 8v16c0 4.42-3.58 8-8 8H72c-4.42 0-8-3.58-8-8v-16zM624 32H16C7.16 32 0 39.16 0 48v48h640V48c0-8.84-7.16-16-16-16z",
105
+ ],
106
+ },
107
+ paypal: {
108
+ viewBox: "0 0 576 512",
109
+ label: "PayPal",
110
+ paths: [
111
+ "M186.3 258.2c0 12.2-9.7 21.5-22 21.5-9.2 0-16-5.2-16-15 0-12.2 9.5-22 21.7-22 9.3 0 16.3 5.7 16.3 15.5zM80.5 209.7h-4.7c-1.5 0-3 1-3.2 2.7l-4.3 26.7 8.2-.3c11 0 19.5-1.5 21.5-14.2 2.3-13.4-6.2-14.9-17.5-14.9zm284 0H360c-1.8 0-3 1-3.2 2.7l-4.2 26.7 8-.3c13 0 22-3 22-18-.1-10.6-9.6-11.1-18.1-11.1zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM128.3 215.4c0-21-16.2-28-34.7-28h-40c-2.5 0-5 2-5.2 4.7L32 294.2c-.3 2 1.2 4 3.2 4h19c2.7 0 5.2-2.9 5.5-5.7l4.5-26.6c1-7.2 13.2-4.7 18-4.7 28.6 0 46.1-17 46.1-45.8zm84.2 8.8h-19c-3.8 0-4 5.5-4.2 8.2-5.8-8.5-14.2-10-23.7-10-24.5 0-43.2 21.5-43.2 45.2 0 19.5 12.2 32.2 31.7 32.2 9 0 20.2-4.9 26.5-11.9-.5 1.5-1 4.7-1 6.2 0 2.3 1 4 3.2 4H200c2.7 0 5-2.9 5.5-5.7l10.2-64.3c.3-1.9-1.2-3.9-3.2-3.9zm40.5 97.9l63.7-92.6c.5-.5.5-1 .5-1.7 0-1.7-1.5-3.5-3.2-3.5h-19.2c-1.7 0-3.5 1-4.5 2.5l-26.5 39-11-37.5c-.8-2.2-3-4-5.5-4h-18.7c-1.7 0-3.2 1.8-3.2 3.5 0 1.2 19.5 56.8 21.2 62.1-2.7 3.8-20.5 28.6-20.5 31.6 0 1.8 1.5 3.2 3.2 3.2h19.2c1.8-.1 3.5-1.1 4.5-2.6zm159.3-106.7c0-21-16.2-28-34.7-28h-39.7c-2.7 0-5.2 2-5.5 4.7l-16.2 102c-.2 2 1.3 4 3.2 4h20.5c2 0 3.5-1.5 4-3.2l4.5-29c1-7.2 13.2-4.7 18-4.7 28.4 0 45.9-17 45.9-45.8zm84.2 8.8h-19c-3.8 0-4 5.5-4.3 8.2-5.5-8.5-14-10-23.7-10-24.5 0-43.2 21.5-43.2 45.2 0 19.5 12.2 32.2 31.7 32.2 9.3 0 20.5-4.9 26.5-11.9-.3 1.5-1 4.7-1 6.2 0 2.3 1 4 3.2 4H484c2.7 0 5-2.9 5.5-5.7l10.2-64.3c.3-1.9-1.2-3.9-3.2-3.9zm47.5-33.3c0-2-1.5-3.5-3.2-3.5h-18.5c-1.5 0-3 1.2-3.2 2.7l-16.2 104-.3.5c0 1.8 1.5 3.5 3.5 3.5h16.5c2.5 0 5-2.9 5.2-5.7L544 191.2v-.3zm-90 51.8c-12.2 0-21.7 9.7-21.7 22 0 9.7 7 15 16.2 15 12 0 21.7-9.2 21.7-21.5.1-9.8-6.9-15.5-16.2-15.5z",
112
+ ],
113
+ },
114
+ venmo: {
115
+ viewBox: "0 0 24 24",
116
+ label: "Venmo",
117
+ paths: [
118
+ "M21.772 13.119c-.267 0-.381-.251-.38-.655 0-.533.121-1.575.712-1.575.267 0 .357.243.357.598 0 .533-.13 1.632-.689 1.632Zm.502-3.377c-1.677 0-2.405 1.285-2.405 2.658 0 1.042.421 1.874 1.693 1.874 1.717 0 2.438-1.406 2.438-2.763 0-1.025-.462-1.769-1.726-1.769Zm-3.833 0c-.558 0-.964.17-1.393.477-.154-.275-.462-.477-.932-.477-.542 0-.947.219-1.247.437l-.04-.364H13.54l-.688 4.354h1.506l.479-3.053c.129-.065.323-.154.518-.154.145 0 .267.049.267.267 0 .056-.016.145-.024.218l-.429 2.722h1.498l.478-3.053c.138-.073.324-.154.51-.154.146 0 .268.049.268.267 0 .056-.017.145-.025.218l-.429 2.722h1.499l.461-2.908c.025-.153.049-.388.049-.549 0-.582-.267-.97-1.037-.97Zm-6.871 0c-.575 0-.98.219-1.287.421l-.017-.348H8.962l-.689 4.354H9.78l.478-3.053c.13-.065.324-.154.518-.154.147 0 .268.049.268.242 0 .081-.024.227-.032.299l-.422 2.666h1.499l.462-2.908c.024-.153.049-.388.049-.549 0-.582-.268-.97-1.03-.97Zm-5.631 1.834c.041-.485.413-.824.697-.824.162 0 .299.097.299.291 0 .404-.713.533-.996.533Zm.843-1.834c-1.604 0-2.382 1.39-2.382 2.698 0 1.01.478 1.817 1.814 1.817.527 0 1.07-.113 1.418-.282l.186-1.26c-.494.25-.874.347-1.271.347-.365 0-.64-.194-.64-.687.826-.008 2.252-.347 2.252-1.453 0-.687-.494-1.18-1.377-1.18Zm-4.239.267c.089.186.146.412.146.743 0 .606-.429 1.494-.777 2.06l-.373-2.989L0 9.969l.705 4.2h1.757c.77-1.01 1.718-2.448 1.718-3.554 0-.347-.073-.622-.235-.889l-1.402.283Z",
119
+ ],
120
+ },
121
+ cashApp: {
122
+ viewBox: "0 0 24 24",
123
+ label: "Cash App",
124
+ paths: [
125
+ "M23.59 3.475a5.1 5.1 0 00-3.05-3.05c-1.31-.42-2.5-.42-4.92-.42H8.36c-2.4 0-3.61 0-4.9.4a5.1 5.1 0 00-3.05 3.06C0 4.765 0 5.965 0 8.365v7.27c0 2.41 0 3.6.4 4.9a5.1 5.1 0 003.05 3.05c1.3.41 2.5.41 4.9.41h7.28c2.41 0 3.61 0 4.9-.4a5.1 5.1 0 003.06-3.06c.41-1.3.41-2.5.41-4.9v-7.25c0-2.41 0-3.61-.41-4.91zm-6.17 4.63l-.93.93a.5.5 0 01-.67.01 5 5 0 00-3.22-1.18c-.97 0-1.94.32-1.94 1.21 0 .9 1.04 1.2 2.24 1.65 2.1.7 3.84 1.58 3.84 3.64 0 2.24-1.74 3.78-4.58 3.95l-.26 1.2a.49.49 0 01-.48.39H9.63l-.09-.01a.5.5 0 01-.38-.59l.28-1.27a6.54 6.54 0 01-2.88-1.57v-.01a.48.48 0 010-.68l1-.97a.49.49 0 01.67 0c.91.86 2.13 1.34 3.39 1.32 1.3 0 2.17-.55 2.17-1.42 0-.87-.88-1.1-2.54-1.72-1.76-.63-3.43-1.52-3.43-3.6 0-2.42 2.01-3.6 4.39-3.71l.25-1.23a.48.48 0 01.48-.38h1.78l.1.01c.26.06.43.31.37.57l-.27 1.37c.9.3 1.75.77 2.48 1.39l.02.02c.19.2.19.5 0 .68z",
126
+ ],
127
+ },
128
+ zelle: {
129
+ viewBox: "0 0 24 24",
130
+ label: "Zelle",
131
+ paths: [
132
+ "M13.559 24h-2.841a.483.483 0 0 1-.483-.483v-2.765H5.638a.667.667 0 0 1-.666-.666v-2.234a.67.67 0 0 1 .142-.412l8.139-10.382h-7.25a.667.667 0 0 1-.667-.667V3.914c0-.367.299-.666.666-.666h4.23V.483c0-.266.217-.483.483-.483h2.841c.266 0 .483.217.483.483v2.765h4.323c.367 0 .666.299.666.666v2.137a.67.67 0 0 1-.141.41l-8.19 10.481h7.665c.367 0 .666.299.666.666v2.477a.667.667 0 0 1-.666.667h-4.32v2.765a.483.483 0 0 1-.483.483Z",
133
+ ],
134
+ },
135
+ applePay: {
136
+ viewBox: "0 0 576 512",
137
+ label: "Apple Pay",
138
+ paths: [
139
+ "M302.2 218.4c0 17.2-10.5 27.1-29 27.1h-24.3v-54.2h24.4c18.4 0 28.9 9.8 28.9 27.1zm47.5 62.6c0 8.3 7.2 13.7 18.5 13.7 14.4 0 25.2-9.1 25.2-21.9v-7.7l-23.5 1.5c-13.3.9-20.2 5.8-20.2 14.4zM576 79v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM127.8 197.2c8.4.7 16.8-4.2 22.1-10.4 5.2-6.4 8.6-15 7.7-23.7-7.4.3-16.6 4.9-21.9 11.3-4.8 5.5-8.9 14.4-7.9 22.8zm60.6 74.5c-.2-.2-19.6-7.6-19.8-30-.2-18.7 15.3-27.7 16-28.2-8.8-13-22.4-14.4-27.1-14.7-12.2-.7-22.6 6.9-28.4 6.9-5.9 0-14.7-6.6-24.3-6.4-12.5.2-24.2 7.3-30.5 18.6-13.1 22.6-3.4 56 9.3 74.4 6.2 9.1 13.7 19.1 23.5 18.7 9.3-.4 13-6 24.2-6 11.3 0 14.5 6 24.3 5.9 10.2-.2 16.5-9.1 22.8-18.2 6.9-10.4 9.8-20.4 10-21zm135.4-53.4c0-26.6-18.5-44.8-44.9-44.8h-51.2v136.4h21.2v-46.6h29.3c26.8 0 45.6-18.4 45.6-45zm90 23.7c0-19.7-15.8-32.4-40-32.4-22.5 0-39.1 12.9-39.7 30.5h19.1c1.6-8.4 9.4-13.9 20-13.9 13 0 20.2 6 20.2 17.2v7.5l-26.4 1.6c-24.6 1.5-37.9 11.6-37.9 29.1 0 17.7 13.7 29.4 33.4 29.4 13.3 0 25.6-6.7 31.2-17.4h.4V310h19.6v-68zM516 210.9h-21.5l-24.9 80.6h-.4l-24.9-80.6H422l35.9 99.3-1.9 6c-3.2 10.2-8.5 14.2-17.9 14.2-1.7 0-4.9-.2-6.2-.3v16.4c1.2.4 6.5.5 8.1.5 20.7 0 30.4-7.9 38.9-31.8L516 210.9z",
140
+ ],
141
+ },
142
+ };
143
+
144
+ /** All supported payment-method keys. */
145
+ export const PAYMENT_ICON_KEYS = Object.keys(
146
+ PAYMENT_ICONS,
147
+ ) as PaymentMethodIconKey[];
148
+
149
+ const THEME_COLORS: Record<PaymentIconTheme, string> = {
150
+ light: "#1a1a1a",
151
+ dark: "#f5f5f5",
152
+ };
153
+
154
+ function resolveColor(options: PaymentIconOptions): string {
155
+ if (options.color) return options.color;
156
+ if (options.theme) return THEME_COLORS[options.theme];
157
+ return "currentColor";
158
+ }
159
+
160
+ function escapeAttr(value: string): string {
161
+ return value
162
+ .replace(/&/g, "&amp;")
163
+ .replace(/"/g, "&quot;")
164
+ .replace(/</g, "&lt;")
165
+ .replace(/>/g, "&gt;");
166
+ }
167
+
168
+ /**
169
+ * Look up the raw icon data for a payment method. Returns `null` for unknown or
170
+ * custom methods so callers can fall back to a text-only label.
171
+ */
172
+ export function paymentIconData(method: string): PaymentIconData | null {
173
+ if (!method) return null;
174
+ return PAYMENT_ICONS[method as PaymentMethodIconKey] ?? null;
175
+ }
176
+
177
+ /**
178
+ * Render a payment-method icon as an `<svg>` markup string, ready to inject in
179
+ * any framework. Returns `null` for unknown/custom methods (render text instead).
180
+ *
181
+ * @example
182
+ * el.innerHTML = paymentIconSvg("visa") ?? ""; // currentColor
183
+ * paymentIconSvg("applePay", { theme: "dark", size: 28 }); // forced light icon
184
+ * paymentIconSvg("zelle", { color: "#6d1ed4" }); // brand color
185
+ */
186
+ export function paymentIconSvg(
187
+ method: string,
188
+ options: PaymentIconOptions = {},
189
+ ): string | null {
190
+ const data = paymentIconData(method);
191
+ if (!data) return null;
192
+ const color = resolveColor(options);
193
+ const size =
194
+ options.size === undefined
195
+ ? "1em"
196
+ : typeof options.size === "number"
197
+ ? String(options.size)
198
+ : options.size;
199
+ const title = options.title === undefined ? data.label : options.title;
200
+ const a11y = title
201
+ ? `role="img" aria-label="${escapeAttr(title)}"`
202
+ : 'aria-hidden="true" focusable="false"';
203
+ const body = data.paths.map((d) => `<path d="${d}"/>`).join("");
204
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${data.viewBox}" width="${size}" height="${size}" fill="${color}" ${a11y}>${body}</svg>`;
205
+ }
package/src/proxy.ts ADDED
@@ -0,0 +1,173 @@
1
+ import {
2
+ BiabDevClient,
3
+ type BiabDevClientOptions,
4
+ BiabDevCustomerPortalClient,
5
+ } from "./client.js";
6
+
7
+ /**
8
+ * Browser-safe customer-portal client.
9
+ *
10
+ * The platform's Package API requires a bearer key — exposing it to a browser
11
+ * would let any visitor read all of the org's data. This client never sends
12
+ * the key directly; it calls a *same-origin* proxy route on your tenant
13
+ * server, and the proxy injects the key + customer-portal org pin server-side.
14
+ *
15
+ * Pattern (Next.js example) — your tenant ships:
16
+ * - this client in browser bundles, configured with `proxyBaseUrl`
17
+ * (e.g. `/api/biab/customer-portal`).
18
+ * - a route at that path that calls {@link createCustomerPortalProxyHandler}
19
+ * with your real BIAB API key + the BIAB org id this site is pinned to.
20
+ *
21
+ * The browser client only knows the proxy URL. The bearer key never leaves
22
+ * the tenant server.
23
+ */
24
+ export type BrowserCustomerPortalClientOptions = {
25
+ /** Same-origin proxy path or absolute URL (e.g. "/api/biab/customer-portal"). */
26
+ proxyBaseUrl: string;
27
+ fetch?: typeof fetch;
28
+ };
29
+
30
+ class BrowserBiabDevClient extends BiabDevClient {
31
+ constructor(options: BrowserCustomerPortalClientOptions) {
32
+ // Pass a placeholder API key — the proxy ignores the Authorization
33
+ // header from the browser and substitutes its own.
34
+ const init: BiabDevClientOptions = {
35
+ baseUrl: options.proxyBaseUrl,
36
+ apiKey: "browser-proxy",
37
+ };
38
+ if (options.fetch) {
39
+ init.fetch = options.fetch;
40
+ }
41
+ super(init);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Browser-only client that talks to your tenant's same-origin proxy route.
47
+ * The proxy injects the BIAB API key and the `X-BIAB-Customer-Portal-Org`
48
+ * pin, so the browser never sees either secret.
49
+ */
50
+ export function createBrowserCustomerPortalClient(
51
+ options: BrowserCustomerPortalClientOptions,
52
+ ) {
53
+ const inner = new BrowserBiabDevClient(options);
54
+ return new BiabDevCustomerPortalClient(inner, null);
55
+ }
56
+
57
+ /**
58
+ * Helper for the *server-side* proxy route a tenant ships. Returns a fetch
59
+ * handler that:
60
+ * - rewrites incoming request paths to the BIAB host's customer-portal API
61
+ * - injects the BIAB API key and `X-BIAB-Customer-Portal-Org` header
62
+ * - forwards the response unchanged.
63
+ *
64
+ * @example // app/api/biab/customer-portal/[...path]/route.ts
65
+ * export const GET = createCustomerPortalProxyHandler({
66
+ * biabBaseUrl: "https://biab.app/api/package/v1",
67
+ * apiKey: process.env.BIAB_API_KEY!,
68
+ * organizationId: process.env.BIAB_ORG_ID!,
69
+ * });
70
+ * export const POST = GET;
71
+ */
72
+ export type CustomerPortalProxyOptions = {
73
+ biabBaseUrl: string;
74
+ apiKey: string;
75
+ /** The BIAB organization id (`org.id` from the portal context) this site is
76
+ * pinned to. Sent as the `X-BIAB-Customer-Portal-Org` header. */
77
+ organizationId?: string;
78
+ /**
79
+ * @deprecated Use {@link organizationId} (the BIAB org id). Still accepted —
80
+ * the platform resolves the pin header by BIAB id or the legacy provider id —
81
+ * but new integrations should pass the BIAB org id and drop any
82
+ * provider-specific env var.
83
+ */
84
+ workosOrganizationId?: string;
85
+ fetch?: typeof fetch;
86
+ /**
87
+ * Origin to send to the platform. Required when the API key has Allowed
88
+ * Host configured on the host (server-to-server `fetch` does not send
89
+ * `Origin`). Accepts a full URL or bare hostname.
90
+ */
91
+ siteOrigin?: string;
92
+ };
93
+
94
+ function normalizeSiteOriginForProxy(
95
+ raw: string | undefined,
96
+ ): string | undefined {
97
+ if (!raw) return undefined;
98
+ const trimmed = raw.trim();
99
+ if (!trimmed) return undefined;
100
+ const withScheme = /^https?:\/\//i.test(trimmed)
101
+ ? trimmed
102
+ : `https://${trimmed}`;
103
+ try {
104
+ const url = new URL(withScheme);
105
+ return `${url.protocol}//${url.host}`;
106
+ } catch {
107
+ return undefined;
108
+ }
109
+ }
110
+
111
+ export function createCustomerPortalProxyHandler(
112
+ options: CustomerPortalProxyOptions,
113
+ ) {
114
+ const fetchImpl = options.fetch ?? fetch;
115
+ const base = options.biabBaseUrl.endsWith("/")
116
+ ? options.biabBaseUrl
117
+ : `${options.biabBaseUrl}/`;
118
+ const siteOrigin = normalizeSiteOriginForProxy(options.siteOrigin);
119
+ // Prefer the BIAB org id; fall back to the deprecated provider-id alias so
120
+ // existing integrations keep working until they migrate.
121
+ const orgPin = options.organizationId ?? options.workosOrganizationId;
122
+ if (!orgPin) {
123
+ throw new Error(
124
+ "createCustomerPortalProxyHandler: `organizationId` is required.",
125
+ );
126
+ }
127
+
128
+ return async (request: Request) => {
129
+ const reqUrl = new URL(request.url);
130
+ // Strip the tenant-side mount prefix and forward everything to the
131
+ // platform's `/customer-portal/...` namespace. The browser client
132
+ // always calls `<proxy>/<verb>` (e.g. `<proxy>/context`) so we just
133
+ // preserve the trailing path.
134
+ const tenantMount = reqUrl.pathname.split("/").pop() ?? "";
135
+ const upstreamPath = `customer-portal/${tenantMount}${reqUrl.search}`;
136
+ const upstream = new URL(upstreamPath, base);
137
+
138
+ const upstreamHeaders = new Headers();
139
+ upstreamHeaders.set("Authorization", `Bearer ${options.apiKey}`);
140
+ upstreamHeaders.set("X-BIAB-Customer-Portal-Org", orgPin);
141
+ upstreamHeaders.set("Accept", "application/json");
142
+ if (siteOrigin) {
143
+ upstreamHeaders.set("Origin", siteOrigin);
144
+ } else {
145
+ const incomingOrigin = request.headers.get("origin");
146
+ if (incomingOrigin && incomingOrigin !== "null") {
147
+ upstreamHeaders.set("Origin", incomingOrigin);
148
+ }
149
+ }
150
+ const incomingContentType = request.headers.get("content-type");
151
+ if (incomingContentType) {
152
+ upstreamHeaders.set("Content-Type", incomingContentType);
153
+ }
154
+
155
+ const init: RequestInit = {
156
+ method: request.method,
157
+ headers: upstreamHeaders,
158
+ };
159
+ if (request.method !== "GET" && request.method !== "HEAD") {
160
+ init.body = await request.text();
161
+ }
162
+
163
+ const upstreamRes = await fetchImpl(upstream, init);
164
+ const body = await upstreamRes.text();
165
+ return new Response(body, {
166
+ status: upstreamRes.status,
167
+ headers: {
168
+ "content-type":
169
+ upstreamRes.headers.get("content-type") ?? "application/json",
170
+ },
171
+ });
172
+ };
173
+ }