@company-semantics/contracts 9.1.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/package.json +4 -1
  2. package/src/__tests__/resource-keys.test.ts +30 -23
  3. package/src/admin/authz-simulate.ts +4 -4
  4. package/src/admin/direct-grants.ts +2 -2
  5. package/src/api/generated-spec-hash.ts +2 -2
  6. package/src/api/generated.ts +97 -0
  7. package/src/api/http/routes/ai-chat.ts +3 -3
  8. package/src/api/http/utils/resource-response.ts +5 -2
  9. package/src/api/index.ts +4 -4
  10. package/src/api/primitives.ts +6 -2
  11. package/src/auth/README.md +1 -0
  12. package/src/auth/index.ts +12 -5
  13. package/src/autotune.ts +5 -1
  14. package/src/billing/index.ts +1 -1
  15. package/src/billing/types.ts +1 -1
  16. package/src/chat/README.md +3 -0
  17. package/src/chat/__tests__/runtime-profile.test.ts +68 -48
  18. package/src/chat/index.ts +10 -4
  19. package/src/chat/runtime-profile.ts +25 -10
  20. package/src/chat/schemas.ts +49 -41
  21. package/src/chat/types.ts +48 -42
  22. package/src/ci-envelope/README.md +2 -0
  23. package/src/ci-envelope/__tests__/transitions.test.ts +56 -56
  24. package/src/ci-envelope/index.ts +2 -2
  25. package/src/ci-envelope/types.ts +20 -20
  26. package/src/ci-results/index.ts +2 -2
  27. package/src/ci-results/repo-ci-result.ts +15 -12
  28. package/src/compatibility.ts +6 -6
  29. package/src/content/index.ts +10 -4
  30. package/src/content/schemas.ts +42 -24
  31. package/src/dispatch/index.ts +18 -15
  32. package/src/email/__tests__/registry.test.ts +81 -77
  33. package/src/email/index.ts +3 -3
  34. package/src/email/registry.ts +25 -25
  35. package/src/email/types.ts +43 -43
  36. package/src/errors/index.ts +8 -8
  37. package/src/execution/__tests__/events.test.ts +42 -42
  38. package/src/execution/__tests__/lifecycle.test.ts +192 -190
  39. package/src/execution/__tests__/registry.test.ts +114 -114
  40. package/src/execution/audit-export.ts +4 -4
  41. package/src/execution/errors.ts +7 -7
  42. package/src/execution/event-metadata.ts +4 -4
  43. package/src/execution/events.ts +23 -21
  44. package/src/execution/expiry.ts +5 -5
  45. package/src/execution/hash-chain.ts +2 -2
  46. package/src/execution/index.ts +19 -28
  47. package/src/execution/kinds.ts +7 -7
  48. package/src/execution/lifecycle.ts +33 -33
  49. package/src/execution/registry.ts +63 -63
  50. package/src/execution/schemas.ts +31 -23
  51. package/src/execution/status.ts +45 -26
  52. package/src/execution/summary.ts +16 -17
  53. package/src/execution/timeline-ui.ts +9 -9
  54. package/src/execution/types.ts +31 -25
  55. package/src/generated/openapi-routes.ts +1 -0
  56. package/src/guards/config.ts +22 -18
  57. package/src/guards/index.ts +4 -4
  58. package/src/guards/types.ts +32 -24
  59. package/src/identity/__tests__/avatar.test.ts +68 -59
  60. package/src/identity/avatar.ts +8 -8
  61. package/src/identity/display-name.ts +3 -3
  62. package/src/identity/index.ts +8 -8
  63. package/src/identity/people-org-chart.ts +8 -4
  64. package/src/identity/schemas.ts +28 -18
  65. package/src/identity/types.ts +5 -5
  66. package/src/impersonation/index.ts +5 -5
  67. package/src/impersonation/schemas.ts +15 -9
  68. package/src/impersonation-events.ts +21 -21
  69. package/src/impersonation.ts +25 -24
  70. package/src/index.ts +118 -90
  71. package/src/interfaces/mcp/tools/help.ts +19 -19
  72. package/src/internal-admin.ts +6 -6
  73. package/src/mcp/README.md +2 -0
  74. package/src/mcp/__tests__/capability-graph.test.ts +290 -290
  75. package/src/mcp/capability-graph.ts +42 -40
  76. package/src/mcp/failure-context.ts +1 -3
  77. package/src/mcp/index.ts +57 -57
  78. package/src/mcp/resources.ts +9 -9
  79. package/src/meetings/index.ts +2 -2
  80. package/src/meetings/schemas.ts +51 -34
  81. package/src/message-parts/README.md +2 -0
  82. package/src/message-parts/__tests__/builder.test.ts +142 -142
  83. package/src/message-parts/__tests__/confirmation.test.ts +100 -86
  84. package/src/message-parts/__tests__/preview.test.ts +63 -63
  85. package/src/message-parts/__tests__/wire.test.ts +130 -124
  86. package/src/message-parts/builder.ts +23 -23
  87. package/src/message-parts/confirmation.ts +17 -14
  88. package/src/message-parts/execution.ts +7 -7
  89. package/src/message-parts/index.ts +10 -10
  90. package/src/message-parts/lifecycle.ts +25 -25
  91. package/src/message-parts/preview.ts +30 -30
  92. package/src/message-parts/types.ts +27 -27
  93. package/src/message-parts/wire.ts +24 -24
  94. package/src/mutations.ts +2 -2
  95. package/src/observability.ts +23 -11
  96. package/src/org/__tests__/org-units.test.ts +131 -96
  97. package/src/org/__tests__/tree-ordering.test.ts +57 -37
  98. package/src/org/__tests__/view-scopes.test.ts +40 -40
  99. package/src/org/domain.ts +9 -9
  100. package/src/org/index.ts +24 -21
  101. package/src/org/org-units.ts +34 -20
  102. package/src/org/schemas.ts +201 -127
  103. package/src/org/sharing.ts +17 -13
  104. package/src/org/tree-ordering.ts +3 -1
  105. package/src/org/types.ts +54 -47
  106. package/src/org/view-scopes.ts +9 -9
  107. package/src/permissions/access-levels.ts +7 -2
  108. package/src/permissions/access-source.ts +6 -6
  109. package/src/permissions/index.ts +5 -5
  110. package/src/permissions/orgchart-roles.ts +7 -7
  111. package/src/permissions/permission-introspection.ts +7 -5
  112. package/src/permissions/share-api.ts +19 -9
  113. package/src/pressure.ts +4 -4
  114. package/src/queryIntent.ts +21 -21
  115. package/src/ralph/__tests__/prd-groups.test.ts +159 -159
  116. package/src/ralph/__tests__/prd.test.ts +30 -30
  117. package/src/ralph/index.ts +3 -8
  118. package/src/ralph/prd.ts +33 -33
  119. package/src/ralph/progress.ts +1 -1
  120. package/src/rate-limit/README.md +4 -4
  121. package/src/rate-limit/index.ts +3 -3
  122. package/src/requests.ts +36 -8
  123. package/src/resource-keys.ts +207 -124
  124. package/src/resource-registry.ts +5 -5
  125. package/src/route-builder.ts +3 -3
  126. package/src/safe-mode.ts +2 -2
  127. package/src/security/index.ts +4 -4
  128. package/src/security/org-secrets.ts +13 -9
  129. package/src/security/secret.ts +3 -3
  130. package/src/sse.ts +3 -1
  131. package/src/system/README.md +3 -0
  132. package/src/system/capabilities.ts +22 -23
  133. package/src/system/diagram.ts +45 -45
  134. package/src/system/index.ts +14 -14
  135. package/src/tiers.ts +1 -1
  136. package/src/timeouts.ts +1 -1
  137. package/src/tracing.ts +30 -30
  138. package/src/types/analytics.ts +2 -2
  139. package/src/usage/README.md +3 -0
  140. package/src/usage/execution-types.ts +69 -69
  141. package/src/usage/types.ts +7 -3
