@mmapp/react-compiler 0.1.0-alpha.6 → 0.1.0-alpha.9

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 (103) hide show
  1. package/dist/auth-3UK75242.mjs +17 -0
  2. package/dist/babel/index.d.mts +2 -2
  3. package/dist/babel/index.d.ts +2 -2
  4. package/dist/babel/index.js +5 -5
  5. package/dist/babel/index.mjs +1 -1
  6. package/dist/chunk-5FTDWKHH.mjs +244 -0
  7. package/dist/chunk-7JRAEFRB.mjs +7510 -0
  8. package/dist/chunk-7T6Q5KAA.mjs +7506 -0
  9. package/dist/chunk-ABYPKRSB.mjs +215 -0
  10. package/dist/chunk-BZEXUPDH.mjs +175 -0
  11. package/dist/chunk-HRYR54PT.mjs +175 -0
  12. package/dist/chunk-J3M4GUS7.mjs +161 -0
  13. package/dist/chunk-JRGFBWTN.mjs +2918 -0
  14. package/dist/chunk-O4AUS7EU.mjs +148 -0
  15. package/dist/chunk-R2DD5GTY.mjs +186 -0
  16. package/dist/chunk-UDDTWG5J.mjs +734 -0
  17. package/dist/chunk-VLTKQDJ3.mjs +244 -0
  18. package/dist/chunk-WVYY32LD.mjs +939 -0
  19. package/dist/chunk-XDVM4YHX.mjs +3450 -0
  20. package/dist/chunk-Z2G5RZ4H.mjs +186 -0
  21. package/dist/chunk-ZE3KCHBM.mjs +2918 -0
  22. package/dist/cli/index.js +4350 -3206
  23. package/dist/cli/index.mjs +77 -179
  24. package/dist/codemod/cli.js +1 -1
  25. package/dist/codemod/cli.mjs +1 -1
  26. package/dist/codemod/index.d.mts +3 -3
  27. package/dist/codemod/index.d.ts +3 -3
  28. package/dist/codemod/index.js +1 -1
  29. package/dist/codemod/index.mjs +1 -1
  30. package/dist/deploy-YAJGW6II.mjs +9 -0
  31. package/dist/dev-server-CrQ041KP.d.mts +79 -0
  32. package/dist/dev-server-CrQ041KP.d.ts +79 -0
  33. package/dist/dev-server.d.mts +2 -2
  34. package/dist/dev-server.d.ts +2 -2
  35. package/dist/dev-server.js +1218 -86
  36. package/dist/dev-server.mjs +4 -4
  37. package/dist/envelope-ChEkuHij.d.mts +265 -0
  38. package/dist/envelope-ChEkuHij.d.ts +265 -0
  39. package/dist/envelope.d.mts +2 -2
  40. package/dist/envelope.d.ts +2 -2
  41. package/dist/envelope.js +5 -5
  42. package/dist/envelope.mjs +2 -2
  43. package/dist/index-CEKyyazf.d.mts +104 -0
  44. package/dist/index-CEKyyazf.d.ts +104 -0
  45. package/dist/index.d.mts +8 -8
  46. package/dist/index.d.ts +8 -8
  47. package/dist/index.js +1266 -342
  48. package/dist/index.mjs +8 -8
  49. package/dist/init-7FJENUDK.mjs +407 -0
  50. package/dist/project-compiler-NNK32MPG.mjs +10 -0
  51. package/dist/project-compiler-ZB4RUYVL.mjs +10 -0
  52. package/dist/project-decompiler-U55HQUHW.mjs +7 -0
  53. package/dist/pull-KOL2QAYQ.mjs +109 -0
  54. package/dist/seed-KOGEPGOJ.mjs +154 -0
  55. package/dist/server-VW6UPCHO.mjs +277 -0
  56. package/dist/testing/index.d.mts +8 -8
  57. package/dist/testing/index.d.ts +8 -8
  58. package/dist/testing/index.js +5 -5
  59. package/dist/testing/index.mjs +1 -1
  60. package/dist/verify-BYHUKARQ.mjs +1833 -0
  61. package/dist/verify-OQDEQYMS.mjs +1833 -0
  62. package/dist/vite/index.d.mts +1 -1
  63. package/dist/vite/index.d.ts +1 -1
  64. package/dist/vite/index.js +5 -5
  65. package/dist/vite/index.mjs +2 -2
  66. package/examples/authentication/main.workflow.tsx +1 -1
  67. package/examples/authentication/mm.config.ts +1 -1
  68. package/examples/authentication/pages/LoginPage.tsx +2 -2
  69. package/examples/authentication/pages/SignupPage.tsx +2 -2
  70. package/examples/counter.workflow.tsx +1 -1
  71. package/examples/dashboard.workflow.tsx +1 -1
  72. package/examples/invoice-approval/actions/invoice.server.ts +1 -1
  73. package/examples/invoice-approval/main.workflow.tsx +1 -1
  74. package/examples/invoice-approval/mm.config.ts +1 -1
  75. package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +1 -1
  76. package/examples/invoice-approval/pages/InvoiceFormPage.tsx +1 -1
  77. package/examples/invoice-approval/pages/InvoiceListPage.tsx +1 -1
  78. package/examples/todo-app.workflow.tsx +1 -1
  79. package/examples/uber-app/actions/matching.server.ts +1 -1
  80. package/examples/uber-app/actions/notifications.server.ts +1 -1
  81. package/examples/uber-app/actions/payments.server.ts +1 -1
  82. package/examples/uber-app/actions/pricing.server.ts +1 -1
  83. package/examples/uber-app/app/admin/analytics.tsx +2 -2
  84. package/examples/uber-app/app/admin/fleet.tsx +2 -2
  85. package/examples/uber-app/app/admin/surge-pricing.tsx +2 -2
  86. package/examples/uber-app/app/driver/dashboard.tsx +2 -2
  87. package/examples/uber-app/app/driver/earnings.tsx +2 -2
  88. package/examples/uber-app/app/driver/navigation.tsx +2 -2
  89. package/examples/uber-app/app/driver/ride-acceptance.tsx +2 -2
  90. package/examples/uber-app/app/rider/home.tsx +2 -2
  91. package/examples/uber-app/app/rider/payment-methods.tsx +2 -2
  92. package/examples/uber-app/app/rider/ride-history.tsx +2 -2
  93. package/examples/uber-app/app/rider/ride-tracking.tsx +2 -2
  94. package/examples/uber-app/components/DriverCard.tsx +1 -1
  95. package/examples/uber-app/components/MapView.tsx +3 -3
  96. package/examples/uber-app/components/RatingStars.tsx +2 -2
  97. package/examples/uber-app/components/RideCard.tsx +1 -1
  98. package/examples/uber-app/mm.config.ts +1 -1
  99. package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +2 -2
  100. package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +2 -2
  101. package/examples/uber-app/workflows/payment-processing.workflow.tsx +2 -2
  102. package/examples/uber-app/workflows/ride-request.workflow.tsx +2 -2
  103. package/package.json +9 -13
