includio-cms 0.36.8 → 0.37.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/API.md +179 -3
- package/CHANGELOG.md +64 -0
- package/DOCS.md +28 -3
- package/ROADMAP.md +18 -0
- package/dist/admin/client/booking/booking-dashboard.svelte +40 -0
- package/dist/admin/client/booking/booking-dashboard.svelte.d.ts +3 -0
- package/dist/admin/client/booking/customer-panel.svelte +102 -0
- package/dist/admin/client/booking/customer-panel.svelte.d.ts +11 -0
- package/dist/admin/client/booking/customer-view.d.ts +52 -0
- package/dist/admin/client/booking/customer-view.js +134 -0
- package/dist/admin/client/booking/participant-data-panel.svelte +330 -0
- package/dist/admin/client/booking/participant-data-panel.svelte.d.ts +22 -0
- package/dist/admin/client/booking/reservation-detail-page.svelte +637 -0
- package/dist/admin/client/booking/reservation-detail-page.svelte.d.ts +3 -0
- package/dist/admin/client/booking/reservations-page.svelte +221 -0
- package/dist/admin/client/booking/reservations-page.svelte.d.ts +3 -0
- package/dist/admin/client/collection/collection-entries.svelte +21 -2
- package/dist/admin/client/collection/entry-link.svelte +6 -4
- package/dist/admin/client/collection/entry-link.svelte.d.ts +3 -1
- package/dist/admin/client/collection/row-actions.svelte +12 -4
- package/dist/admin/client/collection/row-actions.svelte.d.ts +1 -0
- package/dist/admin/client/collection/status-badge.svelte +39 -3
- package/dist/admin/client/collection/status-badge.svelte.d.ts +5 -3
- package/dist/admin/client/entry/entry.svelte +26 -9
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +73 -10
- package/dist/admin/client/entry/hybrid/hybrid-preview.svelte.d.ts +6 -5
- package/dist/admin/client/entry/preview-views-context.svelte.d.ts +22 -0
- package/dist/admin/client/entry/preview-views-context.svelte.js +58 -0
- package/dist/admin/client/entry/preview-views.d.ts +27 -0
- package/dist/admin/client/entry/preview-views.js +33 -0
- package/dist/admin/client/index.d.ts +3 -0
- package/dist/admin/client/index.js +3 -0
- package/dist/admin/client/modules/dashboard-registry.d.ts +7 -0
- package/dist/admin/client/modules/dashboard-registry.js +11 -0
- package/dist/admin/client/modules/module-dashboard-page.svelte +26 -0
- package/dist/admin/client/modules/module-dashboard-page.svelte.d.ts +6 -0
- package/dist/admin/client/modules/stat-card.svelte +22 -0
- package/dist/admin/client/modules/stat-card.svelte.d.ts +10 -0
- package/dist/admin/client/shop/shop-dashboard.svelte +29 -0
- package/dist/admin/client/shop/shop-dashboard.svelte.d.ts +3 -0
- package/dist/admin/components/fields/relation-field.svelte +11 -2
- package/dist/admin/components/icons/icon-map.js +8 -0
- package/dist/admin/components/layout/app-sidebar.svelte +45 -14
- package/dist/admin/components/layout/context-switcher.svelte +90 -0
- package/dist/admin/components/layout/context-switcher.svelte.d.ts +3 -0
- package/dist/admin/components/layout/lang.d.ts +4 -0
- package/dist/admin/components/layout/lang.js +8 -0
- package/dist/admin/components/layout/layout-renderer.svelte +2 -1
- package/dist/admin/components/layout/layout-tabs.svelte +14 -0
- package/dist/admin/components/layout/layout-tabs.svelte.d.ts +2 -0
- package/dist/admin/components/layout/nav-collections.svelte +16 -9
- package/dist/admin/components/layout/nav-collections.svelte.d.ts +5 -1
- package/dist/admin/components/layout/nav-global.svelte +45 -0
- package/dist/admin/components/layout/nav-global.svelte.d.ts +3 -0
- package/dist/admin/components/layout/nav-main.svelte +8 -32
- package/dist/admin/components/layout/nav-main.svelte.d.ts +6 -1
- package/dist/admin/components/layout/nav-module.svelte +57 -0
- package/dist/admin/components/layout/nav-module.svelte.d.ts +7 -0
- package/dist/admin/components/layout/nav-section.svelte +1 -1
- package/dist/admin/components/layout/nav-section.svelte.d.ts +1 -1
- package/dist/admin/components/layout/nav-singletons.svelte +14 -7
- package/dist/admin/components/layout/nav-singletons.svelte.d.ts +5 -1
- package/dist/admin/remote/booking.remote.d.ts +244 -0
- package/dist/admin/remote/booking.remote.js +283 -0
- package/dist/admin/remote/entry.remote.d.ts +3 -0
- package/dist/admin/remote/entry.remote.js +14 -3
- package/dist/admin/remote/index.d.ts +2 -0
- package/dist/admin/remote/index.js +2 -0
- package/dist/admin/remote/modules.remote.d.ts +10 -0
- package/dist/admin/remote/modules.remote.js +14 -0
- package/dist/admin/state/active-context-resolve.d.ts +37 -0
- package/dist/admin/state/active-context-resolve.js +66 -0
- package/dist/admin/state/active-context.svelte.d.ts +8 -0
- package/dist/admin/state/active-context.svelte.js +27 -0
- package/dist/booking/adjustments.d.ts +33 -0
- package/dist/booking/adjustments.js +26 -0
- package/dist/booking/capacity.d.ts +12 -0
- package/dist/booking/capacity.js +10 -0
- package/dist/booking/client/index.d.ts +39 -0
- package/dist/booking/client/index.js +44 -0
- package/dist/booking/client/use-booking.svelte.d.ts +25 -0
- package/dist/booking/client/use-booking.svelte.js +56 -0
- package/dist/booking/config.d.ts +156 -0
- package/dist/booking/config.js +36 -0
- package/dist/booking/draft.d.ts +77 -0
- package/dist/booking/draft.js +67 -0
- package/dist/booking/expiry-logic.d.ts +30 -0
- package/dist/booking/expiry-logic.js +33 -0
- package/dist/booking/index.d.ts +18 -0
- package/dist/booking/index.js +52 -0
- package/dist/booking/ledger.d.ts +46 -0
- package/dist/booking/ledger.js +60 -0
- package/dist/booking/number.d.ts +2 -0
- package/dist/booking/number.js +11 -0
- package/dist/booking/participant-fields/access.d.ts +10 -0
- package/dist/booking/participant-fields/access.js +14 -0
- package/dist/booking/participant-fields/age.d.ts +12 -0
- package/dist/booking/participant-fields/age.js +28 -0
- package/dist/booking/participant-fields/completeness.d.ts +8 -0
- package/dist/booking/participant-fields/completeness.js +13 -0
- package/dist/booking/participant-fields/group.d.ts +6 -0
- package/dist/booking/participant-fields/group.js +15 -0
- package/dist/booking/participant-fields/index.d.ts +6 -0
- package/dist/booking/participant-fields/index.js +6 -0
- package/dist/booking/participant-fields/types.d.ts +50 -0
- package/dist/booking/participant-fields/types.js +5 -0
- package/dist/booking/participant-fields/validate.d.ts +7 -0
- package/dist/booking/participant-fields/validate.js +44 -0
- package/dist/booking/participant-pricing.d.ts +93 -0
- package/dist/booking/participant-pricing.js +91 -0
- package/dist/booking/participants-view.d.ts +32 -0
- package/dist/booking/participants-view.js +22 -0
- package/dist/booking/payment-context.d.ts +19 -0
- package/dist/booking/payment-context.js +29 -0
- package/dist/booking/pricing-inputs.d.ts +28 -0
- package/dist/booking/pricing-inputs.js +35 -0
- package/dist/booking/pricing.d.ts +86 -0
- package/dist/booking/pricing.js +125 -0
- package/dist/booking/recompute.d.ts +22 -0
- package/dist/booking/recompute.js +31 -0
- package/dist/booking/reminders-schedule.d.ts +11 -0
- package/dist/booking/reminders-schedule.js +28 -0
- package/dist/booking/server/adjustments.d.ts +27 -0
- package/dist/booking/server/adjustments.js +136 -0
- package/dist/booking/server/bookings.d.ts +45 -0
- package/dist/booking/server/bookings.js +288 -0
- package/dist/booking/server/catalog.d.ts +9 -0
- package/dist/booking/server/catalog.js +20 -0
- package/dist/booking/server/db.d.ts +7 -0
- package/dist/booking/server/db.js +18 -0
- package/dist/booking/server/email.d.ts +23 -0
- package/dist/booking/server/email.js +59 -0
- package/dist/booking/server/emailTemplateRegistry.d.ts +29 -0
- package/dist/booking/server/emailTemplateRegistry.js +125 -0
- package/dist/booking/server/http/create-handler.d.ts +5 -0
- package/dist/booking/server/http/create-handler.js +68 -0
- package/dist/booking/server/http/index.d.ts +4 -0
- package/dist/booking/server/http/index.js +4 -0
- package/dist/booking/server/http/maintenance-handler.d.ts +9 -0
- package/dist/booking/server/http/maintenance-handler.js +36 -0
- package/dist/booking/server/http/portal-handler.d.ts +13 -0
- package/dist/booking/server/http/portal-handler.js +99 -0
- package/dist/booking/server/http/webhook-handler.d.ts +9 -0
- package/dist/booking/server/http/webhook-handler.js +39 -0
- package/dist/booking/server/index.d.ts +12 -0
- package/dist/booking/server/index.js +14 -0
- package/dist/booking/server/maintenance.d.ts +28 -0
- package/dist/booking/server/maintenance.js +134 -0
- package/dist/booking/server/participants.d.ts +26 -0
- package/dist/booking/server/participants.js +92 -0
- package/dist/booking/server/payments.d.ts +34 -0
- package/dist/booking/server/payments.js +207 -0
- package/dist/booking/server/portal-session.d.ts +16 -0
- package/dist/booking/server/portal-session.js +42 -0
- package/dist/booking/server/portal.d.ts +207 -0
- package/dist/booking/server/portal.js +234 -0
- package/dist/booking/server/refunds.d.ts +7 -0
- package/dist/booking/server/refunds.js +58 -0
- package/dist/booking/server/reminders.d.ts +9 -0
- package/dist/booking/server/reminders.js +24 -0
- package/dist/booking/server/validation.d.ts +17 -0
- package/dist/booking/server/validation.js +55 -0
- package/dist/booking/state-machine.d.ts +41 -0
- package/dist/booking/state-machine.js +73 -0
- package/dist/booking/templates/_partials/footer.en.html +4 -0
- package/dist/booking/templates/_partials/footer.pl.html +4 -0
- package/dist/booking/templates/_partials/header.en.html +4 -0
- package/dist/booking/templates/_partials/header.pl.html +4 -0
- package/dist/booking/templates/balance-due.en.html +10 -0
- package/dist/booking/templates/balance-due.pl.html +10 -0
- package/dist/booking/templates/balance-overdue-cancelled.en.html +5 -0
- package/dist/booking/templates/balance-overdue-cancelled.pl.html +5 -0
- package/dist/booking/templates/booking-received.en.html +9 -0
- package/dist/booking/templates/booking-received.pl.html +9 -0
- package/dist/booking/templates/deposit-paid.en.html +6 -0
- package/dist/booking/templates/deposit-paid.pl.html +6 -0
- package/dist/booking/templates/payment-link.en.html +5 -0
- package/dist/booking/templates/payment-link.pl.html +5 -0
- package/dist/booking/templates/payment-received.en.html +10 -0
- package/dist/booking/templates/payment-received.pl.html +10 -0
- package/dist/booking/totals.d.ts +38 -0
- package/dist/booking/totals.js +61 -0
- package/dist/booking/webhook-logic.d.ts +28 -0
- package/dist/booking/webhook-logic.js +50 -0
- package/dist/cli/create-user.d.ts +7 -1
- package/dist/cli/create-user.js +23 -15
- package/dist/cli/index.js +55 -7
- package/dist/cli/scaffold/admin.d.ts +6 -0
- package/dist/cli/scaffold/admin.js +5 -3
- package/dist/cli/scaffold/booking.d.ts +12 -0
- package/dist/cli/scaffold/booking.js +103 -0
- package/dist/core/cms.d.ts +24 -9
- package/dist/core/cms.js +72 -34
- package/dist/core/config/validatePreviews.d.ts +12 -0
- package/dist/core/config/validatePreviews.js +90 -0
- package/dist/core/fields/dotPath.d.ts +4 -0
- package/dist/core/fields/dotPath.js +18 -0
- package/dist/core/fields/slugPath.d.ts +9 -1
- package/dist/core/fields/slugPath.js +16 -2
- package/dist/core/fields/slugify.d.ts +3 -0
- package/dist/core/fields/slugify.js +4 -0
- package/dist/core/server/entries/operations/duplicate.d.ts +10 -0
- package/dist/core/server/entries/operations/duplicate.js +73 -0
- package/dist/core/server/entries/operations/slugNormalize.d.ts +8 -0
- package/dist/core/server/entries/operations/slugNormalize.js +20 -0
- package/dist/core/server/entries/operations/slugUniqueness.d.ts +17 -0
- package/dist/core/server/entries/operations/slugUniqueness.js +39 -0
- package/dist/core/server/fields/resolveRelationFields.d.ts +11 -2
- package/dist/core/server/fields/resolveRelationFields.js +12 -3
- package/dist/core/server/generator/generator.js +7 -2
- package/dist/db-postgres/schema/booking/bookingAdjustments.d.ts +186 -0
- package/dist/db-postgres/schema/booking/bookingAdjustments.js +22 -0
- package/dist/db-postgres/schema/booking/bookingItemPersons.d.ts +117 -0
- package/dist/db-postgres/schema/booking/bookingItemPersons.js +22 -0
- package/dist/db-postgres/schema/booking/bookingItems.d.ts +181 -0
- package/dist/db-postgres/schema/booking/bookingItems.js +22 -0
- package/dist/db-postgres/schema/booking/bookingPayments.d.ts +204 -0
- package/dist/db-postgres/schema/booking/bookingPayments.js +25 -0
- package/dist/db-postgres/schema/booking/bookingPersons.d.ts +99 -0
- package/dist/db-postgres/schema/booking/bookingPersons.js +17 -0
- package/dist/db-postgres/schema/booking/bookingReminders.d.ts +131 -0
- package/dist/db-postgres/schema/booking/bookingReminders.js +18 -0
- package/dist/db-postgres/schema/booking/bookings.d.ts +307 -0
- package/dist/db-postgres/schema/booking/bookings.js +40 -0
- package/dist/db-postgres/schema/booking/index.d.ts +7 -0
- package/dist/db-postgres/schema/booking/index.js +7 -0
- package/dist/db-postgres/schema/index.d.ts +1 -0
- package/dist/db-postgres/schema/index.js +1 -0
- package/dist/db-postgres/schema-booking.d.ts +1 -0
- package/dist/db-postgres/schema-booking.js +1 -0
- package/dist/server/security/rate-limit-handler.d.ts +19 -0
- package/dist/server/security/rate-limit-handler.js +34 -0
- package/dist/shop/adapters/payu/client.js +3 -1
- package/dist/shop/adapters/payu/index.js +37 -17
- package/dist/shop/adapters/payu/payload.d.ts +6 -0
- package/dist/shop/adapters/payu/payload.js +1 -1
- package/dist/shop/adapters/stripe/index.js +36 -21
- package/dist/shop/index.d.ts +11 -2
- package/dist/shop/index.js +43 -1
- package/dist/shop/rate-limit.d.ts +1 -9
- package/dist/shop/rate-limit.js +3 -28
- package/dist/shop/types.d.ts +19 -0
- package/dist/sveltekit/config.d.ts +4 -0
- package/dist/sveltekit/config.js +6 -0
- package/dist/types/cms.d.ts +15 -1
- package/dist/types/cms.schema.d.ts +96 -2
- package/dist/types/cms.schema.js +84 -1
- package/dist/types/config.d.ts +33 -0
- package/dist/types/layout.d.ts +6 -0
- package/dist/types/modules.d.ts +133 -0
- package/dist/types/modules.js +27 -0
- package/dist/updates/0.36.9/index.d.ts +2 -0
- package/dist/updates/0.36.9/index.js +12 -0
- package/dist/updates/0.37.0/index.d.ts +2 -0
- package/dist/updates/0.37.0/index.js +52 -0
- package/dist/updates/index.js +5 -1
- package/package.json +19 -1
- package/dist/admin/components/layout/nav-shop.svelte +0 -33
- package/dist/admin/components/layout/nav-shop.svelte.d.ts +0 -3
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { bookingsTable } from '../../db-postgres/schema/booking/index.js';
|
|
2
|
+
import { type BookingStatus } from '../../booking/state-machine.js';
|
|
3
|
+
import type { FieldDef } from '../../booking/participant-fields/types.js';
|
|
4
|
+
/** Whether the booking module is registered. @public */
|
|
5
|
+
export declare const getBookingEnabled: import("@sveltejs/kit").RemoteQueryFunction<void, boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Lists active (non-deleted) bookings, newest first — paginated server-side.
|
|
8
|
+
*
|
|
9
|
+
* Search spans the booking number AND the `customer` bag. The bag's shape is defined by the
|
|
10
|
+
* consumer, not by the core, so we match against its text form instead of guessing key names.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export declare const listBookings: import("@sveltejs/kit").RemoteQueryFunction<{
|
|
15
|
+
status?: "paid" | "cancelled" | "draft" | "reserved" | "partially_paid" | "completed" | undefined;
|
|
16
|
+
search?: string | undefined;
|
|
17
|
+
limit?: number | undefined;
|
|
18
|
+
offset?: number | undefined;
|
|
19
|
+
} | undefined, {
|
|
20
|
+
items: {
|
|
21
|
+
id: string;
|
|
22
|
+
number: string;
|
|
23
|
+
status: BookingStatus;
|
|
24
|
+
currency: string;
|
|
25
|
+
customer: Record<string, unknown>;
|
|
26
|
+
totals: import("../../db-postgres/schema/booking/index.js").BookingTotals;
|
|
27
|
+
accessToken: string;
|
|
28
|
+
staffNotes: string | null;
|
|
29
|
+
language: string | null;
|
|
30
|
+
balanceDueAt: Date | null;
|
|
31
|
+
holdExpiresAt: Date | null;
|
|
32
|
+
cancelReason: string | null;
|
|
33
|
+
deletedAt: Date | null;
|
|
34
|
+
deletedBy: string | null;
|
|
35
|
+
createdAt: Date;
|
|
36
|
+
updatedAt: Date;
|
|
37
|
+
}[];
|
|
38
|
+
total: number;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Aggregate stats for the booking dashboard, computed in SQL.
|
|
42
|
+
*
|
|
43
|
+
* Deliberately NOT derived from {@link listBookings}: that query is paginated, so summing its rows
|
|
44
|
+
* would silently report stats for the first page only.
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare const getBookingStats: import("@sveltejs/kit").RemoteQueryFunction<void, {
|
|
49
|
+
active: number;
|
|
50
|
+
outstanding: number;
|
|
51
|
+
toConfirm: number;
|
|
52
|
+
currency: string;
|
|
53
|
+
}>;
|
|
54
|
+
/** Full booking detail (booking + items + participants + ledger + reminders). @public */
|
|
55
|
+
export declare const getBooking: import("@sveltejs/kit").RemoteQueryFunction<string, {
|
|
56
|
+
booking: {
|
|
57
|
+
id: string;
|
|
58
|
+
number: string;
|
|
59
|
+
status: BookingStatus;
|
|
60
|
+
currency: string;
|
|
61
|
+
customer: Record<string, unknown>;
|
|
62
|
+
totals: import("../../db-postgres/schema/booking/index.js").BookingTotals;
|
|
63
|
+
accessToken: string;
|
|
64
|
+
staffNotes: string | null;
|
|
65
|
+
language: string | null;
|
|
66
|
+
balanceDueAt: Date | null;
|
|
67
|
+
holdExpiresAt: Date | null;
|
|
68
|
+
cancelReason: string | null;
|
|
69
|
+
deletedAt: Date | null;
|
|
70
|
+
deletedBy: string | null;
|
|
71
|
+
createdAt: Date;
|
|
72
|
+
updatedAt: Date;
|
|
73
|
+
};
|
|
74
|
+
items: {
|
|
75
|
+
participantFields: FieldDef[];
|
|
76
|
+
/** Human title of the catalog entry; falls back to the raw ref when unresolvable. */
|
|
77
|
+
tripTitle: string;
|
|
78
|
+
id: string;
|
|
79
|
+
bookingId: string;
|
|
80
|
+
tripRef: string;
|
|
81
|
+
departureDate: Date | null;
|
|
82
|
+
participantsCount: number;
|
|
83
|
+
unitPriceSnapshot: number;
|
|
84
|
+
subtotalSnapshot: number | null;
|
|
85
|
+
appliedDiscounts: import("../../booking/pricing.js").AppliedRule[];
|
|
86
|
+
createdAt: Date;
|
|
87
|
+
updatedAt: Date;
|
|
88
|
+
}[];
|
|
89
|
+
participants: import("../../booking/participants-view.js").FlatParticipant[];
|
|
90
|
+
persons: {
|
|
91
|
+
id: string;
|
|
92
|
+
bookingId: string;
|
|
93
|
+
data: Record<string, unknown>;
|
|
94
|
+
createdAt: Date;
|
|
95
|
+
updatedAt: Date;
|
|
96
|
+
}[];
|
|
97
|
+
assignments: {
|
|
98
|
+
id: string;
|
|
99
|
+
itemId: string;
|
|
100
|
+
personId: string;
|
|
101
|
+
data: Record<string, unknown>;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
updatedAt: Date;
|
|
104
|
+
}[];
|
|
105
|
+
payments: {
|
|
106
|
+
id: string;
|
|
107
|
+
bookingId: string;
|
|
108
|
+
kind: import("../../booking/ledger.js").PaymentKind;
|
|
109
|
+
amount: number;
|
|
110
|
+
status: import("../../booking/ledger.js").PaymentStatus;
|
|
111
|
+
providerRef: string | null;
|
|
112
|
+
paymentLink: string | null;
|
|
113
|
+
createdBy: string;
|
|
114
|
+
paidAt: Date | null;
|
|
115
|
+
createdAt: Date;
|
|
116
|
+
updatedAt: Date;
|
|
117
|
+
}[];
|
|
118
|
+
reminders: {
|
|
119
|
+
id: string;
|
|
120
|
+
bookingId: string;
|
|
121
|
+
type: string;
|
|
122
|
+
templateKey: string;
|
|
123
|
+
scheduledFor: Date;
|
|
124
|
+
sentAt: Date | null;
|
|
125
|
+
createdAt: Date;
|
|
126
|
+
}[];
|
|
127
|
+
adjustments: {
|
|
128
|
+
id: string;
|
|
129
|
+
bookingId: string;
|
|
130
|
+
kind: import("../../booking/adjustments.js").AdjustmentKind;
|
|
131
|
+
amount: number;
|
|
132
|
+
label: string;
|
|
133
|
+
reason: string | null;
|
|
134
|
+
createdBy: string;
|
|
135
|
+
createdAt: Date;
|
|
136
|
+
voidedAt: Date | null;
|
|
137
|
+
voidedBy: string | null;
|
|
138
|
+
}[];
|
|
139
|
+
ageFlag: import("../../booking/participant-fields/types.js").AgeFlagConfig | null;
|
|
140
|
+
/**
|
|
141
|
+
* Anchor-date key inside the `customer` bag. The only piece of that bag's semantics the
|
|
142
|
+
* core knows on its own — everything else the customer panel infers from values.
|
|
143
|
+
*/
|
|
144
|
+
arrivalDateField: string | null;
|
|
145
|
+
/** Optional presentation hints for the `customer` bag (labels + `birthDate` role). */
|
|
146
|
+
customerFields: FieldDef[];
|
|
147
|
+
} | null>;
|
|
148
|
+
/** Published catalog trips for the staff item-editor picker (ref + best-effort title). @public */
|
|
149
|
+
export declare const listBookingCatalog: import("@sveltejs/kit").RemoteQueryFunction<void, {
|
|
150
|
+
ref: string;
|
|
151
|
+
title: string;
|
|
152
|
+
}[]>;
|
|
153
|
+
/** Staff: create a booking from the admin panel. @public */
|
|
154
|
+
export declare const createBookingStaff: import("@sveltejs/kit").RemoteCommand<any, Promise<{
|
|
155
|
+
booking: typeof bookingsTable.$inferSelect;
|
|
156
|
+
accessToken: string;
|
|
157
|
+
}>>;
|
|
158
|
+
/** Staff: edit a booking's items/customer (full edit power). @public */
|
|
159
|
+
export declare const editBookingStaff: import("@sveltejs/kit").RemoteCommand<{
|
|
160
|
+
bookingId: string;
|
|
161
|
+
changes: any;
|
|
162
|
+
}, Promise<{
|
|
163
|
+
number: string;
|
|
164
|
+
id: string;
|
|
165
|
+
createdAt: Date;
|
|
166
|
+
status: BookingStatus;
|
|
167
|
+
currency: string;
|
|
168
|
+
language: string | null;
|
|
169
|
+
accessToken: string;
|
|
170
|
+
deletedAt: Date | null;
|
|
171
|
+
deletedBy: string | null;
|
|
172
|
+
updatedAt: Date;
|
|
173
|
+
customer: Record<string, unknown>;
|
|
174
|
+
totals: import("../../db-postgres/schema/booking/index.js").BookingTotals;
|
|
175
|
+
staffNotes: string | null;
|
|
176
|
+
balanceDueAt: Date | null;
|
|
177
|
+
holdExpiresAt: Date | null;
|
|
178
|
+
cancelReason: string | null;
|
|
179
|
+
}>>;
|
|
180
|
+
/** Staff: generate an installment/balance payment link for any amount. @public */
|
|
181
|
+
export declare const addPaymentLink: import("@sveltejs/kit").RemoteCommand<{
|
|
182
|
+
bookingId: string;
|
|
183
|
+
amount: number;
|
|
184
|
+
}, Promise<{
|
|
185
|
+
paymentLink: string | null;
|
|
186
|
+
}>>;
|
|
187
|
+
/** Staff: record a manual cash payment. @public */
|
|
188
|
+
export declare const recordCashPayment: import("@sveltejs/kit").RemoteCommand<{
|
|
189
|
+
bookingId: string;
|
|
190
|
+
amount: number;
|
|
191
|
+
}, Promise<{
|
|
192
|
+
ok: boolean;
|
|
193
|
+
}>>;
|
|
194
|
+
/** Staff: refund a paid ledger entry via the adapter. @public */
|
|
195
|
+
export declare const refundBookingPayment: import("@sveltejs/kit").RemoteCommand<{
|
|
196
|
+
paymentId: string;
|
|
197
|
+
amount?: number | undefined;
|
|
198
|
+
}, Promise<{
|
|
199
|
+
ok: boolean;
|
|
200
|
+
}>>;
|
|
201
|
+
/** Staff: change booking status (validated transition). @public */
|
|
202
|
+
export declare const changeBookingStatus: import("@sveltejs/kit").RemoteCommand<{
|
|
203
|
+
bookingId: string;
|
|
204
|
+
to: string;
|
|
205
|
+
}, Promise<{
|
|
206
|
+
ok: boolean;
|
|
207
|
+
}>>;
|
|
208
|
+
/** Staff: cancel a booking (manual). @public */
|
|
209
|
+
export declare const cancelBooking: import("@sveltejs/kit").RemoteCommand<{
|
|
210
|
+
bookingId: string;
|
|
211
|
+
reason?: "manual" | undefined;
|
|
212
|
+
}, Promise<{
|
|
213
|
+
ok: boolean;
|
|
214
|
+
}>>;
|
|
215
|
+
/** Staff: send a transactional booking email manually. @public */
|
|
216
|
+
export declare const sendBookingEmailCmd: import("@sveltejs/kit").RemoteCommand<{
|
|
217
|
+
bookingId: string;
|
|
218
|
+
kind: string;
|
|
219
|
+
}, Promise<{
|
|
220
|
+
ok: boolean;
|
|
221
|
+
}>>;
|
|
222
|
+
/** Staff: edit a participant's custom-field data (schema-validated). @public */
|
|
223
|
+
export declare const updateParticipantData: import("@sveltejs/kit").RemoteCommand<{
|
|
224
|
+
participantId: string;
|
|
225
|
+
data: Record<string, unknown>;
|
|
226
|
+
}, Promise<{
|
|
227
|
+
ok: boolean;
|
|
228
|
+
}>>;
|
|
229
|
+
/** Staff: add a manual adjustment (surcharge/discount). Amount is a positive magnitude in minor units. @public */
|
|
230
|
+
export declare const addAdjustment: import("@sveltejs/kit").RemoteCommand<{
|
|
231
|
+
bookingId: string;
|
|
232
|
+
kind: "manual_surcharge" | "manual_discount";
|
|
233
|
+
amount: number;
|
|
234
|
+
label: string;
|
|
235
|
+
reason?: string | undefined;
|
|
236
|
+
}, Promise<{
|
|
237
|
+
ok: boolean;
|
|
238
|
+
}>>;
|
|
239
|
+
/** Staff: void (soft-delete) a manual adjustment. @public */
|
|
240
|
+
export declare const voidAdjustment: import("@sveltejs/kit").RemoteCommand<{
|
|
241
|
+
adjustmentId: string;
|
|
242
|
+
}, Promise<{
|
|
243
|
+
ok: boolean;
|
|
244
|
+
}>>;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { command, query } from '$app/server';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
import { getCMS } from '../../core/cms.js';
|
|
4
|
+
import { getBookingDb } from '../../booking/server/db.js';
|
|
5
|
+
import { bookingsTable, bookingItemsTable, bookingPersonsTable, bookingItemPersonsTable, bookingPaymentsTable, bookingRemindersTable, bookingAdjustmentsTable } from '../../db-postgres/schema/booking/index.js';
|
|
6
|
+
import { flattenAssignments } from '../../booking/participants-view.js';
|
|
7
|
+
import { and, desc, eq, ilike, inArray, isNull, or, sql } from 'drizzle-orm';
|
|
8
|
+
import { createBooking, editBooking } from '../../booking/server/bookings.js';
|
|
9
|
+
import { createInstallmentPayment, recordCash } from '../../booking/server/payments.js';
|
|
10
|
+
import { addBookingAdjustment as addAdjustmentSvc, voidBookingAdjustment as voidAdjustmentSvc } from '../../booking/server/adjustments.js';
|
|
11
|
+
import { refundPayment } from '../../booking/server/refunds.js';
|
|
12
|
+
import { saveParticipantData } from '../../booking/server/participants.js';
|
|
13
|
+
import { sendBookingEmail } from '../../booking/server/email.js';
|
|
14
|
+
import { assertTransition, BOOKING_STATUSES } from '../../booking/state-machine.js';
|
|
15
|
+
import { resolveParticipantFields } from '../../booking/config.js';
|
|
16
|
+
import { resolveEntry, resolveEntries } from '../../core/server/entries/operations/resolveEntry.js';
|
|
17
|
+
import { requireAuth } from './middleware/auth.js';
|
|
18
|
+
/**
|
|
19
|
+
* Best-effort display title of a catalog entry. The core does not know the catalog's shape, so it
|
|
20
|
+
* tries the conventional title-ish keys and falls back to the raw ref. Shared by the item picker
|
|
21
|
+
* and the booking detail so both name a trip the same way.
|
|
22
|
+
*/
|
|
23
|
+
function catalogTitle(entry, ref) {
|
|
24
|
+
const title = entry.title ?? entry.name ?? entry._slug;
|
|
25
|
+
return title ? String(title) : ref;
|
|
26
|
+
}
|
|
27
|
+
/** Whether the booking module is registered. @public */
|
|
28
|
+
export const getBookingEnabled = query(async () => {
|
|
29
|
+
return getCMS().hasModule('booking');
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Lists active (non-deleted) bookings, newest first — paginated server-side.
|
|
33
|
+
*
|
|
34
|
+
* Search spans the booking number AND the `customer` bag. The bag's shape is defined by the
|
|
35
|
+
* consumer, not by the core, so we match against its text form instead of guessing key names.
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
export const listBookings = query(z
|
|
40
|
+
.object({
|
|
41
|
+
status: z.enum(BOOKING_STATUSES).optional(),
|
|
42
|
+
search: z.string().optional(),
|
|
43
|
+
limit: z.number().int().min(1).max(200).default(50),
|
|
44
|
+
offset: z.number().int().min(0).default(0)
|
|
45
|
+
})
|
|
46
|
+
.optional(), async (opts) => {
|
|
47
|
+
requireAuth();
|
|
48
|
+
if (!getCMS().hasModule('booking'))
|
|
49
|
+
return { items: [], total: 0 };
|
|
50
|
+
const { status, search, limit = 50, offset = 0 } = opts ?? {};
|
|
51
|
+
const db = getBookingDb();
|
|
52
|
+
const filters = [isNull(bookingsTable.deletedAt)];
|
|
53
|
+
if (status)
|
|
54
|
+
filters.push(eq(bookingsTable.status, status));
|
|
55
|
+
if (search?.trim()) {
|
|
56
|
+
const term = `%${search.trim()}%`;
|
|
57
|
+
filters.push(or(ilike(bookingsTable.number, term), sql `${bookingsTable.customer}::text ILIKE ${term}`));
|
|
58
|
+
}
|
|
59
|
+
const where = and(...filters);
|
|
60
|
+
const [items, counted] = await Promise.all([
|
|
61
|
+
db
|
|
62
|
+
.select()
|
|
63
|
+
.from(bookingsTable)
|
|
64
|
+
.where(where)
|
|
65
|
+
.orderBy(desc(bookingsTable.createdAt))
|
|
66
|
+
.limit(limit)
|
|
67
|
+
.offset(offset),
|
|
68
|
+
db.select({ count: sql `count(*)::int` }).from(bookingsTable).where(where)
|
|
69
|
+
]);
|
|
70
|
+
return { items, total: counted[0]?.count ?? 0 };
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Aggregate stats for the booking dashboard, computed in SQL.
|
|
74
|
+
*
|
|
75
|
+
* Deliberately NOT derived from {@link listBookings}: that query is paginated, so summing its rows
|
|
76
|
+
* would silently report stats for the first page only.
|
|
77
|
+
*
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
export const getBookingStats = query(async () => {
|
|
81
|
+
requireAuth();
|
|
82
|
+
if (!getCMS().hasModule('booking'))
|
|
83
|
+
return { active: 0, outstanding: 0, toConfirm: 0, currency: 'PLN' };
|
|
84
|
+
const db = getBookingDb();
|
|
85
|
+
const cfg = getCMS().getModuleConfig('booking') ?? null;
|
|
86
|
+
const [row] = await db
|
|
87
|
+
.select({
|
|
88
|
+
active: sql `count(*)::int`,
|
|
89
|
+
outstanding: sql `coalesce(sum((${bookingsTable.totals}->>'balance')::bigint), 0)::bigint`,
|
|
90
|
+
toConfirm: sql `count(*) filter (where ${bookingsTable.status} in ('draft','reserved'))::int`
|
|
91
|
+
})
|
|
92
|
+
.from(bookingsTable)
|
|
93
|
+
.where(isNull(bookingsTable.deletedAt));
|
|
94
|
+
return {
|
|
95
|
+
active: row?.active ?? 0,
|
|
96
|
+
outstanding: Number(row?.outstanding ?? 0),
|
|
97
|
+
toConfirm: row?.toConfirm ?? 0,
|
|
98
|
+
currency: cfg?.currency ?? 'PLN'
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
/** Full booking detail (booking + items + participants + ledger + reminders). @public */
|
|
102
|
+
export const getBooking = query(z.string().uuid(), async (id) => {
|
|
103
|
+
requireAuth();
|
|
104
|
+
if (!getCMS().hasModule('booking'))
|
|
105
|
+
return null;
|
|
106
|
+
const db = getBookingDb();
|
|
107
|
+
const [booking] = await db
|
|
108
|
+
.select()
|
|
109
|
+
.from(bookingsTable)
|
|
110
|
+
.where(and(eq(bookingsTable.id, id), isNull(bookingsTable.deletedAt)));
|
|
111
|
+
if (!booking)
|
|
112
|
+
return null;
|
|
113
|
+
const items = await db.select().from(bookingItemsTable).where(eq(bookingItemsTable.bookingId, id));
|
|
114
|
+
const itemIds = items.map((i) => i.id);
|
|
115
|
+
const persons = await db
|
|
116
|
+
.select()
|
|
117
|
+
.from(bookingPersonsTable)
|
|
118
|
+
.where(eq(bookingPersonsTable.bookingId, id));
|
|
119
|
+
const assignments = itemIds.length
|
|
120
|
+
? await db
|
|
121
|
+
.select()
|
|
122
|
+
.from(bookingItemPersonsTable)
|
|
123
|
+
.where(inArray(bookingItemPersonsTable.itemId, itemIds))
|
|
124
|
+
: [];
|
|
125
|
+
const participants = flattenAssignments(persons, assignments);
|
|
126
|
+
const payments = await db
|
|
127
|
+
.select()
|
|
128
|
+
.from(bookingPaymentsTable)
|
|
129
|
+
.where(eq(bookingPaymentsTable.bookingId, id));
|
|
130
|
+
const reminders = await db
|
|
131
|
+
.select()
|
|
132
|
+
.from(bookingRemindersTable)
|
|
133
|
+
.where(eq(bookingRemindersTable.bookingId, id));
|
|
134
|
+
const adjustments = await db
|
|
135
|
+
.select()
|
|
136
|
+
.from(bookingAdjustmentsTable)
|
|
137
|
+
.where(eq(bookingAdjustmentsTable.bookingId, id))
|
|
138
|
+
.orderBy(desc(bookingAdjustmentsTable.createdAt));
|
|
139
|
+
// Resolve the participant-field schema AND a display title per catalog entry (booking-agnostic).
|
|
140
|
+
const cfg = getCMS().getModuleConfig('booking') ?? null;
|
|
141
|
+
const ageFlag = cfg?.ageFlag ?? null;
|
|
142
|
+
// Resolve whenever a catalog exists: staff must see the trip's NAME, not its uuid.
|
|
143
|
+
const needsEntry = cfg != null && cfg.catalogCollection != null;
|
|
144
|
+
const schemaByRef = new Map();
|
|
145
|
+
const titleByRef = new Map();
|
|
146
|
+
if (cfg) {
|
|
147
|
+
for (const ref of new Set(items.map((i) => i.tripRef))) {
|
|
148
|
+
let entry = {};
|
|
149
|
+
if (needsEntry) {
|
|
150
|
+
const resolved = await resolveEntry({ id: ref, status: 'published' });
|
|
151
|
+
if (resolved)
|
|
152
|
+
entry = resolved;
|
|
153
|
+
}
|
|
154
|
+
schemaByRef.set(ref, resolveParticipantFields(cfg, entry));
|
|
155
|
+
titleByRef.set(ref, catalogTitle(entry, ref));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const itemsWithSchema = items.map((i) => ({
|
|
159
|
+
...i,
|
|
160
|
+
participantFields: schemaByRef.get(i.tripRef) ?? [],
|
|
161
|
+
/** Human title of the catalog entry; falls back to the raw ref when unresolvable. */
|
|
162
|
+
tripTitle: titleByRef.get(i.tripRef) ?? i.tripRef
|
|
163
|
+
}));
|
|
164
|
+
return {
|
|
165
|
+
booking,
|
|
166
|
+
items: itemsWithSchema,
|
|
167
|
+
participants,
|
|
168
|
+
persons,
|
|
169
|
+
assignments,
|
|
170
|
+
payments,
|
|
171
|
+
reminders,
|
|
172
|
+
adjustments,
|
|
173
|
+
ageFlag,
|
|
174
|
+
/**
|
|
175
|
+
* Anchor-date key inside the `customer` bag. The only piece of that bag's semantics the
|
|
176
|
+
* core knows on its own — everything else the customer panel infers from values.
|
|
177
|
+
*/
|
|
178
|
+
arrivalDateField: cfg?.arrivalDateField ?? null,
|
|
179
|
+
/** Optional presentation hints for the `customer` bag (labels + `birthDate` role). */
|
|
180
|
+
customerFields: cfg?.customerFields ?? []
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
/** Published catalog trips for the staff item-editor picker (ref + best-effort title). @public */
|
|
184
|
+
export const listBookingCatalog = query(async () => {
|
|
185
|
+
requireAuth();
|
|
186
|
+
const cfg = getCMS().getModuleConfig('booking');
|
|
187
|
+
if (!cfg?.catalogCollection)
|
|
188
|
+
return [];
|
|
189
|
+
const entries = await resolveEntries({ collection: cfg.catalogCollection, status: 'published' });
|
|
190
|
+
return entries.map((e) => {
|
|
191
|
+
const rec = e;
|
|
192
|
+
const ref = String(rec._id ?? '');
|
|
193
|
+
return { ref, title: catalogTitle(rec, ref) };
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
/** Staff: create a booking from the admin panel. @public */
|
|
197
|
+
export const createBookingStaff = command(z.any(), async (input) => {
|
|
198
|
+
requireAuth();
|
|
199
|
+
return createBooking(input);
|
|
200
|
+
});
|
|
201
|
+
/** Staff: edit a booking's items/customer (full edit power). @public */
|
|
202
|
+
export const editBookingStaff = command(z.object({ bookingId: z.string().uuid(), changes: z.any() }), async ({ bookingId, changes }) => {
|
|
203
|
+
requireAuth();
|
|
204
|
+
return editBooking(bookingId, changes, { actor: 'staff' });
|
|
205
|
+
});
|
|
206
|
+
/** Staff: generate an installment/balance payment link for any amount. @public */
|
|
207
|
+
export const addPaymentLink = command(z.object({ bookingId: z.string().uuid(), amount: z.number().int().positive() }), async ({ bookingId, amount }) => {
|
|
208
|
+
requireAuth();
|
|
209
|
+
const result = await createInstallmentPayment(bookingId, amount);
|
|
210
|
+
if (result.paymentLink) {
|
|
211
|
+
await sendBookingEmail(bookingId, 'payment-link', {
|
|
212
|
+
amount,
|
|
213
|
+
paymentLink: result.paymentLink
|
|
214
|
+
}).catch((e) => console.error('[booking] payment-link email failed', e));
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
});
|
|
218
|
+
/** Staff: record a manual cash payment. @public */
|
|
219
|
+
export const recordCashPayment = command(z.object({ bookingId: z.string().uuid(), amount: z.number().int().positive() }), async ({ bookingId, amount }) => {
|
|
220
|
+
requireAuth();
|
|
221
|
+
await recordCash(bookingId, amount);
|
|
222
|
+
return { ok: true };
|
|
223
|
+
});
|
|
224
|
+
/** Staff: refund a paid ledger entry via the adapter. @public */
|
|
225
|
+
export const refundBookingPayment = command(z.object({ paymentId: z.string().uuid(), amount: z.number().int().positive().optional() }), async ({ paymentId, amount }) => {
|
|
226
|
+
requireAuth();
|
|
227
|
+
await refundPayment(paymentId, amount);
|
|
228
|
+
return { ok: true };
|
|
229
|
+
});
|
|
230
|
+
/** Staff: change booking status (validated transition). @public */
|
|
231
|
+
export const changeBookingStatus = command(z.object({ bookingId: z.string().uuid(), to: z.string() }), async ({ bookingId, to }) => {
|
|
232
|
+
requireAuth();
|
|
233
|
+
const db = getBookingDb();
|
|
234
|
+
const [b] = await db.select().from(bookingsTable).where(eq(bookingsTable.id, bookingId));
|
|
235
|
+
if (!b)
|
|
236
|
+
throw new Error('Booking not found');
|
|
237
|
+
assertTransition(b.status, to); // throws BookingStateError on illegal move
|
|
238
|
+
await db
|
|
239
|
+
.update(bookingsTable)
|
|
240
|
+
.set({ status: to, updatedAt: new Date() })
|
|
241
|
+
.where(eq(bookingsTable.id, bookingId));
|
|
242
|
+
return { ok: true };
|
|
243
|
+
});
|
|
244
|
+
/** Staff: cancel a booking (manual). @public */
|
|
245
|
+
export const cancelBooking = command(z.object({ bookingId: z.string().uuid(), reason: z.enum(['manual']).default('manual') }), async ({ bookingId, reason }) => {
|
|
246
|
+
requireAuth();
|
|
247
|
+
const db = getBookingDb();
|
|
248
|
+
await db
|
|
249
|
+
.update(bookingsTable)
|
|
250
|
+
.set({ status: 'cancelled', cancelReason: reason, updatedAt: new Date() })
|
|
251
|
+
.where(eq(bookingsTable.id, bookingId));
|
|
252
|
+
return { ok: true };
|
|
253
|
+
});
|
|
254
|
+
/** Staff: send a transactional booking email manually. @public */
|
|
255
|
+
export const sendBookingEmailCmd = command(z.object({ bookingId: z.string().uuid(), kind: z.string() }), async ({ bookingId, kind }) => {
|
|
256
|
+
requireAuth();
|
|
257
|
+
await sendBookingEmail(bookingId, kind);
|
|
258
|
+
return { ok: true };
|
|
259
|
+
});
|
|
260
|
+
/** Staff: edit a participant's custom-field data (schema-validated). @public */
|
|
261
|
+
export const updateParticipantData = command(z.object({ participantId: z.string().uuid(), data: z.record(z.string(), z.unknown()) }), async ({ participantId, data }) => {
|
|
262
|
+
requireAuth();
|
|
263
|
+
await saveParticipantData(participantId, data, 'staff');
|
|
264
|
+
return { ok: true };
|
|
265
|
+
});
|
|
266
|
+
/** Staff: add a manual adjustment (surcharge/discount). Amount is a positive magnitude in minor units. @public */
|
|
267
|
+
export const addAdjustment = command(z.object({
|
|
268
|
+
bookingId: z.string().uuid(),
|
|
269
|
+
kind: z.enum(['manual_surcharge', 'manual_discount']),
|
|
270
|
+
amount: z.number().int().positive(),
|
|
271
|
+
label: z.string().min(1),
|
|
272
|
+
reason: z.string().optional()
|
|
273
|
+
}), async ({ bookingId, kind, amount, label, reason }) => {
|
|
274
|
+
const { user } = requireAuth();
|
|
275
|
+
await addAdjustmentSvc(bookingId, { kind, magnitude: amount, label, reason }, { actor: user.email ?? 'staff' });
|
|
276
|
+
return { ok: true };
|
|
277
|
+
});
|
|
278
|
+
/** Staff: void (soft-delete) a manual adjustment. @public */
|
|
279
|
+
export const voidAdjustment = command(z.object({ adjustmentId: z.string().uuid() }), async ({ adjustmentId }) => {
|
|
280
|
+
const { user } = requireAuth();
|
|
281
|
+
await voidAdjustmentSvc(adjustmentId, { actor: user.email ?? 'staff' });
|
|
282
|
+
return { ok: true };
|
|
283
|
+
});
|
|
@@ -90,6 +90,9 @@ export declare const updateEntryCommand: import("@sveltejs/kit").RemoteCommand<{
|
|
|
90
90
|
export declare const archiveEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<import("../../types/entries.js").DbEntry>>;
|
|
91
91
|
export declare const unarchiveEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<import("../../types/entries.js").DbEntry>>;
|
|
92
92
|
export declare const deleteEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<void>>;
|
|
93
|
+
export declare const duplicateEntryCommand: import("@sveltejs/kit").RemoteCommand<string, Promise<{
|
|
94
|
+
id: string;
|
|
95
|
+
}>>;
|
|
93
96
|
export declare const reorderEntriesCommand: import("@sveltejs/kit").RemoteCommand<{
|
|
94
97
|
orderedIds: string[];
|
|
95
98
|
collectionSlug: string;
|
|
@@ -6,11 +6,13 @@ import { db } from '../../server/db/index.js';
|
|
|
6
6
|
import { user } from '../../server/db/schema/auth-schema.js';
|
|
7
7
|
import { inArray } from 'drizzle-orm';
|
|
8
8
|
import { createEntry as createEntryOperation, createEntrySchema, createEntryVersion } from '../../core/server/entries/operations/create.js';
|
|
9
|
-
import { _getRawEntries as getRawEntriesOperation, _countRawEntries as countRawEntriesOperation, _getRawEntry as getRawEntryOperation, _getRawEntryOrThrow as getRawEntryOrThrow, _getDbEntry as getDbEntry, getEntryVersion as getEntryVersionOperation, getEntryLabels as getEntryLabelsOperation } from '../../core/server/entries/operations/get.js';
|
|
9
|
+
import { _getRawEntries as getRawEntriesOperation, _countRawEntries as countRawEntriesOperation, _getRawEntry as getRawEntryOperation, _getRawEntryOrThrow as getRawEntryOrThrow, _getDbEntry as getDbEntry, _getDbEntryOrThrow as getDbEntryOrThrow, getEntryVersion as getEntryVersionOperation, getEntryLabels as getEntryLabelsOperation } from '../../core/server/entries/operations/get.js';
|
|
10
10
|
import { resolveEntries, resolveEntry } from '../../core/server/entries/operations/resolveEntry.js';
|
|
11
11
|
import { getCMS } from '../../core/cms.js';
|
|
12
12
|
import { getFieldsFromConfig } from '../../core/fields/layoutUtils.js';
|
|
13
13
|
import { pruneOldDraftVersions, unpublishEntryLang, cancelScheduledEntryLang, upsertDraftVersion, updateEntry, updateEntrySchema, updateEntryVersionCommandTypes } from '../../core/server/entries/operations/update.js';
|
|
14
|
+
import { normalizeSlugFields } from '../../core/server/entries/operations/slugNormalize.js';
|
|
15
|
+
import { duplicateEntry } from '../../core/server/entries/operations/duplicate.js';
|
|
14
16
|
import z from 'zod';
|
|
15
17
|
import { requireAuth } from './middleware/auth.js';
|
|
16
18
|
import { stableSlotReorder } from './reorder.js';
|
|
@@ -205,6 +207,11 @@ const updateEntryVersionCommandSchema = z.object({
|
|
|
205
207
|
});
|
|
206
208
|
export const updateEntryVersionCommand = command(updateEntryVersionCommandSchema, async (input) => {
|
|
207
209
|
const { user } = requireAuth();
|
|
210
|
+
// Normalize slug fields once, before any write path (covers draft in-place
|
|
211
|
+
// updates and publish). Keeps stored slugs valid regardless of raw input.
|
|
212
|
+
const entryForSlug = await getDbEntryOrThrow({ id: input.entryId });
|
|
213
|
+
const config = getCMS().getBySlug(entryForSlug.slug);
|
|
214
|
+
const data = normalizeSlugFields(config, input.data);
|
|
208
215
|
let result;
|
|
209
216
|
// Publish failures should reach the client with a structured body so the
|
|
210
217
|
// editor can pin the message to the offending field. SvelteKit hides any
|
|
@@ -214,7 +221,7 @@ export const updateEntryVersionCommand = command(updateEntryVersionCommandSchema
|
|
|
214
221
|
return await createEntryVersion({
|
|
215
222
|
entryId: input.entryId,
|
|
216
223
|
lang: input.lang,
|
|
217
|
-
data
|
|
224
|
+
data,
|
|
218
225
|
publishedAt,
|
|
219
226
|
publishedBy: user.id
|
|
220
227
|
});
|
|
@@ -232,7 +239,7 @@ export const updateEntryVersionCommand = command(updateEntryVersionCommandSchema
|
|
|
232
239
|
};
|
|
233
240
|
switch (input.type) {
|
|
234
241
|
case 'draft':
|
|
235
|
-
result = await upsertDraftVersion(input.entryId,
|
|
242
|
+
result = await upsertDraftVersion(input.entryId, data, input.lang, { skipValidation: true });
|
|
236
243
|
break;
|
|
237
244
|
case 'published-now': {
|
|
238
245
|
result = await runPublish(new Date());
|
|
@@ -289,6 +296,10 @@ export const deleteEntryCommand = command(z.string().uuid(), async (id) => {
|
|
|
289
296
|
}
|
|
290
297
|
return getCMS().databaseAdapter.deleteEntry({ id });
|
|
291
298
|
});
|
|
299
|
+
export const duplicateEntryCommand = command(z.string().uuid(), async (id) => {
|
|
300
|
+
requireAuth();
|
|
301
|
+
return duplicateEntry(id);
|
|
302
|
+
});
|
|
292
303
|
export const reorderEntriesCommand = command(z.object({
|
|
293
304
|
orderedIds: z.array(z.string().uuid()),
|
|
294
305
|
collectionSlug: z.string()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CMSModuleDescriptor } from '../../types/modules.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the serializable descriptors of all registered modules (shop,
|
|
4
|
+
* booking, …) — id, label, icon, and context (nav sections + surfaced
|
|
5
|
+
* collections). Strips server-only `serverHooks` and the opaque `config`
|
|
6
|
+
* (which may carry adapter functions). Powers the admin context switcher and
|
|
7
|
+
* the generic module nav.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare const getModules: import("@sveltejs/kit").RemoteQueryFunction<void, CMSModuleDescriptor[]>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { query } from '$app/server';
|
|
2
|
+
import { getCMS } from '../../core/cms.js';
|
|
3
|
+
import { toModuleDescriptor } from '../../types/modules.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the serializable descriptors of all registered modules (shop,
|
|
6
|
+
* booking, …) — id, label, icon, and context (nav sections + surfaced
|
|
7
|
+
* collections). Strips server-only `serverHooks` and the opaque `config`
|
|
8
|
+
* (which may carry adapter functions). Powers the admin context switcher and
|
|
9
|
+
* the generic module nav.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export const getModules = query(async () => {
|
|
13
|
+
return Array.from(getCMS().modules.values()).map(toModuleDescriptor);
|
|
14
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Active admin context resolution. Pure, deterministic, framework-free so it can
|
|
3
|
+
* be unit-tested without the browser/runed state.
|
|
4
|
+
*
|
|
5
|
+
* Precedence (highest first):
|
|
6
|
+
* 1. **Unambiguous module path** — `/admin/{id}` or `/admin/{id}/...` always
|
|
7
|
+
* wins, so a deep-link to `/admin/shop/orders` shows the shop context
|
|
8
|
+
* regardless of stored state.
|
|
9
|
+
* 2. **`?ctx=` query** — explicit intent, used when linking a surfaced core
|
|
10
|
+
* collection (`/admin/collections/{slug}?ctx=shop`) whose path doesn't
|
|
11
|
+
* encode a context.
|
|
12
|
+
* 3. **Content-core path** — the dashboard (`/admin`) and core CMS sections
|
|
13
|
+
* (collections, singles, entries, forms) resolve to content. Neutral/global
|
|
14
|
+
* routes (media, users, account, maintenance) are excluded: they fall through
|
|
15
|
+
* to the stored sticky context so they stay inside the active module workspace.
|
|
16
|
+
* 4. **Stored sticky** — the last context the user switched to (covers
|
|
17
|
+
* ambiguous routes like the entry editor `/admin/entries/{id}`).
|
|
18
|
+
* 5. **Content** — the default CMS core workspace.
|
|
19
|
+
*/
|
|
20
|
+
/** The base CMS-core context (content editing). */
|
|
21
|
+
export declare const CONTENT_CONTEXT = "content";
|
|
22
|
+
/** Whether `pathname` is the dashboard or a core CMS section (not a module). */
|
|
23
|
+
export declare function isContentCorePath(pathname: string): boolean;
|
|
24
|
+
export interface ResolveActiveContextInput {
|
|
25
|
+
/** Value of the `ctx` query param, or null/undefined. */
|
|
26
|
+
ctxQuery?: string | null;
|
|
27
|
+
/** Persisted "sticky" context, or null/undefined. */
|
|
28
|
+
stored?: string | null;
|
|
29
|
+
/** Current pathname, e.g. `/admin/shop/orders`. */
|
|
30
|
+
pathname: string;
|
|
31
|
+
/** Ids of registered modules, e.g. `['shop', 'booking']`. */
|
|
32
|
+
moduleIds: string[];
|
|
33
|
+
}
|
|
34
|
+
/** Whether `pathname` is the landing or a sub-route of module `id`. */
|
|
35
|
+
export declare function isModulePath(pathname: string, id: string): boolean;
|
|
36
|
+
/** Resolves the active context id from URL, stored state, and module registry. */
|
|
37
|
+
export declare function resolveActiveContext(input: ResolveActiveContextInput): string;
|