@businessdash/sdk 0.9.60 → 0.9.70
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/README.md +1012 -186
- package/assets/biab-sw.js +92 -0
- package/dist/account-core/index.d.ts +126 -0
- package/dist/account-core/index.d.ts.map +1 -0
- package/dist/account-core/index.js +191 -0
- package/dist/account-core/index.js.map +1 -0
- package/dist/account.d.ts +11 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +11 -0
- package/dist/account.js.map +1 -0
- package/dist/auth-handler.d.ts +1 -1
- package/dist/auth-links.d.ts +33 -0
- package/dist/auth-links.d.ts.map +1 -0
- package/dist/auth-links.js +64 -0
- package/dist/auth-links.js.map +1 -0
- package/dist/blog-core/index.d.ts +112 -0
- package/dist/blog-core/index.d.ts.map +1 -0
- package/dist/blog-core/index.js +330 -0
- package/dist/blog-core/index.js.map +1 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +11 -0
- package/dist/blog.js.map +1 -0
- package/dist/chat-core/index.d.ts +97 -0
- package/dist/chat-core/index.d.ts.map +1 -0
- package/dist/chat-core/index.js +237 -0
- package/dist/chat-core/index.js.map +1 -0
- package/dist/chat.d.ts +11 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +11 -0
- package/dist/chat.js.map +1 -0
- package/dist/checkout-core/index.d.ts +65 -0
- package/dist/checkout-core/index.d.ts.map +1 -0
- package/dist/checkout-core/index.js +159 -0
- package/dist/checkout-core/index.js.map +1 -0
- package/dist/checkout.d.ts +10 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +10 -0
- package/dist/checkout.js.map +1 -0
- package/dist/cli.js +133 -25
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +567 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +807 -1
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +3309 -761
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +541 -4
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +1 -1
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/element.d.ts +30 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +56 -0
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +86 -0
- package/dist/embed-protocol.d.ts.map +1 -0
- package/dist/embed-protocol.js +60 -0
- package/dist/embed-protocol.js.map +1 -0
- package/dist/framework-support.d.ts +122 -0
- package/dist/framework-support.d.ts.map +1 -0
- package/dist/framework-support.js +323 -0
- package/dist/framework-support.js.map +1 -0
- package/dist/index.cjs +1244 -5
- package/dist/legal-core/index.cjs +115 -0
- package/dist/legal-core/index.d.ts +160 -0
- package/dist/legal-core/index.d.ts.map +1 -0
- package/dist/legal-core/index.js +220 -0
- package/dist/legal-core/index.js.map +1 -0
- package/dist/marketing-core/index.d.ts +66 -0
- package/dist/marketing-core/index.d.ts.map +1 -0
- package/dist/marketing-core/index.js +154 -0
- package/dist/marketing-core/index.js.map +1 -0
- package/dist/marketing.d.ts +7 -0
- package/dist/marketing.d.ts.map +1 -0
- package/dist/marketing.js +7 -0
- package/dist/marketing.js.map +1 -0
- package/dist/mcp-adapters/index.d.ts +135 -0
- package/dist/mcp-adapters/index.d.ts.map +1 -0
- package/dist/mcp-adapters/index.js +187 -0
- package/dist/mcp-adapters/index.js.map +1 -0
- package/dist/mcp-adapters.d.ts +7 -0
- package/dist/mcp-adapters.d.ts.map +1 -0
- package/dist/mcp-adapters.js +7 -0
- package/dist/mcp-adapters.js.map +1 -0
- package/dist/model3d-core/index.cjs +95 -0
- package/dist/model3d-core/index.d.ts +167 -0
- package/dist/model3d-core/index.d.ts.map +1 -0
- package/dist/model3d-core/index.js +158 -0
- package/dist/model3d-core/index.js.map +1 -0
- package/dist/notifications-core/index.cjs +315 -0
- package/dist/notifications-core/index.d.ts +229 -0
- package/dist/notifications-core/index.d.ts.map +1 -0
- package/dist/notifications-core/index.js +445 -0
- package/dist/notifications-core/index.js.map +1 -0
- package/dist/portal-core/index.d.ts +451 -0
- package/dist/portal-core/index.d.ts.map +1 -0
- package/dist/portal-core/index.js +819 -0
- package/dist/portal-core/index.js.map +1 -0
- package/dist/portal.d.ts +7 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +7 -0
- package/dist/portal.js.map +1 -0
- package/dist/push-core/index.cjs +171 -0
- package/dist/push-core/index.d.ts +149 -0
- package/dist/push-core/index.d.ts.map +1 -0
- package/dist/push-core/index.js +231 -0
- package/dist/push-core/index.js.map +1 -0
- package/dist/react-marketing.d.ts +1 -17
- package/dist/react-marketing.d.ts.map +1 -1
- package/dist/react-marketing.js +4 -0
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +294 -101
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +302 -246
- package/dist/react.js.map +1 -1
- package/dist/seed-core/index.d.ts +354 -0
- package/dist/seed-core/index.d.ts.map +1 -0
- package/dist/seed-core/index.js +420 -0
- package/dist/seed-core/index.js.map +1 -0
- package/dist/seed.d.ts +7 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +7 -0
- package/dist/seed.js.map +1 -0
- package/dist/seo-core/blog.d.ts +94 -0
- package/dist/seo-core/blog.d.ts.map +1 -0
- package/dist/seo-core/blog.js +149 -0
- package/dist/seo-core/blog.js.map +1 -0
- package/dist/seo-core/commerce.d.ts +64 -0
- package/dist/seo-core/commerce.d.ts.map +1 -0
- package/dist/seo-core/commerce.js +87 -0
- package/dist/seo-core/commerce.js.map +1 -0
- package/dist/seo-core/index.cjs +751 -0
- package/dist/seo-core/index.d.ts +226 -0
- package/dist/seo-core/index.d.ts.map +1 -0
- package/dist/seo-core/index.js +455 -0
- package/dist/seo-core/index.js.map +1 -0
- package/dist/seo-core/local.d.ts +181 -0
- package/dist/seo-core/local.d.ts.map +1 -0
- package/dist/seo-core/local.js +193 -0
- package/dist/seo-core/local.js.map +1 -0
- package/dist/sitemap-core/index.cjs +167 -0
- package/dist/sitemap-core/index.d.ts +155 -0
- package/dist/sitemap-core/index.d.ts.map +1 -0
- package/dist/sitemap-core/index.js +195 -0
- package/dist/sitemap-core/index.js.map +1 -0
- package/dist/social-core/index.d.ts +74 -0
- package/dist/social-core/index.d.ts.map +1 -0
- package/dist/social-core/index.js +72 -0
- package/dist/social-core/index.js.map +1 -0
- package/dist/social.d.ts +7 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +7 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-compat.d.ts +204 -0
- package/dist/solid-compat.d.ts.map +1 -0
- package/dist/solid-compat.js +221 -0
- package/dist/solid-compat.js.map +1 -0
- package/dist/store-core/index.d.ts +141 -0
- package/dist/store-core/index.d.ts.map +1 -0
- package/dist/store-core/index.js +277 -0
- package/dist/store-core/index.js.map +1 -0
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +12 -0
- package/dist/store.js.map +1 -0
- package/dist/vanilla.d.ts +111 -0
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +206 -0
- package/dist/vanilla.js.map +1 -1
- package/dist/verify-core/index.d.ts +98 -0
- package/dist/verify-core/index.d.ts.map +1 -0
- package/dist/verify-core/index.js +186 -0
- package/dist/verify-core/index.js.map +1 -0
- package/dist/verify.d.ts +8 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +8 -0
- package/dist/verify.js.map +1 -0
- package/openapi.json +4316 -1313
- package/package.json +121 -9
- package/src/account-core/index.ts +309 -0
- package/src/account.ts +11 -0
- package/src/angular/headless.ts +519 -0
- package/src/angular/index.ts +3 -0
- package/src/auth-links.ts +76 -0
- package/src/blog-core/index.ts +423 -0
- package/src/blog.ts +11 -0
- package/src/chat-core/index.ts +335 -0
- package/src/chat.ts +11 -0
- package/src/checkout-core/index.ts +225 -0
- package/src/checkout.ts +10 -0
- package/src/cli.ts +184 -28
- package/src/client.ts +998 -0
- package/src/contracts.ts +730 -11
- package/src/data-model-schema.ts +1 -1
- package/src/element.ts +102 -0
- package/src/embed-protocol.ts +100 -0
- package/src/framework-support.ts +440 -0
- package/src/legal-core/index.ts +276 -0
- package/src/marketing-core/index.ts +209 -0
- package/src/marketing.ts +7 -0
- package/src/mcp-adapters/index.ts +264 -0
- package/src/mcp-adapters.ts +7 -0
- package/src/model3d-core/index.ts +248 -0
- package/src/notifications-core/index.ts +650 -0
- package/src/portal-core/index.ts +1564 -0
- package/src/portal.ts +7 -0
- package/src/push-core/index.ts +335 -0
- package/src/qwik.tsx +602 -2
- package/src/react-marketing.tsx +5 -0
- package/src/react.tsx +434 -319
- package/src/seed-core/index.ts +735 -0
- package/src/seed.ts +7 -0
- package/src/seo-core/blog.ts +216 -0
- package/src/seo-core/commerce.ts +138 -0
- package/src/seo-core/index.ts +605 -0
- package/src/seo-core/local.ts +333 -0
- package/src/sitemap-core/index.ts +296 -0
- package/src/social-core/index.ts +103 -0
- package/src/social.ts +7 -0
- package/src/solid-compat.tsx +347 -0
- package/src/solid-surfaces.tsx +1311 -0
- package/src/solid.tsx +82 -60
- package/src/store-core/index.ts +426 -0
- package/src/store.ts +12 -0
- package/src/svelte/SocialLinks.svelte +84 -0
- package/src/svelte/headless.ts +435 -0
- package/src/svelte/index.ts +9 -0
- package/src/vanilla.ts +367 -0
- package/src/verify-core/index.ts +288 -0
- package/src/verify.ts +8 -0
- package/src/vue/headless.ts +527 -0
- package/src/vue/index.ts +3 -0
package/src/contracts.ts
CHANGED
|
@@ -541,21 +541,44 @@ export const chatbotFormFieldSchema = z
|
|
|
541
541
|
.passthrough();
|
|
542
542
|
export type ChatbotFormField = z.infer<typeof chatbotFormFieldSchema>;
|
|
543
543
|
|
|
544
|
-
export const chatbotFormDefinitionSchema = z
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
544
|
+
export const chatbotFormDefinitionSchema = z
|
|
545
|
+
.object({
|
|
546
|
+
id: z.string(),
|
|
547
|
+
slug: z.string(),
|
|
548
|
+
name: z.string(),
|
|
549
|
+
description: z.string(),
|
|
550
|
+
fields: z.array(chatbotFormFieldSchema),
|
|
551
|
+
addsInquiry: z.boolean(),
|
|
552
|
+
addsLead: z.boolean(),
|
|
553
|
+
/**
|
|
554
|
+
* The RENDER contract — animation, multi-step + progress style, exit
|
|
555
|
+
* confirmation, URL safety. The server has always sent this; the schema
|
|
556
|
+
* dropped it, so anyone building a form UI on the typed client got a
|
|
557
|
+
* bare field list and none of the behaviour the dashboard configured.
|
|
558
|
+
*/
|
|
559
|
+
settings: z.record(z.unknown()).nullish(),
|
|
560
|
+
/** Org avatar for the form header, when the form opts in. */
|
|
561
|
+
orgIcon: z.string().nullish(),
|
|
562
|
+
/** Public action previews ("submitting adds you to the list"). */
|
|
563
|
+
actions: z.array(z.record(z.unknown())).nullish(),
|
|
564
|
+
/** Non-sensitive business functions so `calculation` fields compute. */
|
|
565
|
+
businessFunctions: z.array(z.record(z.unknown())).nullish(),
|
|
566
|
+
})
|
|
567
|
+
// Additive server fields reach consumers instead of being silently dropped
|
|
568
|
+
// — the failure this schema just demonstrated.
|
|
569
|
+
.passthrough();
|
|
553
570
|
export type ChatbotFormDefinition = z.infer<typeof chatbotFormDefinitionSchema>;
|
|
554
571
|
|
|
555
572
|
export const chatbotFormSubmitInputSchema = z.object({
|
|
556
573
|
data: z.record(z.unknown()),
|
|
557
574
|
submitterEmail: z.string().email().optional(),
|
|
558
575
|
submitterName: z.string().optional(),
|
|
576
|
+
/** Validate and run the full pipeline WITHOUT persisting. */
|
|
577
|
+
dryRun: z.boolean().optional(),
|
|
578
|
+
/** Provenance the route accepts and this schema previously omitted. */
|
|
579
|
+
source: z.string().max(200).optional(),
|
|
580
|
+
referrer: z.string().max(500).optional(),
|
|
581
|
+
metadata: z.record(z.unknown()).optional(),
|
|
559
582
|
priorChat: z
|
|
560
583
|
.array(
|
|
561
584
|
z.object({
|
|
@@ -573,8 +596,14 @@ export type ChatbotFormSubmitInput = z.infer<
|
|
|
573
596
|
|
|
574
597
|
export const chatbotFormSubmitResponseSchema = z.object({
|
|
575
598
|
success: z.literal(true),
|
|
576
|
-
|
|
599
|
+
/**
|
|
600
|
+
* NULL on a dry run — the submission validated but was deliberately not
|
|
601
|
+
* persisted. Requiring a string here made every test submit throw.
|
|
602
|
+
*/
|
|
603
|
+
submissionId: z.string().nullable(),
|
|
577
604
|
slug: z.string(),
|
|
605
|
+
/** True when nothing was written. Pairs with a null `submissionId`. */
|
|
606
|
+
dryRun: z.boolean().optional(),
|
|
578
607
|
});
|
|
579
608
|
export type ChatbotFormSubmitResponse = z.infer<
|
|
580
609
|
typeof chatbotFormSubmitResponseSchema
|
|
@@ -1496,6 +1525,16 @@ export const customerReturnRequestSchema = z.object({
|
|
|
1496
1525
|
* are separate enums and each is spelled as the database spells it.
|
|
1497
1526
|
*/
|
|
1498
1527
|
status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
|
|
1528
|
+
/**
|
|
1529
|
+
* What was asked for: money back, or a replacement. Mirrors
|
|
1530
|
+
* `order_return_request_kind`. Rows created before this existed read
|
|
1531
|
+
* `refund`, which is what they were.
|
|
1532
|
+
*/
|
|
1533
|
+
kind: openEnum("refund", "exchange"),
|
|
1534
|
+
/** On an exchange: the variant wanted instead, when one was chosen. */
|
|
1535
|
+
exchangeForVariantId: z.string().nullable(),
|
|
1536
|
+
/** Set once a replacement ships — track it like any other shipment. */
|
|
1537
|
+
exchangeShipmentId: z.string().nullable(),
|
|
1499
1538
|
reason: z.string().nullable(),
|
|
1500
1539
|
items: z
|
|
1501
1540
|
.array(
|
|
@@ -1542,6 +1581,16 @@ export const customerOrderDetailSchema = z.object({
|
|
|
1542
1581
|
|
|
1543
1582
|
/** Input for `submitReturnRequest`. Omit `items` for a whole-order request. */
|
|
1544
1583
|
export const customerReturnRequestInputSchema = z.object({
|
|
1584
|
+
/**
|
|
1585
|
+
* `refund` returns the money; `exchange` asks for a replacement. Defaults
|
|
1586
|
+
* to `refund`, so an omitted field means what it always meant.
|
|
1587
|
+
*/
|
|
1588
|
+
kind: z.enum(["refund", "exchange"]).optional(),
|
|
1589
|
+
/**
|
|
1590
|
+
* On an exchange, the variant wanted instead. Optional even then — "a
|
|
1591
|
+
* different size" is a real request that needs a conversation first.
|
|
1592
|
+
*/
|
|
1593
|
+
exchangeForVariantId: z.string().uuid().optional(),
|
|
1545
1594
|
reason: z.string().max(120).optional(),
|
|
1546
1595
|
customerNote: z.string().max(2000).optional(),
|
|
1547
1596
|
items: z
|
|
@@ -1559,6 +1608,372 @@ export const customerReturnRequestCreatedSchema = z.object({
|
|
|
1559
1608
|
id: z.string().nullable(),
|
|
1560
1609
|
/** Mirrors the `order_return_request_status` pg enum. */
|
|
1561
1610
|
status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
|
|
1611
|
+
/** Echoes back what was opened, so a UI need not assume. */
|
|
1612
|
+
kind: openEnum("refund", "exchange"),
|
|
1613
|
+
createdAt: z.string().nullable(),
|
|
1614
|
+
});
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* Result of reporting that a parcel never arrived.
|
|
1618
|
+
*
|
|
1619
|
+
* `carrierStatus` is the carrier's own verdict, UNTOUCHED by the report — the
|
|
1620
|
+
* two facts travel together on purpose. When `contested` is true the carrier
|
|
1621
|
+
* says delivered and the customer says otherwise, which is the case an org
|
|
1622
|
+
* needs to see first.
|
|
1623
|
+
*/
|
|
1624
|
+
export const customerNotReceivedResultSchema = z.object({
|
|
1625
|
+
id: z.string(),
|
|
1626
|
+
/** True when a claim was already open; the original report is unchanged. */
|
|
1627
|
+
alreadyOpen: z.boolean(),
|
|
1628
|
+
reportedAt: z.string(),
|
|
1629
|
+
carrierStatus: openEnum(
|
|
1630
|
+
"pending",
|
|
1631
|
+
"label_created",
|
|
1632
|
+
"in_transit",
|
|
1633
|
+
"delivered",
|
|
1634
|
+
"returned",
|
|
1635
|
+
),
|
|
1636
|
+
carrierDeliveredAt: z.string().nullable(),
|
|
1637
|
+
contested: z.boolean().optional(),
|
|
1638
|
+
});
|
|
1639
|
+
|
|
1640
|
+
/** How an org's legal pages are dressed. Shared by all of them. */
|
|
1641
|
+
export const legalPresentationSchema = z.object({
|
|
1642
|
+
/** Already resolved against the company logo — render as given. */
|
|
1643
|
+
logoUrl: z.string().nullable(),
|
|
1644
|
+
showLogoInHeader: z.boolean(),
|
|
1645
|
+
showLogoInFooter: z.boolean(),
|
|
1646
|
+
headerHtml: z.string().nullable(),
|
|
1647
|
+
footerHtml: z.string().nullable(),
|
|
1648
|
+
});
|
|
1649
|
+
|
|
1650
|
+
/** A legal page in a list — enough for a footer, without the body. */
|
|
1651
|
+
export const legalDocumentSummarySchema = z.object({
|
|
1652
|
+
/** The URL path, without a leading slash: `privacy`, `terms`, … */
|
|
1653
|
+
slug: z.string(),
|
|
1654
|
+
title: z.string(),
|
|
1655
|
+
version: z.number(),
|
|
1656
|
+
/** ISO 8601. Render as "Last updated". */
|
|
1657
|
+
effectiveDate: z.string().nullable(),
|
|
1658
|
+
showInFooter: z.boolean(),
|
|
1659
|
+
updatedAt: z.string(),
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
export const legalListResponseSchema = z.object({
|
|
1663
|
+
items: z.array(legalDocumentSummarySchema),
|
|
1664
|
+
presentation: legalPresentationSchema,
|
|
1665
|
+
});
|
|
1666
|
+
|
|
1667
|
+
/** One legal page, body included. */
|
|
1668
|
+
export const legalDocumentSchema = legalDocumentSummarySchema.extend({
|
|
1669
|
+
/** Sanitised server-side on write, so this is safe to render as HTML. */
|
|
1670
|
+
contentHtml: z.string(),
|
|
1671
|
+
presentation: legalPresentationSchema,
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
export type LegalPresentation = z.infer<typeof legalPresentationSchema>;
|
|
1675
|
+
export type LegalDocumentSummary = z.infer<typeof legalDocumentSummarySchema>;
|
|
1676
|
+
export type LegalListResponse = z.infer<typeof legalListResponseSchema>;
|
|
1677
|
+
export type LegalDocument = z.infer<typeof legalDocumentSchema>;
|
|
1678
|
+
|
|
1679
|
+
/** One browser a customer has registered for push. */
|
|
1680
|
+
export const customerPushDeviceSchema = z.object({
|
|
1681
|
+
id: z.string(),
|
|
1682
|
+
endpoint: z.string(),
|
|
1683
|
+
userAgent: z.string().nullable(),
|
|
1684
|
+
label: z.string().nullable(),
|
|
1685
|
+
/** Null = every category. `[]` = none, but the device stays registered. */
|
|
1686
|
+
categories: z.array(z.string()).nullable(),
|
|
1687
|
+
lastSeenAt: z.string().nullable(),
|
|
1688
|
+
createdAt: z.string(),
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* Push config plus this customer's devices.
|
|
1693
|
+
*
|
|
1694
|
+
* `vapidPublicKey` rides along because a page cannot call `subscribe()` without
|
|
1695
|
+
* it, and a second round trip for one string is one nobody remembers to make.
|
|
1696
|
+
* `enabled: false` means the platform has no key configured — render nothing
|
|
1697
|
+
* rather than a button that cannot work.
|
|
1698
|
+
*/
|
|
1699
|
+
export const customerPushConfigSchema = z.object({
|
|
1700
|
+
vapidPublicKey: z.string().nullable(),
|
|
1701
|
+
enabled: z.boolean(),
|
|
1702
|
+
devices: z.array(customerPushDeviceSchema),
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
export type CustomerPushDevice = z.infer<typeof customerPushDeviceSchema>;
|
|
1706
|
+
export type CustomerPushConfig = z.infer<typeof customerPushConfigSchema>;
|
|
1707
|
+
|
|
1708
|
+
/** Result of handing a customer-portal invite link out again. */
|
|
1709
|
+
export const customerInviteResendResponseSchema = z.object({
|
|
1710
|
+
id: z.string(),
|
|
1711
|
+
/** The NEW link. The previous one no longer works. */
|
|
1712
|
+
url: z.string(),
|
|
1713
|
+
expiresAt: z.string().nullable(),
|
|
1714
|
+
/** Includes this send, so a list can show "sent 3 times". */
|
|
1715
|
+
sendCount: z.number(),
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
export type CustomerInviteResendResponse = z.infer<
|
|
1719
|
+
typeof customerInviteResendResponseSchema
|
|
1720
|
+
>;
|
|
1721
|
+
|
|
1722
|
+
// ── Scheduling / conference calls ─────────────────────────────────────
|
|
1723
|
+
//
|
|
1724
|
+
// The booking surface: what an org offers, when it is free, and the three
|
|
1725
|
+
// token-gated things an invitee can do afterwards.
|
|
1726
|
+
//
|
|
1727
|
+
// `conferenceLink` is the conference-call half — a Meet/Zoom/Teams URL minted
|
|
1728
|
+
// when the event type has a provider. It is null until the booking is
|
|
1729
|
+
// confirmed, and re-minted on reschedule, so a UI must read it back after
|
|
1730
|
+
// either rather than caching the one it first saw.
|
|
1731
|
+
|
|
1732
|
+
export const schedulingEventTypeSchema = z.object({
|
|
1733
|
+
id: z.string(),
|
|
1734
|
+
name: z.string(),
|
|
1735
|
+
slug: z.string(),
|
|
1736
|
+
description: z.string().nullable(),
|
|
1737
|
+
durationMinutes: z.number(),
|
|
1738
|
+
locationType: z.string(),
|
|
1739
|
+
/** google_meet | zoom | teams | null when the meeting is in person. */
|
|
1740
|
+
meetingProvider: z.string().nullable(),
|
|
1741
|
+
color: z.string().nullable(),
|
|
1742
|
+
/** When true a booking lands `pending`, not `confirmed`. */
|
|
1743
|
+
requiresApproval: z.boolean(),
|
|
1744
|
+
});
|
|
1745
|
+
|
|
1746
|
+
export const schedulingQuestionSchema = z
|
|
1747
|
+
.object({
|
|
1748
|
+
id: z.string(),
|
|
1749
|
+
label: z.string(),
|
|
1750
|
+
})
|
|
1751
|
+
.passthrough();
|
|
1752
|
+
|
|
1753
|
+
export const schedulingEventTypeListSchema = z.object({
|
|
1754
|
+
eventTypes: z.array(schedulingEventTypeSchema),
|
|
1755
|
+
});
|
|
1756
|
+
|
|
1757
|
+
export const schedulingEventTypeDetailSchema = z.object({
|
|
1758
|
+
eventType: schedulingEventTypeSchema,
|
|
1759
|
+
questions: z.array(schedulingQuestionSchema),
|
|
1760
|
+
});
|
|
1761
|
+
|
|
1762
|
+
export const schedulingSlotSchema = z.object({
|
|
1763
|
+
startAt: z.string(),
|
|
1764
|
+
endAt: z.string(),
|
|
1765
|
+
});
|
|
1766
|
+
|
|
1767
|
+
export const schedulingSlotsResponseSchema = z.object({
|
|
1768
|
+
slots: z.array(schedulingSlotSchema),
|
|
1769
|
+
});
|
|
1770
|
+
|
|
1771
|
+
export const schedulingBookingStatusSchema = openEnum(
|
|
1772
|
+
"pending",
|
|
1773
|
+
"confirmed",
|
|
1774
|
+
"canceled",
|
|
1775
|
+
"rescheduled",
|
|
1776
|
+
);
|
|
1777
|
+
|
|
1778
|
+
export const schedulingBookingViewSchema = z.object({
|
|
1779
|
+
booking: z.object({
|
|
1780
|
+
id: z.string(),
|
|
1781
|
+
startAt: z.string(),
|
|
1782
|
+
endAt: z.string(),
|
|
1783
|
+
status: schedulingBookingStatusSchema,
|
|
1784
|
+
title: z.string(),
|
|
1785
|
+
notes: z.string().nullable(),
|
|
1786
|
+
/** The conference URL, once there is one. */
|
|
1787
|
+
conferenceLink: z.string().nullable(),
|
|
1788
|
+
}),
|
|
1789
|
+
invitee: z
|
|
1790
|
+
.object({ name: z.string(), email: z.string(), timezone: z.string() })
|
|
1791
|
+
.nullable(),
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
export const schedulingBookingResultSchema = z
|
|
1795
|
+
.object({
|
|
1796
|
+
bookingId: z.string(),
|
|
1797
|
+
status: schedulingBookingStatusSchema,
|
|
1798
|
+
/**
|
|
1799
|
+
* Three separate signed tokens, deliberately.
|
|
1800
|
+
*
|
|
1801
|
+
* A cancel link in an email must not also be able to reschedule, and
|
|
1802
|
+
* neither should read the whole booking. Handing out one token for all
|
|
1803
|
+
* three would make every emailed link as powerful as the strongest
|
|
1804
|
+
* action it enables.
|
|
1805
|
+
*/
|
|
1806
|
+
manageToken: z.string(),
|
|
1807
|
+
rescheduleToken: z.string(),
|
|
1808
|
+
cancelToken: z.string(),
|
|
1809
|
+
})
|
|
1810
|
+
.passthrough();
|
|
1811
|
+
|
|
1812
|
+
export const schedulingRescheduleResultSchema = z
|
|
1813
|
+
.object({
|
|
1814
|
+
bookingId: z.string(),
|
|
1815
|
+
startAt: z.string(),
|
|
1816
|
+
endAt: z.string(),
|
|
1817
|
+
/** Re-minted on reschedule — read it back rather than reusing the old one. */
|
|
1818
|
+
conferenceLink: z.string().nullable().optional(),
|
|
1819
|
+
})
|
|
1820
|
+
.passthrough();
|
|
1821
|
+
|
|
1822
|
+
export const schedulingCancelResultSchema = z
|
|
1823
|
+
.object({ ok: z.boolean() })
|
|
1824
|
+
.passthrough();
|
|
1825
|
+
|
|
1826
|
+
export type SchedulingEventTypeContract = z.infer<
|
|
1827
|
+
typeof schedulingEventTypeSchema
|
|
1828
|
+
>;
|
|
1829
|
+
export type SchedulingEventTypeList = z.infer<
|
|
1830
|
+
typeof schedulingEventTypeListSchema
|
|
1831
|
+
>;
|
|
1832
|
+
export type SchedulingEventTypeDetail = z.infer<
|
|
1833
|
+
typeof schedulingEventTypeDetailSchema
|
|
1834
|
+
>;
|
|
1835
|
+
export type SchedulingSlotsResponse = z.infer<
|
|
1836
|
+
typeof schedulingSlotsResponseSchema
|
|
1837
|
+
>;
|
|
1838
|
+
export type SchedulingBookingView = z.infer<typeof schedulingBookingViewSchema>;
|
|
1839
|
+
export type SchedulingBookingResult = z.infer<
|
|
1840
|
+
typeof schedulingBookingResultSchema
|
|
1841
|
+
>;
|
|
1842
|
+
export type SchedulingRescheduleResult = z.infer<
|
|
1843
|
+
typeof schedulingRescheduleResultSchema
|
|
1844
|
+
>;
|
|
1845
|
+
export type SchedulingCancelResult = z.infer<
|
|
1846
|
+
typeof schedulingCancelResultSchema
|
|
1847
|
+
>;
|
|
1848
|
+
|
|
1849
|
+
/** One of the org's live subscription offerings. */
|
|
1850
|
+
export const customerSubscriptionOfferingSchema = z.object({
|
|
1851
|
+
id: z.string(),
|
|
1852
|
+
name: z.string(),
|
|
1853
|
+
description: z.string().nullable(),
|
|
1854
|
+
imageUrl: z.string().nullable(),
|
|
1855
|
+
amountCents: z.number(),
|
|
1856
|
+
interval: z.string(),
|
|
1857
|
+
});
|
|
1858
|
+
|
|
1859
|
+
/** The customer's subscription state with one org. */
|
|
1860
|
+
export const customerSubscriptionSchema = z.object({
|
|
1861
|
+
/** active | expired | cancelled | pending | failed */
|
|
1862
|
+
status: openEnum("active", "expired", "cancelled", "pending", "failed"),
|
|
1863
|
+
/** trial | monthly_subscribed | annual_subscribed | lifetime */
|
|
1864
|
+
type: openEnum(
|
|
1865
|
+
"trial",
|
|
1866
|
+
"monthly_subscribed",
|
|
1867
|
+
"annual_subscribed",
|
|
1868
|
+
"lifetime",
|
|
1869
|
+
).nullable(),
|
|
1870
|
+
/**
|
|
1871
|
+
* The entitlement decision, computed server-side by the same function the
|
|
1872
|
+
* content gates use.
|
|
1873
|
+
*
|
|
1874
|
+
* **Render from this, not from `status`.** Two cases break a naive
|
|
1875
|
+
* `status === "active"` check: a lifetime purchase has no period to expire,
|
|
1876
|
+
* and a cancelled subscription keeps access until the period already paid
|
|
1877
|
+
* for runs out.
|
|
1878
|
+
*/
|
|
1879
|
+
hasAccess: z.boolean(),
|
|
1880
|
+
/**
|
|
1881
|
+
* Cancelled, but the paid period has not ended. The honest label is
|
|
1882
|
+
* "active until {expiresAt}" — not "cancelled".
|
|
1883
|
+
*/
|
|
1884
|
+
cancelledButActive: z.boolean(),
|
|
1885
|
+
startedAt: z.string().nullable(),
|
|
1886
|
+
/** End of the paid period. Null for lifetime. */
|
|
1887
|
+
expiresAt: z.string().nullable(),
|
|
1888
|
+
cancelledAt: z.string().nullable(),
|
|
1889
|
+
renewedAt: z.string().nullable(),
|
|
1890
|
+
trialEndsAt: z.string().nullable(),
|
|
1891
|
+
trialUsed: z.boolean(),
|
|
1892
|
+
provider: z.string().nullable(),
|
|
1893
|
+
/** The offering they are on, when it still exists. */
|
|
1894
|
+
plan: customerSubscriptionOfferingSchema.nullable(),
|
|
1895
|
+
/** Null means the plan includes no service calls at all. */
|
|
1896
|
+
includedServiceCallsPerPeriod: z.number().nullable(),
|
|
1897
|
+
serviceCallsUsedInPeriod: z.number(),
|
|
1898
|
+
periodStartedAt: z.string().nullable(),
|
|
1899
|
+
});
|
|
1900
|
+
|
|
1901
|
+
export const customerSubscriptionResponseSchema = z.object({
|
|
1902
|
+
/** Null when this customer has never subscribed to this org. */
|
|
1903
|
+
subscription: customerSubscriptionSchema.nullable(),
|
|
1904
|
+
/** The org's live offerings, cheapest first. */
|
|
1905
|
+
offerings: z.array(customerSubscriptionOfferingSchema),
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1908
|
+
/** Result of cancelling — or un-cancelling — a subscription. */
|
|
1909
|
+
export const customerSubscriptionCancelResponseSchema = z.object({
|
|
1910
|
+
/** True when a cancellation is now pending at the end of the period. */
|
|
1911
|
+
cancelAtPeriodEnd: z.boolean(),
|
|
1912
|
+
resumed: z.boolean(),
|
|
1913
|
+
/**
|
|
1914
|
+
* Access continues until this moment. Say "active until {this}", because
|
|
1915
|
+
* that is what is true — cancelling ends the renewal, not the access.
|
|
1916
|
+
*/
|
|
1917
|
+
accessUntil: z.string().nullable(),
|
|
1918
|
+
/**
|
|
1919
|
+
* The stored status still reads its old value until the provider's webhook
|
|
1920
|
+
* lands. Render from `cancelAtPeriodEnd`, not from a re-read.
|
|
1921
|
+
*/
|
|
1922
|
+
statusPending: z.boolean(),
|
|
1923
|
+
});
|
|
1924
|
+
|
|
1925
|
+
/** One piece of subscriber-gated content. */
|
|
1926
|
+
export const customerSubscriberContentItemSchema = z.object({
|
|
1927
|
+
id: z.string(),
|
|
1928
|
+
slug: z.string(),
|
|
1929
|
+
title: z.string(),
|
|
1930
|
+
/** The pitch. Travels even when locked — the BODY never does. */
|
|
1931
|
+
excerpt: z.string().nullable(),
|
|
1932
|
+
featuredImageUrl: z.string().nullable(),
|
|
1933
|
+
publishedAt: z.string().nullable(),
|
|
1934
|
+
tags: z.array(z.string()),
|
|
1935
|
+
accessLevel: z.string(),
|
|
1936
|
+
downloadAccessLevel: z.string(),
|
|
1937
|
+
/** False when the post is readable but its downloads are not. */
|
|
1938
|
+
downloadsAvailable: z.boolean(),
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
export const customerSubscriberContentResponseSchema = z.object({
|
|
1942
|
+
items: z.array(customerSubscriberContentItemSchema),
|
|
1943
|
+
/**
|
|
1944
|
+
* False means these are LOCKED previews, not an empty entitlement. Show
|
|
1945
|
+
* them with the offer — an empty list would hide the pitch at exactly the
|
|
1946
|
+
* moment it is most relevant.
|
|
1947
|
+
*/
|
|
1948
|
+
entitled: z.boolean(),
|
|
1949
|
+
});
|
|
1950
|
+
|
|
1951
|
+
/** One product review the customer has written. */
|
|
1952
|
+
export const customerProductReviewSchema = z.object({
|
|
1953
|
+
id: z.string(),
|
|
1954
|
+
productId: z.string(),
|
|
1955
|
+
productName: z.string(),
|
|
1956
|
+
rating: z.number(),
|
|
1957
|
+
content: z.string(),
|
|
1958
|
+
/**
|
|
1959
|
+
* False means QUEUED for the org to approve, not rejected. Surface it as
|
|
1960
|
+
* "awaiting review" — a customer who thinks their review vanished writes it
|
|
1961
|
+
* again, or writes to support.
|
|
1962
|
+
*/
|
|
1963
|
+
isApproved: z.boolean(),
|
|
1964
|
+
createdAt: z.string(),
|
|
1965
|
+
});
|
|
1966
|
+
|
|
1967
|
+
export const customerProductReviewListSchema = z.object({
|
|
1968
|
+
items: z.array(customerProductReviewSchema),
|
|
1969
|
+
});
|
|
1970
|
+
|
|
1971
|
+
/** Result of submitting a product review from the portal. */
|
|
1972
|
+
export const customerProductReviewCreatedSchema = z.object({
|
|
1973
|
+
id: z.string().nullable(),
|
|
1974
|
+
isApproved: z.boolean(),
|
|
1975
|
+
/** The inverse of `isApproved`, named for what the UI should say. */
|
|
1976
|
+
awaitingModeration: z.boolean(),
|
|
1562
1977
|
createdAt: z.string().nullable(),
|
|
1563
1978
|
});
|
|
1564
1979
|
|
|
@@ -1615,6 +2030,32 @@ export type CustomerReturnRequestInput = z.infer<
|
|
|
1615
2030
|
export type CustomerReturnRequestCreated = z.infer<
|
|
1616
2031
|
typeof customerReturnRequestCreatedSchema
|
|
1617
2032
|
>;
|
|
2033
|
+
export type CustomerNotReceivedResult = z.infer<
|
|
2034
|
+
typeof customerNotReceivedResultSchema
|
|
2035
|
+
>;
|
|
2036
|
+
export type CustomerProductReview = z.infer<typeof customerProductReviewSchema>;
|
|
2037
|
+
export type CustomerProductReviewList = z.infer<
|
|
2038
|
+
typeof customerProductReviewListSchema
|
|
2039
|
+
>;
|
|
2040
|
+
export type CustomerProductReviewCreated = z.infer<
|
|
2041
|
+
typeof customerProductReviewCreatedSchema
|
|
2042
|
+
>;
|
|
2043
|
+
export type CustomerSubscriptionOffering = z.infer<
|
|
2044
|
+
typeof customerSubscriptionOfferingSchema
|
|
2045
|
+
>;
|
|
2046
|
+
export type CustomerSubscription = z.infer<typeof customerSubscriptionSchema>;
|
|
2047
|
+
export type CustomerSubscriptionResponse = z.infer<
|
|
2048
|
+
typeof customerSubscriptionResponseSchema
|
|
2049
|
+
>;
|
|
2050
|
+
export type CustomerSubscriptionCancelResponse = z.infer<
|
|
2051
|
+
typeof customerSubscriptionCancelResponseSchema
|
|
2052
|
+
>;
|
|
2053
|
+
export type CustomerSubscriberContentItem = z.infer<
|
|
2054
|
+
typeof customerSubscriberContentItemSchema
|
|
2055
|
+
>;
|
|
2056
|
+
export type CustomerSubscriberContentResponse = z.infer<
|
|
2057
|
+
typeof customerSubscriberContentResponseSchema
|
|
2058
|
+
>;
|
|
1618
2059
|
export type CustomerDownload = z.infer<typeof customerDownloadSchema>;
|
|
1619
2060
|
export type CustomerDownloadsResponse = z.infer<
|
|
1620
2061
|
typeof customerDownloadsResponseSchema
|
|
@@ -1646,6 +2087,148 @@ export type CustomerInvoicePayment = z.infer<
|
|
|
1646
2087
|
export type CustomerPaymentHistoryEntry = z.infer<
|
|
1647
2088
|
typeof customerPaymentHistoryEntrySchema
|
|
1648
2089
|
>;
|
|
2090
|
+
// ── Customer portal: list endpoints (0.9.61) ──────────────────────────
|
|
2091
|
+
//
|
|
2092
|
+
// The portal had detail-by-id routes for invoices, quotes, contracts and
|
|
2093
|
+
// shipments and no way to LIST any of them, so "show me everything I owe" had
|
|
2094
|
+
// no call behind it.
|
|
2095
|
+
//
|
|
2096
|
+
// The rows reuse the existing `customer*SummarySchema` shapes rather than
|
|
2097
|
+
// defining parallel ones — those already carry the right open enums, and two
|
|
2098
|
+
// definitions of "an invoice summary" would drift.
|
|
2099
|
+
|
|
2100
|
+
export const customerInvoiceListResponseSchema = z.object({
|
|
2101
|
+
items: z.array(customerInvoiceSummarySchema),
|
|
2102
|
+
});
|
|
2103
|
+
|
|
2104
|
+
export const customerQuoteListResponseSchema = z.object({
|
|
2105
|
+
items: z.array(customerQuoteSummarySchema),
|
|
2106
|
+
});
|
|
2107
|
+
|
|
2108
|
+
export const customerContractListResponseSchema = z.object({
|
|
2109
|
+
items: z.array(customerContractSummarySchema),
|
|
2110
|
+
});
|
|
2111
|
+
|
|
2112
|
+
/** No summary shape existed for shipments, so this is the first one. */
|
|
2113
|
+
export const customerShipmentSummarySchema = z.object({
|
|
2114
|
+
id: z.string(),
|
|
2115
|
+
orderId: z.string(),
|
|
2116
|
+
orderNumber: z.string().nullable(),
|
|
2117
|
+
carrier: z.string().nullable(),
|
|
2118
|
+
trackingNumber: z.string().nullable(),
|
|
2119
|
+
trackingUrl: z.string().nullable(),
|
|
2120
|
+
serviceName: z.string().nullable(),
|
|
2121
|
+
status: z.string(),
|
|
2122
|
+
/** A date STRING, not a timestamp — the column is text. */
|
|
2123
|
+
estimatedDelivery: z.string().nullable(),
|
|
2124
|
+
shippedAt: z.string().nullable(),
|
|
2125
|
+
deliveredAt: z.string().nullable(),
|
|
2126
|
+
});
|
|
2127
|
+
|
|
2128
|
+
export const customerShipmentListResponseSchema = z.object({
|
|
2129
|
+
items: z.array(customerShipmentSummarySchema),
|
|
2130
|
+
});
|
|
2131
|
+
|
|
2132
|
+
export type CustomerInvoiceListResponse = z.infer<
|
|
2133
|
+
typeof customerInvoiceListResponseSchema
|
|
2134
|
+
>;
|
|
2135
|
+
export type CustomerQuoteListResponse = z.infer<
|
|
2136
|
+
typeof customerQuoteListResponseSchema
|
|
2137
|
+
>;
|
|
2138
|
+
export type CustomerContractListResponse = z.infer<
|
|
2139
|
+
typeof customerContractListResponseSchema
|
|
2140
|
+
>;
|
|
2141
|
+
export type CustomerShipmentSummary = z.infer<
|
|
2142
|
+
typeof customerShipmentSummarySchema
|
|
2143
|
+
>;
|
|
2144
|
+
export type CustomerShipmentListResponse = z.infer<
|
|
2145
|
+
typeof customerShipmentListResponseSchema
|
|
2146
|
+
>;
|
|
2147
|
+
|
|
2148
|
+
// ── Customer portal: staff chat (0.9.61) ──────────────────────────────
|
|
2149
|
+
//
|
|
2150
|
+
// `org_customer_messages` has always carried a `portal` channel and staff have
|
|
2151
|
+
// always read and written it from the CRM timeline. What was missing was any
|
|
2152
|
+
// package-api route, so a customer could be messaged and had no way to read it
|
|
2153
|
+
// back or reply. Both directions land in the SAME table the staff timeline
|
|
2154
|
+
// reads — a reply appears in the CRM beside everything else about that
|
|
2155
|
+
// customer, not in a parallel inbox nobody watches.
|
|
2156
|
+
|
|
2157
|
+
export const customerPortalMessageSchema = z.object({
|
|
2158
|
+
id: z.string(),
|
|
2159
|
+
/** `inbound` = the customer wrote it; `outbound` = staff did. */
|
|
2160
|
+
direction: openEnum("inbound", "outbound"),
|
|
2161
|
+
channel: openEnum("portal", "email", "sms"),
|
|
2162
|
+
authorName: z.string().nullable(),
|
|
2163
|
+
body: z.string(),
|
|
2164
|
+
attachment: z
|
|
2165
|
+
.object({
|
|
2166
|
+
url: z.string(),
|
|
2167
|
+
name: z.string(),
|
|
2168
|
+
mimeType: z.string(),
|
|
2169
|
+
sizeBytes: z.number(),
|
|
2170
|
+
})
|
|
2171
|
+
.nullable(),
|
|
2172
|
+
jobId: z.string().nullable(),
|
|
2173
|
+
readByCustomerAt: z.string().nullable(),
|
|
2174
|
+
createdAt: z.string(),
|
|
2175
|
+
});
|
|
2176
|
+
|
|
2177
|
+
export const customerPortalMessageListResponseSchema = z.object({
|
|
2178
|
+
items: z.array(customerPortalMessageSchema),
|
|
2179
|
+
});
|
|
2180
|
+
|
|
2181
|
+
export const customerPortalMessagePostInputSchema = z.object({
|
|
2182
|
+
body: z.string().min(1).max(4000),
|
|
2183
|
+
/** Thread the message under a specific job. */
|
|
2184
|
+
jobId: z.string().uuid().optional(),
|
|
2185
|
+
});
|
|
2186
|
+
|
|
2187
|
+
export const customerPortalMessagesMarkReadResponseSchema = z.object({
|
|
2188
|
+
marked: z.number(),
|
|
2189
|
+
});
|
|
2190
|
+
|
|
2191
|
+
export type CustomerPortalMessage = z.infer<typeof customerPortalMessageSchema>;
|
|
2192
|
+
export type CustomerPortalMessageListResponse = z.infer<
|
|
2193
|
+
typeof customerPortalMessageListResponseSchema
|
|
2194
|
+
>;
|
|
2195
|
+
export type CustomerPortalMessagePostInput = z.infer<
|
|
2196
|
+
typeof customerPortalMessagePostInputSchema
|
|
2197
|
+
>;
|
|
2198
|
+
export type CustomerPortalMessagesMarkReadResponse = z.infer<
|
|
2199
|
+
typeof customerPortalMessagesMarkReadResponseSchema
|
|
2200
|
+
>;
|
|
2201
|
+
|
|
2202
|
+
// ── Customer portal: return status readback (0.9.61) ──────────────────
|
|
2203
|
+
//
|
|
2204
|
+
// Closes the audit's gap #5. The submit route existed and nothing read the
|
|
2205
|
+
// status back, so a customer could start a return and then had no way to see
|
|
2206
|
+
// what happened to it — which is the exact moment they pick up the phone.
|
|
2207
|
+
|
|
2208
|
+
export const customerReturnRequestStatusSchema = z.object({
|
|
2209
|
+
id: z.string(),
|
|
2210
|
+
/** Mirrors the `order_return_request_status` pg enum. */
|
|
2211
|
+
status: openEnum("requested", "approved", "denied", "refunded", "cancelled"),
|
|
2212
|
+
reason: z.string().nullable(),
|
|
2213
|
+
customerNote: z.string().nullable(),
|
|
2214
|
+
/** Staff's answer. The whole point when a return is denied. */
|
|
2215
|
+
resolutionNote: z.string().nullable(),
|
|
2216
|
+
items: z.array(z.record(z.string(), z.unknown())).nullable(),
|
|
2217
|
+
resolvedAt: z.string().nullable(),
|
|
2218
|
+
createdAt: z.string(),
|
|
2219
|
+
});
|
|
2220
|
+
|
|
2221
|
+
export const customerReturnRequestListResponseSchema = z.object({
|
|
2222
|
+
items: z.array(customerReturnRequestStatusSchema),
|
|
2223
|
+
});
|
|
2224
|
+
|
|
2225
|
+
export type CustomerReturnRequestStatus = z.infer<
|
|
2226
|
+
typeof customerReturnRequestStatusSchema
|
|
2227
|
+
>;
|
|
2228
|
+
export type CustomerReturnRequestListResponse = z.infer<
|
|
2229
|
+
typeof customerReturnRequestListResponseSchema
|
|
2230
|
+
>;
|
|
2231
|
+
|
|
1649
2232
|
export type CustomerPaymentHistoryResponse = z.infer<
|
|
1650
2233
|
typeof customerPaymentHistoryResponseSchema
|
|
1651
2234
|
>;
|
|
@@ -1752,7 +2335,19 @@ export type CustomerContactCompanyResponse = z.infer<
|
|
|
1752
2335
|
export const customerJobEtaAssignmentSchema = z.object({
|
|
1753
2336
|
displayName: z.string(),
|
|
1754
2337
|
role: z.string().nullable(),
|
|
1755
|
-
|
|
2338
|
+
/**
|
|
2339
|
+
* This technician's own stage. `openEnum` because the column is TEXT and
|
|
2340
|
+
* an org's board can grow a value before the SDK knows about it — an
|
|
2341
|
+
* unknown status should render as itself, not break the response.
|
|
2342
|
+
*/
|
|
2343
|
+
dispatchStatus: openEnum(
|
|
2344
|
+
"pending",
|
|
2345
|
+
"en_route",
|
|
2346
|
+
"on_site",
|
|
2347
|
+
"in_progress",
|
|
2348
|
+
"completed",
|
|
2349
|
+
"declined",
|
|
2350
|
+
),
|
|
1756
2351
|
lastKnownLocation: z
|
|
1757
2352
|
.object({
|
|
1758
2353
|
lat: z.number(),
|
|
@@ -1763,6 +2358,35 @@ export const customerJobEtaAssignmentSchema = z.object({
|
|
|
1763
2358
|
});
|
|
1764
2359
|
|
|
1765
2360
|
export const customerJobEtaResponseSchema = z.object({
|
|
2361
|
+
/**
|
|
2362
|
+
* Where the JOB is — promoted from the assignees by the dispatch board,
|
|
2363
|
+
* NOT the same as any one technician's status.
|
|
2364
|
+
*
|
|
2365
|
+
* The promotion rules are why this is returned rather than left to the
|
|
2366
|
+
* consumer: `en_route`/`arrived`/`started` land on the FIRST assignee to
|
|
2367
|
+
* reach them, while `completed` waits for the LAST. Aggregating that
|
|
2368
|
+
* client-side gets it wrong in the direction that tells a customer the work
|
|
2369
|
+
* is finished when one of three techs has packed up.
|
|
2370
|
+
*/
|
|
2371
|
+
dispatchStatus: openEnum(
|
|
2372
|
+
"unscheduled",
|
|
2373
|
+
"scheduled",
|
|
2374
|
+
"en_route",
|
|
2375
|
+
"arrived",
|
|
2376
|
+
"started",
|
|
2377
|
+
"completed",
|
|
2378
|
+
),
|
|
2379
|
+
/**
|
|
2380
|
+
* When each stage happened. A customer reading "en route" wants to know
|
|
2381
|
+
* since when — a status with no timestamp is why people phone to ask.
|
|
2382
|
+
*/
|
|
2383
|
+
timeline: z.object({
|
|
2384
|
+
scheduledStartAt: z.string().nullable(),
|
|
2385
|
+
enRouteAt: z.string().nullable(),
|
|
2386
|
+
arrivedAt: z.string().nullable(),
|
|
2387
|
+
startedAt: z.string().nullable(),
|
|
2388
|
+
completedAt: z.string().nullable(),
|
|
2389
|
+
}),
|
|
1766
2390
|
assignments: z.array(customerJobEtaAssignmentSchema),
|
|
1767
2391
|
eta: z
|
|
1768
2392
|
.object({
|
|
@@ -1973,6 +2597,30 @@ export const storefrontProductRowSchema = z
|
|
|
1973
2597
|
/** Resolved category (name/description), when the product is categorized. */
|
|
1974
2598
|
category: storefrontProductCategorySchema.nullable().optional(),
|
|
1975
2599
|
images: z.array(z.string()).nullable().optional(),
|
|
2600
|
+
/**
|
|
2601
|
+
* Web-renderable 3D model — `.glb`, `.gltf`, `.obj` or `.stl`.
|
|
2602
|
+
*
|
|
2603
|
+
* All four fields below are ABSENT (not null) unless the org has the
|
|
2604
|
+
* `ecommerce.product_3d` add-on. Absence is the normal case: most
|
|
2605
|
+
* businesses do not sell anything with a model. Use
|
|
2606
|
+
* `@businessdash/sdk/model3d` to turn these into something renderable.
|
|
2607
|
+
*/
|
|
2608
|
+
model3dUrl: z.string().nullable().optional(),
|
|
2609
|
+
/** Apple AR Quick Look companion, `.usdz`. iOS/iPadOS/visionOS Safari. */
|
|
2610
|
+
model3dUsdzUrl: z.string().nullable().optional(),
|
|
2611
|
+
/**
|
|
2612
|
+
* True when the org attached a CAD file (`.step`/`.iges`/native).
|
|
2613
|
+
*
|
|
2614
|
+
* The URL itself is deliberately NOT here. CAD files are the largest
|
|
2615
|
+
* thing the platform serves and are the org's intellectual property, so
|
|
2616
|
+
* they are issued by `GET storefront/products/{id}/cad`, which requires
|
|
2617
|
+
* cookies, rate-limits the caller and re-checks the entitlement.
|
|
2618
|
+
* Publishing the raw URL in a payload any visitor can fetch would route
|
|
2619
|
+
* around all three.
|
|
2620
|
+
*/
|
|
2621
|
+
model3dCadAvailable: z.boolean().optional(),
|
|
2622
|
+
/** Filename for the download link — "bracket-v3.step". */
|
|
2623
|
+
model3dCadName: z.string().nullable().optional(),
|
|
1976
2624
|
createdAt: z.string(),
|
|
1977
2625
|
})
|
|
1978
2626
|
.passthrough();
|
|
@@ -1982,6 +2630,75 @@ export const storefrontListProductsResponseSchema = z.object({
|
|
|
1982
2630
|
nextCursor: z.number().nullable(),
|
|
1983
2631
|
});
|
|
1984
2632
|
|
|
2633
|
+
/**
|
|
2634
|
+
* Result of pushing the catalog to the org's own Stripe account.
|
|
2635
|
+
* Per-product outcomes rather than one all-or-nothing verdict: a single bad
|
|
2636
|
+
* product shouldn't abandon a batch, and the caller needs to know which.
|
|
2637
|
+
*/
|
|
2638
|
+
export const couponSchema = z.object({
|
|
2639
|
+
id: z.string(),
|
|
2640
|
+
code: z.string(),
|
|
2641
|
+
discountType: z.string(),
|
|
2642
|
+
value: z.number(),
|
|
2643
|
+
isActive: z.boolean(),
|
|
2644
|
+
maxUses: z.number().nullable(),
|
|
2645
|
+
usedCount: z.number(),
|
|
2646
|
+
validUntil: z.string().nullable(),
|
|
2647
|
+
stripeCouponId: z.string().nullable(),
|
|
2648
|
+
stripePromotionCodeId: z.string().nullable(),
|
|
2649
|
+
});
|
|
2650
|
+
export type Coupon = z.infer<typeof couponSchema>;
|
|
2651
|
+
|
|
2652
|
+
export const couponCreateInputSchema = z.object({
|
|
2653
|
+
code: z.string().min(3).max(64),
|
|
2654
|
+
discountType: z.enum(["percent", "amount"]),
|
|
2655
|
+
value: z.number().positive(),
|
|
2656
|
+
validFrom: z.coerce.date().optional(),
|
|
2657
|
+
validUntil: z.coerce.date().nullish(),
|
|
2658
|
+
maxUses: z.number().int().positive().nullish(),
|
|
2659
|
+
isActive: z.boolean().optional(),
|
|
2660
|
+
duration: z.enum(["once", "forever", "repeating"]).optional(),
|
|
2661
|
+
durationInMonths: z.number().int().positive().nullish(),
|
|
2662
|
+
appliesTo: z.enum(["order", "shipping", "both"]).optional(),
|
|
2663
|
+
});
|
|
2664
|
+
export type CouponCreateInput = z.input<typeof couponCreateInputSchema>;
|
|
2665
|
+
|
|
2666
|
+
/**
|
|
2667
|
+
* `stripeSynced: false` means the coupon EXISTS locally but is not yet live in
|
|
2668
|
+
* Stripe — reported rather than thrown, so the caller can retry the sync
|
|
2669
|
+
* without re-creating the row.
|
|
2670
|
+
*/
|
|
2671
|
+
export const couponCreateResponseSchema = z.object({
|
|
2672
|
+
coupon: couponSchema,
|
|
2673
|
+
stripeSynced: z.boolean(),
|
|
2674
|
+
stripeError: z.string().nullable(),
|
|
2675
|
+
});
|
|
2676
|
+
export type CouponCreateResponse = z.infer<typeof couponCreateResponseSchema>;
|
|
2677
|
+
|
|
2678
|
+
export const couponListResponseSchema = z.object({
|
|
2679
|
+
coupons: z.array(couponSchema),
|
|
2680
|
+
});
|
|
2681
|
+
export type CouponListResponse = z.infer<typeof couponListResponseSchema>;
|
|
2682
|
+
|
|
2683
|
+
export const storefrontSyncToStripeResponseSchema = z.object({
|
|
2684
|
+
synced: z.array(
|
|
2685
|
+
z.object({
|
|
2686
|
+
productId: z.string(),
|
|
2687
|
+
stripeProductId: z.string(),
|
|
2688
|
+
/** Variant combinations that got a Stripe Price. */
|
|
2689
|
+
combinationsSynced: z.number(),
|
|
2690
|
+
}),
|
|
2691
|
+
),
|
|
2692
|
+
failed: z.array(z.object({ productId: z.string(), error: z.string() })),
|
|
2693
|
+
/** Products still unsynced after this call — keep calling until 0. */
|
|
2694
|
+
remaining: z.number(),
|
|
2695
|
+
/** Connected account written to; null means the platform account. */
|
|
2696
|
+
connectedAccountId: z.string().nullable(),
|
|
2697
|
+
});
|
|
2698
|
+
export type StorefrontSyncToStripeResponse = z.infer<
|
|
2699
|
+
typeof storefrontSyncToStripeResponseSchema
|
|
2700
|
+
>;
|
|
2701
|
+
|
|
1985
2702
|
export const storefrontProductDetailSchema = storefrontProductRowSchema.and(
|
|
1986
2703
|
z.object({
|
|
1987
2704
|
variants: z.array(z.record(z.string(), z.unknown())),
|
|
@@ -2799,6 +3516,8 @@ const bundleCompanySchema = z.object({
|
|
|
2799
3516
|
|
|
2800
3517
|
const bundleGalleryItemSchema = z.object({
|
|
2801
3518
|
id: z.string(),
|
|
3519
|
+
/** Sent by the server on every item and dropped here until now. */
|
|
3520
|
+
description: z.string().nullish(),
|
|
2802
3521
|
type: z.enum(["image", "video"]),
|
|
2803
3522
|
src: z.string(),
|
|
2804
3523
|
width: z.number().nullable(),
|