@fabrika/control-contract 0.6.0 → 0.7.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 +4 -4
- package/src/access.ts +9 -0
- package/src/index.ts +2 -0
- package/src/mail.ts +96 -0
- package/src/rpc.ts +35 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabrika/control-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"zod": "^3.25.76",
|
|
28
|
-
"@fabrika/auth-core": "0.
|
|
29
|
-
"@fabrika/app": "0.
|
|
30
|
-
"@fabrika/provider-contract": "0.
|
|
28
|
+
"@fabrika/auth-core": "0.7.0",
|
|
29
|
+
"@fabrika/app": "0.7.0",
|
|
30
|
+
"@fabrika/provider-contract": "0.7.0"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/src/access.ts
CHANGED
|
@@ -36,6 +36,15 @@ export const CONTROL_ACTIONS = Object.freeze({
|
|
|
36
36
|
* the operator role does not hold it; only a human user principal in the console may use it. Scoped by app/environment.
|
|
37
37
|
*/
|
|
38
38
|
ACCESS_APPROVE: 'access.approve',
|
|
39
|
+
/**
|
|
40
|
+
* List relayed mail and read its metadata. Scoped by app/environment for an application's messages; an installation
|
|
41
|
+
* sender's messages need a global grant.
|
|
42
|
+
*/
|
|
43
|
+
MAIL_READ: 'mail.read',
|
|
44
|
+
/** Read a relayed message's recipient, subject and bodies. Global. */
|
|
45
|
+
MAIL_CONTENT_READ: 'mail.content.read',
|
|
46
|
+
/** Release or drop a held message, requeue a final one, and change the gate's rules. Global. */
|
|
47
|
+
MAIL_MANAGE: 'mail.manage',
|
|
39
48
|
})
|
|
40
49
|
|
|
41
50
|
/**
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './access.js'
|
|
|
6
6
|
export * from './builder-bootstrap.js'
|
|
7
7
|
export * from './builder-connections.js'
|
|
8
8
|
export * from './builder-pairing.js'
|
|
9
|
+
export * from './mail.js'
|
|
9
10
|
|
|
10
11
|
export type { JsonValue }
|
|
11
12
|
|
|
@@ -566,6 +567,7 @@ export type {
|
|
|
566
567
|
PutAppEnvironmentInput,
|
|
567
568
|
PutAppSecretInput,
|
|
568
569
|
PutAppVarInput,
|
|
570
|
+
RotateTokenKeyResponse,
|
|
569
571
|
RunIdInput,
|
|
570
572
|
RunListInput,
|
|
571
573
|
SecretValueInput,
|
package/src/mail.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** The mail relay as the console reads and steers it. */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `held` waits for a person, `queued` for the dispatcher, `sending` is one attempt a dispatcher claimed. `sent`,
|
|
5
|
+
* `failed` (not sent), `unknown` (may have left) and `dropped` are final.
|
|
6
|
+
*/
|
|
7
|
+
export type MailMessageState = 'held' | 'queued' | 'sending' | 'sent' | 'failed' | 'unknown' | 'dropped'
|
|
8
|
+
|
|
9
|
+
export type MailRuleAction = 'pass' | 'hold' | 'drop'
|
|
10
|
+
|
|
11
|
+
/** A relayed message's metadata, behind `mail.read`. It carries no recipient, subject or body. */
|
|
12
|
+
export interface MailMessageDto {
|
|
13
|
+
readonly id: string
|
|
14
|
+
/** `<app>@<env>`, or `installation:<service>` for an installation sender. */
|
|
15
|
+
readonly sender: string
|
|
16
|
+
readonly recipientDomain: string
|
|
17
|
+
readonly state: MailMessageState
|
|
18
|
+
/** The rule that decided the message at acceptance; null when none did. */
|
|
19
|
+
readonly ruleId: string | null
|
|
20
|
+
/** Who released or dropped it, or requeued it once it was final. */
|
|
21
|
+
readonly decidedBy: string | null
|
|
22
|
+
readonly attempts: number
|
|
23
|
+
readonly nextAttemptAt: number | null
|
|
24
|
+
readonly providerMessageId: string | null
|
|
25
|
+
/**
|
|
26
|
+
* The `EmailDeliveryErrorCode` of the last failed attempt, or `dispatch_interrupted`: the dispatcher stopped after it
|
|
27
|
+
* claimed the attempt, before it recorded an outcome.
|
|
28
|
+
*/
|
|
29
|
+
readonly errorCode: string | null
|
|
30
|
+
readonly createdAt: number
|
|
31
|
+
readonly updatedAt: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** One attachment as the console shows it: its name, type and size, never its bytes. */
|
|
35
|
+
export interface MailAttachmentDto {
|
|
36
|
+
readonly filename: string
|
|
37
|
+
readonly contentType: string
|
|
38
|
+
readonly bytes: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** What the recipient sees, behind `mail.content.read`. */
|
|
42
|
+
export interface MailMessageContentDto {
|
|
43
|
+
readonly to: string
|
|
44
|
+
readonly subject: string
|
|
45
|
+
readonly text: string
|
|
46
|
+
readonly html?: string
|
|
47
|
+
readonly replyTo?: string
|
|
48
|
+
readonly fromName?: string
|
|
49
|
+
readonly unsubscribeUrl?: string
|
|
50
|
+
readonly attachments: readonly MailAttachmentDto[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** `withheld`: the caller does not hold `mail.content.read`. `purged`: the relay no longer keeps it. */
|
|
54
|
+
export type MailContentDto =
|
|
55
|
+
| { readonly kind: 'withheld' }
|
|
56
|
+
| { readonly kind: 'purged' }
|
|
57
|
+
| { readonly kind: 'present'; readonly message: MailMessageContentDto }
|
|
58
|
+
|
|
59
|
+
export interface MailMessageDetailDto extends MailMessageDto {
|
|
60
|
+
readonly content: MailContentDto
|
|
61
|
+
/** Whether a requeue would send it again now: `failed`, or `unknown` over an idempotent transport, with its content kept. */
|
|
62
|
+
readonly requeueable: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface MailMessageListInput {
|
|
66
|
+
readonly state?: MailMessageState
|
|
67
|
+
/** One sender: `<app>@<env>` or `installation:<service>`. */
|
|
68
|
+
readonly scope?: string
|
|
69
|
+
readonly cursor?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface MailMessageIdInput {
|
|
73
|
+
readonly id: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface MailRuleDto {
|
|
77
|
+
readonly id: string
|
|
78
|
+
/** `*` or `<app>@<env>`. */
|
|
79
|
+
readonly scope: string
|
|
80
|
+
/** `*` or a lowercase recipient domain. */
|
|
81
|
+
readonly domain: string
|
|
82
|
+
readonly action: MailRuleAction
|
|
83
|
+
readonly createdAt: number
|
|
84
|
+
readonly updatedAt: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Sets the action of the rule of `scope` and `domain`, creating it when there is none. */
|
|
88
|
+
export interface SetMailRuleInput {
|
|
89
|
+
readonly scope: string
|
|
90
|
+
readonly domain: string
|
|
91
|
+
readonly action: MailRuleAction
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface MailRuleIdInput {
|
|
95
|
+
readonly id: string
|
|
96
|
+
}
|
package/src/rpc.ts
CHANGED
|
@@ -47,6 +47,15 @@ import type {
|
|
|
47
47
|
UpdateAppRequest,
|
|
48
48
|
UpdateDeploymentNamespaceRequest,
|
|
49
49
|
} from './index.js'
|
|
50
|
+
import type {
|
|
51
|
+
MailMessageDetailDto,
|
|
52
|
+
MailMessageDto,
|
|
53
|
+
MailMessageIdInput,
|
|
54
|
+
MailMessageListInput,
|
|
55
|
+
MailRuleDto,
|
|
56
|
+
MailRuleIdInput,
|
|
57
|
+
SetMailRuleInput,
|
|
58
|
+
} from './mail.js'
|
|
50
59
|
|
|
51
60
|
type RpcProcedure<TInput, TOutput> = RpcProcedureContract<TInput, TOutput>
|
|
52
61
|
|
|
@@ -54,6 +63,11 @@ export interface AppIdInput {
|
|
|
54
63
|
readonly appId: string
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
/** Whether a rotation was recorded: `false` while the environment holds no token key. */
|
|
67
|
+
export interface RotateTokenKeyResponse {
|
|
68
|
+
readonly requested: boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
export interface AppEnvironmentInput extends AppIdInput {
|
|
58
72
|
readonly env: string
|
|
59
73
|
}
|
|
@@ -161,6 +175,8 @@ export interface ControlRpcContract {
|
|
|
161
175
|
delete: RpcProcedure<AppEnvironmentInput, OkResponse>
|
|
162
176
|
/** Human user principals with `access.approve` only, from the console (ADR-0050 §4). */
|
|
163
177
|
protect: RpcProcedure<SetEnvironmentProtectionRequest, AppEnvDto>
|
|
178
|
+
/** The environment's next deploy retires the key its signed tokens are signed with and signs with a new one. */
|
|
179
|
+
rotateTokenKey: RpcProcedure<AppEnvironmentInput, RotateTokenKeyResponse>
|
|
164
180
|
}
|
|
165
181
|
secrets: {
|
|
166
182
|
list: RpcProcedure<AppIdInput, ListResponse<AppSecretDto>>
|
|
@@ -214,6 +230,25 @@ export interface ControlRpcContract {
|
|
|
214
230
|
connectors: {
|
|
215
231
|
describe: RpcProcedure<DescribeConnectorRequest, ExportDescription>
|
|
216
232
|
}
|
|
233
|
+
/** The mail relay: `mail.read`, `mail.content.read` and `mail.manage`. */
|
|
234
|
+
mail: {
|
|
235
|
+
messages: {
|
|
236
|
+
list: RpcProcedure<MailMessageListInput, CursorList<MailMessageDto>>
|
|
237
|
+
/** The content only with `mail.content.read`. */
|
|
238
|
+
get: RpcProcedure<MailMessageIdInput, MailMessageDetailDto>
|
|
239
|
+
/** A held message only. */
|
|
240
|
+
release: RpcProcedure<MailMessageIdInput, MailMessageDto>
|
|
241
|
+
/** A held message only. */
|
|
242
|
+
drop: RpcProcedure<MailMessageIdInput, MailMessageDto>
|
|
243
|
+
/** A `failed` message, or an `unknown` one over an idempotent transport, whose content is kept. */
|
|
244
|
+
requeue: RpcProcedure<MailMessageIdInput, MailMessageDto>
|
|
245
|
+
}
|
|
246
|
+
rules: {
|
|
247
|
+
list: RpcProcedure<void, ListResponse<MailRuleDto>>
|
|
248
|
+
set: RpcProcedure<SetMailRuleInput, MailRuleDto>
|
|
249
|
+
remove: RpcProcedure<MailRuleIdInput, OkResponse>
|
|
250
|
+
}
|
|
251
|
+
}
|
|
217
252
|
}
|
|
218
253
|
|
|
219
254
|
/**
|