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.
Files changed (259) hide show
  1. package/API.md +179 -3
  2. package/CHANGELOG.md +64 -0
  3. package/DOCS.md +28 -3
  4. package/ROADMAP.md +18 -0
  5. package/dist/admin/client/booking/booking-dashboard.svelte +40 -0
  6. package/dist/admin/client/booking/booking-dashboard.svelte.d.ts +3 -0
  7. package/dist/admin/client/booking/customer-panel.svelte +102 -0
  8. package/dist/admin/client/booking/customer-panel.svelte.d.ts +11 -0
  9. package/dist/admin/client/booking/customer-view.d.ts +52 -0
  10. package/dist/admin/client/booking/customer-view.js +134 -0
  11. package/dist/admin/client/booking/participant-data-panel.svelte +330 -0
  12. package/dist/admin/client/booking/participant-data-panel.svelte.d.ts +22 -0
  13. package/dist/admin/client/booking/reservation-detail-page.svelte +637 -0
  14. package/dist/admin/client/booking/reservation-detail-page.svelte.d.ts +3 -0
  15. package/dist/admin/client/booking/reservations-page.svelte +221 -0
  16. package/dist/admin/client/booking/reservations-page.svelte.d.ts +3 -0
  17. package/dist/admin/client/collection/collection-entries.svelte +21 -2
  18. package/dist/admin/client/collection/entry-link.svelte +6 -4
  19. package/dist/admin/client/collection/entry-link.svelte.d.ts +3 -1
  20. package/dist/admin/client/collection/row-actions.svelte +12 -4
  21. package/dist/admin/client/collection/row-actions.svelte.d.ts +1 -0
  22. package/dist/admin/client/collection/status-badge.svelte +39 -3
  23. package/dist/admin/client/collection/status-badge.svelte.d.ts +5 -3
  24. package/dist/admin/client/entry/entry.svelte +26 -9
  25. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +73 -10
  26. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte.d.ts +6 -5
  27. package/dist/admin/client/entry/preview-views-context.svelte.d.ts +22 -0
  28. package/dist/admin/client/entry/preview-views-context.svelte.js +58 -0
  29. package/dist/admin/client/entry/preview-views.d.ts +27 -0
  30. package/dist/admin/client/entry/preview-views.js +33 -0
  31. package/dist/admin/client/index.d.ts +3 -0
  32. package/dist/admin/client/index.js +3 -0
  33. package/dist/admin/client/modules/dashboard-registry.d.ts +7 -0
  34. package/dist/admin/client/modules/dashboard-registry.js +11 -0
  35. package/dist/admin/client/modules/module-dashboard-page.svelte +26 -0
  36. package/dist/admin/client/modules/module-dashboard-page.svelte.d.ts +6 -0
  37. package/dist/admin/client/modules/stat-card.svelte +22 -0
  38. package/dist/admin/client/modules/stat-card.svelte.d.ts +10 -0
  39. package/dist/admin/client/shop/shop-dashboard.svelte +29 -0
  40. package/dist/admin/client/shop/shop-dashboard.svelte.d.ts +3 -0
  41. package/dist/admin/components/fields/relation-field.svelte +11 -2
  42. package/dist/admin/components/icons/icon-map.js +8 -0
  43. package/dist/admin/components/layout/app-sidebar.svelte +45 -14
  44. package/dist/admin/components/layout/context-switcher.svelte +90 -0
  45. package/dist/admin/components/layout/context-switcher.svelte.d.ts +3 -0
  46. package/dist/admin/components/layout/lang.d.ts +4 -0
  47. package/dist/admin/components/layout/lang.js +8 -0
  48. package/dist/admin/components/layout/layout-renderer.svelte +2 -1
  49. package/dist/admin/components/layout/layout-tabs.svelte +14 -0
  50. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +2 -0
  51. package/dist/admin/components/layout/nav-collections.svelte +16 -9
  52. package/dist/admin/components/layout/nav-collections.svelte.d.ts +5 -1
  53. package/dist/admin/components/layout/nav-global.svelte +45 -0
  54. package/dist/admin/components/layout/nav-global.svelte.d.ts +3 -0
  55. package/dist/admin/components/layout/nav-main.svelte +8 -32
  56. package/dist/admin/components/layout/nav-main.svelte.d.ts +6 -1
  57. package/dist/admin/components/layout/nav-module.svelte +57 -0
  58. package/dist/admin/components/layout/nav-module.svelte.d.ts +7 -0
  59. package/dist/admin/components/layout/nav-section.svelte +1 -1
  60. package/dist/admin/components/layout/nav-section.svelte.d.ts +1 -1
  61. package/dist/admin/components/layout/nav-singletons.svelte +14 -7
  62. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +5 -1
  63. package/dist/admin/remote/booking.remote.d.ts +244 -0
  64. package/dist/admin/remote/booking.remote.js +283 -0
  65. package/dist/admin/remote/entry.remote.d.ts +3 -0
  66. package/dist/admin/remote/entry.remote.js +14 -3
  67. package/dist/admin/remote/index.d.ts +2 -0
  68. package/dist/admin/remote/index.js +2 -0
  69. package/dist/admin/remote/modules.remote.d.ts +10 -0
  70. package/dist/admin/remote/modules.remote.js +14 -0
  71. package/dist/admin/state/active-context-resolve.d.ts +37 -0
  72. package/dist/admin/state/active-context-resolve.js +66 -0
  73. package/dist/admin/state/active-context.svelte.d.ts +8 -0
  74. package/dist/admin/state/active-context.svelte.js +27 -0
  75. package/dist/booking/adjustments.d.ts +33 -0
  76. package/dist/booking/adjustments.js +26 -0
  77. package/dist/booking/capacity.d.ts +12 -0
  78. package/dist/booking/capacity.js +10 -0
  79. package/dist/booking/client/index.d.ts +39 -0
  80. package/dist/booking/client/index.js +44 -0
  81. package/dist/booking/client/use-booking.svelte.d.ts +25 -0
  82. package/dist/booking/client/use-booking.svelte.js +56 -0
  83. package/dist/booking/config.d.ts +156 -0
  84. package/dist/booking/config.js +36 -0
  85. package/dist/booking/draft.d.ts +77 -0
  86. package/dist/booking/draft.js +67 -0
  87. package/dist/booking/expiry-logic.d.ts +30 -0
  88. package/dist/booking/expiry-logic.js +33 -0
  89. package/dist/booking/index.d.ts +18 -0
  90. package/dist/booking/index.js +52 -0
  91. package/dist/booking/ledger.d.ts +46 -0
  92. package/dist/booking/ledger.js +60 -0
  93. package/dist/booking/number.d.ts +2 -0
  94. package/dist/booking/number.js +11 -0
  95. package/dist/booking/participant-fields/access.d.ts +10 -0
  96. package/dist/booking/participant-fields/access.js +14 -0
  97. package/dist/booking/participant-fields/age.d.ts +12 -0
  98. package/dist/booking/participant-fields/age.js +28 -0
  99. package/dist/booking/participant-fields/completeness.d.ts +8 -0
  100. package/dist/booking/participant-fields/completeness.js +13 -0
  101. package/dist/booking/participant-fields/group.d.ts +6 -0
  102. package/dist/booking/participant-fields/group.js +15 -0
  103. package/dist/booking/participant-fields/index.d.ts +6 -0
  104. package/dist/booking/participant-fields/index.js +6 -0
  105. package/dist/booking/participant-fields/types.d.ts +50 -0
  106. package/dist/booking/participant-fields/types.js +5 -0
  107. package/dist/booking/participant-fields/validate.d.ts +7 -0
  108. package/dist/booking/participant-fields/validate.js +44 -0
  109. package/dist/booking/participant-pricing.d.ts +93 -0
  110. package/dist/booking/participant-pricing.js +91 -0
  111. package/dist/booking/participants-view.d.ts +32 -0
  112. package/dist/booking/participants-view.js +22 -0
  113. package/dist/booking/payment-context.d.ts +19 -0
  114. package/dist/booking/payment-context.js +29 -0
  115. package/dist/booking/pricing-inputs.d.ts +28 -0
  116. package/dist/booking/pricing-inputs.js +35 -0
  117. package/dist/booking/pricing.d.ts +86 -0
  118. package/dist/booking/pricing.js +125 -0
  119. package/dist/booking/recompute.d.ts +22 -0
  120. package/dist/booking/recompute.js +31 -0
  121. package/dist/booking/reminders-schedule.d.ts +11 -0
  122. package/dist/booking/reminders-schedule.js +28 -0
  123. package/dist/booking/server/adjustments.d.ts +27 -0
  124. package/dist/booking/server/adjustments.js +136 -0
  125. package/dist/booking/server/bookings.d.ts +45 -0
  126. package/dist/booking/server/bookings.js +288 -0
  127. package/dist/booking/server/catalog.d.ts +9 -0
  128. package/dist/booking/server/catalog.js +20 -0
  129. package/dist/booking/server/db.d.ts +7 -0
  130. package/dist/booking/server/db.js +18 -0
  131. package/dist/booking/server/email.d.ts +23 -0
  132. package/dist/booking/server/email.js +59 -0
  133. package/dist/booking/server/emailTemplateRegistry.d.ts +29 -0
  134. package/dist/booking/server/emailTemplateRegistry.js +125 -0
  135. package/dist/booking/server/http/create-handler.d.ts +5 -0
  136. package/dist/booking/server/http/create-handler.js +68 -0
  137. package/dist/booking/server/http/index.d.ts +4 -0
  138. package/dist/booking/server/http/index.js +4 -0
  139. package/dist/booking/server/http/maintenance-handler.d.ts +9 -0
  140. package/dist/booking/server/http/maintenance-handler.js +36 -0
  141. package/dist/booking/server/http/portal-handler.d.ts +13 -0
  142. package/dist/booking/server/http/portal-handler.js +99 -0
  143. package/dist/booking/server/http/webhook-handler.d.ts +9 -0
  144. package/dist/booking/server/http/webhook-handler.js +39 -0
  145. package/dist/booking/server/index.d.ts +12 -0
  146. package/dist/booking/server/index.js +14 -0
  147. package/dist/booking/server/maintenance.d.ts +28 -0
  148. package/dist/booking/server/maintenance.js +134 -0
  149. package/dist/booking/server/participants.d.ts +26 -0
  150. package/dist/booking/server/participants.js +92 -0
  151. package/dist/booking/server/payments.d.ts +34 -0
  152. package/dist/booking/server/payments.js +207 -0
  153. package/dist/booking/server/portal-session.d.ts +16 -0
  154. package/dist/booking/server/portal-session.js +42 -0
  155. package/dist/booking/server/portal.d.ts +207 -0
  156. package/dist/booking/server/portal.js +234 -0
  157. package/dist/booking/server/refunds.d.ts +7 -0
  158. package/dist/booking/server/refunds.js +58 -0
  159. package/dist/booking/server/reminders.d.ts +9 -0
  160. package/dist/booking/server/reminders.js +24 -0
  161. package/dist/booking/server/validation.d.ts +17 -0
  162. package/dist/booking/server/validation.js +55 -0
  163. package/dist/booking/state-machine.d.ts +41 -0
  164. package/dist/booking/state-machine.js +73 -0
  165. package/dist/booking/templates/_partials/footer.en.html +4 -0
  166. package/dist/booking/templates/_partials/footer.pl.html +4 -0
  167. package/dist/booking/templates/_partials/header.en.html +4 -0
  168. package/dist/booking/templates/_partials/header.pl.html +4 -0
  169. package/dist/booking/templates/balance-due.en.html +10 -0
  170. package/dist/booking/templates/balance-due.pl.html +10 -0
  171. package/dist/booking/templates/balance-overdue-cancelled.en.html +5 -0
  172. package/dist/booking/templates/balance-overdue-cancelled.pl.html +5 -0
  173. package/dist/booking/templates/booking-received.en.html +9 -0
  174. package/dist/booking/templates/booking-received.pl.html +9 -0
  175. package/dist/booking/templates/deposit-paid.en.html +6 -0
  176. package/dist/booking/templates/deposit-paid.pl.html +6 -0
  177. package/dist/booking/templates/payment-link.en.html +5 -0
  178. package/dist/booking/templates/payment-link.pl.html +5 -0
  179. package/dist/booking/templates/payment-received.en.html +10 -0
  180. package/dist/booking/templates/payment-received.pl.html +10 -0
  181. package/dist/booking/totals.d.ts +38 -0
  182. package/dist/booking/totals.js +61 -0
  183. package/dist/booking/webhook-logic.d.ts +28 -0
  184. package/dist/booking/webhook-logic.js +50 -0
  185. package/dist/cli/create-user.d.ts +7 -1
  186. package/dist/cli/create-user.js +23 -15
  187. package/dist/cli/index.js +55 -7
  188. package/dist/cli/scaffold/admin.d.ts +6 -0
  189. package/dist/cli/scaffold/admin.js +5 -3
  190. package/dist/cli/scaffold/booking.d.ts +12 -0
  191. package/dist/cli/scaffold/booking.js +103 -0
  192. package/dist/core/cms.d.ts +24 -9
  193. package/dist/core/cms.js +72 -34
  194. package/dist/core/config/validatePreviews.d.ts +12 -0
  195. package/dist/core/config/validatePreviews.js +90 -0
  196. package/dist/core/fields/dotPath.d.ts +4 -0
  197. package/dist/core/fields/dotPath.js +18 -0
  198. package/dist/core/fields/slugPath.d.ts +9 -1
  199. package/dist/core/fields/slugPath.js +16 -2
  200. package/dist/core/fields/slugify.d.ts +3 -0
  201. package/dist/core/fields/slugify.js +4 -0
  202. package/dist/core/server/entries/operations/duplicate.d.ts +10 -0
  203. package/dist/core/server/entries/operations/duplicate.js +73 -0
  204. package/dist/core/server/entries/operations/slugNormalize.d.ts +8 -0
  205. package/dist/core/server/entries/operations/slugNormalize.js +20 -0
  206. package/dist/core/server/entries/operations/slugUniqueness.d.ts +17 -0
  207. package/dist/core/server/entries/operations/slugUniqueness.js +39 -0
  208. package/dist/core/server/fields/resolveRelationFields.d.ts +11 -2
  209. package/dist/core/server/fields/resolveRelationFields.js +12 -3
  210. package/dist/core/server/generator/generator.js +7 -2
  211. package/dist/db-postgres/schema/booking/bookingAdjustments.d.ts +186 -0
  212. package/dist/db-postgres/schema/booking/bookingAdjustments.js +22 -0
  213. package/dist/db-postgres/schema/booking/bookingItemPersons.d.ts +117 -0
  214. package/dist/db-postgres/schema/booking/bookingItemPersons.js +22 -0
  215. package/dist/db-postgres/schema/booking/bookingItems.d.ts +181 -0
  216. package/dist/db-postgres/schema/booking/bookingItems.js +22 -0
  217. package/dist/db-postgres/schema/booking/bookingPayments.d.ts +204 -0
  218. package/dist/db-postgres/schema/booking/bookingPayments.js +25 -0
  219. package/dist/db-postgres/schema/booking/bookingPersons.d.ts +99 -0
  220. package/dist/db-postgres/schema/booking/bookingPersons.js +17 -0
  221. package/dist/db-postgres/schema/booking/bookingReminders.d.ts +131 -0
  222. package/dist/db-postgres/schema/booking/bookingReminders.js +18 -0
  223. package/dist/db-postgres/schema/booking/bookings.d.ts +307 -0
  224. package/dist/db-postgres/schema/booking/bookings.js +40 -0
  225. package/dist/db-postgres/schema/booking/index.d.ts +7 -0
  226. package/dist/db-postgres/schema/booking/index.js +7 -0
  227. package/dist/db-postgres/schema/index.d.ts +1 -0
  228. package/dist/db-postgres/schema/index.js +1 -0
  229. package/dist/db-postgres/schema-booking.d.ts +1 -0
  230. package/dist/db-postgres/schema-booking.js +1 -0
  231. package/dist/server/security/rate-limit-handler.d.ts +19 -0
  232. package/dist/server/security/rate-limit-handler.js +34 -0
  233. package/dist/shop/adapters/payu/client.js +3 -1
  234. package/dist/shop/adapters/payu/index.js +37 -17
  235. package/dist/shop/adapters/payu/payload.d.ts +6 -0
  236. package/dist/shop/adapters/payu/payload.js +1 -1
  237. package/dist/shop/adapters/stripe/index.js +36 -21
  238. package/dist/shop/index.d.ts +11 -2
  239. package/dist/shop/index.js +43 -1
  240. package/dist/shop/rate-limit.d.ts +1 -9
  241. package/dist/shop/rate-limit.js +3 -28
  242. package/dist/shop/types.d.ts +19 -0
  243. package/dist/sveltekit/config.d.ts +4 -0
  244. package/dist/sveltekit/config.js +6 -0
  245. package/dist/types/cms.d.ts +15 -1
  246. package/dist/types/cms.schema.d.ts +96 -2
  247. package/dist/types/cms.schema.js +84 -1
  248. package/dist/types/config.d.ts +33 -0
  249. package/dist/types/layout.d.ts +6 -0
  250. package/dist/types/modules.d.ts +133 -0
  251. package/dist/types/modules.js +27 -0
  252. package/dist/updates/0.36.9/index.d.ts +2 -0
  253. package/dist/updates/0.36.9/index.js +12 -0
  254. package/dist/updates/0.37.0/index.d.ts +2 -0
  255. package/dist/updates/0.37.0/index.js +52 -0
  256. package/dist/updates/index.js +5 -1
  257. package/package.json +19 -1
  258. package/dist/admin/components/layout/nav-shop.svelte +0 -33
  259. 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: input.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, input.data, input.lang, { skipValidation: true });
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()
@@ -9,4 +9,6 @@ export * from './ai.remote.js';
9
9
  export * from './preview.remote.js';
10
10
  export * from './email.remote.js';
11
11
  export * from './shop.remote.js';
12
+ export * from './booking.remote.js';
13
+ export * from './modules.remote.js';
12
14
  export * from './admin.remote.js';
@@ -9,4 +9,6 @@ export * from './ai.remote.js';
9
9
  export * from './preview.remote.js';
10
10
  export * from './email.remote.js';
11
11
  export * from './shop.remote.js';
12
+ export * from './booking.remote.js';
13
+ export * from './modules.remote.js';
12
14
  export * from './admin.remote.js';
@@ -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;