@idelio/contracts 0.1.0-beta.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SFER LABS LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @idelio/contracts
2
+
3
+ The shared contract of the [Idelio](https://idelio.pro) API: zod schemas and
4
+ TypeScript types for every request and response, the asset catalogue, and
5
+ credit pricing. `@idelio/sdk` is built on it; install it directly when you
6
+ want to validate payloads yourself - for example an incoming webhook.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @idelio/contracts
12
+ ```
13
+
14
+ Requires Node.js 20.19 or later; the package is ESM-only.
15
+
16
+ ## Usage
17
+
18
+ ```typescript
19
+ import { webhookEnvelopeSchema, type Brand } from "@idelio/contracts";
20
+ import { estimateCredits } from "@idelio/contracts/pricing";
21
+
22
+ const event = webhookEnvelopeSchema.parse(JSON.parse(rawBody));
23
+ ```
24
+
25
+ ## OpenAPI
26
+
27
+ The OpenAPI 3.1 document is included at `openapi/openapi.yaml`.
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ export declare const apiKeyEnvironments: readonly ["live", "test"];
3
+ export declare const apiKeySchema: z.ZodObject<{
4
+ id: z.ZodString;
5
+ name: z.ZodString;
6
+ environment: z.ZodEnum<{
7
+ live: "live";
8
+ test: "test";
9
+ }>;
10
+ prefix: z.ZodString;
11
+ last4: z.ZodString;
12
+ requests: z.ZodNumber;
13
+ credits: z.ZodNumber;
14
+ created_at: z.ZodString;
15
+ last_used_at: z.ZodNullable<z.ZodString>;
16
+ created_by_email: z.ZodNullable<z.ZodString>;
17
+ }, z.core.$strip>;
18
+ export declare const apiKeyWithSecretSchema: z.ZodObject<{
19
+ id: z.ZodString;
20
+ name: z.ZodString;
21
+ environment: z.ZodEnum<{
22
+ live: "live";
23
+ test: "test";
24
+ }>;
25
+ prefix: z.ZodString;
26
+ last4: z.ZodString;
27
+ requests: z.ZodNumber;
28
+ credits: z.ZodNumber;
29
+ created_at: z.ZodString;
30
+ last_used_at: z.ZodNullable<z.ZodString>;
31
+ created_by_email: z.ZodNullable<z.ZodString>;
32
+ secret: z.ZodString;
33
+ }, z.core.$strip>;
34
+ export declare const createApiKeyRequestSchema: z.ZodObject<{
35
+ name: z.ZodString;
36
+ environment: z.ZodDefault<z.ZodEnum<{
37
+ live: "live";
38
+ test: "test";
39
+ }>>;
40
+ }, z.core.$strip>;
41
+ export type ApiKeyEnvironment = (typeof apiKeyEnvironments)[number];
42
+ export type ApiKey = z.infer<typeof apiKeySchema>;
43
+ export type ApiKeyWithSecret = z.infer<typeof apiKeyWithSecretSchema>;
44
+ export type CreateApiKeyRequest = z.infer<typeof createApiKeyRequestSchema>;
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ export const apiKeyEnvironments = ["live", "test"];
3
+ export const apiKeySchema = z.object({
4
+ id: z.string(),
5
+ name: z.string(),
6
+ environment: z.enum(apiKeyEnvironments),
7
+ prefix: z.string(),
8
+ last4: z.string(),
9
+ requests: z.number().int().nonnegative(),
10
+ credits: z.number().int().nonnegative(),
11
+ created_at: z.string().datetime(),
12
+ last_used_at: z.string().datetime().nullable(),
13
+ created_by_email: z.string().nullable(),
14
+ });
15
+ export const apiKeyWithSecretSchema = apiKeySchema.extend({ secret: z.string() });
16
+ export const createApiKeyRequestSchema = z.object({
17
+ name: z.string().trim().min(1).max(80),
18
+ environment: z.enum(apiKeyEnvironments).default("live"),
19
+ });
@@ -0,0 +1,188 @@
1
+ import { z } from "zod";
2
+ export declare const assetStatuses: readonly ["queued", "generating", "ready", "failed"];
3
+ export declare const qaCheckStatuses: readonly ["pass", "warn", "fail"];
4
+ export declare const qaCheckSchema: z.ZodObject<{
5
+ id: z.ZodString;
6
+ label: z.ZodString;
7
+ status: z.ZodEnum<{
8
+ pass: "pass";
9
+ warn: "warn";
10
+ fail: "fail";
11
+ }>;
12
+ detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ source: z.ZodOptional<z.ZodEnum<{
14
+ ai: "ai";
15
+ deterministic: "deterministic";
16
+ }>>;
17
+ }, z.core.$strip>;
18
+ export declare const qaReportSchema: z.ZodObject<{
19
+ overall_score: z.ZodNumber;
20
+ checks: z.ZodOptional<z.ZodArray<z.ZodObject<{
21
+ id: z.ZodString;
22
+ label: z.ZodString;
23
+ status: z.ZodEnum<{
24
+ pass: "pass";
25
+ warn: "warn";
26
+ fail: "fail";
27
+ }>;
28
+ detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ source: z.ZodOptional<z.ZodEnum<{
30
+ ai: "ai";
31
+ deterministic: "deterministic";
32
+ }>>;
33
+ }, z.core.$strip>>>;
34
+ }, z.core.$catchall<z.ZodUnknown>>;
35
+ export type QaCheckStatus = (typeof qaCheckStatuses)[number];
36
+ export type QaCheck = z.infer<typeof qaCheckSchema>;
37
+ export type QaReport = z.infer<typeof qaReportSchema>;
38
+ export declare const assetSchema: z.ZodObject<{
39
+ id: z.ZodString;
40
+ brand_id: z.ZodString;
41
+ version_id: z.ZodNullable<z.ZodString>;
42
+ kind: z.ZodEnum<{
43
+ logo: "logo";
44
+ logo_alternative: "logo_alternative";
45
+ logo_wordmark: "logo_wordmark";
46
+ color_palette: "color_palette";
47
+ font_pairing: "font_pairing";
48
+ logo_mono: "logo_mono";
49
+ logo_reversed: "logo_reversed";
50
+ favicon: "favicon";
51
+ brand_guide: "brand_guide";
52
+ profile_avatar: "profile_avatar";
53
+ social_x: "social_x";
54
+ social_linkedin: "social_linkedin";
55
+ social_linkedin_personal: "social_linkedin_personal";
56
+ social_facebook: "social_facebook";
57
+ social_youtube: "social_youtube";
58
+ social_post: "social_post";
59
+ social_story: "social_story";
60
+ app_icon: "app_icon";
61
+ og_image: "og_image";
62
+ email_signature: "email_signature";
63
+ hero_image: "hero_image";
64
+ play_feature_graphic: "play_feature_graphic";
65
+ business_card: "business_card";
66
+ letterhead: "letterhead";
67
+ mockup: "mockup";
68
+ custom_image: "custom_image";
69
+ }>;
70
+ name: z.ZodString;
71
+ status: z.ZodEnum<{
72
+ generating: "generating";
73
+ ready: "ready";
74
+ failed: "failed";
75
+ queued: "queued";
76
+ }>;
77
+ url: z.ZodNullable<z.ZodString>;
78
+ thumbnail_url: z.ZodNullable<z.ZodString>;
79
+ credits: z.ZodNumber;
80
+ pixel_check: z.ZodNullable<z.ZodNumber>;
81
+ qa_report: z.ZodNullable<z.ZodObject<{
82
+ overall_score: z.ZodNumber;
83
+ checks: z.ZodOptional<z.ZodArray<z.ZodObject<{
84
+ id: z.ZodString;
85
+ label: z.ZodString;
86
+ status: z.ZodEnum<{
87
+ pass: "pass";
88
+ warn: "warn";
89
+ fail: "fail";
90
+ }>;
91
+ detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
92
+ source: z.ZodOptional<z.ZodEnum<{
93
+ ai: "ai";
94
+ deterministic: "deterministic";
95
+ }>>;
96
+ }, z.core.$strip>>>;
97
+ }, z.core.$catchall<z.ZodUnknown>>>;
98
+ formats: z.ZodArray<z.ZodString>;
99
+ created_at: z.ZodString;
100
+ }, z.core.$strip>;
101
+ export type AssetStatus = (typeof assetStatuses)[number];
102
+ export type Asset = z.infer<typeof assetSchema>;
103
+ export declare const assetVersionSchema: z.ZodObject<{
104
+ id: z.ZodString;
105
+ asset_id: z.ZodString;
106
+ parent_version_id: z.ZodNullable<z.ZodString>;
107
+ files: z.ZodArray<z.ZodObject<{
108
+ format: z.ZodString;
109
+ content_hash: z.ZodString;
110
+ storage_key: z.ZodString;
111
+ bytes: z.ZodNumber;
112
+ }, z.core.$strip>>;
113
+ credit_cost: z.ZodNumber;
114
+ qa_report: z.ZodNullable<z.ZodObject<{
115
+ overall_score: z.ZodNumber;
116
+ checks: z.ZodOptional<z.ZodArray<z.ZodObject<{
117
+ id: z.ZodString;
118
+ label: z.ZodString;
119
+ status: z.ZodEnum<{
120
+ pass: "pass";
121
+ warn: "warn";
122
+ fail: "fail";
123
+ }>;
124
+ detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
125
+ source: z.ZodOptional<z.ZodEnum<{
126
+ ai: "ai";
127
+ deterministic: "deterministic";
128
+ }>>;
129
+ }, z.core.$strip>>>;
130
+ }, z.core.$catchall<z.ZodUnknown>>>;
131
+ created_at: z.ZodString;
132
+ }, z.core.$strip>;
133
+ export type AssetVersion = z.infer<typeof assetVersionSchema>;
134
+ export declare const wordmarkStyleCount = 11;
135
+ export declare const wordmarkStyleIndexSchema: z.ZodNumber;
136
+ export declare const logoTreatmentOverridesSchema: z.ZodObject<{
137
+ family: z.ZodOptional<z.ZodString>;
138
+ ink: z.ZodOptional<z.ZodString>;
139
+ accent: z.ZodOptional<z.ZodString>;
140
+ styleSeed: z.ZodOptional<z.ZodString>;
141
+ styleIndex: z.ZodOptional<z.ZodNumber>;
142
+ }, z.core.$strip>;
143
+ export type LogoTreatmentOverrides = z.infer<typeof logoTreatmentOverridesSchema>;
144
+ export declare const refineRequestSchema: z.ZodUnion<readonly [z.ZodObject<{
145
+ instruction: z.ZodString;
146
+ }, z.core.$strip>, z.ZodObject<{
147
+ family: z.ZodOptional<z.ZodString>;
148
+ ink: z.ZodOptional<z.ZodString>;
149
+ accent: z.ZodOptional<z.ZodString>;
150
+ styleSeed: z.ZodOptional<z.ZodString>;
151
+ styleIndex: z.ZodOptional<z.ZodNumber>;
152
+ }, z.core.$strip>]>;
153
+ export type RefineRequest = z.infer<typeof refineRequestSchema>;
154
+ export declare const logoTreatmentSchema: z.ZodObject<{
155
+ family: z.ZodString;
156
+ ink: z.ZodString;
157
+ accent: z.ZodString;
158
+ style_seed: z.ZodString;
159
+ style_index: z.ZodNullable<z.ZodNumber>;
160
+ }, z.core.$strip>;
161
+ export type LogoTreatment = z.infer<typeof logoTreatmentSchema>;
162
+ export declare const logoTreatmentPreviewQuerySchema: z.ZodObject<{
163
+ family: z.ZodOptional<z.ZodString>;
164
+ ink: z.ZodOptional<z.ZodString>;
165
+ accent: z.ZodOptional<z.ZodString>;
166
+ style_seed: z.ZodOptional<z.ZodString>;
167
+ style_index: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
168
+ }, z.core.$strip>;
169
+ export type LogoTreatmentPreviewQuery = z.infer<typeof logoTreatmentPreviewQuerySchema>;
170
+ export declare const logoVariationPresets: readonly ["more_minimal", "more_startup", "bolder", "playful", "elegant", "geometric", "hand_drawn", "monochrome"];
171
+ export type LogoVariationPreset = (typeof logoVariationPresets)[number];
172
+ export declare const variationRequestSchema: z.ZodObject<{
173
+ preset: z.ZodEnum<{
174
+ playful: "playful";
175
+ elegant: "elegant";
176
+ geometric: "geometric";
177
+ more_minimal: "more_minimal";
178
+ more_startup: "more_startup";
179
+ bolder: "bolder";
180
+ hand_drawn: "hand_drawn";
181
+ monochrome: "monochrome";
182
+ }>;
183
+ }, z.core.$strip>;
184
+ export type VariationRequest = z.infer<typeof variationRequestSchema>;
185
+ export declare const restoreRequestSchema: z.ZodObject<{
186
+ to_version: z.ZodString;
187
+ }, z.core.$strip>;
188
+ export type RestoreRequest = z.infer<typeof restoreRequestSchema>;
package/dist/assets.js ADDED
@@ -0,0 +1,107 @@
1
+ import { z } from "zod";
2
+ import { assetKinds } from "./brands.js";
3
+ import { hexColorSchema } from "./creative-direction.js";
4
+ export const assetStatuses = ["queued", "generating", "ready", "failed"];
5
+ export const qaCheckStatuses = ["pass", "warn", "fail"];
6
+ export const qaCheckSchema = z.object({
7
+ id: z.string(),
8
+ label: z.string(),
9
+ status: z.enum(qaCheckStatuses),
10
+ detail: z.string().nullable().optional(),
11
+ source: z.enum(["deterministic", "ai"]).optional(),
12
+ });
13
+ export const qaReportSchema = z
14
+ .object({
15
+ overall_score: z.number().int().min(0).max(100),
16
+ checks: z.array(qaCheckSchema).optional(),
17
+ })
18
+ .catchall(z.unknown());
19
+ export const assetSchema = z.object({
20
+ id: z.string(),
21
+ brand_id: z.string(),
22
+ version_id: z.string().nullable(),
23
+ kind: z.enum(assetKinds),
24
+ name: z.string(),
25
+ status: z.enum(assetStatuses),
26
+ url: z.string().nullable(),
27
+ thumbnail_url: z.string().nullable(),
28
+ credits: z.number().int(),
29
+ pixel_check: z.number().int().nullable(),
30
+ qa_report: qaReportSchema.nullable(),
31
+ formats: z.array(z.string()),
32
+ created_at: z.string().datetime(),
33
+ });
34
+ export const assetVersionSchema = z.object({
35
+ id: z.string(),
36
+ asset_id: z.string(),
37
+ parent_version_id: z.string().nullable(),
38
+ files: z.array(z.object({
39
+ format: z.string(),
40
+ content_hash: z.string(),
41
+ storage_key: z.string(),
42
+ bytes: z.number().int(),
43
+ })),
44
+ credit_cost: z.number().int(),
45
+ qa_report: qaReportSchema.nullable(),
46
+ created_at: z.string().datetime(),
47
+ });
48
+ export const wordmarkStyleCount = 11;
49
+ export const wordmarkStyleIndexSchema = z
50
+ .number()
51
+ .int()
52
+ .min(0)
53
+ .max(wordmarkStyleCount - 1);
54
+ export const logoTreatmentOverridesSchema = z
55
+ .object({
56
+ family: z.string().min(1).max(200).optional(),
57
+ ink: hexColorSchema.optional(),
58
+ accent: hexColorSchema.optional(),
59
+ styleSeed: z.string().min(1).max(64).optional(),
60
+ styleIndex: wordmarkStyleIndexSchema.optional(),
61
+ })
62
+ .refine((v) => v.family !== undefined ||
63
+ v.ink !== undefined ||
64
+ v.accent !== undefined ||
65
+ v.styleSeed !== undefined ||
66
+ v.styleIndex !== undefined, {
67
+ message: "At least one of family, ink, accent, styleIndex, or styleSeed is required.",
68
+ });
69
+ export const refineRequestSchema = z.union([
70
+ z.object({ instruction: z.string().min(1).max(500) }),
71
+ logoTreatmentOverridesSchema,
72
+ ]);
73
+ export const logoTreatmentSchema = z.object({
74
+ family: z.string(),
75
+ ink: hexColorSchema,
76
+ accent: hexColorSchema,
77
+ style_seed: z.string(),
78
+ style_index: wordmarkStyleIndexSchema.nullable(),
79
+ });
80
+ export const logoTreatmentPreviewQuerySchema = z.object({
81
+ family: z.string().min(1).max(200).optional(),
82
+ ink: hexColorSchema.optional(),
83
+ accent: hexColorSchema.optional(),
84
+ style_seed: z.string().min(1).max(64).optional(),
85
+ style_index: z.coerce
86
+ .number()
87
+ .int()
88
+ .min(0)
89
+ .max(wordmarkStyleCount - 1)
90
+ .optional(),
91
+ });
92
+ export const logoVariationPresets = [
93
+ "more_minimal",
94
+ "more_startup",
95
+ "bolder",
96
+ "playful",
97
+ "elegant",
98
+ "geometric",
99
+ "hand_drawn",
100
+ "monochrome",
101
+ ];
102
+ export const variationRequestSchema = z.object({
103
+ preset: z.enum(logoVariationPresets),
104
+ });
105
+ export const restoreRequestSchema = z.object({
106
+ to_version: z.string().min(1),
107
+ });
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ export declare const subscriptionSchema: z.ZodObject<{
3
+ plan: z.ZodEnum<{
4
+ studio: "studio";
5
+ free: "free";
6
+ pro: "pro";
7
+ agency: "agency";
8
+ }>;
9
+ status: z.ZodNullable<z.ZodString>;
10
+ next_billed_at: z.ZodNullable<z.ZodString>;
11
+ cancel_at_period_end: z.ZodBoolean;
12
+ pending_plan: z.ZodNullable<z.ZodEnum<{
13
+ studio: "studio";
14
+ free: "free";
15
+ pro: "pro";
16
+ agency: "agency";
17
+ }>>;
18
+ plan_change_effective_at: z.ZodNullable<z.ZodString>;
19
+ }, z.core.$strip>;
20
+ export type Subscription = z.infer<typeof subscriptionSchema>;
21
+ export declare const checkoutRequestSchema: z.ZodObject<{
22
+ price_id: z.ZodString;
23
+ success_url: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strip>;
25
+ export type CheckoutRequest = z.infer<typeof checkoutRequestSchema>;
26
+ export declare const changePlanRequestSchema: z.ZodObject<{
27
+ price_id: z.ZodString;
28
+ }, z.core.$strip>;
29
+ export type ChangePlanRequest = z.infer<typeof changePlanRequestSchema>;
30
+ export declare const billingCatalogSchema: z.ZodObject<{
31
+ plans: z.ZodObject<{
32
+ pro: z.ZodNullable<z.ZodString>;
33
+ studio: z.ZodNullable<z.ZodString>;
34
+ agency: z.ZodNullable<z.ZodString>;
35
+ }, z.core.$strip>;
36
+ topups: z.ZodObject<{
37
+ "100": z.ZodNullable<z.ZodString>;
38
+ "300": z.ZodNullable<z.ZodString>;
39
+ "1000": z.ZodNullable<z.ZodString>;
40
+ }, z.core.$strip>;
41
+ }, z.core.$strip>;
42
+ export type BillingCatalog = z.infer<typeof billingCatalogSchema>;
43
+ export declare const autoTopupSchema: z.ZodObject<{
44
+ enabled: z.ZodBoolean;
45
+ pack_credits: z.ZodNullable<z.ZodUnion<readonly [z.ZodLiteral<100>, z.ZodLiteral<300>, z.ZodLiteral<1000>]>>;
46
+ }, z.core.$strip>;
47
+ export type AutoTopup = z.infer<typeof autoTopupSchema>;
48
+ export declare const updateAutoTopupRequestSchema: z.ZodObject<{
49
+ enabled: z.ZodBoolean;
50
+ pack_credits: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<100>, z.ZodLiteral<300>, z.ZodLiteral<1000>]>>;
51
+ }, z.core.$strip>;
52
+ export type UpdateAutoTopupRequest = z.infer<typeof updateAutoTopupRequestSchema>;
53
+ export declare const paymentMethodSchema: z.ZodObject<{
54
+ brand: z.ZodString;
55
+ last4: z.ZodString;
56
+ exp_month: z.ZodNumber;
57
+ exp_year: z.ZodNumber;
58
+ }, z.core.$strip>;
59
+ export type PaymentMethod = z.infer<typeof paymentMethodSchema>;
60
+ export declare const invoiceSchema: z.ZodObject<{
61
+ id: z.ZodString;
62
+ status: z.ZodString;
63
+ total: z.ZodNullable<z.ZodString>;
64
+ currency: z.ZodNullable<z.ZodString>;
65
+ billed_at: z.ZodNullable<z.ZodString>;
66
+ invoice_number: z.ZodNullable<z.ZodString>;
67
+ url: z.ZodNullable<z.ZodString>;
68
+ }, z.core.$strip>;
69
+ export type Invoice = z.infer<typeof invoiceSchema>;
70
+ export declare const checkoutSessionSchema: z.ZodObject<{
71
+ id: z.ZodString;
72
+ status: z.ZodEnum<{
73
+ failed: "failed";
74
+ pending: "pending";
75
+ paid: "paid";
76
+ cancelled: "cancelled";
77
+ }>;
78
+ kind: z.ZodEnum<{
79
+ plan: "plan";
80
+ topup: "topup";
81
+ }>;
82
+ plan: z.ZodNullable<z.ZodEnum<{
83
+ studio: "studio";
84
+ free: "free";
85
+ pro: "pro";
86
+ agency: "agency";
87
+ }>>;
88
+ credits: z.ZodNullable<z.ZodNumber>;
89
+ amount: z.ZodNullable<z.ZodString>;
90
+ currency: z.ZodNullable<z.ZodString>;
91
+ created_at: z.ZodString;
92
+ settled_at: z.ZodNullable<z.ZodString>;
93
+ }, z.core.$strip>;
94
+ export type CheckoutSession = z.infer<typeof checkoutSessionSchema>;
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ export const subscriptionSchema = z.object({
3
+ plan: z.enum(["free", "pro", "studio", "agency"]),
4
+ status: z.string().nullable(),
5
+ next_billed_at: z.string().datetime().nullable(),
6
+ cancel_at_period_end: z.boolean(),
7
+ pending_plan: z.enum(["free", "pro", "studio", "agency"]).nullable(),
8
+ plan_change_effective_at: z.string().datetime().nullable(),
9
+ });
10
+ export const checkoutRequestSchema = z.object({
11
+ price_id: z.string().min(1),
12
+ success_url: z.string().url().optional(),
13
+ });
14
+ export const changePlanRequestSchema = z.object({
15
+ price_id: z.string().min(1),
16
+ });
17
+ export const billingCatalogSchema = z.object({
18
+ plans: z.object({
19
+ pro: z.string().nullable(),
20
+ studio: z.string().nullable(),
21
+ agency: z.string().nullable(),
22
+ }),
23
+ topups: z.object({
24
+ "100": z.string().nullable(),
25
+ "300": z.string().nullable(),
26
+ "1000": z.string().nullable(),
27
+ }),
28
+ });
29
+ export const autoTopupSchema = z.object({
30
+ enabled: z.boolean(),
31
+ pack_credits: z.union([z.literal(100), z.literal(300), z.literal(1000)]).nullable(),
32
+ });
33
+ export const updateAutoTopupRequestSchema = z
34
+ .object({
35
+ enabled: z.boolean(),
36
+ pack_credits: z.union([z.literal(100), z.literal(300), z.literal(1000)]).optional(),
37
+ })
38
+ .refine((v) => !v.enabled || v.pack_credits !== undefined, {
39
+ message: "pack_credits is required when enabling auto top-up.",
40
+ path: ["pack_credits"],
41
+ });
42
+ export const paymentMethodSchema = z.object({
43
+ brand: z.string(),
44
+ last4: z.string(),
45
+ exp_month: z.number().int().min(1).max(12),
46
+ exp_year: z.number().int(),
47
+ });
48
+ export const invoiceSchema = z.object({
49
+ id: z.string(),
50
+ status: z.string(),
51
+ total: z.string().nullable(),
52
+ currency: z.string().nullable(),
53
+ billed_at: z.string().datetime().nullable(),
54
+ invoice_number: z.string().nullable(),
55
+ url: z.string().url().nullable(),
56
+ });
57
+ export const checkoutSessionSchema = z.object({
58
+ id: z.string(),
59
+ status: z.enum(["pending", "paid", "failed", "cancelled"]),
60
+ kind: z.enum(["plan", "topup"]),
61
+ plan: z.enum(["free", "pro", "studio", "agency"]).nullable(),
62
+ credits: z.number().int().nullable(),
63
+ amount: z.string().nullable(),
64
+ currency: z.string().nullable(),
65
+ created_at: z.string().datetime(),
66
+ settled_at: z.string().datetime().nullable(),
67
+ });