@unchainedshop/core 4.8.29 → 5.0.0-alpha.10

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 (126) hide show
  1. package/README.md +92 -546
  2. package/lib/bulk-exporter/createBulkExporter.d.ts +2 -2
  3. package/lib/bulk-exporter/createBulkExporter.js +1 -1
  4. package/lib/bulk-exporter/handlers/exportAssortmentsHandler.d.ts +19 -19
  5. package/lib/bulk-exporter/handlers/exportAssortmentsHandler.js +9 -9
  6. package/lib/bulk-exporter/handlers/exportFiltersHandler.d.ts +11 -11
  7. package/lib/bulk-exporter/handlers/exportFiltersHandler.js +5 -5
  8. package/lib/bulk-exporter/handlers/exportProductsHandler.d.ts +19 -19
  9. package/lib/bulk-exporter/handlers/exportProductsHandler.js +11 -11
  10. package/lib/bulk-exporter/handlers/exportUsersHandler.d.ts +17 -17
  11. package/lib/bulk-exporter/handlers/exportUsersHandler.js +8 -8
  12. package/lib/bulk-importer/createBulkImporter.d.ts +1 -1
  13. package/lib/bulk-importer/createBulkImporter.js +6 -6
  14. package/lib/bulk-importer/handlers/product/create.d.ts +135 -32
  15. package/lib/bulk-importer/handlers/product/create.js +33 -16
  16. package/lib/bulk-importer/handlers/product/update.d.ts +63 -33
  17. package/lib/bulk-importer/handlers/product/update.js +5 -48
  18. package/lib/core-index.d.ts +4 -2
  19. package/lib/core-index.js +5 -17
  20. package/lib/directors/BaseDiscountAdapter.d.ts +3 -0
  21. package/lib/directors/BaseDiscountDirector.d.ts +2 -2
  22. package/lib/directors/BaseDiscountDirector.js +12 -14
  23. package/lib/directors/BasePricingDirector.d.ts +2 -2
  24. package/lib/directors/BasePricingDirector.js +4 -7
  25. package/lib/directors/BaseWorker.js +3 -2
  26. package/lib/directors/DeliveryAdapter.js +1 -0
  27. package/lib/directors/DeliveryDirector.d.ts +1 -1
  28. package/lib/directors/DeliveryDirector.js +4 -5
  29. package/lib/directors/DeliveryPricingAdapter.d.ts +2 -1
  30. package/lib/directors/DeliveryPricingAdapter.js +2 -1
  31. package/lib/directors/DeliveryPricingDirector.d.ts +1 -1
  32. package/lib/directors/DeliveryPricingDirector.js +4 -3
  33. package/lib/directors/DeliveryPricingSheet.d.ts +1 -1
  34. package/lib/directors/DeliveryPricingSheet.js +1 -1
  35. package/lib/directors/EnrollmentAdapter.js +1 -1
  36. package/lib/directors/EnrollmentDirector.d.ts +1 -1
  37. package/lib/directors/EnrollmentDirector.js +5 -7
  38. package/lib/directors/FileDirector.d.ts +4 -4
  39. package/lib/directors/FileDirector.js +2 -13
  40. package/lib/directors/FilterAdapter.js +1 -0
  41. package/lib/directors/FilterDirector.d.ts +1 -1
  42. package/lib/directors/FilterDirector.js +6 -8
  43. package/lib/directors/OrderDiscountAdapter.d.ts +3 -2
  44. package/lib/directors/OrderDiscountAdapter.js +5 -2
  45. package/lib/directors/OrderDiscountDirector.js +2 -1
  46. package/lib/directors/OrderPricingAdapter.d.ts +2 -1
  47. package/lib/directors/OrderPricingAdapter.js +3 -1
  48. package/lib/directors/OrderPricingDirector.d.ts +4 -1
  49. package/lib/directors/OrderPricingDirector.js +4 -2
  50. package/lib/directors/OrderPricingSheet.d.ts +2 -1
  51. package/lib/directors/OrderPricingSheet.js +18 -18
  52. package/lib/directors/PaymentAdapter.js +1 -0
  53. package/lib/directors/PaymentDirector.d.ts +1 -1
  54. package/lib/directors/PaymentDirector.js +4 -5
  55. package/lib/directors/PaymentPricingAdapter.d.ts +2 -1
  56. package/lib/directors/PaymentPricingAdapter.js +2 -1
  57. package/lib/directors/PaymentPricingDirector.d.ts +2 -1
  58. package/lib/directors/PaymentPricingDirector.js +3 -2
  59. package/lib/directors/PaymentPricingSheet.d.ts +2 -1
  60. package/lib/directors/PaymentPricingSheet.js +2 -1
  61. package/lib/directors/ProductDiscountAdapter.d.ts +3 -2
  62. package/lib/directors/ProductDiscountAdapter.js +5 -2
  63. package/lib/directors/ProductDiscountDirector.d.ts +1 -1
  64. package/lib/directors/ProductDiscountDirector.js +3 -2
  65. package/lib/directors/ProductPricingAdapter.d.ts +2 -1
  66. package/lib/directors/ProductPricingAdapter.js +3 -1
  67. package/lib/directors/ProductPricingDirector.d.ts +3 -1
  68. package/lib/directors/ProductPricingDirector.js +4 -2
  69. package/lib/directors/ProductPricingSheet.d.ts +1 -1
  70. package/lib/directors/ProductPricingSheet.js +1 -1
  71. package/lib/directors/QuotationAdapter.js +1 -0
  72. package/lib/directors/QuotationDirector.d.ts +1 -1
  73. package/lib/directors/QuotationDirector.js +4 -7
  74. package/lib/directors/WarehousingAdapter.js +1 -0
  75. package/lib/directors/WarehousingDirector.d.ts +1 -1
  76. package/lib/directors/WarehousingDirector.js +19 -27
  77. package/lib/directors/WorkerAdapter.js +1 -0
  78. package/lib/directors/WorkerDirector.d.ts +2 -2
  79. package/lib/directors/WorkerDirector.js +3 -22
  80. package/lib/directors/index.d.ts +2 -0
  81. package/lib/directors/index.js +2 -0
  82. package/lib/directors/registryDirector.d.ts +2 -0
  83. package/lib/directors/registryDirector.js +6 -0
  84. package/lib/factory/index.d.ts +12 -1
  85. package/lib/factory/index.js +12 -1
  86. package/lib/factory/registerAssortmentSearchFilter.d.ts +4 -2
  87. package/lib/factory/registerAssortmentSearchFilter.js +18 -6
  88. package/lib/factory/registerInvoicePayment.d.ts +2 -2
  89. package/lib/factory/registerInvoicePayment.js +12 -3
  90. package/lib/factory/registerPhysicalWarehousing.d.ts +2 -2
  91. package/lib/factory/registerPhysicalWarehousing.js +12 -3
  92. package/lib/factory/registerPickUpDelivery.d.ts +2 -2
  93. package/lib/factory/registerPickUpDelivery.js +12 -3
  94. package/lib/factory/registerProductDiscoverabilityFilter.d.ts +4 -2
  95. package/lib/factory/registerProductDiscoverabilityFilter.js +18 -6
  96. package/lib/factory/registerProductSearchFilter.d.ts +4 -2
  97. package/lib/factory/registerProductSearchFilter.js +16 -6
  98. package/lib/factory/registerShippingDelivery.d.ts +2 -2
  99. package/lib/factory/registerShippingDelivery.js +12 -3
  100. package/lib/factory/registerVirtualWarehousing.d.ts +2 -2
  101. package/lib/factory/registerVirtualWarehousing.js +13 -4
  102. package/lib/factory/registerWorker.d.ts +2 -1
  103. package/lib/factory/registerWorker.js +13 -4
  104. package/lib/plugins/PluginRegistry.d.ts +1 -0
  105. package/lib/plugins/PluginRegistry.js +8 -1
  106. package/lib/services/checkoutOrder.js +4 -0
  107. package/lib/services/createDownloadStream.js +1 -1
  108. package/lib/services/createFileDownloadURL.js +2 -1
  109. package/lib/services/createSignedURL.js +2 -1
  110. package/lib/services/index.d.ts +14 -1
  111. package/lib/services/index.js +14 -1
  112. package/lib/services/initCartProviders.js +1 -0
  113. package/lib/services/linkFileService.js +1 -1
  114. package/lib/services/removeFiles.js +1 -1
  115. package/lib/services/reserveOrderDiscountsForCheckout.d.ts +5 -0
  116. package/lib/services/reserveOrderDiscountsForCheckout.js +34 -0
  117. package/lib/services/simulateProductDispatching.d.ts +3 -1
  118. package/lib/services/simulateProductDispatching.js +3 -3
  119. package/lib/services/simulateProductInventory.d.ts +3 -1
  120. package/lib/services/simulateProductInventory.js +3 -3
  121. package/lib/services/supportedDeliveryProviders.js +9 -0
  122. package/lib/services/supportedPaymentProviders.js +9 -0
  123. package/lib/services/supportedWarehousingProviders.js +9 -0
  124. package/lib/services/uploadFileFromStream.js +2 -1
  125. package/lib/services/uploadFileFromURL.js +2 -1
  126. package/package.json +26 -24
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # @unchainedshop/core
5
5
 
