@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.
Files changed (73) hide show
  1. package/LICENSE +202 -0
  2. package/dist/api-keys.d.ts +251 -0
  3. package/dist/api-keys.js +78 -0
  4. package/dist/audit-events.d.ts +94 -0
  5. package/dist/audit-events.js +45 -0
  6. package/dist/billing.d.ts +30 -0
  7. package/dist/billing.js +30 -0
  8. package/dist/clients.d.ts +328 -0
  9. package/dist/clients.js +141 -0
  10. package/dist/common.d.ts +95 -0
  11. package/dist/common.js +99 -0
  12. package/dist/connections.d.ts +201 -0
  13. package/dist/connections.js +107 -0
  14. package/dist/domains.d.ts +167 -0
  15. package/dist/domains.js +74 -0
  16. package/dist/environments.d.ts +194 -0
  17. package/dist/environments.js +101 -0
  18. package/dist/index.d.ts +27 -0
  19. package/dist/index.js +27 -0
  20. package/dist/primitives.d.ts +49 -0
  21. package/dist/primitives.js +56 -0
  22. package/dist/projects.d.ts +78 -0
  23. package/dist/projects.js +49 -0
  24. package/dist/rbac.d.ts +222 -0
  25. package/dist/rbac.js +226 -0
  26. package/dist/usage.d.ts +72 -0
  27. package/dist/usage.js +52 -0
  28. package/dist/user-jobs.d.ts +253 -0
  29. package/dist/user-jobs.js +95 -0
  30. package/dist/user-subresources.d.ts +161 -0
  31. package/dist/user-subresources.js +85 -0
  32. package/dist/users.d.ts +193 -0
  33. package/dist/users.js +112 -0
  34. package/dist/webhooks.d.ts +306 -0
  35. package/dist/webhooks.js +134 -0
  36. package/dist/workspaces.d.ts +172 -0
  37. package/dist/workspaces.js +77 -0
  38. package/package.json +42 -0
  39. package/src/api-keys.test.ts +86 -0
  40. package/src/api-keys.ts +97 -0
  41. package/src/audit-events.test.ts +44 -0
  42. package/src/audit-events.ts +57 -0
  43. package/src/billing.test.ts +57 -0
  44. package/src/billing.ts +46 -0
  45. package/src/clients.test.ts +169 -0
  46. package/src/clients.ts +182 -0
  47. package/src/common.test.ts +102 -0
  48. package/src/common.ts +127 -0
  49. package/src/connections.test.ts +65 -0
  50. package/src/connections.ts +134 -0
  51. package/src/domains.test.ts +48 -0
  52. package/src/domains.ts +104 -0
  53. package/src/environments.test.ts +67 -0
  54. package/src/environments.ts +133 -0
  55. package/src/index.ts +27 -0
  56. package/src/primitives.ts +100 -0
  57. package/src/projects.test.ts +49 -0
  58. package/src/projects.ts +72 -0
  59. package/src/rbac.test.ts +148 -0
  60. package/src/rbac.ts +250 -0
  61. package/src/secret-fields.test.ts +84 -0
  62. package/src/usage.test.ts +57 -0
  63. package/src/usage.ts +66 -0
  64. package/src/user-jobs.test.ts +86 -0
  65. package/src/user-jobs.ts +120 -0
  66. package/src/user-subresources.test.ts +115 -0
  67. package/src/user-subresources.ts +128 -0
  68. package/src/users.test.ts +91 -0
  69. package/src/users.ts +149 -0
  70. package/src/webhooks.test.ts +187 -0
  71. package/src/webhooks.ts +182 -0
  72. package/src/workspaces.test.ts +127 -0
  73. package/src/workspaces.ts +106 -0
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ import { cursorPageSchema, paginationQuerySchema, requestIdSchema } from "./common.js";
3
+ import { auditEventIdSchema, environmentIdSchema, workspaceIdSchema } from "./primitives.js";
4
+ /**
5
+ * `audit_events` (design.md §12.11), read-only (`GET /audit-events` is the
6
+ * only route; design.md §12.11: "監査ログは追記専用とし、通常APIから更新・
7
+ * 削除できない"). `auth_partition_id` is excluded per the assignment's
8
+ * forbidden-field list (internal Auth D1 co-location routing).
9
+ * `ip_prefix_hash` is excluded for the same reason `@smartcrab/contracts-public`
10
+ * excludes hash-only columns from any response: an irreversible hash is not
11
+ * a usable value for an API consumer.
12
+ */
13
+ export const AUDIT_ACTOR_TYPES = ["end_user", "workspace_member", "api_key", "system"];
14
+ export const auditActorTypeSchema = z.enum(AUDIT_ACTOR_TYPES);
15
+ export const AUDIT_RESULTS = ["success", "failure"];
16
+ export const auditResultSchema = z.enum(AUDIT_RESULTS);
17
+ const auditMetadataSchema = z.record(z.string(), z.unknown());
18
+ export const auditEventSchema = z.strictObject({
19
+ id: auditEventIdSchema,
20
+ environment_id: environmentIdSchema,
21
+ workspace_id: workspaceIdSchema,
22
+ actor_type: auditActorTypeSchema,
23
+ actor_id: z.string().min(1).nullable(),
24
+ action: z.string().min(1),
25
+ subject_type: z.string().min(1),
26
+ subject_id: z.string().min(1).nullable(),
27
+ result: auditResultSchema,
28
+ request_id: requestIdSchema,
29
+ metadata: auditMetadataSchema,
30
+ created_at: z.iso.datetime(),
31
+ });
32
+ // ---------------------------------------------------------------------------
33
+ // GET /audit-events
34
+ // ---------------------------------------------------------------------------
35
+ export const auditEventListQuerySchema = paginationQuerySchema.extend({
36
+ environment_id: environmentIdSchema,
37
+ actor_type: auditActorTypeSchema.optional(),
38
+ action: z.string().min(1).optional(),
39
+ subject_type: z.string().min(1).optional(),
40
+ subject_id: z.string().min(1).optional(),
41
+ result: auditResultSchema.optional(),
42
+ created_after: z.iso.datetime().optional(),
43
+ created_before: z.iso.datetime().optional(),
44
+ });
45
+ export const auditEventListResponseSchema = cursorPageSchema(auditEventSchema);
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * `POST /billing/checkout-session`, `POST /billing/portal-session`
4
+ * (design.md §26.2, §28.5: "30,000 MAUを超えて継続利用するにはStripe
5
+ * Customer、Subscription、Payment Methodを有効化する"). design.md does not
6
+ * give an exact JSON shape for these two routes; the request/response
7
+ * fields below are the minimum Stripe Checkout/Billing Portal session
8
+ * creation requires (a return destination in, a redirect URL out) and
9
+ * intentionally surface no Stripe object IDs — this package never exposes
10
+ * `billing_accounts`' Stripe identifiers (design.md §11.14) through these
11
+ * routes, only the redirect URL the dashboard needs.
12
+ */
13
+ export declare const billingCheckoutSessionCreateRequestSchema: z.ZodObject<{
14
+ success_url: z.ZodURL;
15
+ cancel_url: z.ZodURL;
16
+ }, z.core.$strict>;
17
+ export type BillingCheckoutSessionCreateRequest = z.infer<typeof billingCheckoutSessionCreateRequestSchema>;
18
+ export declare const billingCheckoutSessionCreateResponseSchema: z.ZodObject<{
19
+ checkout_url: z.ZodURL;
20
+ expires_at: z.ZodISODateTime;
21
+ }, z.core.$strict>;
22
+ export type BillingCheckoutSessionCreateResponse = z.infer<typeof billingCheckoutSessionCreateResponseSchema>;
23
+ export declare const billingPortalSessionCreateRequestSchema: z.ZodObject<{
24
+ return_url: z.ZodURL;
25
+ }, z.core.$strict>;
26
+ export type BillingPortalSessionCreateRequest = z.infer<typeof billingPortalSessionCreateRequestSchema>;
27
+ export declare const billingPortalSessionCreateResponseSchema: z.ZodObject<{
28
+ portal_url: z.ZodURL;
29
+ }, z.core.$strict>;
30
+ export type BillingPortalSessionCreateResponse = z.infer<typeof billingPortalSessionCreateResponseSchema>;
@@ -0,0 +1,30 @@
1
+ import { httpsUrlSchema } from "@smartcrab/contracts-public";
2
+ import { z } from "zod";
3
+ /**
4
+ * `POST /billing/checkout-session`, `POST /billing/portal-session`
5
+ * (design.md §26.2, §28.5: "30,000 MAUを超えて継続利用するにはStripe
6
+ * Customer、Subscription、Payment Methodを有効化する"). design.md does not
7
+ * give an exact JSON shape for these two routes; the request/response
8
+ * fields below are the minimum Stripe Checkout/Billing Portal session
9
+ * creation requires (a return destination in, a redirect URL out) and
10
+ * intentionally surface no Stripe object IDs — this package never exposes
11
+ * `billing_accounts`' Stripe identifiers (design.md §11.14) through these
12
+ * routes, only the redirect URL the dashboard needs.
13
+ */
14
+ export const billingCheckoutSessionCreateRequestSchema = z.strictObject({
15
+ /** Where Stripe Checkout redirects on success. */
16
+ success_url: httpsUrlSchema,
17
+ /** Where Stripe Checkout redirects if the workspace member cancels. */
18
+ cancel_url: httpsUrlSchema,
19
+ });
20
+ export const billingCheckoutSessionCreateResponseSchema = z.strictObject({
21
+ checkout_url: httpsUrlSchema,
22
+ expires_at: z.iso.datetime(),
23
+ });
24
+ export const billingPortalSessionCreateRequestSchema = z.strictObject({
25
+ /** Where the Stripe Billing Portal redirects when the member is done. */
26
+ return_url: httpsUrlSchema,
27
+ });
28
+ export const billingPortalSessionCreateResponseSchema = z.strictObject({
29
+ portal_url: httpsUrlSchema,
30
+ });
@@ -0,0 +1,328 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * `clients` (design.md §11.5), `client_redirect_uris` (§11.6),
4
+ * `client_origins` (§11.7), `mobile_apps` (§11.8) and the conceptual Client
5
+ * model of design.md §7.4 (which groups these tables' columns into one
6
+ * resource: `redirect_uris`, `post_logout_redirect_uris`, `allowed_origins`,
7
+ * `allowed_scopes`, `allowed_resources`).
8
+ *
9
+ * `secret_hash` (§11.5) is excluded per the assignment's secret-field rule;
10
+ * `public_key_prefix` is kept — it exists specifically so a non-secret
11
+ * fragment of client identity can be displayed (the same pattern as
12
+ * `management_api_keys.prefix` alongside its hidden `key_mac`, §11.12).
13
+ */
14
+ export declare const CLIENT_TYPES: readonly ["web_bff", "web_spa", "react_native"];
15
+ export declare const clientTypeSchema: z.ZodEnum<{
16
+ web_bff: "web_bff";
17
+ web_spa: "web_spa";
18
+ react_native: "react_native";
19
+ }>;
20
+ export type ClientType = (typeof CLIENT_TYPES)[number];
21
+ export declare const TOKEN_ENDPOINT_AUTH_METHODS: readonly ["none", "client_secret_basic", "client_secret_post"];
22
+ export declare const tokenEndpointAuthMethodSchema: z.ZodEnum<{
23
+ client_secret_basic: "client_secret_basic";
24
+ client_secret_post: "client_secret_post";
25
+ none: "none";
26
+ }>;
27
+ export type TokenEndpointAuthMethod = (typeof TOKEN_ENDPOINT_AUTH_METHODS)[number];
28
+ export declare const CLIENT_STATUSES: readonly ["active", "disabled"];
29
+ export declare const clientStatusSchema: z.ZodEnum<{
30
+ active: "active";
31
+ disabled: "disabled";
32
+ }>;
33
+ export type ClientStatus = (typeof CLIENT_STATUSES)[number];
34
+ /**
35
+ * design.md §11.8 `android_sha256_fingerprints_json`: colon-separated hex, 32
36
+ * bytes. Any case is accepted on the wire; the control-plane repository stores
37
+ * and serves the canonical uppercase form. Kept transform-free so the schema
38
+ * stays representable for OpenAPI generation (`z.toJSONSchema` with `io: "output"`).
39
+ */
40
+ export declare const androidSha256FingerprintSchema: z.ZodString;
41
+ /** design.md §11.8 `android_package_name`: reversed-DNS package name with at least two dot-separated segments. */
42
+ export declare const androidPackageNameSchema: z.ZodString;
43
+ /** design.md §11.8, §21.3, §27.3 "React Native設定": present only for `client_type: "react_native"`. */
44
+ export declare const mobileAppSchema: z.ZodObject<{
45
+ app_scheme: z.ZodString;
46
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
47
+ ios_team_id: z.ZodNullable<z.ZodString>;
48
+ android_package_name: z.ZodNullable<z.ZodString>;
49
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
50
+ universal_link_host: z.ZodNullable<z.ZodString>;
51
+ }, z.core.$strict>;
52
+ export type MobileApp = z.infer<typeof mobileAppSchema>;
53
+ export declare const clientSchema: z.ZodObject<{
54
+ id: z.ZodString;
55
+ environment_id: z.ZodString;
56
+ client_type: z.ZodEnum<{
57
+ web_bff: "web_bff";
58
+ web_spa: "web_spa";
59
+ react_native: "react_native";
60
+ }>;
61
+ name: z.ZodString;
62
+ public_key_prefix: z.ZodNullable<z.ZodString>;
63
+ redirect_uris: z.ZodArray<z.ZodString>;
64
+ post_logout_redirect_uris: z.ZodArray<z.ZodString>;
65
+ allowed_origins: z.ZodArray<z.ZodString>;
66
+ allowed_scopes: z.ZodArray<z.ZodString>;
67
+ allowed_resources: z.ZodArray<z.ZodURL>;
68
+ token_endpoint_auth_method: z.ZodEnum<{
69
+ client_secret_basic: "client_secret_basic";
70
+ client_secret_post: "client_secret_post";
71
+ none: "none";
72
+ }>;
73
+ require_pkce: z.ZodBoolean;
74
+ status: z.ZodEnum<{
75
+ active: "active";
76
+ disabled: "disabled";
77
+ }>;
78
+ mobile_app: z.ZodNullable<z.ZodObject<{
79
+ app_scheme: z.ZodString;
80
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
81
+ ios_team_id: z.ZodNullable<z.ZodString>;
82
+ android_package_name: z.ZodNullable<z.ZodString>;
83
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
84
+ universal_link_host: z.ZodNullable<z.ZodString>;
85
+ }, z.core.$strict>>;
86
+ created_at: z.ZodISODateTime;
87
+ updated_at: z.ZodISODateTime;
88
+ }, z.core.$strict>;
89
+ export type Client = z.infer<typeof clientSchema>;
90
+ export declare const clientListQuerySchema: z.ZodObject<{
91
+ cursor: z.ZodOptional<z.ZodString>;
92
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
93
+ environment_id: z.ZodString;
94
+ client_type: z.ZodOptional<z.ZodEnum<{
95
+ web_bff: "web_bff";
96
+ web_spa: "web_spa";
97
+ react_native: "react_native";
98
+ }>>;
99
+ }, z.core.$strip>;
100
+ export type ClientListQuery = z.infer<typeof clientListQuerySchema>;
101
+ export declare const clientListResponseSchema: z.ZodObject<{
102
+ items: z.ZodArray<z.ZodObject<{
103
+ id: z.ZodString;
104
+ environment_id: z.ZodString;
105
+ client_type: z.ZodEnum<{
106
+ web_bff: "web_bff";
107
+ web_spa: "web_spa";
108
+ react_native: "react_native";
109
+ }>;
110
+ name: z.ZodString;
111
+ public_key_prefix: z.ZodNullable<z.ZodString>;
112
+ redirect_uris: z.ZodArray<z.ZodString>;
113
+ post_logout_redirect_uris: z.ZodArray<z.ZodString>;
114
+ allowed_origins: z.ZodArray<z.ZodString>;
115
+ allowed_scopes: z.ZodArray<z.ZodString>;
116
+ allowed_resources: z.ZodArray<z.ZodURL>;
117
+ token_endpoint_auth_method: z.ZodEnum<{
118
+ client_secret_basic: "client_secret_basic";
119
+ client_secret_post: "client_secret_post";
120
+ none: "none";
121
+ }>;
122
+ require_pkce: z.ZodBoolean;
123
+ status: z.ZodEnum<{
124
+ active: "active";
125
+ disabled: "disabled";
126
+ }>;
127
+ mobile_app: z.ZodNullable<z.ZodObject<{
128
+ app_scheme: z.ZodString;
129
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
130
+ ios_team_id: z.ZodNullable<z.ZodString>;
131
+ android_package_name: z.ZodNullable<z.ZodString>;
132
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
133
+ universal_link_host: z.ZodNullable<z.ZodString>;
134
+ }, z.core.$strict>>;
135
+ created_at: z.ZodISODateTime;
136
+ updated_at: z.ZodISODateTime;
137
+ }, z.core.$strict>>;
138
+ next_cursor: z.ZodNullable<z.ZodString>;
139
+ }, z.core.$strict>;
140
+ export type ClientListResponse = z.infer<typeof clientListResponseSchema>;
141
+ export declare const clientCreateRequestSchema: z.ZodObject<{
142
+ environment_id: z.ZodString;
143
+ client_type: z.ZodEnum<{
144
+ web_bff: "web_bff";
145
+ web_spa: "web_spa";
146
+ react_native: "react_native";
147
+ }>;
148
+ name: z.ZodString;
149
+ redirect_uris: z.ZodDefault<z.ZodArray<z.ZodString>>;
150
+ post_logout_redirect_uris: z.ZodDefault<z.ZodArray<z.ZodString>>;
151
+ allowed_origins: z.ZodDefault<z.ZodArray<z.ZodString>>;
152
+ allowed_scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
153
+ allowed_resources: z.ZodDefault<z.ZodArray<z.ZodURL>>;
154
+ token_endpoint_auth_method: z.ZodEnum<{
155
+ client_secret_basic: "client_secret_basic";
156
+ client_secret_post: "client_secret_post";
157
+ none: "none";
158
+ }>;
159
+ require_pkce: z.ZodDefault<z.ZodBoolean>;
160
+ mobile_app: z.ZodOptional<z.ZodObject<{
161
+ app_scheme: z.ZodString;
162
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
163
+ ios_team_id: z.ZodNullable<z.ZodString>;
164
+ android_package_name: z.ZodNullable<z.ZodString>;
165
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
166
+ universal_link_host: z.ZodNullable<z.ZodString>;
167
+ }, z.core.$strict>>;
168
+ }, z.core.$strict>;
169
+ export type ClientCreateRequest = z.infer<typeof clientCreateRequestSchema>;
170
+ /**
171
+ * design.md §11.12's "Secretは作成時に1回だけ表示する" applies by the same
172
+ * logic to any generated confidential-client secret: `client_secret` is
173
+ * present only when `token_endpoint_auth_method !== "none"`, and only on this
174
+ * one response — never on `GET`/`PATCH`/list.
175
+ */
176
+ export declare const clientCreateResponseSchema: z.ZodObject<{
177
+ id: z.ZodString;
178
+ environment_id: z.ZodString;
179
+ client_type: z.ZodEnum<{
180
+ web_bff: "web_bff";
181
+ web_spa: "web_spa";
182
+ react_native: "react_native";
183
+ }>;
184
+ name: z.ZodString;
185
+ public_key_prefix: z.ZodNullable<z.ZodString>;
186
+ redirect_uris: z.ZodArray<z.ZodString>;
187
+ post_logout_redirect_uris: z.ZodArray<z.ZodString>;
188
+ allowed_origins: z.ZodArray<z.ZodString>;
189
+ allowed_scopes: z.ZodArray<z.ZodString>;
190
+ allowed_resources: z.ZodArray<z.ZodURL>;
191
+ token_endpoint_auth_method: z.ZodEnum<{
192
+ client_secret_basic: "client_secret_basic";
193
+ client_secret_post: "client_secret_post";
194
+ none: "none";
195
+ }>;
196
+ require_pkce: z.ZodBoolean;
197
+ status: z.ZodEnum<{
198
+ active: "active";
199
+ disabled: "disabled";
200
+ }>;
201
+ mobile_app: z.ZodNullable<z.ZodObject<{
202
+ app_scheme: z.ZodString;
203
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
204
+ ios_team_id: z.ZodNullable<z.ZodString>;
205
+ android_package_name: z.ZodNullable<z.ZodString>;
206
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
207
+ universal_link_host: z.ZodNullable<z.ZodString>;
208
+ }, z.core.$strict>>;
209
+ created_at: z.ZodISODateTime;
210
+ updated_at: z.ZodISODateTime;
211
+ client_secret: z.ZodOptional<z.ZodString>;
212
+ }, z.core.$strict>;
213
+ export type ClientCreateResponse = z.infer<typeof clientCreateResponseSchema>;
214
+ export declare const clientGetResponseSchema: z.ZodObject<{
215
+ id: z.ZodString;
216
+ environment_id: z.ZodString;
217
+ client_type: z.ZodEnum<{
218
+ web_bff: "web_bff";
219
+ web_spa: "web_spa";
220
+ react_native: "react_native";
221
+ }>;
222
+ name: z.ZodString;
223
+ public_key_prefix: z.ZodNullable<z.ZodString>;
224
+ redirect_uris: z.ZodArray<z.ZodString>;
225
+ post_logout_redirect_uris: z.ZodArray<z.ZodString>;
226
+ allowed_origins: z.ZodArray<z.ZodString>;
227
+ allowed_scopes: z.ZodArray<z.ZodString>;
228
+ allowed_resources: z.ZodArray<z.ZodURL>;
229
+ token_endpoint_auth_method: z.ZodEnum<{
230
+ client_secret_basic: "client_secret_basic";
231
+ client_secret_post: "client_secret_post";
232
+ none: "none";
233
+ }>;
234
+ require_pkce: z.ZodBoolean;
235
+ status: z.ZodEnum<{
236
+ active: "active";
237
+ disabled: "disabled";
238
+ }>;
239
+ mobile_app: z.ZodNullable<z.ZodObject<{
240
+ app_scheme: z.ZodString;
241
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
242
+ ios_team_id: z.ZodNullable<z.ZodString>;
243
+ android_package_name: z.ZodNullable<z.ZodString>;
244
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
245
+ universal_link_host: z.ZodNullable<z.ZodString>;
246
+ }, z.core.$strict>>;
247
+ created_at: z.ZodISODateTime;
248
+ updated_at: z.ZodISODateTime;
249
+ }, z.core.$strict>;
250
+ export type ClientGetResponse = z.infer<typeof clientGetResponseSchema>;
251
+ export declare const clientUpdateRequestSchema: z.ZodObject<{
252
+ name: z.ZodOptional<z.ZodString>;
253
+ redirect_uris: z.ZodOptional<z.ZodArray<z.ZodString>>;
254
+ post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodString>>;
255
+ allowed_origins: z.ZodOptional<z.ZodArray<z.ZodString>>;
256
+ allowed_scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
257
+ allowed_resources: z.ZodOptional<z.ZodArray<z.ZodURL>>;
258
+ token_endpoint_auth_method: z.ZodOptional<z.ZodEnum<{
259
+ client_secret_basic: "client_secret_basic";
260
+ client_secret_post: "client_secret_post";
261
+ none: "none";
262
+ }>>;
263
+ require_pkce: z.ZodOptional<z.ZodBoolean>;
264
+ status: z.ZodOptional<z.ZodEnum<{
265
+ active: "active";
266
+ disabled: "disabled";
267
+ }>>;
268
+ mobile_app: z.ZodOptional<z.ZodNullable<z.ZodObject<{
269
+ app_scheme: z.ZodString;
270
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
271
+ ios_team_id: z.ZodNullable<z.ZodString>;
272
+ android_package_name: z.ZodNullable<z.ZodString>;
273
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
274
+ universal_link_host: z.ZodNullable<z.ZodString>;
275
+ }, z.core.$strict>>>;
276
+ }, z.core.$strict>;
277
+ export type ClientUpdateRequest = z.infer<typeof clientUpdateRequestSchema>;
278
+ export declare const clientUpdateResponseSchema: z.ZodObject<{
279
+ id: z.ZodString;
280
+ environment_id: z.ZodString;
281
+ client_type: z.ZodEnum<{
282
+ web_bff: "web_bff";
283
+ web_spa: "web_spa";
284
+ react_native: "react_native";
285
+ }>;
286
+ name: z.ZodString;
287
+ public_key_prefix: z.ZodNullable<z.ZodString>;
288
+ redirect_uris: z.ZodArray<z.ZodString>;
289
+ post_logout_redirect_uris: z.ZodArray<z.ZodString>;
290
+ allowed_origins: z.ZodArray<z.ZodString>;
291
+ allowed_scopes: z.ZodArray<z.ZodString>;
292
+ allowed_resources: z.ZodArray<z.ZodURL>;
293
+ token_endpoint_auth_method: z.ZodEnum<{
294
+ client_secret_basic: "client_secret_basic";
295
+ client_secret_post: "client_secret_post";
296
+ none: "none";
297
+ }>;
298
+ require_pkce: z.ZodBoolean;
299
+ status: z.ZodEnum<{
300
+ active: "active";
301
+ disabled: "disabled";
302
+ }>;
303
+ mobile_app: z.ZodNullable<z.ZodObject<{
304
+ app_scheme: z.ZodString;
305
+ ios_bundle_id: z.ZodNullable<z.ZodString>;
306
+ ios_team_id: z.ZodNullable<z.ZodString>;
307
+ android_package_name: z.ZodNullable<z.ZodString>;
308
+ android_sha256_fingerprints: z.ZodArray<z.ZodString>;
309
+ universal_link_host: z.ZodNullable<z.ZodString>;
310
+ }, z.core.$strict>>;
311
+ created_at: z.ZodISODateTime;
312
+ updated_at: z.ZodISODateTime;
313
+ }, z.core.$strict>;
314
+ export type ClientUpdateResponse = z.infer<typeof clientUpdateResponseSchema>;
315
+ export declare const clientDeleteResponseSchema: z.ZodObject<{
316
+ id: z.ZodString;
317
+ deleted: z.ZodLiteral<true>;
318
+ }, z.core.$strict>;
319
+ export type ClientDeleteResponse = z.infer<typeof clientDeleteResponseSchema>;
320
+ export declare const clientRotateSecretRequestSchema: z.ZodObject<{}, z.core.$strict>;
321
+ export type ClientRotateSecretRequest = z.infer<typeof clientRotateSecretRequestSchema>;
322
+ /** One-time plaintext secret (design.md §11.12's display-once rule, applied to client secrets). */
323
+ export declare const clientRotateSecretResponseSchema: z.ZodObject<{
324
+ id: z.ZodString;
325
+ client_secret: z.ZodString;
326
+ rotated_at: z.ZodISODateTime;
327
+ }, z.core.$strict>;
328
+ export type ClientRotateSecretResponse = z.infer<typeof clientRotateSecretResponseSchema>;
@@ -0,0 +1,141 @@
1
+ import { z } from "zod";
2
+ import { cursorPageSchema, paginationQuerySchema } from "./common.js";
3
+ import { clientIdSchema, environmentIdSchema, httpsUrlSchema } from "./primitives.js";
4
+ /**
5
+ * `clients` (design.md §11.5), `client_redirect_uris` (§11.6),
6
+ * `client_origins` (§11.7), `mobile_apps` (§11.8) and the conceptual Client
7
+ * model of design.md §7.4 (which groups these tables' columns into one
8
+ * resource: `redirect_uris`, `post_logout_redirect_uris`, `allowed_origins`,
9
+ * `allowed_scopes`, `allowed_resources`).
10
+ *
11
+ * `secret_hash` (§11.5) is excluded per the assignment's secret-field rule;
12
+ * `public_key_prefix` is kept — it exists specifically so a non-secret
13
+ * fragment of client identity can be displayed (the same pattern as
14
+ * `management_api_keys.prefix` alongside its hidden `key_mac`, §11.12).
15
+ */
16
+ export const CLIENT_TYPES = ["web_bff", "web_spa", "react_native"];
17
+ export const clientTypeSchema = z.enum(CLIENT_TYPES);
18
+ export const TOKEN_ENDPOINT_AUTH_METHODS = [
19
+ "none",
20
+ "client_secret_basic",
21
+ "client_secret_post",
22
+ ];
23
+ export const tokenEndpointAuthMethodSchema = z.enum(TOKEN_ENDPOINT_AUTH_METHODS);
24
+ export const CLIENT_STATUSES = ["active", "disabled"];
25
+ export const clientStatusSchema = z.enum(CLIENT_STATUSES);
26
+ /** design.md §11.6: exact-match only, no wildcards; §15.9 governs shape rules by client type. */
27
+ const clientRedirectUriSchema = z.string().min(1).max(2048);
28
+ /** design.md §11.7: "Originにはscheme、host、portのみを許可し、path/query/fragmentを拒否する。" */
29
+ const originSchema = z.string().regex(/^https?:\/\/[^/?#]+$/);
30
+ /** A single non-whitespace OAuth scope token, e.g. `openid` or a custom API scope. */
31
+ const allowedScopeSchema = z.string().min(1).max(100).regex(/^\S+$/);
32
+ /**
33
+ * design.md §11.8 `android_sha256_fingerprints_json`: colon-separated hex, 32
34
+ * bytes. Any case is accepted on the wire; the control-plane repository stores
35
+ * and serves the canonical uppercase form. Kept transform-free so the schema
36
+ * stays representable for OpenAPI generation (`z.toJSONSchema` with `io: "output"`).
37
+ */
38
+ export const androidSha256FingerprintSchema = z
39
+ .string()
40
+ .regex(/^([0-9A-Fa-f]{2}:){31}[0-9A-Fa-f]{2}$/);
41
+ /** design.md §11.8 `android_package_name`: reversed-DNS package name with at least two dot-separated segments. */
42
+ export const androidPackageNameSchema = z
43
+ .string()
44
+ .regex(/^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/);
45
+ /** design.md §11.8, §21.3, §27.3 "React Native設定": present only for `client_type: "react_native"`. */
46
+ export const mobileAppSchema = z.strictObject({
47
+ app_scheme: z.string().min(1),
48
+ ios_bundle_id: z.string().min(1).nullable(),
49
+ ios_team_id: z.string().min(1).nullable(),
50
+ android_package_name: androidPackageNameSchema.nullable(),
51
+ android_sha256_fingerprints: z.array(androidSha256FingerprintSchema),
52
+ universal_link_host: z.string().min(1).nullable(),
53
+ });
54
+ export const clientSchema = z.strictObject({
55
+ id: clientIdSchema,
56
+ environment_id: environmentIdSchema,
57
+ client_type: clientTypeSchema,
58
+ name: z.string().min(1).max(200),
59
+ public_key_prefix: z.string().min(1).nullable(),
60
+ redirect_uris: z.array(clientRedirectUriSchema).max(50),
61
+ post_logout_redirect_uris: z.array(clientRedirectUriSchema).max(50),
62
+ allowed_origins: z.array(originSchema).max(50),
63
+ allowed_scopes: z.array(allowedScopeSchema).max(50),
64
+ allowed_resources: z.array(httpsUrlSchema).max(20),
65
+ token_endpoint_auth_method: tokenEndpointAuthMethodSchema,
66
+ require_pkce: z.boolean(),
67
+ status: clientStatusSchema,
68
+ mobile_app: mobileAppSchema.nullable(),
69
+ created_at: z.iso.datetime(),
70
+ updated_at: z.iso.datetime(),
71
+ });
72
+ // ---------------------------------------------------------------------------
73
+ // GET /clients
74
+ // ---------------------------------------------------------------------------
75
+ export const clientListQuerySchema = paginationQuerySchema.extend({
76
+ environment_id: environmentIdSchema,
77
+ client_type: clientTypeSchema.optional(),
78
+ });
79
+ export const clientListResponseSchema = cursorPageSchema(clientSchema);
80
+ // ---------------------------------------------------------------------------
81
+ // POST /clients
82
+ // ---------------------------------------------------------------------------
83
+ export const clientCreateRequestSchema = z.strictObject({
84
+ environment_id: environmentIdSchema,
85
+ client_type: clientTypeSchema,
86
+ name: z.string().min(1).max(200),
87
+ redirect_uris: z.array(clientRedirectUriSchema).max(50).default([]),
88
+ post_logout_redirect_uris: z.array(clientRedirectUriSchema).max(50).default([]),
89
+ allowed_origins: z.array(originSchema).max(50).default([]),
90
+ allowed_scopes: z.array(allowedScopeSchema).max(50).default([]),
91
+ allowed_resources: z.array(httpsUrlSchema).max(20).default([]),
92
+ token_endpoint_auth_method: tokenEndpointAuthMethodSchema,
93
+ require_pkce: z.boolean().default(true),
94
+ mobile_app: mobileAppSchema.optional(),
95
+ });
96
+ /**
97
+ * design.md §11.12's "Secretは作成時に1回だけ表示する" applies by the same
98
+ * logic to any generated confidential-client secret: `client_secret` is
99
+ * present only when `token_endpoint_auth_method !== "none"`, and only on this
100
+ * one response — never on `GET`/`PATCH`/list.
101
+ */
102
+ export const clientCreateResponseSchema = clientSchema.extend({
103
+ client_secret: z.string().min(1).optional(),
104
+ });
105
+ // ---------------------------------------------------------------------------
106
+ // GET /clients/:clientId
107
+ // ---------------------------------------------------------------------------
108
+ export const clientGetResponseSchema = clientSchema;
109
+ // ---------------------------------------------------------------------------
110
+ // PATCH /clients/:clientId
111
+ // ---------------------------------------------------------------------------
112
+ export const clientUpdateRequestSchema = z.strictObject({
113
+ name: z.string().min(1).max(200).optional(),
114
+ redirect_uris: z.array(clientRedirectUriSchema).max(50).optional(),
115
+ post_logout_redirect_uris: z.array(clientRedirectUriSchema).max(50).optional(),
116
+ allowed_origins: z.array(originSchema).max(50).optional(),
117
+ allowed_scopes: z.array(allowedScopeSchema).max(50).optional(),
118
+ allowed_resources: z.array(httpsUrlSchema).max(20).optional(),
119
+ token_endpoint_auth_method: tokenEndpointAuthMethodSchema.optional(),
120
+ require_pkce: z.boolean().optional(),
121
+ status: clientStatusSchema.optional(),
122
+ mobile_app: mobileAppSchema.nullable().optional(),
123
+ });
124
+ export const clientUpdateResponseSchema = clientSchema;
125
+ // ---------------------------------------------------------------------------
126
+ // DELETE /clients/:clientId
127
+ // ---------------------------------------------------------------------------
128
+ export const clientDeleteResponseSchema = z.strictObject({
129
+ id: clientIdSchema,
130
+ deleted: z.literal(true),
131
+ });
132
+ // ---------------------------------------------------------------------------
133
+ // POST /clients/:clientId/rotate-secret
134
+ // ---------------------------------------------------------------------------
135
+ export const clientRotateSecretRequestSchema = z.strictObject({});
136
+ /** One-time plaintext secret (design.md §11.12's display-once rule, applied to client secrets). */
137
+ export const clientRotateSecretResponseSchema = z.strictObject({
138
+ id: clientIdSchema,
139
+ client_secret: z.string().min(1),
140
+ rotated_at: z.iso.datetime(),
141
+ });
@@ -0,0 +1,95 @@
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
+ export declare const DEFAULT_PAGE_SIZE = 25;
23
+ export declare const MAX_PAGE_SIZE = 100;
24
+ /**
25
+ * Query parameters shared by every `GET` list route. `limit` is coerced from
26
+ * its wire representation (a query string) to a number so callers can parse
27
+ * `URLSearchParams` values directly.
28
+ */
29
+ export declare const paginationQuerySchema: z.ZodObject<{
30
+ cursor: z.ZodOptional<z.ZodString>;
31
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
32
+ }, z.core.$strip>;
33
+ export type PaginationQuery = z.infer<typeof paginationQuerySchema>;
34
+ /**
35
+ * Generic cursor-paginated list envelope: `{ items, next_cursor }`.
36
+ * `next_cursor` is `null` once the caller has reached the last page.
37
+ */
38
+ export declare const cursorPageSchema: <ItemSchema extends z.ZodType>(itemSchema: ItemSchema) => z.ZodObject<{
39
+ items: z.ZodArray<ItemSchema>;
40
+ next_cursor: z.ZodNullable<z.ZodString>;
41
+ }, z.core.$strict>;
42
+ export type CursorPage<Item> = {
43
+ readonly items: readonly Item[];
44
+ readonly next_cursor: string | null;
45
+ };
46
+ export declare const idempotencyKeySchema: z.ZodString;
47
+ /** Header carried by every `POST`/`PATCH`/`DELETE` write request. */
48
+ export declare const idempotencyKeyHeaderSchema: z.ZodObject<{
49
+ "idempotency-key": z.ZodString;
50
+ }, z.core.$strict>;
51
+ export type IdempotencyKeyHeader = z.infer<typeof idempotencyKeyHeaderSchema>;
52
+ /** An opaque entity tag, optionally weak (`W/"..."`) or quoted per RFC 9110 §8.8.3. */
53
+ export declare const etagSchema: z.ZodString;
54
+ export type ETag = z.infer<typeof etagSchema>;
55
+ /** Header carried by every conditional `PATCH`/`DELETE` request. */
56
+ export declare const ifMatchHeaderSchema: z.ZodObject<{
57
+ "if-match": z.ZodString;
58
+ }, z.core.$strict>;
59
+ export type IfMatchHeader = z.infer<typeof ifMatchHeaderSchema>;
60
+ /** `req_...` (design.md §7.5 / `@smartcrab/identifiers` `ID_PREFIXES.request`). */
61
+ export declare const requestIdSchema: z.ZodString;
62
+ export type RequestId = z.infer<typeof requestIdSchema>;
63
+ export declare const requestIdHeaderSchema: z.ZodObject<{
64
+ "x-request-id": z.ZodString;
65
+ }, z.core.$strict>;
66
+ export type RequestIdHeader = z.infer<typeof requestIdHeaderSchema>;
67
+ /**
68
+ * Matches `@smartcrab/result`'s `ProblemDetails` interface shape exactly
69
+ * (this package does not import `@smartcrab/result`, per assignment
70
+ * rules, so the shape is redefined here as a zod schema for request/response
71
+ * contract validation rather than reused as a TS type).
72
+ *
73
+ * ```json
74
+ * {
75
+ * "type": "https://docs.example-auth.com/errors/invalid-redirect-uri",
76
+ * "title": "Invalid redirect URI",
77
+ * "status": 400,
78
+ * "detail": "The redirect URI is not registered for this client.",
79
+ * "code": "invalid_redirect_uri",
80
+ * "request_id": "req_xxx"
81
+ * }
82
+ * ```
83
+ *
84
+ * Deliberately NOT `z.strictObject`: RFC 9457 explicitly allows arbitrary
85
+ * extension members alongside the standard ones.
86
+ */
87
+ export declare const problemDetailsSchema: z.ZodObject<{
88
+ type: z.ZodString;
89
+ title: z.ZodString;
90
+ status: z.ZodNumber;
91
+ detail: z.ZodOptional<z.ZodString>;
92
+ code: z.ZodOptional<z.ZodString>;
93
+ request_id: z.ZodOptional<z.ZodString>;
94
+ }, z.core.$strip>;
95
+ export type ProblemDetails = z.infer<typeof problemDetailsSchema>;