includio-cms 0.28.0 → 0.33.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 (99) hide show
  1. package/API.md +41 -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 +543 -543
  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 +2 -2
  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 +1 -1
  30. package/dist/admin/remote/shop.remote.d.ts +71 -44
  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/input/input.svelte.d.ts +1 -1
  37. package/dist/components/ui/input-group/input-group-input.svelte.d.ts +1 -1
  38. package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +1 -1
  39. package/dist/core/cms.d.ts +44 -2
  40. package/dist/core/cms.js +64 -0
  41. package/dist/core/index.d.ts +2 -4
  42. package/dist/core/index.js +1 -4
  43. package/dist/core/server/index.d.ts +4 -1
  44. package/dist/core/server/index.js +4 -1
  45. package/dist/db-postgres/schema/shop/order.d.ts +34 -0
  46. package/dist/db-postgres/schema/shop/order.js +4 -0
  47. package/dist/shop/adapters/fakturownia/client.d.ts +5 -0
  48. package/dist/shop/adapters/fakturownia/client.js +20 -0
  49. package/dist/shop/adapters/fakturownia/index.js +11 -0
  50. package/dist/shop/adapters/payu/index.js +11 -0
  51. package/dist/shop/index.d.ts +1 -1
  52. package/dist/shop/server/coupons.d.ts +10 -0
  53. package/dist/shop/server/coupons.js +19 -0
  54. package/dist/shop/server/email.d.ts +7 -3
  55. package/dist/shop/server/email.js +86 -112
  56. package/dist/shop/server/emailTemplateRegistry.d.ts +47 -0
  57. package/dist/shop/server/emailTemplateRegistry.js +288 -0
  58. package/dist/shop/server/orders.d.ts +60 -1
  59. package/dist/shop/server/orders.js +145 -16
  60. package/dist/shop/templates/_partials/footer.en.html +4 -0
  61. package/dist/shop/templates/_partials/footer.pl.html +4 -0
  62. package/dist/shop/templates/_partials/header.en.html +4 -0
  63. package/dist/shop/templates/_partials/header.pl.html +4 -0
  64. package/dist/shop/templates/_partials/items.en.html +14 -0
  65. package/dist/shop/templates/_partials/items.pl.html +14 -0
  66. package/dist/shop/templates/_partials/tracking.en.html +7 -0
  67. package/dist/shop/templates/_partials/tracking.pl.html +7 -0
  68. package/dist/shop/templates/awaiting-payment.en.html +6 -0
  69. package/dist/shop/templates/awaiting-payment.pl.html +6 -0
  70. package/dist/shop/templates/cancelled.en.html +6 -0
  71. package/dist/shop/templates/cancelled.pl.html +6 -0
  72. package/dist/shop/templates/low-stock.en.html +14 -0
  73. package/dist/shop/templates/low-stock.pl.html +14 -0
  74. package/dist/shop/templates/order-completed.en.html +6 -0
  75. package/dist/shop/templates/order-completed.pl.html +6 -0
  76. package/dist/shop/templates/order-received.en.html +7 -0
  77. package/dist/shop/templates/order-received.pl.html +7 -0
  78. package/dist/shop/templates/payment-received.en.html +7 -0
  79. package/dist/shop/templates/payment-received.pl.html +7 -0
  80. package/dist/shop/templates/payment-rejected.en.html +6 -0
  81. package/dist/shop/templates/payment-rejected.pl.html +6 -0
  82. package/dist/shop/templates/preparing.en.html +7 -0
  83. package/dist/shop/templates/preparing.pl.html +7 -0
  84. package/dist/shop/templates/refunded.en.html +6 -0
  85. package/dist/shop/templates/refunded.pl.html +6 -0
  86. package/dist/shop/templates/shipped.en.html +7 -0
  87. package/dist/shop/templates/shipped.pl.html +7 -0
  88. package/dist/shop/types.d.ts +63 -0
  89. package/dist/sveltekit/index.d.ts +0 -1
  90. package/dist/sveltekit/index.js +0 -1
  91. package/dist/sveltekit/server/index.d.ts +1 -0
  92. package/dist/sveltekit/server/index.js +1 -0
  93. package/dist/types/adapters/email.d.ts +13 -0
  94. package/dist/types/cms.d.ts +30 -0
  95. package/dist/types/index.d.ts +1 -1
  96. package/dist/updates/0.34.0/index.d.ts +2 -0
  97. package/dist/updates/0.34.0/index.js +17 -0
  98. package/dist/updates/index.js +3 -1
  99. package/package.json +7 -2
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Czekamy na płatność</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Otrzymaliśmy zamówienie {{order.number}}. Czekamy na płatność zgodnie z wybraną metodą.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Order cancelled</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Order {{order.number}} has been cancelled.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zamówienie anulowane</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Zamówienie {{order.number}} zostało anulowane.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en"><body style="margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;background:#f5f5f8;color:#1a1a2e;">
3
+ <div style="max-width:560px;margin:0 auto;padding:24px;">
4
+ <div style="background:#fff;border-radius:12px;padding:28px;">
5
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;color:#C4893A;">Low stock alert</h1>
6
+ <p style="margin:0 0 16px;color:#555566;line-height:1.5;">
7
+ Product <strong>{{product.title}}</strong>{{#if product.variantSku}} (SKU {{product.variantSku}}){{/if}}
8
+ has only <strong>{{product.stock}}</strong> units left in stock (alert threshold: {{product.threshold}}).
9
+ </p>
10
+ <p style="margin:0;color:#8888A0;font-size:13px;">Restock in the admin panel to avoid running out.</p>
11
+ </div>
12
+ <p style="text-align:center;color:#8888A0;font-size:12px;margin-top:16px;">AriaCMS · {{shop.adminEmail}}</p>
13
+ </div>
14
+ </body></html>
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="pl"><body style="margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;background:#f5f5f8;color:#1a1a2e;">
3
+ <div style="max-width:560px;margin:0 auto;padding:24px;">
4
+ <div style="background:#fff;border-radius:12px;padding:28px;">
5
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;color:#C4893A;">Niski stan magazynowy</h1>
6
+ <p style="margin:0 0 16px;color:#555566;line-height:1.5;">
7
+ Produkt <strong>{{product.title}}</strong>{{#if product.variantSku}} (SKU {{product.variantSku}}){{/if}}
8
+ ma już tylko <strong>{{product.stock}}</strong> sztuk w magazynie (próg alertu: {{product.threshold}}).
9
+ </p>
10
+ <p style="margin:0;color:#8888A0;font-size:13px;">Uzupełnij stan w panelu admina, żeby uniknąć przerwy w sprzedaży.</p>
11
+ </div>
12
+ <p style="text-align:center;color:#8888A0;font-size:12px;margin-top:16px;">AriaCMS · {{shop.adminEmail}}</p>
13
+ </div>
14
+ </body></html>
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Order completed</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Order {{order.number}} is complete. Thanks for shopping with us!</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zamówienie zrealizowane</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Zamówienie {{order.number}} zostało zakończone. Dziękujemy za zakupy!</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Order {{order.number}}</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Thanks! We received your order and will process it shortly.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zamówienie {{order.number}}</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Dziękujemy! Otrzymaliśmy Twoje zamówienie i wkrótce je przetworzymy.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Payment received</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Payment for order {{order.number}} has been received. Your order is moving to fulfilment.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Płatność zaksięgowana</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Płatność za zamówienie {{order.number}} została zaksięgowana. Przekazujemy zamówienie do realizacji.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Payment rejected</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Payment for order {{order.number}} was not received. Please contact us if you have questions.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Płatność odrzucona</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Płatność za zamówienie {{order.number}} nie została zaksięgowana. Skontaktuj się z nami w razie pytań.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Preparing order</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Your order {{order.number}} is being prepared.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zamówienie w przygotowaniu</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Twoje zamówienie {{order.number}} jest pakowane.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Order refunded</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Your refund for order {{order.number}} has been issued. It should reach your account within a few business days.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,6 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zwrot zaksięgowany</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Środki za zamówienie {{order.number}} zostały zwrócone. Powinny pojawić się na koncie w ciągu kilku dni roboczych.</p>
4
+ {{> items}}
5
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
6
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Order shipped</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Order {{order.number}} has been shipped.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -0,0 +1,7 @@
1
+ {{> header}}
2
+ <h1 style="font-size:20px;font-weight:800;margin:0 0 8px;">Zamówienie wysłane</h1>
3
+ <p style="margin:0 0 20px;color:#555566;line-height:1.5;">Zamówienie {{order.number}} zostało wysłane.</p>
4
+ {{> items}}
5
+ {{> tracking}}
6
+ {{#if viewUrl}}<div style="margin-top:24px;text-align:center;"><a href="{{viewUrl}}" style="display:inline-block;background:#5B4A9E;color:#fff;text-decoration:none;padding:10px 18px;border-radius:8px;font-weight:600;">{{viewLinkLabel}}</a></div>{{/if}}
7
+ {{> footer}}
@@ -1,5 +1,12 @@
1
1
  import type { Language } from '../types/languages.js';
2
+ import type { shopOrdersTable } from '../db-postgres/schema/shop/order.js';
2
3
  export type Currency = 'PLN';
4
+ /**
5
+ * Public row type for a single shop order — mirrors the Drizzle `shop_orders`
6
+ * table. Use this in `ShopConfig.onOrderPaid` and similar hooks.
7
+ * @public
8
+ */
9
+ export type Order = typeof shopOrdersTable.$inferSelect;
3
10
  export type OrderStatus = 'new' | 'awaitingPayment' | 'paid' | 'preparing' | 'sent' | 'done' | 'cancelled' | 'paymentRejected' | 'refunded';
4
11
  export type I18nText = {
5
12
  [lang: string]: string;
@@ -27,11 +34,28 @@ export interface PaymentCreateContext {
27
34
  customerIp?: string;
28
35
  language?: string | null;
29
36
  }
37
+ /**
38
+ * Result of a non-invasive integration connectivity check. Returned by an
39
+ * adapter's optional `healthCheck()` — `ok` reflects reachability + auth, and
40
+ * `message` carries a human-readable detail (error text on failure, optional
41
+ * note on success). MUST NOT leak secrets.
42
+ * @public
43
+ */
44
+ export interface IntegrationHealthResult {
45
+ ok: boolean;
46
+ message?: string;
47
+ }
30
48
  export interface PaymentAdapter {
31
49
  id: string;
32
50
  label: I18nText;
33
51
  createPayment(order: OrderRef, ctx?: PaymentCreateContext): Promise<PaymentCreateResult>;
34
52
  handleWebhook?(req: Request): Promise<PaymentEvent>;
53
+ /**
54
+ * Non-invasive connectivity check (e.g. an OAuth token fetch). Optional —
55
+ * adapters omitting this are reported as "health-check unsupported". MUST
56
+ * NOT create real transactions.
57
+ */
58
+ healthCheck?(): Promise<IntegrationHealthResult>;
35
59
  /**
36
60
  * Poll the provider for the latest payment status. Used as a fallback
37
61
  * when a webhook is lost. `providerRef` is the external id the adapter
@@ -323,6 +347,12 @@ export interface InvoicingAdapter {
323
347
  issueWhen?: InvoiceIssuePolicy;
324
348
  createInvoice(payload: InvoicePayload, ctx?: InvoiceContext): Promise<InvoiceCreateResult>;
325
349
  send?(externalId: string, ctx?: InvoiceContext): Promise<void>;
350
+ /**
351
+ * Non-invasive connectivity check (e.g. a read-only account lookup).
352
+ * Optional — adapters omitting this are reported as "health-check
353
+ * unsupported". MUST NOT issue real invoices.
354
+ */
355
+ healthCheck?(): Promise<IntegrationHealthResult>;
326
356
  }
327
357
  export interface ShopConfig {
328
358
  currency: Currency;
@@ -370,6 +400,39 @@ export interface ShopConfig {
370
400
  * @public
371
401
  */
372
402
  variantExpiry?: VariantExpiryConfig;
403
+ /**
404
+ * Optional shop email templates configuration. Templates are looked up
405
+ * first in the consumer project's `dir` (override), then in the bundled
406
+ * defaults. Files are named `<name>.<lang>.html` (per-lang) with a
407
+ * lang-agnostic project fallback (`<name>.html`). Handlebars syntax with
408
+ * partials in `_partials/<name>.<lang>.html`. CMS singletons accessible
409
+ * via `{{cms.<slug>.<field>}}` tokens (auto-fetched per template).
410
+ * @public
411
+ */
412
+ emailTemplates?: {
413
+ /** Project directory holding overrides. Default `'src/emails/shop'`. */
414
+ dir?: string;
415
+ /** Throw on missing tokens / unknown CMS slugs. Default `false` (lenient → ""). */
416
+ strict?: boolean;
417
+ };
418
+ /**
419
+ * Optional callback fired after an order transitions to `paid`.
420
+ *
421
+ * Triggered inside `updateOrderStatus` only when the previous status was
422
+ * NOT `paid` and the new status is `paid` (transition guard) — so a manual
423
+ * `cancelled → paid` flip will fire, but a no-op `paid → paid` call will not.
424
+ * Runs AFTER `sendOrderStatusEmail` and `maybeIssueInvoiceForOrder`; receives
425
+ * the fresh order row (post-update snapshot, with the latest `consents` etc).
426
+ *
427
+ * Errors are caught and logged — the callback never blocks the webhook,
428
+ * the status write, or the invoice. Use for fire-and-forget side effects
429
+ * (admin notifications, CRM sync, slack ping). If you need strict
430
+ * once-per-order semantics across refund→repay cycles, persist your own
431
+ * idempotency flag in userland (the transition guard alone fires once per
432
+ * `paid` entry, which may not match "lifetime once" for refunded orders).
433
+ * @public
434
+ */
435
+ onOrderPaid?: (order: Order) => Promise<void> | void;
373
436
  }
374
437
  export interface ResolvedShopConfig extends Omit<ShopConfig, 'variantLabel' | 'variantExpiry' | 'invoicing'> {
375
438
  features: Required<ShopFeatures>;
@@ -12,4 +12,3 @@ export { enableHybridEditing } from './components/hybrid-context.js';
12
12
  export { setPreferMp4 } from './components/video-context.js';
13
13
  export { getLink, isImageFieldData, isVideoFieldData } from './utils/index.js';
14
14
  export { structuredToHtml } from '../core/fields/structuredToHtml.js';
15
- export { extractBlocks, extractInlineBlocks, extractText, extractMediaRefs } from '../core/server/fields/queryStructuredContent.js';
@@ -12,4 +12,3 @@ export { enableHybridEditing } from './components/hybrid-context.js';
12
12
  export { setPreferMp4 } from './components/video-context.js';
13
13
  export { getLink, isImageFieldData, isVideoFieldData } from './utils/index.js';
14
14
  export { structuredToHtml } from '../core/fields/structuredToHtml.js';
15
- export { extractBlocks, extractInlineBlocks, extractText, extractMediaRefs } from '../core/server/fields/queryStructuredContent.js';
@@ -8,3 +8,4 @@ export { getPreviewEntry } from './preview.js';
8
8
  export { createRestApiHandler } from '../../admin/api/rest/handler.js';
9
9
  export { generateApiKey } from '../../admin/api/rest/middleware/generateApiKey.js';
10
10
  export { createAdminApiHandler } from '../../admin/api/handler.js';
11
+ export { extractBlocks, extractInlineBlocks, extractText, extractMediaRefs } from '../../core/server/fields/queryStructuredContent.js';
@@ -10,3 +10,4 @@ export { createRestApiHandler } from '../../admin/api/rest/handler.js';
10
10
  export { generateApiKey } from '../../admin/api/rest/middleware/generateApiKey.js';
11
11
  // Folded from `./admin/api/handler` (dropped as separate export in 0.26.1)
12
12
  export { createAdminApiHandler } from '../../admin/api/handler.js';
13
+ export { extractBlocks, extractInlineBlocks, extractText, extractMediaRefs } from '../../core/server/fields/queryStructuredContent.js';
@@ -14,5 +14,18 @@ export interface SendMailOptions {
14
14
  to: string | string[];
15
15
  subject: string;
16
16
  html: string;
17
+ /**
18
+ * Plain-text fallback served alongside HTML for clients that prefer text
19
+ * (better deliverability + accessibility). Optional — omitted = HTML-only.
20
+ * @public
21
+ */
22
+ text?: string;
23
+ /**
24
+ * Override the Reply-To header. Useful for admin notifications where the
25
+ * default sender is a no-reply address but replies should land in a real
26
+ * inbox. Omitted = adapter default (typically no Reply-To header).
27
+ * @public
28
+ */
29
+ replyTo?: string;
17
30
  }
18
31
  export type SendMail = (options: SendMailOptions) => Promise<void>;
@@ -52,9 +52,21 @@ export interface AuthAdapter {
52
52
  } | null>;
53
53
  };
54
54
  }
55
+ export interface AuthRateLimitRule {
56
+ window: number;
57
+ max: number;
58
+ }
59
+ export interface AuthRateLimitConfig {
60
+ enabled?: boolean;
61
+ window?: number;
62
+ max?: number;
63
+ customRules?: Record<string, AuthRateLimitRule>;
64
+ storage?: 'memory' | 'secondary-storage' | 'database';
65
+ }
55
66
  export interface AuthConfig {
56
67
  secret: string;
57
68
  baseURL?: string;
69
+ rateLimit?: AuthRateLimitConfig;
58
70
  }
59
71
  export interface ApiKeyConfig {
60
72
  key: string;
@@ -68,6 +80,22 @@ export interface ApiKeyConfig {
68
80
  export interface TypographyConfig {
69
81
  fixOrphans?: boolean;
70
82
  }
83
+ /**
84
+ * Optional admin UI configuration — extension points for the panel sidebar
85
+ * and other admin surfaces. Set on `defineConfig({ admin: ... })`.
86
+ *
87
+ * @public
88
+ */
89
+ export interface AdminConfig {
90
+ /**
91
+ * Additional sidebar nav items rendered below the built-in sections
92
+ * (Dashboard, Collections, Singles, Forms, Shop). Useful for custom
93
+ * admin pages added by the consumer project (e.g. `/admin/newsletter`).
94
+ * Items are read once per session via a remote query and rendered with
95
+ * the same styling as built-in sections.
96
+ */
97
+ extraNavItems?: import('../admin/types.js').AdminNavItem[];
98
+ }
71
99
  export interface CMSConfig {
72
100
  languages: Language[];
73
101
  collections?: CollectionConfig[];
@@ -85,6 +113,7 @@ export interface CMSConfig {
85
113
  sidebarHelp?: boolean;
86
114
  shop?: ResolvedShopConfig;
87
115
  cmp?: ResolvedCmpConfig;
116
+ admin?: AdminConfig;
88
117
  }
89
118
  export interface ICMS {
90
119
  collections: Record<string, CollectionConfigWithType>;
@@ -104,4 +133,5 @@ export interface ICMS {
104
133
  typographyConfig: TypographyConfig;
105
134
  shopConfig: ResolvedShopConfig | null;
106
135
  cmpConfig: ResolvedCmpConfig | null;
136
+ adminConfig: AdminConfig | null;
107
137
  }
@@ -9,7 +9,7 @@ export { type CollectionConfig } from './collections.js';
9
9
  export { type SingleConfig } from './singles.js';
10
10
  export { type FormConfig, type FormSubmission } from './forms.js';
11
11
  export { type FormField, type FormFieldType, type FormBaseField, type FormTextField, type FormEmailField, type FormTextareaField, type FormCheckboxField, type FormSelectField } from './formFields.js';
12
- export { type CMSConfig, type ApiKeyConfig, type AuthConfig, type TypographyConfig } from './cms.js';
12
+ export { type CMSConfig, type ApiKeyConfig, type AuthConfig, type AuthRateLimitConfig, type AuthRateLimitRule, type TypographyConfig } from './cms.js';
13
13
  export { type PluginConfig, type CustomFieldDefinition, type IconSetPlugin, type IconDefinition, type Plugin, isIconSetPlugin } from './plugins.js';
14
14
  export { type Language, type Localized } from './languages.js';
15
15
  export { type Layout, type LayoutNode, type LayoutPreset, type LayoutNodeType, type ColumnRatio, type SectionNode, type ColumnsNode, type CardNode, type AccordionNode, type StackNode, type TabsNode, type TabNode } from './layout.js';
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,17 @@
1
+ export const update = {
2
+ version: '0.34.0',
3
+ date: '2026-06-03',
4
+ description: '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.',
5
+ features: [
6
+ '`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`).',
7
+ '`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`.',
8
+ '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.',
9
+ '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).',
10
+ '`deleteOrderCmd` / `restoreOrderCmd` (commands) + `listOrdersAdmin({ deleted })` (`includio-cms/admin/remote`) — chronione `requireRole("admin")` (kosz i usuwanie tylko dla admina; normalna lista nadal `requireAuth`).',
11
+ '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.'
12
+ ],
13
+ fixes: [],
14
+ breakingChanges: [],
15
+ sql: `ALTER TABLE shop_orders ADD COLUMN IF NOT EXISTS deleted_at timestamptz;
16
+ ALTER TABLE shop_orders ADD COLUMN IF NOT EXISTS deleted_by text;`
17
+ };
@@ -63,6 +63,7 @@ import { update as update0260 } from './0.26.0/index.js';
63
63
  import { update as update0261 } from './0.26.1/index.js';
64
64
  import { update as update0270 } from './0.27.0/index.js';
65
65
  import { update as update0280 } from './0.28.0/index.js';
66
+ import { update as update0340 } from './0.34.0/index.js';
66
67
  export const updates = [
67
68
  update0065,
68
69
  update0066,
@@ -128,7 +129,8 @@ export const updates = [
128
129
  update0260,
129
130
  update0261,
130
131
  update0270,
131
- update0280
132
+ update0280,
133
+ update0340
132
134
  ];
133
135
  export const getUpdatesFrom = (fromVersion) => {
134
136
  const fromParts = fromVersion.split('.').map(Number);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "includio-cms",
3
- "version": "0.28.0",
3
+ "version": "0.33.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -43,7 +43,7 @@
43
43
  "prepublishOnly": "tsx scripts/generate-changelog.ts && tsx scripts/compile-docs.ts && tsx scripts/generate-api-md.ts && git add CHANGELOG.md DOCS.md API.md && (git diff --cached --quiet || git commit -m \"Prepublish v${npm_package_version} (CHANGELOG.md, DOCS.md and API.md updated)\")"
44
44
  },
45
45
  "bin": {
46
- "includio": "./dist/cli/index.js"
46
+ "aria": "./dist/cli/index.js"
47
47
  },
48
48
  "files": [
49
49
  "dist",
@@ -72,6 +72,10 @@
72
72
  "svelte": "./dist/core/index.js",
73
73
  "node": "./dist/core/index.js"
74
74
  },
75
+ "./core/server": {
76
+ "types": "./dist/core/server/index.d.ts",
77
+ "node": "./dist/core/server/index.js"
78
+ },
75
79
  "./types": {
76
80
  "types": "./dist/types/index.d.ts",
77
81
  "svelte": "./dist/types/index.js",
@@ -302,6 +306,7 @@
302
306
  "dotenv": "^16.5.0",
303
307
  "fast-glob": "^3.3.3",
304
308
  "fluent-ffmpeg": "^2.1.3",
309
+ "handlebars": "^4.7.9",
305
310
  "isomorphic-dompurify": "3.0.0-rc.2",
306
311
  "lowlight": "^3.3.0",
307
312
  "mrmime": "^2.0.1",