@mmapp/react-compiler 0.1.0-alpha.1

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 (314) hide show
  1. package/README.md +107 -0
  2. package/compile-blueprint-chat.mjs +99 -0
  3. package/compile-blueprint-glass-console.mjs +98 -0
  4. package/compile-chat-defs.mjs +92 -0
  5. package/dist/babel/index.d.mts +3 -0
  6. package/dist/babel/index.d.ts +3 -0
  7. package/dist/babel/index.js +4851 -0
  8. package/dist/babel/index.mjs +7 -0
  9. package/dist/chunk-26U577GB.mjs +3465 -0
  10. package/dist/chunk-2FBDFAX6.mjs +2362 -0
  11. package/dist/chunk-2L4QSMXG.mjs +175 -0
  12. package/dist/chunk-2REDFOER.mjs +931 -0
  13. package/dist/chunk-46YKSHQR.mjs +175 -0
  14. package/dist/chunk-4XHK6FWL.mjs +2058 -0
  15. package/dist/chunk-5M7DKKBC.mjs +215 -0
  16. package/dist/chunk-5VNJ7C6N.mjs +154 -0
  17. package/dist/chunk-6CQOAAMV.mjs +1803 -0
  18. package/dist/chunk-6SEVAAVT.mjs +3516 -0
  19. package/dist/chunk-6YLR5ZDA.mjs +2829 -0
  20. package/dist/chunk-AOGY2GK6.mjs +3292 -0
  21. package/dist/chunk-AXXUXRNA.mjs +1434 -0
  22. package/dist/chunk-CHLVKMQW.mjs +175 -0
  23. package/dist/chunk-CKGOZAB7.mjs +939 -0
  24. package/dist/chunk-D34RAZUX.mjs +2223 -0
  25. package/dist/chunk-EQGA6A6D.mjs +121 -0
  26. package/dist/chunk-EY2CSXYA.mjs +822 -0
  27. package/dist/chunk-FIQ65CDR.mjs +925 -0
  28. package/dist/chunk-FOZXJFAR.mjs +186 -0
  29. package/dist/chunk-FX6URXWN.mjs +186 -0
  30. package/dist/chunk-G7SMOWOL.mjs +828 -0
  31. package/dist/chunk-GGB4G5YY.mjs +175 -0
  32. package/dist/chunk-HLRGCCIL.mjs +4839 -0
  33. package/dist/chunk-HOIUP6IF.mjs +690 -0
  34. package/dist/chunk-I3AU7GRD.mjs +120 -0
  35. package/dist/chunk-ILFGMUVD.mjs +1933 -0
  36. package/dist/chunk-IPTX5MJU.mjs +3223 -0
  37. package/dist/chunk-ITGUSH2Z.mjs +2783 -0
  38. package/dist/chunk-IXHBCAMF.mjs +3306 -0
  39. package/dist/chunk-J7TWJ3TM.mjs +2784 -0
  40. package/dist/chunk-JDPLDGVF.mjs +4810 -0
  41. package/dist/chunk-K53XP2DL.mjs +148 -0
  42. package/dist/chunk-K5HX2SVL.mjs +1902 -0
  43. package/dist/chunk-KFGYOOVS.mjs +214 -0
  44. package/dist/chunk-KFVVOS5N.mjs +925 -0
  45. package/dist/chunk-L2OZ4CDV.mjs +113 -0
  46. package/dist/chunk-MIZV3TAN.mjs +3293 -0
  47. package/dist/chunk-NKKLQE5V.mjs +148 -0
  48. package/dist/chunk-NOW23XFZ.mjs +186 -0
  49. package/dist/chunk-NRXQKQ74.mjs +148 -0
  50. package/dist/chunk-OWI6XWCD.mjs +3375 -0
  51. package/dist/chunk-PRUMNNDI.mjs +3192 -0
  52. package/dist/chunk-QTBD5B3F.mjs +148 -0
  53. package/dist/chunk-SKSDPPNT.mjs +3788 -0
  54. package/dist/chunk-SP2YUS33.mjs +186 -0
  55. package/dist/chunk-SU4E6E7B.mjs +3153 -0
  56. package/dist/chunk-SYUUKW5A.mjs +3379 -0
  57. package/dist/chunk-UL2XZEMA.mjs +3128 -0
  58. package/dist/chunk-XMWUHQVV.mjs +939 -0
  59. package/dist/chunk-XZNEDRGN.mjs +3876 -0
  60. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  61. package/dist/chunk-YFS6JMYO.mjs +3342 -0
  62. package/dist/chunk-Z6AIQ4KL.mjs +113 -0
  63. package/dist/cli/index.d.mts +1 -0
  64. package/dist/cli/index.d.ts +1 -0
  65. package/dist/cli/index.js +11585 -0
  66. package/dist/cli/index.mjs +701 -0
  67. package/dist/codemod/cli.d.mts +1 -0
  68. package/dist/codemod/cli.d.ts +1 -0
  69. package/dist/codemod/cli.js +1104 -0
  70. package/dist/codemod/cli.mjs +157 -0
  71. package/dist/codemod/index.d.mts +148 -0
  72. package/dist/codemod/index.d.ts +148 -0
  73. package/dist/codemod/index.js +981 -0
  74. package/dist/codemod/index.mjs +25 -0
  75. package/dist/dev-server-Bs_sz2DG.d.mts +111 -0
  76. package/dist/dev-server-Bs_sz2DG.d.ts +111 -0
  77. package/dist/dev-server-CjoufJ-u.d.mts +109 -0
  78. package/dist/dev-server-CjoufJ-u.d.ts +109 -0
  79. package/dist/dev-server.d.mts +3 -0
  80. package/dist/dev-server.d.ts +3 -0
  81. package/dist/dev-server.js +7603 -0
  82. package/dist/dev-server.mjs +11 -0
  83. package/dist/envelope-DD7v0v6E.d.mts +265 -0
  84. package/dist/envelope-DD7v0v6E.d.ts +265 -0
  85. package/dist/envelope-vCVjrHlo.d.mts +265 -0
  86. package/dist/envelope-vCVjrHlo.d.ts +265 -0
  87. package/dist/envelope.d.mts +2 -0
  88. package/dist/envelope.d.ts +2 -0
  89. package/dist/envelope.js +5184 -0
  90. package/dist/envelope.mjs +9 -0
  91. package/dist/index-B5gSgvnd.d.mts +44 -0
  92. package/dist/index-B5gSgvnd.d.ts +44 -0
  93. package/dist/index-Bs0MnR54.d.mts +103 -0
  94. package/dist/index-Bs0MnR54.d.ts +103 -0
  95. package/dist/index-DR0nNc_f.d.mts +101 -0
  96. package/dist/index-DR0nNc_f.d.ts +101 -0
  97. package/dist/index-revho_gS.d.mts +104 -0
  98. package/dist/index-revho_gS.d.ts +104 -0
  99. package/dist/index.d.mts +1099 -0
  100. package/dist/index.d.ts +1099 -0
  101. package/dist/index.js +10162 -0
  102. package/dist/index.mjs +372 -0
  103. package/dist/init-IXEE2RCF.mjs +340 -0
  104. package/dist/project-compiler-EGJUTAJU.mjs +10 -0
  105. package/dist/project-compiler-VFR6CSDX.mjs +10 -0
  106. package/dist/project-decompiler-5GY2KSG4.mjs +7 -0
  107. package/dist/pull-A2QUHW4K.mjs +109 -0
  108. package/dist/pull-JBEQWVPE.mjs +109 -0
  109. package/dist/testing/index.d.mts +211 -0
  110. package/dist/testing/index.d.ts +211 -0
  111. package/dist/testing/index.js +5106 -0
  112. package/dist/testing/index.mjs +247 -0
  113. package/dist/vite/index.d.mts +59 -0
  114. package/dist/vite/index.d.ts +59 -0
  115. package/dist/vite/index.js +5023 -0
  116. package/dist/vite/index.mjs +8 -0
  117. package/examples/README.md +72 -0
  118. package/examples/authentication/main.workflow.tsx +139 -0
  119. package/examples/authentication/mm.config.ts +22 -0
  120. package/examples/authentication/models/auth.ts +45 -0
  121. package/examples/authentication/pages/LoginPage.tsx +79 -0
  122. package/examples/authentication/pages/SignupPage.tsx +87 -0
  123. package/examples/counter.workflow.tsx +65 -0
  124. package/examples/dashboard.workflow.tsx +419 -0
  125. package/examples/invoice-approval/actions/invoice.server.ts +72 -0
  126. package/examples/invoice-approval/main.workflow.tsx +168 -0
  127. package/examples/invoice-approval/mm.config.ts +18 -0
  128. package/examples/invoice-approval/models/invoice.ts +46 -0
  129. package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +175 -0
  130. package/examples/invoice-approval/pages/InvoiceFormPage.tsx +198 -0
  131. package/examples/invoice-approval/pages/InvoiceListPage.tsx +141 -0
  132. package/examples/todo-app.workflow.tsx +131 -0
  133. package/examples/uber-app/actions/matching.server.ts +177 -0
  134. package/examples/uber-app/actions/notifications.server.ts +176 -0
  135. package/examples/uber-app/actions/payments.server.ts +184 -0
  136. package/examples/uber-app/actions/pricing.server.ts +176 -0
  137. package/examples/uber-app/app/admin/analytics.tsx +102 -0
  138. package/examples/uber-app/app/admin/fleet.tsx +102 -0
  139. package/examples/uber-app/app/admin/surge-pricing.tsx +95 -0
  140. package/examples/uber-app/app/driver/dashboard.tsx +87 -0
  141. package/examples/uber-app/app/driver/earnings.tsx +101 -0
  142. package/examples/uber-app/app/driver/navigation.tsx +94 -0
  143. package/examples/uber-app/app/driver/ride-acceptance.tsx +103 -0
  144. package/examples/uber-app/app/rider/home.tsx +109 -0
  145. package/examples/uber-app/app/rider/payment-methods.tsx +134 -0
  146. package/examples/uber-app/app/rider/ride-history.tsx +90 -0
  147. package/examples/uber-app/app/rider/ride-tracking.tsx +108 -0
  148. package/examples/uber-app/components/DriverCard.tsx +176 -0
  149. package/examples/uber-app/components/MapView.tsx +216 -0
  150. package/examples/uber-app/components/RatingStars.tsx +227 -0
  151. package/examples/uber-app/components/RideCard.tsx +167 -0
  152. package/examples/uber-app/mm.config.ts +30 -0
  153. package/examples/uber-app/models/location.model.ts +70 -0
  154. package/examples/uber-app/models/payment.model.ts +87 -0
  155. package/examples/uber-app/models/rating.model.ts +54 -0
  156. package/examples/uber-app/models/ride.model.ts +118 -0
  157. package/examples/uber-app/models/user.model.ts +66 -0
  158. package/examples/uber-app/models/vehicle.model.ts +63 -0
  159. package/examples/uber-app/tests/payment.test.tsx +129 -0
  160. package/examples/uber-app/tests/ride-flow.test.tsx +123 -0
  161. package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +205 -0
  162. package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +227 -0
  163. package/examples/uber-app/workflows/payment-processing.workflow.tsx +223 -0
  164. package/examples/uber-app/workflows/ride-request.workflow.tsx +194 -0
  165. package/package.json +77 -0
  166. package/package.json.backup +86 -0
  167. package/scripts/decompile.ts +226 -0
  168. package/scripts/seed-auth.ts +267 -0
  169. package/scripts/seed-uber.ts +248 -0
  170. package/scripts/validate-uber.ts +119 -0
  171. package/seed-blueprint-chat.mjs +444 -0
  172. package/seed-blueprint-glass-console.mjs +445 -0
  173. package/seed-compiled.mjs +318 -0
  174. package/src/RoundTripValidator.ts +400 -0
  175. package/src/__tests__/atom-rendering-coverage.test.ts +680 -0
  176. package/src/__tests__/auth-module-compilation.test.ts +247 -0
  177. package/src/__tests__/auth-template-compilation.test.ts +589 -0
  178. package/src/__tests__/change-extractor.test.ts +142 -0
  179. package/src/__tests__/cli-pull.test.ts +73 -0
  180. package/src/__tests__/cli-test.test.ts +72 -0
  181. package/src/__tests__/component-extractor.test.ts +331 -0
  182. package/src/__tests__/context-extractor.test.ts +145 -0
  183. package/src/__tests__/decompiler.test.ts +718 -0
  184. package/src/__tests__/define-blueprint.test.ts +133 -0
  185. package/src/__tests__/definition-validator.test.ts +519 -0
  186. package/src/__tests__/during-extractor.test.ts +152 -0
  187. package/src/__tests__/effect-extractor.test.ts +107 -0
  188. package/src/__tests__/event-emission.test.ts +127 -0
  189. package/src/__tests__/examples.test.ts +236 -0
  190. package/src/__tests__/full-blueprint-coverage.test.ts +1221 -0
  191. package/src/__tests__/golden-suite.test.ts +403 -0
  192. package/src/__tests__/grammar-island-extractor.test.ts +289 -0
  193. package/src/__tests__/instance-key.test.ts +82 -0
  194. package/src/__tests__/ir-migration.test.ts +255 -0
  195. package/src/__tests__/lock-file.test.ts +117 -0
  196. package/src/__tests__/model-extractor.test.ts +195 -0
  197. package/src/__tests__/model-field-acl.test.ts +237 -0
  198. package/src/__tests__/model-hooks.test.ts +130 -0
  199. package/src/__tests__/model-ref-resolution.test.ts +268 -0
  200. package/src/__tests__/model-roundtrip.test.ts +502 -0
  201. package/src/__tests__/model-runtime.test.ts +112 -0
  202. package/src/__tests__/model-transitions.test.ts +183 -0
  203. package/src/__tests__/nrt-action-trace.test.ts +391 -0
  204. package/src/__tests__/pipeline-hardening.test.ts +413 -0
  205. package/src/__tests__/project-compiler.test.ts +546 -0
  206. package/src/__tests__/project-decompiler.test.ts +343 -0
  207. package/src/__tests__/query-compilation.test.ts +145 -0
  208. package/src/__tests__/round-trip/PLAN.md +158 -0
  209. package/src/__tests__/round-trip/README.md +52 -0
  210. package/src/__tests__/round-trip/RESULTS.md +86 -0
  211. package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +55 -0
  212. package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +11 -0
  213. package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +54 -0
  214. package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +79 -0
  215. package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +12 -0
  216. package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +50 -0
  217. package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +25 -0
  218. package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +11 -0
  219. package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +32 -0
  220. package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +79 -0
  221. package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +10 -0
  222. package/src/__tests__/round-trip/round-trip.test.ts +2598 -0
  223. package/src/__tests__/round-trip-ir.test.ts +300 -0
  224. package/src/__tests__/round-trip.test.ts +1212 -0
  225. package/src/__tests__/route-merging.test.ts +372 -0
  226. package/src/__tests__/router-composition.test.ts +489 -0
  227. package/src/__tests__/router-extractor.test.ts +176 -0
  228. package/src/__tests__/server-action-extractor.test.ts +128 -0
  229. package/src/__tests__/smart-type-inference.test.ts +365 -0
  230. package/src/__tests__/source-envelope.test.ts +284 -0
  231. package/src/__tests__/source-fidelity.test.ts +516 -0
  232. package/src/__tests__/state-extractor.test.ts +115 -0
  233. package/src/__tests__/strict-mode.test.ts +227 -0
  234. package/src/__tests__/transition-effect-extractor.test.ts +119 -0
  235. package/src/__tests__/transition-extractor.test.ts +68 -0
  236. package/src/__tests__/ts-to-expression.test.ts +462 -0
  237. package/src/__tests__/type-generator.test.ts +201 -0
  238. package/src/__tests__/uber-validation.test.ts +502 -0
  239. package/src/action-compiler.ts +361 -0
  240. package/src/babel/emitters/experience-transform.ts +199 -0
  241. package/src/babel/emitters/ir-to-tsx-emitter.ts +110 -0
  242. package/src/babel/emitters/pure-form-emitter.ts +1023 -0
  243. package/src/babel/emitters/runtime-glue-emitter.ts +39 -0
  244. package/src/babel/extractors/change-extractor.ts +199 -0
  245. package/src/babel/extractors/component-extractor.ts +907 -0
  246. package/src/babel/extractors/computed-extractor.ts +262 -0
  247. package/src/babel/extractors/context-extractor.ts +277 -0
  248. package/src/babel/extractors/during-extractor.ts +295 -0
  249. package/src/babel/extractors/effect-extractor.ts +340 -0
  250. package/src/babel/extractors/event-extractor.ts +235 -0
  251. package/src/babel/extractors/grammar-island-extractor.ts +302 -0
  252. package/src/babel/extractors/model-extractor.ts +1018 -0
  253. package/src/babel/extractors/router-extractor.ts +303 -0
  254. package/src/babel/extractors/server-action-extractor.ts +173 -0
  255. package/src/babel/extractors/server-action-hook-extractor.ts +72 -0
  256. package/src/babel/extractors/server-state-extractor.ts +88 -0
  257. package/src/babel/extractors/state-extractor.ts +214 -0
  258. package/src/babel/extractors/transition-effect-extractor.ts +176 -0
  259. package/src/babel/extractors/transition-extractor.ts +143 -0
  260. package/src/babel/index.ts +24 -0
  261. package/src/babel/transpilers/ts-to-expression.ts +674 -0
  262. package/src/babel/visitor.ts +807 -0
  263. package/src/cli/auth.ts +255 -0
  264. package/src/cli/build.ts +288 -0
  265. package/src/cli/deploy.ts +206 -0
  266. package/src/cli/index.ts +328 -0
  267. package/src/cli/init.ts +388 -0
  268. package/src/cli/installer.ts +261 -0
  269. package/src/cli/lock-file.ts +94 -0
  270. package/src/cli/mmrc.ts +22 -0
  271. package/src/cli/pull.ts +172 -0
  272. package/src/cli/registry-client.ts +175 -0
  273. package/src/cli/test.ts +397 -0
  274. package/src/cli/type-generator.ts +243 -0
  275. package/src/codemod/__tests__/forward.test.ts +239 -0
  276. package/src/codemod/__tests__/reverse.test.ts +145 -0
  277. package/src/codemod/__tests__/round-trip.test.ts +137 -0
  278. package/src/codemod/annotation.ts +97 -0
  279. package/src/codemod/classify.ts +197 -0
  280. package/src/codemod/cli.ts +207 -0
  281. package/src/codemod/control-flow.ts +409 -0
  282. package/src/codemod/forward.ts +244 -0
  283. package/src/codemod/import-manager.ts +171 -0
  284. package/src/codemod/index.ts +120 -0
  285. package/src/codemod/reverse.ts +197 -0
  286. package/src/codemod/rules.ts +174 -0
  287. package/src/codemod/state-transform.ts +126 -0
  288. package/src/decompiler/ast-builder.ts +538 -0
  289. package/src/decompiler/config-generator.ts +151 -0
  290. package/src/decompiler/index.ts +315 -0
  291. package/src/decompiler/project-decompiler.ts +1776 -0
  292. package/src/decompiler/project.ts +862 -0
  293. package/src/decompiler/split-strategy.ts +140 -0
  294. package/src/decompiler/state-emitter.ts +1053 -0
  295. package/src/decompiler/sx-emitter.ts +318 -0
  296. package/src/decompiler/workspace-hydrator.ts +189 -0
  297. package/src/dev-server.ts +238 -0
  298. package/src/envelope/fs-tree.ts +217 -0
  299. package/src/envelope/source-envelope.ts +264 -0
  300. package/src/envelope.ts +315 -0
  301. package/src/incremental-compiler.ts +401 -0
  302. package/src/index.ts +99 -0
  303. package/src/model-compiler.ts +277 -0
  304. package/src/project-compiler.ts +1629 -0
  305. package/src/route-extractor.ts +333 -0
  306. package/src/testing/index.ts +32 -0
  307. package/src/testing/snapshot.ts +252 -0
  308. package/src/testing/test-utils.ts +226 -0
  309. package/src/types.ts +68 -0
  310. package/src/vite/index.ts +288 -0
  311. package/test-compile.mjs +142 -0
  312. package/tsconfig.json +25 -0
  313. package/tsup.config.ts +23 -0
  314. package/vitest.config.ts +9 -0
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @workflow slug="uber-rideshare"
3
+ * @description Driver matching algorithm — finds optimal driver based on proximity, rating, and vehicle type
4
+ */
5
+
6
+ import type { TransitionContext, ActionResult } from '@mindmatrix/react';
7
+
8
+ /** Haversine distance in kilometers between two lat/lng points */
9
+ function haversineKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
10
+ const R = 6371;
11
+ const dLat = ((lat2 - lat1) * Math.PI) / 180;
12
+ const dLon = ((lon2 - lon1) * Math.PI) / 180;
13
+ const a =
14
+ Math.sin(dLat / 2) * Math.sin(dLat / 2) +
15
+ Math.cos((lat1 * Math.PI) / 180) *
16
+ Math.cos((lat2 * Math.PI) / 180) *
17
+ Math.sin(dLon / 2) *
18
+ Math.sin(dLon / 2);
19
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
20
+ }
21
+
22
+ /** Score a driver for matching — higher is better */
23
+ function scoreDriver(
24
+ driver: Record<string, unknown>,
25
+ pickupLat: number,
26
+ pickupLng: number,
27
+ requestedType: string
28
+ ): number {
29
+ const dist = haversineKm(
30
+ pickupLat,
31
+ pickupLng,
32
+ driver.currentLatitude as number,
33
+ driver.currentLongitude as number
34
+ );
35
+
36
+ // Distance score: closer = higher (max 50 points, 0 at 15km+)
37
+ const distanceScore = Math.max(0, 50 - dist * (50 / 15));
38
+
39
+ // Rating score: 0-25 points
40
+ const ratingScore = ((driver.driverRating as number) / 5) * 25;
41
+
42
+ // Acceptance rate score: 0-15 points
43
+ const acceptScore = ((driver.acceptanceRate as number) / 100) * 15;
44
+
45
+ // Vehicle type match bonus: 10 points
46
+ const typeBonus = driver.vehicleType === requestedType ? 10 : 0;
47
+
48
+ return distanceScore + ratingScore + acceptScore + typeBonus;
49
+ }
50
+
51
+ /** Find and match the best available driver for a ride request */
52
+ export async function findBestDriver(ctx: TransitionContext): Promise<ActionResult> {
53
+ const { instance, env } = ctx;
54
+ const { originLatitude, originLongitude, vehicleType } = instance.fields as Record<string, unknown>;
55
+
56
+ // Query nearby online drivers with matching vehicle type
57
+ const drivers = await env.query('uber-user', {
58
+ filter: {
59
+ role: 'driver',
60
+ isOnline: true,
61
+ status: 'active',
62
+ },
63
+ limit: 50,
64
+ });
65
+
66
+ if (!drivers.data || drivers.data.length === 0) {
67
+ return { success: false, data: { reason: 'no_drivers_available' } };
68
+ }
69
+
70
+ // Score and rank all candidate drivers
71
+ const scored = drivers.data
72
+ .map((driver: Record<string, unknown>) => ({
73
+ driver,
74
+ score: scoreDriver(
75
+ driver,
76
+ originLatitude as number,
77
+ originLongitude as number,
78
+ vehicleType as string
79
+ ),
80
+ distance: haversineKm(
81
+ originLatitude as number,
82
+ originLongitude as number,
83
+ driver.currentLatitude as number,
84
+ driver.currentLongitude as number
85
+ ),
86
+ }))
87
+ .filter((d) => d.distance <= 15) // Max 15km radius
88
+ .sort((a, b) => b.score - a.score);
89
+
90
+ if (scored.length === 0) {
91
+ return { success: false, data: { reason: 'no_drivers_in_range' } };
92
+ }
93
+
94
+ const best = scored[0];
95
+ const etaMinutes = Math.round((best.distance / 30) * 60); // Assume 30km/h avg
96
+
97
+ return {
98
+ success: true,
99
+ data: {
100
+ driverId: best.driver.id,
101
+ driverName: best.driver.displayName,
102
+ vehicleId: best.driver.vehicleId,
103
+ driverLatitude: best.driver.currentLatitude,
104
+ driverLongitude: best.driver.currentLongitude,
105
+ driverRating: best.driver.driverRating,
106
+ etaMinutes,
107
+ matchScore: best.score,
108
+ candidatesEvaluated: scored.length,
109
+ },
110
+ };
111
+ }
112
+
113
+ /** Batch-match multiple ride requests to available drivers (for dispatch optimization) */
114
+ export async function batchMatchDrivers(ctx: TransitionContext): Promise<ActionResult> {
115
+ const { env } = ctx;
116
+
117
+ const pendingRides = await env.query('uber-ride', {
118
+ filter: { status: 'searching' },
119
+ limit: 100,
120
+ orderBy: 'requestedAt',
121
+ order: 'asc',
122
+ });
123
+
124
+ const matchedDriverIds = new Set<string>();
125
+ const results: Array<{ rideId: string; driverId: string; eta: number }> = [];
126
+
127
+ for (const ride of pendingRides.data) {
128
+ const drivers = await env.query('uber-user', {
129
+ filter: {
130
+ role: 'driver',
131
+ isOnline: true,
132
+ status: 'active',
133
+ },
134
+ limit: 50,
135
+ });
136
+
137
+ const available = drivers.data.filter(
138
+ (d: Record<string, unknown>) => !matchedDriverIds.has(d.id as string)
139
+ );
140
+
141
+ if (available.length > 0) {
142
+ const scored = available
143
+ .map((driver: Record<string, unknown>) => ({
144
+ driver,
145
+ score: scoreDriver(
146
+ driver,
147
+ ride.originLatitude as number,
148
+ ride.originLongitude as number,
149
+ ride.vehicleType as string
150
+ ),
151
+ distance: haversineKm(
152
+ ride.originLatitude as number,
153
+ ride.originLongitude as number,
154
+ driver.currentLatitude as number,
155
+ driver.currentLongitude as number
156
+ ),
157
+ }))
158
+ .filter((d) => d.distance <= 15)
159
+ .sort((a, b) => b.score - a.score);
160
+
161
+ if (scored.length > 0) {
162
+ const best = scored[0];
163
+ matchedDriverIds.add(best.driver.id as string);
164
+ results.push({
165
+ rideId: ride.id as string,
166
+ driverId: best.driver.id as string,
167
+ eta: Math.round((best.distance / 30) * 60),
168
+ });
169
+ }
170
+ }
171
+ }
172
+
173
+ return {
174
+ success: true,
175
+ data: { matched: results.length, total: pendingRides.data.length, results },
176
+ };
177
+ }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @workflow slug="uber-rideshare"
3
+ * @description Push notification delivery for ride lifecycle events
4
+ */
5
+
6
+ import type { TransitionContext, ActionResult } from '@mindmatrix/react';
7
+
8
+ type NotificationChannel = 'push' | 'sms' | 'email' | 'in_app';
9
+
10
+ interface NotificationPayload {
11
+ userId: string;
12
+ title: string;
13
+ body: string;
14
+ channels: NotificationChannel[];
15
+ data?: Record<string, unknown>;
16
+ priority?: 'high' | 'normal' | 'low';
17
+ sound?: string;
18
+ badge?: number;
19
+ }
20
+
21
+ /** Send notification via configured channels */
22
+ async function sendNotification(
23
+ env: TransitionContext['env'],
24
+ payload: NotificationPayload
25
+ ): Promise<void> {
26
+ // In production: calls FCM/APNs/Twilio/SendGrid
27
+ await env.emit('notification:sent', {
28
+ userId: payload.userId,
29
+ title: payload.title,
30
+ channels: payload.channels,
31
+ timestamp: new Date().toISOString(),
32
+ });
33
+ }
34
+
35
+ /** Notify rider that a driver has been matched */
36
+ export async function notifyRideMatched(ctx: TransitionContext): Promise<ActionResult> {
37
+ const { instance, env } = ctx;
38
+ const fields = instance.fields as Record<string, unknown>;
39
+
40
+ await sendNotification(env, {
41
+ userId: fields.riderId as string,
42
+ title: 'Driver Found!',
43
+ body: `${fields.driverName} is on the way in a ${fields.vehicleType}. ETA: ${fields.etaMinutes} min`,
44
+ channels: ['push', 'in_app'],
45
+ priority: 'high',
46
+ sound: 'ride_matched.mp3',
47
+ data: {
48
+ type: 'ride_matched',
49
+ rideId: instance.id,
50
+ driverName: fields.driverName,
51
+ etaMinutes: fields.etaMinutes,
52
+ },
53
+ });
54
+
55
+ return { success: true, data: { notified: 'rider', event: 'ride_matched' } };
56
+ }
57
+
58
+ /** Notify rider that driver has arrived at pickup */
59
+ export async function notifyDriverArrived(ctx: TransitionContext): Promise<ActionResult> {
60
+ const { instance, env } = ctx;
61
+ const fields = instance.fields as Record<string, unknown>;
62
+
63
+ await sendNotification(env, {
64
+ userId: fields.riderId as string,
65
+ title: 'Your driver has arrived',
66
+ body: `${fields.driverName} is waiting at the pickup location. Share code: ${fields.shareCode}`,
67
+ channels: ['push', 'sms', 'in_app'],
68
+ priority: 'high',
69
+ sound: 'driver_arrived.mp3',
70
+ data: { type: 'driver_arrived', rideId: instance.id, shareCode: fields.shareCode },
71
+ });
72
+
73
+ return { success: true, data: { notified: 'rider', event: 'driver_arrived' } };
74
+ }
75
+
76
+ /** Notify driver of an incoming ride request */
77
+ export async function notifyNewRideRequest(ctx: TransitionContext): Promise<ActionResult> {
78
+ const { instance, env } = ctx;
79
+ const fields = instance.fields as Record<string, unknown>;
80
+
81
+ await sendNotification(env, {
82
+ userId: fields.driverId as string,
83
+ title: 'New Ride Request',
84
+ body: `Pickup: ${fields.originAddress}. Fare: $${fields.estimatedFare}`,
85
+ channels: ['push', 'in_app'],
86
+ priority: 'high',
87
+ sound: 'new_request.mp3',
88
+ badge: 1,
89
+ data: {
90
+ type: 'ride_request',
91
+ rideId: instance.id,
92
+ originAddress: fields.originAddress,
93
+ estimatedFare: fields.estimatedFare,
94
+ vehicleType: fields.vehicleType,
95
+ },
96
+ });
97
+
98
+ return { success: true, data: { notified: 'driver', event: 'ride_request' } };
99
+ }
100
+
101
+ /** Notify rider when ride is completed with fare summary */
102
+ export async function notifyRideCompleted(ctx: TransitionContext): Promise<ActionResult> {
103
+ const { instance, env } = ctx;
104
+ const fields = instance.fields as Record<string, unknown>;
105
+
106
+ // Notify rider
107
+ await sendNotification(env, {
108
+ userId: fields.riderId as string,
109
+ title: 'Ride Complete',
110
+ body: `You arrived at ${fields.destinationAddress}. Total: $${fields.actualFare}`,
111
+ channels: ['push', 'in_app'],
112
+ data: { type: 'ride_completed', rideId: instance.id, fare: fields.actualFare },
113
+ });
114
+
115
+ // Notify driver
116
+ await sendNotification(env, {
117
+ userId: fields.driverId as string,
118
+ title: 'Trip Complete',
119
+ body: `Earnings: $${fields.actualFare}. Don't forget to rate your rider.`,
120
+ channels: ['push', 'in_app'],
121
+ data: { type: 'ride_completed', rideId: instance.id },
122
+ });
123
+
124
+ return { success: true, data: { notified: 'both', event: 'ride_completed' } };
125
+ }
126
+
127
+ /** Notify about ride cancellation */
128
+ export async function notifyCancellation(ctx: TransitionContext): Promise<ActionResult> {
129
+ const { instance, env } = ctx;
130
+ const fields = instance.fields as Record<string, unknown>;
131
+ const cancelledBy = fields.cancelledBy as string;
132
+
133
+ const targetUserId = cancelledBy === 'rider'
134
+ ? fields.driverId as string
135
+ : fields.riderId as string;
136
+
137
+ if (targetUserId) {
138
+ await sendNotification(env, {
139
+ userId: targetUserId,
140
+ title: 'Ride Cancelled',
141
+ body: `The ride was cancelled by the ${cancelledBy}. ${
142
+ (fields.cancellationFee as number) > 0
143
+ ? `Cancellation fee: $${fields.cancellationFee}`
144
+ : 'No cancellation fee.'
145
+ }`,
146
+ channels: ['push', 'in_app'],
147
+ data: {
148
+ type: 'ride_cancelled',
149
+ rideId: instance.id,
150
+ cancelledBy,
151
+ cancellationFee: fields.cancellationFee,
152
+ },
153
+ });
154
+ }
155
+
156
+ return { success: true, data: { notified: targetUserId ? 'counterparty' : 'none', event: 'cancellation' } };
157
+ }
158
+
159
+ /** Send safety alert to emergency contacts */
160
+ export async function sendSafetyAlert(ctx: TransitionContext): Promise<ActionResult> {
161
+ const { instance, env } = ctx;
162
+ const fields = instance.fields as Record<string, unknown>;
163
+
164
+ await env.emit('safety:alert', {
165
+ rideId: instance.id,
166
+ riderId: fields.riderId,
167
+ driverId: fields.driverId,
168
+ location: {
169
+ latitude: fields.driverLatitude,
170
+ longitude: fields.driverLongitude,
171
+ },
172
+ timestamp: new Date().toISOString(),
173
+ });
174
+
175
+ return { success: true, data: { event: 'safety_alert', emergencyContacted: true } };
176
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @workflow slug="uber-rideshare"
3
+ * @description Payment processing — authorization, capture, settlement, refund, and payout
4
+ */
5
+
6
+ import type { TransitionContext, ActionResult } from '@mindmatrix/react';
7
+
8
+ /** Authorize a payment hold before ride starts */
9
+ export async function authorizePayment(ctx: TransitionContext): Promise<ActionResult> {
10
+ const { instance, env } = ctx;
11
+ const fields = instance.fields as Record<string, unknown>;
12
+
13
+ // Pre-authorize for estimated fare + 20% buffer
14
+ const estimatedFare = fields.estimatedFare as number;
15
+ const authAmount = Math.round(estimatedFare * 1.2 * 100) / 100;
16
+
17
+ // Mock processor call — in production this calls Stripe/Adyen
18
+ const processorTransactionId = `txn_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
19
+ const authorizationCode = `auth_${Math.random().toString(36).slice(2, 10)}`;
20
+
21
+ await env.emit('payment:authorized', {
22
+ rideId: fields.rideId,
23
+ amount: authAmount,
24
+ processorTransactionId,
25
+ });
26
+
27
+ return {
28
+ success: true,
29
+ data: {
30
+ status: 'authorized',
31
+ processorTransactionId,
32
+ authorizationCode,
33
+ totalAmount: authAmount,
34
+ authorizedAt: new Date().toISOString(),
35
+ },
36
+ };
37
+ }
38
+
39
+ /** Capture the actual fare after ride completion */
40
+ export async function capturePayment(ctx: TransitionContext): Promise<ActionResult> {
41
+ const { instance, env } = ctx;
42
+ const fields = instance.fields as Record<string, unknown>;
43
+
44
+ const actualFare = fields.actualFare as number;
45
+ const tipAmount = (fields.tipAmount as number) || 0;
46
+ const totalCapture = actualFare + tipAmount;
47
+
48
+ // Calculate tax
49
+ const taxRate = 8.875;
50
+ const taxAmount = Math.round(totalCapture * (taxRate / 100) * 100) / 100;
51
+
52
+ // Platform split: 25% of fare (not tip)
53
+ const platformFeePercent = 25;
54
+ const platformFee = Math.round(actualFare * (platformFeePercent / 100) * 100) / 100;
55
+ const driverPayout = Math.round((actualFare - platformFee + tipAmount) * 100) / 100;
56
+
57
+ // Generate receipt
58
+ const invoiceNumber = `INV-${new Date().getFullYear()}-${String(Date.now()).slice(-8)}`;
59
+ const receiptUrl = `/receipts/${invoiceNumber}`;
60
+
61
+ await env.emit('payment:captured', {
62
+ rideId: fields.rideId,
63
+ amount: totalCapture,
64
+ driverPayout,
65
+ platformFee,
66
+ });
67
+
68
+ return {
69
+ success: true,
70
+ data: {
71
+ status: 'captured',
72
+ totalAmount: Math.round(totalCapture * 100) / 100,
73
+ taxAmount,
74
+ taxRate,
75
+ platformFee,
76
+ platformFeePercent,
77
+ driverPayout,
78
+ capturedAt: new Date().toISOString(),
79
+ invoiceNumber,
80
+ receiptUrl,
81
+ },
82
+ };
83
+ }
84
+
85
+ /** Settle payment — transfer funds to driver account */
86
+ export async function settlePayment(ctx: TransitionContext): Promise<ActionResult> {
87
+ const { instance, env } = ctx;
88
+ const fields = instance.fields as Record<string, unknown>;
89
+
90
+ const driverPayout = fields.driverPayout as number;
91
+ const driverId = fields.driverId as string;
92
+ const payoutId = `po_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
93
+
94
+ // Credit driver's earnings balance
95
+ await env.update('uber-user', driverId, {
96
+ earningsBalance: { $increment: driverPayout },
97
+ });
98
+
99
+ await env.emit('payment:settled', {
100
+ rideId: fields.rideId,
101
+ driverId,
102
+ payoutId,
103
+ amount: driverPayout,
104
+ });
105
+
106
+ return {
107
+ success: true,
108
+ data: {
109
+ status: 'settled',
110
+ payoutId,
111
+ payoutStatus: 'completed',
112
+ settledAt: new Date().toISOString(),
113
+ payoutCompletedAt: new Date().toISOString(),
114
+ },
115
+ };
116
+ }
117
+
118
+ /** Process a refund — full or partial */
119
+ export async function processRefund(ctx: TransitionContext): Promise<ActionResult> {
120
+ const { instance, env } = ctx;
121
+ const fields = instance.fields as Record<string, unknown>;
122
+
123
+ const refundAmount = fields.refundAmount as number;
124
+ const totalAmount = fields.totalAmount as number;
125
+ const isPartial = refundAmount < totalAmount;
126
+
127
+ // Reverse platform fee proportionally
128
+ const refundRatio = refundAmount / totalAmount;
129
+ const platformFeeRefund = Math.round((fields.platformFee as number) * refundRatio * 100) / 100;
130
+ const driverPayoutDeduction = Math.round((fields.driverPayout as number) * refundRatio * 100) / 100;
131
+
132
+ // Debit driver's earnings balance
133
+ const driverId = fields.driverId as string;
134
+ await env.update('uber-user', driverId, {
135
+ earningsBalance: { $increment: -driverPayoutDeduction },
136
+ });
137
+
138
+ // Credit rider's wallet
139
+ const riderId = fields.riderId as string;
140
+ await env.update('uber-user', riderId, {
141
+ walletBalance: { $increment: refundAmount },
142
+ });
143
+
144
+ await env.emit('payment:refunded', {
145
+ rideId: fields.rideId,
146
+ amount: refundAmount,
147
+ isPartial,
148
+ });
149
+
150
+ return {
151
+ success: true,
152
+ data: {
153
+ status: isPartial ? 'partially_refunded' : 'refunded',
154
+ refundAmount,
155
+ refundedAt: new Date().toISOString(),
156
+ },
157
+ };
158
+ }
159
+
160
+ /** Process driver payout to external bank account */
161
+ export async function processDriverPayout(ctx: TransitionContext): Promise<ActionResult> {
162
+ const { instance } = ctx;
163
+ const fields = instance.fields as Record<string, unknown>;
164
+
165
+ const driverId = fields.driverId as string;
166
+ const amount = fields.earningsBalance as number;
167
+
168
+ if (amount < 25) {
169
+ return { success: false, data: { reason: 'minimum_payout_not_met', minimum: 25, current: amount } };
170
+ }
171
+
172
+ const payoutId = `payout_${Date.now()}`;
173
+
174
+ return {
175
+ success: true,
176
+ data: {
177
+ payoutId,
178
+ amount,
179
+ driverId,
180
+ payoutStatus: 'processing',
181
+ payoutScheduledAt: new Date().toISOString(),
182
+ },
183
+ };
184
+ }