includio-cms 0.28.0 → 0.34.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 (117) hide show
  1. package/API.md +39 -13
  2. package/CHANGELOG.md +19 -0
  3. package/DOCS.md +1 -1
  4. package/ROADMAP.md +1 -0
  5. package/dist/admin/api/handler.js +4 -0
  6. package/dist/admin/api/integrations.d.ts +13 -0
  7. package/dist/admin/api/integrations.js +61 -0
  8. package/dist/admin/api/test-email.d.ts +9 -0
  9. package/dist/admin/api/test-email.js +39 -0
  10. package/dist/admin/auth-client.d.ts +2209 -2209
  11. package/dist/admin/client/index.d.ts +10 -0
  12. package/dist/admin/client/index.js +12 -0
  13. package/dist/admin/client/maintenance/maintenance-page.svelte +210 -0
  14. package/dist/admin/client/shop/coupon-schema.d.ts +1 -1
  15. package/dist/admin/client/shop/restore-order-cell.svelte +29 -0
  16. package/dist/admin/client/shop/restore-order-cell.svelte.d.ts +8 -0
  17. package/dist/admin/client/shop/shop-order-detail-page.svelte +71 -1
  18. package/dist/admin/client/shop/shop-orders-list-page.svelte +113 -53
  19. package/dist/admin/components/layout/app-sidebar.svelte +2 -0
  20. package/dist/admin/components/layout/nav-custom.svelte +26 -0
  21. package/dist/admin/components/layout/nav-custom.svelte.d.ts +3 -0
  22. package/dist/admin/components/layout/page-header.svelte +13 -3
  23. package/dist/admin/components/layout/page-header.svelte.d.ts +13 -3
  24. package/dist/admin/remote/admin.remote.d.ts +7 -0
  25. package/dist/admin/remote/admin.remote.js +10 -0
  26. package/dist/admin/remote/entry.remote.d.ts +4 -4
  27. package/dist/admin/remote/index.d.ts +1 -0
  28. package/dist/admin/remote/index.js +1 -0
  29. package/dist/admin/remote/invite.d.ts +2 -2
  30. package/dist/admin/remote/shop.remote.d.ts +75 -48
  31. package/dist/admin/remote/shop.remote.js +41 -10
  32. package/dist/admin/types.d.ts +15 -0
  33. package/dist/admin/utils/csv-export.d.ts +45 -0
  34. package/dist/admin/utils/csv-export.js +61 -0
  35. package/dist/cli/scaffold/admin.js +1 -1
  36. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  37. package/dist/components/ui/command/command.svelte.d.ts +1 -1
  38. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  39. package/dist/components/ui/input/input.svelte.d.ts +1 -1
  40. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  41. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  42. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  43. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  44. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  45. package/dist/core/cms.d.ts +44 -2
  46. package/dist/core/cms.js +64 -0
  47. package/dist/core/index.d.ts +1 -4
  48. package/dist/core/index.js +4 -4
  49. package/dist/core/server/index.d.ts +4 -1
  50. package/dist/core/server/index.js +4 -1
  51. package/dist/db-postgres/schema/shop/order.d.ts +34 -0
  52. package/dist/db-postgres/schema/shop/order.js +4 -0
  53. package/dist/paraglide/messages/_index.d.ts +3 -36
  54. package/dist/paraglide/messages/_index.js +3 -71
  55. package/dist/paraglide/messages/hello_world.d.ts +5 -0
  56. package/dist/paraglide/messages/hello_world.js +33 -0
  57. package/dist/paraglide/messages/login_hello.d.ts +16 -0
  58. package/dist/paraglide/messages/login_hello.js +34 -0
  59. package/dist/paraglide/messages/login_please_login.d.ts +16 -0
  60. package/dist/paraglide/messages/login_please_login.js +34 -0
  61. package/dist/shop/adapters/fakturownia/client.d.ts +5 -0
  62. package/dist/shop/adapters/fakturownia/client.js +20 -0
  63. package/dist/shop/adapters/fakturownia/index.js +11 -0
  64. package/dist/shop/adapters/payu/index.js +11 -0
  65. package/dist/shop/index.d.ts +1 -1
  66. package/dist/shop/server/coupons.d.ts +10 -0
  67. package/dist/shop/server/coupons.js +19 -0
  68. package/dist/shop/server/email.d.ts +7 -3
  69. package/dist/shop/server/email.js +86 -112
  70. package/dist/shop/server/emailTemplateRegistry.d.ts +47 -0
  71. package/dist/shop/server/emailTemplateRegistry.js +288 -0
  72. package/dist/shop/server/orders.d.ts +60 -1
  73. package/dist/shop/server/orders.js +145 -16
  74. package/dist/shop/templates/_partials/footer.en.html +4 -0
  75. package/dist/shop/templates/_partials/footer.pl.html +4 -0
  76. package/dist/shop/templates/_partials/header.en.html +4 -0
  77. package/dist/shop/templates/_partials/header.pl.html +4 -0
  78. package/dist/shop/templates/_partials/items.en.html +14 -0
  79. package/dist/shop/templates/_partials/items.pl.html +14 -0
  80. package/dist/shop/templates/_partials/tracking.en.html +7 -0
  81. package/dist/shop/templates/_partials/tracking.pl.html +7 -0
  82. package/dist/shop/templates/awaiting-payment.en.html +6 -0
  83. package/dist/shop/templates/awaiting-payment.pl.html +6 -0
  84. package/dist/shop/templates/cancelled.en.html +6 -0
  85. package/dist/shop/templates/cancelled.pl.html +6 -0
  86. package/dist/shop/templates/low-stock.en.html +14 -0
  87. package/dist/shop/templates/low-stock.pl.html +14 -0
  88. package/dist/shop/templates/order-completed.en.html +6 -0
  89. package/dist/shop/templates/order-completed.pl.html +6 -0
  90. package/dist/shop/templates/order-received.en.html +7 -0
  91. package/dist/shop/templates/order-received.pl.html +7 -0
  92. package/dist/shop/templates/payment-received.en.html +7 -0
  93. package/dist/shop/templates/payment-received.pl.html +7 -0
  94. package/dist/shop/templates/payment-rejected.en.html +6 -0
  95. package/dist/shop/templates/payment-rejected.pl.html +6 -0
  96. package/dist/shop/templates/preparing.en.html +7 -0
  97. package/dist/shop/templates/preparing.pl.html +7 -0
  98. package/dist/shop/templates/refunded.en.html +6 -0
  99. package/dist/shop/templates/refunded.pl.html +6 -0
  100. package/dist/shop/templates/shipped.en.html +7 -0
  101. package/dist/shop/templates/shipped.pl.html +7 -0
  102. package/dist/shop/types.d.ts +63 -0
  103. package/dist/sveltekit/index.d.ts +0 -1
  104. package/dist/sveltekit/index.js +0 -1
  105. package/dist/sveltekit/server/index.d.ts +2 -0
  106. package/dist/sveltekit/server/index.js +4 -0
  107. package/dist/types/adapters/email.d.ts +13 -0
  108. package/dist/types/cms.d.ts +30 -0
  109. package/dist/types/index.d.ts +1 -1
  110. package/dist/updates/0.34.0/index.d.ts +2 -0
  111. package/dist/updates/0.34.0/index.js +17 -0
  112. package/dist/updates/index.js +3 -1
  113. package/package.json +7 -2
  114. package/dist/paraglide/messages/en.d.ts +0 -5
  115. package/dist/paraglide/messages/en.js +0 -14
  116. package/dist/paraglide/messages/pl.d.ts +0 -5
  117. package/dist/paraglide/messages/pl.js +0 -14
