@company-semantics/contracts 28.1.0 → 29.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "28.1.0",
3
+ "version": "29.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,7 @@ exports[`email render > auth.otp · Default 1`] = `
8
8
  <body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
9
9
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Copy/paste code in login form:</p>
10
10
  <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; border-radius: 0; margin: 0 0 20px 0;">
11
- <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; letter-spacing: 4px;">
11
+ <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px; letter-spacing: 4px;">
12
12
  <b>&gt;&gt; 123456 &lt;&lt;</b>
13
13
  </td></tr>
14
14
  </table>
@@ -49,7 +49,7 @@ exports[`email render > auth.otp · Short expiry 1`] = `
49
49
  <body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
50
50
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Copy/paste code in login form:</p>
51
51
  <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; border-radius: 0; margin: 0 0 20px 0;">
52
- <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; letter-spacing: 4px;">
52
+ <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px; letter-spacing: 4px;">
53
53
  <b>&gt;&gt; 902413 &lt;&lt;</b>
54
54
  </td></tr>
55
55
  </table>
@@ -90,7 +90,7 @@ exports[`email render > auth.otp · With request metadata 1`] = `
90
90
  <body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
91
91
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Copy/paste code in login form:</p>
92
92
  <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; border-radius: 0; margin: 0 0 20px 0;">
93
- <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; letter-spacing: 4px;">
93
+ <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px; letter-spacing: 4px;">
94
94
  <b>&gt;&gt; 246810 &lt;&lt;</b>
95
95
  </td></tr>
96
96
  </table>
@@ -150,8 +150,8 @@ exports[`email render > chat.shared · Default 1`] = `
150
150
  </tr>
151
151
  </table>
152
152
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; margin: 0 0 16px 0; max-width: 320px; text-align: center;">⋮</p>
153
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 200px;">
154
- <tr><td style="padding: 12px 20px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px;">
153
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
154
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
155
155
  <a href="https://app.companysemantics.ai/share/abc123" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; SEE MORE &lt;&lt;</b></a>
156
156
  </td></tr>
157
157
  </table>
@@ -211,8 +211,8 @@ exports[`email render > chat.shared · Long preview 1`] = `
211
211
  </tr>
212
212
  </table>
213
213
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; margin: 0 0 16px 0; max-width: 320px; text-align: center;">⋮</p>
214
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 200px;">
215
- <tr><td style="padding: 12px 20px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px;">
214
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
215
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
216
216
  <a href="https://app.companysemantics.ai/share/preview789" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; SEE MORE &lt;&lt;</b></a>
217
217
  </td></tr>
218
218
  </table>
@@ -272,8 +272,8 @@ exports[`email render > chat.shared · Long title 1`] = `
272
272
  </tr>
273
273
  </table>
274
274
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; margin: 0 0 16px 0; max-width: 320px; text-align: center;">⋮</p>
275
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 200px;">
276
- <tr><td style="padding: 12px 20px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px;">
275
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
276
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
277
277
  <a href="https://app.companysemantics.ai/share/long456" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; SEE MORE &lt;&lt;</b></a>
278
278
  </td></tr>
279
279
  </table>
@@ -327,8 +327,8 @@ exports[`email render > chat.shared · No preview 1`] = `
327
327
  </tr>
328
328
  </table>
329
329
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; margin: 0 0 16px 0; max-width: 320px; text-align: center;">⋮</p>
330
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 200px;">
331
- <tr><td style="padding: 12px 20px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px;">
330
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
331
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
332
332
  <a href="https://app.companysemantics.ai/share/xyz789" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; SEE MORE &lt;&lt;</b></a>
333
333
  </td></tr>
334
334
  </table>
@@ -382,8 +382,8 @@ exports[`email render > chat.shared · Short 1`] = `
382
382
  </tr>
383
383
  </table>
384
384
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 20px; margin: 0 0 16px 0; max-width: 320px; text-align: center;">⋮</p>
385
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 200px;">
386
- <tr><td style="padding: 12px 20px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px;">
385
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
386
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
387
387
  <a href="https://app.companysemantics.ai/share/short123" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; SEE MORE &lt;&lt;</b></a>
388
388
  </td></tr>
389
389
  </table>
@@ -662,8 +662,8 @@ exports[`email render > org.invite · Admin 1`] = `
662
662
  <head><meta charset="UTF-8"></head>
663
663
  <body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
