@leaflow/sdk 0.35.0 → 0.37.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/dist/account/v1/schema.d.ts +16 -2
- package/dist/iam/v1/index.d.ts +18 -0
- package/dist/iam/v1/schema.d.ts +357 -7
- package/dist/notification/v1/index.d.ts +8 -0
- package/dist/notification/v1/schema.d.ts +204 -6
- package/dist/support/v1/index.d.ts +2 -2
- package/dist/support/v1/schema.d.ts +17 -18
- package/package.json +1 -1
|
@@ -492,10 +492,24 @@ export interface components {
|
|
|
492
492
|
GrantResource: {
|
|
493
493
|
admin: boolean;
|
|
494
494
|
owner: boolean;
|
|
495
|
-
/** @description 持有的全部自定义角色的权限并集,已去重排序 */
|
|
496
|
-
permissions: string[] | null;
|
|
497
495
|
/** @description 持有的角色编码,只用于展示 */
|
|
498
496
|
roles: string[] | null;
|
|
497
|
+
/** @description 他全部策略编译出来的规则。**不要自己遍历它做判定**——拿它配上自己那份权限目录交给 pkg/rbac:那里面的顺序(所有者不可被 deny、deny 优先于管理员、带资源范围的规则不 参与项目级判定)每一条都对着一种会静默放行的写法。 */
|
|
498
|
+
rules: components["schemas"]["RuleResource"][] | null;
|
|
499
|
+
};
|
|
500
|
+
ResourceRefResource: {
|
|
501
|
+
/** @description 是字符串而不是 uuid:dns 的 zone 标识是一个域名,而且它根本不在 IAM 的库里。匹配 语义是 glob,所以 *.example.com 能表达一批子域名;uuid 和域名都不含 glob 元字符, 对它们来说这就是精确相等。 */
|
|
502
|
+
id: string;
|
|
503
|
+
/** @description 形如 compute:instance、dns:zone,和权限名同一个命名空间 */
|
|
504
|
+
type: string;
|
|
505
|
+
};
|
|
506
|
+
RuleResource: {
|
|
507
|
+
/** @enum {string} */
|
|
508
|
+
effect: "allow" | "deny";
|
|
509
|
+
/** @description 支持尾部通配(compute:instance.*),通配必须带服务前缀 */
|
|
510
|
+
permissions: string[] | null;
|
|
511
|
+
/** @description 为空表示这条规则在整个项目范围内成立;非空则表示它只在这些资源上成立,而那意味着 它回答不了项目级的问题。 */
|
|
512
|
+
resources: components["schemas"]["ResourceRefResource"][] | null;
|
|
499
513
|
};
|
|
500
514
|
ProjectAccessResource: {
|
|
501
515
|
grant: components["schemas"]["GrantResource"];
|
package/dist/iam/v1/index.d.ts
CHANGED
|
@@ -32,6 +32,24 @@ export type ListMembersQuery = operations["list-members"]["parameters"]["query"]
|
|
|
32
32
|
export type SetMemberRolesResult = operations["set-member-roles"]["responses"][200]["content"]["application/json"];
|
|
33
33
|
/** `PUT /api/v1/members/{userId}/roles` 的请求体。 */
|
|
34
34
|
export type SetMemberRolesBody = NonNullable<operations["set-member-roles"]["requestBody"]>["content"]["application/json"];
|
|
35
|
+
/** `PUT /api/v1/members/{userId}/permissions` 成功时的响应体。 */
|
|
36
|
+
export type SetMemberPermissionsResult = operations["set-member-permissions"]["responses"][200]["content"]["application/json"];
|
|
37
|
+
/** `PUT /api/v1/members/{userId}/permissions` 的请求体。 */
|
|
38
|
+
export type SetMemberPermissionsBody = NonNullable<operations["set-member-permissions"]["requestBody"]>["content"]["application/json"];
|
|
39
|
+
/** `GET /api/v1/policies` 成功时的响应体。 */
|
|
40
|
+
export type ListPoliciesResult = operations["list-policies"]["responses"][200]["content"]["application/json"];
|
|
41
|
+
/** `GET /api/v1/policies` 的查询参数。 */
|
|
42
|
+
export type ListPoliciesQuery = operations["list-policies"]["parameters"]["query"];
|
|
43
|
+
/** `POST /api/v1/policies` 成功时的响应体。 */
|
|
44
|
+
export type AttachPolicyResult = operations["attach-policy"]["responses"][201]["content"]["application/json"];
|
|
45
|
+
/** `POST /api/v1/policies` 的请求体。 */
|
|
46
|
+
export type AttachPolicyBody = NonNullable<operations["attach-policy"]["requestBody"]>["content"]["application/json"];
|
|
47
|
+
/** `GET /api/v1/policies/{policyId}` 成功时的响应体。 */
|
|
48
|
+
export type GetPolicyResult = operations["get-policy"]["responses"][200]["content"]["application/json"];
|
|
49
|
+
/** `PUT /api/v1/policies/{policyId}` 成功时的响应体。 */
|
|
50
|
+
export type UpdatePolicyResult = operations["update-policy"]["responses"][200]["content"]["application/json"];
|
|
51
|
+
/** `PUT /api/v1/policies/{policyId}` 的请求体。 */
|
|
52
|
+
export type UpdatePolicyBody = NonNullable<operations["update-policy"]["requestBody"]>["content"]["application/json"];
|
|
35
53
|
/** `POST /api/v1/transfer-ownership` 成功时的响应体。 */
|
|
36
54
|
export type TransferProjectOwnershipResult = operations["transfer-project-ownership"]["responses"][200]["content"]["application/json"];
|
|
37
55
|
/** `POST /api/v1/transfer-ownership` 的请求体。 */
|
package/dist/iam/v1/schema.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export interface paths {
|
|
|
11
11
|
cookie?: never;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
* @description
|
|
14
|
+
* 列出全平台可授予的权限
|
|
15
|
+
* @description 各服务在启动时把自己那份目录注册进 IAM(和 AddFinalizer 同一段代码),所以这里是一份汇总,不只是 IAM 自己那几条。**IAM 不用它做判定**——判定在各服务自己那边,拿 Grant 配它自己那份目录算;这份汇总只是让界面画得出勾选框,它落后一个版本只会让界面上少几条可选项,不会让判定出错。一个还没启动过的服务,它的权限不在这里。
|
|
16
16
|
*/
|
|
17
17
|
get: operations["list-permissions"];
|
|
18
18
|
put?: never;
|
|
@@ -190,6 +190,78 @@ export interface paths {
|
|
|
190
190
|
patch?: never;
|
|
191
191
|
trace?: never;
|
|
192
192
|
};
|
|
193
|
+
"/api/v1/members/{userId}/permissions": {
|
|
194
|
+
parameters: {
|
|
195
|
+
query?: never;
|
|
196
|
+
header?: never;
|
|
197
|
+
path?: never;
|
|
198
|
+
cookie?: never;
|
|
199
|
+
};
|
|
200
|
+
get?: never;
|
|
201
|
+
/**
|
|
202
|
+
* 设置一个成员直挂的权限
|
|
203
|
+
* @description 整体替换基础策略上直挂的那些权限。直挂让「给某个人临时开一条」不必先造一个只有他一个人持有的角色,但它不会随角色调整而更新,所以它适合一次性的、说得出理由的授予——角色仍然是主要的组织方式。要 iam:members.manage。
|
|
204
|
+
*/
|
|
205
|
+
put: operations["set-member-permissions"];
|
|
206
|
+
post?: never;
|
|
207
|
+
delete?: never;
|
|
208
|
+
options?: never;
|
|
209
|
+
head?: never;
|
|
210
|
+
patch?: never;
|
|
211
|
+
trace?: never;
|
|
212
|
+
};
|
|
213
|
+
"/api/v1/policies": {
|
|
214
|
+
parameters: {
|
|
215
|
+
query?: never;
|
|
216
|
+
header?: never;
|
|
217
|
+
path?: never;
|
|
218
|
+
cookie?: never;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* 列出这个项目里的策略
|
|
222
|
+
* @description 在项目里就看得到,和成员列表同一条规则:谁被授了什么也是「这个项目有谁」的一部分。
|
|
223
|
+
*/
|
|
224
|
+
get: operations["list-policies"];
|
|
225
|
+
put?: never;
|
|
226
|
+
/**
|
|
227
|
+
* 附加一条策略
|
|
228
|
+
* @description 它建的是**附加**策略——要么带资源范围,要么方向是 deny。一条不限资源的 allow 是基础策略,每个成员只有一条,改它走 set-member-roles 和 set-member-permissions。roles 里不能有 OWNER 或 ADMIN:它们是规则而不是权限集合,「限定在三台机器上的所有者」讲不通。要 iam:members.manage。
|
|
229
|
+
*/
|
|
230
|
+
post: operations["attach-policy"];
|
|
231
|
+
delete?: never;
|
|
232
|
+
options?: never;
|
|
233
|
+
head?: never;
|
|
234
|
+
patch?: never;
|
|
235
|
+
trace?: never;
|
|
236
|
+
};
|
|
237
|
+
"/api/v1/policies/{policyId}": {
|
|
238
|
+
parameters: {
|
|
239
|
+
query?: never;
|
|
240
|
+
header?: never;
|
|
241
|
+
path?: never;
|
|
242
|
+
cookie?: never;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* 查看一条策略
|
|
246
|
+
* @description 和 list-policies 同一条规则,在项目里就看得到:谁被授了什么也是「这个项目有谁」的一部分,读它不需要额外的权限。
|
|
247
|
+
*/
|
|
248
|
+
get: operations["get-policy"];
|
|
249
|
+
/**
|
|
250
|
+
* 改一条策略
|
|
251
|
+
* @description 整体替换而不是逐字段改:resources、roles、permissions 各自整份覆盖,没发的那份就是空的——只有「这就是这条策略现在的全貌」这一种语义说得清一次写入到底收回了什么。改不动的是策略的**种类**:基础策略(不限资源的 allow)加不上资源范围,这个成员的角色就存在它上面,给它加个范围等于让他在别的资源上什么都不是;一条带范围的策略反过来也不能把范围清空变成基础策略,那个位置每个成员只有一条。要换种类就删了重建。要 iam:members.manage。
|
|
252
|
+
*/
|
|
253
|
+
put: operations["update-policy"];
|
|
254
|
+
post?: never;
|
|
255
|
+
/**
|
|
256
|
+
* 摘掉一条策略
|
|
257
|
+
* @description 基础策略摘不掉——它是这个成员角色的落点,删了它这个人就不再持有任何角色,而「让他离开这个项目」是 remove-member 的事。要 iam:members.manage。
|
|
258
|
+
*/
|
|
259
|
+
delete: operations["detach-policy"];
|
|
260
|
+
options?: never;
|
|
261
|
+
head?: never;
|
|
262
|
+
patch?: never;
|
|
263
|
+
trace?: never;
|
|
264
|
+
};
|
|
193
265
|
"/api/v1/transfer-ownership": {
|
|
194
266
|
parameters: {
|
|
195
267
|
query?: never;
|
|
@@ -320,17 +392,43 @@ export interface components {
|
|
|
320
392
|
name: string;
|
|
321
393
|
/** @description 只有项目所有者能做,绑到自定义角色上也不会生效 */
|
|
322
394
|
owner_only: boolean;
|
|
395
|
+
/** @description 这条权限的判定对象是哪类资源,空表示它是项目级的。**它不必等于操作对象本身**——compute 的 route 表上没有 project_id,隔离本来就经父网络传递,所以 compute:route.create 的判定对象是 compute:private_network。非空同时意味着这条权限可以被限定到具体实例;create 和 list 一律留空 */
|
|
396
|
+
resource_type: string;
|
|
397
|
+
};
|
|
398
|
+
ResourceTypeResource: {
|
|
399
|
+
description: string;
|
|
400
|
+
name: string;
|
|
401
|
+
};
|
|
402
|
+
CatalogResource: {
|
|
403
|
+
permissions: components["schemas"]["PermissionResource"][] | null;
|
|
404
|
+
/** @description 这个服务声明的资源类型。带资源范围的规则只落得到它们上面——一个没有被声明过的类型没人认得,限定在它上面的规则谁都判不出来 */
|
|
405
|
+
resource_types: components["schemas"]["ResourceTypeResource"][] | null;
|
|
406
|
+
service: string;
|
|
407
|
+
};
|
|
408
|
+
CatalogListResponseBody: {
|
|
409
|
+
items: components["schemas"]["CatalogResource"][] | null;
|
|
410
|
+
};
|
|
411
|
+
ResourceRefResource: {
|
|
412
|
+
/** @description 是字符串不是 uuid:dns 的 zone 标识是域名,而且不在 IAM 库里。匹配语义是 glob,所以 *.example.com 能表达一批子域名;uuid 和域名都不含 glob 元字符,对它们来说就是精确相等 */
|
|
413
|
+
id: string;
|
|
414
|
+
/** @description 形如 compute:instance、dns:zone,和权限名同一个命名空间 */
|
|
415
|
+
type: string;
|
|
323
416
|
};
|
|
324
|
-
|
|
325
|
-
|
|
417
|
+
RuleResource: {
|
|
418
|
+
/** @enum {string} */
|
|
419
|
+
effect: "allow" | "deny";
|
|
420
|
+
/** @description 权限名,支持尾部通配(compute:instance.*)。通配必须带服务前缀——一条光秃秃的 * 会把日后新上线的服务的操作也一起授出去,而那件事发生的时候没有任何人在场 */
|
|
421
|
+
permissions: string[] | null;
|
|
422
|
+
/** @description 为空表示整个项目范围;非空表示这条规则只在这些资源上成立,而那意味着它回答不了项目级的问题 */
|
|
423
|
+
resources: components["schemas"]["ResourceRefResource"][] | null;
|
|
326
424
|
};
|
|
327
425
|
GrantResource: {
|
|
328
426
|
admin: boolean;
|
|
329
427
|
owner: boolean;
|
|
330
|
-
/** @description 持有的全部自定义角色的权限并集,已去重排序 */
|
|
331
|
-
permissions: string[] | null;
|
|
332
428
|
/** @description 持有的角色编码,只用于展示 */
|
|
333
429
|
roles: string[] | null;
|
|
430
|
+
/** @description 他全部策略编译出来的规则。**不要自己遍历它做判定**——拿它配上自己那份权限目录交给 pkg/rbac:owner 不可被 deny、deny 优先于 admin、带资源范围的规则不参与项目级判定,那里面的顺序每一条都对着一种会静默放行的写法 */
|
|
431
|
+
rules: components["schemas"]["RuleResource"][] | null;
|
|
334
432
|
};
|
|
335
433
|
ProjectResource: {
|
|
336
434
|
ban_reason: string;
|
|
@@ -470,6 +568,63 @@ export interface components {
|
|
|
470
568
|
/** @description 这个人应当持有的**全部**角色编码。OWNER 不能出现在这里 */
|
|
471
569
|
roles: string[] | null;
|
|
472
570
|
};
|
|
571
|
+
SetMemberPermissionsRequestBody: {
|
|
572
|
+
/** @description 这个人应当直挂的**全部**权限名,整体替换。角色给的那些不在这里,也不会被这次写入碰到 */
|
|
573
|
+
permissions: string[] | null;
|
|
574
|
+
};
|
|
575
|
+
PolicyResource: {
|
|
576
|
+
/** @description 基础策略是方向 allow、不限资源的那一条,每个成员恰好一条,装的是他的常规角色。改它走 PUT /members/{userId}/roles 和 PUT /members/{userId}/permissions */
|
|
577
|
+
base: boolean;
|
|
578
|
+
/** Format: date-time */
|
|
579
|
+
created_at: string;
|
|
580
|
+
/** @description 给人看的理由。一条附加策略事后最难回答的是「当初为什么开这一条」 */
|
|
581
|
+
description: string;
|
|
582
|
+
/** @enum {string} */
|
|
583
|
+
effect: "allow" | "deny";
|
|
584
|
+
/** Format: uuid */
|
|
585
|
+
id: string;
|
|
586
|
+
/** @description 直挂在这个人身上的权限名,不经过角色 */
|
|
587
|
+
permissions: string[] | null;
|
|
588
|
+
/** @description 为空表示整个项目范围 */
|
|
589
|
+
resources: components["schemas"]["ResourceRefResource"][] | null;
|
|
590
|
+
/** @description 这条策略带上的角色编码 */
|
|
591
|
+
roles: string[] | null;
|
|
592
|
+
/** Format: date-time */
|
|
593
|
+
updated_at: string;
|
|
594
|
+
user_id: string;
|
|
595
|
+
};
|
|
596
|
+
PolicyListResponseBody: {
|
|
597
|
+
items: components["schemas"]["PolicyResource"][] | null;
|
|
598
|
+
};
|
|
599
|
+
AttachPolicyRequestBody: {
|
|
600
|
+
/** @description 给人看的理由。一条附加策略事后最难回答的是「当初为什么开这一条」 */
|
|
601
|
+
description?: string;
|
|
602
|
+
/** @enum {string} */
|
|
603
|
+
effect: "allow" | "deny";
|
|
604
|
+
/** @description 直挂的权限名,用它就不必为一个人临时造一个只有他持有的角色 */
|
|
605
|
+
permissions?: string[] | null;
|
|
606
|
+
/** @description 这条策略只在这些资源上成立。留空只有配合 deny 才讲得通——一条不限资源的 allow 是基础策略,那一条已经有了 */
|
|
607
|
+
resources?: components["schemas"]["ResourceRefResource"][] | null;
|
|
608
|
+
/** @description 必须是这个项目已经定义的角色。OWNER 和 ADMIN 不行——它们是规则而不是权限集合,「限定在三台机器上的所有者」讲不通 */
|
|
609
|
+
roles?: string[] | null;
|
|
610
|
+
/** @description 必须已经是这个项目的成员 */
|
|
611
|
+
user_id: string;
|
|
612
|
+
};
|
|
613
|
+
UpdatePolicyRequestBody: {
|
|
614
|
+
/** @description 给人看的理由。它和这次改动一起替换,不然留下来的会是一句解释着上一个版本的话 */
|
|
615
|
+
description?: string;
|
|
616
|
+
/**
|
|
617
|
+
* @description 必须和这条策略当前的方向一致。方向改不动——那不是「改一条策略」,是一次意思完全相反的授权决定,改它的人多半以为自己在收紧,而读这行数据的下一个人看到的是一条方向和当初授予时不同、说明文字却还是旧的策略。仍然要求发这个字段而不是干脆不收,是因为整体替换的语义是「这就是这条策略现在的全貌」:少一个字段的话,调用方以为自己把 deny 改成了 allow,而服务端默默忽略了它。不一致时返回 PROJECT_POLICY_EFFECT_IMMUTABLE
|
|
618
|
+
* @enum {string}
|
|
619
|
+
*/
|
|
620
|
+
effect: "allow" | "deny";
|
|
621
|
+
/** @description 直挂的权限名,整份替换。没列进来的就是被收回了——它不是往上加一条 */
|
|
622
|
+
permissions?: string[] | null;
|
|
623
|
+
/** @description 这条策略的资源范围,整份替换。范围内容能改,有没有范围改不了:基础策略加不上范围,带范围的也清不空——清空之后它就是基础策略的形状,而那个位置每个成员只有一条 */
|
|
624
|
+
resources?: components["schemas"]["ResourceRefResource"][] | null;
|
|
625
|
+
/** @description 必须是这个项目已经定义的角色,整份替换。和挂上去那次一样不能有 OWNER 或 ADMIN */
|
|
626
|
+
roles?: string[] | null;
|
|
627
|
+
};
|
|
473
628
|
TransferOwnershipRequestBody: {
|
|
474
629
|
/** @description 接手的人必须已经是这个项目的成员 */
|
|
475
630
|
to_user_id: string;
|
|
@@ -584,7 +739,7 @@ export interface operations {
|
|
|
584
739
|
[name: string]: unknown;
|
|
585
740
|
};
|
|
586
741
|
content: {
|
|
587
|
-
"application/json": components["schemas"]["
|
|
742
|
+
"application/json": components["schemas"]["CatalogListResponseBody"];
|
|
588
743
|
};
|
|
589
744
|
};
|
|
590
745
|
/** @description Error */
|
|
@@ -947,6 +1102,201 @@ export interface operations {
|
|
|
947
1102
|
};
|
|
948
1103
|
};
|
|
949
1104
|
};
|
|
1105
|
+
"set-member-permissions": {
|
|
1106
|
+
parameters: {
|
|
1107
|
+
query?: never;
|
|
1108
|
+
header?: never;
|
|
1109
|
+
path: {
|
|
1110
|
+
userId: string;
|
|
1111
|
+
};
|
|
1112
|
+
cookie?: never;
|
|
1113
|
+
};
|
|
1114
|
+
requestBody: {
|
|
1115
|
+
content: {
|
|
1116
|
+
"application/json": components["schemas"]["SetMemberPermissionsRequestBody"];
|
|
1117
|
+
};
|
|
1118
|
+
};
|
|
1119
|
+
responses: {
|
|
1120
|
+
/** @description OK */
|
|
1121
|
+
200: {
|
|
1122
|
+
headers: {
|
|
1123
|
+
[name: string]: unknown;
|
|
1124
|
+
};
|
|
1125
|
+
content: {
|
|
1126
|
+
"application/json": components["schemas"]["PolicyResource"];
|
|
1127
|
+
};
|
|
1128
|
+
};
|
|
1129
|
+
/** @description Error */
|
|
1130
|
+
default: {
|
|
1131
|
+
headers: {
|
|
1132
|
+
[name: string]: unknown;
|
|
1133
|
+
};
|
|
1134
|
+
content: {
|
|
1135
|
+
"application/json": components["schemas"]["Error"];
|
|
1136
|
+
};
|
|
1137
|
+
};
|
|
1138
|
+
};
|
|
1139
|
+
};
|
|
1140
|
+
"list-policies": {
|
|
1141
|
+
parameters: {
|
|
1142
|
+
query?: {
|
|
1143
|
+
/** @description 只看这个人身上的。不传表示整个项目的 */
|
|
1144
|
+
userId?: string;
|
|
1145
|
+
};
|
|
1146
|
+
header?: never;
|
|
1147
|
+
path?: never;
|
|
1148
|
+
cookie?: never;
|
|
1149
|
+
};
|
|
1150
|
+
requestBody?: never;
|
|
1151
|
+
responses: {
|
|
1152
|
+
/** @description OK */
|
|
1153
|
+
200: {
|
|
1154
|
+
headers: {
|
|
1155
|
+
[name: string]: unknown;
|
|
1156
|
+
};
|
|
1157
|
+
content: {
|
|
1158
|
+
"application/json": components["schemas"]["PolicyListResponseBody"];
|
|
1159
|
+
};
|
|
1160
|
+
};
|
|
1161
|
+
/** @description Error */
|
|
1162
|
+
default: {
|
|
1163
|
+
headers: {
|
|
1164
|
+
[name: string]: unknown;
|
|
1165
|
+
};
|
|
1166
|
+
content: {
|
|
1167
|
+
"application/json": components["schemas"]["Error"];
|
|
1168
|
+
};
|
|
1169
|
+
};
|
|
1170
|
+
};
|
|
1171
|
+
};
|
|
1172
|
+
"attach-policy": {
|
|
1173
|
+
parameters: {
|
|
1174
|
+
query?: never;
|
|
1175
|
+
header?: never;
|
|
1176
|
+
path?: never;
|
|
1177
|
+
cookie?: never;
|
|
1178
|
+
};
|
|
1179
|
+
requestBody: {
|
|
1180
|
+
content: {
|
|
1181
|
+
"application/json": components["schemas"]["AttachPolicyRequestBody"];
|
|
1182
|
+
};
|
|
1183
|
+
};
|
|
1184
|
+
responses: {
|
|
1185
|
+
/** @description Created */
|
|
1186
|
+
201: {
|
|
1187
|
+
headers: {
|
|
1188
|
+
[name: string]: unknown;
|
|
1189
|
+
};
|
|
1190
|
+
content: {
|
|
1191
|
+
"application/json": components["schemas"]["PolicyResource"];
|
|
1192
|
+
};
|
|
1193
|
+
};
|
|
1194
|
+
/** @description Error */
|
|
1195
|
+
default: {
|
|
1196
|
+
headers: {
|
|
1197
|
+
[name: string]: unknown;
|
|
1198
|
+
};
|
|
1199
|
+
content: {
|
|
1200
|
+
"application/json": components["schemas"]["Error"];
|
|
1201
|
+
};
|
|
1202
|
+
};
|
|
1203
|
+
};
|
|
1204
|
+
};
|
|
1205
|
+
"get-policy": {
|
|
1206
|
+
parameters: {
|
|
1207
|
+
query?: never;
|
|
1208
|
+
header?: never;
|
|
1209
|
+
path: {
|
|
1210
|
+
policyId: string;
|
|
1211
|
+
};
|
|
1212
|
+
cookie?: never;
|
|
1213
|
+
};
|
|
1214
|
+
requestBody?: never;
|
|
1215
|
+
responses: {
|
|
1216
|
+
/** @description OK */
|
|
1217
|
+
200: {
|
|
1218
|
+
headers: {
|
|
1219
|
+
[name: string]: unknown;
|
|
1220
|
+
};
|
|
1221
|
+
content: {
|
|
1222
|
+
"application/json": components["schemas"]["PolicyResource"];
|
|
1223
|
+
};
|
|
1224
|
+
};
|
|
1225
|
+
/** @description Error */
|
|
1226
|
+
default: {
|
|
1227
|
+
headers: {
|
|
1228
|
+
[name: string]: unknown;
|
|
1229
|
+
};
|
|
1230
|
+
content: {
|
|
1231
|
+
"application/json": components["schemas"]["Error"];
|
|
1232
|
+
};
|
|
1233
|
+
};
|
|
1234
|
+
};
|
|
1235
|
+
};
|
|
1236
|
+
"update-policy": {
|
|
1237
|
+
parameters: {
|
|
1238
|
+
query?: never;
|
|
1239
|
+
header?: never;
|
|
1240
|
+
path: {
|
|
1241
|
+
policyId: string;
|
|
1242
|
+
};
|
|
1243
|
+
cookie?: never;
|
|
1244
|
+
};
|
|
1245
|
+
requestBody: {
|
|
1246
|
+
content: {
|
|
1247
|
+
"application/json": components["schemas"]["UpdatePolicyRequestBody"];
|
|
1248
|
+
};
|
|
1249
|
+
};
|
|
1250
|
+
responses: {
|
|
1251
|
+
/** @description OK */
|
|
1252
|
+
200: {
|
|
1253
|
+
headers: {
|
|
1254
|
+
[name: string]: unknown;
|
|
1255
|
+
};
|
|
1256
|
+
content: {
|
|
1257
|
+
"application/json": components["schemas"]["PolicyResource"];
|
|
1258
|
+
};
|
|
1259
|
+
};
|
|
1260
|
+
/** @description Error */
|
|
1261
|
+
default: {
|
|
1262
|
+
headers: {
|
|
1263
|
+
[name: string]: unknown;
|
|
1264
|
+
};
|
|
1265
|
+
content: {
|
|
1266
|
+
"application/json": components["schemas"]["Error"];
|
|
1267
|
+
};
|
|
1268
|
+
};
|
|
1269
|
+
};
|
|
1270
|
+
};
|
|
1271
|
+
"detach-policy": {
|
|
1272
|
+
parameters: {
|
|
1273
|
+
query?: never;
|
|
1274
|
+
header?: never;
|
|
1275
|
+
path: {
|
|
1276
|
+
policyId: string;
|
|
1277
|
+
};
|
|
1278
|
+
cookie?: never;
|
|
1279
|
+
};
|
|
1280
|
+
requestBody?: never;
|
|
1281
|
+
responses: {
|
|
1282
|
+
/** @description No Content */
|
|
1283
|
+
204: {
|
|
1284
|
+
headers: {
|
|
1285
|
+
[name: string]: unknown;
|
|
1286
|
+
};
|
|
1287
|
+
content?: never;
|
|
1288
|
+
};
|
|
1289
|
+
/** @description Error */
|
|
1290
|
+
default: {
|
|
1291
|
+
headers: {
|
|
1292
|
+
[name: string]: unknown;
|
|
1293
|
+
};
|
|
1294
|
+
content: {
|
|
1295
|
+
"application/json": components["schemas"]["Error"];
|
|
1296
|
+
};
|
|
1297
|
+
};
|
|
1298
|
+
};
|
|
1299
|
+
};
|
|
950
1300
|
"transfer-project-ownership": {
|
|
951
1301
|
parameters: {
|
|
952
1302
|
query?: never;
|
|
@@ -34,6 +34,14 @@ export type GetNotificationPreferencesResult = operations["get-notification-pref
|
|
|
34
34
|
export type UpdateNotificationPreferencesResult = operations["update-notification-preferences"]["responses"][200]["content"]["application/json"];
|
|
35
35
|
/** `PATCH /api/v1/preferences` 的请求体。 */
|
|
36
36
|
export type UpdateNotificationPreferencesBody = NonNullable<operations["update-notification-preferences"]["requestBody"]>["content"]["application/json"];
|
|
37
|
+
/** `POST /api/v1/preferences/email-override/code` 成功时的响应体。 */
|
|
38
|
+
export type SendEmailOverrideCodeResult = operations["send-email-override-code"]["responses"][200]["content"]["application/json"];
|
|
39
|
+
/** `DELETE /api/v1/preferences/email-override/code` 成功时的响应体。 */
|
|
40
|
+
export type CancelEmailOverrideResult = operations["cancel-email-override"]["responses"][200]["content"]["application/json"];
|
|
41
|
+
/** `POST /api/v1/preferences/email-override/code/confirm` 成功时的响应体。 */
|
|
42
|
+
export type ConfirmEmailOverrideResult = operations["confirm-email-override"]["responses"][200]["content"]["application/json"];
|
|
43
|
+
/** `POST /api/v1/preferences/email-override/code/confirm` 的请求体。 */
|
|
44
|
+
export type ConfirmEmailOverrideBody = NonNullable<operations["confirm-email-override"]["requestBody"]>["content"]["application/json"];
|
|
37
45
|
/** `GET /api/v1/preferences/types` 成功时的响应体。 */
|
|
38
46
|
export type ListTypePreferencesResult = operations["list-type-preferences"]["responses"][200]["content"]["application/json"];
|
|
39
47
|
/** `GET /api/v1/preferences/types` 的查询参数。 */
|
|
@@ -275,13 +275,80 @@ export interface paths {
|
|
|
275
275
|
* Update your delivery preferences
|
|
276
276
|
* @description Fields that are omitted are left alone.
|
|
277
277
|
*
|
|
278
|
-
* Setting `email_override`
|
|
279
|
-
*
|
|
280
|
-
*
|
|
278
|
+
* Setting `email_override` records it as the pending address; nothing is sent to it until
|
|
279
|
+
* `send-email-override-code` is called, and email keeps going where it went before. Setting
|
|
280
|
+
* it to null clears the pending address and any address in use, returning delivery to the
|
|
281
|
+
* account address.
|
|
282
|
+
*
|
|
283
|
+
* An address is never used until somebody proves they can read it. Without that, anybody
|
|
284
|
+
* could point their own notifications at a stranger's mailbox, and the stranger would get
|
|
285
|
+
* mail about an account they have never heard of.
|
|
281
286
|
*/
|
|
282
287
|
patch: operations["update-notification-preferences"];
|
|
283
288
|
trace?: never;
|
|
284
289
|
};
|
|
290
|
+
"/api/v1/preferences/email-override/code": {
|
|
291
|
+
parameters: {
|
|
292
|
+
query?: never;
|
|
293
|
+
header?: never;
|
|
294
|
+
path?: never;
|
|
295
|
+
cookie?: never;
|
|
296
|
+
};
|
|
297
|
+
get?: never;
|
|
298
|
+
put?: never;
|
|
299
|
+
/**
|
|
300
|
+
* Send a code to the pending address
|
|
301
|
+
* @description Emails a short code to the address waiting to be confirmed. That address receives this and
|
|
302
|
+
* nothing else; every other notification keeps going where it went before.
|
|
303
|
+
*
|
|
304
|
+
* The code stops working after a few minutes, and a wrong one can only be tried a handful of
|
|
305
|
+
* times before it is thrown away and a new one has to be sent. Both limits exist for the same
|
|
306
|
+
* reason: a six digit code is guessable if it lives forever and can be tried forever.
|
|
307
|
+
*
|
|
308
|
+
* Sending is rate limited per account and per destination address. The second limit is the one
|
|
309
|
+
* that matters to somebody who never asked to be involved: without it, this operation is a way
|
|
310
|
+
* to make the platform mail a stranger repeatedly.
|
|
311
|
+
*/
|
|
312
|
+
post: operations["send-email-override-code"];
|
|
313
|
+
/**
|
|
314
|
+
* Give up on the pending address
|
|
315
|
+
* @description Drops the pending address and the code that was sent to it. Nothing else changes: an address
|
|
316
|
+
* that was already confirmed keeps receiving email.
|
|
317
|
+
*
|
|
318
|
+
* It exists because starting this and then changing your mind is ordinary, and the alternative
|
|
319
|
+
* is a settings page that shows an address waiting to be confirmed forever.
|
|
320
|
+
*/
|
|
321
|
+
delete: operations["cancel-email-override"];
|
|
322
|
+
options?: never;
|
|
323
|
+
head?: never;
|
|
324
|
+
patch?: never;
|
|
325
|
+
trace?: never;
|
|
326
|
+
};
|
|
327
|
+
"/api/v1/preferences/email-override/code/confirm": {
|
|
328
|
+
parameters: {
|
|
329
|
+
query?: never;
|
|
330
|
+
header?: never;
|
|
331
|
+
path?: never;
|
|
332
|
+
cookie?: never;
|
|
333
|
+
};
|
|
334
|
+
get?: never;
|
|
335
|
+
put?: never;
|
|
336
|
+
/**
|
|
337
|
+
* Confirm the pending address with its code
|
|
338
|
+
* @description A correct code moves the pending address into use: email starts going there instead of the
|
|
339
|
+
* account address, and the pending slot is emptied.
|
|
340
|
+
*
|
|
341
|
+
* A wrong code counts against the attempts on that code. Running out of attempts throws the
|
|
342
|
+
* code away, and a new one has to be sent; the pending address itself is kept, so nobody
|
|
343
|
+
* loses their place by mistyping.
|
|
344
|
+
*/
|
|
345
|
+
post: operations["confirm-email-override"];
|
|
346
|
+
delete?: never;
|
|
347
|
+
options?: never;
|
|
348
|
+
head?: never;
|
|
349
|
+
patch?: never;
|
|
350
|
+
trace?: never;
|
|
351
|
+
};
|
|
285
352
|
"/api/v1/preferences/types": {
|
|
286
353
|
parameters: {
|
|
287
354
|
query?: never;
|
|
@@ -756,11 +823,26 @@ export interface components {
|
|
|
756
823
|
PreferencesResource: {
|
|
757
824
|
/** @description Where email is delivered right now, which is the account address unless a verified override replaces it */
|
|
758
825
|
email_address: string;
|
|
759
|
-
/**
|
|
826
|
+
/**
|
|
827
|
+
* @description The address email goes to instead of the account address; null when the account address
|
|
828
|
+
* is used. Only ever an address that was confirmed by code
|
|
829
|
+
*/
|
|
760
830
|
email_override: string | null;
|
|
831
|
+
/**
|
|
832
|
+
* @description An address waiting to be confirmed; null when nothing is waiting. It receives nothing but
|
|
833
|
+
* the code, and the address in `email_override` keeps being used until this one is
|
|
834
|
+
* confirmed
|
|
835
|
+
*/
|
|
836
|
+
email_override_pending: string | null;
|
|
837
|
+
/**
|
|
838
|
+
* Format: date-time
|
|
839
|
+
* @description When the code last sent to the pending address stops working; null when no code is
|
|
840
|
+
* outstanding, in which case a new one has to be sent before it can be confirmed
|
|
841
|
+
*/
|
|
842
|
+
email_override_pending_expires_at: string | null;
|
|
761
843
|
/**
|
|
762
844
|
* Format: date-time
|
|
763
|
-
* @description When the
|
|
845
|
+
* @description When the address in `email_override` was confirmed; null when there is no override
|
|
764
846
|
*/
|
|
765
847
|
email_override_verified_at: string | null;
|
|
766
848
|
/** @description The language notifications are written in, as an IETF language tag */
|
|
@@ -768,11 +850,36 @@ export interface components {
|
|
|
768
850
|
};
|
|
769
851
|
/** @description Fields that are omitted are left alone. */
|
|
770
852
|
UpdatePreferencesRequestBody: {
|
|
771
|
-
/**
|
|
853
|
+
/**
|
|
854
|
+
* @description An address to receive email instead of the account address. It is stored as pending and
|
|
855
|
+
* receives nothing until it is confirmed by code, so the address in use does not change
|
|
856
|
+
* here. Null clears both the pending address and the one in use, returning delivery to
|
|
857
|
+
* the account address
|
|
858
|
+
*/
|
|
772
859
|
email_override?: string | null;
|
|
773
860
|
/** @description An IETF language tag. A language that is not supported is rejected rather than approximated */
|
|
774
861
|
locale?: string;
|
|
775
862
|
};
|
|
863
|
+
/** @description What was sent, and when the next one may be asked for. */
|
|
864
|
+
EmailOverrideCodeResource: {
|
|
865
|
+
/** @description Where the code went. It is the pending address, echoed so a client can show it */
|
|
866
|
+
address: string;
|
|
867
|
+
/**
|
|
868
|
+
* Format: date-time
|
|
869
|
+
* @description When this code stops working
|
|
870
|
+
*/
|
|
871
|
+
expires_at: string;
|
|
872
|
+
/**
|
|
873
|
+
* Format: date-time
|
|
874
|
+
* @description The earliest another code may be asked for. Asking sooner is refused rather than
|
|
875
|
+
* silently ignored, so a client can show the wait instead of a failure
|
|
876
|
+
*/
|
|
877
|
+
resend_available_at: string;
|
|
878
|
+
};
|
|
879
|
+
ConfirmEmailOverrideRequestBody: {
|
|
880
|
+
/** @description The code from the email, exactly as it appears there */
|
|
881
|
+
code: string;
|
|
882
|
+
};
|
|
776
883
|
TypePreferenceResource: {
|
|
777
884
|
/** @description Where this type is delivered */
|
|
778
885
|
channels: components["schemas"]["NotificationChannel"][];
|
|
@@ -1435,6 +1542,97 @@ export interface operations {
|
|
|
1435
1542
|
};
|
|
1436
1543
|
};
|
|
1437
1544
|
};
|
|
1545
|
+
"send-email-override-code": {
|
|
1546
|
+
parameters: {
|
|
1547
|
+
query?: never;
|
|
1548
|
+
header?: never;
|
|
1549
|
+
path?: never;
|
|
1550
|
+
cookie?: never;
|
|
1551
|
+
};
|
|
1552
|
+
requestBody?: never;
|
|
1553
|
+
responses: {
|
|
1554
|
+
/** @description OK */
|
|
1555
|
+
200: {
|
|
1556
|
+
headers: {
|
|
1557
|
+
[name: string]: unknown;
|
|
1558
|
+
};
|
|
1559
|
+
content: {
|
|
1560
|
+
"application/json": components["schemas"]["EmailOverrideCodeResource"];
|
|
1561
|
+
};
|
|
1562
|
+
};
|
|
1563
|
+
/** @description Error */
|
|
1564
|
+
default: {
|
|
1565
|
+
headers: {
|
|
1566
|
+
[name: string]: unknown;
|
|
1567
|
+
};
|
|
1568
|
+
content: {
|
|
1569
|
+
"application/json": components["schemas"]["Error"];
|
|
1570
|
+
};
|
|
1571
|
+
};
|
|
1572
|
+
};
|
|
1573
|
+
};
|
|
1574
|
+
"cancel-email-override": {
|
|
1575
|
+
parameters: {
|
|
1576
|
+
query?: never;
|
|
1577
|
+
header?: never;
|
|
1578
|
+
path?: never;
|
|
1579
|
+
cookie?: never;
|
|
1580
|
+
};
|
|
1581
|
+
requestBody?: never;
|
|
1582
|
+
responses: {
|
|
1583
|
+
/** @description OK */
|
|
1584
|
+
200: {
|
|
1585
|
+
headers: {
|
|
1586
|
+
[name: string]: unknown;
|
|
1587
|
+
};
|
|
1588
|
+
content: {
|
|
1589
|
+
"application/json": components["schemas"]["PreferencesResource"];
|
|
1590
|
+
};
|
|
1591
|
+
};
|
|
1592
|
+
/** @description Error */
|
|
1593
|
+
default: {
|
|
1594
|
+
headers: {
|
|
1595
|
+
[name: string]: unknown;
|
|
1596
|
+
};
|
|
1597
|
+
content: {
|
|
1598
|
+
"application/json": components["schemas"]["Error"];
|
|
1599
|
+
};
|
|
1600
|
+
};
|
|
1601
|
+
};
|
|
1602
|
+
};
|
|
1603
|
+
"confirm-email-override": {
|
|
1604
|
+
parameters: {
|
|
1605
|
+
query?: never;
|
|
1606
|
+
header?: never;
|
|
1607
|
+
path?: never;
|
|
1608
|
+
cookie?: never;
|
|
1609
|
+
};
|
|
1610
|
+
requestBody: {
|
|
1611
|
+
content: {
|
|
1612
|
+
"application/json": components["schemas"]["ConfirmEmailOverrideRequestBody"];
|
|
1613
|
+
};
|
|
1614
|
+
};
|
|
1615
|
+
responses: {
|
|
1616
|
+
/** @description OK */
|
|
1617
|
+
200: {
|
|
1618
|
+
headers: {
|
|
1619
|
+
[name: string]: unknown;
|
|
1620
|
+
};
|
|
1621
|
+
content: {
|
|
1622
|
+
"application/json": components["schemas"]["PreferencesResource"];
|
|
1623
|
+
};
|
|
1624
|
+
};
|
|
1625
|
+
/** @description Error */
|
|
1626
|
+
default: {
|
|
1627
|
+
headers: {
|
|
1628
|
+
[name: string]: unknown;
|
|
1629
|
+
};
|
|
1630
|
+
content: {
|
|
1631
|
+
"application/json": components["schemas"]["Error"];
|
|
1632
|
+
};
|
|
1633
|
+
};
|
|
1634
|
+
};
|
|
1635
|
+
};
|
|
1438
1636
|
"list-type-preferences": {
|
|
1439
1637
|
parameters: {
|
|
1440
1638
|
query?: {
|
|
@@ -36,8 +36,8 @@ export type ListTicketCategoriesQuery = operations["list-ticket-categories"]["pa
|
|
|
36
36
|
export type UploadAttachmentResult = operations["upload-attachment"]["responses"][201]["content"]["application/json"];
|
|
37
37
|
/** `POST /api/v1/attachments` 的查询参数。 */
|
|
38
38
|
export type UploadAttachmentQuery = operations["upload-attachment"]["parameters"]["query"];
|
|
39
|
-
/** `GET /api/v1/attachments/{attachmentId}/
|
|
40
|
-
export type
|
|
39
|
+
/** `GET /api/v1/attachments/{attachmentId}/content` 的查询参数。 */
|
|
40
|
+
export type DownloadAttachmentQuery = operations["download-attachment"]["parameters"]["query"];
|
|
41
41
|
/** `GET /api/v1/maintenances` 成功时的响应体。 */
|
|
42
42
|
export type ListMaintenancesResult = operations["list-maintenances"]["responses"][200]["content"]["application/json"];
|
|
43
43
|
/** `GET /api/v1/maintenances` 的查询参数。 */
|
|
@@ -202,7 +202,7 @@ export interface paths {
|
|
|
202
202
|
patch?: never;
|
|
203
203
|
trace?: never;
|
|
204
204
|
};
|
|
205
|
-
"/api/v1/attachments/{attachmentId}/
|
|
205
|
+
"/api/v1/attachments/{attachmentId}/content": {
|
|
206
206
|
parameters: {
|
|
207
207
|
query?: never;
|
|
208
208
|
header?: never;
|
|
@@ -210,13 +210,16 @@ export interface paths {
|
|
|
210
210
|
cookie?: never;
|
|
211
211
|
};
|
|
212
212
|
/**
|
|
213
|
-
*
|
|
214
|
-
* @description
|
|
215
|
-
*
|
|
213
|
+
* Download an attachment
|
|
214
|
+
* @description Serves the file itself. The bytes are proxied by this API; the object store is not reachable
|
|
215
|
+
* from outside, and no address to it is ever handed out.
|
|
216
216
|
*
|
|
217
|
-
*
|
|
217
|
+
* `Content-Type` is the type determined from the content at upload time, not the one the
|
|
218
|
+
* client claimed. `Content-Disposition` is `attachment` unless `inline` is requested **and**
|
|
219
|
+
* the content type is one that can be rendered safely, in which case it is `inline`. Asking
|
|
220
|
+
* for `inline` on anything else still yields a download.
|
|
218
221
|
*/
|
|
219
|
-
get: operations["
|
|
222
|
+
get: operations["download-attachment"];
|
|
220
223
|
put?: never;
|
|
221
224
|
post?: never;
|
|
222
225
|
delete?: never;
|
|
@@ -469,15 +472,6 @@ export interface components {
|
|
|
469
472
|
status: components["schemas"]["MaintenanceStatus"];
|
|
470
473
|
title: string;
|
|
471
474
|
};
|
|
472
|
-
AttachmentDownloadResource: {
|
|
473
|
-
/**
|
|
474
|
-
* Format: date-time
|
|
475
|
-
* @description After this moment the address stops working; request a new one
|
|
476
|
-
*/
|
|
477
|
-
expires_at: string;
|
|
478
|
-
/** @description A temporary address serving the file */
|
|
479
|
-
url: string;
|
|
480
|
-
};
|
|
481
475
|
CreateTicketRequestBody: {
|
|
482
476
|
/** @description Attachments to reference from the first message. Each must have been uploaded in this project and not yet referenced */
|
|
483
477
|
attachment_ids?: string[];
|
|
@@ -940,9 +934,12 @@ export interface operations {
|
|
|
940
934
|
};
|
|
941
935
|
};
|
|
942
936
|
};
|
|
943
|
-
"
|
|
937
|
+
"download-attachment": {
|
|
944
938
|
parameters: {
|
|
945
|
-
query?:
|
|
939
|
+
query?: {
|
|
940
|
+
/** @description Render in the browser instead of downloading, where the content type allows it */
|
|
941
|
+
inline?: boolean;
|
|
942
|
+
};
|
|
946
943
|
header?: never;
|
|
947
944
|
path: {
|
|
948
945
|
attachmentId: string;
|
|
@@ -954,10 +951,12 @@ export interface operations {
|
|
|
954
951
|
/** @description OK */
|
|
955
952
|
200: {
|
|
956
953
|
headers: {
|
|
954
|
+
/** @description `inline` when the content type can be rendered safely and `inline` was asked for, `attachment` otherwise. Carries the original file name */
|
|
955
|
+
"Content-Disposition"?: string;
|
|
957
956
|
[name: string]: unknown;
|
|
958
957
|
};
|
|
959
958
|
content: {
|
|
960
|
-
"
|
|
959
|
+
"*/*": string;
|
|
961
960
|
};
|
|
962
961
|
};
|
|
963
962
|
/** @description Error */
|