6
- Core orchestration package for the Unchained Engine. Integrates all core-* modules, provides business services, directors for plugins, and bulk import functionality.
6
+ Core orchestration for the Unchained Engine: domain modules, cross-module services, plugin directors, and bulk import/export.
7
7
 
8
8
  ## Installation
9
9
 
@@ -13,602 +13,148 @@ npm install @unchainedshop/core
13
13
 
14
14
  ## Usage
15
15
 
16
- ```typescript
17
- import { initCore, type UnchainedCore } from '@unchainedshop/core';
18
-
19
- const unchainedCore = await initCore({
20
- db,
21
- migrationRepository,
22
- options: {
23
- // Module-specific options
24
- },
25
- });
26
-
27
- // Access modules
28
- const products = await unchainedCore.modules.products.findProducts({});
29
-
30
- // Use services
31
- const pricing = await unchainedCore.services.orders.pricingSheet(order);
32
-
33
- // Bulk import
34
- await unchainedCore.bulkImporter.prepare('PRODUCT');
35
- ```
36
-
37
- ## API Overview
38
-
39
- ### Initialization
40
-
41
- | Export | Description |
42
- |--------|-------------|
43
- | `initCore` | Initialize the core with all modules and services |
44
- | `getAllAdapters` | Get all registered adapters across all directors |
45
-
46
- ### Modules
47
-
48
- The `modules` object provides access to all core-* module APIs:
49
-
50
- | Module | Description |
51
- |--------|-------------|
52
- | `products` | Product management |
53
- | `assortments` | Category/assortment management |
54
- | `filters` | Product filtering and search |
55
- | `orders` | Order management |
56
- | `users` | User management |
57
- | `payment` | Payment providers |
58
- | `delivery` | Delivery providers |
59
- | `warehousing` | Inventory and stock |
60
- | `enrollments` | Subscriptions |
61
- | `quotations` | Quote management |
62
- | `bookmarks` | User bookmarks |
63
- | `countries` | Country management |
64
- | `currencies` | Currency management |
65
- | `languages` | Language management |
66
- | `files` | File management |
67
- | `events` | Event history |
68
- | `worker` | Background jobs |
69
-
70
- ### Services
71
-
72
- Business logic services that orchestrate multiple modules:
73
-
74
- | Service | Description |
75
- |---------|-------------|
76
- | `orders` | Order pricing, checkout workflows |
77
- | `products` | Product pricing calculations |
78
- | `users` | User-related operations |
79
- | `files` | File operations with adapters |
80
-
81
- ### Directors
82
-
83
- Plugin directors provide extensibility through the Director/Adapter pattern. Each director manages a collection of adapters that implement specific behaviors.
84
-
85
- | Director | Description |
86
- |----------|-------------|
87
- | `PaymentDirector` | Payment processing adapters |
88
- | `DeliveryDirector` | Delivery/shipping adapters |
89
- | `WarehousingDirector` | Inventory and stock adapters |
90
- | `WorkerDirector` | Background job workers |
91
- | `FilterDirector` | Product search and filtering |
92
- | `EnrollmentDirector` | Subscription plan handling |
93
- | `QuotationDirector` | Quote/RFQ processing |
94
- | `ProductPricingDirector` | Product price calculations |
95
- | `OrderPricingDirector` | Order total calculations |
96
- | `DeliveryPricingDirector` | Delivery fee calculations |
97
- | `PaymentPricingDirector` | Payment fee calculations |
98
- | `ProductDiscountDirector` | Product-level discounts |
99
- | `OrderDiscountDirector` | Order-level discounts |
100
- | `MessagingDirector` | Email/notification templates |
101
-
102
- ## Director/Adapter Architecture
103
-
104
- The Unchained Engine uses a Director/Adapter pattern for extensibility. Directors manage collections of adapters, and adapters implement specific behaviors.
105
-
106
- ### Base Classes
16
+ Most applications initialize core through `startPlatform()` from `@unchainedshop/platform`. Infrastructure integrations can initialize it directly with an existing database and migration repository:
107
17
 
