@legible-sync/example-eda 1.2.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 (118) hide show
  1. package/.eslintrc.js +16 -0
  2. package/README.md +103 -0
  3. package/__tests__/integration/ecommerce-flow.test.ts +247 -0
  4. package/__tests__/unit/EventBus.test.ts +154 -0
  5. package/__tests__/unit/PluginManager.test.ts +111 -0
  6. package/__tests__/unit/concepts/User.test.ts +130 -0
  7. package/dist/core/EventBus.d.ts +16 -0
  8. package/dist/core/EventBus.d.ts.map +1 -0
  9. package/dist/core/EventBus.js +44 -0
  10. package/dist/core/EventBus.js.map +1 -0
  11. package/dist/core/PluginManager.d.ts +16 -0
  12. package/dist/core/PluginManager.d.ts.map +1 -0
  13. package/dist/core/PluginManager.js +37 -0
  14. package/dist/core/PluginManager.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +145 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/plugins/analytics/concepts/Analytics.d.ts +3 -0
  20. package/dist/plugins/analytics/concepts/Analytics.d.ts.map +1 -0
  21. package/dist/plugins/analytics/concepts/Analytics.js +43 -0
  22. package/dist/plugins/analytics/concepts/Analytics.js.map +1 -0
  23. package/dist/plugins/analytics/index.d.ts +3 -0
  24. package/dist/plugins/analytics/index.d.ts.map +1 -0
  25. package/dist/plugins/analytics/index.js +16 -0
  26. package/dist/plugins/analytics/index.js.map +1 -0
  27. package/dist/plugins/analytics/syncs/analytics-events.sync.d.ts +3 -0
  28. package/dist/plugins/analytics/syncs/analytics-events.sync.d.ts.map +1 -0
  29. package/dist/plugins/analytics/syncs/analytics-events.sync.js +101 -0
  30. package/dist/plugins/analytics/syncs/analytics-events.sync.js.map +1 -0
  31. package/dist/plugins/inventory/concepts/Inventory.d.ts +3 -0
  32. package/dist/plugins/inventory/concepts/Inventory.d.ts.map +1 -0
  33. package/dist/plugins/inventory/concepts/Inventory.js +60 -0
  34. package/dist/plugins/inventory/concepts/Inventory.js.map +1 -0
  35. package/dist/plugins/inventory/index.d.ts +3 -0
  36. package/dist/plugins/inventory/index.d.ts.map +1 -0
  37. package/dist/plugins/inventory/index.js +15 -0
  38. package/dist/plugins/inventory/index.js.map +1 -0
  39. package/dist/plugins/notifications/concepts/Notification.d.ts +3 -0
  40. package/dist/plugins/notifications/concepts/Notification.d.ts.map +1 -0
  41. package/dist/plugins/notifications/concepts/Notification.js +42 -0
  42. package/dist/plugins/notifications/concepts/Notification.js.map +1 -0
  43. package/dist/plugins/notifications/index.d.ts +3 -0
  44. package/dist/plugins/notifications/index.d.ts.map +1 -0
  45. package/dist/plugins/notifications/index.js +15 -0
  46. package/dist/plugins/notifications/index.js.map +1 -0
  47. package/dist/plugins/orders/concepts/Order.d.ts +3 -0
  48. package/dist/plugins/orders/concepts/Order.d.ts.map +1 -0
  49. package/dist/plugins/orders/concepts/Order.js +98 -0
  50. package/dist/plugins/orders/concepts/Order.js.map +1 -0
  51. package/dist/plugins/orders/index.d.ts +3 -0
  52. package/dist/plugins/orders/index.d.ts.map +1 -0
  53. package/dist/plugins/orders/index.js +16 -0
  54. package/dist/plugins/orders/index.js.map +1 -0
  55. package/dist/plugins/orders/syncs/order-workflow.sync.d.ts +3 -0
  56. package/dist/plugins/orders/syncs/order-workflow.sync.d.ts.map +1 -0
  57. package/dist/plugins/orders/syncs/order-workflow.sync.js +168 -0
  58. package/dist/plugins/orders/syncs/order-workflow.sync.js.map +1 -0
  59. package/dist/plugins/payments/concepts/Payment.d.ts +3 -0
  60. package/dist/plugins/payments/concepts/Payment.d.ts.map +1 -0
  61. package/dist/plugins/payments/concepts/Payment.js +156 -0
  62. package/dist/plugins/payments/concepts/Payment.js.map +1 -0
  63. package/dist/plugins/payments/index.d.ts +3 -0
  64. package/dist/plugins/payments/index.d.ts.map +1 -0
  65. package/dist/plugins/payments/index.js +16 -0
  66. package/dist/plugins/payments/index.js.map +1 -0
  67. package/dist/plugins/payments/syncs/payment-workflow.sync.d.ts +3 -0
  68. package/dist/plugins/payments/syncs/payment-workflow.sync.d.ts.map +1 -0
  69. package/dist/plugins/payments/syncs/payment-workflow.sync.js +264 -0
  70. package/dist/plugins/payments/syncs/payment-workflow.sync.js.map +1 -0
  71. package/dist/plugins/products/concepts/Product.d.ts +3 -0
  72. package/dist/plugins/products/concepts/Product.d.ts.map +1 -0
  73. package/dist/plugins/products/concepts/Product.js +85 -0
  74. package/dist/plugins/products/concepts/Product.js.map +1 -0
  75. package/dist/plugins/products/index.d.ts +3 -0
  76. package/dist/plugins/products/index.d.ts.map +1 -0
  77. package/dist/plugins/products/index.js +16 -0
  78. package/dist/plugins/products/index.js.map +1 -0
  79. package/dist/plugins/products/syncs/product-events.sync.d.ts +3 -0
  80. package/dist/plugins/products/syncs/product-events.sync.d.ts.map +1 -0
  81. package/dist/plugins/products/syncs/product-events.sync.js +77 -0
  82. package/dist/plugins/products/syncs/product-events.sync.js.map +1 -0
  83. package/dist/plugins/users/concepts/User.d.ts +3 -0
  84. package/dist/plugins/users/concepts/User.d.ts.map +1 -0
  85. package/dist/plugins/users/concepts/User.js +81 -0
  86. package/dist/plugins/users/concepts/User.js.map +1 -0
  87. package/dist/plugins/users/index.d.ts +3 -0
  88. package/dist/plugins/users/index.d.ts.map +1 -0
  89. package/dist/plugins/users/index.js +16 -0
  90. package/dist/plugins/users/index.js.map +1 -0
  91. package/dist/plugins/users/syncs/user-events.sync.d.ts +3 -0
  92. package/dist/plugins/users/syncs/user-events.sync.d.ts.map +1 -0
  93. package/dist/plugins/users/syncs/user-events.sync.js +75 -0
  94. package/dist/plugins/users/syncs/user-events.sync.js.map +1 -0
  95. package/package.json +40 -0
  96. package/src/core/EventBus.ts +55 -0
  97. package/src/core/PluginManager.ts +51 -0
  98. package/src/index.ts +169 -0
  99. package/src/plugins/analytics/concepts/Analytics.ts +53 -0
  100. package/src/plugins/analytics/index.ts +15 -0
  101. package/src/plugins/analytics/syncs/analytics-events.sync.ts +103 -0
  102. package/src/plugins/inventory/concepts/Inventory.ts +73 -0
  103. package/src/plugins/inventory/index.ts +14 -0
  104. package/src/plugins/notifications/concepts/Notification.ts +49 -0
  105. package/src/plugins/notifications/index.ts +14 -0
  106. package/src/plugins/orders/concepts/Order.ts +118 -0
  107. package/src/plugins/orders/index.ts +15 -0
  108. package/src/plugins/orders/syncs/order-workflow.sync.ts +173 -0
  109. package/src/plugins/payments/concepts/Payment.ts +186 -0
  110. package/src/plugins/payments/index.ts +15 -0
  111. package/src/plugins/payments/syncs/payment-workflow.sync.ts +274 -0
  112. package/src/plugins/products/concepts/Product.ts +102 -0
  113. package/src/plugins/products/index.ts +15 -0
  114. package/src/plugins/products/syncs/product-events.sync.ts +78 -0
  115. package/src/plugins/users/concepts/User.ts +97 -0
  116. package/src/plugins/users/index.ts +15 -0
  117. package/src/plugins/users/syncs/user-events.sync.ts +76 -0
  118. package/tsconfig.json +9 -0
