@cimplify/sdk 0.44.16 → 0.44.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advanced.js +22 -21
- package/dist/advanced.mjs +3 -2
- package/dist/{chunk-MBGQP6FZ.js → chunk-3FS3ZDKX.js} +60 -60
- package/dist/{chunk-UXLQ7WXI.mjs → chunk-5OK3YDZC.mjs} +2 -2
- package/dist/{chunk-MNIKXG7W.js → chunk-BN2CXGMO.js} +5 -272
- package/dist/chunk-GLOO4HUN.mjs +676 -0
- package/dist/{chunk-CFD4J32N.js → chunk-HBRCVJL4.js} +22 -21
- package/dist/{chunk-ZLEFMQC6.mjs → chunk-KSKZAXG2.mjs} +4 -498
- package/dist/{chunk-6AZZ6AOF.mjs → chunk-NRT6PVW5.mjs} +4 -251
- package/dist/{chunk-XL4CX75J.js → chunk-PGSM3NQ2.js} +237 -781
- package/dist/chunk-Q4I7JRGO.js +733 -0
- package/dist/chunk-QBQCMQ4F.js +271 -0
- package/dist/chunk-XPXAZXF2.mjs +250 -0
- package/dist/{chunk-7NML226B.mjs → chunk-XZPO5GEM.mjs} +2 -1
- package/dist/client-B_Ei3ENB.d.mts +86 -0
- package/dist/client-Bep2FooI.d.ts +86 -0
- package/dist/index.js +145 -144
- package/dist/index.mjs +4 -3
- package/dist/mock/cli.mjs +2 -0
- package/dist/mock/library.js +2 -0
- package/dist/mock/library.mjs +2 -0
- package/dist/mock/msw.js +2 -0
- package/dist/mock/msw.mjs +2 -0
- package/dist/react.js +81 -80
- package/dist/react.mjs +4 -3
- package/dist/server.js +6 -5
- package/dist/server.mjs +4 -3
- package/dist/testing/msw.d.mts +17 -0
- package/dist/testing/msw.d.ts +17 -0
- package/dist/testing/msw.js +42 -0
- package/dist/testing/msw.mjs +40 -0
- package/dist/testing/suite.d.mts +25 -0
- package/dist/testing/suite.d.ts +25 -0
- package/dist/testing/suite.js +28 -23
- package/dist/testing/suite.mjs +9 -4
- package/dist/testing.d.mts +963 -135
- package/dist/testing.d.ts +963 -135
- package/dist/testing.js +123 -59
- package/dist/testing.mjs +51 -4
- package/dist/utils.js +29 -28
- package/dist/utils.mjs +2 -1
- package/package.json +11 -2
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
import { createCimplifyClient } from './chunk-5OK3YDZC.mjs';
|
|
2
|
+
import { createMockApp } from './chunk-KSKZAXG2.mjs';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
var cimplifyRegistry = z.registry();
|
|
6
|
+
function registerSchema(schema, meta) {
|
|
7
|
+
cimplifyRegistry.add(schema, meta);
|
|
8
|
+
return schema;
|
|
9
|
+
}
|
|
10
|
+
var MoneySchema = registerSchema(
|
|
11
|
+
z.string().regex(/^-?\d+\.\d{2}$/, 'Money must be a decimal string with exactly 2 decimals (e.g. "12.50")'),
|
|
12
|
+
{ id: "Money", description: "Strict 2-decimal money string", version: "1.0.0" }
|
|
13
|
+
);
|
|
14
|
+
var MoneyLooseSchema = registerSchema(
|
|
15
|
+
z.string().regex(/^-?\d+(\.\d+)?$/, "Must be a decimal string"),
|
|
16
|
+
{ id: "MoneyLoose", description: "Decimal string with arbitrary precision", version: "1.0.0" }
|
|
17
|
+
);
|
|
18
|
+
var IsoDateTimeSchema = registerSchema(z.iso.datetime(), {
|
|
19
|
+
id: "IsoDateTime",
|
|
20
|
+
description: "ISO 8601 date-time",
|
|
21
|
+
version: "1.0.0"
|
|
22
|
+
});
|
|
23
|
+
var TimestampSchema = registerSchema(
|
|
24
|
+
z.union([z.iso.datetime(), z.string().min(1)]),
|
|
25
|
+
{
|
|
26
|
+
id: "Timestamp",
|
|
27
|
+
description: "ISO 8601 or any non-empty string (boundary use)",
|
|
28
|
+
version: "1.0.0"
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
var CurrencyCodeSchema = registerSchema(
|
|
32
|
+
z.string().length(3, "currency must be a 3-letter ISO 4217 code").regex(/^[A-Z]{3}$/, "currency must be uppercase letters"),
|
|
33
|
+
{ id: "CurrencyCode", description: "ISO 4217 currency code", version: "1.0.0" }
|
|
34
|
+
);
|
|
35
|
+
var CountryCodeSchema = registerSchema(
|
|
36
|
+
z.string().length(2, "countryCode must be ISO 3166-1 alpha-2").regex(/^[A-Z]{2}$/, "countryCode must be uppercase letters"),
|
|
37
|
+
{ id: "CountryCode", description: "ISO 3166-1 alpha-2 country code", version: "1.0.0" }
|
|
38
|
+
);
|
|
39
|
+
var LocaleSchema = registerSchema(
|
|
40
|
+
z.string().regex(/^[a-z]{2}(_[A-Z]{2})?$/, "locale must look like 'en' or 'en_GH'"),
|
|
41
|
+
{ id: "Locale", description: "BCP-47-ish locale", version: "1.0.0" }
|
|
42
|
+
);
|
|
43
|
+
var PhoneE164Schema = registerSchema(
|
|
44
|
+
z.string().regex(/^\+?[0-9]{7,15}$/, "phoneTel should be E.164-ish digits (7\u201315)"),
|
|
45
|
+
{ id: "PhoneE164", description: "E.164-ish phone number", version: "1.0.0" }
|
|
46
|
+
);
|
|
47
|
+
var SeedNameSchema = registerSchema(
|
|
48
|
+
z.enum([
|
|
49
|
+
"default",
|
|
50
|
+
"empty",
|
|
51
|
+
"reesa-storefront",
|
|
52
|
+
"restaurant",
|
|
53
|
+
"retail",
|
|
54
|
+
"services",
|
|
55
|
+
"grocery",
|
|
56
|
+
"fashion"
|
|
57
|
+
]),
|
|
58
|
+
{ id: "SeedName", description: "Mock seed identifier", version: "1.0.0" }
|
|
59
|
+
);
|
|
60
|
+
var ProductTypeSchema = registerSchema(
|
|
61
|
+
z.enum(["product", "service", "digital", "bundle", "composite"]),
|
|
62
|
+
{ id: "ProductType", description: "Product type discriminator", version: "1.0.0" }
|
|
63
|
+
);
|
|
64
|
+
var LineTypeSchema = registerSchema(
|
|
65
|
+
z.enum(["simple", "service", "digital", "bundle", "composite"]),
|
|
66
|
+
{ id: "LineType", description: "Cart line type discriminator", version: "1.0.0" }
|
|
67
|
+
);
|
|
68
|
+
var ServiceStatusSchema = registerSchema(
|
|
69
|
+
z.enum(["pending", "confirmed", "completed", "cancelled"]),
|
|
70
|
+
{ id: "ServiceStatus", description: "Service booking status", version: "1.0.0" }
|
|
71
|
+
);
|
|
72
|
+
var SchemaViolationError = class extends Error {
|
|
73
|
+
constructor(message, label, issues) {
|
|
74
|
+
super(message);
|
|
75
|
+
this.label = label;
|
|
76
|
+
this.issues = issues;
|
|
77
|
+
this.name = "SchemaViolationError";
|
|
78
|
+
}
|
|
79
|
+
toJSON() {
|
|
80
|
+
return {
|
|
81
|
+
type: "https://cimplify.io/errors/schema-violation",
|
|
82
|
+
title: "Schema Violation",
|
|
83
|
+
status: 422,
|
|
84
|
+
detail: `${this.label} did not match its schema`,
|
|
85
|
+
errors: this.issues
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function makeAssertion(schema, label) {
|
|
90
|
+
return (value) => {
|
|
91
|
+
const result = schema.safeParse(value);
|
|
92
|
+
if (!result.success) {
|
|
93
|
+
const pretty = z.prettifyError(result.error);
|
|
94
|
+
const issues = result.error.issues.map((i) => ({
|
|
95
|
+
path: i.path.map(String),
|
|
96
|
+
message: i.message,
|
|
97
|
+
code: i.code
|
|
98
|
+
}));
|
|
99
|
+
throw new SchemaViolationError(
|
|
100
|
+
`${label} schema violation:
|
|
101
|
+
${pretty}`,
|
|
102
|
+
label,
|
|
103
|
+
issues
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
var BrandSocialSchema = z.object({
|
|
109
|
+
label: z.string().min(1),
|
|
110
|
+
href: z.string().url(),
|
|
111
|
+
icon: z.string().optional()
|
|
112
|
+
});
|
|
113
|
+
var BrandNavLinkSchema = z.object({
|
|
114
|
+
label: z.string().min(1),
|
|
115
|
+
href: z.string().min(1)
|
|
116
|
+
});
|
|
117
|
+
var BrandPolicySectionSchema = z.object({
|
|
118
|
+
heading: z.string().min(1),
|
|
119
|
+
body: z.union([
|
|
120
|
+
z.string().min(1),
|
|
121
|
+
z.object({ intro: z.string(), bullets: z.array(z.string()).min(1) })
|
|
122
|
+
])
|
|
123
|
+
});
|
|
124
|
+
var BrandPolicyPageSchema = z.object({
|
|
125
|
+
eyebrow: z.string(),
|
|
126
|
+
title: z.string().min(1),
|
|
127
|
+
lastUpdated: z.string().min(1),
|
|
128
|
+
sections: z.array(BrandPolicySectionSchema).min(1)
|
|
129
|
+
});
|
|
130
|
+
var BrandContactSchema = z.object({
|
|
131
|
+
email: z.string().email(),
|
|
132
|
+
phone: z.string().min(1),
|
|
133
|
+
phoneTel: PhoneE164Schema,
|
|
134
|
+
streetAddress: z.string().min(1),
|
|
135
|
+
city: z.string().min(1),
|
|
136
|
+
countryCode: CountryCodeSchema,
|
|
137
|
+
hours: z.string().optional()
|
|
138
|
+
});
|
|
139
|
+
var BrandHeroSchema = z.object({
|
|
140
|
+
badge: z.string().optional(),
|
|
141
|
+
title: z.string().min(1),
|
|
142
|
+
subtitle: z.string().min(1),
|
|
143
|
+
primaryCta: BrandNavLinkSchema.optional(),
|
|
144
|
+
secondaryCta: BrandNavLinkSchema.optional()
|
|
145
|
+
});
|
|
146
|
+
var BrandFaqSchema = z.object({
|
|
147
|
+
eyebrow: z.string().optional(),
|
|
148
|
+
title: z.string().min(1),
|
|
149
|
+
sections: z.array(
|
|
150
|
+
z.object({
|
|
151
|
+
title: z.string(),
|
|
152
|
+
items: z.array(z.object({ q: z.string(), a: z.string() }))
|
|
153
|
+
})
|
|
154
|
+
)
|
|
155
|
+
});
|
|
156
|
+
var BrandSchema = registerSchema(
|
|
157
|
+
z.object({
|
|
158
|
+
// Identity
|
|
159
|
+
name: z.string().min(1),
|
|
160
|
+
shortName: z.string().min(1),
|
|
161
|
+
microTag: z.string(),
|
|
162
|
+
description: z.string().min(20, "description should be at least 20 characters"),
|
|
163
|
+
schemaType: z.string().min(1),
|
|
164
|
+
currency: CurrencyCodeSchema,
|
|
165
|
+
locale: LocaleSchema,
|
|
166
|
+
contact: BrandContactSchema,
|
|
167
|
+
socials: z.array(BrandSocialSchema),
|
|
168
|
+
header: z.object({ nav: z.array(BrandNavLinkSchema).min(1) }),
|
|
169
|
+
hero: BrandHeroSchema,
|
|
170
|
+
// Optional sections — render conditionally when present
|
|
171
|
+
trustItems: z.array(z.object({ title: z.string().min(1), body: z.string().min(1) })).optional(),
|
|
172
|
+
brandStrip: z.object({ headline: z.string(), logos: z.array(z.string()).min(1) }).optional(),
|
|
173
|
+
promo: z.object({
|
|
174
|
+
eyebrow: z.string().optional(),
|
|
175
|
+
title: z.string().min(1),
|
|
176
|
+
cta: BrandNavLinkSchema
|
|
177
|
+
}).optional(),
|
|
178
|
+
// Standalone policy pages
|
|
179
|
+
terms: BrandPolicyPageSchema,
|
|
180
|
+
privacy: BrandPolicyPageSchema,
|
|
181
|
+
shipping: BrandPolicyPageSchema,
|
|
182
|
+
returns: BrandPolicyPageSchema,
|
|
183
|
+
accessibility: BrandPolicyPageSchema,
|
|
184
|
+
// Misc
|
|
185
|
+
newsletter: z.object({
|
|
186
|
+
eyebrow: z.string().optional(),
|
|
187
|
+
title: z.string().min(1),
|
|
188
|
+
body: z.string()
|
|
189
|
+
}),
|
|
190
|
+
about: z.object({
|
|
191
|
+
eyebrow: z.string().optional(),
|
|
192
|
+
title: z.string().min(1),
|
|
193
|
+
body: z.union([z.string(), z.array(z.string())])
|
|
194
|
+
}),
|
|
195
|
+
faq: BrandFaqSchema,
|
|
196
|
+
account: z.object({
|
|
197
|
+
eyebrow: z.string().optional(),
|
|
198
|
+
title: z.string().min(1),
|
|
199
|
+
signin: z.object({ eyebrow: z.string().optional(), title: z.string().min(1) }).optional(),
|
|
200
|
+
signup: z.object({ eyebrow: z.string().optional(), title: z.string().min(1) }).optional()
|
|
201
|
+
}),
|
|
202
|
+
contactPage: z.object({
|
|
203
|
+
eyebrow: z.string().optional(),
|
|
204
|
+
title: z.string().min(1),
|
|
205
|
+
body: z.string()
|
|
206
|
+
}),
|
|
207
|
+
trackOrder: z.object({
|
|
208
|
+
eyebrow: z.string().optional(),
|
|
209
|
+
title: z.string().min(1),
|
|
210
|
+
body: z.string()
|
|
211
|
+
}),
|
|
212
|
+
footer: z.object({
|
|
213
|
+
sitemap: z.array(z.unknown()).optional(),
|
|
214
|
+
poweredBy: z.string().optional()
|
|
215
|
+
}),
|
|
216
|
+
llms: z.object({ summary: z.string().min(20) }),
|
|
217
|
+
mock: z.object({
|
|
218
|
+
seed: SeedNameSchema,
|
|
219
|
+
businessId: z.string().regex(/^bus_/, "businessId should start with 'bus_'")
|
|
220
|
+
})
|
|
221
|
+
}),
|
|
222
|
+
{
|
|
223
|
+
id: "Brand",
|
|
224
|
+
description: "Single-source-of-truth contract for lib/brand.ts in storefront templates",
|
|
225
|
+
version: "1.0.0"
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
var assertBrand = makeAssertion(BrandSchema, "brand");
|
|
229
|
+
var BundleSelectionInputSchema = z.object({
|
|
230
|
+
component_id: z.string(),
|
|
231
|
+
variant_id: z.string().optional(),
|
|
232
|
+
quantity: z.number().int().positive(),
|
|
233
|
+
scheduled_start: z.string().optional(),
|
|
234
|
+
scheduled_end: z.string().optional()
|
|
235
|
+
});
|
|
236
|
+
var CompositeSelectionInputSchema = z.object({
|
|
237
|
+
component_id: z.string().optional(),
|
|
238
|
+
source_product_id: z.string().optional(),
|
|
239
|
+
source_stock_id: z.string().optional(),
|
|
240
|
+
source_type: z.enum(["product", "stock", "add_on", "standalone"]).optional(),
|
|
241
|
+
quantity: z.number().int().positive().optional()
|
|
242
|
+
});
|
|
243
|
+
var CustomerInputValueSchema = z.object({
|
|
244
|
+
field_id: z.string(),
|
|
245
|
+
field_name: z.string().optional(),
|
|
246
|
+
field_type: z.string().optional(),
|
|
247
|
+
value: z.unknown()
|
|
248
|
+
});
|
|
249
|
+
var AddItemPayloadSchema = registerSchema(
|
|
250
|
+
z.object({
|
|
251
|
+
item_id: z.string().min(1),
|
|
252
|
+
quantity: z.number().int().positive(),
|
|
253
|
+
variant_id: z.string().optional(),
|
|
254
|
+
quote_id: z.string().optional(),
|
|
255
|
+
add_on_options: z.array(z.string()).optional(),
|
|
256
|
+
bundle_selections: z.array(BundleSelectionInputSchema).optional(),
|
|
257
|
+
composite_selections: z.array(CompositeSelectionInputSchema).optional(),
|
|
258
|
+
scheduled_start: z.string().optional(),
|
|
259
|
+
scheduled_end: z.string().optional(),
|
|
260
|
+
staff_id: z.string().optional(),
|
|
261
|
+
resource_id: z.string().optional(),
|
|
262
|
+
special_instructions: z.string().optional(),
|
|
263
|
+
customer_inputs: z.array(CustomerInputValueSchema).optional(),
|
|
264
|
+
billing_plan_id: z.string().optional(),
|
|
265
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
266
|
+
}),
|
|
267
|
+
{
|
|
268
|
+
id: "AddItemPayload",
|
|
269
|
+
description: "POST /cart/items request body \u2014 strict on shape, lenient on optional fields",
|
|
270
|
+
version: "1.0.0"
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
var assertAddItemPayload = makeAssertion(AddItemPayloadSchema, "payload");
|
|
274
|
+
var VariantDisplayAttributeSchema = z.object({
|
|
275
|
+
axis_id: z.string(),
|
|
276
|
+
axis_name: z.string(),
|
|
277
|
+
value_id: z.string(),
|
|
278
|
+
value_name: z.string()
|
|
279
|
+
});
|
|
280
|
+
var VariantInfoSchema = registerSchema(
|
|
281
|
+
z.object({
|
|
282
|
+
id: z.string(),
|
|
283
|
+
name: z.string(),
|
|
284
|
+
sku: z.string().optional(),
|
|
285
|
+
price: MoneySchema,
|
|
286
|
+
price_adjustment: MoneySchema,
|
|
287
|
+
is_default: z.boolean(),
|
|
288
|
+
display_attributes: z.array(VariantDisplayAttributeSchema).optional(),
|
|
289
|
+
images: z.array(z.string()).optional()
|
|
290
|
+
}),
|
|
291
|
+
{
|
|
292
|
+
id: "VariantInfo",
|
|
293
|
+
description: "Variant axis values + display attributes \u2014 emitted on cart line items",
|
|
294
|
+
version: "1.1.0"
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
var VariantDetailsSchema = z.object({
|
|
298
|
+
variant_id: z.string(),
|
|
299
|
+
sku: z.string().optional(),
|
|
300
|
+
properties: z.record(z.string(), z.string())
|
|
301
|
+
});
|
|
302
|
+
var ChosenPriceSchema = z.object({
|
|
303
|
+
base_price: MoneySchema,
|
|
304
|
+
final_price: MoneySchema,
|
|
305
|
+
markup_percentage: MoneySchema,
|
|
306
|
+
markup_amount: MoneySchema,
|
|
307
|
+
markup_discount_percentage: MoneySchema,
|
|
308
|
+
markup_discount_amount: MoneySchema
|
|
309
|
+
});
|
|
310
|
+
var SelectedAddOnOptionSchema = registerSchema(
|
|
311
|
+
z.object({
|
|
312
|
+
option_id: z.string(),
|
|
313
|
+
add_on_id: z.string(),
|
|
314
|
+
name: z.string(),
|
|
315
|
+
price: MoneySchema,
|
|
316
|
+
quantity: z.number().int().nonnegative(),
|
|
317
|
+
is_required: z.boolean(),
|
|
318
|
+
selected_at: TimestampSchema,
|
|
319
|
+
price_info: z.unknown().optional()
|
|
320
|
+
}),
|
|
321
|
+
{
|
|
322
|
+
id: "SelectedAddOnOption",
|
|
323
|
+
description: "A specific add-on option chosen for a cart line",
|
|
324
|
+
version: "1.0.0"
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
var AddOnInDetailsSchema = registerSchema(
|
|
328
|
+
z.object({
|
|
329
|
+
add_on_id: z.string(),
|
|
330
|
+
name: z.string(),
|
|
331
|
+
min_selections: z.number().int().nonnegative(),
|
|
332
|
+
max_selections: z.number().int().nonnegative(),
|
|
333
|
+
selected_options: z.array(z.string()),
|
|
334
|
+
is_required: z.boolean()
|
|
335
|
+
}),
|
|
336
|
+
{
|
|
337
|
+
id: "AddOnInDetails",
|
|
338
|
+
description: "Add-on group as embedded inside add_on_details \u2014 selected_options is an ID list",
|
|
339
|
+
version: "1.0.0"
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
var AddOnDetailsSchema = registerSchema(
|
|
343
|
+
z.object({
|
|
344
|
+
selected_options: z.array(SelectedAddOnOptionSchema),
|
|
345
|
+
total_add_on_price: MoneySchema,
|
|
346
|
+
add_ons: z.array(AddOnInDetailsSchema)
|
|
347
|
+
}),
|
|
348
|
+
{
|
|
349
|
+
id: "AddOnDetails",
|
|
350
|
+
description: "Combined add-on selection state for a cart line",
|
|
351
|
+
version: "1.0.0"
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
var AddOnOptionDetailsSchema = registerSchema(
|
|
355
|
+
z.object({
|
|
356
|
+
id: z.string(),
|
|
357
|
+
name: z.string(),
|
|
358
|
+
is_required: z.boolean(),
|
|
359
|
+
description: z.string().optional(),
|
|
360
|
+
price: MoneySchema.optional(),
|
|
361
|
+
image_url: z.string().optional()
|
|
362
|
+
}),
|
|
363
|
+
{
|
|
364
|
+
id: "AddOnOptionDetails",
|
|
365
|
+
description: "Option-level details (one per chosen add-on option)",
|
|
366
|
+
version: "1.0.0"
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
var AddOnGroupDetailsSchema = registerSchema(
|
|
370
|
+
z.object({
|
|
371
|
+
id: z.string(),
|
|
372
|
+
name: z.string(),
|
|
373
|
+
is_multiple_allowed: z.boolean(),
|
|
374
|
+
min_selections: z.number().int().nonnegative(),
|
|
375
|
+
max_selections: z.number().int().nonnegative(),
|
|
376
|
+
required: z.boolean(),
|
|
377
|
+
options: z.array(AddOnOptionDetailsSchema)
|
|
378
|
+
}),
|
|
379
|
+
{
|
|
380
|
+
id: "AddOnGroupDetails",
|
|
381
|
+
description: "Group-level details for an add-on; contains its options",
|
|
382
|
+
version: "1.0.0"
|
|
383
|
+
}
|
|
384
|
+
);
|
|
385
|
+
var BundleResolvedSchema = z.looseObject({
|
|
386
|
+
bundle_id: z.string(),
|
|
387
|
+
selections: z.array(z.unknown())
|
|
388
|
+
});
|
|
389
|
+
var CompositeResolvedSchema = z.looseObject({
|
|
390
|
+
composite_id: z.string(),
|
|
391
|
+
selections: z.array(z.unknown()),
|
|
392
|
+
breakdown: z.object({
|
|
393
|
+
base_price: MoneySchema,
|
|
394
|
+
components_total: MoneySchema,
|
|
395
|
+
final_price: MoneySchema,
|
|
396
|
+
tier_applied: z.string().optional()
|
|
397
|
+
}).optional()
|
|
398
|
+
});
|
|
399
|
+
var DiscountDetailsSchema = z.object({
|
|
400
|
+
applied_count: z.number().int().nonnegative(),
|
|
401
|
+
total_amount: MoneySchema,
|
|
402
|
+
discount_ids: z.array(z.string())
|
|
403
|
+
});
|
|
404
|
+
var CartItemSchema = registerSchema(
|
|
405
|
+
z.looseObject({
|
|
406
|
+
id: z.string(),
|
|
407
|
+
cart_id: z.string(),
|
|
408
|
+
item_id: z.string(),
|
|
409
|
+
quantity: z.number().int().nonnegative(),
|
|
410
|
+
line_key: z.string(),
|
|
411
|
+
line_type: LineTypeSchema,
|
|
412
|
+
name: z.string(),
|
|
413
|
+
description: z.string().optional(),
|
|
414
|
+
image_url: z.string().optional(),
|
|
415
|
+
category_id: z.string().optional(),
|
|
416
|
+
category_name: z.string().optional(),
|
|
417
|
+
is_available: z.boolean(),
|
|
418
|
+
variant_id: z.string().optional(),
|
|
419
|
+
variant_name: z.string().optional(),
|
|
420
|
+
variant_info: VariantInfoSchema.optional(),
|
|
421
|
+
variant_details: VariantDetailsSchema.optional(),
|
|
422
|
+
base_price: MoneySchema,
|
|
423
|
+
add_ons_price: MoneySchema,
|
|
424
|
+
total_price: MoneySchema,
|
|
425
|
+
item_discount_amount: MoneySchema,
|
|
426
|
+
price_info: ChosenPriceSchema,
|
|
427
|
+
add_on_option_ids: z.array(z.string()),
|
|
428
|
+
add_on_ids: z.array(z.string()),
|
|
429
|
+
add_on_details: AddOnDetailsSchema,
|
|
430
|
+
add_on_options: z.array(AddOnOptionDetailsSchema),
|
|
431
|
+
add_ons: z.array(AddOnGroupDetailsSchema),
|
|
432
|
+
scheduled_start: z.string().optional(),
|
|
433
|
+
scheduled_end: z.string().optional(),
|
|
434
|
+
staff_id: z.string().optional(),
|
|
435
|
+
resource_id: z.string().optional(),
|
|
436
|
+
service_status: ServiceStatusSchema.optional(),
|
|
437
|
+
confirmation_code: z.string().optional(),
|
|
438
|
+
special_instructions: z.string().optional(),
|
|
439
|
+
customer_inputs: z.array(CustomerInputValueSchema).optional(),
|
|
440
|
+
bundle_selections: z.unknown().optional(),
|
|
441
|
+
bundle_resolved: BundleResolvedSchema.optional(),
|
|
442
|
+
composite_selections: z.unknown().optional(),
|
|
443
|
+
composite_resolved: CompositeResolvedSchema.optional(),
|
|
444
|
+
billing_plan_id: z.string().optional(),
|
|
445
|
+
applied_discount_ids: z.array(z.string()),
|
|
446
|
+
discount_details: DiscountDetailsSchema.optional(),
|
|
447
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
448
|
+
created_at: TimestampSchema,
|
|
449
|
+
updated_at: TimestampSchema
|
|
450
|
+
}),
|
|
451
|
+
{
|
|
452
|
+
id: "CartItem",
|
|
453
|
+
description: "Cart line item \u2014 loose so backend additions don't break old SDK clients",
|
|
454
|
+
version: "1.0.0"
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
var assertCartItem = makeAssertion(CartItemSchema, "cartItem");
|
|
458
|
+
var CartPricingSchema = registerSchema(
|
|
459
|
+
z.object({
|
|
460
|
+
subtotal: MoneySchema,
|
|
461
|
+
total_discounts: MoneySchema,
|
|
462
|
+
tax_amount: MoneySchema,
|
|
463
|
+
service_charge: MoneySchema,
|
|
464
|
+
total_price: MoneySchema,
|
|
465
|
+
currency: CurrencyCodeSchema,
|
|
466
|
+
tax_rate: MoneySchema.optional(),
|
|
467
|
+
service_charge_rate: MoneySchema.optional()
|
|
468
|
+
}),
|
|
469
|
+
{
|
|
470
|
+
id: "CartPricing",
|
|
471
|
+
description: "Cart-level pricing roll-up \u2014 subtotal, tax, service, total",
|
|
472
|
+
version: "1.0.0"
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
var CartSchema = registerSchema(
|
|
476
|
+
z.looseObject({
|
|
477
|
+
id: z.string(),
|
|
478
|
+
business_id: z.string(),
|
|
479
|
+
items: z.array(CartItemSchema),
|
|
480
|
+
pricing: CartPricingSchema,
|
|
481
|
+
customer_info: z.object({
|
|
482
|
+
name: z.string(),
|
|
483
|
+
email: z.string().optional(),
|
|
484
|
+
phone: z.string().optional(),
|
|
485
|
+
address: z.string().optional()
|
|
486
|
+
}),
|
|
487
|
+
created_at: TimestampSchema,
|
|
488
|
+
updated_at: TimestampSchema,
|
|
489
|
+
expires_at: TimestampSchema,
|
|
490
|
+
status: z.string(),
|
|
491
|
+
source: z.string(),
|
|
492
|
+
channel: z.string()
|
|
493
|
+
}),
|
|
494
|
+
{
|
|
495
|
+
id: "Cart",
|
|
496
|
+
description: "Full cart envelope \u2014 loose for forward-compat with backend additions",
|
|
497
|
+
version: "1.0.0"
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
var assertCart = makeAssertion(CartSchema, "cart");
|
|
501
|
+
var CheckoutCustomerSchema = z.object({
|
|
502
|
+
name: z.string().min(1),
|
|
503
|
+
email: z.string().email(),
|
|
504
|
+
phone: z.string().min(1),
|
|
505
|
+
notes: z.string().optional(),
|
|
506
|
+
save_details: z.boolean().optional()
|
|
507
|
+
});
|
|
508
|
+
var CheckoutBodySchema = registerSchema(
|
|
509
|
+
z.object({
|
|
510
|
+
cart_id: z.string().min(1),
|
|
511
|
+
location_id: z.string().optional(),
|
|
512
|
+
customer: CheckoutCustomerSchema,
|
|
513
|
+
order_type: z.string().min(1),
|
|
514
|
+
address_info: z.record(z.string(), z.unknown()).optional(),
|
|
515
|
+
payment_method: z.string().min(1),
|
|
516
|
+
mobile_money_details: z.object({ phone_number: z.string(), provider: z.string() }).optional(),
|
|
517
|
+
special_instructions: z.string().optional(),
|
|
518
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
519
|
+
pay_currency: z.string().optional(),
|
|
520
|
+
fx_quote_id: z.string().optional()
|
|
521
|
+
}),
|
|
522
|
+
{
|
|
523
|
+
id: "CheckoutBody",
|
|
524
|
+
description: "POST /checkout request body",
|
|
525
|
+
version: "1.0.0"
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
var assertCheckoutBody = makeAssertion(CheckoutBodySchema, "checkoutBody");
|
|
529
|
+
var AuthorizationTypeSchema = z.enum(["otp", "pin", "phone", "birthday", "address"]);
|
|
530
|
+
var NextActionSchema = z.discriminatedUnion("type", [
|
|
531
|
+
z.object({ type: z.literal("none") }),
|
|
532
|
+
z.object({ type: z.literal("redirect"), authorization_url: z.string() }),
|
|
533
|
+
z.object({
|
|
534
|
+
type: z.literal("authorization"),
|
|
535
|
+
authorization_type: z.string(),
|
|
536
|
+
display_text: z.string().optional()
|
|
537
|
+
})
|
|
538
|
+
]);
|
|
539
|
+
var CheckoutResponseSchema = registerSchema(
|
|
540
|
+
z.looseObject({
|
|
541
|
+
order_id: z.string().min(1),
|
|
542
|
+
order_number: z.string().min(1),
|
|
543
|
+
payment_status: z.string().min(1),
|
|
544
|
+
payment_reference: z.string().optional(),
|
|
545
|
+
requires_authorization: z.boolean(),
|
|
546
|
+
authorization_type: AuthorizationTypeSchema.optional(),
|
|
547
|
+
next_action: NextActionSchema,
|
|
548
|
+
provider: z.string().optional(),
|
|
549
|
+
authorization_url: z.string().optional(),
|
|
550
|
+
display_text: z.string().optional(),
|
|
551
|
+
bill_token: z.string().optional(),
|
|
552
|
+
client_secret: z.string().optional(),
|
|
553
|
+
public_key: z.string().optional()
|
|
554
|
+
}),
|
|
555
|
+
{
|
|
556
|
+
id: "CheckoutResponse",
|
|
557
|
+
description: "POST /checkout response \u2014 loose for payment-provider field additions",
|
|
558
|
+
version: "1.0.0"
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
var assertCheckoutResponse = makeAssertion(CheckoutResponseSchema, "checkout");
|
|
562
|
+
|
|
563
|
+
// src/testing/client.ts
|
|
564
|
+
var TEST_BASE_URL = "http://test.local";
|
|
565
|
+
async function toForwardedRequest(input, init) {
|
|
566
|
+
if (input instanceof Request) {
|
|
567
|
+
return {
|
|
568
|
+
method: init?.method ?? input.method,
|
|
569
|
+
headers: new Headers(init?.headers ?? input.headers),
|
|
570
|
+
body: init?.body ?? (["GET", "HEAD"].includes(input.method) ? void 0 : await input.text())
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
method: init?.method ?? "GET",
|
|
575
|
+
headers: new Headers(init?.headers ?? {}),
|
|
576
|
+
body: init?.body ?? void 0
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
function createTestClient(options = {}) {
|
|
580
|
+
const mock = createMockApp(options);
|
|
581
|
+
let sessionToken;
|
|
582
|
+
const fetchImpl = async (input, init) => {
|
|
583
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
584
|
+
if (!url.startsWith(TEST_BASE_URL)) {
|
|
585
|
+
return globalThis.fetch(input, init);
|
|
586
|
+
}
|
|
587
|
+
const path = url.slice(TEST_BASE_URL.length);
|
|
588
|
+
const fwd = await toForwardedRequest(input, init);
|
|
589
|
+
if (sessionToken) fwd.headers.set("x-session-token", sessionToken);
|
|
590
|
+
const res = await mock.request(path, {
|
|
591
|
+
method: fwd.method,
|
|
592
|
+
headers: fwd.headers,
|
|
593
|
+
body: fwd.body
|
|
594
|
+
});
|
|
595
|
+
const echoed = res.headers.get("x-session-token");
|
|
596
|
+
if (echoed) sessionToken = echoed;
|
|
597
|
+
return res;
|
|
598
|
+
};
|
|
599
|
+
const client = createCimplifyClient({
|
|
600
|
+
baseUrl: TEST_BASE_URL,
|
|
601
|
+
publicKey: "test-public-key",
|
|
602
|
+
suppressPublicKeyWarning: true,
|
|
603
|
+
fetch: fetchImpl
|
|
604
|
+
});
|
|
605
|
+
return {
|
|
606
|
+
client,
|
|
607
|
+
mock,
|
|
608
|
+
reset: () => {
|
|
609
|
+
mock.deps.resetAll();
|
|
610
|
+
sessionToken = void 0;
|
|
611
|
+
},
|
|
612
|
+
dispose: () => {
|
|
613
|
+
mock.deps.resetAll();
|
|
614
|
+
sessionToken = void 0;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
async function pickProduct(client, opts) {
|
|
619
|
+
const list = await client.catalogue.getProducts();
|
|
620
|
+
if (!list.ok) throw list.error;
|
|
621
|
+
const body = list.value;
|
|
622
|
+
const products = body.items ?? [];
|
|
623
|
+
if (products.length === 0) throw new Error("No products in catalogue (wrong seed?)");
|
|
624
|
+
if (opts.slug) {
|
|
625
|
+
const found = products.find((p) => p.slug === opts.slug);
|
|
626
|
+
if (!found) throw new Error(`Product slug "${opts.slug}" not found in catalogue`);
|
|
627
|
+
return found;
|
|
628
|
+
}
|
|
629
|
+
return products.find((p) => p.type === "product") ?? products[0];
|
|
630
|
+
}
|
|
631
|
+
var fixtures = {
|
|
632
|
+
/**
|
|
633
|
+
* Add the first available product (or a named one) to the cart.
|
|
634
|
+
* Picks the first variant if the product has variants.
|
|
635
|
+
*/
|
|
636
|
+
async addFirstProduct(client, opts = {}) {
|
|
637
|
+
const product = await pickProduct(client, opts);
|
|
638
|
+
let variantId;
|
|
639
|
+
if (opts.withVariant !== false) {
|
|
640
|
+
const variants = await client.catalogue.getVariants(product.id);
|
|
641
|
+
if (variants.ok && variants.value.length > 0) {
|
|
642
|
+
variantId = variants.value[0]?.id;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const res = await client.cart.addItem({
|
|
646
|
+
item_id: product.id,
|
|
647
|
+
quantity: 1,
|
|
648
|
+
variant_id: variantId
|
|
649
|
+
});
|
|
650
|
+
if (!res.ok) throw res.error;
|
|
651
|
+
return { product, variantId };
|
|
652
|
+
},
|
|
653
|
+
/** A minimal valid customer object for checkout. */
|
|
654
|
+
customer(overrides = {}) {
|
|
655
|
+
return {
|
|
656
|
+
name: overrides.name ?? "Test Customer",
|
|
657
|
+
email: overrides.email ?? "test@example.com",
|
|
658
|
+
phone: overrides.phone ?? "+233244000000"
|
|
659
|
+
};
|
|
660
|
+
},
|
|
661
|
+
/**
|
|
662
|
+
* Run the full guest auth flow (request OTP → verify) and return
|
|
663
|
+
* the new session token. The mock's permissive auth mode echoes
|
|
664
|
+
* the code in `request_otp`, so we don't need to read it.
|
|
665
|
+
*/
|
|
666
|
+
async authenticate(client, contact = "test@example.com", code = "123456") {
|
|
667
|
+
const req = await client.auth.requestOtp(contact);
|
|
668
|
+
if (!req.ok) throw req.error;
|
|
669
|
+
const verify = await client.auth.verifyOtp(contact, code);
|
|
670
|
+
if (!verify.ok) throw verify.error;
|
|
671
|
+
const value = verify.value;
|
|
672
|
+
return { token: value.session_token ?? "", customerId: value.customer_id ?? "" };
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
export { AddItemPayloadSchema, AddOnDetailsSchema, AddOnGroupDetailsSchema, AddOnInDetailsSchema, AddOnOptionDetailsSchema, AuthorizationTypeSchema, BrandContactSchema, BrandFaqSchema, BrandHeroSchema, BrandNavLinkSchema, BrandPolicyPageSchema, BrandPolicySectionSchema, BrandSchema, BrandSocialSchema, BundleResolvedSchema, BundleSelectionInputSchema, CartItemSchema, CartPricingSchema, CartSchema, CheckoutBodySchema, CheckoutCustomerSchema, CheckoutResponseSchema, ChosenPriceSchema, CompositeResolvedSchema, CompositeSelectionInputSchema, CountryCodeSchema, CurrencyCodeSchema, CustomerInputValueSchema, DiscountDetailsSchema, IsoDateTimeSchema, LineTypeSchema, LocaleSchema, MoneyLooseSchema, MoneySchema, NextActionSchema, PhoneE164Schema, ProductTypeSchema, SchemaViolationError, SeedNameSchema, SelectedAddOnOptionSchema, ServiceStatusSchema, TimestampSchema, VariantDetailsSchema, VariantDisplayAttributeSchema, VariantInfoSchema, assertAddItemPayload, assertBrand, assertCart, assertCartItem, assertCheckoutBody, assertCheckoutResponse, cimplifyRegistry, createTestClient, fixtures, makeAssertion, registerSchema };
|