664
664
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Workspace invitation.</p>
665
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0;">
666
- <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
665
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
666
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
667
667
  <a href="https://app.companysemantics.ai/invite/abc123" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; JOIN &lt;&lt;</b></a>
668
668
  </td></tr>
669
669
  </table>
@@ -706,8 +706,8 @@ exports[`email render > org.invite · Member 1`] = `
706
706
  <head><meta charset="UTF-8"></head>
707
707
  <body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
708
708
  <p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Workspace invitation.</p>
709
- <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0;">
710
- <tr><td style="padding: 20px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
709
+ <table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
710
+ <tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
711
711
  <a href="https://app.companysemantics.ai/invite/def456" style="color: #0047FF; text-decoration: underline;"><b>&gt;&gt; JOIN &lt;&lt;</b></a>
712
712
  </td></tr>
713
713
  </table>
@@ -33,13 +33,7 @@ export function renderAuthOtp(
33
33
 
34
34
  const blocks: Block[] = [
35
35
  paragraph("Copy/paste code in login form:"),
36
- ctaBox({
37
- label: otp,
38
- padding: "20px 24px",
39
- fontSize: "20px",
40
- borderRadiusZero: true,
41
- letterSpacing: "4px",
42
- }),
36
+ ctaBox({ label: otp, variant: "code" }),
43
37
  keyValue("Status", "VALID"),
44
38
  keyValue(
45
39
  "Expires in",
@@ -190,17 +190,35 @@ export interface CtaBoxOptions {
190
190
  /** When present, the label links to this URL (and the URL rides under the
191
191
  * plain-text box). */
192
192
  href?: string;
193
- /** Inner-cell padding, e.g. `"16px 24px"`. */
193
+ /** Visual kind. `"action"` = link CTA (default); `"code"` = copy/paste code
194
+ * box (square corners, letter-spaced). */
195
+ variant?: "action" | "code";
196
+ }
197
+
198
+ /** Component-owned styling per CTA variant. Templates supply only `label`/`href`/
199
+ * `variant` — the only allowable UI is the component, so all CSS lives here,
200
+ * never at the call site. */
201
+ interface CtaVariantStyle {
194
202
  padding: string;
195
- /** Label font-size, e.g. `"16px"`. */
196
203
  fontSize: string;
197
- /** Optional table `max-width`, e.g. `"220px"`. */
198
204
  maxWidth?: string;
199
- /** Emit `border-radius: 0;` (OTP code box). */
200
- borderRadiusZero?: boolean;
201
- /** Optional `letter-spacing`, e.g. `"4px"` (OTP code box). */
205
+ square: boolean;
202
206
  letterSpacing?: string;
203
207
  }
208
+ const CTA_VARIANTS: Record<"action" | "code", CtaVariantStyle> = {
209
+ action: {
210
+ padding: "16px 24px",
211
+ fontSize: "16px",
212
+ maxWidth: "220px",
213
+ square: false,
214
+ },
215
+ code: {
216
+ padding: "20px 24px",
217
+ fontSize: "16px",
218
+ square: true,
219
+ letterSpacing: "4px",
220
+ },
221
+ };
204
222
 
205
223
  /** Padding columns on each side of the `>> LABEL <<` line in the ASCII box. */
206
224
  const CTA_BOX_PAD = 3;
@@ -216,19 +234,13 @@ function asciiCtaBox(label: string): string {
216
234
  /** The bordered `>> LABEL <<` CTA box (OTP / JOIN / OPEN / VIEW TEAM / …). When
217
235
  * `href` is given, HTML links the label and plain text prints the URL below. */
218
236
  export function ctaBox(opts: CtaBoxOptions): Block {
219
- const {
220
- label,
221
- href,
222
- padding,
223
- fontSize,
224
- maxWidth,
225
- borderRadiusZero,
226
- letterSpacing,
227
- } = opts;
237
+ const { label, href, variant = "action" } = opts;
238
+ const { padding, fontSize, maxWidth, square, letterSpacing } =
239
+ CTA_VARIANTS[variant];
228
240
 
229
241
  const tableStyle =
230
242
  `border: 2px solid #1a1a1a;` +
231
- (borderRadiusZero ? ` border-radius: 0;` : ``) +
243
+ (square ? ` border-radius: 0;` : ``) +
232
244
  ` margin: 0 0 20px 0;` +
233
245
  (maxWidth ? ` max-width: ${maxWidth};` : ``);
234
246
 