108
18
  ```typescript
109
- import { BaseAdapter, BaseDirector } from '@unchainedshop/utils';
110
- ```
111
-
112
- - **BaseDirector**: Factory function that creates a generic director with methods to register, unregister, and retrieve adapters
113
- - **BaseAdapter**: Base implementation providing logging and utility methods for all adapters
114
-
115
- ### Creating a Custom Adapter
116
-
117
- All adapters extend from `BaseAdapter` and must implement:
19
+ import { initCore } from '@unchainedshop/core';
118
20
 
119
- ```typescript
120
- const MyAdapter = {
121
- key: 'my-adapter', // Unique identifier
122
- label: 'My Custom Adapter', // Human-readable label
123
- version: '1.0.0', // Adapter version
124
-
125
- // Adapter-specific methods...
126
- };
127
-
128
- // Register with the appropriate director
129
- SomeDirector.registerAdapter(MyAdapter);
21
+ const core = await initCore({ db, migrationRepository });
22
+ const products = await core.modules.products.findProducts({});
130
23
  ```
131
24
 
132
- ### Payment Director
133
-
134
- Manages payment processing and orchestrates payment adapters.
135
-
136
- ```typescript
137
- import { PaymentDirector, type IPaymentAdapter } from '@unchainedshop/core';
138
-
139
- const MyPaymentAdapter: IPaymentAdapter = {
140
- key: 'my-payment',
141
- label: 'My Payment Gateway',
142
- version: '1.0.0',
25
+ `initCore()` accepts `options` for built-in modules, `modules` containing custom `{ configure }` factories, `services` for custom services, and `bulkImporter`/`bulkExporter` handler configuration. Built-in modules are included automatically. Platform startup additionally initializes plugin modules and lifecycle hooks, accounts, templates, HTTP API, and workers.
143
26
 
144
- typeSupported(type) {
145
- return type === 'CARD';
146
- },
27
+ ## Modules and services
147
28
 
148
- actions(config, context) {
149
- return {
150
- configurationError() { return null; },
151
- isActive() { return true; },
152
- isPayLaterAllowed() { return false; },
153
-
154
- async charge() {
155
- // Process payment charge
156
- return { transactionId: '...' };
157
- },
158
- async confirm() {
159
- // Confirm payment
160
- return { transactionId: '...' };
161
- },
162
- async cancel() {
163
- // Cancel payment
164
- return true;
165
- },
166
- async register() {
167
- // Register payment method
168
- return { token: '...' };
169
- },
170
- async sign() {
171
- // Sign payment request
172
- return '...';
173
- },
174
- async validate(token) {
175
- // Validate payment token
176
- return true;
177
- },
178
- };
179
- },
180
- };
29
+ `core.modules` exposes `products`, `assortments`, `filters`, `orders`, `users`, `payment`, `delivery`, `warehousing`, `enrollments`, `quotations`, `bookmarks`, `countries`, `currencies`, `languages`, `files`, `events`, and `worker`.
181
30
 
182
- PaymentDirector.registerAdapter(MyPaymentAdapter);
183
- ```
31
+ `core.services` coordinates operations across modules, including pricing, checkout, payment, delivery, filtering, files, and enrollment processing. See [module configuration](src/modules.ts) and [service composition](src/services/index.ts) for their current interfaces.
184
32
 