package/API.md CHANGED
@@ -1,8 +1,8 @@
1
- # includio-cms — Public API v0.28.0
1
+ # includio-cms — Public API v0.34.0
2
2
 
3
3
  > Auto-generated by `scripts/generate-api-md.ts`. Do not edit by hand.
4
4
 
5
- Entry points: **18** · Stable: **464** · Experimental: **4**
5
+ Entry points: **19** · Stable: **487** · Experimental: **4**
6
6
 
7
7
  Tags:
8
8
  - `@public` — frozen for v1.0; semver-protected.
@@ -13,23 +13,25 @@ Tags:
13
13
 
14
14
  ### `includio-cms`
15
15
 
16
- - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS
17
- - `getAuth(): <inferred>` — Returns the underlying `better-auth` instance from the initialized CMS.
18
- - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()`
19
- - `interface ResolvedMedia` — Resolved media file plus its image styles + blur placeholder. Returned by
16
+ - `interface EmailAdapter`Contract for email adapters. Used by `better-auth` reset-password flow and form submission
20
17
  - `type ResolvedSeo = { [K in keyof SeoFieldData]: K extends 'ogImage' ? string | MediaFile | undefined : string | unde...` — Normalized SEO data — localized values flattened by `language`. A stable
21
- - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins or
22
18
  - `resolveSeo(entry: { seo?: Record<string, unknown> } | Record<string,..., language?: string): ResolvedSeo` — Resolve `entry.seo` into flat fields, flattening localized objects by
19
+ - `interface SendMailOptions`
23
20
 
24
21
  ### `includio-cms/core`
25
22
 
23
+ - `interface EmailAdapter` — Contract for email adapters. Used by `better-auth` reset-password flow and form submission
24
+ - `type ResolvedSeo = { [K in keyof SeoFieldData]: K extends 'ogImage' ? string | MediaFile | undefined : string | unde...` — Normalized SEO data — localized values flattened by `language`. A stable
25
+ - `resolveSeo(entry: { seo?: Record<string, unknown> } | Record<string,..., language?: string): ResolvedSeo` — Resolve `entry.seo` into flat fields, flattening localized objects by
26
+ - `interface SendMailOptions`
27
+
28
+ ### `includio-cms/core/server`
29
+
26
30
  - `createEntityAPI(cms: CMS, opts?: EntityAPIOptions): <inferred>` — Creates a high-level Entity API (CRUD + publish/archive) bound to a CMS
27
31
  - `getAuth(): <inferred>` — Returns the underlying `better-auth` instance from the initialized CMS.
28
32
  - `getCMS(): CMS` — Returns the singleton CMS instance. Must be called after `includioCMS()`
29
33
  - `interface ResolvedMedia` — Resolved media file plus its image styles + blur placeholder. Returned by
30
- - `type ResolvedSeo = { [K in keyof SeoFieldData]: K extends 'ogImage' ? string | MediaFile | undefined : string | unde...` — Normalized SEO data — localized values flattened by `language`. A stable
31
34
  - `resolveMediaWithStyles(mediaIds: string[], styles?: ImageFieldStyle[]): Promise<Record<string, ResolvedMedia>>` — Resolve media files by IDs and generate image styles. Useful for plugins or
32
- - `resolveSeo(entry: { seo?: Record<string, unknown> } | Record<string,..., language?: string): ResolvedSeo` — Resolve `entry.seo` into flat fields, flattening localized objects by
33
35
 
34
36
  ### `includio-cms/types`
35
37
 
@@ -37,6 +39,8 @@ Tags:
37
39
  - `interface ApiKeyConfig`
38
40
  - `interface ArrayField`
39
41
  - `interface AuthConfig`
42
+ - `interface AuthRateLimitConfig`
43
+ - `interface AuthRateLimitRule`
40
44
  - `interface BaseField`
41
45
  - `interface BlocksField`
42
46
  - `interface BooleanField`
@@ -134,19 +138,28 @@ Tags:
134
138
 
135
139
  - `const AcceptInvitePage: LegacyComponentType`
136
140
  - `const AdminAfterLoginLayout: LegacyComponentType`
141
+ - `interface AdminConfig` — Optional admin UI configuration — extension points for the panel sidebar
137
142
  - `const AdminLayout: LegacyComponentType`
143
+ - `interface AdminNavItem` — One additional sidebar entry rendered below built-in nav sections
138
144
  - `const Badge: LegacyComponentType`
145
+ - `interface Breadcrumb`
146
+ - `class Breadcrumbs`
147
+ - `buildCsv(opts: { headers: string[]; rows: (string | number | null ...): string` — Build a CSV string from `headers` and `rows`. Values are escaped per
139
148
  - `buildCustomFieldsMap(...plugins: PluginConfig[]): Map<string, CustomFieldDefinition>` — Build a Map<fieldType, CustomFieldDefinition> from plugin configs.
140
149
  - `buildIconSetMap(...plugins: IconSetPlugin[]): Map<string, IconSetPlugin>` — Build a Map<slug, IconSetPlugin> from icon-set plugin instances.
141
150
  - `const Button: LegacyComponentType`
142
151
  - `Card`
143
152
  - `const CollectionPage: LegacyComponentType`
153
+ - `type ColumnDef = DisplayColumnDef<TData, TValue> | GroupColumnDef<TData, TValue> | AccessorColumnDef<TData, TValue>`
144
154
  - `const DashboardPage: LegacyComponentType`
155
+ - `const DataTable: LegacyComponentType`
145
156
  - `Dialog`
157
+ - `downloadCsv(opts: { filename: string; csv: string }): void` — Trigger a client-side CSV download. Wraps the given `csv` string in a
146
158
  - `const EntryPage: LegacyComponentType`
147
159
  - `const FileMiniature: LegacyComponentType`
148
160
  - `const FormPage: LegacyComponentType`
149
161
  - `const FormSubmissionPage: LegacyComponentType`
162
+ - `getBreadcrumbs`
150
163
  - `getContentLanguage`
151
164
  - `getCustomFields(): Map<string, CustomFieldDefinition>`
152
165
  - `getIconSets(): Map<string, IconSetPlugin>`
@@ -158,9 +171,12 @@ Tags:
158
171
  - `const MaintenancePage: LegacyComponentType`
159
172
  - `const MediaPage: LegacyComponentType`
160
173
  - `const MediaSelector: LegacyComponentType`
174
+ - `const PageHeader: LegacyComponentType`
175
+ - `interface PaginationState`
161
176
  - `const ResetPasswordPage: LegacyComponentType`
162
177
  - `resolveIconSet(slug?: string): IconSetPlugin | null` — Resolve a single icon set: explicit `slug` (from {@link IconField.set}) takes
163
178
  - `const Separator: LegacyComponentType`
179
+ - `setBreadcrumbs`
164
180
  - `const ShippingMethodEditPage: LegacyComponentType`
165
181
  - `const ShippingMethodNewPage: LegacyComponentType`
166
182
  - `const ShippingMethodsListPage: LegacyComponentType`
@@ -171,6 +187,10 @@ Tags:
171
187
  - `const ShopOrdersListPage: LegacyComponentType`
172
188
  - `const ShopProductsListPage: LegacyComponentType`
173
189
  - `const Skeleton: LegacyComponentType`
190
+ - `type SortingState = ColumnSort[]`
191
+ - `const StateDisplay: LegacyComponentType`
192
+ - `const TablePagination: LegacyComponentType`
193
+ - `const TableToolbar: LegacyComponentType`
174
194
  - `Tabs`
175
195
  - `Tooltip`
176
196
  - `useField(form: SuperForm<Record<string, unknown>>, path: FormPathLeaves<Record<string, unknown>>): <inferred>` — Simplified wrapper around sveltekit-superforms' formFieldProxy.
@@ -195,6 +215,7 @@ Tags:
195
215
  - `const deleteFormSubmissions: <inferred>`
196
216
  - `const deleteMediaFile: <inferred>`
197
217
  - `const deleteMediaTag: <inferred>`
218
+ - `const deleteOrderCmd: <inferred>`
198
219
  - `const deleteShippingMethodCmd: <inferred>`
199
220
  - `const deleteShopDataForEntry: <inferred>`
200
221
  - `const exportFormSubmissions: <inferred>`
@@ -202,6 +223,7 @@ Tags:
202
223
  - `const findMediaReferences: <inferred>`
203
224
  - `const generateAltText: <inferred>`
204
225
  - `const generateBalanceLinkForOrder: <inferred>`
226
+ - `const getAdminExtraNavItems: <inferred>`
205
227
  - `const getAltOverview: <inferred>`
206
228
  - `const getCollection: <inferred>`
207
229
  - `const getCollections: <inferred>`
@@ -250,6 +272,7 @@ Tags:
250
272
  - `const reorderEntriesCommand: <inferred>`
251
273
  - `const reorderShippingMethodsCmd: <inferred>`
252
274
  - `const resendOrderEmailCmd: <inferred>`
275
+ - `const restoreOrderCmd: <inferred>`
253
276
  - `const searchEntries: <inferred>`
254
277
  - `const searchLinkableEntries: <inferred>`
255
278
  - `const setFocalPoint: <inferred>`
@@ -275,10 +298,6 @@ Tags:
275
298
  - `defineObject(config: Omit<ObjectField, 'type'>): ObjectField` — Defines a reusable object field (nested record). Use inline inside `fields[]`
276
299
  - `defineSingle(config: SingleInput): SingleConfig` — Defines a singleton (single-entry content type, e.g. site settings, homepage).
277
300
  - `enableHybridEditing(): <inferred>` — Call in a layout/component script to enable data-hybrid-path rendering for all descendant HybridTarget/Image/Video.
278
- - `extractBlocks(doc: StructuredContentDoc, type?: string): SCNode[]` — Extract block-level nodes, optionally filtered by type.
279
- - `extractInlineBlocks(doc: StructuredContentDoc, blockType?: string): SCInlineBlockAttrs[]` — Extract inline block nodes, optionally filtered by blockType.
280
- - `extractMediaRefs(doc: StructuredContentDoc): MediaRef[]` — Extract media references from figure/video/image nodes.
281
- - `extractText(doc: StructuredContentDoc): string` — Extract all plain text from doc (useful for excerpts, search indexing).
282
301
  - `getCustomFields(): Map<string, CustomFieldDefinition>`
283
302
  - `getLink(link: string | { url: string | Record<string, string> } |..., language?: string): string` — Resolves a link value to a URL string.
284
303
  - `getRemotes(): typeof remotes`
@@ -304,7 +323,12 @@ Tags:
304
323
  - `const createConsentLog: <inferred>`
305
324
  - `const createFormSubmission: <inferred>`
306
325
  - `createRestApiHandler(): <inferred>` — REST API handler factory. Returns `{ GET, POST, PUT, DELETE }`
326
+ - `extractBlocks(doc: StructuredContentDoc, type?: string): SCNode[]` — Extract block-level nodes, optionally filtered by type.
327
+ - `extractInlineBlocks(doc: StructuredContentDoc, blockType?: string): SCInlineBlockAttrs[]` — Extract inline block nodes, optionally filtered by blockType.
328
+ - `extractMediaRefs(doc: StructuredContentDoc): MediaRef[]` — Extract media references from figure/video/image nodes.
329
+ - `extractText(doc: StructuredContentDoc): string` — Extract all plain text from doc (useful for excerpts, search indexing).
307
330
  - `generateApiKey(): string` — Generate a cryptographically random API key (32 bytes, base64url-encoded).
331
+ - `getMailer(): EmailAdapter | null` — Returns the configured email adapter from the active CMS singleton, or
308
332
  - `getPreviewEntry(event: RequestEvent, options: { language: string }): Promise<Entry | null>` — Resolves the preview entry from a `?preview=<versionId>` query param.
309
333
  - `includioCMS(cmsConfig: CMSConfig): Handle[]` — SvelteKit `Handle[]` array that initializes the CMS, generates runtime
310
334
  - `parseFormDataForSubmission(formData: FormData, fields: FormField[]): Promise<Record<string, unknown>>` — Parses multipart `FormData` into a typed record of field values, handling
@@ -314,6 +338,7 @@ Tags:
314
338
  - `resolveEntry(opts: ResolveEntryOptions): Promise<Entry | null>` — Fetch a single populated Entry.
315
339
  - `interface ResolveEntryOptions`
316
340
  - `type ResolveStatus = 'published' | 'draft' | 'scheduled'` — Status filter for `resolveEntry`/`resolveEntries`/`countEntries`.
341
+ - `sendMail(options: SendMailOptions): Promise<void>` — Send an email through the configured CMS email adapter. Thin convenience
317
342
 
318
343
  ### `includio-cms/db-postgres`
319
344
 
@@ -439,6 +464,7 @@ Tags:
439
464
  - `isValidNip(nip: string): boolean` — Validate a Polish NIP (tax id) — 10 digits with a weighted checksum.
440
465
  - `isVariantExpired(variant: VariantLike, config: VariantExpiryConfig | null, now: Date = new Date(Date.now())): boolean` — Check whether a variant has expired under the given config. Fail-open by
441
466
  - `manualAdapter(opts: ManualPaymentAdapterOptions = {}): PaymentAdapter` — Manual payment adapter — order goes to awaitingPayment, admin marks as paid later
467
+ - `type Order = typeof shopOrdersTable.$inferSelect` — Public row type for a single shop order — mirrors the Drizzle `shop_orders`
442
468
  - `interface OrderRef`
443
469
  - `type OrderStatus = | 'new' | 'awaitingPayment' | 'paid' | 'preparing' | 'sent' | 'done' | 'cancelled' | 'paymentReje...`
444
470
  - `interface PartialPayment` — Persisted partial-payment summary on `order.partialPayment` when the order
package/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
3
3
  All notable changes to includio-cms are documented here.
4
4
  Generated from `src/lib/updates/` — do not edit manually.
5
5
 
6
+ ## 0.34.0 — 2026-06-03
7
+
8
+ Soft-delete zamówień (admin-only) — administrator może ukryć zamówienie z listy bez utraty danych. Odwracalne (kosz + przywracanie), bezpieczne księgowo: nie kasuje wiersza, faktur ani historii. Dozwolone tylko dla „bezpiecznych" statusów bez płatności (`new`, `awaitingPayment`, `cancelled`, `paymentRejected`) i zablokowane dla zamówień z wystawioną fakturą. Cała funkcja widoczna wyłącznie dla roli `admin`. Additive only — bez breaking changes.
9
+
10
+ ### Added
11
+ - `shop_orders` dostaje kolumny `deleted_at` (timestamptz, NULL = widoczne) i `deleted_by` (text). Lista zamówień domyślnie ukrywa miękko usunięte; `listOrders`/`countOrders` (`$lib/shop/server/orders.ts`) przyjmują `deleted: "exclude" | "only" | "include"` (domyślnie `exclude`).
12
+ - `softDeleteOrder(orderId, deletedBy)` / `restoreOrder(orderId)` (`$lib/shop/server/orders.ts`, `@public`) — miękkie usuwanie/przywracanie (idempotentne). Soft-delete zwalnia natychmiast aktywną rezerwację stocku (nie czeka na TTL). Guard: `decideOrderDeletion(status, invoice)` + `DELETABLE_ORDER_STATUSES` / `isOrderDeletable(status)` (czyste, testowalne) — rzuca `OrderNotDeletableError` dla niedozwolonego statusu lub faktury `issued`/`sent`.
13
+ - Auto-restore: zmiana statusu miękko usuniętego zamówienia na nieusuwalny (np. spóźniony webhook płatności na ukrytym `awaitingPayment` → `paid`) automatycznie zdejmuje je z kosza — opłacone zamówienia nigdy nie zostają ukryte.
14
+ - Customer-facing `getOrderByNumber` nie zwraca miękko usuniętego zamówienia (nie resolvuje się na storefroncie); admin `getOrderById` celowo ignoruje `deletedAt` (podgląd/przywracanie z kosza).
15
+ - `deleteOrderCmd` / `restoreOrderCmd` (commands) + `listOrdersAdmin({ deleted })` (`includio-cms/admin/remote`) — chronione `requireRole("admin")` (kosz i usuwanie tylko dla admina; normalna lista nadal `requireAuth`).
16
+ - Admin UI: `shop-order-detail-page` zyskuje sekcję „Usuń zamówienie" (tylko admin + status usuwalny) z dialogiem potwierdzenia; `shop-orders-list-page` — przełącznik „Kosz" (tylko admin) z akcją „Przywróć" w wierszu.
17
+
18
+ ### Migration
19
+
20
+ ```sql
21
+ ALTER TABLE shop_orders ADD COLUMN IF NOT EXISTS deleted_at timestamptz;
22
+ ALTER TABLE shop_orders ADD COLUMN IF NOT EXISTS deleted_by text;
23
+ ```
24
+
6
25
  ## 0.28.0 — 2026-06-01
7
26
 
8
27
  Fakturowanie — integracja sklepu z Fakturownią: automatyczne wystawianie i wysyłka faktury po opłaceniu zamówienia. Nowy generyczny `InvoicingAdapter` (spójny z payment/carrier) + `fakturowniaAdapter()` jako pierwsza implementacja. Faktura wystawiana fire-and-forget gdy zamówienie jest w pełni opłacone (`!balanceOwed` — zaliczki czekają na dopłatę balansu), wysyłana przez Fakturownię (`send_by_email`). Trigger konfigurowalny per-adapter (`issueWhen`: `b2bAndOnRequest` domyślnie / `always`). Checkout zbiera dane B2B (NIP z twardą walidacją sumy kontrolnej, nazwa firmy, adres do faktury, opt-in „chcę fakturę"). Idempotencja przez `shop_invoices` (unikat per zamówienie); ręczny retry w adminie. Additive only — żadnych breaking zmian.
package/DOCS.md CHANGED
@@ -1,4 +1,4 @@
1
- # Includio CMS Documentation (v0.28.0)
1
+ # Includio CMS Documentation (v0.34.0)
2
2
 
3
3
  > This file is auto-generated from the docs site. For the latest version, update the package.
4
4
 
package/ROADMAP.md CHANGED
@@ -30,6 +30,7 @@
30
30
  - [x] Faza 6 — envet integration (pilot consumer) — szkolenia variants + deposit flow + balance link end-to-end QA. <!-- files: envet repo src/lib/cms/cms.config.ts, src/routes/api/shop/, src/routes/(website)/{szkolenia,koszyk}/, src/lib/components/{CartIcon,AddToCartModal,CoursePage}.svelte, cli/seed.ts -->
31
31
  - [x] Faza 7 — Release artifacts (changelog, ROADMAP cleanup, API.md, build) — 3 post-Faza-5 hotfixy w 0.27.0 (single release). <!-- files: src/lib/updates/0.27.0/index.ts, ROADMAP.md, CHANGELOG.md, API.md, MIGRATION-... -->
32
32
  - [x] `[feature]` `[P1]` Slug first-class + SEO v1.0 freeze (0.26.0) — `resolveSeo` public (`includio-cms/core`), `seoFieldDescriptor` SSOT (Zod+TS drift-guard), admin URL un-hardcode (`slugPath.ts` pure resolver, no `seo`-field requirement), `SlugField`/`SeoField`/`SeoFieldData` `@public` v1.0-frozen <!-- files: src/lib/core/fields/slugPath.ts, src/lib/core/fields/seoFieldDescriptor.ts, src/lib/core/fields/resolveSeo.ts, src/lib/types/fields.ts, src/lib/admin/client/collection/collection-entries.svelte, src/lib/updates/0.26.0/ -->
33
+ - [x] `[feature]` `[P2]` Soft-delete zamówień admin-only (0.34.0) — ukrycie zamówienia z listy bez utraty danych (`deleted_at`/`deleted_by`), kosz + przywracanie, guard `decideOrderDeletion` (safe-statuses + faktura), auto-restore przy płatności, zwolnienie rezerwacji stocku, `requireRole('admin')` <!-- files: src/lib/shop/server/orders.ts, src/lib/db-postgres/schema/shop/order.ts, src/lib/admin/remote/shop.remote.ts, src/lib/admin/client/shop/{shop-order-detail-page,shop-orders-list-page,restore-order-cell}.svelte, src/lib/updates/0.34.0/ -->
33
34
 
34
35
  ## v1.x — Post-v1.0 deferred
35
36
 
@@ -11,6 +11,8 @@ import * as transcodeVideosHandlers from './transcode-videos.js';
11
11
  import * as uploadLimitHandlers from './upload-limit.js';
12
12
  import * as systemInfoHandlers from './system-info.js';
13
13
  import * as maintenanceStatusHandlers from './maintenance-status.js';
14
+ import * as integrationsHandlers from './integrations.js';
15
+ import * as testEmailHandlers from './test-email.js';
14
16
  import { requireAuth } from '../remote/middleware/auth.js';
15
17
  import { getCMS } from '../../core/cms.js';
16
18
  import { lookup } from 'mrmime';
@@ -28,6 +30,8 @@ export function createAdminApiHandler(options) {
28
30
  'upload-limit': uploadLimitHandlers,
29
31
  'system-info': systemInfoHandlers,
30
32
  'maintenance-status': maintenanceStatusHandlers,
33
+ integrations: integrationsHandlers,
34
+ 'test-email': testEmailHandlers,
31
35
  ...options?.extraRoutes
32
36
  };
33
37
  const privateMediaGet = async (event) => {
@@ -0,0 +1,13 @@
1
+ import { type RequestHandler } from '@sveltejs/kit';
2
+ /**
3
+ * Integration diagnostics for the admin maintenance panel.
4
+ *
5
+ * `GET` — report which integrations are configured and whether each supports a
6
+ * connectivity ping. Returns NO secrets (only ids, labels, booleans
7
+ * and the admin notification e-mail used as a UI placeholder).
8
+ * `POST` — run a single adapter's non-invasive `healthCheck()` and return the
9
+ * `{ ok, message }` result. Errors are mapped to `message` text — the
10
+ * underlying secret/token is never serialised to the client.
11
+ */
12
+ export declare const GET: RequestHandler;
13
+ export declare const POST: RequestHandler;
@@ -0,0 +1,61 @@
1
+ import { json } from '@sveltejs/kit';
2
+ import { requireRole } from '../remote/middleware/auth.js';
3
+ import { getCMS } from '../../core/cms.js';
4
+ /**
5
+ * Integration diagnostics for the admin maintenance panel.
6
+ *
7
+ * `GET` — report which integrations are configured and whether each supports a
8
+ * connectivity ping. Returns NO secrets (only ids, labels, booleans
9
+ * and the admin notification e-mail used as a UI placeholder).
10
+ * `POST` — run a single adapter's non-invasive `healthCheck()` and return the
11
+ * `{ ok, message }` result. Errors are mapped to `message` text — the
12
+ * underlying secret/token is never serialised to the client.
13
+ */
14
+ export const GET = async () => {
15
+ requireRole('admin');
16
+ const cms = getCMS();
17
+ const shop = cms.shopConfig;
18
+ return json({
19
+ email: {
20
+ configured: !!cms.emailAdapter,
21
+ adminEmail: shop?.adminEmail ?? null
22
+ },
23
+ payment: (shop?.payment ?? []).map((p) => ({
24
+ id: p.id,
25
+ label: p.label,
26
+ canPing: typeof p.healthCheck === 'function'
27
+ })),
28
+ invoicing: shop?.invoicing
29
+ ? {
30
+ id: shop.invoicing.id,
31
+ canPing: typeof shop.invoicing.healthCheck === 'function'
32
+ }
33
+ : null
34
+ });
35
+ };
36
+ export const POST = async ({ request }) => {
37
+ requireRole('admin');
38
+ const body = (await request.json().catch(() => null));
39
+ if (!body || (body.kind !== 'payment' && body.kind !== 'invoicing')) {
40
+ return json({ error: 'Invalid body: expected { kind: "payment" | "invoicing", id? }' }, {
41
+ status: 400
42
+ });
43
+ }
44
+ const shop = getCMS().shopConfig;
45
+ const adapter = body.kind === 'payment'
46
+ ? (shop?.payment ?? []).find((p) => p.id === body.id) ?? shop?.payment?.[0]
47
+ : shop?.invoicing ?? null;
48
+ if (!adapter) {
49
+ return json({ error: 'Integration not configured' }, { status: 404 });
50
+ }
51
+ if (typeof adapter.healthCheck !== 'function') {
52
+ return json({ ok: false, message: 'Health-check not supported by this adapter' });
53
+ }
54
+ try {
55
+ const result = await adapter.healthCheck();
56
+ return json(result);
57
+ }
58
+ catch (e) {
59
+ return json({ ok: false, message: e instanceof Error ? e.message : String(e) });
60
+ }
61
+ };
@@ -0,0 +1,9 @@
1
+ import { type RequestHandler } from '@sveltejs/kit';
2
+ /**
3
+ * Send a real test e-mail through the configured email adapter, to verify
4
+ * end-to-end SMTP delivery from the admin maintenance panel.
5
+ *
6
+ * Body: `{ to?: string }`. When `to` is empty, falls back to the shop's
7
+ * `adminEmail`. Returns `{ ok }` or `{ ok: false, message }`.
8
+ */
9
+ export declare const POST: RequestHandler;
@@ -0,0 +1,39 @@
1
+ import { json } from '@sveltejs/kit';
2
+ import { requireRole } from '../remote/middleware/auth.js';
3
+ import { getCMS } from '../../core/cms.js';
4
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
5
+ /**
6
+ * Send a real test e-mail through the configured email adapter, to verify
7
+ * end-to-end SMTP delivery from the admin maintenance panel.
8
+ *
9
+ * Body: `{ to?: string }`. When `to` is empty, falls back to the shop's
10
+ * `adminEmail`. Returns `{ ok }` or `{ ok: false, message }`.
11
+ */
12
+ export const POST = async ({ request }) => {
13
+ requireRole('admin');
14
+ const cms = getCMS();
15
+ const mailer = cms.emailAdapter;
16
+ if (!mailer) {
17
+ return json({ ok: false, message: 'Brak skonfigurowanego adaptera e-mail' }, { status: 400 });
18
+ }
19
+ const body = (await request.json().catch(() => null));
20
+ const to = (body?.to?.trim() || cms.shopConfig?.adminEmail || '').trim();
21
+ if (!to) {
22
+ return json({ ok: false, message: 'Brak odbiorcy — podaj adres lub ustaw ADMIN_EMAIL' }, { status: 400 });
23
+ }
24
+ if (!EMAIL_RE.test(to)) {
25
+ return json({ ok: false, message: `Nieprawidłowy adres e-mail: ${to}` }, { status: 400 });
26
+ }
27
+ try {
28
+ await mailer.sendMail({
29
+ to,
30
+ subject: 'AriaCMS — test połączenia e-mail',
31
+ html: '<p>To jest testowa wiadomość wysłana z panelu Konserwacja. Jeśli ją widzisz, integracja e-mail działa poprawnie.</p>',
32
+ text: 'To jest testowa wiadomość wysłana z panelu Konserwacja. Jeśli ją widzisz, integracja e-mail działa poprawnie.'
33
+ });
34
+ return json({ ok: true });
35
+ }
36
+ catch (e) {
37
+ return json({ ok: false, message: e instanceof Error ? e.message : String(e) });
38
+ }
39
+ };