@@ -31,13 +31,7 @@ export function renderChatShared(payload: ChatSharedPayload): Block[] {
31
31
 
32
32
  blocks.push(
33
33
  chatDots(),
34
- ctaBox({
35
- label: "SEE MORE",
36
- href: shareUrl,
37
- padding: "12px 20px",
38
- fontSize: "14px",
39
- maxWidth: "200px",
40
- }),
34
+ ctaBox({ label: "SEE MORE", href: shareUrl }),
41
35
  footer(`This share was sent via ${COMPANY_NAME}.`),
42
36
  paragraph(NOTICE, "tight"),
43
37
  signature(),
@@ -30,13 +30,7 @@ export function renderAccessApproved(payload: AccessApprovedPayload): Block[] {
30
30
  bold(`"${docTitle}"`),
31
31
  ` — you ${ACCESS_PHRASE[accessLevel]}.`,
32
32
  ]),
33
- ctaBox({
34
- label: "OPEN",
35
- href: docUrl,
36
- padding: "16px 24px",
37
- fontSize: "16px",
38
- maxWidth: "220px",
39
- }),
33
+ ctaBox({ label: "OPEN", href: docUrl }),
40
34
  footer(`This notification was sent via ${COMPANY_NAME}.`),
41
35
  signature(),
42
36
  ];
@@ -39,13 +39,7 @@ export function renderAccessRequested(
39
39
  if (message) blocks.push(chatUser(message, `Message from ${requesterName}`));
40
40
 
41
41
  blocks.push(
42
- ctaBox({
43
- label: "REVIEW",
44
- href: reviewUrl,
45
- padding: "16px 24px",
46
- fontSize: "16px",
47
- maxWidth: "220px",
48
- }),
42
+ ctaBox({ label: "REVIEW", href: reviewUrl }),
49
43
  footer(`This notification was sent via ${COMPANY_NAME}.`, OWNER_NOTE),
50
44
  signature(),
51
45
  );
@@ -22,12 +22,7 @@ export function renderOrgInvite(payload: OrgInvitePayload): Block[] {
22
22
 
23
23
  return [
24
24
  paragraph("Workspace invitation."),
25
- ctaBox({
26
- label: "JOIN",
27
- href: acceptUrl,
28
- padding: "20px 24px",
29
- fontSize: "16px",
30
- }),
25
+ ctaBox({ label: "JOIN", href: acceptUrl }),
31
26
  keyValue("From", inviterName),
32
27
  keyValue("Workspace", orgName),
33
28
  keyValue("Role", role),
@@ -33,13 +33,7 @@ export function renderOwnershipTransfer(
33
33
  if (note) blocks.push(chatUser(note, "Message from the current owner"));
34
34
 
35
35
  blocks.push(
36
- ctaBox({
37
- label: "ACCEPT",
38
- href: acceptUrl,
39
- padding: "16px 24px",
40
- fontSize: "16px",
41
- maxWidth: "220px",
42
- }),
36
+ ctaBox({ label: "ACCEPT", href: acceptUrl }),
43
37
  keyValue("Expires in", `${expiresInDays} days`, "normal"),
44
38
  footer(
45
39
  "If you did not expect this invitation, you can safely ignore this email.",
@@ -49,13 +49,7 @@ export function renderShareGranted(payload: ShareGrantedPayload): Block[] {
49
49
  if (message) blocks.push(chatUser(message, `Message from ${granterName}`));
50
50
 
51
51
  blocks.push(
52
- ctaBox({
53
- label: "OPEN",
54
- href: ctaUrl,
55
- padding: "16px 24px",
56
- fontSize: "16px",
57
- maxWidth: "220px",
58
- }),
52
+ ctaBox({ label: "OPEN", href: ctaUrl }),
59
53
  footer(`This notification was sent via ${COMPANY_NAME}.`, NOTICE),
60
54
  signature(),
61
55
  );
@@ -40,13 +40,7 @@ export function renderUnitOwnerGranted(
40
40
  if (message) blocks.push(chatUser(message, `Message from ${granterName}`));
41
41
 
42
42
  blocks.push(
43
- ctaBox({
44
- label: "VIEW TEAM",
45
- href: ctaUrl,
46
- padding: "16px 24px",
47
- fontSize: "16px",
48
- maxWidth: "220px",
49
- }),
43
+ ctaBox({ label: "VIEW TEAM", href: ctaUrl }),
50
44
  footer(`This notification was sent via ${COMPANY_NAME}.`, NOTICE),
51
45
  signature(),
52
46
  );