185
- ### Delivery Director
33
+ ## Plugin registration
186
34
 
187
- Manages delivery operations and coordinates shipping adapters.
35
+ Register built-in plugins explicitly before platform startup. Importing a plugin has no registration side effect:
188
36
 
189
37
  ```typescript
190
- import { DeliveryDirector, type IDeliveryAdapter } from '@unchainedshop/core';
191
-
192
- const MyDeliveryAdapter: IDeliveryAdapter = {
193
- key: 'my-delivery',
194
- label: 'My Shipping Provider',
195
- version: '1.0.0',
38
+ import { pluginRegistry } from '@unchainedshop/core';
39
+ import { StripePlugin } from '@unchainedshop/plugins/payment/stripe';
196
40
 
197
- typeSupported(type) {
198
- return type === 'SHIPPING';
199
- },
200
-
201
- actions(config, context) {
202
- return {
203
- configurationError() { return null; },
204
- isActive() { return true; },
205
- isAutoReleaseAllowed() { return false; },
206
-
207
- async send() {
208
- // Trigger delivery
209
- return { trackingNumber: '...' };
210
- },
211
- estimatedDeliveryThroughput(warehousingTime) {
212
- // Return estimated delivery time in ms
213
- return 3 * 24 * 60 * 60 * 1000; // 3 days
214
- },
215
- async pickUpLocations() {
216
- // Return available pickup locations
217
- return [];
218
- },
219
- async pickUpLocationById(locationId) {
220
- return null;
221
- },
222
- };
223
- },
224
- };
225
-
226
- DeliveryDirector.registerAdapter(MyDeliveryAdapter);
41
+ pluginRegistry.register(StripePlugin);
227
42
  ```