@@ -32,7 +32,7 @@ export type {
32
32
  CIExecutionOutcome,
33
33
  // Core Envelope
34
34
  CIExecutionEnvelope,
35
- } from './types';
35
+ } from "./types";
36
36
 
37
37
  // Constants (documentation/type-level, not runtime)
38
- export { ENVELOPE_TRANSITIONS } from './types';
38
+ export { ENVELOPE_TRANSITIONS } from "./types";
@@ -22,7 +22,7 @@
22
22
  * Currently Claude-only, extensible for future actor types.
23
23
  */
24
24
  export type CIActorInfo = {
25
- kind: 'claude';
25
+ kind: "claude";
26
26
  model: string;
27
27
  };
28
28
 
@@ -46,15 +46,15 @@ export type CISessionInfo = {
46
46
  * not here. This type defines vocabulary only.
47
47
  */
48
48
  export type ExecutionIntent =
49
- | 'feature_extension'
50
- | 'bug_fix'
51
- | 'refactor_structural'
52
- | 'guard_update'
53
- | 'policy_update'
54
- | 'schema_change'
55
- | 'doc_update'
56
- | 'cleanup'
57
- | 'experimental';
49
+ | "feature_extension"
50
+ | "bug_fix"
51
+ | "refactor_structural"
52
+ | "guard_update"
53
+ | "policy_update"
54
+ | "schema_change"
55
+ | "doc_update"
56
+ | "cleanup"
57
+ | "experimental";
58
58
 
59
59
  /**
60
60
  * Intent declaration with optional ADR references.
@@ -73,7 +73,7 @@ export type CIIntentDeclaration = {
73
73
  /**
74
74
  * Change kind for scope declarations.
75
75
  */
76
- export type CIChangeKind = 'add' | 'modify' | 'delete';
76
+ export type CIChangeKind = "add" | "modify" | "delete";
77
77
 
78
78
  /**
79
79
  * Execution scope defining affected repos and paths.
@@ -130,11 +130,11 @@ export type CIGuardPlan = {
130
130
  * Note: Transition validation logic lives in CI repo, not here.
131
131
  */
132
132
  export type CIEnvelopeStatus =
133
- | 'proposed'
134
- | 'validated'
135
- | 'blocked'
136
- | 'executing'
137
- | 'finalized';
133
+ | "proposed"
134
+ | "validated"
135
+ | "blocked"
136
+ | "executing"
137
+ | "finalized";
138
138
 
139
139
  // =============================================================================
140
140
  // Outcome Types
@@ -145,7 +145,7 @@ export type CIEnvelopeStatus =
145
145
  */
146
146
  export type CIGuardViolation = {
147
147
  guardId: string;
148
- severity: 'error' | 'warning';
148
+ severity: "error" | "warning";
149
149
  message: string;
150
150
  file?: string;
151
151
  line?: number;
@@ -208,9 +208,9 @@ export const ENVELOPE_TRANSITIONS: Record<
208
208
  CIEnvelopeStatus,
209
209
  readonly CIEnvelopeStatus[]
210
210
  > = {
211
- proposed: ['validated', 'blocked'],
212
- validated: ['executing', 'blocked'],
211
+ proposed: ["validated", "blocked"],
212
+ validated: ["executing", "blocked"],
213
213
  blocked: [],
214
- executing: ['finalized', 'blocked'],
214
+ executing: ["finalized", "blocked"],
215
215
  finalized: [],
216
216
  } as const;
@@ -11,6 +11,6 @@ export type {
11
11
  GuardTier,
12
12
  GuardResultPayload,
13
13
  RepoCiResult,
14
- } from './repo-ci-result';
14
+ } from "./repo-ci-result";
15
15
 
16
- export { assertRepoCiResultConsistent } from './repo-ci-result';
16
+ export { assertRepoCiResultConsistent } from "./repo-ci-result";
@@ -6,11 +6,11 @@
6
6
  */
7
7
 
8
8
  export type GuardTier =
9
- | 'structural'
10
- | 'behavioral'
11
- | 'invariants'
12
- | 'evolution'
13
- | 'meta';
9
+ | "structural"
10
+ | "behavioral"
11
+ | "invariants"
12
+ | "evolution"
13
+ | "meta";
14
14
 
15
15
  /**
16
16
  * Minimal structural shape of a guard orchestrator result payload.
@@ -22,7 +22,10 @@ export interface GuardResultPayload {
22
22
  readonly results: Readonly<
23
23
  Record<
24
24
  GuardTier,
25
- { readonly errors: readonly unknown[]; readonly warnings: readonly unknown[] }
25
+ {
26
+ readonly errors: readonly unknown[];
27
+ readonly warnings: readonly unknown[];
28
+ }
26
29
  >
27
30
  >;
28
31
  }
@@ -39,7 +42,7 @@ export interface RepoCiResult {
39
42
  /** Sibling repo name without the 'company-semantics-' prefix. */
40
43
  readonly repo: string;
41
44
  /** pass when ci:local exited 0 and the guard artifact was produced; fail otherwise. */
42
- readonly status: 'pass' | 'fail';
45
+ readonly status: "pass" | "fail";
43
46
  /**
44
47
  * Total errors across all guard tiers.
45
48
  * MUST equal the sum of guardResult.results[tier].errors.length across
@@ -59,11 +62,11 @@ export interface RepoCiResult {
59
62
  }
60
63
 
61
64
  const TIERS: readonly GuardTier[] = [
62
- 'structural',
63
- 'behavioral',
64
- 'invariants',
65
- 'evolution',
66
- 'meta',
65
+ "structural",
66
+ "behavioral",
67
+ "invariants",
68
+ "evolution",
69
+ "meta",
67
70
  ];
68
71
 
69
72
  /**
@@ -13,11 +13,11 @@
13
13
  */
14
14
  export interface Deprecation {
15
15
  /** Semver range (e.g., "0.12.x") */
16
- range: string
16
+ range: string;
17
17
  /** Human-readable reason for deprecation */
18
- reason: string
18
+ reason: string;
19
19
  /** Version in which support will be removed */
20
- removeIn: string
20
+ removeIn: string;
21
21
  }
22
22
 
23
23
  /**
@@ -26,10 +26,10 @@ export interface Deprecation {
26
26
  */
27
27
  export const COMPATIBILITY = {
28
28
  /** Minimum version that all consumers should use */
29
- minSupported: '0.14.0',
29
+ minSupported: "0.14.0",
30
30
 
31
31
  /** Versions that still work but should upgrade (with reasons) */
32
32
  deprecations: [] as Deprecation[],
33
- } as const
33
+ } as const;
34
34
 
