@agent-native/core 0.138.0 → 0.140.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 (100) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/server/lib/dashboard-report.ts +2 -0
  3. package/corpus/templates/analytics/server/lib/emails.ts +51 -0
  4. package/corpus/templates/analytics/server/plugins/transactional-emails.ts +5 -0
  5. package/corpus/templates/calendar/server/lib/booking-emails.ts +154 -70
  6. package/corpus/templates/calendar/server/lib/emails.ts +167 -0
  7. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +64 -28
  8. package/corpus/templates/calendar/server/plugins/transactional-emails.ts +5 -0
  9. package/corpus/templates/clips/actions/invite-member.ts +39 -15
  10. package/corpus/templates/clips/server/lib/emails.ts +256 -0
  11. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +24 -0
  12. package/corpus/templates/clips/server/plugins/transactional-email-catalog.ts +5 -0
  13. package/corpus/templates/content/server/lib/comment-notifications.ts +57 -26
  14. package/corpus/templates/content/server/lib/emails.ts +70 -0
  15. package/corpus/templates/content/server/plugins/transactional-emails.ts +5 -0
  16. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +44 -1
  17. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +265 -1
  18. package/corpus/templates/design/actions/create-design-system.ts +9 -10
  19. package/corpus/templates/design/actions/get-design-system.ts +53 -0
  20. package/corpus/templates/design/actions/import-design-tokens.ts +5 -71
  21. package/corpus/templates/design/actions/index-design-tokens.ts +61 -80
  22. package/corpus/templates/design/actions/update-design-system.ts +7 -10
  23. package/corpus/templates/design/app/components/design/EditPanel.tsx +45 -2
  24. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +12 -0
  25. package/corpus/templates/design/app/components/design/edit-panel/design-system-swatches.ts +215 -0
  26. package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +10 -6
  27. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +19 -3
  28. package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +36 -10
  29. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +15 -0
  30. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +19 -1
  31. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +6 -0
  32. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +53 -10
  33. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +142 -4
  34. package/corpus/templates/design/app/components/design/types.ts +6 -0
  35. package/corpus/templates/design/app/i18n-data.ts +20 -0
  36. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
  37. package/corpus/templates/design/app/pages/DesignSystems.tsx +78 -1
  38. package/corpus/templates/design/app/pages/design-editor/html-layer-positioning.ts +6 -1
  39. package/corpus/templates/design/changelog/2026-08-04-design-system-tokens-show-by-name-in-the-editor.md +6 -0
  40. package/corpus/templates/design/e2e/helpers.ts +17 -0
  41. package/corpus/templates/design/server/lib/design-system-tokens.ts +35 -0
  42. package/corpus/templates/design/shared/authored-color-styles.ts +401 -0
  43. package/corpus/templates/design/shared/resolve-tweaks.ts +10 -18
  44. package/corpus/templates/dispatch/app/routes/transactional-email.$appId.$id.tsx +4 -0
  45. package/corpus/templates/dispatch/app/routes/transactional-email.tsx +4 -0
  46. package/corpus/templates/forms/server/lib/emails.ts +52 -0
  47. package/corpus/templates/forms/server/lib/response-email.ts +2 -0
  48. package/corpus/templates/forms/server/plugins/transactional-emails.ts +5 -0
  49. package/corpus/templates/plan/actions/request-plan-access.ts +33 -12
  50. package/corpus/templates/plan/server/lib/comment-notifications.ts +53 -27
  51. package/corpus/templates/plan/server/lib/emails.ts +67 -0
  52. package/corpus/templates/plan/server/plugins/transactional-emails.ts +5 -0
  53. package/corpus/templates/slides/server/lib/comment-notifications.ts +44 -21
  54. package/corpus/templates/slides/server/lib/emails.ts +40 -0
  55. package/corpus/templates/slides/server/plugins/transactional-emails.ts +5 -0
  56. package/dist/brand-kit/index.d.ts +1 -0
  57. package/dist/brand-kit/index.js +1 -0
  58. package/dist/brand-kit/tokens.d.ts +92 -0
  59. package/dist/brand-kit/tokens.js +280 -0
  60. package/dist/brand-kit/types.d.ts +25 -0
  61. package/dist/collab/awareness.d.ts +2 -2
  62. package/dist/collab/routes.d.ts +2 -2
  63. package/dist/email-catalog/actions/list-email-activity.d.ts +6 -0
  64. package/dist/email-catalog/actions/list-email-activity.js +15 -0
  65. package/dist/email-catalog/actions/list-email-engagement.d.ts +6 -0
  66. package/dist/email-catalog/actions/list-email-engagement.js +15 -0
  67. package/dist/email-catalog/actions/list-email-log.d.ts +8 -0
  68. package/dist/email-catalog/actions/list-email-log.js +22 -0
  69. package/dist/email-catalog/actions/list-transactional-emails.d.ts +23 -0
  70. package/dist/email-catalog/actions/list-transactional-emails.js +61 -0
  71. package/dist/email-catalog/actions/render-transactional-email-preview.d.ts +10 -0
  72. package/dist/email-catalog/actions/render-transactional-email-preview.js +24 -0
  73. package/dist/email-catalog/authorize.d.ts +2 -0
  74. package/dist/email-catalog/authorize.js +10 -0
  75. package/dist/email-catalog/log.d.ts +57 -0
  76. package/dist/email-catalog/log.js +117 -0
  77. package/dist/email-catalog/provider-metrics.d.ts +34 -0
  78. package/dist/email-catalog/provider-metrics.js +165 -0
  79. package/dist/email-catalog/registry.d.ts +79 -0
  80. package/dist/email-catalog/registry.js +71 -0
  81. package/dist/email-catalog/schema.d.ts +212 -0
  82. package/dist/email-catalog/schema.js +49 -0
  83. package/dist/email-catalog/system-emails.d.ts +14 -0
  84. package/dist/email-catalog/system-emails.js +68 -0
  85. package/dist/localization/default-messages.d.ts +45 -0
  86. package/dist/localization/default-messages.js +45 -0
  87. package/dist/notifications/routes.d.ts +6 -6
  88. package/dist/org/handlers.js +8 -1
  89. package/dist/progress/routes.d.ts +1 -1
  90. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  91. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  92. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  93. package/dist/resources/handlers.d.ts +1 -1
  94. package/dist/server/action-discovery.js +22 -0
  95. package/dist/server/better-auth-instance.js +17 -2
  96. package/dist/server/email.d.ts +9 -0
  97. package/dist/server/email.js +44 -3
  98. package/dist/server/index.d.ts +1 -0
  99. package/dist/server/index.js +1 -0
  100. package/package.json +3 -1