228
43
 
229
- ### Warehousing Director
230
-
231
- Manages inventory and stock operations, including NFT/token support.
232
-
233
- ```typescript
234
- import { WarehousingDirector, type IWarehousingAdapter } from '@unchainedshop/core';
235
-
236
- const MyWarehousingAdapter: IWarehousingAdapter = {
237
- key: 'my-warehouse',
238
- label: 'My Inventory System',
239
- version: '1.0.0',
240
-
241
- typeSupported(type) {
242
- return type === 'PHYSICAL';
243
- },
244
-
245
- actions(config, context) {
246
- return {
247
- configurationError() { return null; },
248
- isActive() { return true; },
249
-
250
- async stock(referenceDate) {
251
- // Return current stock quantity
252
- return 100;
253
- },
254
- async productionTime(quantity) {
255
- // Return production time in ms
256
- return 0;
257
- },
258
- async commissioningTime(quantity) {
259
- // Return commissioning time in ms
260
- return 24 * 60 * 60 * 1000; // 1 day
261
- },
262
- async estimatedStock() {
263
- return 100;
264
- },
265
- async estimatedDispatch() {
266
- return new Date();
267
- },
268
- // For tokenized products (NFTs):
269
- async tokenize() { return []; },
270
- async tokenMetadata(serial, date) { return {}; },
271
- async isInvalidateable(serial, date) { return false; },
272
- };
273
- },
274
- };
44
+ Alternatively, call `registerBasePlugins()`, `registerAllPlugins()`, or `registerCryptoPlugins()` from the corresponding `@unchainedshop/plugins/presets/base`, `/all`, or `/crypto` subpath. Package subpaths have no file extension.
275
45
 
276
- WarehousingDirector.registerAdapter(MyWarehousingAdapter);
277
- ```
46
+ Directors resolve adapters from `pluginRegistry` by the `adapterType` symbol provided by each domain's base adapter. `getAllAdapters()` lists the adapters of all registered plugins that were not skipped during startup.
278
47
 
279
- ### Worker Director
48
+ ### Custom adapters
280
49
 
281
- Manages background job processing and scheduled tasks.
50
+ The typed `registerX()` factories both create and register an `IPlugin`. Call them before platform startup:
282
51
 
283
52
  ```typescript
284
- import { WorkerDirector, type IWorkerAdapter } from '@unchainedshop/core';
285
-
286
- interface MyInput { email: string; subject: string; }
287
- interface MyOutput { messageId: string; }
288
-
289
- const MyWorkerAdapter: IWorkerAdapter<MyInput, MyOutput> = {
290
- key: 'my-worker',
291
- label: 'My Background Worker',
292
- version: '1.0.0',
293
- type: 'MY_WORK_TYPE', // Work type identifier
294
- external: false, // Runs in-process
295
- maxParallelAllocations: 10, // Max concurrent executions
296
-
297
- async doWork(input, unchainedAPI, workId) {
298
- // Process the work item
299
- const { email, subject } = input;
300
-
301
- // Return result
302
- return {
303
- success: true,
304
- result: { messageId: 'msg-123' },
305
- };
306
- },
307
- };
308
-
309
- WorkerDirector.registerAdapter(MyWorkerAdapter);
310
-
311
- // Schedule recurring work
312
- WorkerDirector.configureAutoscheduling({
313
- type: 'MY_WORK_TYPE',
314
- input: { email: 'test@example.com', subject: 'Test' },
315
- schedule: '0 * * * *', // Every hour (cron syntax)
53
+ import {
54
+ registerPaymentProvider,
55
+ registerDeliveryProvider,
56
+ registerPhysicalWarehousing,
57
+ registerProductPricing,
58
+ } from '@unchainedshop/core';
59
+
60
+ registerPaymentProvider({
61
+ adapterId: 'manual-payment',
62
+ isPayLaterAllowed: true,
63
+ charge: false,
316
64
  });
317
- ```
318
-
319
- ### Pricing Directors
320
65
 