35
- export type Compatibility = typeof COMPATIBILITY
35
+ export type Compatibility = typeof COMPATIBILITY;
@@ -11,14 +11,20 @@ export {
11
11
  CompanyMdDocResponseSchema,
12
12
  CompanyMdShareResponseSchema,
13
13
  CompanyMdContextBankResponseSchema,
14
- } from './schemas';
14
+ } from "./schemas";
15
15
  export type {
16
16
  CompanyMdListResponse,
17
17
  CompanyMdDocResponse,
18
18
  CompanyMdShareResponse,
19
19
  CompanyMdContextBankResponse,
20
- } from './schemas';
20
+ } from "./schemas";
21
21
 
22
22
  // Drive response schemas (PRD-00448)
23
- export { DriveFileListResponseSchema, DriveFileContentResponseSchema } from './schemas';
24
- export type { DriveFileListResponse, DriveFileContentResponse } from './schemas';
23
+ export {
24
+ DriveFileListResponseSchema,
25
+ DriveFileContentResponseSchema,
26
+ } from "./schemas";
27
+ export type {
28
+ DriveFileListResponse,
29
+ DriveFileContentResponse,
30
+ } from "./schemas";
@@ -9,8 +9,8 @@
9
9
  * - company-md-sharing.ts (GET /api/company-md/docs/:slug/sharing)