package/dist/index.js CHANGED
@@ -2680,7 +2680,7 @@ var import_player_core, PROP_RULES, COMPONENT_RENAMES, RENAME_EXTRA_CONFIG, emit
2680
2680
  var init_pure_form_emitter = __esm({
2681
2681
  "src/babel/emitters/pure-form-emitter.ts"() {
2682
2682
  "use strict";
2683
- import_player_core = require("@mindmatrix/player-core");
2683
+ import_player_core = require("@mmapp/player-core");
2684
2684
  init_transition_extractor();
2685
2685
  init_experience_transform();
2686
2686
  PROP_RULES = {
@@ -5220,7 +5220,7 @@ function extractImperativeWorkflow(path, state) {
5220
5220
  const source = node.source.value;
5221
5221
  for (const spec of node.specifiers) {
5222
5222
  const localName = spec.local.name;
5223
- if (source.includes("@mmapp/react") || source.includes("@mindmatrix/react")) {
5223
+ if (source.includes("@mmapp/react") || source.includes("@mmapp/react")) {
5224
5224
  stdLibImports.add(localName);
5225
5225
  } else {
5226
5226
  importedFns.set(localName, source);
@@ -7413,7 +7413,7 @@ function createVisitor(options = {}) {
7413
7413
  if (mode === "strict" && STRICT_BANNED_HOOKS[hookName]) {
7414
7414
  const error = {
7415
7415
  code: STRICT_BANNED_HOOKS[hookName],
7416
- message: `${hookName}() is not allowed in strict mode. Use @mindmatrix/react effect hooks instead.`,
7416
+ message: `${hookName}() is not allowed in strict mode. Use @mmapp/react effect hooks instead.`,
7417
7417
  line: path.node.loc?.start.line,
7418
7418
  column: path.node.loc?.start.column,
7419
7419
  severity: "error"
@@ -7505,12 +7505,12 @@ function createVisitor(options = {}) {
7505
7505
  }
7506
7506
  }
7507
7507
  if (mode !== "strict") return;
7508
- if (source.startsWith("@mindmatrix/") || source.startsWith("@mmapp/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
7508
+ if (source.startsWith("@mmapp/") || source.startsWith("@mmapp/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
7509
7509
  return;
7510
7510
  }
7511
7511
  const error = {
7512
7512
  code: "STRICT_FORBIDDEN_IMPORT",
7513
- message: `Import from '${source}' is not allowed in strict mode. Only @mindmatrix/* and relative imports are permitted.`,
7513
+ message: `Import from '${source}' is not allowed in strict mode. Only @mmapp/* and relative imports are permitted.`,
7514
7514
  line: path.node.loc?.start.line,
7515
7515
  column: path.node.loc?.start.column,
7516
7516
  severity: "error"
@@ -10616,6 +10616,552 @@ var init_project_compiler = __esm({
10616
10616
  }
10617
10617
  });
10618
10618
 
10619
+ // src/cli/auth.ts
10620
+ var auth_exports = {};
10621
+ __export(auth_exports, {
10622
+ loadCredentials: () => loadCredentials,
10623
+ login: () => login,
10624
+ logout: () => logout,
10625
+ resolveToken: () => resolveToken,
10626
+ saveCredentials: () => saveCredentials,
10627
+ whoami: () => whoami
10628
+ });
10629
+ function loadCredentials() {
10630
+ if (!(0, import_fs4.existsSync)(CREDENTIALS_PATH)) return {};
10631
+ try {
10632
+ return JSON.parse((0, import_fs4.readFileSync)(CREDENTIALS_PATH, "utf-8"));
10633
+ } catch {
10634
+ return {};
10635
+ }
10636
+ }
10637
+ function saveCredentials(apiUrl, token) {
10638
+ (0, import_fs4.mkdirSync)(MMRC_DIR, { recursive: true, mode: 448 });
10639
+ const creds = loadCredentials();
10640
+ creds[apiUrl] = { token, savedAt: (/* @__PURE__ */ new Date()).toISOString() };
10641
+ (0, import_fs4.writeFileSync)(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8");
10642
+ try {
10643
+ const { chmodSync } = require("fs");
10644
+ chmodSync(CREDENTIALS_PATH, 384);
10645
+ } catch {
10646
+ }
10647
+ }
10648
+ function removeCredentials(apiUrl) {
10649
+ if (!(0, import_fs4.existsSync)(CREDENTIALS_PATH)) return;
10650
+ if (!apiUrl) {
10651
+ (0, import_fs4.unlinkSync)(CREDENTIALS_PATH);
10652
+ return;
10653
+ }
10654
+ const creds = loadCredentials();
10655
+ delete creds[apiUrl];
10656
+ if (Object.keys(creds).length === 0) {
10657
+ (0, import_fs4.unlinkSync)(CREDENTIALS_PATH);
10658
+ } else {
10659
+ (0, import_fs4.writeFileSync)(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8");
10660
+ }
10661
+ }
10662
+ function resolveToken(apiUrl, explicitToken) {
10663
+ if (explicitToken) return explicitToken;
10664
+ const envToken = process.env.MMRC_TOKEN;
10665
+ if (envToken) return envToken;
10666
+ const creds = loadCredentials();
10667
+ const entry = creds[apiUrl];
10668
+ if (entry?.token) return entry.token;
10669
+ return null;
10670
+ }
10671
+ function prompt(question, hidden = false) {
10672
+ return new Promise((resolve3) => {
10673
+ const rl = (0, import_readline.createInterface)({
10674
+ input: process.stdin,
10675
+ output: process.stdout
10676
+ });
10677
+ if (hidden && process.stdin.isTTY) {
10678
+ const origWrite = process.stdout.write.bind(process.stdout);
10679
+ process.stdout.write = ((chunk, encodingOrCb, cb) => {
10680
+ if (typeof chunk === "string" && chunk.includes(question)) {
10681
+ return origWrite(chunk, encodingOrCb, cb);
10682
+ }
10683
+ if (typeof chunk === "string" && !chunk.includes("\n")) {
10684
+ return true;
10685
+ }
10686
+ return origWrite(chunk, encodingOrCb, cb);
10687
+ });
10688
+ rl.question(question, (answer) => {
10689
+ process.stdout.write = origWrite;
10690
+ console.log();
10691
+ rl.close();
10692
+ resolve3(answer.trim());
10693
+ });
10694
+ } else {
10695
+ rl.question(question, (answer) => {
10696
+ rl.close();
10697
+ resolve3(answer.trim());
10698
+ });
10699
+ }
10700
+ });
10701
+ }
10702
+ async function login(apiUrl, email, password) {
10703
+ if (!email) {
10704
+ email = await prompt("Email: ");
10705
+ }
10706
+ if (!password) {
10707
+ password = await prompt("Password: ", true);
10708
+ }
10709
+ if (!email || !password) {
10710
+ throw new Error("Email and password are required");
10711
+ }
10712
+ console.log(`[mmrc] Logging in to ${apiUrl}...`);
10713
+ const res = await fetch(`${apiUrl}/auth/login`, {
10714
+ method: "POST",
10715
+ headers: { "Content-Type": "application/json" },
10716
+ body: JSON.stringify({ email, password })
10717
+ });
10718
+ if (!res.ok) {
10719
+ const text = await res.text();
10720
+ throw new Error(`Login failed: ${res.status} ${text}`);
10721
+ }
10722
+ const data = await res.json();
10723
+ const token = data.token ?? data.access_token ?? data.accessToken;
10724
+ if (!token) {
10725
+ throw new Error("Login succeeded but no token in response");
10726
+ }
10727
+ saveCredentials(apiUrl, token);
10728
+ const userName = data.name ?? data.user?.name ?? data.user?.email ?? email;
10729
+ console.log(`[mmrc] Logged in as ${userName}`);
10730
+ console.log(`[mmrc] Token saved to ${CREDENTIALS_PATH}`);
10731
+ return token;
10732
+ }
10733
+ function logout(apiUrl) {
10734
+ if (apiUrl) {
10735
+ removeCredentials(apiUrl);
10736
+ console.log(`[mmrc] Credentials removed for ${apiUrl}`);
10737
+ } else {
10738
+ removeCredentials();
10739
+ console.log("[mmrc] All saved credentials removed");
10740
+ }
10741
+ }
10742
+ async function whoami(apiUrl) {
10743
+ const token = resolveToken(apiUrl);
10744
+ if (!token) {
10745
+ console.log("[mmrc] Not logged in. Run `mmrc login` to authenticate.");
10746
+ return;
10747
+ }
10748
+ try {
10749
+ const res = await fetch(`${apiUrl}/auth/me`, {
10750
+ headers: { Authorization: `Bearer ${token}` }
10751
+ });
10752
+ if (!res.ok) {
10753
+ if (res.status === 401) {
10754
+ console.log("[mmrc] Token is expired or invalid. Run `mmrc login` to re-authenticate.");
10755
+ return;
10756
+ }
10757
+ console.log(`[mmrc] Failed to fetch user info: ${res.status}`);
10758
+ return;
10759
+ }
10760
+ const user = await res.json();
10761
+ console.log(`[mmrc] Logged in to ${apiUrl}`);
10762
+ console.log(` Name: ${user.name ?? "(unknown)"}`);
10763
+ console.log(` Email: ${user.email ?? "(unknown)"}`);
10764
+ if (user.id) console.log(` ID: ${user.id}`);
10765
+ if (user.role) console.log(` Role: ${user.role}`);
10766
+ } catch (error) {
10767
+ console.log(`[mmrc] Could not connect to ${apiUrl}: ${error.message}`);
10768
+ }
10769
+ }
10770
+ var import_fs4, import_path3, import_os, import_readline, MMRC_DIR, CREDENTIALS_PATH;
10771
+ var init_auth = __esm({
10772
+ "src/cli/auth.ts"() {
10773
+ "use strict";
10774
+ import_fs4 = require("fs");
10775
+ import_path3 = require("path");
10776
+ import_os = require("os");
10777
+ import_readline = require("readline");
10778
+ MMRC_DIR = (0, import_path3.join)((0, import_os.homedir)(), ".mmrc");
10779
+ CREDENTIALS_PATH = (0, import_path3.join)(MMRC_DIR, "credentials.json");
10780
+ }
10781
+ });
10782
+
10783
+ // src/cli/deploy.ts
10784
+ var deploy_exports = {};
10785
+ __export(deploy_exports, {
10786
+ deploy: () => deploy,
10787
+ syncServices: () => syncServices
10788
+ });
10789
+ async function deploy(options) {
10790
+ const dir = options.dir ?? "dist/workflows";
10791
+ const targetLabel = options.targetName ? ` (target: ${options.targetName})` : "";
10792
+ console.log(`[mindmatrix-react] Deploying workflows from ${dir} to ${options.apiUrl}${targetLabel}...`);
10793
+ const files = await (0, import_glob2.glob)(`${dir}/**/*.workflow.json`);
10794
+ if (files.length === 0) {
10795
+ console.log(`[mindmatrix-react] No workflow files found in ${dir}`);
10796
+ return { created: [], updated: [], versioned: [], skipped: [], failed: [] };
10797
+ }
10798
+ const result = {
10799
+ created: [],
10800
+ updated: [],
10801
+ versioned: [],
10802
+ skipped: [],
10803
+ failed: []
10804
+ };
10805
+ const deployedIRs = [];
10806
+ for (const file2 of files) {
10807
+ try {
10808
+ const ir = JSON.parse((0, import_fs5.readFileSync)(file2, "utf-8"));
10809
+ const slug = ir.slug;
10810
+ if (options.dryRun) {
10811
+ console.log(` [dry-run] Would deploy ${slug} (${(0, import_path4.basename)(file2)})`);
10812
+ continue;
10813
+ }
10814
+ const existing = await fetchExistingDefinition(options.apiUrl, options.token, slug);
10815
+ if (!existing) {
10816
+ await createDefinition(options.apiUrl, options.token, ir);
10817
+ console.log(` \u2713 ${slug} (created)`);
10818
+ result.created.push(slug);
10819
+ } else if (existing.instanceCount === 0 || options.force) {
10820
+ await updateDefinition(options.apiUrl, options.token, existing.id, ir);
10821
+ console.log(` \u2713 ${slug} (updated)`);
10822
+ result.updated.push(slug);
10823
+ } else {
10824
+ const newVersion = bumpVersion(existing.version);
10825
+ ir.version = newVersion;
10826
+ await createDefinition(options.apiUrl, options.token, ir);
10827
+ console.log(` \u2713 ${slug} v${newVersion} (new version, ${existing.instanceCount} instances on v${existing.version})`);
10828
+ result.versioned.push(slug);
10829
+ }
10830
+ deployedIRs.push(ir);
10831
+ } catch (error) {
10832
+ const slug = (0, import_path4.basename)(file2).replace(".workflow.json", "");
10833
+ const msg = error.message;
10834
+ console.error(` \u2717 ${slug}: ${msg}`);
10835
+ result.failed.push({ slug, error: msg });
10836
+ }
10837
+ }
10838
+ if (!options.dryRun) {
10839
+ for (const ir of deployedIRs) {
10840
+ const serviceResult = await syncServices(options.apiUrl, options.token, ir);
10841
+ if (serviceResult) {
10842
+ if (!result.services) {
10843
+ result.services = { registered: [], updated: [], failed: [] };
10844
+ }
10845
+ result.services.registered.push(...serviceResult.registered);
10846
+ result.services.updated.push(...serviceResult.updated);
10847
+ result.services.failed.push(...serviceResult.failed);
10848
+ }
10849
+ }
10850
+ }
10851
+ if (options.reportFile) {
10852
+ (0, import_fs5.writeFileSync)(options.reportFile, JSON.stringify(result, null, 2), "utf-8");
10853
+ console.log(`
10854
+ Report written to ${options.reportFile}`);
10855
+ }
10856
+ const total = result.created.length + result.updated.length + result.versioned.length;
10857
+ console.log(
10858
+ `
10859
+ [mindmatrix-react] Deployed ${total} workflows (${result.created.length} created, ${result.updated.length} updated, ${result.versioned.length} versioned, ${result.failed.length} failed)`
10860
+ );
10861
+ if (result.services) {
10862
+ const svcTotal = result.services.registered.length + result.services.updated.length;
10863
+ if (svcTotal > 0 || result.services.failed.length > 0) {
10864
+ console.log(
10865
+ `[mindmatrix-react] Synced ${svcTotal} services (${result.services.registered.length} registered, ${result.services.updated.length} updated, ${result.services.failed.length} failed)`
10866
+ );
10867
+ }
10868
+ }
10869
+ return result;
10870
+ }
10871
+ async function fetchExistingDefinition(apiUrl, token, slug) {
10872
+ try {
10873
+ const res = await fetch(`${apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`, {
10874
+ headers: { Authorization: `Bearer ${token}` }
10875
+ });
10876
+ if (!res.ok) return null;
10877
+ const data = await res.json();
10878
+ const definitions = Array.isArray(data) ? data : data.items ?? data.data;
10879
+ if (!definitions || definitions.length === 0) return null;
10880
+ const def = definitions[0];
10881
+ return {
10882
+ id: def.id,
10883
+ slug: def.slug,
10884
+ version: def.version || "0.1.0",
10885
+ instanceCount: def.instanceCount ?? def.instance_count ?? 0
10886
+ };
10887
+ } catch {
10888
+ return null;
10889
+ }
10890
+ }
10891
+ async function createDefinition(apiUrl, token, ir) {
10892
+ const res = await fetch(`${apiUrl}/workflow/definitions`, {
10893
+ method: "POST",
10894
+ headers: {
10895
+ "Content-Type": "application/json",
10896
+ Authorization: `Bearer ${token}`
10897
+ },
10898
+ body: JSON.stringify(ir)
10899
+ });
10900
+ if (!res.ok) {
10901
+ const errorText = await res.text();
10902
+ throw new Error(`Create failed: ${res.status} ${errorText}`);
10903
+ }
10904
+ }
10905
+ async function updateDefinition(apiUrl, token, id, ir) {
10906
+ const { slug: _slug, ...updatePayload } = ir;
10907
+ const res = await fetch(`${apiUrl}/workflow/definitions/${id}`, {
10908
+ method: "PATCH",
10909
+ headers: {
10910
+ "Content-Type": "application/json",
10911
+ Authorization: `Bearer ${token}`
10912
+ },
10913
+ body: JSON.stringify(updatePayload)
10914
+ });
10915
+ if (!res.ok) {
10916
+ const errorText = await res.text();
10917
+ throw new Error(`Update failed: ${res.status} ${errorText}`);
10918
+ }
10919
+ }
10920
+ function bumpVersion(version) {
10921
+ const parts = version.split(".");
10922
+ if (parts.length !== 3) return `${version}.1`;
10923
+ const patch = parseInt(parts[2], 10) || 0;
10924
+ return `${parts[0]}.${parts[1]}.${patch + 1}`;
10925
+ }
10926
+ async function syncServices(apiUrl, token, ir) {
10927
+ const metadata = ir.metadata;
10928
+ const orchestration = metadata?.orchestration;
10929
+ const services = orchestration?.services;
10930
+ if (!services || Object.keys(services).length === 0) return null;
10931
+ const result = { registered: [], updated: [], failed: [] };
10932
+ for (const [name, config] of Object.entries(services)) {
10933
+ try {
10934
+ const registration = {
10935
+ name,
10936
+ connection: {
10937
+ type: config.type || "webhook",
10938
+ url: config.url,
10939
+ queue: config.queue
10940
+ },
10941
+ actions: config.actions || [],
10942
+ labels: config.labels || {}
10943
+ };
10944
+ const existing = await fetchExistingService(apiUrl, token, name);
10945
+ if (existing) {
10946
+ await fetch(`${apiUrl}/services/${existing.id}`, {
10947
+ method: "PATCH",
10948
+ headers: {
10949
+ "Content-Type": "application/json",
10950
+ Authorization: `Bearer ${token}`
10951
+ },
10952
+ body: JSON.stringify(registration)
10953
+ });
10954
+ console.log(` \u2713 service: ${name} (updated)`);
10955
+ result.updated.push(name);
10956
+ } else {
10957
+ const res = await fetch(`${apiUrl}/services`, {
10958
+ method: "POST",
10959
+ headers: {
10960
+ "Content-Type": "application/json",
10961
+ Authorization: `Bearer ${token}`
10962
+ },
10963
+ body: JSON.stringify(registration)
10964
+ });
10965
+ if (!res.ok) {
10966
+ const errorText = await res.text();
10967
+ throw new Error(`Register failed: ${res.status} ${errorText}`);
10968
+ }
10969
+ console.log(` \u2713 service: ${name} (registered)`);
10970
+ result.registered.push(name);
10971
+ }
10972
+ } catch (error) {
10973
+ const msg = error.message;
10974
+ console.error(` \u2717 service: ${name}: ${msg}`);
10975
+ result.failed.push(name);
10976
+ }
10977
+ }
10978
+ return result;
10979
+ }
10980
+ async function fetchExistingService(apiUrl, token, name) {
10981
+ try {
10982
+ const res = await fetch(`${apiUrl}/services?name=${encodeURIComponent(name)}`, {
10983
+ headers: { Authorization: `Bearer ${token}` }
10984
+ });
10985
+ if (!res.ok) return null;
10986
+ const data = await res.json();
10987
+ const servicesList = Array.isArray(data) ? data : data.services ?? data.items ?? data.data;
10988
+ if (!servicesList || servicesList.length === 0) return null;
10989
+ const found = servicesList.find((s) => s.name === name);
10990
+ return found ? { id: found.id, name: found.name } : null;
10991
+ } catch {
10992
+ return null;
10993
+ }
10994
+ }
10995
+ var import_glob2, import_fs5, import_path4;
10996
+ var init_deploy = __esm({
10997
+ "src/cli/deploy.ts"() {
10998
+ "use strict";
10999
+ import_glob2 = require("glob");
11000
+ import_fs5 = require("fs");
11001
+ import_path4 = require("path");
11002
+ }
11003
+ });
11004
+
11005
+ // src/cli/seed.ts
11006
+ var seed_exports = {};
11007
+ __export(seed_exports, {
11008
+ generateFieldValue: () => generateFieldValue,
11009
+ generateInstanceData: () => generateInstanceData,
11010
+ seedInstances: () => seedInstances
11011
+ });
11012
+ function randomInt(min, max) {
11013
+ return Math.floor(Math.random() * (max - min + 1)) + min;
11014
+ }
11015
+ function randomPick(arr) {
11016
+ return arr[Math.floor(Math.random() * arr.length)];
11017
+ }
11018
+ function loremSentence(words = 5) {
11019
+ const result = [];
11020
+ for (let i = 0; i < words; i++) result.push(randomPick(LOREM_WORDS));
11021
+ const s = result.join(" ");
11022
+ return s.charAt(0).toUpperCase() + s.slice(1);
11023
+ }
11024
+ function generateFieldValue(field, index) {
11025
+ if (field.default_value !== void 0 && field.default_value !== null) {
11026
+ return field.default_value;
11027
+ }
11028
+ if (field.options && field.options.length > 0) {
11029
+ return field.options[index % field.options.length].value;
11030
+ }
11031
+ const ft = (field.field_type ?? field.type ?? "text").toLowerCase();
11032
+ switch (ft) {
11033
+ case "text":
11034
+ case "string":
11035
+ case "textarea":
11036
+ case "rich_text": {
11037
+ const name = field.name.toLowerCase();
11038
+ if (name.includes("email")) return `${randomPick(FIRST_NAMES).toLowerCase()}${++_counter}@${randomPick(DOMAINS)}`;
11039
+ if (name.includes("name") && name.includes("first")) return randomPick(FIRST_NAMES);
11040
+ if (name.includes("name") && name.includes("last")) return randomPick(LAST_NAMES);
11041
+ if (name.includes("name") || name === "title") return `${randomPick(FIRST_NAMES)} ${randomPick(LAST_NAMES)}`;
11042
+ if (name.includes("company") || name.includes("org")) return randomPick(COMPANIES);
11043
+ if (name.includes("phone")) return `+1-555-${randomInt(100, 999)}-${randomInt(1e3, 9999)}`;
11044
+ if (name.includes("url") || name.includes("website")) return `https://${randomPick(DOMAINS)}/${field.name}`;
11045
+ if (name.includes("description") || name.includes("note") || name.includes("comment")) return loremSentence(randomInt(8, 15));
11046
+ if (name.includes("address")) return `${randomInt(100, 9999)} ${loremSentence(2)} St`;
11047
+ return loremSentence(randomInt(2, 5));
11048
+ }
11049
+ case "number":
11050
+ case "numeric":
11051
+ case "integer":
11052
+ case "int": {
11053
+ const name = field.name.toLowerCase();
11054
+ if (name.includes("price") || name.includes("amount") || name.includes("cost") || name.includes("salary"))
11055
+ return randomInt(1e3, 99999) / 100;
11056
+ if (name.includes("age")) return randomInt(18, 65);
11057
+ if (name.includes("quantity") || name.includes("count") || name.includes("qty")) return randomInt(1, 100);
11058
+ if (name.includes("percent") || name.includes("rate")) return randomInt(1, 100);
11059
+ return randomInt(1, 1e3);
11060
+ }
11061
+ case "currency":
11062
+ case "decimal":
11063
+ return randomInt(100, 999999) / 100;
11064
+ case "boolean":
11065
+ case "bool":
11066
+ case "checkbox":
11067
+ case "toggle":
11068
+ return index % 2 === 0;
11069
+ case "date":
11070
+ case "datetime":
11071
+ case "timestamptz": {
11072
+ const d = /* @__PURE__ */ new Date();
11073
+ d.setDate(d.getDate() - randomInt(0, 365));
11074
+ return d.toISOString().split("T")[0];
11075
+ }
11076
+ case "select":
11077
+ case "enum":
11078
+ case "multi_select":
11079
+ return field.options?.[index % (field.options?.length || 1)]?.value ?? "option_1";
11080
+ case "email":
11081
+ return `${randomPick(FIRST_NAMES).toLowerCase()}${++_counter}@${randomPick(DOMAINS)}`;
11082
+ case "url":
11083
+ return `https://${randomPick(DOMAINS)}/${field.name}`;
11084
+ case "json":
11085
+ case "object":
11086
+ return {};
11087
+ case "array":
11088
+ return [];
11089
+ default:
11090
+ return loremSentence(3);
11091
+ }
11092
+ }
11093
+ function generateInstanceData(fields, index) {
11094
+ const data = {};
11095
+ for (const field of fields) {
11096
+ if (field.name === "id" || field.name === "created_at" || field.name === "updated_at") continue;
11097
+ data[field.name] = generateFieldValue(field, index);
11098
+ }
11099
+ return data;
11100
+ }
11101
+ async function seedInstances(options) {
11102
+ const dir = options.dir ?? "dist/workflows";
11103
+ const count = options.count ?? 7;
11104
+ const result = { created: 0, definitions: 0, errors: [] };
11105
+ const files = await (0, import_glob3.glob)(`${dir}/**/*.workflow.json`);
11106
+ if (files.length === 0) return result;
11107
+ for (const file2 of files) {
11108
+ let def;
11109
+ try {
11110
+ def = JSON.parse((0, import_fs6.readFileSync)(file2, "utf-8"));
11111
+ } catch {
11112
+ continue;
11113
+ }
11114
+ if (!def.slug || !def.fields || def.fields.length === 0) continue;
11115
+ const startState = def.states?.find((s) => s.state_type === "START")?.name ?? def.states?.[0]?.name ?? "initial";
11116
+ let defCreated = 0;
11117
+ for (let i = 0; i < count; i++) {
11118
+ const stateData = generateInstanceData(def.fields, i);
11119
+ try {
11120
+ const resp = await fetch(`${options.apiUrl}/workflow/instances`, {
11121
+ method: "POST",
11122
+ headers: {
11123
+ "Content-Type": "application/json",
11124
+ "Authorization": `Bearer ${options.token}`
11125
+ },
11126
+ body: JSON.stringify({
11127
+ definition_slug: def.slug,
11128
+ initial_state: startState,
11129
+ state_data: stateData
11130
+ })
11131
+ });
11132
+ if (resp.ok) {
11133
+ defCreated++;
11134
+ } else {
11135
+ const errText = await resp.text().catch(() => resp.statusText);
11136
+ result.errors.push(`${def.slug}[${i}]: ${resp.status} ${errText}`);
11137
+ }
11138
+ } catch (e) {
11139
+ result.errors.push(`${def.slug}[${i}]: ${e instanceof Error ? e.message : String(e)}`);
11140
+ }
11141
+ }
11142
+ if (defCreated > 0) {
11143
+ result.definitions++;
11144
+ result.created += defCreated;
11145
+ console.log(` [seed] ${def.slug}: ${defCreated} instances created`);
11146
+ }
11147
+ }
11148
+ return result;
11149
+ }
11150
+ var import_fs6, import_glob3, FIRST_NAMES, LAST_NAMES, COMPANIES, LOREM_WORDS, DOMAINS, _counter;
11151
+ var init_seed = __esm({
11152
+ "src/cli/seed.ts"() {
11153
+ "use strict";
11154
+ import_fs6 = require("fs");
11155
+ import_glob3 = require("glob");
11156
+ FIRST_NAMES = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry"];
11157
+ LAST_NAMES = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis"];
11158
+ COMPANIES = ["Acme Corp", "TechStart Inc", "GlobalTrade Ltd", "DataFlow Systems", "CloudPeak"];
11159
+ LOREM_WORDS = ["lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", "tempor"];
11160
+ DOMAINS = ["example.com", "test.org", "demo.io", "sample.net"];
11161
+ _counter = 0;
11162
+ }
11163
+ });
11164
+
10619
11165
  // src/index.ts
10620
11166
  var index_exports = {};
10621
11167
  __export(index_exports, {
@@ -11116,7 +11662,7 @@ function buildJSXTree(node, imports, symbols) {
11116
11662
  }
11117
11663
  const componentName = node.component;
11118
11664
  if (REACT_ATOMS.has(componentName)) {
11119
- addImport(imports, "@mindmatrix/react", componentName);
11665
+ addImport(imports, "@mmapp/react", componentName);
11120
11666
  }
11121
11667
  const attributes = [];
11122
11668
  if (node.config) {
@@ -11161,7 +11707,7 @@ function buildJSXTree(node, imports, symbols) {
11161
11707
  isSelfClosing
11162
11708
  );
11163
11709
  if (node.visible_when) {
11164
- addImport(imports, "@mindmatrix/react", "Show");
11710
+ addImport(imports, "@mmapp/react", "Show");
11165
11711
  return t8.jsxElement(
11166
11712
  t8.jsxOpeningElement(
11167
11713
  t8.jsxIdentifier("Show"),
@@ -11242,7 +11788,7 @@ function fieldTypeAnnotation(field) {
11242
11788
  }
11243
11789
  function emitFieldDeclarations(fields, imports) {
11244
11790
  if (fields.length === 0) return [];
11245
- addImport2(imports, "@mindmatrix/react", "useState");
11791
+ addImport2(imports, "@mmapp/react", "useState");
11246
11792
  const statements = [];
11247
11793
  for (const field of fields) {
11248
11794
  if (field.computed) continue;
@@ -11306,7 +11852,7 @@ function emitStateEffects(states, imports) {
11306
11852
  const statements = [];
11307
11853
  for (const state of states) {
11308
11854
  if (state.on_enter.length > 0) {
11309
- addImport2(imports, "@mindmatrix/react", "useOnEnter");
11855
+ addImport2(imports, "@mmapp/react", "useOnEnter");
11310
11856
  statements.push(
11311
11857
  t9.expressionStatement(
11312
11858
  t9.callExpression(t9.identifier("useOnEnter"), [
@@ -11317,7 +11863,7 @@ function emitStateEffects(states, imports) {
11317
11863
  );
11318
11864
  }
11319
11865
  if (state.on_exit.length > 0) {
11320
- addImport2(imports, "@mindmatrix/react", "useOnExit");
11866
+ addImport2(imports, "@mmapp/react", "useOnExit");
11321
11867
  statements.push(
11322
11868
  t9.expressionStatement(
11323
11869
  t9.callExpression(t9.identifier("useOnExit"), [
@@ -11328,7 +11874,7 @@ function emitStateEffects(states, imports) {
11328
11874
  );
11329
11875
  }
11330
11876
  if (state.during.length > 0) {
11331
- addImport2(imports, "@mindmatrix/react", "useWhileIn");
11877
+ addImport2(imports, "@mmapp/react", "useWhileIn");
11332
11878
  for (const during of state.during) {
11333
11879
  const args = [
11334
11880
  t9.stringLiteral(state.name)
@@ -11349,7 +11895,7 @@ function emitStateEffects(states, imports) {
11349
11895
  }
11350
11896
  function emitTransitionDeclarations(transitions, imports) {
11351
11897
  if (transitions.length === 0) return [];
11352
- addImport2(imports, "@mindmatrix/react", "useTransition");
11898
+ addImport2(imports, "@mmapp/react", "useTransition");
11353
11899
  const correctedTransitions = correctFromFields(transitions);
11354
11900
  const statements = [];
11355
11901
  for (const transition of correctedTransitions) {
@@ -11584,7 +12130,7 @@ function emitSingleCondition(cond) {
11584
12130
  function emitRoleDeclarations(metadata, imports) {
11585
12131
  const roleDeps = metadata?.roleDependencies;
11586
12132
  if (!roleDeps || roleDeps.length === 0) return [];
11587
- addImport2(imports, "@mindmatrix/react", "useRole");
12133
+ addImport2(imports, "@mmapp/react", "useRole");
11588
12134
  const statements = [];
11589
12135
  for (const role of roleDeps) {
11590
12136
  const varName = `is${toPascalCase(role)}`;
@@ -11605,7 +12151,7 @@ function emitQueryDeclarations(metadata, imports) {
11605
12151
  const modelImports = metadata?.modelImports;
11606
12152
  const addedModelImports = /* @__PURE__ */ new Set();
11607
12153
  if (dataSources && dataSources.length > 0) {
11608
- addImport2(imports, "@mindmatrix/react", "useQuery");
12154
+ addImport2(imports, "@mmapp/react", "useQuery");
11609
12155
  const usedVarNames = /* @__PURE__ */ new Set();
11610
12156
  for (const ds of dataSources) {
11611
12157
  if (ds.type !== "workflow") continue;
@@ -11672,7 +12218,7 @@ function emitQueryDeclarations(metadata, imports) {
11672
12218
  }
11673
12219
  const mutationTargets = metadata?.mutationTargets;
11674
12220
  if (mutationTargets && mutationTargets.length > 0) {
11675
- addImport2(imports, "@mindmatrix/react", "useMutation");
12221
+ addImport2(imports, "@mmapp/react", "useMutation");
11676
12222
  for (const slug of mutationTargets) {
11677
12223
  const modelPath = modelImports?.[slug];
11678
12224
  const modelVarName2 = modelPath ? `${toCamelCase2(slug.replace(/-/g, "_"))}Model` : void 0;
@@ -11697,7 +12243,7 @@ function emitQueryDeclarations(metadata, imports) {
11697
12243
  function emitChangeWatchers(metadata, imports) {
11698
12244
  const watchers = metadata?.fieldWatchers;
11699
12245
  if (!watchers || watchers.length === 0) return [];
11700
- addImport2(imports, "@mindmatrix/react", "useOnChange");
12246
+ addImport2(imports, "@mmapp/react", "useOnChange");
11701
12247
  const statements = [];
11702
12248
  for (const watcher of watchers) {
11703
12249
  statements.push(
@@ -11713,7 +12259,7 @@ function emitChangeWatchers(metadata, imports) {
11713
12259
  }
11714
12260
  function emitEventSubscriptions(onEvent, imports) {
11715
12261
  if (!onEvent || onEvent.length === 0) return [];
11716
- addImport2(imports, "@mindmatrix/react", "useOnEvent");
12262
+ addImport2(imports, "@mmapp/react", "useOnEvent");
11717
12263
  const statements = [];
11718
12264
  for (const sub of onEvent) {
11719
12265
  const actions = sub.actions.map((a, i) => ({
@@ -11740,7 +12286,7 @@ function emitEventSubscriptions(onEvent, imports) {
11740
12286
  function emitTransitionEffects(metadata, imports) {
11741
12287
  const effects = metadata?.transitionEffects;
11742
12288
  if (!effects || effects.length === 0) return [];
11743
- addImport2(imports, "@mindmatrix/react", "useOnTransition");
12289
+ addImport2(imports, "@mmapp/react", "useOnTransition");
11744
12290
  const statements = [];
11745
12291
  for (const effect of effects) {
11746
12292
  statements.push(
@@ -11771,7 +12317,7 @@ function emitLocalDefaultDeclarations(experience, existingFields, imports) {
11771
12317
  const camelName = toCamelCase2(key);
11772
12318
  if (emittedCamelNames.has(camelName)) continue;
11773
12319
  emittedCamelNames.add(camelName);
11774
- addImport2(imports, "@mindmatrix/react", "useState");
12320
+ addImport2(imports, "@mmapp/react", "useState");
11775
12321
  const setter = `set${toPascalCase(key)}`;
11776
12322
  let defaultExpr;
11777
12323
  if (value === void 0 || value === null) {
@@ -11984,7 +12530,7 @@ function generateServerActionFile(actions) {
11984
12530
  ` * Each receives a TransitionContext with instance data and utilities.`,
11985
12531
  ` */`,
11986
12532
  ``,
11987
- `import type { TransitionContext } from '@mindmatrix/react';`,
12533
+ `import type { TransitionContext } from '@mmapp/react';`,
11988
12534
  ``
11989
12535
  ];
11990
12536
  for (const action of actions) {
@@ -12057,7 +12603,7 @@ function generateConfigFile(def) {
12057
12603
  ` * Blueprint configuration for "${def.name || pascalCase(def.slug)}".`,
12058
12604
  ` */`,
12059
12605
  ``,
12060
- `import { defineBlueprint } from '@mindmatrix/react';`,
12606
+ `import { defineBlueprint } from '@mmapp/react';`,
12061
12607
  ``,
12062
12608
  `export default defineBlueprint({`,
12063
12609
  ` slug: '${def.slug}',`,
@@ -12152,7 +12698,7 @@ function generateMainFile(def, pages, hasModel, serverActionNames, options) {
12152
12698
  reactImports.add("Stack");
12153
12699
  if (reactImports.size > 0) {
12154
12700
  const sorted = [...reactImports].sort();
12155
- importLines.push(`import { ${sorted.join(", ")} } from '@mindmatrix/react';`);
12701
+ importLines.push(`import { ${sorted.join(", ")} } from '@mmapp/react';`);
12156
12702
  }
12157
12703
  if (hasModel) {
12158
12704
  const typeName = pascalCase(slug);
@@ -13349,27 +13895,580 @@ async function startWatchMode(options) {
13349
13895
  console.log(`
13350
13896
  [mindmatrix-react] Watching ${srcDir} for changes... (Ctrl+C to stop)
13351
13897
  `);
13352
- fsWatch(srcDir, { recursive: true }, (_event, filename) => {
13353
- if (!filename) return;
13354
- if (!filename.match(/\.(tsx?|jsx?)$/)) return;
13355
- if (filename.includes("node_modules") || filename.includes("dist")) return;
13356
- if (debounce) clearTimeout(debounce);
13357
- debounce = setTimeout(async () => {
13358
- const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
13359
- console.log(`
13360
- [${ts}] Change detected: ${filename} \u2014 recompiling...`);
13361
- try {
13362
- await build({ ...options, watch: false, skipTypeCheck: true });
13363
- } catch (e) {
13364
- console.error(`[mindmatrix-react] Rebuild failed:`, e.message);
13365
- }
13366
- }, 300);
13367
- });
13368
- return new Promise(() => {
13369
- });
13898
+ fsWatch(srcDir, { recursive: true }, (_event, filename) => {
13899
+ if (!filename) return;
13900
+ if (!filename.match(/\.(tsx?|jsx?)$/)) return;
13901
+ if (filename.includes("node_modules") || filename.includes("dist")) return;
13902
+ if (debounce) clearTimeout(debounce);
13903
+ debounce = setTimeout(async () => {
13904
+ const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
13905
+ console.log(`
13906
+ [${ts}] Change detected: ${filename} \u2014 recompiling...`);
13907
+ try {
13908
+ await build({ ...options, watch: false, skipTypeCheck: true });
13909
+ } catch (e) {
13910
+ console.error(`[mindmatrix-react] Rebuild failed:`, e.message);
13911
+ }
13912
+ }, 300);
13913
+ });
13914
+ return new Promise(() => {
13915
+ });
13916
+ }
13917
+
13918
+ // src/cli/local-server.ts
13919
+ var http = __toESM(require("http"));
13920
+ var import_node_crypto = require("crypto");
13921
+ var MemoryStore = class {
13922
+ constructor() {
13923
+ this.definitions = /* @__PURE__ */ new Map();
13924
+ this.instances = /* @__PURE__ */ new Map();
13925
+ this.slugIndex = /* @__PURE__ */ new Map();
13926
+ }
13927
+ // slug → id
13928
+ // ── Definitions ──────────────────────────────────────────────────────
13929
+ createDefinition(input) {
13930
+ if (this.slugIndex.has(input.slug)) {
13931
+ const existing = this.definitions.get(this.slugIndex.get(input.slug));
13932
+ if (existing) return existing;
13933
+ }
13934
+ const now = (/* @__PURE__ */ new Date()).toISOString();
13935
+ const def = {
13936
+ id: input.id ?? (0, import_node_crypto.randomUUID)(),
13937
+ slug: input.slug,
13938
+ name: input.name,
13939
+ version: input.version ?? "1.0.0",
13940
+ description: input.description ?? null,
13941
+ category: input.category ?? "workflow",
13942
+ fields: input.fields ?? [],
13943
+ states: input.states ?? [],
13944
+ transitions: input.transitions ?? [],
13945
+ roles: input.roles ?? [],
13946
+ experience: input.experience ?? null,
13947
+ metadata: input.metadata ?? {},
13948
+ child_definitions: input.child_definitions ?? [],
13949
+ is_immutable: input.is_immutable ?? false,
13950
+ tags: input.tags ?? [],
13951
+ inline_tags: input.inline_tags ?? [],
13952
+ created_at: now,
13953
+ updated_at: now
13954
+ };
13955
+ this.definitions.set(def.id, def);
13956
+ this.slugIndex.set(def.slug, def.id);
13957
+ return def;
13958
+ }
13959
+ getDefinition(idOrSlug) {
13960
+ const byId = this.definitions.get(idOrSlug);
13961
+ if (byId) return byId;
13962
+ const id = this.slugIndex.get(idOrSlug);
13963
+ if (id) return this.definitions.get(id);
13964
+ return void 0;
13965
+ }
13966
+ listDefinitions(opts) {
13967
+ let items = Array.from(this.definitions.values());
13968
+ if (opts?.category) {
13969
+ items = items.filter((d) => d.category === opts.category);
13970
+ }
13971
+ const total = items.length;
13972
+ const offset = opts?.offset ?? 0;
13973
+ const limit = opts?.limit ?? 50;
13974
+ items = items.slice(offset, offset + limit);
13975
+ return { items, total };
13976
+ }
13977
+ patchDefinition(id, patch) {
13978
+ const def = this.definitions.get(id);
13979
+ if (!def) return void 0;
13980
+ Object.assign(def, patch, { updated_at: (/* @__PURE__ */ new Date()).toISOString() });
13981
+ return def;
13982
+ }
13983
+ deleteDefinition(id) {
13984
+ const def = this.definitions.get(id);
13985
+ if (!def) return false;
13986
+ this.slugIndex.delete(def.slug);
13987
+ this.definitions.delete(id);
13988
+ return true;
13989
+ }
13990
+ // ── Instances ────────────────────────────────────────────────────────
13991
+ createInstance(input) {
13992
+ const def = this.getDefinition(input.definition_id) ?? this.getDefinition(input.definition_slug);
13993
+ if (!def) return null;
13994
+ const initialState = def.states.find((s) => s.type === "START" || s.type === "initial");
13995
+ const stateName = initialState?.name ?? "initial";
13996
+ const stateData = {};
13997
+ for (const field of def.fields) {
13998
+ if (field.default_value !== void 0) {
13999
+ stateData[field.name] = field.default_value;
14000
+ }
14001
+ }
14002
+ Object.assign(stateData, input.state_data ?? {});
14003
+ const now = (/* @__PURE__ */ new Date()).toISOString();
14004
+ const inst = {
14005
+ id: (0, import_node_crypto.randomUUID)(),
14006
+ definition_id: def.id,
14007
+ definition_slug: def.slug,
14008
+ current_state: stateName,
14009
+ state_data: stateData,
14010
+ execution_lock_version: 0,
14011
+ event_log: [{
14012
+ event_type: "transition",
14013
+ message: `Instance created in state '${stateName}'`,
14014
+ timestamp: now
14015
+ }],
14016
+ created_at: now,
14017
+ updated_at: now
14018
+ };
14019
+ this.instances.set(inst.id, inst);
14020
+ return inst;
14021
+ }
14022
+ getInstance(id) {
14023
+ return this.instances.get(id);
14024
+ }
14025
+ listInstances(opts) {
14026
+ let items = Array.from(this.instances.values());
14027
+ if (opts?.definition_id) {
14028
+ items = items.filter((i) => i.definition_id === opts.definition_id);
14029
+ }
14030
+ const total = items.length;
14031
+ const offset = opts?.offset ?? 0;
14032
+ const limit = opts?.limit ?? 50;
14033
+ items = items.slice(offset, offset + limit);
14034
+ return { items, total };
14035
+ }
14036
+ // ── Execute Action (Transition) ──────────────────────────────────────
14037
+ executeAction(input) {
14038
+ const def = this.getDefinition(input.definition_id);
14039
+ if (!def) return { success: false, error: "Definition not found" };
14040
+ let inst;
14041
+ if (input.instance_id) {
14042
+ const existing = this.instances.get(input.instance_id);
14043
+ if (!existing) return { success: false, error: "Instance not found" };
14044
+ inst = existing;
14045
+ } else {
14046
+ const created = this.createInstance({
14047
+ definition_id: def.id,
14048
+ definition_slug: def.slug,
14049
+ state_data: input.payload
14050
+ });
14051
+ if (!created) return { success: false, error: "Failed to create instance" };
14052
+ inst = created;
14053
+ }
14054
+ if (input.payload && input.instance_id) {
14055
+ Object.assign(inst.state_data, input.payload);
14056
+ }
14057
+ const transition = def.transitions.find((t27) => t27.name === input.action_name && t27.from.includes(inst.current_state));
14058
+ if (!transition) {
14059
+ return {
14060
+ success: false,
14061
+ instance_id: inst.id,
14062
+ from_state: inst.current_state,
14063
+ to_state: null,
14064
+ state_data: inst.state_data,
14065
+ error: `No transition '${input.action_name}' from state '${inst.current_state}'`
14066
+ };
14067
+ }
14068
+ const fromState = inst.current_state;
14069
+ const now = (/* @__PURE__ */ new Date()).toISOString();
14070
+ const events = [];
14071
+ let lastEvalResult = null;
14072
+ events.push({ event_type: "transition", message: `Transition '${transition.name}' started: ${fromState} \u2192 ${transition.to}`, timestamp: now });
14073
+ for (const action of transition.actions ?? []) {
14074
+ try {
14075
+ if (action.type === "set_field") {
14076
+ const field = action.config?.field;
14077
+ if (action.config?.expression) {
14078
+ const expr = action.config.expression;
14079
+ const result = this.evaluateSimpleExpression(expr, inst.state_data);
14080
+ inst.state_data[field] = result;
14081
+ } else if (action.config?.value !== void 0) {
14082
+ inst.state_data[field] = action.config.value;
14083
+ }
14084
+ events.push({ event_type: "action_executed", message: `transition action 'set_field' succeeded`, timestamp: now });
14085
+ } else if (action.type === "eval") {
14086
+ const expr = action.config?.expression;
14087
+ lastEvalResult = this.evaluateSimpleExpression(expr, inst.state_data);
14088
+ events.push({ event_type: "action_executed", message: `transition action 'eval' succeeded`, timestamp: now });
14089
+ } else {
14090
+ events.push({ event_type: "action_executed", message: `transition action '${action.type}' succeeded (no-op in local mode)`, timestamp: now });
14091
+ }
14092
+ } catch (err) {
14093
+ const msg = err instanceof Error ? err.message : String(err);
14094
+ events.push({ event_type: "action_failed", message: `transition action '${action.type}' failed: ${msg}`, timestamp: now });
14095
+ return {
14096
+ success: false,
14097
+ instance_id: inst.id,
14098
+ from_state: fromState,
14099
+ to_state: null,
14100
+ state_data: inst.state_data,
14101
+ event_log: events,
14102
+ error: `transition action failed: ${msg}`
14103
+ };
14104
+ }
14105
+ }
14106
+ inst.current_state = transition.to;
14107
+ inst.execution_lock_version++;
14108
+ inst.updated_at = now;
14109
+ events.push({ event_type: "transition", message: `State changed: ${fromState} \u2192 ${transition.to}`, timestamp: now });
14110
+ inst.event_log.push(...events);
14111
+ return {
14112
+ success: true,
14113
+ instance_id: inst.id,
14114
+ from_state: fromState,
14115
+ to_state: transition.to,
14116
+ state_data: inst.state_data,
14117
+ result: lastEvalResult,
14118
+ event_log: events
14119
+ };
14120
+ }
14121
+ /**
14122
+ * Minimal expression evaluator for local dev mode.
14123
+ * Handles: field references, arithmetic, string literals, simple comparisons.
14124
+ * Does NOT handle: while loops, if/else, function calls, multi-statement blocks.
14125
+ * For full evaluation, use mm-napi when available.
14126
+ */
14127
+ evaluateSimpleExpression(expr, context) {
14128
+ if (context[expr] !== void 0) return context[expr];
14129
+ const arithMatch = expr.match(/^(\w+)\s*([+\-*/])\s*(\d+(?:\.\d+)?)$/);
14130
+ if (arithMatch) {
14131
+ const [, field, op, numStr] = arithMatch;
14132
+ const left = Number(context[field] ?? 0);
14133
+ const right = Number(numStr);
14134
+ switch (op) {
14135
+ case "+":
14136
+ return left + right;
14137
+ case "-":
14138
+ return left - right;
14139
+ case "*":
14140
+ return left * right;
14141
+ case "/":
14142
+ return right !== 0 ? left / right : 0;
14143
+ }
14144
+ }
14145
+ if (/^\d+(\.\d+)?$/.test(expr.trim())) {
14146
+ return Number(expr.trim());
14147
+ }
14148
+ const strMatch = expr.match(/^["'](.*)["']$/);
14149
+ if (strMatch) return strMatch[1];
14150
+ try {
14151
+ const keys = Object.keys(context);
14152
+ const values = Object.values(context);
14153
+ const fn = new Function(...keys, `"use strict"; return (${expr});`);
14154
+ return fn(...values);
14155
+ } catch {
14156
+ return null;
14157
+ }
14158
+ }
14159
+ };
14160
+ async function startLocalServer(options = {}) {
14161
+ const { port = 4200, noAuth = true } = options;
14162
+ const store = new MemoryStore();
14163
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
14164
+ function json(res, status, body) {
14165
+ const data = JSON.stringify(body);
14166
+ res.writeHead(status, {
14167
+ "Content-Type": "application/json",
14168
+ "Access-Control-Allow-Origin": "*",
14169
+ "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
14170
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
14171
+ "Content-Length": Buffer.byteLength(data)
14172
+ });
14173
+ res.end(data);
14174
+ }
14175
+ function readBody(req) {
14176
+ return new Promise((resolve3, reject) => {
14177
+ const chunks = [];
14178
+ req.on("data", (chunk) => chunks.push(chunk));
14179
+ req.on("end", () => resolve3(Buffer.concat(chunks).toString()));
14180
+ req.on("error", reject);
14181
+ });
14182
+ }
14183
+ function parseQuery(url) {
14184
+ const idx = url.indexOf("?");
14185
+ if (idx === -1) return {};
14186
+ const params = {};
14187
+ const qs = url.slice(idx + 1);
14188
+ for (const pair of qs.split("&")) {
14189
+ const [k, v] = pair.split("=");
14190
+ if (k) params[decodeURIComponent(k)] = decodeURIComponent(v ?? "");
14191
+ }
14192
+ return params;
14193
+ }
14194
+ const server = http.createServer(async (req, res) => {
14195
+ const method = req.method?.toUpperCase() ?? "GET";
14196
+ const rawUrl = req.url ?? "/";
14197
+ const queryStart = rawUrl.indexOf("?");
14198
+ const path = queryStart >= 0 ? rawUrl.slice(0, queryStart) : rawUrl;
14199
+ const query = parseQuery(rawUrl);
14200
+ if (method === "OPTIONS") {
14201
+ res.writeHead(204, {
14202
+ "Access-Control-Allow-Origin": "*",
14203
+ "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
14204
+ "Access-Control-Allow-Headers": "Content-Type, Authorization",
14205
+ "Access-Control-Max-Age": "86400"
14206
+ });
14207
+ res.end();
14208
+ return;
14209
+ }
14210
+ try {
14211
+ if (path === "/health" && method === "GET") {
14212
+ return json(res, 200, {
14213
+ status: "ok",
14214
+ service: "mm-local-dev",
14215
+ mode: "in-memory",
14216
+ started_at: startedAt,
14217
+ definitions: store.definitions.size,
14218
+ instances: store.instances.size
14219
+ });
14220
+ }
14221
+ if (path === "/api/v1/auth/login" && (method === "POST" || method === "GET")) {
14222
+ return json(res, 200, {
14223
+ token: "dev-token-local",
14224
+ user: {
14225
+ id: "dev-user-001",
14226
+ email: "dev@localhost",
14227
+ role: "admin",
14228
+ name: "Local Developer"
14229
+ }
14230
+ });
14231
+ }
14232
+ if (path === "/api/v1/workflow/definitions" && method === "GET") {
14233
+ const result = store.listDefinitions({
14234
+ category: query.category,
14235
+ limit: query.limit ? parseInt(query.limit, 10) : void 0,
14236
+ offset: query.offset ? parseInt(query.offset, 10) : void 0
14237
+ });
14238
+ if (query.slug) {
14239
+ const def = store.getDefinition(query.slug);
14240
+ return json(res, 200, { items: def ? [def] : [], total: def ? 1 : 0 });
14241
+ }
14242
+ return json(res, 200, result);
14243
+ }
14244
+ const defMatch = path.match(/^\/api\/v1\/workflow\/definitions\/([^/]+)$/);
14245
+ if (defMatch && method === "GET") {
14246
+ const def = store.getDefinition(defMatch[1]);
14247
+ if (!def) return json(res, 404, { error: "Not found" });
14248
+ return json(res, 200, def);
14249
+ }
14250
+ if (path === "/api/v1/workflow/definitions" && method === "POST") {
14251
+ const body = JSON.parse(await readBody(req));
14252
+ const def = store.createDefinition(body);
14253
+ return json(res, 201, def);
14254
+ }
14255
+ if (defMatch && method === "PATCH") {
14256
+ const body = JSON.parse(await readBody(req));
14257
+ const updated = store.patchDefinition(defMatch[1], body);
14258
+ if (!updated) return json(res, 404, { error: "Not found" });
14259
+ return json(res, 200, updated);
14260
+ }
14261
+ if (defMatch && method === "DELETE") {
14262
+ const deleted = store.deleteDefinition(defMatch[1]);
14263
+ if (!deleted) return json(res, 404, { error: "Not found" });
14264
+ return json(res, 204, null);
14265
+ }
14266
+ if (path === "/api/v1/workflow/instances" && method === "GET") {
14267
+ const result = store.listInstances({
14268
+ definition_id: query.definition_id,
14269
+ limit: query.limit ? parseInt(query.limit, 10) : void 0,
14270
+ offset: query.offset ? parseInt(query.offset, 10) : void 0
14271
+ });
14272
+ return json(res, 200, result);
14273
+ }
14274
+ if (path === "/api/v1/workflow/instances" && method === "POST") {
14275
+ const body = JSON.parse(await readBody(req));
14276
+ const inst = store.createInstance(body);
14277
+ if (!inst) return json(res, 404, { error: "Definition not found" });
14278
+ return json(res, 201, inst);
14279
+ }
14280
+ const instMatch = path.match(/^\/api\/v1\/workflow\/instances\/([^/]+)$/);
14281
+ if (instMatch && method === "GET") {
14282
+ const inst = store.getInstance(instMatch[1]);
14283
+ if (!inst) return json(res, 404, { error: "Not found" });
14284
+ return json(res, 200, inst);
14285
+ }
14286
+ if (path === "/api/v1/workflow/execute-action" && method === "POST") {
14287
+ const body = JSON.parse(await readBody(req));
14288
+ const result = store.executeAction(body);
14289
+ return json(res, 200, result);
14290
+ }
14291
+ const dataMatch = path.match(/^\/api\/v1\/data\/([^/]+)$/);
14292
+ if (dataMatch && method === "GET") {
14293
+ const def = store.getDefinition(dataMatch[1]);
14294
+ if (!def) return json(res, 404, { error: "Not found" });
14295
+ const instances = store.listInstances({ definition_id: def.id });
14296
+ return json(res, 200, instances);
14297
+ }
14298
+ if (path.startsWith("/api/v1/")) {
14299
+ return json(res, 501, { error: "Not implemented in local dev mode", path, method });
14300
+ }
14301
+ return json(res, 404, { error: "Not found", path });
14302
+ } catch (err) {
14303
+ const message = err instanceof Error ? err.message : String(err);
14304
+ console.error(`[mm-local] ${method} ${path} \u2014 Error: ${message}`);
14305
+ return json(res, 500, { error: message });
14306
+ }
14307
+ });
14308
+ return new Promise((resolve3, reject) => {
14309
+ server.on("error", (err) => {
14310
+ if (err.code === "EADDRINUSE") {
14311
+ reject(new Error(`Port ${port} is already in use. Is another server running?`));
14312
+ } else {
14313
+ reject(err);
14314
+ }
14315
+ });
14316
+ server.listen(port, () => {
14317
+ console.log(`[mm-local] Local API server running at http://localhost:${port}`);
14318
+ console.log(`[mm-local] Mode: in-memory (data lost on restart)`);
14319
+ console.log(`[mm-local] Auth: disabled (all requests accepted)`);
14320
+ resolve3({
14321
+ server,
14322
+ port,
14323
+ store,
14324
+ async close() {
14325
+ return new Promise((res) => {
14326
+ server.close(() => {
14327
+ console.log("[mm-local] Local API server stopped");
14328
+ res();
14329
+ });
14330
+ });
14331
+ }
14332
+ });
14333
+ });
14334
+ });
14335
+ }
14336
+
14337
+ // src/dev-server.ts
14338
+ var currentErrors = null;
14339
+ function escapeHtml(s) {
14340
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
14341
+ }
14342
+ function renderErrorOverlay(errors) {
14343
+ const cards = errors.map((err) => {
14344
+ const loc = err.line ? `${err.file}:${err.line}${err.column ? ":" + err.column : ""}` : err.file;
14345
+ const snippet = err.snippet ? `<pre style="background:#1a1a2e;color:#e0e0e0;padding:12px 16px;border-radius:6px;overflow-x:auto;margin-top:8px;font-size:13px;line-height:1.5">${escapeHtml(err.snippet)}</pre>` : "";
14346
+ return `<div style="background:#2d1b1b;border:1px solid #5c2020;border-radius:8px;padding:16px 20px;margin-bottom:12px">
14347
+ <div style="color:#ff6b6b;font-family:monospace;font-size:13px;margin-bottom:6px">${escapeHtml(loc)}</div>
14348
+ <div style="color:#ffa0a0;font-size:15px;font-weight:500">${escapeHtml(err.message)}</div>${snippet}</div>`;
14349
+ }).join("\n");
14350
+ return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
14351
+ <title>Compile Error - MindMatrix Dev</title>
14352
+ <style>*{box-sizing:border-box;margin:0;padding:0}body{background:#1a1a2e;color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;padding:40px 20px;min-height:100vh}</style></head>
14353
+ <body><div style="max-width:800px;margin:0 auto">
14354
+ <div style="display:flex;align-items:center;gap:12px;margin-bottom:24px">
14355
+ <div style="background:#5c2020;color:#ff6b6b;font-size:14px;font-weight:600;padding:4px 10px;border-radius:4px">COMPILE ERROR</div>
14356
+ <div style="color:#888;font-size:13px">${errors.length} error${errors.length !== 1 ? "s" : ""}</div></div>
14357
+ ${cards}
14358
+ <div style="color:#666;font-size:12px;margin-top:24px;text-align:center">Fix the error and save -- the page will reload automatically.</div></div>
14359
+ <script>const ws=new WebSocket('ws://'+location.host+'/__mm_dev');ws.onmessage=e=>{const m=JSON.parse(e.data);if(m.type==='workflow:compiled'||m.type==='workflow:rebuild')location.reload()};ws.onclose=()=>setTimeout(()=>location.reload(),2000)</script>
14360
+ </body></html>`;
14361
+ }
14362
+ function errorOverlayMiddleware() {
14363
+ return (req, res, next) => {
14364
+ if (!currentErrors || !req.url) return next();
14365
+ const url = req.url;
14366
+ if (url.startsWith("/api") || url.startsWith("/health") || url.startsWith("/ws") || url.startsWith("/__mm_dev") || url.startsWith("/@") || url.startsWith("/node_modules")) return next();
14367
+ const accept = req.headers?.accept ?? "";
14368
+ if (!accept.includes("text/html")) return next();
14369
+ res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
14370
+ res.end(renderErrorOverlay(currentErrors));
14371
+ };
14372
+ }
14373
+ async function resolveDevToken(apiUrl, explicit) {
14374
+ if (explicit) return explicit;
14375
+ try {
14376
+ const { resolveToken: resolveToken2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
14377
+ const s = resolveToken2(apiUrl);
14378
+ if (s) return s;
14379
+ } catch {
14380
+ }
14381
+ try {
14382
+ const resp = await fetch(`${apiUrl}/auth/login`, {
14383
+ method: "POST",
14384
+ headers: { "Content-Type": "application/json" },
14385
+ body: JSON.stringify({ email: "admin@mindmatrix.com", password: "Admin123!" })
14386
+ });
14387
+ if (resp.ok) {
14388
+ const data = await resp.json();
14389
+ const token = data.token ?? data.access_token;
14390
+ if (token) {
14391
+ try {
14392
+ const { saveCredentials: saveCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
14393
+ saveCredentials2(apiUrl, token);
14394
+ } catch {
14395
+ }
14396
+ return token;
14397
+ }
14398
+ }
14399
+ } catch {
14400
+ }
14401
+ return process.env.MINDMATRIX_TOKEN;
14402
+ }
14403
+ async function checkBackendHealth(apiUrl) {
14404
+ try {
14405
+ const base = apiUrl.replace(/\/api\/v1\/?$/, "");
14406
+ const resp = await fetch(`${base}/health`, { signal: AbortSignal.timeout(5e3) });
14407
+ if (resp.ok) {
14408
+ const d = await resp.json();
14409
+ return { ok: true, version: d.version, db: d.database };
14410
+ }
14411
+ return { ok: resp.status < 500 };
14412
+ } catch {
14413
+ return { ok: false };
14414
+ }
14415
+ }
14416
+ async function initialBuildDeploy(src, outDir, mode, apiUrl, token) {
14417
+ console.log("[mm-dev] Compiling project...");
14418
+ const buildResult = await build({ src, outDir, mode, skipTypeCheck: true });
14419
+ if (buildResult.errors > 0) {
14420
+ currentErrors = buildResult.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
14421
+ console.error(`[mm-dev] Build failed with ${buildResult.errors} error(s) -- error overlay active`);
14422
+ return { buildResult, deployed: false, slug: void 0 };
14423
+ }
14424
+ currentErrors = null;
14425
+ if (buildResult.compiled === 0) return { buildResult, deployed: false, slug: void 0 };
14426
+ console.log(`[mm-dev] Compiled ${buildResult.compiled} definition(s)`);
14427
+ try {
14428
+ const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
14429
+ const result = await deploy2({ apiUrl, token, dir: outDir });
14430
+ const total = result.created.length + result.updated.length + result.versioned.length;
14431
+ if (total > 0) console.log(`[mm-dev] Deployed: ${result.created.length} created, ${result.updated.length} updated`);
14432
+ return { buildResult, deployed: true, slug: buildResult.definitions?.[0]?.slug };
14433
+ } catch (e) {
14434
+ console.warn(`[mm-dev] Deploy failed: ${e instanceof Error ? e.message : e}`);
14435
+ return { buildResult, deployed: false, slug: void 0 };
14436
+ }
14437
+ }
14438
+ function printBanner(o) {
14439
+ const l = "-".repeat(58);
14440
+ console.log(`
14441
+ ${l}
14442
+ MindMatrix Dev Server
14443
+ ${l}
14444
+ `);
14445
+ console.log(` Preview: http://localhost:${o.port}`);
14446
+ console.log(` API Proxy: /api/* -> ${o.apiUrl}`);
14447
+ console.log(` WebSocket: ws://localhost:${o.port}/__mm_dev`);
14448
+ console.log(` Watching: ${o.src} (${o.include.join(", ")})
14449
+ `);
14450
+ console.log(` Backend: ${o.health.ok ? "connected" : "unreachable"}${o.health.version ? ` (v${o.health.version})` : ""}`);
14451
+ if (o.health.db) console.log(` Database: ${o.health.db}`);
14452
+ console.log(` Auth: ${o.token ? "authenticated" : "no token"}`);
14453
+ if (o.compiled > 0) {
14454
+ console.log(` Blueprint: ${o.slug ?? "unknown"} (${o.compiled} defs)`);
14455
+ console.log(` Deploy: ${o.deployed ? "synced" : "pending"}`);
14456
+ }
14457
+ if (o.errors > 0) console.log(` Errors: ${o.errors} compile error(s) -- overlay active`);
14458
+ console.log(`
14459
+ ${l}
14460
+ `);
14461
+ }
14462
+ function broadcast(clients, data) {
14463
+ const msg = JSON.stringify(data);
14464
+ for (const c of clients) {
14465
+ try {
14466
+ if (c.readyState === 1) c.send(msg);
14467
+ } catch {
14468
+ clients.delete(c);
14469
+ }
14470
+ }
13370
14471
  }
13371
-
13372
- // src/dev-server.ts
13373
14472
  async function createDevServer(options = {}) {
13374
14473
  const {
13375
14474
  port = 5199,
@@ -13378,44 +14477,87 @@ async function createDevServer(options = {}) {
13378
14477
  include = ["**/*.workflow.tsx"],
13379
14478
  outDir = "dist/workflows",
13380
14479
  seed = false,
13381
- apiUrl = "http://localhost:4200/api/v1",
13382
- authToken = process.env.MINDMATRIX_TOKEN,
14480
+ apiUrl: rawApiUrl = "auto",
14481
+ authToken: explicitToken,
13383
14482
  ws: enableWs = true,
13384
14483
  open = false
13385
14484
  } = options;
13386
14485
  const clients = /* @__PURE__ */ new Set();
13387
- const pluginOptions = {
13388
- mode,
13389
- include,
13390
- outDir,
13391
- seedOnCompile: seed,
13392
- apiUrl,
13393
- authToken
13394
- };
13395
- const notifyPlugin = {
13396
- name: "mindmatrix-dev-notify",
14486
+ let localServer = null;
14487
+ let apiUrl;
14488
+ let isLocalMode = false;
14489
+ if (rawApiUrl === "local") {
14490
+ localServer = await startLocalServer({ port: 4200 });
14491
+ apiUrl = "http://localhost:4200/api/v1";
14492
+ isLocalMode = true;
14493
+ } else if (rawApiUrl === "auto") {
14494
+ const defaultRemote = "https://dev.mindmatrix.club/api/v1";
14495
+ const remoteHealth = await checkBackendHealth(defaultRemote);
14496
+ if (remoteHealth.ok) {
14497
+ apiUrl = defaultRemote;
14498
+ } else {
14499
+ const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
14500
+ if (localHealth.ok) {
14501
+ apiUrl = "http://localhost:4200/api/v1";
14502
+ } else {
14503
+ console.log("[mm-dev] No backend detected \u2014 starting local in-memory API server...");
14504
+ localServer = await startLocalServer({ port: 4200 });
14505
+ apiUrl = "http://localhost:4200/api/v1";
14506
+ isLocalMode = true;
14507
+ }
14508
+ }
14509
+ } else {
14510
+ apiUrl = rawApiUrl;
14511
+ }
14512
+ const token = isLocalMode ? "dev-token-local" : await resolveDevToken(apiUrl, explicitToken);
14513
+ const health = isLocalMode ? { ok: true, version: "local", db: "in-memory" } : await checkBackendHealth(apiUrl);
14514
+ let initialSlug, initialCompiled = 0, initialDeployed = false, initialErrors = 0;
14515
+ if (token && health.ok) {
14516
+ const r = await initialBuildDeploy(src, outDir, mode, apiUrl, token);
14517
+ initialCompiled = r.buildResult.compiled;
14518
+ initialDeployed = r.deployed;
14519
+ initialSlug = r.slug;
14520
+ initialErrors = r.buildResult.errors;
14521
+ }
14522
+ if (seed && token && initialDeployed) {
14523
+ try {
14524
+ const { seedInstances: seedInstances2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
14525
+ console.log("[mm-dev] Seeding sample instances...");
14526
+ const sr = await seedInstances2({ apiUrl, token, dir: outDir });
14527
+ console.log(`[mm-dev] Seeded ${sr.created} instance(s) across ${sr.definitions} definition(s)`);
14528
+ } catch (e) {
14529
+ console.warn(`[mm-dev] Seed failed: ${e instanceof Error ? e.message : e}`);
14530
+ }
14531
+ }
14532
+ const pluginOpts = { mode, include, outDir, seedOnCompile: seed, apiUrl, authToken: token };
14533
+ const proxyTarget = apiUrl.replace(/\/api\/v1\/?$/, "") || apiUrl;
14534
+ let deployInFlight = false;
14535
+ const compileDeployPlugin = {
14536
+ name: "mindmatrix-dev-compile-deploy",
13397
14537
  enforce: "post",
13398
- handleHotUpdate(ctx) {
13399
- const isWorkflow = include.some((pattern) => {
13400
- const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<GLOBSTAR>>").replace(/\*/g, "[^/]*").replace(/<<GLOBSTAR>>/g, ".*").replace(/\?/g, ".");
13401
- return new RegExp(regex).test(ctx.file);
13402
- });
13403
- if (!isWorkflow) return;
13404
- const message = JSON.stringify({
13405
- type: "workflow:compiled",
13406
- file: ctx.file,
13407
- timestamp: ctx.timestamp
13408
- });
13409
- for (const client of clients) {
14538
+ async handleHotUpdate(ctx) {
14539
+ const isWf = include.some((p) => new RegExp(p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<G>>").replace(/\*/g, "[^/]*").replace(/<<G>>/g, ".*").replace(/\?/g, ".")).test(ctx.file));
14540
+ if (!isWf) return;
14541
+ const fn = ctx.file.split("/").pop() ?? ctx.file;
14542
+ console.log(`[mm-dev] Recompiling ${fn}...`);
14543
+ const br = await build({ src, outDir, mode, skipTypeCheck: true });
14544
+ if (br.errors > 0) {
14545
+ currentErrors = br.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
14546
+ broadcast(clients, { type: "workflow:error", errors: br.errors, timestamp: ctx.timestamp });
14547
+ return;
14548
+ }
14549
+ currentErrors = null;
14550
+ if (token && !deployInFlight) {
14551
+ deployInFlight = true;
13410
14552
  try {
13411
- if (client.readyState === 1) {
13412
- client.send(message);
13413
- }
14553
+ const { deploy: d } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
14554
+ await d({ apiUrl, token, dir: outDir });
13414
14555
  } catch {
13415
- clients.delete(client);
14556
+ } finally {
14557
+ deployInFlight = false;
13416
14558
  }
13417
14559
  }
13418
- console.log(`[mm-dev] Compiled ${ctx.file.split("/").pop()} \u2014 notified ${clients.size} client(s)`);
14560
+ broadcast(clients, { type: "workflow:compiled", file: ctx.file, compiled: br.compiled, timestamp: ctx.timestamp });
13419
14561
  }
13420
14562
  };
13421
14563
  const viteConfig = {
@@ -13423,311 +14565,93 @@ async function createDevServer(options = {}) {
13423
14565
  server: {
13424
14566
  port,
13425
14567
  open,
13426
- host: true
14568
+ host: true,
14569
+ proxy: {
14570
+ "/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
14571
+ "/health": { target: proxyTarget, changeOrigin: true, secure: true },
14572
+ "/ws": { target: proxyTarget.replace(/^http/, "ws"), changeOrigin: true, ws: true }
14573
+ }
13427
14574
  },
13428
14575
  plugins: [
13429
- mindmatrixReact(pluginOptions),
13430
- notifyPlugin
14576
+ mindmatrixReact(pluginOpts),
14577
+ compileDeployPlugin,
14578
+ { name: "mindmatrix-error-overlay", configureServer(server) {
14579
+ server.middlewares.use(errorOverlayMiddleware());
14580
+ } }
13431
14581
  ],
13432
- logLevel: "info"
14582
+ logLevel: "warn"
13433
14583
  };
13434
- const { createServer } = await import("vite");
13435
- const vite = await createServer(viteConfig);
14584
+ const { createServer: createServer2 } = await import("vite");
14585
+ const vite = await createServer2(viteConfig);
13436
14586
  await vite.listen();
13437
14587
  const resolvedPort = vite.config.server.port ?? port;
13438
14588
  if (enableWs && vite.httpServer) {
13439
14589
  try {
13440
- const wsModule = await Function('return import("ws")')();
13441
- const WebSocketServer = wsModule.WebSocketServer ?? wsModule.default?.WebSocketServer;
13442
- if (WebSocketServer) {
13443
- const wss = new WebSocketServer({
13444
- server: vite.httpServer,
13445
- path: "/__mm_dev"
13446
- });
13447
- wss.on("connection", (socket) => {
13448
- clients.add(socket);
13449
- console.log(`[mm-dev] Editor connected (${clients.size} total)`);
13450
- socket.on("close", () => {
13451
- clients.delete(socket);
13452
- console.log(`[mm-dev] Editor disconnected (${clients.size} total)`);
13453
- });
13454
- socket.send(JSON.stringify({
13455
- type: "mm:connected",
13456
- version: "0.1.0",
13457
- capabilities: ["compile", "seed", "notify"]
13458
- }));
14590
+ const wsM = await Function('return import("ws")')();
14591
+ const WSS = wsM.WebSocketServer ?? wsM.default?.WebSocketServer;
14592
+ if (WSS) {
14593
+ const wss = new WSS({ server: vite.httpServer, path: "/__mm_dev" });
14594
+ wss.on("connection", (s) => {
14595
+ clients.add(s);
14596
+ s.on("close", () => clients.delete(s));
14597
+ s.send(JSON.stringify({ type: "mm:connected", version: "0.1.0", capabilities: ["compile", "deploy", "proxy", "notify", "error-overlay"] }));
13459
14598
  });
13460
14599
  }
13461
14600
  } catch {
13462
- console.warn("[mm-dev] ws package not available \u2014 WebSocket notifications disabled");
13463
14601
  }
13464
14602
  }
13465
- console.log(`
13466
- [mm-dev] MindMatrix Dev Server running`);
13467
- console.log(` Local: http://localhost:${resolvedPort}`);
13468
- console.log(` WebSocket: ws://localhost:${resolvedPort}/__mm_dev`);
13469
- console.log(` Watching: ${src} (${include.join(", ")})`);
13470
- if (seed) {
13471
- console.log(` Seeding: ${apiUrl}`);
13472
- }
13473
- console.log();
14603
+ printBanner({ port: resolvedPort, apiUrl: isLocalMode ? `${apiUrl} (local in-memory)` : apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
13474
14604
  return {
13475
14605
  vite,
13476
14606
  port: resolvedPort,
13477
14607
  clients,
13478
14608
  async rebuild() {
13479
- console.log("[mm-dev] Full rebuild triggered...");
13480
- const result = await build({ src, outDir, mode });
13481
- const message = JSON.stringify({
13482
- type: "workflow:rebuild",
13483
- compiled: result.compiled,
13484
- errors: result.errors,
13485
- timestamp: Date.now()
13486
- });
13487
- for (const client of clients) {
13488
- try {
13489
- if (client.readyState === 1) client.send(message);
13490
- } catch {
13491
- clients.delete(client);
14609
+ const r = await build({ src, outDir, mode });
14610
+ if (r.errors > 0) {
14611
+ currentErrors = r.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
14612
+ } else {
14613
+ currentErrors = null;
14614
+ if (token) {
14615
+ try {
14616
+ const { deploy: d } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
14617
+ await d({ apiUrl, token, dir: outDir });
14618
+ } catch {
14619
+ }
13492
14620
  }
13493
14621
  }
13494
- return result;
14622
+ broadcast(clients, { type: "workflow:rebuild", compiled: r.compiled, errors: r.errors, timestamp: Date.now() });
14623
+ return r;
13495
14624
  },
13496
14625
  async close() {
13497
- for (const client of clients) {
14626
+ for (const c of clients) {
13498
14627
  try {
13499
- client.close();
14628
+ c.close();
13500
14629
  } catch {
13501
14630
  }
13502
14631
  }
13503
14632
  clients.clear();
14633
+ currentErrors = null;
13504
14634
  await vite.close();
13505
- console.log("[mm-dev] Server stopped");
14635
+ if (localServer) {
14636
+ await localServer.close();
14637
+ }
13506
14638
  }
13507
14639
  };
13508
14640
  }
13509
14641
 
13510
- // src/cli/deploy.ts
13511
- var import_glob2 = require("glob");
13512
- var import_fs4 = require("fs");
13513
- var import_path3 = require("path");
13514
- async function deploy(options) {
13515
- const dir = options.dir ?? "dist/workflows";
13516
- const targetLabel = options.targetName ? ` (target: ${options.targetName})` : "";
13517
- console.log(`[mindmatrix-react] Deploying workflows from ${dir} to ${options.apiUrl}${targetLabel}...`);
13518
- const files = await (0, import_glob2.glob)(`${dir}/**/*.workflow.json`);
13519
- if (files.length === 0) {
13520
- console.log(`[mindmatrix-react] No workflow files found in ${dir}`);
13521
- return { created: [], updated: [], versioned: [], skipped: [], failed: [] };
13522
- }
13523
- const result = {
13524
- created: [],
13525
- updated: [],
13526
- versioned: [],
13527
- skipped: [],
13528
- failed: []
13529
- };
13530
- const deployedIRs = [];
13531
- for (const file2 of files) {
13532
- try {
13533
- const ir = JSON.parse((0, import_fs4.readFileSync)(file2, "utf-8"));
13534
- const slug = ir.slug;
13535
- if (options.dryRun) {
13536
- console.log(` [dry-run] Would deploy ${slug} (${(0, import_path3.basename)(file2)})`);
13537
- continue;
13538
- }
13539
- const existing = await fetchExistingDefinition(options.apiUrl, options.token, slug);
13540
- if (!existing) {
13541
- await createDefinition(options.apiUrl, options.token, ir);
13542
- console.log(` \u2713 ${slug} (created)`);
13543
- result.created.push(slug);
13544
- } else if (existing.instanceCount === 0 || options.force) {
13545
- await updateDefinition(options.apiUrl, options.token, existing.id, ir);
13546
- console.log(` \u2713 ${slug} (updated)`);
13547
- result.updated.push(slug);
13548
- } else {
13549
- const newVersion = bumpVersion(existing.version);
13550
- ir.version = newVersion;
13551
- await createDefinition(options.apiUrl, options.token, ir);
13552
- console.log(` \u2713 ${slug} v${newVersion} (new version, ${existing.instanceCount} instances on v${existing.version})`);
13553
- result.versioned.push(slug);
13554
- }
13555
- deployedIRs.push(ir);
13556
- } catch (error) {
13557
- const slug = (0, import_path3.basename)(file2).replace(".workflow.json", "");
13558
- const msg = error.message;
13559
- console.error(` \u2717 ${slug}: ${msg}`);
13560
- result.failed.push({ slug, error: msg });
13561
- }
13562
- }
13563
- if (!options.dryRun) {
13564
- for (const ir of deployedIRs) {
13565
- const serviceResult = await syncServices(options.apiUrl, options.token, ir);
13566
- if (serviceResult) {
13567
- if (!result.services) {
13568
- result.services = { registered: [], updated: [], failed: [] };
13569
- }
13570
- result.services.registered.push(...serviceResult.registered);
13571
- result.services.updated.push(...serviceResult.updated);
13572
- result.services.failed.push(...serviceResult.failed);
13573
- }
13574
- }
13575
- }
13576
- if (options.reportFile) {
13577
- (0, import_fs4.writeFileSync)(options.reportFile, JSON.stringify(result, null, 2), "utf-8");
13578
- console.log(`
13579
- Report written to ${options.reportFile}`);
13580
- }
13581
- const total = result.created.length + result.updated.length + result.versioned.length;
13582
- console.log(
13583
- `
13584
- [mindmatrix-react] Deployed ${total} workflows (${result.created.length} created, ${result.updated.length} updated, ${result.versioned.length} versioned, ${result.failed.length} failed)`
13585
- );
13586
- if (result.services) {
13587
- const svcTotal = result.services.registered.length + result.services.updated.length;
13588
- if (svcTotal > 0 || result.services.failed.length > 0) {
13589
- console.log(
13590
- `[mindmatrix-react] Synced ${svcTotal} services (${result.services.registered.length} registered, ${result.services.updated.length} updated, ${result.services.failed.length} failed)`
13591
- );
13592
- }
13593
- }
13594
- return result;
13595
- }
13596
- async function fetchExistingDefinition(apiUrl, token, slug) {
13597
- try {
13598
- const res = await fetch(`${apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`, {
13599
- headers: { Authorization: `Bearer ${token}` }
13600
- });
13601
- if (!res.ok) return null;
13602
- const data = await res.json();
13603
- const definitions = Array.isArray(data) ? data : data.items ?? data.data;
13604
- if (!definitions || definitions.length === 0) return null;
13605
- const def = definitions[0];
13606
- return {
13607
- id: def.id,
13608
- slug: def.slug,
13609
- version: def.version || "0.1.0",
13610
- instanceCount: def.instanceCount ?? def.instance_count ?? 0
13611
- };
13612
- } catch {
13613
- return null;
13614
- }
13615
- }
13616
- async function createDefinition(apiUrl, token, ir) {
13617
- const res = await fetch(`${apiUrl}/workflow/definitions`, {
13618
- method: "POST",
13619
- headers: {
13620
- "Content-Type": "application/json",
13621
- Authorization: `Bearer ${token}`
13622
- },
13623
- body: JSON.stringify(ir)
13624
- });
13625
- if (!res.ok) {
13626
- const errorText = await res.text();
13627
- throw new Error(`Create failed: ${res.status} ${errorText}`);
13628
- }
13629
- }
13630
- async function updateDefinition(apiUrl, token, id, ir) {
13631
- const { slug: _slug, ...updatePayload } = ir;
13632
- const res = await fetch(`${apiUrl}/workflow/definitions/${id}`, {
13633
- method: "PATCH",
13634
- headers: {
13635
- "Content-Type": "application/json",
13636
- Authorization: `Bearer ${token}`
13637
- },
13638
- body: JSON.stringify(updatePayload)
13639
- });
13640
- if (!res.ok) {
13641
- const errorText = await res.text();
13642
- throw new Error(`Update failed: ${res.status} ${errorText}`);
13643
- }
13644
- }
13645
- function bumpVersion(version) {
13646
- const parts = version.split(".");
13647
- if (parts.length !== 3) return `${version}.1`;
13648
- const patch = parseInt(parts[2], 10) || 0;
13649
- return `${parts[0]}.${parts[1]}.${patch + 1}`;
13650
- }
13651
- async function syncServices(apiUrl, token, ir) {
13652
- const metadata = ir.metadata;
13653
- const orchestration = metadata?.orchestration;
13654
- const services = orchestration?.services;
13655
- if (!services || Object.keys(services).length === 0) return null;
13656
- const result = { registered: [], updated: [], failed: [] };
13657
- for (const [name, config] of Object.entries(services)) {
13658
- try {
13659
- const registration = {
13660
- name,
13661
- connection: {
13662
- type: config.type || "webhook",
13663
- url: config.url,
13664
- queue: config.queue
13665
- },
13666
- actions: config.actions || [],
13667
- labels: config.labels || {}
13668
- };
13669
- const existing = await fetchExistingService(apiUrl, token, name);
13670
- if (existing) {
13671
- await fetch(`${apiUrl}/services/${existing.id}`, {
13672
- method: "PATCH",
13673
- headers: {
13674
- "Content-Type": "application/json",
13675
- Authorization: `Bearer ${token}`
13676
- },
13677
- body: JSON.stringify(registration)
13678
- });
13679
- console.log(` \u2713 service: ${name} (updated)`);
13680
- result.updated.push(name);
13681
- } else {
13682
- const res = await fetch(`${apiUrl}/services`, {
13683
- method: "POST",
13684
- headers: {
13685
- "Content-Type": "application/json",
13686
- Authorization: `Bearer ${token}`
13687
- },
13688
- body: JSON.stringify(registration)
13689
- });
13690
- if (!res.ok) {
13691
- const errorText = await res.text();
13692
- throw new Error(`Register failed: ${res.status} ${errorText}`);
13693
- }
13694
- console.log(` \u2713 service: ${name} (registered)`);
13695
- result.registered.push(name);
13696
- }
13697
- } catch (error) {
13698
- const msg = error.message;
13699
- console.error(` \u2717 service: ${name}: ${msg}`);
13700
- result.failed.push(name);
13701
- }
13702
- }
13703
- return result;
13704
- }
13705
- async function fetchExistingService(apiUrl, token, name) {
13706
- try {
13707
- const res = await fetch(`${apiUrl}/services?name=${encodeURIComponent(name)}`, {
13708
- headers: { Authorization: `Bearer ${token}` }
13709
- });
13710
- if (!res.ok) return null;
13711
- const data = await res.json();
13712
- const servicesList = Array.isArray(data) ? data : data.services ?? data.items ?? data.data;
13713
- if (!servicesList || servicesList.length === 0) return null;
13714
- const found = servicesList.find((s) => s.name === name);
13715
- return found ? { id: found.id, name: found.name } : null;
13716
- } catch {
13717
- return null;
13718
- }
13719
- }
14642
+ // src/index.ts
14643
+ init_deploy();
13720
14644
 
13721
14645
  // src/envelope.ts
13722
14646
  var import_crypto3 = require("crypto");
13723
- var import_fs5 = require("fs");
13724
- var import_path4 = require("path");
13725
- var import_glob3 = require("glob");
14647
+ var import_fs7 = require("fs");
14648
+ var import_path5 = require("path");
14649
+ var import_glob4 = require("glob");
13726
14650
  var import_core7 = require("@babel/core");
13727
14651
  init_babel();
13728
14652
  async function buildEnvelope(projectDir, options = {}) {
13729
- const root = (0, import_path4.resolve)(projectDir);
13730
- const slug = options.slug ?? (0, import_path4.basename)(root);
14653
+ const root = (0, import_path5.resolve)(projectDir);
14654
+ const slug = options.slug ?? (0, import_path5.basename)(root);
13731
14655
  const version = options.version ?? "0.1.0";
13732
14656
  const mode = options.mode ?? "infer";
13733
14657
  const patterns = options.include ?? [
@@ -13737,11 +14661,11 @@ async function buildEnvelope(projectDir, options = {}) {
13737
14661
  ];
13738
14662
  const discoveredFiles = [];
13739
14663
  for (const pattern of patterns) {
13740
- const matches = await (0, import_glob3.glob)(pattern, { absolute: true });
14664
+ const matches = await (0, import_glob4.glob)(pattern, { absolute: true });
13741
14665
  discoveredFiles.push(...matches);
13742
14666
  }
13743
14667
  const uniqueFiles = [...new Set(discoveredFiles)];
13744
- const allSourceFiles = await (0, import_glob3.glob)(`${root}/**/*.{ts,tsx,js,jsx,css,json}`, {
14668
+ const allSourceFiles = await (0, import_glob4.glob)(`${root}/**/*.{ts,tsx,js,jsx,css,json}`, {
13745
14669
  absolute: true,
13746
14670
  ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
13747
14671
  });
@@ -13751,10 +14675,10 @@ async function buildEnvelope(projectDir, options = {}) {
13751
14675
  const errors = [];
13752
14676
  const sourceBindings = [];
13753
14677
  for (const file2 of uniqueFiles) {
13754
- const relativePath = (0, import_path4.relative)(root, file2);
14678
+ const relativePath = (0, import_path5.relative)(root, file2);
13755
14679
  let fileContent;
13756
14680
  try {
13757
- fileContent = (0, import_fs5.readFileSync)(file2);
14681
+ fileContent = (0, import_fs7.readFileSync)(file2);
13758
14682
  } catch {
13759
14683
  errors.push({ file: relativePath, message: "Could not read file" });
13760
14684
  continue;