321
- Pricing directors calculate prices using a chain of adapters. Each adapter can add, modify, or discount prices.
322
-
323
- ```typescript
324
- import { ProductPricingDirector, type IProductPricingAdapter } from '@unchainedshop/core';
325
-
326
- const MyPricingAdapter: IProductPricingAdapter = {
327
- key: 'my-pricing',
328
- label: 'My Pricing Logic',
329
- version: '1.0.0',
330
- orderIndex: 10, // Lower numbers run first
66
+ registerDeliveryProvider({
67
+ adapterId: 'manual-shipping',
68
+ autoReleaseAllowed: false,
69
+ send: true,
70
+ });
331
71
 
332
- isActivatedFor(context) {
333
- // Return true if this adapter should apply
334
- return true;
335
- },
72
+ registerPhysicalWarehousing({
73
+ adapterId: 'local-stock',
74
+ stock: 100,
75
+ commissioningTime: 24 * 60 * 60 * 1000,
76
+ });
336
77
 
337
- actions(params) {
338
- return {
339
- calculate() {
340
- // Add price calculations
341
- this.calculation.addItem({
342
- category: 'BASE',
343
- amount: 1000, // in smallest currency unit
344
- });
345
- },
346
- };
78
+ registerProductPricing({
79
+ adapterId: 'fixed-price',
80
+ orderIndex: 0,
81
+ calculate: async (sheet) => {
82
+ sheet.addItem({ amount: 1000, isTaxable: true, isNetPrice: false });
347
83
  },
348
- };
349
-
350
- ProductPricingDirector.registerAdapter(MyPricingAdapter);
84
+ });
351
85
  ```
352
86
 
353
- ### Discount Directors
87
+ The pricing example supplies a fixed base price in the smallest currency unit. Choose the pricing adapters appropriate to your shop so multiple adapters do not unintentionally add base prices.
354
88
 
355
- Discount directors manage coupon codes and automatic discounts.
89
+ | Concern | Factories |
90
+ |---------|-----------|
91
+ | Payment | `registerPaymentProvider`, `registerInvoicePayment` |
92
+ | Delivery | `registerDeliveryProvider`, `registerShippingDelivery`, `registerPickUpDelivery` |
93
+ | Warehousing | `registerPhysicalWarehousing`, `registerVirtualWarehousing` |
94
+ | Pricing | `registerProductPricing`, `registerOrderPricing`, `registerPaymentPricing`, `registerDeliveryPricing` |
95
+ | Discounts | `registerProductDiscount`, `registerOrderDiscount` |
96
+ | Filtering | `registerProductDiscoverabilityFilter`, `registerProductSearchFilter`, `registerAssortmentSearchFilter` |
97
+ | Files | `registerFileAdapter` |
98
+ | Quotations | `registerQuotation` |
99
+ | Enrollments | `registerEnrollment` |
100
+ | Workers | `registerWorker` |
356
101
 
357
- ```typescript
358
- import { OrderDiscountDirector, type IDiscountAdapter } from '@unchainedshop/core';
102
+ See the [factory implementations](src/factory/index.ts) for typed callback signatures. For capabilities beyond the factories, spread the relevant domain base adapter (for example `PaymentAdapter`) and its `actions()` defaults, then put the adapter in an `IPlugin` and call `pluginRegistry.register(plugin)`. This preserves the adapter's type symbol and required default methods.
359
103
 
360
- const MyDiscountAdapter: IDiscountAdapter = {
361
- key: 'my-discount',
362
- label: 'My Discount System',
363
- version: '1.0.0',
364
- orderIndex: 10,
104
+ ### Workers and recurring schedules
365
105
 
366
- isManualAdditionAllowed(code) {
367
- return code.startsWith('PROMO');
368
- },
369
- isManualRemovalAllowed() {
370
- return true;
371
- },
106
+ ```typescript
107
+ import { registerWorker, schedule, WorkerDirector } from '@unchainedshop/core';
372
108
 