@@ -0,0 +1,186 @@
1
+ // plugins/payments/concepts/Payment.ts
2
+ import { Concept } from '@legible-sync/core';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+
5
+ export const Payment: Concept = {
6
+ state: {
7
+ payments: new Map<string, any>(),
8
+ transactions: new Map<string, any>(),
9
+ },
10
+
11
+ async execute(action: string, input: any) {
12
+ const state = this.state;
13
+
14
+ switch (action) {
15
+ case 'initiate': {
16
+ const { orderId, amount, method } = input;
17
+
18
+ // Validation
19
+ if (!orderId || !amount || amount <= 0) {
20
+ throw new Error('Order ID and positive amount are required');
21
+ }
22
+
23
+ // Create payment
24
+ const paymentId = uuidv4();
25
+ const payment = {
26
+ id: paymentId,
27
+ orderId,
28
+ amount,
29
+ method: method || 'credit_card',
30
+ status: 'pending',
31
+ createdAt: new Date(),
32
+ transactions: []
33
+ };
34
+
35
+ state.payments.set(paymentId, payment);
36
+
37
+ return { paymentId, payment };
38
+ }
39
+
40
+ case 'process': {
41
+ const { paymentId } = input;
42
+ const payment = state.payments.get(paymentId);
43
+ if (!payment) {
44
+ throw new Error('Payment not found');
45
+ }
46
+
47
+ if (payment.status !== 'pending') {
48
+ throw new Error('Payment is not in pending status');
49
+ }
50
+
51
+ // Simulate payment processing (in real app, integrate with payment gateway)
52
+ const transactionId = uuidv4();
53
+ const transaction = {
54
+ id: transactionId,
55
+ paymentId,
56
+ type: 'charge',
57
+ amount: payment.amount,
58
+ status: 'processing',
59
+ gatewayResponse: 'Processing payment...',
60
+ createdAt: new Date()
61
+ };
62
+
63
+ state.transactions.set(transactionId, transaction);
64
+ payment.transactions.push(transactionId);
65
+ payment.status = 'processing';
66
+ state.payments.set(paymentId, payment);
67
+
68
+ return { payment, transaction };
69
+ }
70
+
71
+ case 'confirm': {
72
+ const { paymentId, transactionId } = input;
73
+ const payment = state.payments.get(paymentId);
74
+ const transaction = state.transactions.get(transactionId);
75
+
76
+ if (!payment || !transaction) {
77
+ throw new Error('Payment or transaction not found');
78
+ }
79
+
80
+ if (payment.status !== 'processing') {
81
+ throw new Error('Payment is not in processing status');
82
+ }
83
+
84
+ // Confirm payment
85
+ payment.status = 'completed';
86
+ payment.completedAt = new Date();
87
+ transaction.status = 'completed';
88
+ transaction.gatewayResponse = 'Payment successful';
89
+ transaction.completedAt = new Date();
90
+
91
+ state.payments.set(paymentId, payment);
92
+ state.transactions.set(transactionId, transaction);
93
+
94
+ return { payment, transaction };
95
+ }
96
+
97
+ case 'fail': {
98
+ const { paymentId, reason } = input;
99
+ const payment = state.payments.get(paymentId);
100
+ if (!payment) {
101
+ throw new Error('Payment not found');
102
+ }
103
+
104
+ payment.status = 'failed';
105
+ payment.failedAt = new Date();
106
+ payment.failureReason = reason;
107
+ state.payments.set(paymentId, payment);
108
+
109
+ // Mark any pending transactions as failed
110
+ for (const txId of payment.transactions) {
111
+ const tx = state.transactions.get(txId);
112
+ if (tx && tx.status === 'processing') {
113
+ tx.status = 'failed';
114
+ tx.gatewayResponse = reason;
115
+ state.transactions.set(txId, tx);
116
+ }
117
+ }
118
+
119
+ return { payment };
120
+ }
121
+
122
+ case 'refund': {
123
+ const { paymentId, amount, reason } = input;
124
+ const payment = state.payments.get(paymentId);
125
+ if (!payment) {
126
+ throw new Error('Payment not found');
127
+ }
128
+
129
+ if (payment.status !== 'completed') {
130
+ throw new Error('Can only refund completed payments');
131
+ }
132
+
133
+ const refundAmount = amount || payment.amount;
134
+ if (refundAmount > payment.amount) {
135
+ throw new Error('Refund amount cannot exceed payment amount');
136
+ }
137
+
138
+ // Create refund transaction
139
+ const transactionId = uuidv4();
140
+ const transaction = {
141
+ id: transactionId,
142
+ paymentId,
143
+ type: 'refund',
144
+ amount: refundAmount,
145
+ status: 'completed',
146
+ gatewayResponse: 'Refund processed',
147
+ reason,
148
+ createdAt: new Date(),
149
+ completedAt: new Date()
150
+ };
151
+
152
+ state.transactions.set(transactionId, transaction);
153
+ payment.transactions.push(transactionId);
154
+ payment.status = refundAmount === payment.amount ? 'refunded' : 'partially_refunded';
155
+ state.payments.set(paymentId, payment);
156
+
157
+ return { payment, transaction };
158
+ }
159
+
160
+ case 'get': {
161
+ const { paymentId } = input;
162
+ const payment = state.payments.get(paymentId);
163
+ if (!payment) {
164
+ throw new Error('Payment not found');
165
+ }
166
+
167
+ const transactions = payment.transactions.map((txId: string) => state.transactions.get(txId));
168
+ return { payment: { ...payment, transactions } };
169
+ }
170
+
171
+ case 'getByOrderId': {
172
+ const { orderId } = input;
173
+ for (const [paymentId, payment] of state.payments) {
174
+ if (payment.orderId === orderId) {
175
+ const transactions = payment.transactions.map((txId: string) => state.transactions.get(txId));
176
+ return { payment: { ...payment, transactions }, paymentId };
177
+ }
178
+ }
179
+ throw new Error('Payment not found for order');
180
+ }
181
+
182
+ default:
183
+ throw new Error(`Unknown action: ${action}`);
184
+ }
185
+ }
186
+ };
@@ -0,0 +1,15 @@
1
+ // plugins/payments/index.ts
2
+ import { Plugin } from '../../core/PluginManager';
3
+ import { Payment } from './concepts/Payment';
4
+ import { paymentWorkflowSyncs } from './syncs/payment-workflow.sync';
5
+
6
+ export const paymentsPlugin: Plugin = {
7
+ name: 'payments',
8
+ concepts: {
9
+ Payment
10
+ },
11
+ syncs: paymentWorkflowSyncs,
12
+ initialize: async (_engine) => {
13
+ console.log('💳 Payments plugin initialized');
14
+ }
15
+ };
@@ -0,0 +1,274 @@
1
+ // plugins/payments/syncs/payment-workflow.sync.ts
2
+ import { SyncRule } from '@legible-sync/core';
3
+
4
+ export const paymentWorkflowSyncs: SyncRule[] = [
5
+ // When order is confirmed, initiate payment
6
+ {
7
+ name: "InitiatePaymentOnOrderConfirm",
8
+ when: [
9
+ {
10
+ concept: "Order",
11
+ action: "confirm"
12
+ }
13
+ ],
14
+ then: [
15
+ {
16
+ concept: "Payment",
17
+ action: "initiate",
18
+ input: {
19
+ orderId: "?orderId",
20
+ amount: "?order.total",
21
+ method: "credit_card"
22
+ }
23
+ }
24
+ ]
25
+ },
26
+
27
+ // When payment is initiated, automatically process it
28
+ {
29
+ name: "AutoProcessPayment",
30
+ when: [
31
+ {
32
+ concept: "Payment",
33
+ action: "initiate"
34
+ }
35
+ ],
36
+ then: [
37
+ {
38
+ concept: "Payment",
39
+ action: "process",
40
+ input: {
41
+ paymentId: "?paymentId"
42
+ }
43
+ }
44
+ ]
45
+ },
46
+
47
+ // When payment processing starts, confirm it (simplified for demo)
48
+ {
49
+ name: "AutoConfirmPayment",
50
+ when: [
51
+ {
52
+ concept: "Payment",
53
+ action: "process"
54
+ }
55
+ ],
56
+ then: [
57
+ {
58
+ concept: "Payment",
59
+ action: "confirm",
60
+ input: {
61
+ paymentId: "?paymentId",
62
+ transactionId: "?transaction.id"
63
+ }
64
+ }
65
+ ]
66
+ },
67
+
68
+ // When payment is confirmed, get order details first
69
+ {
70
+ name: "GetOrderDetailsAfterPaymentConfirm",
71
+ when: [
72
+ {
73
+ concept: "Payment",
74
+ action: "confirm"
75
+ }
76
+ ],
77
+ then: [
78
+ {
79
+ concept: "Order",
80
+ action: "get",
81
+ input: {
82
+ orderId: "?payment.orderId"
83
+ }
84
+ }
85
+ ]
86
+ },
87
+
88
+ // When order details are retrieved after payment confirmation, get user details
89
+ {
90
+ name: "GetUserDetailsAfterPaymentConfirm",
91
+ when: [
92
+ {
93
+ concept: "Order",
94
+ action: "get"
95
+ }
96
+ ],
97
+ then: [
98
+ {
99
+ concept: "User",
100
+ action: "get",
101
+ input: {
102
+ userId: "?order.userId"
103
+ }
104
+ }
105
+ ]
106
+ },
107
+
108
+ // When user details are retrieved after payment confirmation, send notification
109
+ {
110
+ name: "SendPaymentSuccessNotification",
111
+ when: [
112
+ {
113
+ concept: "User",
114
+ action: "get"
115
+ }
116
+ ],
117
+ then: [
118
+ {
119
+ concept: "Notification",
120
+ action: "send",
121
+ input: {
122
+ type: "email",
123
+ to: "?user.email",
124
+ template: "payment-success",
125
+ data: {
126
+ orderId: "?payment.orderId",
127
+ amount: "?payment.amount",
128
+ paymentId: "?paymentId"
129
+ }
130
+ }
131
+ }
132
+ ]
133
+ },
134
+
135
+ // When payment fails, get order details first
136
+ {
137
+ name: "GetOrderDetailsAfterPaymentFail",
138
+ when: [
139
+ {
140
+ concept: "Payment",
141
+ action: "fail"
142
+ }
143
+ ],
144
+ then: [
145
+ {
146
+ concept: "Order",
147
+ action: "get",
148
+ input: {
149
+ orderId: "?payment.orderId"
150
+ }
151
+ },
152
+ {
153
+ concept: "Order",
154
+ action: "cancel",
155
+ input: {
156
+ orderId: "?payment.orderId"
157
+ }
158
+ }
159
+ ]
160
+ },
161
+
162
+ // When order details are retrieved after payment failure, get user details
163
+ {
164
+ name: "GetUserDetailsAfterPaymentFail",
165
+ when: [
166
+ {
167
+ concept: "Order",
168
+ action: "get"
169
+ }
170
+ ],
171
+ then: [
172
+ {
173
+ concept: "User",
174
+ action: "get",
175
+ input: {
176
+ userId: "?order.userId"
177
+ }
178
+ }
179
+ ]
180
+ },
181
+
182
+ // When user details are retrieved after payment failure, send notification
183
+ {
184
+ name: "SendPaymentFailureNotification",
185
+ when: [
186
+ {
187
+ concept: "User",
188
+ action: "get"
189
+ }
190
+ ],
191
+ then: [
192
+ {
193
+ concept: "Notification",
194
+ action: "send",
195
+ input: {
196
+ type: "email",
197
+ to: "?user.email",
198
+ template: "payment-failed",
199
+ data: {
200
+ orderId: "?payment.orderId",
201
+ reason: "?payment.failureReason"
202
+ }
203
+ }
204
+ }
205
+ ]
206
+ },
207
+
208
+ // When refund is processed, get order details first
209
+ {
210
+ name: "GetOrderDetailsAfterRefund",
211
+ when: [
212
+ {
213
+ concept: "Payment",
214
+ action: "refund"
215
+ }
216
+ ],
217
+ then: [
218
+ {
219
+ concept: "Order",
220
+ action: "get",
221
+ input: {
222
+ orderId: "?payment.orderId"
223
+ }
224
+ }
225
+ ]
226
+ },
227
+
228
+ // When order details are retrieved after refund, get user details
229
+ {
230
+ name: "GetUserDetailsAfterRefund",
231
+ when: [
232
+ {
233
+ concept: "Order",
234
+ action: "get"
235
+ }
236
+ ],
237
+ then: [
238
+ {
239
+ concept: "User",
240
+ action: "get",
241
+ input: {
242
+ userId: "?order.userId"
243
+ }
244
+ }
245
+ ]
246
+ },
247
+
248
+ // When user details are retrieved after refund, send notification
249
+ {
250
+ name: "SendRefundNotification",
251
+ when: [
252
+ {
253
+ concept: "User",
254
+ action: "get"
255
+ }
256
+ ],
257
+ then: [
258
+ {
259
+ concept: "Notification",
260
+ action: "send",
261
+ input: {
262
+ type: "email",
263
+ to: "?user.email",
264
+ template: "payment-refund",
265
+ data: {
266
+ orderId: "?payment.orderId",
267
+ amount: "?transaction.amount",
268
+ reason: "?transaction.reason"
269
+ }
270
+ }
271
+ }
272
+ ]
273
+ }
274
+ ];
@@ -0,0 +1,102 @@
1
+ // plugins/products/concepts/Product.ts
2
+ import { Concept } from '@legible-sync/core';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+
5
+ export const Product: Concept = {
6
+ state: {
7
+ products: new Map<string, any>(),
8
+ skus: new Set<string>(),
9
+ },
10
+
11
+ async execute(action: string, input: any) {
12
+ const state = this.state;
13
+
14
+ switch (action) {
15
+ case 'create': {
16
+ const { name, sku, price, description, category } = input;
17
+
18
+ // Validation
19
+ if (!name || !sku || price === undefined) {
20
+ throw new Error('Name, SKU, and price are required');
21
+ }
22
+
23
+ if (state.skus.has(sku)) {
24
+ throw new Error('SKU already exists');
25
+ }
26
+
27
+ // Create product
28
+ const productId = uuidv4();
29
+ const product = {
30
+ id: productId,
31
+ name,
32
+ sku,
33
+ price: Number(price),
34
+ description: description || '',
35
+ category: category || 'general',
36
+ status: 'active',
37
+ createdAt: new Date()
38
+ };
39
+
40
+ state.products.set(productId, product);
41
+ state.skus.add(sku);
42
+
43
+ return { productId, product };
44
+ }
45
+
46
+ case 'get': {
47
+ const { productId } = input;
48
+ const product = state.products.get(productId);
49
+ if (!product) {
50
+ throw new Error('Product not found');
51
+ }
52
+ return { product };
53
+ }
54
+
55
+ case 'update': {
56
+ const { productId, updates } = input;
57
+ const product = state.products.get(productId);
58
+ if (!product) {
59
+ throw new Error('Product not found');
60
+ }
61
+
62
+ // Update product
63
+ const updatedProduct = { ...product, ...updates, updatedAt: new Date() };
64
+ state.products.set(productId, updatedProduct);
65
+
66
+ return { product: updatedProduct };
67
+ }
68
+
69
+ case 'deactivate': {
70
+ const { productId } = input;
71
+ const product = state.products.get(productId);
72
+ if (!product) {
73
+ throw new Error('Product not found');
74
+ }
75
+
76
+ product.status = 'inactive';
77
+ product.deactivatedAt = new Date();
78
+ state.products.set(productId, product);
79
+
80
+ return { product };
81
+ }
82
+
83
+ case 'list': {
84
+ const { category, status = 'active' } = input;
85
+ const products = Array.from(state.products.values())
86
+ .filter((p: any) => p.status === status)
87
+ .filter((p: any) => !category || p.category === category);
88
+
89
+ return { products };
90
+ }
91
+
92
+ case 'reset': {
93
+ state.products.clear();
94
+ state.skus.clear();
95
+ return { reset: true };
96
+ }
97
+
98
+ default:
99
+ throw new Error(`Unknown action: ${action}`);
100
+ }
101
+ }
102
+ };
@@ -0,0 +1,15 @@
1
+ // plugins/products/index.ts
2
+ import { Plugin } from '../../core/PluginManager';
3
+ import { Product } from './concepts/Product';
4
+ import { productEventSyncs } from './syncs/product-events.sync';
5
+
6
+ export const productsPlugin: Plugin = {
7
+ name: 'products',
8
+ concepts: {
9
+ Product
10
+ },
11
+ syncs: productEventSyncs,
12
+ initialize: async (_engine) => {
13
+ console.log('📦 Products plugin initialized');
14
+ }
15
+ };
@@ -0,0 +1,78 @@
1
+ // plugins/products/syncs/product-events.sync.ts
2
+ import { SyncRule } from '@legible-sync/core';
3
+
4
+ export const productEventSyncs: SyncRule[] = [
5
+ // When a product is created, publish product.created event
6
+ {
7
+ name: "PublishProductCreatedEvent",
8
+ when: [
9
+ {
10
+ concept: "Product",
11
+ action: "create"
12
+ }
13
+ ],
14
+ then: [
15
+ {
16
+ concept: "EventBus",
17
+ action: "publish",
18
+ input: {
19
+ event: "product.created",
20
+ data: {
21
+ productId: "?productId",
22
+ name: "?product.name",
23
+ sku: "?product.sku",
24
+ price: "?product.price",
25
+ category: "?product.category"
26
+ }
27
+ }
28
+ }
29
+ ]
30
+ },
31
+
32
+ // When a product is updated, publish product.updated event
33
+ {
34
+ name: "PublishProductUpdatedEvent",
35
+ when: [
36
+ {
37
+ concept: "Product",
38
+ action: "update"
39
+ }
40
+ ],
41
+ then: [
42
+ {
43
+ concept: "EventBus",
44
+ action: "publish",
45
+ input: {
46
+ event: "product.updated",
47
+ data: {
48
+ productId: "?productId",
49
+ updates: "?updates"
50
+ }
51
+ }
52
+ }
53
+ ]
54
+ },
55
+
56
+ // When a product is deactivated, publish product.deactivated event
57
+ {
58
+ name: "PublishProductDeactivatedEvent",
59
+ when: [
60
+ {
61
+ concept: "Product",
62
+ action: "deactivate"
63
+ }
64
+ ],
65
+ then: [
66
+ {
67
+ concept: "EventBus",
68
+ action: "publish",
69
+ input: {
70
+ event: "product.deactivated",
71
+ data: {
72
+ productId: "?productId"
73
+ }
74
+ }
75
+ }
76
+ ]
77
+ }
78
+ ];