@mohasinac/appkit 4.14.0 → 4.15.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/dist/_internal/server/features/auctions/actions.js +2 -2
- package/dist/_internal/server/features/cart/service.d.ts +3 -3
- package/dist/_internal/server/features/checkout/actions.js +19 -0
- package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
- package/dist/_internal/server/features/checkout/source-context.js +157 -0
- package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
- package/dist/_internal/server/features/offers/adapters.js +88 -0
- package/dist/_internal/server/features/offers/index.d.ts +2 -0
- package/dist/_internal/server/features/offers/index.js +1 -0
- package/dist/_internal/server/features/orders/adapters.js +24 -0
- package/dist/_internal/server/jobs/core/offerExpiry.js +10 -10
- package/dist/_internal/shared/actions/action-registry.js +3 -1
- package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
- package/dist/_internal/shared/features/auctions/schema.js +13 -1
- package/dist/_internal/shared/features/cart/schema.d.ts +14 -9
- package/dist/_internal/shared/features/cart/schema.js +15 -0
- package/dist/_internal/shared/features/products/schema.d.ts +2 -2
- package/dist/_internal/shared/history/history.d.ts +22 -0
- package/dist/_internal/shared/history/history.js +41 -1
- package/dist/client.d.ts +13 -2
- package/dist/client.js +20 -2
- package/dist/constants/field-names.d.ts +8 -6
- package/dist/constants/field-names.js +48 -6
- package/dist/features/account/components/UserBidsView.js +12 -4
- package/dist/features/account/components/UserReturnsView.d.ts +3 -0
- package/dist/features/account/components/UserReturnsView.js +17 -1
- package/dist/features/admin/components/AdminAuditLogView.js +1 -0
- package/dist/features/admin/components/AdminBidsView.js +15 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
- package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
- package/dist/features/admin/components/AdminNavEditorView.js +15 -5
- package/dist/features/admin/components/AdminNewsletterView.js +18 -2
- package/dist/features/admin/components/AdminOffersView.js +62 -18
- package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
- package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
- package/dist/features/admin/components/AdminScammersView.js +3 -8
- package/dist/features/admin/components/AdminSectionsView.js +32 -23
- package/dist/features/admin/components/AdminSessionsView.js +17 -2
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
- package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
- package/dist/features/admin/schemas/homepage-section-form.js +68 -0
- package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
- package/dist/features/admin/schemas/nav-item-form.js +72 -0
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
- package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
- package/dist/features/auctions/components/bid-detail-fields.js +103 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
- package/dist/features/audit-log/schemas/firestore.js +7 -0
- package/dist/features/blog/schemas/blog-form.d.ts +80 -0
- package/dist/features/blog/schemas/blog-form.js +100 -0
- package/dist/features/events/components/AdminEventEditorView.js +32 -54
- package/dist/features/events/components/AdminEventEntriesView.js +22 -3
- package/dist/features/events/schemas/event-form.d.ts +113 -0
- package/dist/features/events/schemas/event-form.js +82 -0
- package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
- package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
- package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
- package/dist/features/homepage/schemas/index.d.ts +31 -0
- package/dist/features/homepage/schemas/index.js +24 -0
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
- package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
- package/dist/features/orders/repository/orders.repository.js +5 -0
- package/dist/features/orders/schemas/firestore.d.ts +36 -1
- package/dist/features/orders/types/index.d.ts +35 -7
- package/dist/features/products/components/GroupSettingsPanel.js +5 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +73 -0
- package/dist/features/products/schemas/product-features.validators.js +63 -0
- package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
- package/dist/features/scams/constants/scammer-status-display.js +79 -0
- package/dist/features/seller/actions/offer-actions.js +32 -2
- package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
- package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
- package/dist/features/seller/components/SellerBidsView.js +11 -4
- package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
- package/dist/features/seller/components/SellerOffersView.js +2 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +38 -14
- package/dist/features/seller/repository/offer.repository.d.ts +69 -8
- package/dist/features/seller/repository/offer.repository.js +127 -23
- package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
- package/dist/features/seller/schemas/coupon-form.js +116 -0
- package/dist/features/seller/schemas/firestore.d.ts +56 -2
- package/dist/features/seller/schemas/firestore.js +27 -0
- package/dist/features/seller/schemas/offer-forms.d.ts +21 -0
- package/dist/features/seller/schemas/offer-forms.js +21 -0
- package/dist/features/shell/build-sections.d.ts +63 -0
- package/dist/features/shell/build-sections.js +207 -0
- package/dist/features/shell/field-ui-meta.d.ts +115 -0
- package/dist/features/shell/field-ui-meta.js +324 -0
- package/dist/features/shell/index.d.ts +4 -0
- package/dist/features/shell/index.js +2 -0
- package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
- package/dist/features/status-history/components/StatusTimeline.js +46 -0
- package/dist/features/status-history/index.d.ts +11 -0
- package/dist/features/status-history/index.js +10 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
- package/dist/features/store-extensions/index.d.ts +12 -0
- package/dist/features/store-extensions/index.js +12 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
- package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
- package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
- package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
- package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
- package/dist/features/store-extensions/schemas/firestore.js +60 -0
- package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
- package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
- package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
- package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
- package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
- package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
- package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
- package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
- package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +326 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +12 -2
- package/dist/next/routing/route-map.d.ts +16 -2
- package/dist/next/routing/route-map.js +9 -2
- package/dist/schemas/firestore-value.d.ts +8 -0
- package/dist/schemas/firestore-value.js +44 -0
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/registry.d.ts +634 -1
- package/dist/schemas/registry.js +64 -1
- package/dist/seed/bids-seed-data.js +30 -0
- package/dist/seed/offers-seed-data.js +212 -7
- package/dist/seed/orders-seed-data.js +336 -1
- package/dist/seed/products-auctions-seed-data.js +41 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +5 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/RecordDetailModal.d.ts +10 -1
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/package.json +2 -1
- package/scripts/node-esm-loader.mjs +65 -0
- package/scripts/seed-cli-loader.mjs +6 -49
- package/scripts/seed-cli.mjs +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Whether a string is a permission this system can actually grant. */
|
|
3
|
+
export declare function isKnownPermission(value: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
6
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
7
|
+
*/
|
|
8
|
+
export declare const customRoleFormSchema: z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
slug: z.ZodString;
|
|
11
|
+
description: z.ZodOptional<z.ZodString>;
|
|
12
|
+
scope: z.ZodEnum<["global", "store"]>;
|
|
13
|
+
permissions: z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">;
|
|
14
|
+
inheritsFrom: z.ZodOptional<z.ZodString>;
|
|
15
|
+
isActive: z.ZodBoolean;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
scope: "store" | "global";
|
|
18
|
+
name: string;
|
|
19
|
+
slug: string;
|
|
20
|
+
isActive: boolean;
|
|
21
|
+
permissions: string[];
|
|
22
|
+
description?: string | undefined;
|
|
23
|
+
inheritsFrom?: string | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
scope: "store" | "global";
|
|
26
|
+
name: string;
|
|
27
|
+
slug: string;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
permissions: string[];
|
|
30
|
+
description?: string | undefined;
|
|
31
|
+
inheritsFrom?: string | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
export type CustomRoleFormValues = z.infer<typeof customRoleFormSchema>;
|
|
34
|
+
/** Create contract. `createdBy` is absent — the route sets it from the session. */
|
|
35
|
+
export declare const customRoleCreateSchema: z.ZodObject<{
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
slug: z.ZodString;
|
|
38
|
+
description: z.ZodOptional<z.ZodString>;
|
|
39
|
+
scope: z.ZodEnum<["global", "store"]>;
|
|
40
|
+
permissions: z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">;
|
|
41
|
+
inheritsFrom: z.ZodOptional<z.ZodString>;
|
|
42
|
+
isActive: z.ZodBoolean;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
scope: "store" | "global";
|
|
45
|
+
name: string;
|
|
46
|
+
slug: string;
|
|
47
|
+
isActive: boolean;
|
|
48
|
+
permissions: string[];
|
|
49
|
+
description?: string | undefined;
|
|
50
|
+
inheritsFrom?: string | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
scope: "store" | "global";
|
|
53
|
+
name: string;
|
|
54
|
+
slug: string;
|
|
55
|
+
isActive: boolean;
|
|
56
|
+
permissions: string[];
|
|
57
|
+
description?: string | undefined;
|
|
58
|
+
inheritsFrom?: string | undefined;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Update contract — partial and `.strict()`, so an unknown key is a 400 rather
|
|
62
|
+
* than a silent write into a document the permission system reads.
|
|
63
|
+
*/
|
|
64
|
+
export declare const customRoleUpdateSchema: z.ZodObject<{
|
|
65
|
+
name: z.ZodOptional<z.ZodString>;
|
|
66
|
+
description: z.ZodOptional<z.ZodString>;
|
|
67
|
+
scope: z.ZodOptional<z.ZodEnum<["global", "store"]>>;
|
|
68
|
+
permissions: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>;
|
|
69
|
+
inheritsFrom: z.ZodOptional<z.ZodString>;
|
|
70
|
+
isActive: z.ZodOptional<z.ZodBoolean>;
|
|
71
|
+
}, "strict", z.ZodTypeAny, {
|
|
72
|
+
scope?: "store" | "global" | undefined;
|
|
73
|
+
name?: string | undefined;
|
|
74
|
+
description?: string | undefined;
|
|
75
|
+
isActive?: boolean | undefined;
|
|
76
|
+
permissions?: string[] | undefined;
|
|
77
|
+
inheritsFrom?: string | undefined;
|
|
78
|
+
}, {
|
|
79
|
+
scope?: "store" | "global" | undefined;
|
|
80
|
+
name?: string | undefined;
|
|
81
|
+
description?: string | undefined;
|
|
82
|
+
isActive?: boolean | undefined;
|
|
83
|
+
permissions?: string[] | undefined;
|
|
84
|
+
inheritsFrom?: string | undefined;
|
|
85
|
+
}>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Custom roles GRANT PERMISSIONS, and neither creating nor updating one
|
|
3
|
+
* validated anything. Measured 2026-08-24:
|
|
4
|
+
* · `POST /api/admin/roles` — `parseJsonBody` then `...body` spread
|
|
5
|
+
* into `.create()`.
|
|
6
|
+
* · `PATCH /api/admin/roles/[id]` — the raw body handed straight to
|
|
7
|
+
* `.update()`.
|
|
8
|
+
* · Both pages (`admin/roles/new`, `.../[id]/edit`) are raw controls
|
|
9
|
+
* with no Zod anywhere.
|
|
10
|
+
* So a role could be written with no name, a `permissions` array holding
|
|
11
|
+
* arbitrary strings, a `scope` outside its union, or any invented key —
|
|
12
|
+
* all persisted verbatim into the document the permission system reads.
|
|
13
|
+
* WHAT: One schema for both pages AND both routes.
|
|
14
|
+
*
|
|
15
|
+
* ## Permissions are checked against the real catalogue
|
|
16
|
+
*
|
|
17
|
+
* `Permission` is a closed union of ~85 `admin:resource:action` strings, and
|
|
18
|
+
* `PERMISSION_GROUPS` is its runtime form. A permission string that is not in
|
|
19
|
+
* it grants nothing — it silently never matches — so a role built from typos
|
|
20
|
+
* looks configured and does nothing, which is worse than being rejected.
|
|
21
|
+
*
|
|
22
|
+
* `"*"` is accepted deliberately: `security/rbac/types.ts` defines it as the
|
|
23
|
+
* wildcard, and rejecting it here would break a legitimate super-role.
|
|
24
|
+
*
|
|
25
|
+
* ## What is NOT accepted from the body
|
|
26
|
+
*
|
|
27
|
+
* `createdBy` is set from the session by the route. `id`/`createdAt`/
|
|
28
|
+
* `updatedAt` are the repository's. A caller able to set `createdBy` could
|
|
29
|
+
* attribute a privilege grant to somebody else, which is precisely the field
|
|
30
|
+
* an audit trail depends on.
|
|
31
|
+
*
|
|
32
|
+
* EXPORTS:
|
|
33
|
+
* customRoleFormSchema, customRoleCreateSchema, customRoleUpdateSchema,
|
|
34
|
+
* isKnownPermission, type CustomRoleFormValues
|
|
35
|
+
*
|
|
36
|
+
* @tag domain:store-extensions,rbac
|
|
37
|
+
* @tag layer:schema
|
|
38
|
+
* @tag pattern:none
|
|
39
|
+
* @tag access:isomorphic
|
|
40
|
+
* @tag consumers:admin/roles pages,/api/admin/roles
|
|
41
|
+
* @tag sideEffects:none
|
|
42
|
+
*/
|
|
43
|
+
import { z } from "zod";
|
|
44
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
45
|
+
import { PERMISSION_GROUPS } from "../../auth/permissions/constants";
|
|
46
|
+
/**
|
|
47
|
+
* Every permission the catalogue actually defines, plus the wildcard.
|
|
48
|
+
*
|
|
49
|
+
* Derived from `PERMISSION_GROUPS` rather than restated — a hand-written copy
|
|
50
|
+
* would be the second list of ~85 strings to keep in sync, and the first one
|
|
51
|
+
* to drift (Root Cause #61).
|
|
52
|
+
*/
|
|
53
|
+
const KNOWN_PERMISSIONS = new Set([
|
|
54
|
+
"*",
|
|
55
|
+
...Object.values(PERMISSION_GROUPS).flat(),
|
|
56
|
+
]);
|
|
57
|
+
/** Whether a string is a permission this system can actually grant. */
|
|
58
|
+
export function isKnownPermission(value) {
|
|
59
|
+
return KNOWN_PERMISSIONS.has(value);
|
|
60
|
+
}
|
|
61
|
+
const permissionSchema = z.string().refine(isKnownPermission, {
|
|
62
|
+
message: "Not a permission this system defines — it would grant nothing.",
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
66
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
67
|
+
*/
|
|
68
|
+
export const customRoleFormSchema = z.object({
|
|
69
|
+
name: annotate(z.string().min(1, "A role needs a name.").max(80, "Keep the name under 80 characters."), {
|
|
70
|
+
section: "basics", sectionLabel: "Role", sectionRequired: true,
|
|
71
|
+
quick: true, order: 1, row: "pair",
|
|
72
|
+
}),
|
|
73
|
+
slug: annotate(z
|
|
74
|
+
.string()
|
|
75
|
+
.min(1, "A slug is required.")
|
|
76
|
+
.max(80)
|
|
77
|
+
.regex(/^[a-z0-9-]+$/, "Use lowercase letters, numbers and hyphens only."), {
|
|
78
|
+
section: "basics", quick: true, order: 2, row: "pair",
|
|
79
|
+
tier: "t1-derive",
|
|
80
|
+
help: "Generated from the name when left blank.",
|
|
81
|
+
}),
|
|
82
|
+
description: annotate(z.string().max(300, "Keep the description under 300 characters.").optional(), {
|
|
83
|
+
section: "basics", order: 3, row: "full",
|
|
84
|
+
}),
|
|
85
|
+
scope: annotate(z.enum(["global", "store"]), {
|
|
86
|
+
section: "basics", quick: true, order: 4, row: "pair",
|
|
87
|
+
}),
|
|
88
|
+
permissions: annotate(z.array(permissionSchema), {
|
|
89
|
+
section: "permissions", sectionLabel: "Permissions",
|
|
90
|
+
order: 1, row: "full", kind: "list",
|
|
91
|
+
}),
|
|
92
|
+
inheritsFrom: annotate(z.string().max(80).optional(), {
|
|
93
|
+
section: "permissions", order: 2, row: "pair",
|
|
94
|
+
help: "Another role whose permissions this one starts from.",
|
|
95
|
+
}),
|
|
96
|
+
isActive: annotate(z.boolean(), {
|
|
97
|
+
section: "visibility", sectionLabel: "Visibility", order: 1, row: "quarter",
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
/** Create contract. `createdBy` is absent — the route sets it from the session. */
|
|
101
|
+
export const customRoleCreateSchema = customRoleFormSchema;
|
|
102
|
+
/**
|
|
103
|
+
* Update contract — partial and `.strict()`, so an unknown key is a 400 rather
|
|
104
|
+
* than a silent write into a document the permission system reads.
|
|
105
|
+
*/
|
|
106
|
+
export const customRoleUpdateSchema = z
|
|
107
|
+
.object({
|
|
108
|
+
name: z.string().min(1).max(80).optional(),
|
|
109
|
+
description: z.string().max(300).optional(),
|
|
110
|
+
scope: z.enum(["global", "store"]).optional(),
|
|
111
|
+
permissions: z.array(permissionSchema).optional(),
|
|
112
|
+
inheritsFrom: z.string().max(80).optional(),
|
|
113
|
+
isActive: z.boolean().optional(),
|
|
114
|
+
// `slug` is deliberately absent: it is the role's stable identifier and
|
|
115
|
+
// renaming it would orphan every user already assigned the role. Same
|
|
116
|
+
// create-only rule every other slug in this codebase follows.
|
|
117
|
+
})
|
|
118
|
+
.strict();
|
|
@@ -100,7 +100,25 @@ export interface StoreCategoryDocument extends BaseDocument {
|
|
|
100
100
|
export declare const STORE_CATEGORIES_COLLECTION: "storeCategories";
|
|
101
101
|
export declare const STORE_CATEGORY_INDEXED_FIELDS: readonly ["storeId", "slug", "isActive", "displayOrder", "createdAt"];
|
|
102
102
|
export declare const DEFAULT_STORE_CATEGORY_DATA: Partial<StoreCategoryDocument>;
|
|
103
|
-
|
|
103
|
+
/**
|
|
104
|
+
* The listing kinds a seller can save a template for.
|
|
105
|
+
*
|
|
106
|
+
* A runtime array, with the type DERIVED from it — so the Zod enum in
|
|
107
|
+
* `listing-template-form.ts` reads this rather than restating it. That was the
|
|
108
|
+
* eleventh hand-written copy of the listing-type union in this codebase, and
|
|
109
|
+
* the tenth had already drifted (Root Cause #61).
|
|
110
|
+
*
|
|
111
|
+
* Two deliberate differences from `ListingType`:
|
|
112
|
+
* - `bundle` is KEPT even though SB-UNI-D stopped it being a listingType. A
|
|
113
|
+
* seeded template stores it (`store-extensions-seed-data.ts:202`), so
|
|
114
|
+
* dropping it here would make that template fail validation and become
|
|
115
|
+
* unsaveable — the same defect as the blog `slug` regex no stored row
|
|
116
|
+
* satisfied.
|
|
117
|
+
* - `art` and `stickers` are ADDED. They are real listing types a seller can
|
|
118
|
+
* create, and their absence meant a template could never be saved for them.
|
|
119
|
+
*/
|
|
120
|
+
export declare const LISTING_TEMPLATE_TYPES: readonly ["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"];
|
|
121
|
+
export type ListingTemplateType = (typeof LISTING_TEMPLATE_TYPES)[number];
|
|
104
122
|
export interface ListingTemplateDocument extends BaseDocument {
|
|
105
123
|
storeId: string;
|
|
106
124
|
ownerId: string;
|
|
@@ -151,6 +169,8 @@ export interface ReportDocument extends BaseDocument {
|
|
|
151
169
|
resolution?: string;
|
|
152
170
|
resolvedAt?: Date;
|
|
153
171
|
}
|
|
172
|
+
export declare const REPORT_ENTITY_TYPES: [ReportEntityType, ...ReportEntityType[]];
|
|
173
|
+
export declare const REPORT_REASONS: [ReportReason, ...ReportReason[]];
|
|
154
174
|
export declare const REPORTS_COLLECTION: "reports";
|
|
155
175
|
export declare const REPORT_INDEXED_FIELDS: readonly ["entityType", "entityId", "reporterId", "reason", "status", "createdAt"];
|
|
156
176
|
export declare const DEFAULT_REPORT_DATA: Partial<ReportDocument>;
|
|
@@ -63,6 +63,36 @@ export const DEFAULT_STORE_CATEGORY_DATA = {
|
|
|
63
63
|
displayOrder: 0,
|
|
64
64
|
productIds: [],
|
|
65
65
|
};
|
|
66
|
+
// 6. ───── listingTemplates ───────────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* The listing kinds a seller can save a template for.
|
|
69
|
+
*
|
|
70
|
+
* A runtime array, with the type DERIVED from it — so the Zod enum in
|
|
71
|
+
* `listing-template-form.ts` reads this rather than restating it. That was the
|
|
72
|
+
* eleventh hand-written copy of the listing-type union in this codebase, and
|
|
73
|
+
* the tenth had already drifted (Root Cause #61).
|
|
74
|
+
*
|
|
75
|
+
* Two deliberate differences from `ListingType`:
|
|
76
|
+
* - `bundle` is KEPT even though SB-UNI-D stopped it being a listingType. A
|
|
77
|
+
* seeded template stores it (`store-extensions-seed-data.ts:202`), so
|
|
78
|
+
* dropping it here would make that template fail validation and become
|
|
79
|
+
* unsaveable — the same defect as the blog `slug` regex no stored row
|
|
80
|
+
* satisfied.
|
|
81
|
+
* - `art` and `stickers` are ADDED. They are real listing types a seller can
|
|
82
|
+
* create, and their absence meant a template could never be saved for them.
|
|
83
|
+
*/
|
|
84
|
+
export const LISTING_TEMPLATE_TYPES = [
|
|
85
|
+
"standard",
|
|
86
|
+
"auction",
|
|
87
|
+
"pre-order",
|
|
88
|
+
"prize-draw",
|
|
89
|
+
"bundle",
|
|
90
|
+
"classified",
|
|
91
|
+
"digital-code",
|
|
92
|
+
"live",
|
|
93
|
+
"art",
|
|
94
|
+
"stickers",
|
|
95
|
+
];
|
|
66
96
|
export const LISTING_TEMPLATES_COLLECTION = "listingTemplates";
|
|
67
97
|
export const LISTING_TEMPLATE_INDEXED_FIELDS = [
|
|
68
98
|
"storeId",
|
|
@@ -92,6 +122,36 @@ export const MODERATION_QUEUE_INDEXED_FIELDS = [
|
|
|
92
122
|
export const DEFAULT_MODERATION_QUEUE_DATA = {
|
|
93
123
|
status: "pending",
|
|
94
124
|
};
|
|
125
|
+
/*
|
|
126
|
+
* Runtime companions for the three report unions above.
|
|
127
|
+
*
|
|
128
|
+
* Keyed `Record<Union, true>` rather than written as arrays, because that is
|
|
129
|
+
* the only shape where BOTH mistakes are compile errors: a member added to the
|
|
130
|
+
* union and forgotten here, AND a value here that is not a real member. An
|
|
131
|
+
* array literal catches neither, which is how ten independent enumerations of
|
|
132
|
+
* `ListingType` came to disagree (Recurrent Root Cause #61).
|
|
133
|
+
*/
|
|
134
|
+
const REPORT_ENTITY_TYPE_MAP = {
|
|
135
|
+
product: true,
|
|
136
|
+
store: true,
|
|
137
|
+
review: true,
|
|
138
|
+
event: true,
|
|
139
|
+
user: true,
|
|
140
|
+
blog: true,
|
|
141
|
+
comment: true,
|
|
142
|
+
};
|
|
143
|
+
export const REPORT_ENTITY_TYPES = Object.keys(REPORT_ENTITY_TYPE_MAP);
|
|
144
|
+
const REPORT_REASON_MAP = {
|
|
145
|
+
scam: true,
|
|
146
|
+
counterfeit: true,
|
|
147
|
+
prohibited: true,
|
|
148
|
+
inappropriate: true,
|
|
149
|
+
harassment: true,
|
|
150
|
+
spam: true,
|
|
151
|
+
"ip-violation": true,
|
|
152
|
+
other: true,
|
|
153
|
+
};
|
|
154
|
+
export const REPORT_REASONS = Object.keys(REPORT_REASON_MAP);
|
|
95
155
|
export const REPORTS_COLLECTION = "reports";
|
|
96
156
|
export const REPORT_INDEXED_FIELDS = [
|
|
97
157
|
"entityType",
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { StoreGoogleConfigDocument } from "./firestore";
|
|
3
|
+
/**
|
|
4
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
5
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
6
|
+
*/
|
|
7
|
+
export declare const storeGoogleConfigUpdateSchema: z.ZodObject<{
|
|
8
|
+
isConnected: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
placeId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
businessName: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strict", z.ZodTypeAny, {
|
|
12
|
+
placeId?: string | undefined;
|
|
13
|
+
isConnected?: boolean | undefined;
|
|
14
|
+
businessName?: string | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
placeId?: string | undefined;
|
|
17
|
+
isConnected?: boolean | undefined;
|
|
18
|
+
businessName?: string | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export type StoreGoogleConfigFormValues = z.infer<typeof storeGoogleConfigUpdateSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* What the seller's own settings page may see.
|
|
23
|
+
*
|
|
24
|
+
* An ALLOW-list, built as a new object — never the document with keys deleted.
|
|
25
|
+
* A deny-list publishes every field nobody thought to remove, including ones
|
|
26
|
+
* the interface does not declare, which is exactly how a decrypted API token
|
|
27
|
+
* and an unmasked ad-credentials blob reached anonymous callers before
|
|
28
|
+
* (Recurrent Root Cause #70).
|
|
29
|
+
*
|
|
30
|
+
* PUBLIC (to the store owner):
|
|
31
|
+
* storeId, isConnected — what the page renders
|
|
32
|
+
* placeId, businessName — what the page lets them edit
|
|
33
|
+
* averageRating, totalReviews, lastSyncedAt — sync output they need to see
|
|
34
|
+
* id, createdAt, updatedAt — ordinary record metadata
|
|
35
|
+
*
|
|
36
|
+
* PRIVATE:
|
|
37
|
+
* oauthRefreshToken — a long-lived Google credential with no reader and no
|
|
38
|
+
* writer anywhere in either tree. It was being sent to the browser on every
|
|
39
|
+
* load simply because the route returned the document whole.
|
|
40
|
+
*/
|
|
41
|
+
export declare function toSellerGoogleConfig(doc: StoreGoogleConfigDocument): {
|
|
42
|
+
id: string;
|
|
43
|
+
storeId: string;
|
|
44
|
+
isConnected: boolean;
|
|
45
|
+
placeId: string | undefined;
|
|
46
|
+
businessName: string | undefined;
|
|
47
|
+
averageRating: number | undefined;
|
|
48
|
+
totalReviews: number | undefined;
|
|
49
|
+
lastSyncedAt: Date | undefined;
|
|
50
|
+
createdAt: Date;
|
|
51
|
+
updatedAt: Date;
|
|
52
|
+
};
|
|
53
|
+
export type SellerGoogleConfig = ReturnType<typeof toSellerGoogleConfig>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `PUT /api/store/google-reviews` spread the raw request body into
|
|
3
|
+
* Firestore on both the create and the update branch, with `storeId`
|
|
4
|
+
* pinned and nothing else checked.
|
|
5
|
+
*
|
|
6
|
+
* ## 🛑 The field that makes this worth doing carefully
|
|
7
|
+
*
|
|
8
|
+
* `StoreGoogleConfigDocument` declares `oauthRefreshToken` — a long-lived
|
|
9
|
+
* Google credential. The raw spread meant a request body could set it, and the
|
|
10
|
+
* sibling `GET` returns the document WHOLE, so it was also being sent to the
|
|
11
|
+
* browser on every load of the seller's Google Reviews settings page.
|
|
12
|
+
*
|
|
13
|
+
* It is scoped to the caller's own store, so this is not a cross-tenant leak.
|
|
14
|
+
* It is still a secret in a page payload for no reason: a repo-wide grep finds
|
|
15
|
+
* **no reader and no writer** for that field anywhere — nothing sets it and
|
|
16
|
+
* nothing consumes it. Per the public-projection rule, a field nobody can name
|
|
17
|
+
* a reader for is private by default.
|
|
18
|
+
*
|
|
19
|
+
* So this schema deliberately does NOT declare it, and the route projects it
|
|
20
|
+
* out of the response. The field itself is left on the document rather than
|
|
21
|
+
* deleted — removing a schema field is a data-model change and deserves its
|
|
22
|
+
* own decision, not a drive-by inside a validation fix.
|
|
23
|
+
*
|
|
24
|
+
* ## `averageRating` / `totalReviews` / `lastSyncedAt` are absent too
|
|
25
|
+
*
|
|
26
|
+
* Those are SYNC OUTPUT — what Google last told us. A seller typing their own
|
|
27
|
+
* review count in is not configuration, it is fabricating the number the
|
|
28
|
+
* storefront displays.
|
|
29
|
+
*
|
|
30
|
+
* EXPORTS:
|
|
31
|
+
* storeGoogleConfigUpdateSchema, toSellerGoogleConfig,
|
|
32
|
+
* type StoreGoogleConfigFormValues, type SellerGoogleConfig
|
|
33
|
+
*
|
|
34
|
+
* @tag domain:store-extensions,google-reviews
|
|
35
|
+
* @tag layer:schema
|
|
36
|
+
* @tag pattern:none
|
|
37
|
+
* @tag access:isomorphic
|
|
38
|
+
* @tag consumers:/api/store/google-reviews
|
|
39
|
+
* @tag sideEffects:none
|
|
40
|
+
*/
|
|
41
|
+
import { z } from "zod";
|
|
42
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
43
|
+
/**
|
|
44
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
45
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
46
|
+
*/
|
|
47
|
+
export const storeGoogleConfigUpdateSchema = z
|
|
48
|
+
.object({
|
|
49
|
+
isConnected: annotate(z.boolean().optional(), {
|
|
50
|
+
section: "google",
|
|
51
|
+
sectionLabel: "Google Reviews",
|
|
52
|
+
sectionRequired: true,
|
|
53
|
+
quick: true,
|
|
54
|
+
order: 1,
|
|
55
|
+
row: "quarter",
|
|
56
|
+
}),
|
|
57
|
+
placeId: annotate(z.string().max(256).optional(), {
|
|
58
|
+
section: "google",
|
|
59
|
+
quick: true,
|
|
60
|
+
order: 2,
|
|
61
|
+
row: "pair",
|
|
62
|
+
help: "The Google Place ID for this store's listing.",
|
|
63
|
+
}),
|
|
64
|
+
businessName: annotate(z.string().max(200).optional(), {
|
|
65
|
+
section: "google",
|
|
66
|
+
quick: true,
|
|
67
|
+
order: 3,
|
|
68
|
+
row: "pair",
|
|
69
|
+
}),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
72
|
+
/**
|
|
73
|
+
* What the seller's own settings page may see.
|
|
74
|
+
*
|
|
75
|
+
* An ALLOW-list, built as a new object — never the document with keys deleted.
|
|
76
|
+
* A deny-list publishes every field nobody thought to remove, including ones
|
|
77
|
+
* the interface does not declare, which is exactly how a decrypted API token
|
|
78
|
+
* and an unmasked ad-credentials blob reached anonymous callers before
|
|
79
|
+
* (Recurrent Root Cause #70).
|
|
80
|
+
*
|
|
81
|
+
* PUBLIC (to the store owner):
|
|
82
|
+
* storeId, isConnected — what the page renders
|
|
83
|
+
* placeId, businessName — what the page lets them edit
|
|
84
|
+
* averageRating, totalReviews, lastSyncedAt — sync output they need to see
|
|
85
|
+
* id, createdAt, updatedAt — ordinary record metadata
|
|
86
|
+
*
|
|
87
|
+
* PRIVATE:
|
|
88
|
+
* oauthRefreshToken — a long-lived Google credential with no reader and no
|
|
89
|
+
* writer anywhere in either tree. It was being sent to the browser on every
|
|
90
|
+
* load simply because the route returned the document whole.
|
|
91
|
+
*/
|
|
92
|
+
export function toSellerGoogleConfig(doc) {
|
|
93
|
+
return {
|
|
94
|
+
id: doc.id,
|
|
95
|
+
storeId: doc.storeId,
|
|
96
|
+
isConnected: doc.isConnected,
|
|
97
|
+
placeId: doc.placeId,
|
|
98
|
+
businessName: doc.businessName,
|
|
99
|
+
averageRating: doc.averageRating,
|
|
100
|
+
totalReviews: doc.totalReviews,
|
|
101
|
+
lastSyncedAt: doc.lastSyncedAt,
|
|
102
|
+
createdAt: doc.createdAt,
|
|
103
|
+
updatedAt: doc.updatedAt,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
4
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
5
|
+
*/
|
|
6
|
+
export declare const itemRequestCreateSchema: z.ZodObject<{
|
|
7
|
+
title: z.ZodString;
|
|
8
|
+
description: z.ZodString;
|
|
9
|
+
category: z.ZodOptional<z.ZodString>;
|
|
10
|
+
brand: z.ZodOptional<z.ZodString>;
|
|
11
|
+
maxBudget: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
imageUrls: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
}, "strict", z.ZodTypeAny, {
|
|
14
|
+
title: string;
|
|
15
|
+
description: string;
|
|
16
|
+
brand?: string | undefined;
|
|
17
|
+
category?: string | undefined;
|
|
18
|
+
imageUrls?: string[] | undefined;
|
|
19
|
+
maxBudget?: number | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
brand?: string | undefined;
|
|
24
|
+
category?: string | undefined;
|
|
25
|
+
imageUrls?: string[] | undefined;
|
|
26
|
+
maxBudget?: number | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export type ItemRequestCreateValues = z.infer<typeof itemRequestCreateSchema>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `POST /api/item-requests` spread the raw body into Firestore, and this
|
|
3
|
+
* one is READ BY THE PUBLIC — `GET /api/item-requests` is `auth: false`
|
|
4
|
+
* and returns the open list to anyone.
|
|
5
|
+
*
|
|
6
|
+
* const body = await parseJsonBody<FirestoreDocument>(request);
|
|
7
|
+
* await itemRequestsRepository.create({ ...body, opUserId, ..., replies: [], replyCount: 0 });
|
|
8
|
+
*
|
|
9
|
+
* So an unvalidated write here is an unvalidated PUBLISH. A request could
|
|
10
|
+
* be created with no title and no description, and a caller could set
|
|
11
|
+
* `approvedAt` / `approvedBy` — the fields that record a moderator having
|
|
12
|
+
* cleared it.
|
|
13
|
+
*
|
|
14
|
+
* `status`, `replies` and `replyCount` were pinned server-side, so the
|
|
15
|
+
* approval GATE itself held; what a caller could forge was the RECORD of
|
|
16
|
+
* approval, which is the part a human reads when deciding whether it has
|
|
17
|
+
* already been looked at.
|
|
18
|
+
*
|
|
19
|
+
* WHAT: The create contract — title and description required, budget bounded,
|
|
20
|
+
* and nothing a moderator owns.
|
|
21
|
+
*
|
|
22
|
+
* ## `maxBudget` is coerced and bounded
|
|
23
|
+
*
|
|
24
|
+
* It arrives from a number input as a string. Uncoerced it was written to
|
|
25
|
+
* Firestore as a string, and a later numeric comparison against it would sort
|
|
26
|
+
* lexically — the quiet half of the same class as the `resolvedAt` string that
|
|
27
|
+
* was being written into a Date field on the reports route.
|
|
28
|
+
*
|
|
29
|
+
* EXPORTS: itemRequestCreateSchema, type ItemRequestCreateValues
|
|
30
|
+
*
|
|
31
|
+
* @tag domain:store-extensions,item-requests
|
|
32
|
+
* @tag layer:schema
|
|
33
|
+
* @tag pattern:none
|
|
34
|
+
* @tag access:isomorphic
|
|
35
|
+
* @tag consumers:/api/item-requests
|
|
36
|
+
* @tag sideEffects:none
|
|
37
|
+
*/
|
|
38
|
+
import { z } from "zod";
|
|
39
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
40
|
+
/**
|
|
41
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
42
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
43
|
+
*/
|
|
44
|
+
export const itemRequestCreateSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
title: annotate(z
|
|
47
|
+
.string()
|
|
48
|
+
.min(3, "Give the request a title of at least 3 characters.")
|
|
49
|
+
.max(200, "Keep the title under 200 characters."), {
|
|
50
|
+
section: "basics",
|
|
51
|
+
sectionLabel: "What are you looking for?",
|
|
52
|
+
sectionRequired: true,
|
|
53
|
+
quick: true,
|
|
54
|
+
order: 1,
|
|
55
|
+
row: "full",
|
|
56
|
+
}),
|
|
57
|
+
description: annotate(z
|
|
58
|
+
.string()
|
|
59
|
+
.min(10, "Describe what you're after in at least 10 characters.")
|
|
60
|
+
.max(5000, "Keep the description under 5000 characters."), { section: "basics", quick: true, order: 2, row: "full", kind: "textarea" }),
|
|
61
|
+
category: annotate(z.string().max(120).optional(), {
|
|
62
|
+
section: "basics",
|
|
63
|
+
order: 3,
|
|
64
|
+
row: "pair",
|
|
65
|
+
}),
|
|
66
|
+
brand: annotate(z.string().max(120).optional(), {
|
|
67
|
+
section: "basics",
|
|
68
|
+
order: 4,
|
|
69
|
+
row: "pair",
|
|
70
|
+
}),
|
|
71
|
+
// Coerced — see the header. Bounded so a typo cannot record a budget that
|
|
72
|
+
// reads as real money.
|
|
73
|
+
maxBudget: annotate(z.coerce
|
|
74
|
+
.number()
|
|
75
|
+
.min(0, "A budget cannot be negative.")
|
|
76
|
+
.max(10000000, "That budget looks like a typo.")
|
|
77
|
+
.optional(), { section: "basics", order: 5, row: "pair", kind: "number" }),
|
|
78
|
+
imageUrls: annotate(z.array(z.string().url("Each image must be a URL.")).max(10).optional(), { section: "media", sectionLabel: "Photos", order: 1, row: "full", kind: "media" }),
|
|
79
|
+
})
|
|
80
|
+
.strict();
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
4
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
5
|
+
*/
|
|
6
|
+
export declare const listingTemplateFormSchema: z.ZodObject<{
|
|
7
|
+
name: z.ZodString;
|
|
8
|
+
description: z.ZodOptional<z.ZodString>;
|
|
9
|
+
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"]>;
|
|
10
|
+
defaults: z.ZodRecord<z.ZodString, z.ZodType<import("../../..").FirestoreValue, z.ZodTypeDef, import("../../..").FirestoreValue>>;
|
|
11
|
+
isShared: z.ZodBoolean;
|
|
12
|
+
isActive: z.ZodBoolean;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
name: string;
|
|
15
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle";
|
|
16
|
+
isActive: boolean;
|
|
17
|
+
isShared: boolean;
|
|
18
|
+
defaults: Record<string, import("../../..").FirestoreValue>;
|
|
19
|
+
description?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
name: string;
|
|
22
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle";
|
|
23
|
+
isActive: boolean;
|
|
24
|
+
isShared: boolean;
|
|
25
|
+
defaults: Record<string, import("../../..").FirestoreValue>;
|
|
26
|
+
description?: string | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export type ListingTemplateFormValues = z.infer<typeof listingTemplateFormSchema>;
|
|
29
|
+
/**
|
|
30
|
+
* Create contract. `storeId`/`ownerId` are deliberately absent: the route sets
|
|
31
|
+
* both from the session, so a caller cannot create a template inside someone
|
|
32
|
+
* else's store by adding a field to the body.
|
|
33
|
+
*/
|
|
34
|
+
export declare const listingTemplateCreateSchema: z.ZodObject<{
|
|
35
|
+
name: z.ZodString;
|
|
36
|
+
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
37
|
+
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"]>;
|
|
38
|
+
isActive: z.ZodOptional<z.ZodBoolean>;
|
|
39
|
+
isShared: z.ZodOptional<z.ZodBoolean>;
|
|
40
|
+
defaults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("../../..").FirestoreValue, z.ZodTypeDef, import("../../..").FirestoreValue>>>;
|
|
41
|
+
}, "strip", z.ZodTypeAny, {
|
|
42
|
+
name: string;
|
|
43
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle";
|
|
44
|
+
description?: string | undefined;
|
|
45
|
+
isActive?: boolean | undefined;
|
|
46
|
+
isShared?: boolean | undefined;
|
|
47
|
+
defaults?: Record<string, import("../../..").FirestoreValue> | undefined;
|
|
48
|
+
}, {
|
|
49
|
+
name: string;
|
|
50
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle";
|
|
51
|
+
description?: string | undefined;
|
|
52
|
+
isActive?: boolean | undefined;
|
|
53
|
+
isShared?: boolean | undefined;
|
|
54
|
+
defaults?: Record<string, import("../../..").FirestoreValue> | undefined;
|
|
55
|
+
}>;
|
|
56
|
+
/** Update contract — every field optional, and the same ownership fields absent. */
|
|
57
|
+
export declare const listingTemplateUpdateSchema: z.ZodObject<{
|
|
58
|
+
name: z.ZodOptional<z.ZodString>;
|
|
59
|
+
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
60
|
+
listingType: z.ZodOptional<z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"]>>;
|
|
61
|
+
defaults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<import("../../..").FirestoreValue, z.ZodTypeDef, import("../../..").FirestoreValue>>>;
|
|
62
|
+
isShared: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
isActive: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
}, "strip", z.ZodTypeAny, {
|
|
65
|
+
name?: string | undefined;
|
|
66
|
+
description?: string | undefined;
|
|
67
|
+
listingType?: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle" | undefined;
|
|
68
|
+
isActive?: boolean | undefined;
|
|
69
|
+
isShared?: boolean | undefined;
|
|
70
|
+
defaults?: Record<string, import("../../..").FirestoreValue> | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
name?: string | undefined;
|
|
73
|
+
description?: string | undefined;
|
|
74
|
+
listingType?: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live" | "bundle" | undefined;
|
|
75
|
+
isActive?: boolean | undefined;
|
|
76
|
+
isShared?: boolean | undefined;
|
|
77
|
+
defaults?: Record<string, import("../../..").FirestoreValue> | undefined;
|
|
78
|
+
}>;
|