373
- actions(context) {
374
- return {
375
- isValidForSystemTriggering() {
376
- // Auto-apply discount?
377
- return false;
378
- },
379
- isValidForCodeTriggering(code) {
380
- // Apply when code entered?
381
- return code === 'PROMO10';
382
- },
383
- discountForPricingAdapterKey(params) {
384
- // Return discount configuration for pricing adapter
385
- return {
386
- isNetPrice: false,
387
- rate: 0.1, // 10% off
388
- };
389
- },
390
- async reserve(code) {
391
- // Reserve discount (e.g., decrement coupon balance)
392
- },
393
- async release() {
394
- // Release reservation on order cancellation
395
- },
396
- };
109
+ registerWorker<{ message: string }, { logged: boolean }>({
110
+ type: 'LOG_MESSAGE',
111
+ maxParallelAllocations: 1,
112
+ process: async ({ message }) => {
113
+ console.log(message);
114
+ return { logged: true };
397
115
  },
398
- };
116
+ });
399
117
 
400
- OrderDiscountDirector.registerAdapter(MyDiscountAdapter);
118
+ WorkerDirector.configureAutoscheduling({
119
+ type: 'LOG_MESSAGE',
120
+ input: async () => ({ message: 'Hourly check' }),
121
+ schedule: schedule.parse.cron('0 * * * *'),
122
+ });
401
123
  ```
402
124
 
403
- ### Filter Director
404
-
405
- Manages product filtering and search functionality.
406
-
407
- ```typescript
408
- import { FilterDirector, type IFilterAdapter } from '@unchainedshop/core';
409
-
410
- const MyFilterAdapter: IFilterAdapter = {
411
- key: 'my-filter',
412
- label: 'My Search Filter',
413
- version: '1.0.0',
414
- orderIndex: 10,
415
-
416
- actions(context) {
417
- return {
418
- async aggregateProductIds(params) {
419
- // Return product IDs matching filter
420
- return ['product-1', 'product-2'];
421
- },
422
- async searchProducts(params, options) {
423
- // Search products
424
- return { productIds: [], totalCount: 0 };
425
- },
426
- async searchAssortments(params, options) {
427
- // Search assortments
428
- return { assortmentIds: [], totalCount: 0 };
429
- },
430
- transformProductSelector(selector, options) {
431
- // Modify MongoDB product selector
432
- return selector;
433
- },
434
- transformFilterSelector(selector, options) {
435
- // Modify MongoDB filter selector
436
- return selector;
437
- },
438
- transformSortStage(sort, options) {
439
- // Modify MongoDB sort stage
440
- return sort;
441
- },
442
- };
443
- },
444
- };
445
-
446
- FilterDirector.registerAdapter(MyFilterAdapter);
447
- ```
125
+ Autoscheduling accepts parsed `ScheduleData` and an asynchronous input factory. The platform's queue managers enqueue and execute the scheduled work.
448
126
 
449
- ### Messaging Director
127
+ ### Messaging templates
450
128
 
451
- The Messaging Director uses a template resolver pattern instead of traditional adapters.
129
+ Messaging uses template resolvers registered separately from adapters:
452
130
 
453
131
  ```typescript
454
132
  import { MessagingDirector } from '@unchainedshop/core';
455
133
 