@@ -14,6 +14,8 @@ import {
14
14
  import type { PlanBundle, PlanComment } from "../../shared/types.js";
15
15
  import { getDb, schema } from "../db/index.js";
16
16
 
17
+ export const PLAN_COMMENT_EMAIL_ID = "plan.plan-comment";
18
+
17
19
  type CommentNotificationInput = {
18
20
  bundle: PlanBundle;
19
21
  insertedCommentIds: string[];
@@ -205,40 +207,64 @@ export function planCommentNotificationRecipients(input: {
205
207
  return Array.from(recipients.values());
206
208
  }
207
209
 
208
- async function sendPlanCommentNotification(input: {
209
- recipient: NotificationRecipient;
210
- comment: PlanComment;
210
+ export function renderPlanCommentEmail(input: {
211
+ actor: string;
212
+ app: string;
211
213
  planTitle: string;
212
- planId: string;
214
+ planUrl: string;
215
+ message: string;
216
+ isReply: boolean;
217
+ reason: NotificationRecipient["reason"];
213
218
  }) {
214
- const actor = actorName(input.comment);
215
- const app = appName();
216
- const isReply = Boolean(input.comment.parentCommentId);
217
- const subject = isReply
218
- ? `${actor} replied to a comment on "${input.planTitle}"`
219
- : `${actor} commented on "${input.planTitle}"`;
220
219
  const actionText =
221
- input.recipient.reason === "mention"
220
+ input.reason === "mention"
222
221
  ? "mentioned you in a comment on"
223
- : input.recipient.reason === "plan-owner"
222
+ : input.reason === "plan-owner"
224
223
  ? "left a comment on your plan"
225
224
  : "replied in a comment thread you participated in";
226
- const { html, text } = renderEmail({
227
- preheader: `${actor} ${actionText} on ${app}.`,
228
- heading: isReply ? "New reply on your plan" : "New comment on your plan",
229
- paragraphs: [
230
- `${emailStrong(actor)} ${actionText} ${emailStrong(input.planTitle)}.`,
231
- `Comment: "${commentExcerpt(input.comment.message)}"`,
232
- ],
233
- cta: { label: "Open plan", url: planUrl(input.planId) },
234
- footer:
235
- input.recipient.reason === "plan-owner"
236
- ? "You received this because you own this plan."
237
- : input.recipient.reason === "mention"
238
- ? "You received this because you were mentioned in this comment."
239
- : "You received this because you participated in this comment thread.",
225
+ return {
226
+ subject: input.isReply
227
+ ? `${input.actor} replied to a comment on "${input.planTitle}"`
228
+ : `${input.actor} commented on "${input.planTitle}"`,
229
+ ...renderEmail({
230
+ preheader: `${input.actor} ${actionText} on ${input.app}.`,
231
+ heading: input.isReply
232
+ ? "New reply on your plan"
233
+ : "New comment on your plan",
234
+ paragraphs: [
235
+ `${emailStrong(input.actor)} ${actionText} ${emailStrong(input.planTitle)}.`,
236
+ `Comment: "${commentExcerpt(input.message)}"`,
237
+ ],
238
+ cta: { label: "Open plan", url: input.planUrl },
239
+ footer:
240
+ input.reason === "plan-owner"
241
+ ? "You received this because you own this plan."
242
+ : input.reason === "mention"
243
+ ? "You received this because you were mentioned in this comment."
244
+ : "You received this because you participated in this comment thread.",
245
+ }),
246
+ };
247
+ }
248
+
249
+ async function sendPlanCommentNotification(input: {
250
+ recipient: NotificationRecipient;
251
+ comment: PlanComment;
252
+ planTitle: string;
253
+ planId: string;
254
+ }) {
255
+ await sendEmail({
256
+ ...renderPlanCommentEmail({
257
+ actor: actorName(input.comment),
258
+ app: appName(),
259
+ planTitle: input.planTitle,
260
+ planUrl: planUrl(input.planId),
261
+ message: input.comment.message,
262
+ isReply: Boolean(input.comment.parentCommentId),
263
+ reason: input.recipient.reason,
264
+ }),
265
+ to: input.recipient.email,
266
+ templateId: PLAN_COMMENT_EMAIL_ID,
240
267
  });
241
- await sendEmail({ to: input.recipient.email, subject, html, text });
242
268
  }
243
269
 
244
270
  export async function notifyPlanCommentRecipients({
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Catalog entries for the transactional emails Plan sends.
3
+ *
4
+ * Registered from `server/plugins/transactional-emails.ts` so Dispatch can list
5
+ * and preview them without the app having sent anything yet.
6
+ */
7
+
8
+ import { defineTransactionalEmail } from "@agent-native/core/email-catalog";
9
+
10
+ import {
11
+ PLAN_ACCESS_REQUEST_EMAIL_ID,
12
+ renderPlanAccessRequestEmail,
13
+ } from "../../actions/request-plan-access.js";
14
+ import {
15
+ PLAN_COMMENT_EMAIL_ID,
16
+ renderPlanCommentEmail,
17
+ } from "./comment-notifications.js";
18
+
19
+ let registered = false;
20
+
21
+ export function registerPlanEmails(): void {
22
+ if (registered) return;
23
+ registered = true;
24
+
25
+ defineTransactionalEmail({
26
+ id: PLAN_COMMENT_EMAIL_ID,
27
+ name: "Plan comment",
28
+ trigger:
29
+ "A human (never the agent) posts a comment or reply on a plan or recap. The subject changes for a reply and the body changes with why the recipient was picked; all variants send under this id.",
30
+ recipientLabel: "Owner, mentions, authors",
31
+ recipient:
32
+ "The plan owner, everyone mentioned in the comment, and — for a reply — every other human author in the same thread. The comment's own author, synthetic QA addresses, and the owner when the comment mentions the source author are all dropped. One email per remaining address.",
33
+ senderLabel: "Default sender",
34
+ sender:
35
+ "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`.",
36
+ preview: () =>
37
+ renderPlanCommentEmail({
38
+ actor: "Sam Rivera",
39
+ app: "Agent-Native Plan",
40
+ planTitle: "Checkout rewrite",
41
+ planUrl: "https://example.com/plans/plan_sample",
42
+ message: "Can we split the migration into two deploys?",
43
+ isReply: false,
44
+ reason: "plan-owner",
45
+ }),
46
+ });
47
+
48
+ defineTransactionalEmail({
49
+ id: PLAN_ACCESS_REQUEST_EMAIL_ID,
50
+ name: "Plan access request",
51
+ trigger:
52
+ "A signed-in user who cannot resolve access calls `request-plan-access` on a private plan URL. Skipped when email is not configured or the requester is the owner.",
53
+ recipientLabel: "Plan owner",
54
+ recipient:
55
+ "The plan's `ownerEmail` column. Anonymous public viewers and guest author identities cannot reach this path.",
56
+ senderLabel: "Default sender",
57
+ sender:
58
+ "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`, so the owner cannot reply straight to the requester.",
59
+ preview: () =>
60
+ renderPlanAccessRequestEmail({
61
+ requesterName: "Sam Rivera",
62
+ requesterEmail: "sam.rivera@example.com",
63
+ planTitle: "Checkout rewrite",
64
+ url: "https://example.com/plans/plan_sample",
65
+ }),
66
+ });
67
+ }
@@ -0,0 +1,5 @@
1
+ import { registerPlanEmails } from "../lib/emails.js";
2
+
3
+ export default function registerTransactionalEmails(): void {
4
+ registerPlanEmails();
5
+ }
@@ -21,6 +21,7 @@ import { and, eq } from "drizzle-orm";
21
21
  import { getDeckUrl } from "../../actions/_app-url.js";
22
22
  import { SLIDES_USER_PREFS_KEY } from "../../shared/slides-user-prefs.js";
23
23
  import { getDb, schema } from "../db/index.js";
24
+ import { SLIDES_DECK_COMMENT_EMAIL_ID } from "./emails.js";
24
25
 
25
26
  /**
26
27
  * `deck-missing` stays distinct from `no-recipients`: one means the deck could
@@ -99,6 +100,41 @@ async function threadParticipants(
99
100
  return rows.map((row) => row.authorEmail);
100
101
  }
101
102
 
103
+ export function renderDeckCommentEmail({
104
+ actor,
105
+ title,
106
+ url,
107
+ content,
108
+ isReply,
109
+ }: {
110
+ actor: string;
111
+ title: string;
112
+ url: string;
113
+ content: string;
114
+ isReply: boolean;
115
+ }) {
116
+ return {
117
+ subject: isReply
118
+ ? `${actor} replied to a comment on "${title}"`
119
+ : `${actor} commented on "${title}"`,
120
+ ...renderEmail({
121
+ preheader: isReply
122
+ ? `${actor} replied to a comment on ${title}.`
123
+ : `${actor} commented on ${title}.`,
124
+ heading: isReply ? "New reply on your deck" : "New comment",
125
+ paragraphs: [
126
+ isReply
127
+ ? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(title)}.`
128
+ : `${emailStrong(actor)} commented on ${emailStrong(title)}.`,
129
+ `"${excerpt(content)}"`,
130
+ ],
131
+ cta: { label: "Open deck", url },
132
+ footer:
133
+ "You received this because you own or participated in this thread. Turn these off in Slides settings.",
134
+ }),
135
+ };
136
+ }
137
+
102
138
  export async function notifyDeckComment(input: {
103
139
  deckId: string;
104
140
  slideId: string;
@@ -153,29 +189,16 @@ async function deliverDeckCommentEmails(input: {
153
189
  preferenceKey: SLIDES_USER_PREFS_KEY,
154
190
  logLabel: LOG_LABEL,
155
191
  send: async (to) => {
156
- const { html, text } = renderEmail({
157
- preheader: input.isReply
158
- ? `${actor} replied to a comment on ${deck.title}.`
159
- : `${actor} commented on ${deck.title}.`,
160
- heading: input.isReply ? "New reply on your deck" : "New comment",
161
- paragraphs: [
162
- input.isReply
163
- ? `${emailStrong(actor)} replied in a comment thread on ${emailStrong(deck.title)}.`
164
- : `${emailStrong(actor)} commented on ${emailStrong(deck.title)}.`,
165
- `"${excerpt(input.content)}"`,
166
- ],
167
- cta: { label: "Open deck", url },
168
- footer:
169
- "You received this because you own or participated in this thread. Turn these off in Slides settings.",
170
- });
171
-
172
192
  await sendEmail({
193
+ ...renderDeckCommentEmail({
194
+ actor,
195
+ title: deck.title,
196
+ url,
197
+ content: input.content,
198
+ isReply: input.isReply,
199
+ }),
173
200
  to,
174
- subject: input.isReply
175
- ? `${actor} replied to a comment on "${deck.title}"`
176
- : `${actor} commented on "${deck.title}"`,
177
- html,
178
- text,
201
+ templateId: SLIDES_DECK_COMMENT_EMAIL_ID,
179
202
  });
180
203
  },
181
204
  });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Catalog entries for the transactional emails Slides sends.
3
+ *
4
+ * Registered from `server/plugins/transactional-emails.ts` so Dispatch can list
5
+ * and preview them without the app having sent anything yet.
6
+ */
7
+
8
+ import { defineTransactionalEmail } from "@agent-native/core/email-catalog";
9
+
10
+ import { renderDeckCommentEmail } from "./comment-notifications.js";
11
+
12
+ export const SLIDES_DECK_COMMENT_EMAIL_ID = "slides.deck-comment";
13
+
14
+ let registered = false;
15
+
16
+ export function registerSlidesEmails(): void {
17
+ if (registered) return;
18
+ registered = true;
19
+
20
+ defineTransactionalEmail({
21
+ id: SLIDES_DECK_COMMENT_EMAIL_ID,
22
+ name: "Deck comment",
23
+ trigger:
24
+ "Someone posts a comment or a thread reply on a slide. Subject and copy differ slightly for a reply; both send under this id.",
25
+ recipientLabel: "Deck owner and authors",
26
+ recipient:
27
+ "The deck owner, plus every prior author in the thread when the new comment is a reply. The list is re-checked against the deck's live ACL and filtered by each user's `emailNotifications` preference; the comment's own author never receives it.",
28
+ senderLabel: "Default sender",
29
+ sender:
30
+ "The configured default sender. This call site sets no `from`, `fromName`, `replyTo`, or `appSender`.",
31
+ preview: () =>
32
+ renderDeckCommentEmail({
33
+ actor: "Sam Rivera",
34
+ title: "Series A narrative",
35
+ url: "https://example.com/decks/deck_sample?slide=3",
36
+ content: "Slide 3 needs the updated revenue chart before Thursday.",
37
+ isReply: false,
38
+ }),
39
+ });
40
+ }
@@ -0,0 +1,5 @@
1
+ import { registerSlidesEmails } from "../lib/emails.js";
2
+
3
+ export default function registerTransactionalEmails(): void {
4
+ registerSlidesEmails();
5
+ }
@@ -16,6 +16,7 @@
16
16
  */
17
17
  export * from "./types.js";
18
18
  export * from "./brand-signals.js";
19
+ export * from "./tokens.js";
19
20
  export { extractDesignTokensFromUrl, validateUrl, parseOwnerRepo, fetchGitHubJson, fetchGitHubJsonResult, fetchGitHubRaw, parseTailwindConfig, parseCss, detectStylingFramework, createCodeAnalysisState, analyzeCodeFile, analyzeCssFile, analyzeTailwindConfig, analyzeJsonTheme, analyzePackageJson, analyzeThemeSourceFile, addFont, extractCssVars, extractCodeColors, extractCodeFonts, extractDocumentColors, extractDocumentFonts, classifyFile, suggestionsForType, unique, MAX_FILES, MAX_FILE_SIZE, FETCH_TIMEOUT, ROOT_PATTERNS, SECONDARY_PATHS, CODE_MAX_FILES, CODE_MAX_TOTAL_BYTES, } from "../server/design-token-utils.js";
20
21
  export type { ContentType, ParsedCss, ParsedTailwindConfig, CodeAnalysisState, UrlExtractionResult, GitHubFetchOptions, GitHubJsonResult, } from "../server/design-token-utils.js";
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -16,6 +16,7 @@
16
16
  */
17
17
  export * from "./types.js";
18
18
  export * from "./brand-signals.js";
19
+ export * from "./tokens.js";
19
20
  // Import-source parsing + token extraction (Tailwind/CSS/GitHub/URL/document/
20
21
  // code analysis). These already power the import-* actions across templates.
21
22
  export {
@@ -0,0 +1,92 @@
1
+ /**
2
+ * `@agent-native/core/brand-kit/tokens`
3
+ *
4
+ * Pure helpers for the named-token vocabulary a Brand Kit stores alongside its
5
+ * seven color roles. Kept on its own subpath (no `design-token-utils` re-export)
6
+ * so browser code can import the CSS-safety predicates without pulling the
7
+ * server-side extraction stack into the bundle.
8
+ */
9
+ import type { BrandKitToken, BrandKitTokenType } from "./types.js";
10
+ /**
11
+ * Upper bound on a single kit's stored vocabulary. Large systems legitimately
12
+ * define hundreds of tokens; this only stops an unbounded scrape landing in SQL.
13
+ */
14
+ export declare const MAX_BRAND_KIT_TOKENS = 500;
15
+ export declare function isSafeCssVarName(value: string): boolean;
16
+ /**
17
+ * Token values are spliced raw into `:root { … }` declarations, so anything that
18
+ * could terminate a declaration or break out of a `<style>` element is unsafe.
19
+ */
20
+ export declare function isSafeCssTokenValue(value: string): boolean;
21
+ export declare function isColorTokenValue(value: string): boolean;
22
+ /**
23
+ * Bucket a token, trusting the value's shape over the name's keywords.
24
+ *
25
+ * Name-first classification called Primer's `--text-body-size-medium: 1rem` a
26
+ * color because the name contains "text", which then rendered a swatch with
27
+ * `background: 1rem`. A dimension is never a color however the token is named.
28
+ */
29
+ export declare function classifyBrandKitToken(name: string, value: string): BrandKitTokenType;
30
+ /** Title-case display name derived from a CSS var, e.g. `--primary-color`. */
31
+ export declare function friendlyTokenName(cssVar: string): string;
32
+ export type BrandKitTokenRejectionReason = "malformed" | "unsafe-css-var" | "unsafe-value" | "over-limit";
33
+ export interface BrandKitTokenRejection {
34
+ reason: BrandKitTokenRejectionReason;
35
+ /** Best-effort identifier for the offending entry, for error messages. */
36
+ label: string;
37
+ }
38
+ export interface NormalizedBrandKitTokens {
39
+ tokens: BrandKitToken[];
40
+ /**
41
+ * Entries that could not be stored. Callers must surface these — a kit that
42
+ * silently kept 4 of 40 tokens reads downstream as a 4-token design system.
43
+ */
44
+ rejected: BrandKitTokenRejection[];
45
+ }
46
+ /**
47
+ * Coerce untrusted token JSON into storable tokens, reporting every entry it
48
+ * could not accept. Later duplicates of a `cssVar` win, matching the overlay
49
+ * order importers use.
50
+ */
51
+ export declare function normalizeBrandKitTokens(input: unknown): NormalizedBrandKitTokens;
52
+ /** Human-readable summary of why tokens were refused, for thrown errors. */
53
+ export declare function describeBrandKitTokenRejections(rejected: readonly BrandKitTokenRejection[]): string;
54
+ /**
55
+ * The seven colour roles plus radius/spacing, as tokens. Derived from a kit's
56
+ * summary fields rather than named by the source system, so they carry no
57
+ * `group`.
58
+ */
59
+ export declare function brandKitRoleTokens(data: {
60
+ colors?: object | null;
61
+ borders?: {
62
+ radius?: string;
63
+ } | null;
64
+ spacing?: object | null;
65
+ } | null | undefined, source?: string): BrandKitToken[];
66
+ /**
67
+ * Read a kit's named tokens out of a raw CSS block. A kit's `customCSS` already
68
+ * spells out the source system's real token names. Declaration order wins on
69
+ * duplicates, matching the cascade.
70
+ */
71
+ export declare function parseBrandKitTokensFromCss(css: string, source?: string): BrandKitToken[];
72
+ /**
73
+ * The kit's named vocabulary: its stored `tokens` when it has them, else the
74
+ * names its `customCSS` declares. Kits predating `tokens` still carry real names
75
+ * in CSS, so reading only `tokens` would report them as having none.
76
+ */
77
+ export declare function resolveBrandKitTokens(data: {
78
+ tokens?: unknown;
79
+ customCSS?: unknown;
80
+ } | null | undefined, cssSource?: string): BrandKitToken[];
81
+ export interface BrandKitTokenGroup {
82
+ /** The source's own group path when it has one, else the token type. */
83
+ label: string;
84
+ type: BrandKitTokenType;
85
+ tokens: BrandKitToken[];
86
+ }
87
+ /**
88
+ * Group tokens for display, preserving the source's collection paths. Groups sort
89
+ * by token type so colors lead, then alphabetically within a type.
90
+ */
91
+ export declare function groupBrandKitTokens(tokens: readonly BrandKitToken[]): BrandKitTokenGroup[];
92
+ //# sourceMappingURL=tokens.d.ts.map