@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,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.productEventSyncs = void 0;
4
+ exports.productEventSyncs = [
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
+ // When a product is updated, publish product.updated event
32
+ {
33
+ name: "PublishProductUpdatedEvent",
34
+ when: [
35
+ {
36
+ concept: "Product",
37
+ action: "update"
38
+ }
39
+ ],
40
+ then: [
41
+ {
42
+ concept: "EventBus",
43
+ action: "publish",
44
+ input: {
45
+ event: "product.updated",
46
+ data: {
47
+ productId: "?productId",
48
+ updates: "?updates"
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ },
54
+ // When a product is deactivated, publish product.deactivated event
55
+ {
56
+ name: "PublishProductDeactivatedEvent",
57
+ when: [
58
+ {
59
+ concept: "Product",
60
+ action: "deactivate"
61
+ }
62
+ ],
63
+ then: [
64
+ {
65
+ concept: "EventBus",
66
+ action: "publish",
67
+ input: {
68
+ event: "product.deactivated",
69
+ data: {
70
+ productId: "?productId"
71
+ }
72
+ }
73
+ }
74
+ ]
75
+ }
76
+ ];
77
+ //# sourceMappingURL=product-events.sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-events.sync.js","sourceRoot":"","sources":["../../../../src/plugins/products/syncs/product-events.sync.ts"],"names":[],"mappings":";;;AAGa,QAAA,iBAAiB,GAAe;IAC3C,2DAA2D;IAC3D;QACE,IAAI,EAAE,4BAA4B;QAClC,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,SAAS;gBAClB,MAAM,EAAE,QAAQ;aACjB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,iBAAiB;oBACxB,IAAI,EAAE;wBACJ,SAAS,EAAE,YAAY;wBACvB,IAAI,EAAE,eAAe;wBACrB,GAAG,EAAE,cAAc;wBACnB,KAAK,EAAE,gBAAgB;wBACvB,QAAQ,EAAE,mBAAmB;qBAC9B;iBACF;aACF;SACF;KACF;IAED,2DAA2D;IAC3D;QACE,IAAI,EAAE,4BAA4B;QAClC,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,SAAS;gBAClB,MAAM,EAAE,QAAQ;aACjB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,iBAAiB;oBACxB,IAAI,EAAE;wBACJ,SAAS,EAAE,YAAY;wBACvB,OAAO,EAAE,UAAU;qBACpB;iBACF;aACF;SACF;KACF;IAED,mEAAmE;IACnE;QACE,IAAI,EAAE,gCAAgC;QACtC,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,SAAS;gBAClB,MAAM,EAAE,YAAY;aACrB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,qBAAqB;oBAC5B,IAAI,EAAE;wBACJ,SAAS,EAAE,YAAY;qBACxB;iBACF;aACF;SACF;KACF;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Concept } from '@legible-sync/core';
2
+ export declare const User: Concept;
3
+ //# sourceMappingURL=User.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.d.ts","sourceRoot":"","sources":["../../../../src/plugins/users/concepts/User.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C,eAAO,MAAM,IAAI,EAAE,OA4FlB,CAAC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.User = void 0;
4
+ const uuid_1 = require("uuid");
5
+ exports.User = {
6
+ state: {
7
+ users: new Map(),
8
+ emails: new Set(),
9
+ usernames: new Set(),
10
+ },
11
+ async execute(action, input) {
12
+ const state = this.state;
13
+ switch (action) {
14
+ case 'register': {
15
+ const { username, email, password } = input;
16
+ // Validation
17
+ if (!username || !email || !password) {
18
+ throw new Error('Username, email, and password are required');
19
+ }
20
+ if (state.emails.has(email)) {
21
+ throw new Error('Email already registered');
22
+ }
23
+ if (state.usernames.has(username)) {
24
+ throw new Error('Username already taken');
25
+ }
26
+ // Create user
27
+ const userId = (0, uuid_1.v4)();
28
+ const user = {
29
+ id: userId,
30
+ username,
31
+ email,
32
+ createdAt: new Date(),
33
+ status: 'active'
34
+ };
35
+ state.users.set(userId, user);
36
+ state.emails.add(email);
37
+ state.usernames.add(username);
38
+ return { userId, user };
39
+ }
40
+ case 'get': {
41
+ const { userId } = input;
42
+ const user = state.users.get(userId);
43
+ if (!user) {
44
+ throw new Error('User not found');
45
+ }
46
+ return { user };
47
+ }
48
+ case 'update': {
49
+ const { userId, updates } = input;
50
+ const user = state.users.get(userId);
51
+ if (!user) {
52
+ throw new Error('User not found');
53
+ }
54
+ // Update user
55
+ const updatedUser = { ...user, ...updates, updatedAt: new Date() };
56
+ state.users.set(userId, updatedUser);
57
+ return { user: updatedUser };
58
+ }
59
+ case 'deactivate': {
60
+ const { userId } = input;
61
+ const user = state.users.get(userId);
62
+ if (!user) {
63
+ throw new Error('User not found');
64
+ }
65
+ user.status = 'inactive';
66
+ user.deactivatedAt = new Date();
67
+ state.users.set(userId, user);
68
+ return { user };
69
+ }
70
+ case 'reset': {
71
+ state.users.clear();
72
+ state.emails.clear();
73
+ state.usernames.clear();
74
+ return { reset: true };
75
+ }
76
+ default:
77
+ throw new Error(`Unknown action: ${action}`);
78
+ }
79
+ }
80
+ };
81
+ //# sourceMappingURL=User.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.js","sourceRoot":"","sources":["../../../../src/plugins/users/concepts/User.ts"],"names":[],"mappings":";;;AAEA,+BAAoC;AAEvB,QAAA,IAAI,GAAY;IAC3B,KAAK,EAAE;QACL,KAAK,EAAE,IAAI,GAAG,EAAe;QAC7B,MAAM,EAAE,IAAI,GAAG,EAAU;QACzB,SAAS,EAAE,IAAI,GAAG,EAAU;KAC7B;IAED,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,KAAU;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAEzB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;gBAE5C,aAAa;gBACb,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACrC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAChE,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5B,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;gBAC9C,CAAC;gBAED,IAAI,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAClC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;gBAC5C,CAAC;gBAED,cAAc;gBACd,MAAM,MAAM,GAAG,IAAA,SAAM,GAAE,CAAC;gBACxB,MAAM,IAAI,GAAG;oBACX,EAAE,EAAE,MAAM;oBACV,QAAQ;oBACR,KAAK;oBACL,SAAS,EAAE,IAAI,IAAI,EAAE;oBACrB,MAAM,EAAE,QAAQ;iBACjB,CAAC;gBAEF,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBAC9B,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxB,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAE9B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAC1B,CAAC;YAED,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;gBACzB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBACpC,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,CAAC;YAClB,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;gBAClC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBACpC,CAAC;gBAED,cAAc;gBACd,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;gBACnE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gBAErC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;YAC/B,CAAC;YAEA,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;gBACzB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACrC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;gBACpC,CAAC;gBAED,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;gBACzB,IAAI,CAAC,aAAa,GAAG,IAAI,IAAI,EAAE,CAAC;gBAChC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBAE9B,OAAO,EAAE,IAAI,EAAE,CAAC;YAClB,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBACpB,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBACxB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;YAED;gBACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Plugin } from '../../core/PluginManager';
2
+ export declare const usersPlugin: Plugin;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/users/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAIlD,eAAO,MAAM,WAAW,EAAE,MASzB,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usersPlugin = void 0;
4
+ const User_1 = require("./concepts/User");
5
+ const user_events_sync_1 = require("./syncs/user-events.sync");
6
+ exports.usersPlugin = {
7
+ name: 'users',
8
+ concepts: {
9
+ User: User_1.User
10
+ },
11
+ syncs: user_events_sync_1.userEventSyncs,
12
+ initialize: async (_engine) => {
13
+ console.log('šŸ‘¤ Users plugin initialized');
14
+ }
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/users/index.ts"],"names":[],"mappings":";;;AAEA,0CAAuC;AACvC,+DAA0D;AAE7C,QAAA,WAAW,GAAW;IACjC,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE;QACR,IAAI,EAAJ,WAAI;KACL;IACD,KAAK,EAAE,iCAAc;IACrB,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC5B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { SyncRule } from '@legible-sync/core';
2
+ export declare const userEventSyncs: SyncRule[];
3
+ //# sourceMappingURL=user-events.sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-events.sync.d.ts","sourceRoot":"","sources":["../../../../src/plugins/users/syncs/user-events.sync.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,eAAO,MAAM,cAAc,EAAE,QAAQ,EAwEpC,CAAC"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.userEventSyncs = void 0;
4
+ exports.userEventSyncs = [
5
+ // When a user registers, publish user.registered event
6
+ {
7
+ name: "PublishUserRegisteredEvent",
8
+ when: [
9
+ {
10
+ concept: "User",
11
+ action: "register"
12
+ }
13
+ ],
14
+ then: [
15
+ {
16
+ concept: "EventBus",
17
+ action: "publish",
18
+ input: {
19
+ event: "user.registered",
20
+ data: {
21
+ userId: "?userId",
22
+ username: "?user.username",
23
+ email: "?user.email"
24
+ }
25
+ }
26
+ }
27
+ ]
28
+ },
29
+ // When a user is updated, publish user.updated event
30
+ {
31
+ name: "PublishUserUpdatedEvent",
32
+ when: [
33
+ {
34
+ concept: "User",
35
+ action: "update"
36
+ }
37
+ ],
38
+ then: [
39
+ {
40
+ concept: "EventBus",
41
+ action: "publish",
42
+ input: {
43
+ event: "user.updated",
44
+ data: {
45
+ userId: "?userId",
46
+ updates: "?updates"
47
+ }
48
+ }
49
+ }
50
+ ]
51
+ },
52
+ // When a user is deactivated, publish user.deactivated event
53
+ {
54
+ name: "PublishUserDeactivatedEvent",
55
+ when: [
56
+ {
57
+ concept: "User",
58
+ action: "deactivate"
59
+ }
60
+ ],
61
+ then: [
62
+ {
63
+ concept: "EventBus",
64
+ action: "publish",
65
+ input: {
66
+ event: "user.deactivated",
67
+ data: {
68
+ userId: "?userId"
69
+ }
70
+ }
71
+ }
72
+ ]
73
+ }
74
+ ];
75
+ //# sourceMappingURL=user-events.sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-events.sync.js","sourceRoot":"","sources":["../../../../src/plugins/users/syncs/user-events.sync.ts"],"names":[],"mappings":";;;AAGa,QAAA,cAAc,GAAe;IACxC,uDAAuD;IACvD;QACE,IAAI,EAAE,4BAA4B;QAClC,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,UAAU;aACnB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,iBAAiB;oBACxB,IAAI,EAAE;wBACJ,MAAM,EAAE,SAAS;wBACjB,QAAQ,EAAE,gBAAgB;wBAC1B,KAAK,EAAE,aAAa;qBACrB;iBACF;aACF;SACF;KACF;IAED,qDAAqD;IACrD;QACE,IAAI,EAAE,yBAAyB;QAC/B,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,QAAQ;aACjB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,cAAc;oBACrB,IAAI,EAAE;wBACJ,MAAM,EAAE,SAAS;wBACjB,OAAO,EAAE,UAAU;qBACpB;iBACF;aACF;SACF;KACF;IAED,6DAA6D;IAC7D;QACE,IAAI,EAAE,6BAA6B;QACnC,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,YAAY;aACrB;SACF;QACD,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE;oBACL,KAAK,EAAE,kBAAkB;oBACzB,IAAI,EAAE;wBACJ,MAAM,EAAE,SAAS;qBAClB;iBACF;aACF;SACF;KACF;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@legible-sync/example-eda",
3
+ "version": "1.2.0",
4
+ "description": "Event-Driven Architecture example with plugin-based modules",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "start": "ts-node src/index.ts",
8
+ "build": "tsc",
9
+ "dev": "ts-node src/index.ts",
10
+ "typecheck": "tsc --noEmit",
11
+ "lint": "eslint src/**/*.ts",
12
+ "test": "jest",
13
+ "test:watch": "jest --watch",
14
+ "test:coverage": "jest --coverage"
15
+ },
16
+ "dependencies": {
17
+ "@legible-sync/core": "^1.2.0"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/mastepanoski/legiblesync.git",
22
+ "directory": "packages/example-eda"
23
+ },
24
+ "homepage": "https://github.com/mastepanoski/legiblesync",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "devDependencies": {
29
+ "@types/jest": "^29.5.0",
30
+ "@types/node": "^20.0.0",
31
+ "jest": "^29.7.0",
32
+ "ts-jest": "^29.1.0",
33
+ "ts-node": "^10.9.0",
34
+ "typescript": "^5.0.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "gitHead": "0ac4e896d835d961c7efee0c7295f287d08d92a4"
40
+ }
@@ -0,0 +1,55 @@
1
+ // core/EventBus.ts
2
+
3
+ export interface Event {
4
+ type: string;
5
+ payload: Record<string, any>;
6
+ source: string;
7
+ timestamp: Date;
8
+ flowId: string;
9
+ }
10
+
11
+ export type EventHandler = (event: Event) => Promise<void>;
12
+
13
+ export class EventBus {
14
+ private handlers: Map<string, EventHandler[]> = new Map();
15
+
16
+ constructor() {
17
+ // EventBus is independent of the LegibleEngine
18
+ }
19
+
20
+ subscribe(eventType: string, handler: EventHandler): void {
21
+ if (!this.handlers.has(eventType)) {
22
+ this.handlers.set(eventType, []);
23
+ }
24
+ this.handlers.get(eventType)!.push(handler);
25
+ }
26
+
27
+ async publish(event: Omit<Event, 'timestamp'>): Promise<void> {
28
+ const fullEvent: Event = {
29
+ ...event,
30
+ timestamp: new Date()
31
+ };
32
+
33
+ console.log(`šŸ“¢ Event: ${fullEvent.type} from ${fullEvent.source}`, fullEvent.payload);
34
+
35
+ const handlers = this.handlers.get(event.type) || [];
36
+ for (const handler of handlers) {
37
+ try {
38
+ await handler(fullEvent);
39
+ } catch (error) {
40
+ // Handler errors are silently ignored to prevent cascading failures
41
+ }
42
+ }
43
+ }
44
+
45
+ // Helper to create events from engine actions
46
+ createEventFromAction(concept: string, action: string, input: any, output: any, flowId: string): Event {
47
+ return {
48
+ type: `${concept}.${action}`,
49
+ payload: { input, output },
50
+ source: concept,
51
+ timestamp: new Date(),
52
+ flowId
53
+ };
54
+ }
55
+ }
@@ -0,0 +1,51 @@
1
+ // core/PluginManager.ts
2
+ import { LegibleEngine, Concept, SyncRule } from '@legible-sync/core';
3
+
4
+ export interface Plugin {
5
+ name: string;
6
+ concepts: Record<string, Concept>;
7
+ syncs: SyncRule[];
8
+ initialize?: (engine: LegibleEngine) => Promise<void>;
9
+ }
10
+
11
+ export class PluginManager {
12
+ private engine: LegibleEngine;
13
+ private loadedPlugins: Map<string, Plugin> = new Map();
14
+
15
+ constructor(engine: LegibleEngine) {
16
+ this.engine = engine;
17
+ }
18
+
19
+ async loadPlugin(plugin: Plugin): Promise<void> {
20
+ console.log(`šŸ”Œ Loading plugin: ${plugin.name}`);
21
+
22
+ // Register concepts
23
+ for (const [name, concept] of Object.entries(plugin.concepts)) {
24
+ this.engine.registerConcept(name, concept);
25
+ console.log(` āœ“ Registered concept: ${name}`);
26
+ }
27
+
28
+ // Register sync rules
29
+ for (const sync of plugin.syncs) {
30
+ this.engine.registerSync(sync);
31
+ console.log(` āœ“ Registered sync: ${sync.name}`);
32
+ }
33
+
34
+ // Initialize plugin if needed
35
+ if (plugin.initialize) {
36
+ await plugin.initialize(this.engine);
37
+ console.log(` āœ“ Initialized plugin: ${plugin.name}`);
38
+ }
39
+
40
+ this.loadedPlugins.set(plugin.name, plugin);
41
+ console.log(`āœ… Plugin ${plugin.name} loaded successfully\n`);
42
+ }
43
+
44
+ getLoadedPlugins(): string[] {
45
+ return Array.from(this.loadedPlugins.keys());
46
+ }
47
+
48
+ getPlugin(name: string): Plugin | undefined {
49
+ return this.loadedPlugins.get(name);
50
+ }
51
+ }
package/src/index.ts ADDED
@@ -0,0 +1,169 @@
1
+ // example-eda/src/index.ts
2
+ import { LegibleEngine } from '@legible-sync/core';
3
+ import { PluginManager } from './core/PluginManager';
4
+ import { EventBus } from './core/EventBus';
5
+
6
+ // Import all plugins
7
+ import { usersPlugin } from './plugins/users';
8
+ import { productsPlugin } from './plugins/products';
9
+ import { ordersPlugin } from './plugins/orders';
10
+ import { inventoryPlugin } from './plugins/inventory';
11
+ import { notificationsPlugin } from './plugins/notifications';
12
+ import { analyticsPlugin } from './plugins/analytics';
13
+ import { paymentsPlugin } from './plugins/payments';
14
+
15
+ async function main() {
16
+ console.log('šŸš€ Starting Event-Driven Architecture Example\n');
17
+
18
+ // Initialize core systems
19
+ const engine = new LegibleEngine();
20
+ const pluginManager = new PluginManager(engine);
21
+ const eventBus = new EventBus();
22
+
23
+ // Register EventBus as a concept so plugins can publish events
24
+ engine.registerConcept('EventBus', {
25
+ state: {},
26
+ async execute(action: string, input: any) {
27
+ if (action === 'publish') {
28
+ const { event, data } = input;
29
+ await eventBus.publish({
30
+ type: event,
31
+ payload: data,
32
+ source: 'system',
33
+ flowId: input.flowId || 'system'
34
+ });
35
+ return { published: true };
36
+ }
37
+ throw new Error(`Unknown EventBus action: ${action}`);
38
+ }
39
+ });
40
+
41
+ // Load all plugins
42
+ const plugins = [
43
+ usersPlugin,
44
+ productsPlugin,
45
+ inventoryPlugin,
46
+ ordersPlugin,
47
+ paymentsPlugin,
48
+ notificationsPlugin,
49
+ analyticsPlugin
50
+ ];
51
+
52
+ for (const plugin of plugins) {
53
+ await pluginManager.loadPlugin(plugin);
54
+ }
55
+
56
+ console.log('\nāœ… All plugins loaded successfully!');
57
+ console.log('Loaded plugins:', pluginManager.getLoadedPlugins());
58
+
59
+ // Demonstrate the EDA system with a complete e-commerce flow
60
+ console.log('\nšŸ›ļø Demonstrating E-commerce Flow:\n');
61
+
62
+ try {
63
+ // 1. Create a user
64
+ console.log('1. šŸ‘¤ Creating user...');
65
+ const userFlow = 'user-flow-1';
66
+ const userResult = await engine.invoke('User', 'register', {
67
+ username: 'johndoe',
68
+ email: 'john@example.com',
69
+ password: 'password123'
70
+ }, userFlow);
71
+
72
+ console.log(' User created:', userResult.user.username);
73
+
74
+ // 2. Create a product
75
+ console.log('\n2. šŸ“¦ Creating product...');
76
+ const productFlow = 'product-flow-1';
77
+ const productResult = await engine.invoke('Product', 'create', {
78
+ name: 'Wireless Headphones',
79
+ sku: 'WH-001',
80
+ price: 99.99,
81
+ description: 'High-quality wireless headphones',
82
+ category: 'electronics'
83
+ }, productFlow);
84
+
85
+ console.log(' Product created:', productResult.product.name);
86
+
87
+ // 3. Set inventory for the product
88
+ console.log('\n3. šŸ“Š Setting inventory...');
89
+ await engine.invoke('Inventory', 'setStock', {
90
+ productId: productResult.productId,
91
+ quantity: 10
92
+ }, 'inventory-flow-1');
93
+
94
+ console.log(' Inventory set: 10 units');
95
+
96
+ // 4. Create an order
97
+ console.log('\n4. šŸ›’ Creating order...');
98
+ const orderFlow = 'order-flow-1';
99
+ const orderResult = await engine.invoke('Order', 'create', {
100
+ userId: userResult.userId,
101
+ items: [
102
+ {
103
+ productId: productResult.productId,
104
+ quantity: 2,
105
+ price: productResult.product.price
106
+ }
107
+ ]
108
+ }, orderFlow);
109
+
110
+ console.log(' Order created, checking inventory...');
111
+
112
+ // The system should automatically:
113
+ // - Check inventory availability
114
+ // - Confirm the order if available
115
+ // - Initiate and process payment
116
+ // - Deduct inventory
117
+ // - Send confirmation notification
118
+ // - Track analytics events
119
+
120
+ // Wait a bit for async operations
121
+ await new Promise(resolve => setTimeout(resolve, 100));
122
+
123
+ // 5. Check order status
124
+ console.log('\n5. šŸ“‹ Checking order status...');
125
+ const orderStatus = await engine.invoke('Order', 'get', {
126
+ orderId: orderResult.orderId
127
+ }, 'status-flow-1');
128
+
129
+ console.log(' Order status:', orderStatus.order.status);
130
+ console.log(' Order total: $' + orderStatus.order.total);
131
+
132
+ // 6. Check payment status
133
+ console.log('\n6. šŸ’³ Checking payment status...');
134
+ const paymentStatus = await engine.invoke('Payment', 'getByOrderId', {
135
+ orderId: orderResult.orderId
136
+ }, 'payment-check-flow-1');
137
+
138
+ console.log(' Payment status:', paymentStatus.payment.status);
139
+ console.log(' Payment amount: $' + paymentStatus.payment.amount);
140
+
141
+ // 7. Check inventory after order
142
+ console.log('\n7. šŸ“Š Checking inventory after order...');
143
+ const inventoryStatus = await engine.invoke('Inventory', 'getStock', {
144
+ productId: productResult.productId
145
+ }, 'inventory-check-flow-1');
146
+
147
+ console.log(' Remaining stock:', inventoryStatus.quantity, 'units');
148
+
149
+ // 8. Check analytics
150
+ console.log('\n8. šŸ“ˆ Checking analytics...');
151
+ const analytics = await engine.invoke('Analytics', 'getMetrics', {}, 'analytics-flow-1');
152
+ console.log(' Events tracked:', analytics.metrics);
153
+
154
+ console.log('\nšŸŽ‰ E-commerce flow completed successfully!');
155
+ console.log('The system automatically handled:');
156
+ console.log(' āœ“ Inventory validation');
157
+ console.log(' āœ“ Order confirmation');
158
+ console.log(' āœ“ Payment processing');
159
+ console.log(' āœ“ Stock deduction');
160
+ console.log(' āœ“ Email notifications');
161
+ console.log(' āœ“ Analytics tracking');
162
+
163
+ } catch (error) {
164
+ console.error('āŒ Error in demo:', error);
165
+ }
166
+ }
167
+
168
+ // Run the demo
169
+ main().catch(console.error);
@@ -0,0 +1,53 @@
1
+ // plugins/analytics/concepts/Analytics.ts
2
+ import { Concept } from '@legible-sync/core';
3
+
4
+ export const Analytics: Concept = {
5
+ state: {
6
+ events: new Map<string, any[]>(),
7
+ metrics: new Map<string, number>(),
8
+ },
9
+
10
+ async execute(action: string, input: any) {
11
+ const state = this.state;
12
+
13
+ switch (action) {
14
+ case 'track': {
15
+ const { event, data } = input;
16
+
17
+ if (!state.events.has(event)) {
18
+ state.events.set(event, []);
19
+ }
20
+
21
+ const eventData = {
22
+ ...data,
23
+ timestamp: new Date(),
24
+ id: `event_${Date.now()}`
25
+ };
26
+
27
+ state.events.get(event)!.push(eventData);
28
+
29
+ // Update metrics
30
+ const count = state.metrics.get(event) || 0;
31
+ state.metrics.set(event, count + 1);
32
+
33
+ console.log(`šŸ“Š Tracked: ${event}`, data);
34
+
35
+ return { eventId: eventData.id };
36
+ }
37
+
38
+ case 'getMetrics': {
39
+ const metrics = Object.fromEntries(state.metrics);
40
+ return { metrics };
41
+ }
42
+
43
+ case 'getEvents': {
44
+ const { event, limit = 10 } = input;
45
+ const events = state.events.get(event) || [];
46
+ return { events: events.slice(-limit) };
47
+ }
48
+
49
+ default:
50
+ throw new Error(`Unknown action: ${action}`);
51
+ }
52
+ }
53
+ };