@smartcrab/contracts-management 0.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/LICENSE +202 -0
- package/dist/api-keys.d.ts +251 -0
- package/dist/api-keys.js +78 -0
- package/dist/audit-events.d.ts +94 -0
- package/dist/audit-events.js +45 -0
- package/dist/billing.d.ts +30 -0
- package/dist/billing.js +30 -0
- package/dist/clients.d.ts +328 -0
- package/dist/clients.js +141 -0
- package/dist/common.d.ts +95 -0
- package/dist/common.js +99 -0
- package/dist/connections.d.ts +201 -0
- package/dist/connections.js +107 -0
- package/dist/domains.d.ts +167 -0
- package/dist/domains.js +74 -0
- package/dist/environments.d.ts +194 -0
- package/dist/environments.js +101 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +27 -0
- package/dist/primitives.d.ts +49 -0
- package/dist/primitives.js +56 -0
- package/dist/projects.d.ts +78 -0
- package/dist/projects.js +49 -0
- package/dist/rbac.d.ts +222 -0
- package/dist/rbac.js +226 -0
- package/dist/usage.d.ts +72 -0
- package/dist/usage.js +52 -0
- package/dist/user-jobs.d.ts +253 -0
- package/dist/user-jobs.js +95 -0
- package/dist/user-subresources.d.ts +161 -0
- package/dist/user-subresources.js +85 -0
- package/dist/users.d.ts +193 -0
- package/dist/users.js +112 -0
- package/dist/webhooks.d.ts +306 -0
- package/dist/webhooks.js +134 -0
- package/dist/workspaces.d.ts +172 -0
- package/dist/workspaces.js +77 -0
- package/package.json +42 -0
- package/src/api-keys.test.ts +86 -0
- package/src/api-keys.ts +97 -0
- package/src/audit-events.test.ts +44 -0
- package/src/audit-events.ts +57 -0
- package/src/billing.test.ts +57 -0
- package/src/billing.ts +46 -0
- package/src/clients.test.ts +169 -0
- package/src/clients.ts +182 -0
- package/src/common.test.ts +102 -0
- package/src/common.ts +127 -0
- package/src/connections.test.ts +65 -0
- package/src/connections.ts +134 -0
- package/src/domains.test.ts +48 -0
- package/src/domains.ts +104 -0
- package/src/environments.test.ts +67 -0
- package/src/environments.ts +133 -0
- package/src/index.ts +27 -0
- package/src/primitives.ts +100 -0
- package/src/projects.test.ts +49 -0
- package/src/projects.ts +72 -0
- package/src/rbac.test.ts +148 -0
- package/src/rbac.ts +250 -0
- package/src/secret-fields.test.ts +84 -0
- package/src/usage.test.ts +57 -0
- package/src/usage.ts +66 -0
- package/src/user-jobs.test.ts +86 -0
- package/src/user-jobs.ts +120 -0
- package/src/user-subresources.test.ts +115 -0
- package/src/user-subresources.ts +128 -0
- package/src/users.test.ts +91 -0
- package/src/users.ts +149 -0
- package/src/webhooks.test.ts +187 -0
- package/src/webhooks.ts +182 -0
- package/src/workspaces.test.ts +127 -0
- package/src/workspaces.ts +106 -0
package/dist/common.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Common Management API envelope conventions (design.md §26.3):
|
|
4
|
+
*
|
|
5
|
+
* - cursor pagination, max page size 100
|
|
6
|
+
* - write APIs support `Idempotency-Key`
|
|
7
|
+
* - updates support ETag / `If-Match`
|
|
8
|
+
* - a Request ID is attached to every response
|
|
9
|
+
* - errors are returned as RFC 9457 Problem Details
|
|
10
|
+
*
|
|
11
|
+
* `request_id`: design.md §26.3's Problem Details example embeds
|
|
12
|
+
* `request_id` inside the error body. For success responses this package
|
|
13
|
+
* does not duplicate `request_id` into every resource/list schema — doing so
|
|
14
|
+
* would force every list item and every nested object to carry a redundant
|
|
15
|
+
* copy. Instead, success responses attach it the same way
|
|
16
|
+
* `@smartcrab/result`'s `problemDetailsResponse` already does for errors:
|
|
17
|
+
* an `X-Request-Id` response header (`requestIdHeaderSchema` below). Routes
|
|
18
|
+
* that need the id in the JSON body too may extend a resource schema with
|
|
19
|
+
* `problemDetailsSchema`'s `request_id` field; the header is the one
|
|
20
|
+
* guarantee this package encodes as "attached to all responses".
|
|
21
|
+
*/
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Pagination (design.md §26.3: "cursor pagination", "最大page size 100")
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export const DEFAULT_PAGE_SIZE = 25;
|
|
26
|
+
export const MAX_PAGE_SIZE = 100;
|
|
27
|
+
/**
|
|
28
|
+
* Query parameters shared by every `GET` list route. `limit` is coerced from
|
|
29
|
+
* its wire representation (a query string) to a number so callers can parse
|
|
30
|
+
* `URLSearchParams` values directly.
|
|
31
|
+
*/
|
|
32
|
+
export const paginationQuerySchema = z.object({
|
|
33
|
+
cursor: z.string().min(1).max(2048).optional(),
|
|
34
|
+
limit: z.coerce.number().int().min(1).max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE),
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Generic cursor-paginated list envelope: `{ items, next_cursor }`.
|
|
38
|
+
* `next_cursor` is `null` once the caller has reached the last page.
|
|
39
|
+
*/
|
|
40
|
+
export const cursorPageSchema = (itemSchema) => z.strictObject({
|
|
41
|
+
items: z.array(itemSchema),
|
|
42
|
+
next_cursor: z.string().min(1).nullable(),
|
|
43
|
+
});
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Idempotency-Key (design.md §26.3: "write APIは`Idempotency-Key`対応")
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
export const idempotencyKeySchema = z.string().min(1).max(255);
|
|
48
|
+
/** Header carried by every `POST`/`PATCH`/`DELETE` write request. */
|
|
49
|
+
export const idempotencyKeyHeaderSchema = z.strictObject({
|
|
50
|
+
"idempotency-key": idempotencyKeySchema,
|
|
51
|
+
});
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// ETag / If-Match (design.md §26.3: "updateはETag / `If-Match`対応")
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/** An opaque entity tag, optionally weak (`W/"..."`) or quoted per RFC 9110 §8.8.3. */
|
|
56
|
+
export const etagSchema = z.string().min(1).max(512);
|
|
57
|
+
/** Header carried by every conditional `PATCH`/`DELETE` request. */
|
|
58
|
+
export const ifMatchHeaderSchema = z.strictObject({
|
|
59
|
+
"if-match": etagSchema,
|
|
60
|
+
});
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Request ID (design.md §26.3: "Request IDを全レスポンスへ付与")
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/** `req_...` (design.md §7.5 / `@smartcrab/identifiers` `ID_PREFIXES.request`). */
|
|
65
|
+
export const requestIdSchema = z.string().regex(/^req_[a-z2-7]{32}$/);
|
|
66
|
+
export const requestIdHeaderSchema = z.strictObject({
|
|
67
|
+
"x-request-id": requestIdSchema,
|
|
68
|
+
});
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Problem Details (design.md §26.3, RFC 9457)
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Matches `@smartcrab/result`'s `ProblemDetails` interface shape exactly
|
|
74
|
+
* (this package does not import `@smartcrab/result`, per assignment
|
|
75
|
+
* rules, so the shape is redefined here as a zod schema for request/response
|
|
76
|
+
* contract validation rather than reused as a TS type).
|
|
77
|
+
*
|
|
78
|
+
* ```json
|
|
79
|
+
* {
|
|
80
|
+
* "type": "https://docs.example-auth.com/errors/invalid-redirect-uri",
|
|
81
|
+
* "title": "Invalid redirect URI",
|
|
82
|
+
* "status": 400,
|
|
83
|
+
* "detail": "The redirect URI is not registered for this client.",
|
|
84
|
+
* "code": "invalid_redirect_uri",
|
|
85
|
+
* "request_id": "req_xxx"
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* Deliberately NOT `z.strictObject`: RFC 9457 explicitly allows arbitrary
|
|
90
|
+
* extension members alongside the standard ones.
|
|
91
|
+
*/
|
|
92
|
+
export const problemDetailsSchema = z.object({
|
|
93
|
+
type: z.string().min(1),
|
|
94
|
+
title: z.string().min(1),
|
|
95
|
+
status: z.number().int().min(100).max(599),
|
|
96
|
+
detail: z.string().optional(),
|
|
97
|
+
code: z.string().optional(),
|
|
98
|
+
request_id: requestIdSchema.optional(),
|
|
99
|
+
});
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `provider_connections` (design.md §11.10, §20). `secret_ciphertext`,
|
|
4
|
+
* `secret_iv`, and `secret_key_version` are excluded: the first two per the
|
|
5
|
+
* assignment's forbidden-field list, the third as the internal encryption
|
|
6
|
+
* key-rotation generation for those ciphertexts — the same "internal
|
|
7
|
+
* routing/security machinery" category, not a resource attribute a
|
|
8
|
+
* dashboard/API consumer needs.
|
|
9
|
+
*
|
|
10
|
+
* The provider's own OAuth `client_id` (design.md §11.10's `client_id`
|
|
11
|
+
* column) is renamed here to `provider_client_id` to avoid colliding with
|
|
12
|
+
* this platform's own `Client` resource (`clients.id`, §11.5) — the two are
|
|
13
|
+
* unrelated identifiers that happen to share a column name in the schema.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CONNECTION_MODES: readonly ["managed", "byo"];
|
|
16
|
+
export declare const connectionModeSchema: z.ZodEnum<{
|
|
17
|
+
managed: "managed";
|
|
18
|
+
byo: "byo";
|
|
19
|
+
}>;
|
|
20
|
+
export type ConnectionMode = (typeof CONNECTION_MODES)[number];
|
|
21
|
+
export declare const CONNECTION_STATUSES: readonly ["active", "disabled"];
|
|
22
|
+
export declare const connectionStatusSchema: z.ZodEnum<{
|
|
23
|
+
active: "active";
|
|
24
|
+
disabled: "disabled";
|
|
25
|
+
}>;
|
|
26
|
+
export type ConnectionStatus = (typeof CONNECTION_STATUSES)[number];
|
|
27
|
+
export declare const connectionSchema: z.ZodObject<{
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
environment_id: z.ZodString;
|
|
30
|
+
provider: z.ZodEnum<{
|
|
31
|
+
google: "google";
|
|
32
|
+
apple: "apple";
|
|
33
|
+
github: "github";
|
|
34
|
+
microsoft: "microsoft";
|
|
35
|
+
generic_oidc: "generic_oidc";
|
|
36
|
+
}>;
|
|
37
|
+
mode: z.ZodEnum<{
|
|
38
|
+
managed: "managed";
|
|
39
|
+
byo: "byo";
|
|
40
|
+
}>;
|
|
41
|
+
provider_key: z.ZodString;
|
|
42
|
+
issuer: z.ZodNullable<z.ZodURL>;
|
|
43
|
+
provider_client_id: z.ZodString;
|
|
44
|
+
scopes: z.ZodArray<z.ZodString>;
|
|
45
|
+
profile_mapping: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
46
|
+
status: z.ZodEnum<{
|
|
47
|
+
active: "active";
|
|
48
|
+
disabled: "disabled";
|
|
49
|
+
}>;
|
|
50
|
+
owner_confirmed: z.ZodBoolean;
|
|
51
|
+
created_at: z.ZodISODateTime;
|
|
52
|
+
updated_at: z.ZodISODateTime;
|
|
53
|
+
}, z.core.$strict>;
|
|
54
|
+
export type Connection = z.infer<typeof connectionSchema>;
|
|
55
|
+
export declare const connectionListQuerySchema: z.ZodObject<{
|
|
56
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
57
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
58
|
+
environment_id: z.ZodString;
|
|
59
|
+
provider: z.ZodOptional<z.ZodEnum<{
|
|
60
|
+
google: "google";
|
|
61
|
+
apple: "apple";
|
|
62
|
+
github: "github";
|
|
63
|
+
microsoft: "microsoft";
|
|
64
|
+
generic_oidc: "generic_oidc";
|
|
65
|
+
}>>;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
export type ConnectionListQuery = z.infer<typeof connectionListQuerySchema>;
|
|
68
|
+
export declare const connectionListResponseSchema: z.ZodObject<{
|
|
69
|
+
items: z.ZodArray<z.ZodObject<{
|
|
70
|
+
id: z.ZodString;
|
|
71
|
+
environment_id: z.ZodString;
|
|
72
|
+
provider: z.ZodEnum<{
|
|
73
|
+
google: "google";
|
|
74
|
+
apple: "apple";
|
|
75
|
+
github: "github";
|
|
76
|
+
microsoft: "microsoft";
|
|
77
|
+
generic_oidc: "generic_oidc";
|
|
78
|
+
}>;
|
|
79
|
+
mode: z.ZodEnum<{
|
|
80
|
+
managed: "managed";
|
|
81
|
+
byo: "byo";
|
|
82
|
+
}>;
|
|
83
|
+
provider_key: z.ZodString;
|
|
84
|
+
issuer: z.ZodNullable<z.ZodURL>;
|
|
85
|
+
provider_client_id: z.ZodString;
|
|
86
|
+
scopes: z.ZodArray<z.ZodString>;
|
|
87
|
+
profile_mapping: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
88
|
+
status: z.ZodEnum<{
|
|
89
|
+
active: "active";
|
|
90
|
+
disabled: "disabled";
|
|
91
|
+
}>;
|
|
92
|
+
owner_confirmed: z.ZodBoolean;
|
|
93
|
+
created_at: z.ZodISODateTime;
|
|
94
|
+
updated_at: z.ZodISODateTime;
|
|
95
|
+
}, z.core.$strict>>;
|
|
96
|
+
next_cursor: z.ZodNullable<z.ZodString>;
|
|
97
|
+
}, z.core.$strict>;
|
|
98
|
+
export type ConnectionListResponse = z.infer<typeof connectionListResponseSchema>;
|
|
99
|
+
/**
|
|
100
|
+
* `provider_client_secret` is write-only: it is the plaintext OAuth client
|
|
101
|
+
* secret issued by the upstream provider (§20.4 "Secret暗号化" — the server
|
|
102
|
+
* encrypts it into `secret_ciphertext` before persisting). Unlike the
|
|
103
|
+
* platform-generated client/webhook/API-key secrets, this value is supplied
|
|
104
|
+
* by the caller, not generated by the server, so it never appears in any
|
|
105
|
+
* response, not even a one-time-display response.
|
|
106
|
+
*/
|
|
107
|
+
export declare const connectionCreateRequestSchema: z.ZodObject<{
|
|
108
|
+
environment_id: z.ZodString;
|
|
109
|
+
provider: z.ZodEnum<{
|
|
110
|
+
google: "google";
|
|
111
|
+
apple: "apple";
|
|
112
|
+
github: "github";
|
|
113
|
+
microsoft: "microsoft";
|
|
114
|
+
generic_oidc: "generic_oidc";
|
|
115
|
+
}>;
|
|
116
|
+
mode: z.ZodEnum<{
|
|
117
|
+
managed: "managed";
|
|
118
|
+
byo: "byo";
|
|
119
|
+
}>;
|
|
120
|
+
provider_key: z.ZodString;
|
|
121
|
+
issuer: z.ZodOptional<z.ZodURL>;
|
|
122
|
+
provider_client_id: z.ZodString;
|
|
123
|
+
provider_client_secret: z.ZodString;
|
|
124
|
+
scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
125
|
+
profile_mapping: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
126
|
+
}, z.core.$strict>;
|
|
127
|
+
export type ConnectionCreateRequest = z.infer<typeof connectionCreateRequestSchema>;
|
|
128
|
+
export declare const connectionCreateResponseSchema: z.ZodObject<{
|
|
129
|
+
id: z.ZodString;
|
|
130
|
+
environment_id: z.ZodString;
|
|
131
|
+
provider: z.ZodEnum<{
|
|
132
|
+
google: "google";
|
|
133
|
+
apple: "apple";
|
|
134
|
+
github: "github";
|
|
135
|
+
microsoft: "microsoft";
|
|
136
|
+
generic_oidc: "generic_oidc";
|
|
137
|
+
}>;
|
|
138
|
+
mode: z.ZodEnum<{
|
|
139
|
+
managed: "managed";
|
|
140
|
+
byo: "byo";
|
|
141
|
+
}>;
|
|
142
|
+
provider_key: z.ZodString;
|
|
143
|
+
issuer: z.ZodNullable<z.ZodURL>;
|
|
144
|
+
provider_client_id: z.ZodString;
|
|
145
|
+
scopes: z.ZodArray<z.ZodString>;
|
|
146
|
+
profile_mapping: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
147
|
+
status: z.ZodEnum<{
|
|
148
|
+
active: "active";
|
|
149
|
+
disabled: "disabled";
|
|
150
|
+
}>;
|
|
151
|
+
owner_confirmed: z.ZodBoolean;
|
|
152
|
+
created_at: z.ZodISODateTime;
|
|
153
|
+
updated_at: z.ZodISODateTime;
|
|
154
|
+
}, z.core.$strict>;
|
|
155
|
+
export type ConnectionCreateResponse = z.infer<typeof connectionCreateResponseSchema>;
|
|
156
|
+
export declare const connectionUpdateRequestSchema: z.ZodObject<{
|
|
157
|
+
issuer: z.ZodOptional<z.ZodURL>;
|
|
158
|
+
provider_client_id: z.ZodOptional<z.ZodString>;
|
|
159
|
+
provider_client_secret: z.ZodOptional<z.ZodString>;
|
|
160
|
+
scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
161
|
+
profile_mapping: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
162
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
163
|
+
active: "active";
|
|
164
|
+
disabled: "disabled";
|
|
165
|
+
}>>;
|
|
166
|
+
owner_confirmed: z.ZodOptional<z.ZodBoolean>;
|
|
167
|
+
}, z.core.$strict>;
|
|
168
|
+
export type ConnectionUpdateRequest = z.infer<typeof connectionUpdateRequestSchema>;
|
|
169
|
+
export declare const connectionUpdateResponseSchema: z.ZodObject<{
|
|
170
|
+
id: z.ZodString;
|
|
171
|
+
environment_id: z.ZodString;
|
|
172
|
+
provider: z.ZodEnum<{
|
|
173
|
+
google: "google";
|
|
174
|
+
apple: "apple";
|
|
175
|
+
github: "github";
|
|
176
|
+
microsoft: "microsoft";
|
|
177
|
+
generic_oidc: "generic_oidc";
|
|
178
|
+
}>;
|
|
179
|
+
mode: z.ZodEnum<{
|
|
180
|
+
managed: "managed";
|
|
181
|
+
byo: "byo";
|
|
182
|
+
}>;
|
|
183
|
+
provider_key: z.ZodString;
|
|
184
|
+
issuer: z.ZodNullable<z.ZodURL>;
|
|
185
|
+
provider_client_id: z.ZodString;
|
|
186
|
+
scopes: z.ZodArray<z.ZodString>;
|
|
187
|
+
profile_mapping: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
188
|
+
status: z.ZodEnum<{
|
|
189
|
+
active: "active";
|
|
190
|
+
disabled: "disabled";
|
|
191
|
+
}>;
|
|
192
|
+
owner_confirmed: z.ZodBoolean;
|
|
193
|
+
created_at: z.ZodISODateTime;
|
|
194
|
+
updated_at: z.ZodISODateTime;
|
|
195
|
+
}, z.core.$strict>;
|
|
196
|
+
export type ConnectionUpdateResponse = z.infer<typeof connectionUpdateResponseSchema>;
|
|
197
|
+
export declare const connectionDeleteResponseSchema: z.ZodObject<{
|
|
198
|
+
id: z.ZodString;
|
|
199
|
+
deleted: z.ZodLiteral<true>;
|
|
200
|
+
}, z.core.$strict>;
|
|
201
|
+
export type ConnectionDeleteResponse = z.infer<typeof connectionDeleteResponseSchema>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { httpsUrlSchema, socialProviderSchema } from "@smartcrab/contracts-public";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { cursorPageSchema, paginationQuerySchema } from "./common.js";
|
|
4
|
+
import { connectionIdSchema, environmentIdSchema } from "./primitives.js";
|
|
5
|
+
/**
|
|
6
|
+
* `provider_connections` (design.md §11.10, §20). `secret_ciphertext`,
|
|
7
|
+
* `secret_iv`, and `secret_key_version` are excluded: the first two per the
|
|
8
|
+
* assignment's forbidden-field list, the third as the internal encryption
|
|
9
|
+
* key-rotation generation for those ciphertexts — the same "internal
|
|
10
|
+
* routing/security machinery" category, not a resource attribute a
|
|
11
|
+
* dashboard/API consumer needs.
|
|
12
|
+
*
|
|
13
|
+
* The provider's own OAuth `client_id` (design.md §11.10's `client_id`
|
|
14
|
+
* column) is renamed here to `provider_client_id` to avoid colliding with
|
|
15
|
+
* this platform's own `Client` resource (`clients.id`, §11.5) — the two are
|
|
16
|
+
* unrelated identifiers that happen to share a column name in the schema.
|
|
17
|
+
*/
|
|
18
|
+
export const CONNECTION_MODES = ["managed", "byo"];
|
|
19
|
+
export const connectionModeSchema = z.enum(CONNECTION_MODES);
|
|
20
|
+
export const CONNECTION_STATUSES = ["active", "disabled"];
|
|
21
|
+
export const connectionStatusSchema = z.enum(CONNECTION_STATUSES);
|
|
22
|
+
/** A single non-whitespace OAuth scope token requested from the upstream provider. */
|
|
23
|
+
const providerScopeSchema = z.string().min(1).max(100).regex(/^\S+$/);
|
|
24
|
+
/** design.md §11.10 `provider_key`: distinguishes multiple connections of the same provider per environment. */
|
|
25
|
+
const providerKeySchema = z
|
|
26
|
+
.string()
|
|
27
|
+
.min(1)
|
|
28
|
+
.max(100)
|
|
29
|
+
.regex(/^[a-z0-9]+(?:[_-][a-z0-9]+)*$/);
|
|
30
|
+
/** Maps this platform's normalized profile fields to the provider's own claim/attribute names. */
|
|
31
|
+
const profileMappingSchema = z.record(z.string(), z.string());
|
|
32
|
+
export const connectionSchema = z.strictObject({
|
|
33
|
+
id: connectionIdSchema,
|
|
34
|
+
environment_id: environmentIdSchema,
|
|
35
|
+
provider: socialProviderSchema,
|
|
36
|
+
mode: connectionModeSchema,
|
|
37
|
+
provider_key: providerKeySchema,
|
|
38
|
+
/** Only meaningful for `provider: "generic_oidc"` (design.md §11.10 `issuer NULLABLE`). */
|
|
39
|
+
issuer: httpsUrlSchema.nullable(),
|
|
40
|
+
provider_client_id: z.string().min(1),
|
|
41
|
+
scopes: z.array(providerScopeSchema).max(20),
|
|
42
|
+
profile_mapping: profileMappingSchema,
|
|
43
|
+
status: connectionStatusSchema,
|
|
44
|
+
/**
|
|
45
|
+
* design.md §20.3: "Dashboard上で所有者が明示確認するまでConnectionを有効化
|
|
46
|
+
* しない" — a `generic_oidc` connection's owner-supplied issuer is a real
|
|
47
|
+
* SSRF surface, so it stays unusable until the Dashboard owner explicitly
|
|
48
|
+
* confirms it here. Always `true` for every other provider (nothing to
|
|
49
|
+
* confirm).
|
|
50
|
+
*/
|
|
51
|
+
owner_confirmed: z.boolean(),
|
|
52
|
+
created_at: z.iso.datetime(),
|
|
53
|
+
updated_at: z.iso.datetime(),
|
|
54
|
+
});
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// GET /connections
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
export const connectionListQuerySchema = paginationQuerySchema.extend({
|
|
59
|
+
environment_id: environmentIdSchema,
|
|
60
|
+
provider: socialProviderSchema.optional(),
|
|
61
|
+
});
|
|
62
|
+
export const connectionListResponseSchema = cursorPageSchema(connectionSchema);
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// POST /connections
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* `provider_client_secret` is write-only: it is the plaintext OAuth client
|
|
68
|
+
* secret issued by the upstream provider (§20.4 "Secret暗号化" — the server
|
|
69
|
+
* encrypts it into `secret_ciphertext` before persisting). Unlike the
|
|
70
|
+
* platform-generated client/webhook/API-key secrets, this value is supplied
|
|
71
|
+
* by the caller, not generated by the server, so it never appears in any
|
|
72
|
+
* response, not even a one-time-display response.
|
|
73
|
+
*/
|
|
74
|
+
export const connectionCreateRequestSchema = z.strictObject({
|
|
75
|
+
environment_id: environmentIdSchema,
|
|
76
|
+
provider: socialProviderSchema,
|
|
77
|
+
mode: connectionModeSchema,
|
|
78
|
+
provider_key: providerKeySchema,
|
|
79
|
+
issuer: httpsUrlSchema.optional(),
|
|
80
|
+
provider_client_id: z.string().min(1),
|
|
81
|
+
provider_client_secret: z.string().min(1),
|
|
82
|
+
scopes: z.array(providerScopeSchema).max(20).default([]),
|
|
83
|
+
profile_mapping: profileMappingSchema.default({}),
|
|
84
|
+
});
|
|
85
|
+
export const connectionCreateResponseSchema = connectionSchema;
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// PATCH /connections/:connectionId
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
export const connectionUpdateRequestSchema = z.strictObject({
|
|
90
|
+
issuer: httpsUrlSchema.optional(),
|
|
91
|
+
provider_client_id: z.string().min(1).optional(),
|
|
92
|
+
/** Write-only; omit to leave the stored secret unchanged. */
|
|
93
|
+
provider_client_secret: z.string().min(1).optional(),
|
|
94
|
+
scopes: z.array(providerScopeSchema).max(20).optional(),
|
|
95
|
+
profile_mapping: profileMappingSchema.optional(),
|
|
96
|
+
status: connectionStatusSchema.optional(),
|
|
97
|
+
/** design.md §20.3: the Dashboard owner's explicit confirmation step (only meaningful for `generic_oidc`; see `connectionSchema.owner_confirmed`). */
|
|
98
|
+
owner_confirmed: z.boolean().optional(),
|
|
99
|
+
});
|
|
100
|
+
export const connectionUpdateResponseSchema = connectionSchema;
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// DELETE /connections/:connectionId
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
export const connectionDeleteResponseSchema = z.strictObject({
|
|
105
|
+
id: connectionIdSchema,
|
|
106
|
+
deleted: z.literal(true),
|
|
107
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `custom_domains` (design.md §11.9, §8.2). `cloudflare_custom_hostname_id`
|
|
4
|
+
* is excluded: it is an internal pointer into the Cloudflare for SaaS API
|
|
5
|
+
* (the same "internal routing" category as the assignment's named
|
|
6
|
+
* `*_database_key`/`auth_partition_id` fields), not a customer-facing
|
|
7
|
+
* attribute — validation progress is fully described by `status` and
|
|
8
|
+
* `validation_errors` without it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CUSTOM_DOMAIN_STATUSES: readonly ["pending", "active", "moved", "failed", "deleting"];
|
|
11
|
+
export declare const customDomainStatusSchema: z.ZodEnum<{
|
|
12
|
+
failed: "failed";
|
|
13
|
+
active: "active";
|
|
14
|
+
pending: "pending";
|
|
15
|
+
moved: "moved";
|
|
16
|
+
deleting: "deleting";
|
|
17
|
+
}>;
|
|
18
|
+
export type CustomDomainStatus = (typeof CUSTOM_DOMAIN_STATUSES)[number];
|
|
19
|
+
/** Canonicalize a custom hostname at an external boundary before persistence or routing. */
|
|
20
|
+
export declare const canonicalizeCustomHostname: (hostname: string) => string;
|
|
21
|
+
export declare const domainSchema: z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
environment_id: z.ZodString;
|
|
24
|
+
hostname: z.ZodString;
|
|
25
|
+
status: z.ZodEnum<{
|
|
26
|
+
failed: "failed";
|
|
27
|
+
active: "active";
|
|
28
|
+
pending: "pending";
|
|
29
|
+
moved: "moved";
|
|
30
|
+
deleting: "deleting";
|
|
31
|
+
}>;
|
|
32
|
+
rp_enabled: z.ZodBoolean;
|
|
33
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
34
|
+
created_at: z.ZodISODateTime;
|
|
35
|
+
updated_at: z.ZodISODateTime;
|
|
36
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
export type Domain = z.infer<typeof domainSchema>;
|
|
39
|
+
export declare const domainListQuerySchema: z.ZodObject<{
|
|
40
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
41
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
42
|
+
environment_id: z.ZodString;
|
|
43
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
44
|
+
failed: "failed";
|
|
45
|
+
active: "active";
|
|
46
|
+
pending: "pending";
|
|
47
|
+
moved: "moved";
|
|
48
|
+
deleting: "deleting";
|
|
49
|
+
}>>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
export type DomainListQuery = z.infer<typeof domainListQuerySchema>;
|
|
52
|
+
export declare const domainListResponseSchema: z.ZodObject<{
|
|
53
|
+
items: z.ZodArray<z.ZodObject<{
|
|
54
|
+
id: z.ZodString;
|
|
55
|
+
environment_id: z.ZodString;
|
|
56
|
+
hostname: z.ZodString;
|
|
57
|
+
status: z.ZodEnum<{
|
|
58
|
+
failed: "failed";
|
|
59
|
+
active: "active";
|
|
60
|
+
pending: "pending";
|
|
61
|
+
moved: "moved";
|
|
62
|
+
deleting: "deleting";
|
|
63
|
+
}>;
|
|
64
|
+
rp_enabled: z.ZodBoolean;
|
|
65
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
66
|
+
created_at: z.ZodISODateTime;
|
|
67
|
+
updated_at: z.ZodISODateTime;
|
|
68
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
69
|
+
}, z.core.$strict>>;
|
|
70
|
+
next_cursor: z.ZodNullable<z.ZodString>;
|
|
71
|
+
}, z.core.$strict>;
|
|
72
|
+
export type DomainListResponse = z.infer<typeof domainListResponseSchema>;
|
|
73
|
+
export declare const domainCreateRequestSchema: z.ZodObject<{
|
|
74
|
+
environment_id: z.ZodString;
|
|
75
|
+
hostname: z.ZodString;
|
|
76
|
+
rp_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
77
|
+
}, z.core.$strict>;
|
|
78
|
+
export type DomainCreateRequest = z.infer<typeof domainCreateRequestSchema>;
|
|
79
|
+
/** A freshly created domain always starts `pending` validation (design.md §11.9). */
|
|
80
|
+
export declare const domainCreateResponseSchema: z.ZodObject<{
|
|
81
|
+
id: z.ZodString;
|
|
82
|
+
environment_id: z.ZodString;
|
|
83
|
+
hostname: z.ZodString;
|
|
84
|
+
status: z.ZodEnum<{
|
|
85
|
+
failed: "failed";
|
|
86
|
+
active: "active";
|
|
87
|
+
pending: "pending";
|
|
88
|
+
moved: "moved";
|
|
89
|
+
deleting: "deleting";
|
|
90
|
+
}>;
|
|
91
|
+
rp_enabled: z.ZodBoolean;
|
|
92
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
93
|
+
created_at: z.ZodISODateTime;
|
|
94
|
+
updated_at: z.ZodISODateTime;
|
|
95
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
96
|
+
}, z.core.$strict>;
|
|
97
|
+
export type DomainCreateResponse = z.infer<typeof domainCreateResponseSchema>;
|
|
98
|
+
export declare const domainGetResponseSchema: z.ZodObject<{
|
|
99
|
+
id: z.ZodString;
|
|
100
|
+
environment_id: z.ZodString;
|
|
101
|
+
hostname: z.ZodString;
|
|
102
|
+
status: z.ZodEnum<{
|
|
103
|
+
failed: "failed";
|
|
104
|
+
active: "active";
|
|
105
|
+
pending: "pending";
|
|
106
|
+
moved: "moved";
|
|
107
|
+
deleting: "deleting";
|
|
108
|
+
}>;
|
|
109
|
+
rp_enabled: z.ZodBoolean;
|
|
110
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
111
|
+
created_at: z.ZodISODateTime;
|
|
112
|
+
updated_at: z.ZodISODateTime;
|
|
113
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
114
|
+
}, z.core.$strict>;
|
|
115
|
+
export type DomainGetResponse = z.infer<typeof domainGetResponseSchema>;
|
|
116
|
+
export declare const domainDeleteResponseSchema: z.ZodObject<{
|
|
117
|
+
id: z.ZodString;
|
|
118
|
+
deleted: z.ZodLiteral<true>;
|
|
119
|
+
}, z.core.$strict>;
|
|
120
|
+
export type DomainDeleteResponse = z.infer<typeof domainDeleteResponseSchema>;
|
|
121
|
+
/**
|
|
122
|
+
* design.md §8.3: `rp_enabled` switches both the WebAuthn RP ID and the hosted
|
|
123
|
+
* Interaction Domain to this custom domain. At most one per Environment.
|
|
124
|
+
*/
|
|
125
|
+
export declare const domainUpdateRequestSchema: z.ZodObject<{
|
|
126
|
+
rp_enabled: z.ZodBoolean;
|
|
127
|
+
}, z.core.$strict>;
|
|
128
|
+
export type DomainUpdateRequest = z.infer<typeof domainUpdateRequestSchema>;
|
|
129
|
+
export declare const domainUpdateResponseSchema: z.ZodObject<{
|
|
130
|
+
id: z.ZodString;
|
|
131
|
+
environment_id: z.ZodString;
|
|
132
|
+
hostname: z.ZodString;
|
|
133
|
+
status: z.ZodEnum<{
|
|
134
|
+
failed: "failed";
|
|
135
|
+
active: "active";
|
|
136
|
+
pending: "pending";
|
|
137
|
+
moved: "moved";
|
|
138
|
+
deleting: "deleting";
|
|
139
|
+
}>;
|
|
140
|
+
rp_enabled: z.ZodBoolean;
|
|
141
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
142
|
+
created_at: z.ZodISODateTime;
|
|
143
|
+
updated_at: z.ZodISODateTime;
|
|
144
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
145
|
+
}, z.core.$strict>;
|
|
146
|
+
export type DomainUpdateResponse = z.infer<typeof domainUpdateResponseSchema>;
|
|
147
|
+
export declare const domainRetryValidationRequestSchema: z.ZodObject<{}, z.core.$strict>;
|
|
148
|
+
export type DomainRetryValidationRequest = z.infer<typeof domainRetryValidationRequestSchema>;
|
|
149
|
+
/** Retrying resets `status` to `pending` and clears prior `validation_errors`. */
|
|
150
|
+
export declare const domainRetryValidationResponseSchema: z.ZodObject<{
|
|
151
|
+
id: z.ZodString;
|
|
152
|
+
environment_id: z.ZodString;
|
|
153
|
+
hostname: z.ZodString;
|
|
154
|
+
status: z.ZodEnum<{
|
|
155
|
+
failed: "failed";
|
|
156
|
+
active: "active";
|
|
157
|
+
pending: "pending";
|
|
158
|
+
moved: "moved";
|
|
159
|
+
deleting: "deleting";
|
|
160
|
+
}>;
|
|
161
|
+
rp_enabled: z.ZodBoolean;
|
|
162
|
+
validation_errors: z.ZodArray<z.ZodString>;
|
|
163
|
+
created_at: z.ZodISODateTime;
|
|
164
|
+
updated_at: z.ZodISODateTime;
|
|
165
|
+
activated_at: z.ZodNullable<z.ZodISODateTime>;
|
|
166
|
+
}, z.core.$strict>;
|
|
167
|
+
export type DomainRetryValidationResponse = z.infer<typeof domainRetryValidationResponseSchema>;
|
package/dist/domains.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { cursorPageSchema, paginationQuerySchema } from "./common.js";
|
|
3
|
+
import { domainIdSchema, environmentIdSchema } from "./primitives.js";
|
|
4
|
+
/**
|
|
5
|
+
* `custom_domains` (design.md §11.9, §8.2). `cloudflare_custom_hostname_id`
|
|
6
|
+
* is excluded: it is an internal pointer into the Cloudflare for SaaS API
|
|
7
|
+
* (the same "internal routing" category as the assignment's named
|
|
8
|
+
* `*_database_key`/`auth_partition_id` fields), not a customer-facing
|
|
9
|
+
* attribute — validation progress is fully described by `status` and
|
|
10
|
+
* `validation_errors` without it.
|
|
11
|
+
*/
|
|
12
|
+
export const CUSTOM_DOMAIN_STATUSES = ["pending", "active", "moved", "failed", "deleting"];
|
|
13
|
+
export const customDomainStatusSchema = z.enum(CUSTOM_DOMAIN_STATUSES);
|
|
14
|
+
const customHostnameSchema = z.string().min(1).max(253);
|
|
15
|
+
/** Canonicalize a custom hostname at an external boundary before persistence or routing. */
|
|
16
|
+
export const canonicalizeCustomHostname = (hostname) => hostname.toLowerCase();
|
|
17
|
+
export const domainSchema = z.strictObject({
|
|
18
|
+
id: domainIdSchema,
|
|
19
|
+
environment_id: environmentIdSchema,
|
|
20
|
+
hostname: customHostnameSchema,
|
|
21
|
+
status: customDomainStatusSchema,
|
|
22
|
+
/** design.md §11.9: whether this custom domain also serves as the WebAuthn RP ID host. */
|
|
23
|
+
rp_enabled: z.boolean(),
|
|
24
|
+
validation_errors: z.array(z.string().min(1)),
|
|
25
|
+
created_at: z.iso.datetime(),
|
|
26
|
+
updated_at: z.iso.datetime(),
|
|
27
|
+
activated_at: z.iso.datetime().nullable(),
|
|
28
|
+
});
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// GET /domains
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
export const domainListQuerySchema = paginationQuerySchema.extend({
|
|
33
|
+
environment_id: environmentIdSchema,
|
|
34
|
+
status: customDomainStatusSchema.optional(),
|
|
35
|
+
});
|
|
36
|
+
export const domainListResponseSchema = cursorPageSchema(domainSchema);
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// POST /domains
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
export const domainCreateRequestSchema = z.strictObject({
|
|
41
|
+
environment_id: environmentIdSchema,
|
|
42
|
+
hostname: customHostnameSchema,
|
|
43
|
+
rp_enabled: z.boolean().default(false),
|
|
44
|
+
});
|
|
45
|
+
/** A freshly created domain always starts `pending` validation (design.md §11.9). */
|
|
46
|
+
export const domainCreateResponseSchema = domainSchema;
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// GET /domains/:domainId
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
export const domainGetResponseSchema = domainSchema;
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// DELETE /domains/:domainId
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
export const domainDeleteResponseSchema = z.strictObject({
|
|
55
|
+
id: domainIdSchema,
|
|
56
|
+
deleted: z.literal(true),
|
|
57
|
+
});
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// PATCH /domains/:domainId
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* design.md §8.3: `rp_enabled` switches both the WebAuthn RP ID and the hosted
|
|
63
|
+
* Interaction Domain to this custom domain. At most one per Environment.
|
|
64
|
+
*/
|
|
65
|
+
export const domainUpdateRequestSchema = z.strictObject({
|
|
66
|
+
rp_enabled: z.boolean(),
|
|
67
|
+
});
|
|
68
|
+
export const domainUpdateResponseSchema = domainSchema;
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// POST /domains/:domainId/retry-validation
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
export const domainRetryValidationRequestSchema = z.strictObject({});
|
|
73
|
+
/** Retrying resets `status` to `pending` and clears prior `validation_errors`. */
|
|
74
|
+
export const domainRetryValidationResponseSchema = domainSchema;
|