456
- // Register a message template
457
- MessagingDirector.registerTemplate('ORDER_CONFIRMATION', async (context) => {
458
- const { order, user } = context;
459
-
460
- return [
461
- {
462
- type: 'EMAIL',
463
- input: {
464
- to: user.email,
465
- subject: `Order Confirmation #${order.orderNumber}`,
466
- html: '<h1>Thank you for your order!</h1>',
467
- },
134
+ MessagingDirector.registerTemplate('CUSTOM_NOTICE', async ({ email }) => [
135
+ {
136
+ type: 'EMAIL',
137
+ input: {
138
+ from: 'shop@example.com',
139
+ to: email,
140
+ subject: 'Shop notice',
141
+ text: 'Your requested notification.',
468
142
  },
469
- {
470
- type: 'SMS',
471
- input: {
472
- to: user.phone,
473
- text: `Order #${order.orderNumber} confirmed!`,
474
- },
475
- },
476
- ];
477
- });
478
- ```
479
-
480
- ### Quotation Director
481
-
482
- Handles quotation/RFQ (Request for Quote) operations.
483
-
484
- ```typescript
485
- import { QuotationDirector, type IQuotationAdapter } from '@unchainedshop/core';
486
-
487
- const MyQuotationAdapter: IQuotationAdapter = {
488
- key: 'my-quotation',
489
- label: 'My Quote System',
490
- version: '1.0.0',
491
-
492
- isActivatedFor(quotationContext, unchainedAPI) {
493
- return true;
494
143
  },
495
-
496
- actions(context) {
497
- return {
498
- configurationError() { return null; },
499
- isManualProposalRequired() { return true; },
500
- isManualRequestVerificationRequired() { return false; },
501
-
502
- async quote() {
503
- // Generate quote
504
- return { price: 1000, currency: 'CHF' };
505
- },
506
- async submitRequest(quotationContext) {
507
- // Submit RFQ
508
- },
509
- async verifyRequest(quotationContext) {
510
- // Verify RFQ
511
- },
512
- async rejectRequest(quotationContext) {
513
- // Reject RFQ
514
- },
515
- transformItemConfiguration(params) {
516
- return params.configuration;
517
- },
518
- };
519
- },
520
- };
521
-
522
- QuotationDirector.registerAdapter(MyQuotationAdapter);
523
- ```
524
-
525
- ### Enrollment Director
526
-
527
- Manages subscription/enrollment plans and recurring billing.
528
-
529
- ```typescript
530
- import { EnrollmentDirector, type IEnrollmentAdapter } from '@unchainedshop/core';
531
-
532
- const MyEnrollmentAdapter: IEnrollmentAdapter = {
533
- key: 'my-enrollment',
534
- label: 'My Subscription System',
535
- version: '1.0.0',
536
-
537
- isActivatedFor(productPlan) {
538
- return productPlan.type === 'PLAN_PRODUCT';
539
- },
540
-
541
- transformOrderItemToEnrollmentPlan(orderPosition, unchainedAPI) {
542
- return {
543
- configuration: orderPosition.configuration,
544
- };
545
- },
546
-
547
- actions(context) {
548
- return {
549
- async nextPeriod() {
550
- // Calculate next billing period
551
- return {
552
- start: new Date(),
553
- end: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
554
- };
555
- },
556
- isValidForActivation() {
557
- return true;
558
- },
559
- isOverdue() {
560
- return false;
561
- },
562
- async configurationForOrder(period) {
563
- // Return order configuration for period
564
- return {};
565
- },
566
- };
567
- },
568
- };
569
-
570
- EnrollmentDirector.registerAdapter(MyEnrollmentAdapter);
144
+ ]);
571
145
  ```
572
146
 
573
- ### Bulk Importer
147
+ Each returned item is work for its registered worker type, such as `EMAIL` or `TWILIO`. Template parameters depend on the caller; they are not automatically populated with order/user documents.
574
148
 
575
- | Method | Description |
576
- |--------|-------------|
577
- | `bulkImporter.prepare` | Prepare bulk import for entity type |
578
- | `bulkImporter.process` | Process prepared import data |
149
+ ## Bulk import and export
579
150
 
580
- ### Types
151
+ `core.bulkImporter.createBulkImporter(options)` creates an import session with `validate(event)`, `prepare(event, core)`, `execute()`, and `invalidateCaches(core)`. Events carry `entity`, `operation`, and `payload`; the built-in entities are `PRODUCT`, `ASSORTMENT`, and `FILTER`.
581
152
 
582
- | Export | Description |
583
- |--------|-------------|
584
- | `UnchainedCore` | Core instance type |
585
- | `UnchainedCoreOptions` | Initialization options |
586
- | `Modules` | All modules type |
587
- | `Services` | All services type |
588
- | `BulkImporter` | Bulk importer type |
153
+ For streams, use `validateEventStream(readStream)` and `pipeEventStream(readStream, importer, core)`, then execute the import and invalidate caches. See the [importer](src/bulk-importer/createBulkImporter.ts) and [exporter](src/bulk-exporter/index.ts) for the full interfaces.
589
154
 
590
- ## Configuration
155
+ ## Types
591
156
 
592
- ```typescript
593
- const core = await initCore({
594
- db,
595
- migrationRepository,
596
- modules: {
597
- // Custom modules
598
- },
599
- services: {
600
- // Custom services
601
- },
602
- bulkImporter: {
603
- handlers: {
604
- // Custom import handlers
605
- },
606
- },
607
- options: {
608
- // Module-specific options
609
- },
610
- });
611
- ```
157
+ The package exports `UnchainedCore`, `UnchainedCoreOptions`, `Services`, `BulkImporter`, `BulkExporter`, and `IPlugin`, along with domain adapter/context and pricing sheet types. Access the composed module type through `UnchainedCore['modules']`.
612
158
 
613
159
  ## License
614
160