10
10
  * - drive.ts (GET /api/drive/files, GET /api/drive/files/recent, etc.)
11
11
  */
12
- import { z } from 'zod';
13
- import { CursorPageSchema } from '../api/primitives';
12
+ import { z } from "zod";
13
+ import { CursorPageSchema } from "../api/primitives";
14
14
 
15
15
  // ---------------------------------------------------------------------------
16
16
  // Company.md Sub-schemas
@@ -23,7 +23,7 @@ const CompanyMdPersonSchema = z.object({
23
23
 
24
24
  const CompanyMdSourceSchema = z.object({
25
25
  label: z.string(),
26
- sourceType: z.enum(['meeting', 'document', 'conversation', 'manual']),
26
+ sourceType: z.enum(["meeting", "document", "conversation", "manual"]),
27
27
  referencedAt: z.string(),
28
28
  });
29
29
 
@@ -36,11 +36,21 @@ const CompanyMdTreeNodeSchema = z.object({
36
36
  id: z.string(),
37
37
  slug: z.string(),
38
38
  title: z.string(),
39
- level: z.enum(['root', 'department', 'team', 'context']),
39
+ level: z.enum(["root", "department", "team", "context"]),
40
40
  parentId: z.string().nullable(),
41
- visibility: z.enum(['private', 'unit', 'org']),
41
+ visibility: z.enum(["private", "unit", "org"]),
42
42
  owningUnitId: z.string().nullable(),
43
- type: z.enum(['company', 'department', 'team', 'cross_team', 'doc', 'goal', 'source', 'map', 'context_bank']),
43
+ type: z.enum([
44
+ "company",
45
+ "department",
46
+ "team",
47
+ "cross_team",
48
+ "doc",
49
+ "goal",
50
+ "source",
51
+ "map",
52
+ "context_bank",
53
+ ]),
44
54
  canEdit: z.boolean(),
45
55
  memberCount: z.number().int(),
46
56
  description: z.string().optional(),
@@ -53,16 +63,18 @@ const CompanyMdTreeNodeSchema = z.object({
53
63
  // ---------------------------------------------------------------------------
54
64
 
55
65
  /** Response for GET /api/company-md/tree */
56
- export const CompanyMdListResponseSchema = CursorPageSchema(CompanyMdTreeNodeSchema);
66
+ export const CompanyMdListResponseSchema = CursorPageSchema(
67
+ CompanyMdTreeNodeSchema,
68
+ );
57
69
 
58
70
  /** Response for GET /api/company-md/docs/:slug */
59
71
  export const CompanyMdDocResponseSchema = z.object({
60
72
  id: z.string(),
61
73
  slug: z.string(),
62
74
  title: z.string(),
63
- level: z.enum(['root', 'department', 'team', 'context']),
75
+ level: z.enum(["root", "department", "team", "context"]),
64
76
  content: z.string(),
65
- visibility: z.enum(['private', 'unit', 'org']),
77
+ visibility: z.enum(["private", "unit", "org"]),
66
78
  parentId: z.string().nullable(),
67
79
  owningUnitId: z.string().nullable(),
68
80
  owner: CompanyMdPersonSchema.nullable(),
@@ -71,7 +83,7 @@ export const CompanyMdDocResponseSchema = z.object({
71
83
  sources: z.array(CompanyMdSourceSchema),
72
84
  dependencies: z.array(CompanyMdDependencySchema),
73
85
  members: z.array(CompanyMdPersonSchema),
74
- extractionStatus: z.enum(['pending', 'extracting', 'complete', 'failed']),
86
+ extractionStatus: z.enum(["pending", "extracting", "complete", "failed"]),
75
87
  /**
76
88
  * Populated only when `extractionStatus === 'failed'`. Carries the
77
89
  * diagnostic class/reason recorded by the worker on the latest
@@ -89,35 +101,35 @@ export const CompanyMdDocResponseSchema = z.object({
89
101
  // ---------------------------------------------------------------------------
90
102
 
91
103
  const AclEntrySchema = z.object({
92
- principalType: z.enum(['user', 'unit']),
104
+ principalType: z.enum(["user", "unit"]),
93
105
  principalId: z.string(),
94
106
  principalName: z.string(),
95
- accessLevel: z.enum(['viewer', 'commenter', 'editor']),
107
+ accessLevel: z.enum(["viewer", "commenter", "editor"]),
96
108
  grantedBy: z.object({ id: z.string(), name: z.string() }).nullable(),
97
109
  grantedAt: z.string(),
98
110
  });
99
111
 
100
112
  const AccessReasonSchema = z.object({
101
113
  source: z.enum([
102
- 'org_rbac',
103
- 'sharing_policy',
104
- 'unit_baseline',
105
- 'unit_delegation',
106
- 'acl_grant',
107
- 'doc_ownership',
114
+ "org_rbac",
115
+ "sharing_policy",
116
+ "unit_baseline",
117
+ "unit_delegation",
118
+ "acl_grant",
119
+ "doc_ownership",
108
120
  ]),
109
121
  detail: z.string(),
110
122
  });
111
123
 
112
124
  const EffectiveAccessSchema = z.object({
113
- level: z.enum(['none', 'viewer', 'commenter', 'editor']),
125
+ level: z.enum(["none", "viewer", "commenter", "editor"]),
114
126
  reasons: z.array(AccessReasonSchema),
115
127
  canShare: z.boolean(),
116
128
  });
117
129
 
118
130
  /** Response for GET /api/company-md/docs/:slug/sharing */
119
131
  export const CompanyMdShareResponseSchema = z.object({
120
- sharingPolicy: z.enum(['restricted', 'org_read', 'org_comment', 'org_edit']),
132
+ sharingPolicy: z.enum(["restricted", "org_read", "org_comment", "org_edit"]),
121
133
  acl: z.array(AclEntrySchema),
122
134
  effectiveAccess: EffectiveAccessSchema,
123
135
  });
@@ -130,7 +142,7 @@ const CompanyMdContextBankItemSchema = z.object({
130
142
  id: z.string(),
131
143
  slug: z.string(),
132
144
  title: z.string(),
133
- visibility: z.enum(['private', 'unit', 'org']),
145
+ visibility: z.enum(["private", "unit", "org"]),
134
146
  updatedAt: z.string(),
135
147
  });
136
148
 
@@ -183,7 +195,13 @@ export const DriveFileContentResponseSchema = z.object({
183
195
 
184
196
  export type CompanyMdListResponse = z.infer<typeof CompanyMdListResponseSchema>;
185
197
  export type CompanyMdDocResponse = z.infer<typeof CompanyMdDocResponseSchema>;
186
- export type CompanyMdShareResponse = z.infer<typeof CompanyMdShareResponseSchema>;
187
- export type CompanyMdContextBankResponse = z.infer<typeof CompanyMdContextBankResponseSchema>;
198
+ export type CompanyMdShareResponse = z.infer<
199
+ typeof CompanyMdShareResponseSchema
200
+ >;
201
+ export type CompanyMdContextBankResponse = z.infer<
202
+ typeof CompanyMdContextBankResponseSchema
203
+ >;
188
204
  export type DriveFileListResponse = z.infer<typeof DriveFileListResponseSchema>;
189
- export type DriveFileContentResponse = z.infer<typeof DriveFileContentResponseSchema>;
205
+ export type DriveFileContentResponse = z.infer<
206
+ typeof DriveFileContentResponseSchema
207
+ >;
@@ -20,15 +20,15 @@
20
20
  */
21
21
 
22
22
  export const DISPATCH_DENY_CODES = [
23
- 'incremental_consent_required',
24
- 'write_tier_disabled',
25
- 'provider_access_denied',
26
- 'execution_budget_exceeded',
23
+ "incremental_consent_required",
24
+ "write_tier_disabled",
25
+ "provider_access_denied",
26
+ "execution_budget_exceeded",
27
27
  ] as const;
28
28
 
29
29
  export type DispatchDenyCode = (typeof DISPATCH_DENY_CODES)[number];
30
30
 
31
- export type ActionTier = 'SAFE' | 'EXTERNAL' | 'DESTRUCTIVE';
31
+ export type ActionTier = "SAFE" | "EXTERNAL" | "DESTRUCTIVE";
32
32
 
33
33
  /**
34
34
  * The user has no active grant row in `incremental_consents` for the
@@ -59,14 +59,14 @@ export interface WriteTierDisabledMeta {
59
59
  * tier paused for this provider).
60
60
  */
61
61
  export type ProviderAccessDenyReason =
62
- | 'provider-disabled'
63
- | 'org-override'
64
- | 'tier-SAFE-disabled'
65
- | 'tier-EXTERNAL-disabled'
66
- | 'tier-DESTRUCTIVE-disabled'
67
- | 'write-tier-SAFE-globally-disabled'
68
- | 'write-tier-EXTERNAL-globally-disabled'
69
- | 'write-tier-DESTRUCTIVE-globally-disabled';
62
+ | "provider-disabled"
63
+ | "org-override"
64
+ | "tier-SAFE-disabled"
65
+ | "tier-EXTERNAL-disabled"
66
+ | "tier-DESTRUCTIVE-disabled"
67
+ | "write-tier-SAFE-globally-disabled"
68
+ | "write-tier-EXTERNAL-globally-disabled"
69
+ | "write-tier-DESTRUCTIVE-globally-disabled";
70
70
 
71
71
  export interface ProviderAccessDeniedMeta {
72
72
  reason: ProviderAccessDenyReason;
@@ -81,7 +81,7 @@ export interface ProviderAccessDeniedMeta {
81
81
  * recovery is always "start a new session / execution".
82
82
  */
83
83
  export interface ExecutionBudgetExceededMeta {
84
- kind: 'token_uses' | 'time_window' | 'provider_calls' | 'rows_returned';
84
+ kind: "token_uses" | "time_window" | "provider_calls" | "rows_returned";
85
85
  executionId: string;
86
86
  }
87
87
 
@@ -95,5 +95,8 @@ export interface DispatchDenyMetaByCode {
95
95
 
96
96
  /** Narrow `unknown` to a `DispatchDenyCode` for error-code dispatch switches. */
97
97
  export function isDispatchDenyCode(code: unknown): code is DispatchDenyCode {
98
- return typeof code === 'string' && (DISPATCH_DENY_CODES as readonly string[]).includes(code);
98
+ return (
99
+ typeof code === "string" &&
100
+ (DISPATCH_DENY_CODES as readonly string[]).includes(code)
101
+ );
99
102
  }
@@ -1,121 +1,125 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { EMAIL_KINDS, getEmailKindDefinition, isValidEmailKind } from '../registry.js'
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ EMAIL_KINDS,
4
+ getEmailKindDefinition,
5
+ isValidEmailKind,
6
+ } from "../registry.js";
3
7
 
4
- describe('EMAIL_KINDS golden snapshot', () => {
5
- it('exact values are frozen', () => {
8
+ describe("EMAIL_KINDS golden snapshot", () => {
9
+ it("exact values are frozen", () => {
6
10
  expect(EMAIL_KINDS).toStrictEqual({
7
- 'auth.otp': {
8
- kind: 'auth.otp',
9
- subject: 'Your login code',
11
+ "auth.otp": {
12
+ kind: "auth.otp",
13
+ subject: "Your login code",
10
14
  plainTextRequired: true,
11
15
  htmlSupported: false,
12
16
  },
13
- 'auth.magic_link': {
14
- kind: 'auth.magic_link',
15
- subject: 'Your login link',
17
+ "auth.magic_link": {
18
+ kind: "auth.magic_link",
19
+ subject: "Your login link",
16
20
  plainTextRequired: true,
17
21
  htmlSupported: false,
18
22
  },
19
- 'org.invite': {
20
- kind: 'org.invite',
21
- subject: 'You have been invited to join a workspace',
23
+ "org.invite": {
24
+ kind: "org.invite",
25
+ subject: "You have been invited to join a workspace",
22
26
  plainTextRequired: true,
23
27
  htmlSupported: true,
24
28
  },
25
- 'org.leadership_granted': {
26
- kind: 'org.leadership_granted',
29
+ "org.leadership_granted": {
30
+ kind: "org.leadership_granted",
27
31
  subject: "You've been added to a team",
28
32
  plainTextRequired: true,
29
33
  htmlSupported: true,
30
34
  },
31
- 'security.alert': {
32
- kind: 'security.alert',
33
- subject: 'Security alert for your account',
35
+ "security.alert": {
36
+ kind: "security.alert",
37
+ subject: "Security alert for your account",
34
38
  plainTextRequired: true,
35
39
  htmlSupported: false,
36
40
  },
37
- 'chat.shared': {
38
- kind: 'chat.shared',
39
- subject: 'A chat has been shared with you',
41
+ "chat.shared": {
42
+ kind: "chat.shared",
43
+ subject: "A chat has been shared with you",
40
44
  plainTextRequired: true,
41
45
  htmlSupported: true,
42
46
  },
43
- })
44
- })
45
- })
47
+ });
48
+ });
49
+ });
46
50
 
47
- describe('EMAIL_KINDS registry invariants', () => {
48
- it('every registry key matches its definition.kind field', () => {
51
+ describe("EMAIL_KINDS registry invariants", () => {
52
+ it("every registry key matches its definition.kind field", () => {
49
53
  for (const [key, def] of Object.entries(EMAIL_KINDS)) {
50
- expect(def.kind).toBe(key)
54
+ expect(def.kind).toBe(key);
51
55
  }
52
- })
56
+ });
53
57
 
54
- it('all subjects are non-empty strings', () => {
58
+ it("all subjects are non-empty strings", () => {
55
59
  for (const def of Object.values(EMAIL_KINDS)) {
56
- expect(typeof def.subject).toBe('string')
57
- expect(def.subject.length).toBeGreaterThan(0)
60
+ expect(typeof def.subject).toBe("string");
61
+ expect(def.subject.length).toBeGreaterThan(0);
58
62
  }
59
- })
63
+ });
60
64
 
61
- it('all entries have required boolean fields plainTextRequired and htmlSupported', () => {
65
+ it("all entries have required boolean fields plainTextRequired and htmlSupported", () => {
62
66
  for (const def of Object.values(EMAIL_KINDS)) {
63
- expect(typeof def.plainTextRequired).toBe('boolean')
64
- expect(typeof def.htmlSupported).toBe('boolean')
67
+ expect(typeof def.plainTextRequired).toBe("boolean");
68
+ expect(typeof def.htmlSupported).toBe("boolean");
65
69
  }
66
- })
67
- })
70
+ });
71
+ });
68
72
 
69
- describe('getEmailKindDefinition', () => {
70
- it('returns correct definition for auth.otp', () => {
71
- const def = getEmailKindDefinition('auth.otp')
72
- expect(def).toStrictEqual(EMAIL_KINDS['auth.otp'])
73
- })
73
+ describe("getEmailKindDefinition", () => {
74
+ it("returns correct definition for auth.otp", () => {
75
+ const def = getEmailKindDefinition("auth.otp");
76
+ expect(def).toStrictEqual(EMAIL_KINDS["auth.otp"]);
77
+ });
74
78
 
75
- it('returns correct definition for auth.magic_link', () => {
76
- const def = getEmailKindDefinition('auth.magic_link')
77
- expect(def).toStrictEqual(EMAIL_KINDS['auth.magic_link'])
78
- })
79
+ it("returns correct definition for auth.magic_link", () => {
80
+ const def = getEmailKindDefinition("auth.magic_link");
81
+ expect(def).toStrictEqual(EMAIL_KINDS["auth.magic_link"]);
82
+ });
79
83
 
80
- it('returns correct definition for org.invite', () => {
81
- const def = getEmailKindDefinition('org.invite')
82
- expect(def).toStrictEqual(EMAIL_KINDS['org.invite'])
83
- })
84
+ it("returns correct definition for org.invite", () => {
85
+ const def = getEmailKindDefinition("org.invite");
86
+ expect(def).toStrictEqual(EMAIL_KINDS["org.invite"]);
87
+ });
84
88
 
85
- it('returns correct definition for security.alert', () => {
86
- const def = getEmailKindDefinition('security.alert')
87
- expect(def).toStrictEqual(EMAIL_KINDS['security.alert'])
88
- })
89
+ it("returns correct definition for security.alert", () => {
90
+ const def = getEmailKindDefinition("security.alert");
91
+ expect(def).toStrictEqual(EMAIL_KINDS["security.alert"]);
92
+ });
89
93
 
90
- it('returns correct definition for chat.shared', () => {
91
- const def = getEmailKindDefinition('chat.shared')
92
- expect(def).toStrictEqual(EMAIL_KINDS['chat.shared'])
93
- })
94
+ it("returns correct definition for chat.shared", () => {
95
+ const def = getEmailKindDefinition("chat.shared");
96
+ expect(def).toStrictEqual(EMAIL_KINDS["chat.shared"]);
97
+ });
94
98
 
95
- it('return value matches registry entry exactly', () => {
99
+ it("return value matches registry entry exactly", () => {
96
100
  for (const [key, expected] of Object.entries(EMAIL_KINDS)) {
97
- const def = getEmailKindDefinition(key as keyof typeof EMAIL_KINDS)
98
- expect(def).toBe(expected)
101
+ const def = getEmailKindDefinition(key as keyof typeof EMAIL_KINDS);
102
+ expect(def).toBe(expected);
99
103
  }
100
- })
101
- })
104
+ });
105
+ });
102
106
 
103
- describe('isValidEmailKind', () => {
104
- it('returns true for all valid email kinds', () => {
107
+ describe("isValidEmailKind", () => {
108
+ it("returns true for all valid email kinds", () => {
105
109
  for (const kind of Object.keys(EMAIL_KINDS)) {
106
- expect(isValidEmailKind(kind)).toBe(true)
110
+ expect(isValidEmailKind(kind)).toBe(true);
107
111
  }
108
- })
112
+ });
109
113
 
110
- it('returns false for unknown string', () => {
111
- expect(isValidEmailKind('unknown.kind')).toBe(false)
112
- })
114
+ it("returns false for unknown string", () => {
115
+ expect(isValidEmailKind("unknown.kind")).toBe(false);
116
+ });
113
117
 
114
- it('returns false for empty string', () => {
115
- expect(isValidEmailKind('')).toBe(false)
116
- })
118
+ it("returns false for empty string", () => {
119
+ expect(isValidEmailKind("")).toBe(false);
120
+ });
117
121
 
118
- it('returns false for partial match', () => {
119
- expect(isValidEmailKind('auth')).toBe(false)
120
- })
121
- })
122
+ it("returns false for partial match", () => {
123
+ expect(isValidEmailKind("auth")).toBe(false);
124
+ });
125
+ });
@@ -11,13 +11,13 @@
11
11
  // Kind Types
12
12
  // =============================================================================
13
13
 
14
- export type { EmailKind, EmailPayloads, SendEmailInput } from './types'
14
+ export type { EmailKind, EmailPayloads, SendEmailInput } from "./types";
15
15
 
16
16
  // =============================================================================
17
17
  // Definition Types
18
18
  // =============================================================================
19
19
 
20
- export type { EmailKindDefinition } from './registry'
20
+ export type { EmailKindDefinition } from "./registry";
21
21
 
22
22
  // =============================================================================
23
23
  // Registry
@@ -27,4 +27,4 @@ export {
27
27
  EMAIL_KINDS,
28
28
  getEmailKindDefinition,
29
29
  isValidEmailKind,
30
- } from './registry'
30
+ } from "./registry";