@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.
- package/README.md +92 -546
- package/lib/bulk-exporter/createBulkExporter.d.ts +2 -2
- package/lib/bulk-exporter/createBulkExporter.js +1 -1
- package/lib/bulk-exporter/handlers/exportAssortmentsHandler.d.ts +19 -19
- package/lib/bulk-exporter/handlers/exportAssortmentsHandler.js +9 -9
- package/lib/bulk-exporter/handlers/exportFiltersHandler.d.ts +11 -11
- package/lib/bulk-exporter/handlers/exportFiltersHandler.js +5 -5
- package/lib/bulk-exporter/handlers/exportProductsHandler.d.ts +19 -19
- package/lib/bulk-exporter/handlers/exportProductsHandler.js +11 -11
- package/lib/bulk-exporter/handlers/exportUsersHandler.d.ts +17 -17
- package/lib/bulk-exporter/handlers/exportUsersHandler.js +8 -8
- package/lib/bulk-importer/createBulkImporter.d.ts +1 -1
- package/lib/bulk-importer/createBulkImporter.js +6 -6
- package/lib/bulk-importer/handlers/product/create.d.ts +135 -32
- package/lib/bulk-importer/handlers/product/create.js +33 -16
- package/lib/bulk-importer/handlers/product/update.d.ts +63 -33
- package/lib/bulk-importer/handlers/product/update.js +5 -48
- package/lib/core-index.d.ts +4 -2
- package/lib/core-index.js +5 -17
- package/lib/directors/BaseDiscountAdapter.d.ts +3 -0
- package/lib/directors/BaseDiscountDirector.d.ts +2 -2
- package/lib/directors/BaseDiscountDirector.js +12 -14
- package/lib/directors/BasePricingDirector.d.ts +2 -2
- package/lib/directors/BasePricingDirector.js +4 -7
- package/lib/directors/BaseWorker.js +3 -2
- package/lib/directors/DeliveryAdapter.js +1 -0
- package/lib/directors/DeliveryDirector.d.ts +1 -1
- package/lib/directors/DeliveryDirector.js +4 -5
- package/lib/directors/DeliveryPricingAdapter.d.ts +2 -1
- package/lib/directors/DeliveryPricingAdapter.js +2 -1
- package/lib/directors/DeliveryPricingDirector.d.ts +1 -1
- package/lib/directors/DeliveryPricingDirector.js +4 -3
- package/lib/directors/DeliveryPricingSheet.d.ts +1 -1
- package/lib/directors/DeliveryPricingSheet.js +1 -1
- package/lib/directors/EnrollmentAdapter.js +1 -1
- package/lib/directors/EnrollmentDirector.d.ts +1 -1
- package/lib/directors/EnrollmentDirector.js +5 -7
- package/lib/directors/FileDirector.d.ts +4 -4
- package/lib/directors/FileDirector.js +2 -13
- package/lib/directors/FilterAdapter.js +1 -0
- package/lib/directors/FilterDirector.d.ts +1 -1
- package/lib/directors/FilterDirector.js +6 -8
- package/lib/directors/OrderDiscountAdapter.d.ts +3 -2
- package/lib/directors/OrderDiscountAdapter.js +5 -2
- package/lib/directors/OrderDiscountDirector.js +2 -1
- package/lib/directors/OrderPricingAdapter.d.ts +2 -1
- package/lib/directors/OrderPricingAdapter.js +3 -1
- package/lib/directors/OrderPricingDirector.d.ts +4 -1
- package/lib/directors/OrderPricingDirector.js +4 -2
- package/lib/directors/OrderPricingSheet.d.ts +2 -1
- package/lib/directors/OrderPricingSheet.js +18 -18
- package/lib/directors/PaymentAdapter.js +1 -0
- package/lib/directors/PaymentDirector.d.ts +1 -1
- package/lib/directors/PaymentDirector.js +4 -5
- package/lib/directors/PaymentPricingAdapter.d.ts +2 -1
- package/lib/directors/PaymentPricingAdapter.js +2 -1
- package/lib/directors/PaymentPricingDirector.d.ts +2 -1
- package/lib/directors/PaymentPricingDirector.js +3 -2
- package/lib/directors/PaymentPricingSheet.d.ts +2 -1
- package/lib/directors/PaymentPricingSheet.js +2 -1
- package/lib/directors/ProductDiscountAdapter.d.ts +3 -2
- package/lib/directors/ProductDiscountAdapter.js +5 -2
- package/lib/directors/ProductDiscountDirector.d.ts +1 -1
- package/lib/directors/ProductDiscountDirector.js +3 -2
- package/lib/directors/ProductPricingAdapter.d.ts +2 -1
- package/lib/directors/ProductPricingAdapter.js +3 -1
- package/lib/directors/ProductPricingDirector.d.ts +3 -1
- package/lib/directors/ProductPricingDirector.js +4 -2
- package/lib/directors/ProductPricingSheet.d.ts +1 -1
- package/lib/directors/ProductPricingSheet.js +1 -1
- package/lib/directors/QuotationAdapter.js +1 -0
- package/lib/directors/QuotationDirector.d.ts +1 -1
- package/lib/directors/QuotationDirector.js +4 -7
- package/lib/directors/WarehousingAdapter.js +1 -0
- package/lib/directors/WarehousingDirector.d.ts +1 -1
- package/lib/directors/WarehousingDirector.js +19 -27
- package/lib/directors/WorkerAdapter.js +1 -0
- package/lib/directors/WorkerDirector.d.ts +2 -2
- package/lib/directors/WorkerDirector.js +3 -22
- package/lib/directors/index.d.ts +2 -0
- package/lib/directors/index.js +2 -0
- package/lib/directors/registryDirector.d.ts +2 -0
- package/lib/directors/registryDirector.js +6 -0
- package/lib/factory/index.d.ts +12 -1
- package/lib/factory/index.js +12 -1
- package/lib/factory/registerAssortmentSearchFilter.d.ts +4 -2
- package/lib/factory/registerAssortmentSearchFilter.js +18 -6
- package/lib/factory/registerInvoicePayment.d.ts +2 -2
- package/lib/factory/registerInvoicePayment.js +12 -3
- package/lib/factory/registerPhysicalWarehousing.d.ts +2 -2
- package/lib/factory/registerPhysicalWarehousing.js +12 -3
- package/lib/factory/registerPickUpDelivery.d.ts +2 -2
- package/lib/factory/registerPickUpDelivery.js +12 -3
- package/lib/factory/registerProductDiscoverabilityFilter.d.ts +4 -2
- package/lib/factory/registerProductDiscoverabilityFilter.js +18 -6
- package/lib/factory/registerProductSearchFilter.d.ts +4 -2
- package/lib/factory/registerProductSearchFilter.js +16 -6
- package/lib/factory/registerShippingDelivery.d.ts +2 -2
- package/lib/factory/registerShippingDelivery.js +12 -3
- package/lib/factory/registerVirtualWarehousing.d.ts +2 -2
- package/lib/factory/registerVirtualWarehousing.js +13 -4
- package/lib/factory/registerWorker.d.ts +2 -1
- package/lib/factory/registerWorker.js +13 -4
- package/lib/plugins/PluginRegistry.d.ts +1 -0
- package/lib/plugins/PluginRegistry.js +8 -1
- package/lib/services/checkoutOrder.js +4 -0
- package/lib/services/createDownloadStream.js +1 -1
- package/lib/services/createFileDownloadURL.js +2 -1
- package/lib/services/createSignedURL.js +2 -1
- package/lib/services/index.d.ts +14 -1
- package/lib/services/index.js +14 -1
- package/lib/services/initCartProviders.js +1 -0
- package/lib/services/linkFileService.js +1 -1
- package/lib/services/removeFiles.js +1 -1
- package/lib/services/reserveOrderDiscountsForCheckout.d.ts +5 -0
- package/lib/services/reserveOrderDiscountsForCheckout.js +34 -0
- package/lib/services/simulateProductDispatching.d.ts +3 -1
- package/lib/services/simulateProductDispatching.js +3 -3
- package/lib/services/simulateProductInventory.d.ts +3 -1
- package/lib/services/simulateProductInventory.js +3 -3
- package/lib/services/supportedDeliveryProviders.js +9 -0
- package/lib/services/supportedPaymentProviders.js +9 -0
- package/lib/services/supportedWarehousingProviders.js +9 -0
- package/lib/services/uploadFileFromStream.js +2 -1
- package/lib/services/uploadFileFromURL.js +2 -1
- package/package.json +26 -24
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# @unchainedshop/core
|
|
5
5
|
|
|
6
|
-
Core orchestration
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
120
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
145
|
-
return type === 'CARD';
|
|
146
|
-
},
|
|
27
|
+
## Modules and services
|
|
147
28
|
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
+
## Plugin registration
|
|
186
34
|
|
|
187
|
-
|
|
35
|
+
Register built-in plugins explicitly before platform startup. Importing a plugin has no registration side effect:
|
|
188
36
|
|
|
189
37
|
```typescript
|
|
190
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
48
|
+
### Custom adapters
|
|
280
49
|
|
|
281
|
-
|
|
50
|
+
The typed `registerX()` factories both create and register an `IPlugin`. Call them before platform startup:
|
|
282
51
|
|
|
283
52
|
```typescript
|
|
284
|
-
import {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
72
|
+
registerPhysicalWarehousing({
|
|
73
|
+
adapterId: 'local-stock',
|
|
74
|
+
stock: 100,
|
|
75
|
+
commissioningTime: 24 * 60 * 60 * 1000,
|
|
76
|
+
});
|
|
336
77
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
367
|
-
|
|
368
|
-
},
|
|
369
|
-
isManualRemovalAllowed() {
|
|
370
|
-
return true;
|
|
371
|
-
},
|
|
106
|
+
```typescript
|
|
107
|
+
import { registerWorker, schedule, WorkerDirector } from '@unchainedshop/core';
|
|
372
108
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
127
|
+
### Messaging templates
|
|
450
128
|
|
|
451
|
-
|
|
129
|
+
Messaging uses template resolvers registered separately from adapters:
|
|
452
130
|
|
|
453
131
|
```typescript
|
|
454
132
|
import { MessagingDirector } from '@unchainedshop/core';
|
|
455
133
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
155
|
+
## Types
|
|
591
156
|
|
|
592
|
-
|
|
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
|
|