@company-semantics/contracts 28.0.0 → 28.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -745,6 +745,21 @@ Questions? Contact support@companysemantics.ai
|
|
|
745
745
|
|
|
746
746
|
exports[`email render > org.ownership_transfer · No note 1`] = `
|
|
747
747
|
{
|
|
748
|
+
"html": "<!DOCTYPE html>
|
|
749
|
+
<html lang="en">
|
|
750
|
+
<head><meta charset="UTF-8"></head>
|
|
751
|
+
<body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
|
|
752
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">You have been invited to become the owner of <b>"Acme Corp"</b>.</p>
|
|
753
|
+
<table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
|
|
754
|
+
<tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
|
|
755
|
+
<a href="https://app.companysemantics.ai/owner-transfer/accept/tok456" style="color: #0047FF; text-decoration: underline;"><b>>> ACCEPT <<</b></a>
|
|
756
|
+
</td></tr>
|
|
757
|
+
</table>
|
|
758
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Expires in: <b>14 days</b></p>
|
|
759
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">If you did not expect this invitation, you can safely ignore this email.</p>
|
|
760
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0;">Company Semantics<br><span style="color: #888;">Questions? Contact <a href="mailto:support@companysemantics.ai" style="color: #888;">support@companysemantics.ai</a></span></p>
|
|
761
|
+
</body>
|
|
762
|
+
</html>",
|
|
748
763
|
"subject": "You've been invited to become a workspace owner",
|
|
749
764
|
"text": "You have been invited to become the owner of "Acme Corp".
|
|
750
765
|
|
|
@@ -767,6 +782,31 @@ Questions? Contact support@companysemantics.ai
|
|
|
767
782
|
|
|
768
783
|
exports[`email render > org.ownership_transfer · With note 1`] = `
|
|
769
784
|
{
|
|
785
|
+
"html": "<!DOCTYPE html>
|
|
786
|
+
<html lang="en">
|
|
787
|
+
<head><meta charset="UTF-8"></head>
|
|
788
|
+
<body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
|
|
789
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">You have been invited to become the owner of <b>"Acme Corp"</b>.</p>
|
|
790
|
+
<table cellpadding="0" cellspacing="0" border="0" style="margin: 0 0 16px 0;">
|
|
791
|
+
<tr>
|
|
792
|
+
<td style="border: 1px solid #1a1a1a; border-radius: 12px 12px 0 12px; padding: 10px 14px; min-width: 280px; text-align: right; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 13px; background: #f5f5f5;">Handing this over as I move to an advisory role.</td>
|
|
793
|
+
<td style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; padding-left: 8px; vertical-align: bottom;">(•̀_ರ╮)</td>
|
|
794
|
+
</tr>
|
|
795
|
+
<tr>
|
|
796
|
+
<td style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 11px; color: #888; text-align: right; padding-top: 4px;">Message from the current owner</td>
|
|
797
|
+
<td></td>
|
|
798
|
+
</tr>
|
|
799
|
+
</table>
|
|
800
|
+
<table cellpadding="0" cellspacing="0" border="0" style="border: 2px solid #1a1a1a; margin: 0 0 20px 0; max-width: 220px;">
|
|
801
|
+
<tr><td style="padding: 16px 24px; text-align: center; font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 16px;">
|
|
802
|
+
<a href="https://app.companysemantics.ai/owner-transfer/accept/tok123" style="color: #0047FF; text-decoration: underline;"><b>>> ACCEPT <<</b></a>
|
|
803
|
+
</td></tr>
|
|
804
|
+
</table>
|
|
805
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Expires in: <b>14 days</b></p>
|
|
806
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">If you did not expect this invitation, you can safely ignore this email.</p>
|
|
807
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0;">Company Semantics<br><span style="color: #888;">Questions? Contact <a href="mailto:support@companysemantics.ai" style="color: #888;">support@companysemantics.ai</a></span></p>
|
|
808
|
+
</body>
|
|
809
|
+
</html>",
|
|
770
810
|
"subject": "You've been invited to become a workspace owner",
|
|
771
811
|
"text": "You have been invited to become the owner of "Acme Corp".
|
|
772
812
|
|
|
@@ -795,6 +835,16 @@ Questions? Contact support@companysemantics.ai
|
|
|
795
835
|
|
|
796
836
|
exports[`email render > org.ownership_transfer_completed · Default 1`] = `
|
|
797
837
|
{
|
|
838
|
+
"html": "<!DOCTYPE html>
|
|
839
|
+
<html lang="en">
|
|
840
|
+
<head><meta charset="UTF-8"></head>
|
|
841
|
+
<body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
|
|
842
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">The ownership of <b>"Acme Corp"</b> has been transferred to <b>new.owner@acme.com</b>.</p>
|
|
843
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">You are no longer the owner of this workspace, but you remain an admin.</p>
|
|
844
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">If you did not authorize this transfer, please contact support immediately.</p>
|
|
845
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0;">Company Semantics<br><span style="color: #888;">Questions? Contact <a href="mailto:support@companysemantics.ai" style="color: #888;">support@companysemantics.ai</a></span></p>
|
|
846
|
+
</body>
|
|
847
|
+
</html>",
|
|
798
848
|
"subject": "Workspace ownership has been transferred",
|
|
799
849
|
"text": "The ownership of "Acme Corp" has been transferred to new.owner@acme.com.
|
|
800
850
|
|
|
@@ -903,6 +953,19 @@ Questions? Contact support@companysemantics.ai
|
|
|
903
953
|
|
|
904
954
|
exports[`email render > security.alert · Excessive OTP requests 1`] = `
|
|
905
955
|
{
|
|
956
|
+
"html": "<!DOCTYPE html>
|
|
957
|
+
<html lang="en">
|
|
958
|
+
<head><meta charset="UTF-8"></head>
|
|
959
|
+
<body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
|
|
960
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">We detected an unusual number of login code requests for your account.</p>
|
|
961
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Details: <b>12 login codes requested in 5 minutes</b></p>
|
|
962
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 4px 0;">If this was you, no action is needed.</p>
|
|
963
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 4px 0;">If you didn't request these codes, someone may be trying to access your account.</p>
|
|
964
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">We recommend reviewing your account security.</p>
|
|
965
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Time: <b>Sun, 12 Jul 2026 14:30:00 GMT</b></p>
|
|
966
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0;">Company Semantics Security<br><span style="color: #888;">Questions? Contact <a href="mailto:support@companysemantics.ai" style="color: #888;">support@companysemantics.ai</a></span></p>
|
|
967
|
+
</body>
|
|
968
|
+
</html>",
|
|
906
969
|
"subject": "Security alert for your account",
|
|
907
970
|
"text": "We detected an unusual number of login code requests for your account.
|
|
908
971
|
|
|
@@ -923,6 +986,18 @@ Questions? Contact support@companysemantics.ai
|
|
|
923
986
|
|
|
924
987
|
exports[`email render > security.alert · Unusual login location 1`] = `
|
|
925
988
|
{
|
|
989
|
+
"html": "<!DOCTYPE html>
|
|
990
|
+
<html lang="en">
|
|
991
|
+
<head><meta charset="UTF-8"></head>
|
|
992
|
+
<body style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; color: #1a1a1a; margin: 0; padding: 0;">
|
|
993
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">We detected a login attempt from an unusual location.</p>
|
|
994
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Details: <b>Login from Berlin, DE</b></p>
|
|
995
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 4px 0;">If this was you, no action is needed.</p>
|
|
996
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">If you didn't attempt to log in, please secure your account immediately.</p>
|
|
997
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0 0 20px 0;">Time: <b>Sun, 12 Jul 2026 14:30:00 GMT</b></p>
|
|
998
|
+
<p style="font-family: 'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; font-size: 14px; margin: 0;">Company Semantics Security<br><span style="color: #888;">Questions? Contact <a href="mailto:support@companysemantics.ai" style="color: #888;">support@companysemantics.ai</a></span></p>
|
|
999
|
+
</body>
|
|
1000
|
+
</html>",
|
|
926
1001
|
"subject": "Security alert for your account",
|
|
927
1002
|
"text": "We detected a login attempt from an unusual location.
|
|
928
1003
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Central email dispatcher. Given a kind + payload it returns
|
|
3
|
-
* `{ subject, text, html
|
|
3
|
+
* `{ subject, text, html }`, pulling the subject from the registry (single
|
|
4
4
|
* source of truth) and deriving both surfaces from ONE composed block list
|
|
5
5
|
* (`htmlShell` + `textShell`). This is the one entry point both the backend
|
|
6
6
|
* (real sends) and the app (Ladle preview) call.
|
|
@@ -28,8 +28,8 @@ export interface RenderedEmail {
|
|
|
28
28
|
subject: string;
|
|
29
29
|
/** Plain-text body. */
|
|
30
30
|
text: string;
|
|
31
|
-
/** HTML body (
|
|
32
|
-
html
|
|
31
|
+
/** HTML body (every kind is dual-output). */
|
|
32
|
+
html: string;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/** Caller-supplied render options. */
|
|
@@ -55,30 +55,13 @@ export const IMPLEMENTED_EMAIL_KINDS = [
|
|
|
55
55
|
|
|
56
56
|
export type ImplementedEmailKind = (typeof IMPLEMENTED_EMAIL_KINDS)[number];
|
|
57
57
|
|
|
58
|
-
/**
|
|
59
|
-
* Kinds delivered as plain text only. The unified block model renders HTML for
|
|
60
|
-
* every template, but these keep their historical text-only surface — the
|
|
61
|
-
* dispatcher omits `html` for them. (Enabling HTML later is deleting the entry.)
|
|
62
|
-
*/
|
|
63
|
-
const TEXT_ONLY_KINDS = new Set<EmailKind>([
|
|
64
|
-
"security.alert",
|
|
65
|
-
"org.ownership_transfer",
|
|
66
|
-
"org.ownership_transfer_completed",
|
|
67
|
-
]);
|
|
68
|
-
|
|
69
58
|
/** Payload type for a kind (or `never` for kinds without a payload). */
|
|
70
59
|
type PayloadFor<K extends EmailKind> = K extends keyof EmailPayloads
|
|
71
60
|
? EmailPayloads[K]
|
|
72
61
|
: never;
|
|
73
62
|
|
|
74
|
-
function toEmail(
|
|
75
|
-
subject:
|
|
76
|
-
kind: EmailKind,
|
|
77
|
-
blocks: Block[],
|
|
78
|
-
): RenderedEmail {
|
|
79
|
-
const email: RenderedEmail = { subject, text: textShell(blocks) };
|
|
80
|
-
if (!TEXT_ONLY_KINDS.has(kind)) email.html = htmlShell(blocks);
|
|
81
|
-
return email;
|
|
63
|
+
function toEmail(subject: string, blocks: Block[]): RenderedEmail {
|
|
64
|
+
return { subject, text: textShell(blocks), html: htmlShell(blocks) };
|
|
82
65
|
}
|
|
83
66
|
|
|
84
67
|
/**
|
|
@@ -100,19 +83,16 @@ export function renderEmail<K extends EmailKind>(
|
|
|
100
83
|
case "auth.otp":
|
|
101
84
|
return toEmail(
|
|
102
85
|
subject,
|
|
103
|
-
kind,
|
|
104
86
|
renderAuthOtp(payload as EmailPayloads["auth.otp"], options),
|
|
105
87
|
);
|
|
106
88
|
case "org.invite":
|
|
107
89
|
return toEmail(
|
|
108
90
|
subject,
|
|
109
|
-
kind,
|
|
110
91
|
renderOrgInvite(payload as EmailPayloads["org.invite"]),
|
|
111
92
|
);
|
|
112
93
|
case "org.unit_owner_granted":
|
|
113
94
|
return toEmail(
|
|
114
95
|
subject,
|
|
115
|
-
kind,
|
|
116
96
|
renderUnitOwnerGranted(
|
|
117
97
|
payload as EmailPayloads["org.unit_owner_granted"],
|
|
118
98
|
),
|
|
@@ -120,7 +100,6 @@ export function renderEmail<K extends EmailKind>(
|
|
|
120
100
|
case "org.ownership_transfer":
|
|
121
101
|
return toEmail(
|
|
122
102
|
subject,
|
|
123
|
-
kind,
|
|
124
103
|
renderOwnershipTransfer(
|
|
125
104
|
payload as EmailPayloads["org.ownership_transfer"],
|
|
126
105
|
),
|
|
@@ -128,7 +107,6 @@ export function renderEmail<K extends EmailKind>(
|
|
|
128
107
|
case "org.ownership_transfer_completed":
|
|
129
108
|
return toEmail(
|
|
130
109
|
subject,
|
|
131
|
-
kind,
|
|
132
110
|
renderOwnershipTransferCompleted(
|
|
133
111
|
payload as EmailPayloads["org.ownership_transfer_completed"],
|
|
134
112
|
),
|
|
@@ -136,25 +114,21 @@ export function renderEmail<K extends EmailKind>(
|
|
|
136
114
|
case "security.alert":
|
|
137
115
|
return toEmail(
|
|
138
116
|
subject,
|
|
139
|
-
kind,
|
|
140
117
|
renderSecurityAlert(payload as EmailPayloads["security.alert"]),
|
|
141
118
|
);
|
|
142
119
|
case "chat.shared":
|
|
143
120
|
return toEmail(
|
|
144
121
|
subject,
|
|
145
|
-
kind,
|
|
146
122
|
renderChatShared(payload as EmailPayloads["chat.shared"]),
|
|
147
123
|
);
|
|
148
124
|
case "share.granted":
|
|
149
125
|
return toEmail(
|
|
150
126
|
subject,
|
|
151
|
-
kind,
|
|
152
127
|
renderShareGranted(payload as EmailPayloads["share.granted"]),
|
|
153
128
|
);
|
|
154
129
|
case "companyMd.access_requested":
|
|
155
130
|
return toEmail(
|
|
156
131
|
subject,
|
|
157
|
-
kind,
|
|
158
132
|
renderAccessRequested(
|
|
159
133
|
payload as EmailPayloads["companyMd.access_requested"],
|
|
160
134
|
),
|
|
@@ -162,7 +136,6 @@ export function renderEmail<K extends EmailKind>(
|
|
|
162
136
|
case "companyMd.access_request_approved":
|
|
163
137
|
return toEmail(
|
|
164
138
|
subject,
|
|
165
|
-
kind,
|
|
166
139
|
renderAccessApproved(
|
|
167
140
|
payload as EmailPayloads["companyMd.access_request_approved"],
|
|
168
141
|
),
|
|
@@ -170,7 +143,6 @@ export function renderEmail<K extends EmailKind>(
|
|
|
170
143
|
case "companyMd.access_request_denied":
|
|
171
144
|
return toEmail(
|
|
172
145
|
subject,
|
|
173
|
-
kind,
|
|
174
146
|
renderAccessDenied(
|
|
175
147
|
payload as EmailPayloads["companyMd.access_request_denied"],
|
|
176
148
|
),
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* - `ownership` — entity.owner_user_id column projection
|
|
13
13
|
* - `visibility` — entity.visibility tier compiled to viewer rows
|
|
14
14
|
* - `inheritance` — org-chart-membership-based unit walk
|
|
15
|
+
* - `authority` — org-admin / account-owner / unit-editor / sharing-policy
|
|
16
|
+
* bands as synthetic live-resolved principals (ADR-BE-185)
|
|
17
|
+
* - `context_association` — a company.md context-bank doc inherits viewer access
|
|
18
|
+
* from every associated parent (the governed union, ADR-BE-392)
|
|
15
19
|
* - `migration` — one-shot backfill from legacy systems (AUTH-004)
|
|
16
20
|
*/
|
|
17
21
|
import { z } from "zod";
|
|
@@ -21,6 +25,8 @@ export const ACCESS_SOURCES = [
|
|
|
21
25
|
"ownership",
|
|
22
26
|
"visibility",
|
|
23
27
|
"inheritance",
|
|
28
|
+
"authority",
|
|
29
|
+
"context_association",
|
|
24
30
|
"migration",
|
|
25
31
|
] as const;
|
|
26
32
|
export type AccessSource = (typeof ACCESS_SOURCES)[number];
|