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

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/babel/index.d.mts +2 -2
  2. package/dist/babel/index.d.ts +2 -2
  3. package/dist/babel/index.js +5 -5
  4. package/dist/babel/index.mjs +1 -1
  5. package/dist/cli/index.js +797 -1941
  6. package/dist/cli/index.mjs +179 -77
  7. package/dist/codemod/cli.js +1 -1
  8. package/dist/codemod/cli.mjs +1 -1
  9. package/dist/codemod/index.d.mts +3 -3
  10. package/dist/codemod/index.d.ts +3 -3
  11. package/dist/codemod/index.js +1 -1
  12. package/dist/codemod/index.mjs +1 -1
  13. package/dist/dev-server.d.mts +2 -2
  14. package/dist/dev-server.d.ts +2 -2
  15. package/dist/dev-server.js +86 -1218
  16. package/dist/dev-server.mjs +4 -4
  17. package/dist/envelope.d.mts +2 -2
  18. package/dist/envelope.d.ts +2 -2
  19. package/dist/envelope.js +5 -5
  20. package/dist/envelope.mjs +2 -2
  21. package/dist/index.d.mts +8 -8
  22. package/dist/index.d.ts +8 -8
  23. package/dist/index.js +342 -1266
  24. package/dist/index.mjs +8 -8
  25. package/dist/testing/index.d.mts +8 -8
  26. package/dist/testing/index.d.ts +8 -8
  27. package/dist/testing/index.js +5 -5
  28. package/dist/testing/index.mjs +1 -1
  29. package/dist/vite/index.d.mts +1 -1
  30. package/dist/vite/index.d.ts +1 -1
  31. package/dist/vite/index.js +5 -5
  32. package/dist/vite/index.mjs +2 -2
  33. package/examples/authentication/main.workflow.tsx +1 -1
  34. package/examples/authentication/mm.config.ts +1 -1
  35. package/examples/authentication/pages/LoginPage.tsx +2 -2
  36. package/examples/authentication/pages/SignupPage.tsx +2 -2
  37. package/examples/counter.workflow.tsx +1 -1
  38. package/examples/dashboard.workflow.tsx +1 -1
  39. package/examples/invoice-approval/actions/invoice.server.ts +1 -1
  40. package/examples/invoice-approval/main.workflow.tsx +1 -1
  41. package/examples/invoice-approval/mm.config.ts +1 -1
  42. package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +1 -1
  43. package/examples/invoice-approval/pages/InvoiceFormPage.tsx +1 -1
  44. package/examples/invoice-approval/pages/InvoiceListPage.tsx +1 -1
  45. package/examples/todo-app.workflow.tsx +1 -1
  46. package/examples/uber-app/actions/matching.server.ts +1 -1
  47. package/examples/uber-app/actions/notifications.server.ts +1 -1
  48. package/examples/uber-app/actions/payments.server.ts +1 -1
  49. package/examples/uber-app/actions/pricing.server.ts +1 -1
  50. package/examples/uber-app/app/admin/analytics.tsx +2 -2
  51. package/examples/uber-app/app/admin/fleet.tsx +2 -2
  52. package/examples/uber-app/app/admin/surge-pricing.tsx +2 -2
  53. package/examples/uber-app/app/driver/dashboard.tsx +2 -2
  54. package/examples/uber-app/app/driver/earnings.tsx +2 -2
  55. package/examples/uber-app/app/driver/navigation.tsx +2 -2
  56. package/examples/uber-app/app/driver/ride-acceptance.tsx +2 -2
  57. package/examples/uber-app/app/rider/home.tsx +2 -2
  58. package/examples/uber-app/app/rider/payment-methods.tsx +2 -2
  59. package/examples/uber-app/app/rider/ride-history.tsx +2 -2
  60. package/examples/uber-app/app/rider/ride-tracking.tsx +2 -2
  61. package/examples/uber-app/components/DriverCard.tsx +1 -1
  62. package/examples/uber-app/components/MapView.tsx +3 -3
  63. package/examples/uber-app/components/RatingStars.tsx +2 -2
  64. package/examples/uber-app/components/RideCard.tsx +1 -1
  65. package/examples/uber-app/mm.config.ts +1 -1
  66. package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +2 -2
  67. package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +2 -2
  68. package/examples/uber-app/workflows/payment-processing.workflow.tsx +2 -2
  69. package/examples/uber-app/workflows/ride-request.workflow.tsx +2 -2
  70. package/package.json +13 -9
  71. package/dist/auth-3UK75242.mjs +0 -17
  72. package/dist/chunk-5FTDWKHH.mjs +0 -244
  73. package/dist/chunk-7JRAEFRB.mjs +0 -7510
  74. package/dist/chunk-7T6Q5KAA.mjs +0 -7506
  75. package/dist/chunk-ABYPKRSB.mjs +0 -215
  76. package/dist/chunk-BZEXUPDH.mjs +0 -175
  77. package/dist/chunk-HRYR54PT.mjs +0 -175
  78. package/dist/chunk-J3M4GUS7.mjs +0 -161
  79. package/dist/chunk-JRGFBWTN.mjs +0 -2918
  80. package/dist/chunk-O4AUS7EU.mjs +0 -148
  81. package/dist/chunk-R2DD5GTY.mjs +0 -186
  82. package/dist/chunk-UDDTWG5J.mjs +0 -734
  83. package/dist/chunk-VLTKQDJ3.mjs +0 -244
  84. package/dist/chunk-WVYY32LD.mjs +0 -939
  85. package/dist/chunk-XDVM4YHX.mjs +0 -3450
  86. package/dist/chunk-Z2G5RZ4H.mjs +0 -186
  87. package/dist/chunk-ZE3KCHBM.mjs +0 -2918
  88. package/dist/deploy-YAJGW6II.mjs +0 -9
  89. package/dist/dev-server-CrQ041KP.d.mts +0 -79
  90. package/dist/dev-server-CrQ041KP.d.ts +0 -79
  91. package/dist/envelope-ChEkuHij.d.mts +0 -265
  92. package/dist/envelope-ChEkuHij.d.ts +0 -265
  93. package/dist/index-CEKyyazf.d.mts +0 -104
  94. package/dist/index-CEKyyazf.d.ts +0 -104
  95. package/dist/init-7FJENUDK.mjs +0 -407
  96. package/dist/project-compiler-NNK32MPG.mjs +0 -10
  97. package/dist/project-compiler-ZB4RUYVL.mjs +0 -10
  98. package/dist/project-decompiler-U55HQUHW.mjs +0 -7
  99. package/dist/pull-KOL2QAYQ.mjs +0 -109
  100. package/dist/seed-KOGEPGOJ.mjs +0 -154
  101. package/dist/server-VW6UPCHO.mjs +0 -277
  102. package/dist/verify-BYHUKARQ.mjs +0 -1833
  103. package/dist/verify-OQDEQYMS.mjs +0 -1833
@@ -4387,7 +4387,7 @@ function extractImperativeWorkflow(path, state) {
4387
4387
  const source = node.source.value;
4388
4388
  for (const spec of node.specifiers) {
4389
4389
  const localName = spec.local.name;
4390
- if (source.includes("@mmapp/react") || source.includes("@mmapp/react")) {
4390
+ if (source.includes("@mmapp/react") || source.includes("@mindmatrix/react")) {
4391
4391
  stdLibImports.add(localName);
4392
4392
  } else {
4393
4393
  importedFns.set(localName, source);
@@ -7027,7 +7027,7 @@ var import_player_core, PROP_RULES, COMPONENT_RENAMES, RENAME_EXTRA_CONFIG;
7027
7027
  var init_pure_form_emitter = __esm({
7028
7028
  "src/babel/emitters/pure-form-emitter.ts"() {
7029
7029
  "use strict";
7030
- import_player_core = require("@mmapp/player-core");
7030
+ import_player_core = require("@mindmatrix/player-core");
7031
7031
  init_transition_extractor();
7032
7032
  init_experience_transform();
7033
7033
  PROP_RULES = {
@@ -7406,7 +7406,7 @@ function createVisitor(options = {}) {
7406
7406
  if (mode === "strict" && STRICT_BANNED_HOOKS[hookName]) {
7407
7407
  const error = {
7408
7408
  code: STRICT_BANNED_HOOKS[hookName],
7409
- message: `${hookName}() is not allowed in strict mode. Use @mmapp/react effect hooks instead.`,
7409
+ message: `${hookName}() is not allowed in strict mode. Use @mindmatrix/react effect hooks instead.`,
7410
7410
  line: path.node.loc?.start.line,
7411
7411
  column: path.node.loc?.start.column,
7412
7412
  severity: "error"
@@ -7498,12 +7498,12 @@ function createVisitor(options = {}) {
7498
7498
  }
7499
7499
  }
7500
7500
  if (mode !== "strict") return;
7501
- if (source.startsWith("@mmapp/") || source.startsWith("@mmapp/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
7501
+ if (source.startsWith("@mindmatrix/") || source.startsWith("@mmapp/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
7502
7502
  return;
7503
7503
  }
7504
7504
  const error = {
7505
7505
  code: "STRICT_FORBIDDEN_IMPORT",
7506
- message: `Import from '${source}' is not allowed in strict mode. Only @mmapp/* and relative imports are permitted.`,
7506
+ message: `Import from '${source}' is not allowed in strict mode. Only @mindmatrix/* and relative imports are permitted.`,
7507
7507
  line: path.node.loc?.start.line,
7508
7508
  column: path.node.loc?.start.column,
7509
7509
  severity: "error"
@@ -10589,552 +10589,6 @@ var init_project_compiler = __esm({
10589
10589
  }
10590
10590
  });
10591
10591
 
10592
- // src/cli/auth.ts
10593
- var auth_exports = {};
10594
- __export(auth_exports, {
10595
- loadCredentials: () => loadCredentials,
10596
- login: () => login,
10597
- logout: () => logout,
10598
- resolveToken: () => resolveToken,
10599
- saveCredentials: () => saveCredentials,
10600
- whoami: () => whoami
10601
- });
10602
- function loadCredentials() {
10603
- if (!(0, import_fs4.existsSync)(CREDENTIALS_PATH)) return {};
10604
- try {
10605
- return JSON.parse((0, import_fs4.readFileSync)(CREDENTIALS_PATH, "utf-8"));
10606
- } catch {
10607
- return {};
10608
- }
10609
- }
10610
- function saveCredentials(apiUrl, token) {
10611
- (0, import_fs4.mkdirSync)(MMRC_DIR, { recursive: true, mode: 448 });
10612
- const creds = loadCredentials();
10613
- creds[apiUrl] = { token, savedAt: (/* @__PURE__ */ new Date()).toISOString() };
10614
- (0, import_fs4.writeFileSync)(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8");
10615
- try {
10616
- const { chmodSync } = require("fs");
10617
- chmodSync(CREDENTIALS_PATH, 384);
10618
- } catch {
10619
- }
10620
- }
10621
- function removeCredentials(apiUrl) {
10622
- if (!(0, import_fs4.existsSync)(CREDENTIALS_PATH)) return;
10623
- if (!apiUrl) {
10624
- (0, import_fs4.unlinkSync)(CREDENTIALS_PATH);
10625
- return;
10626
- }
10627
- const creds = loadCredentials();
10628
- delete creds[apiUrl];
10629
- if (Object.keys(creds).length === 0) {
10630
- (0, import_fs4.unlinkSync)(CREDENTIALS_PATH);
10631
- } else {
10632
- (0, import_fs4.writeFileSync)(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8");
10633
- }
10634
- }
10635
- function resolveToken(apiUrl, explicitToken) {
10636
- if (explicitToken) return explicitToken;
10637
- const envToken = process.env.MMRC_TOKEN;
10638
- if (envToken) return envToken;
10639
- const creds = loadCredentials();
10640
- const entry = creds[apiUrl];
10641
- if (entry?.token) return entry.token;
10642
- return null;
10643
- }
10644
- function prompt(question, hidden = false) {
10645
- return new Promise((resolve2) => {
10646
- const rl = (0, import_readline.createInterface)({
10647
- input: process.stdin,
10648
- output: process.stdout
10649
- });
10650
- if (hidden && process.stdin.isTTY) {
10651
- const origWrite = process.stdout.write.bind(process.stdout);
10652
- process.stdout.write = ((chunk, encodingOrCb, cb) => {
10653
- if (typeof chunk === "string" && chunk.includes(question)) {
10654
- return origWrite(chunk, encodingOrCb, cb);
10655
- }
10656
- if (typeof chunk === "string" && !chunk.includes("\n")) {
10657
- return true;
10658
- }
10659
- return origWrite(chunk, encodingOrCb, cb);
10660
- });
10661
- rl.question(question, (answer) => {
10662
- process.stdout.write = origWrite;
10663
- console.log();
10664
- rl.close();
10665
- resolve2(answer.trim());
10666
- });
10667
- } else {
10668
- rl.question(question, (answer) => {
10669
- rl.close();
10670
- resolve2(answer.trim());
10671
- });
10672
- }
10673
- });
10674
- }
10675
- async function login(apiUrl, email, password) {
10676
- if (!email) {
10677
- email = await prompt("Email: ");
10678
- }
10679
- if (!password) {
10680
- password = await prompt("Password: ", true);
10681
- }
10682
- if (!email || !password) {
10683
- throw new Error("Email and password are required");
10684
- }
10685
- console.log(`[mmrc] Logging in to ${apiUrl}...`);
10686
- const res = await fetch(`${apiUrl}/auth/login`, {
10687
- method: "POST",
10688
- headers: { "Content-Type": "application/json" },
10689
- body: JSON.stringify({ email, password })
10690
- });
10691
- if (!res.ok) {
10692
- const text = await res.text();
10693
- throw new Error(`Login failed: ${res.status} ${text}`);
10694
- }
10695
- const data = await res.json();
10696
- const token = data.token ?? data.access_token ?? data.accessToken;
10697
- if (!token) {
10698
- throw new Error("Login succeeded but no token in response");
10699
- }
10700
- saveCredentials(apiUrl, token);
10701
- const userName = data.name ?? data.user?.name ?? data.user?.email ?? email;
10702
- console.log(`[mmrc] Logged in as ${userName}`);
10703
- console.log(`[mmrc] Token saved to ${CREDENTIALS_PATH}`);
10704
- return token;
10705
- }
10706
- function logout(apiUrl) {
10707
- if (apiUrl) {
10708
- removeCredentials(apiUrl);
10709
- console.log(`[mmrc] Credentials removed for ${apiUrl}`);
10710
- } else {
10711
- removeCredentials();
10712
- console.log("[mmrc] All saved credentials removed");
10713
- }
10714
- }
10715
- async function whoami(apiUrl) {
10716
- const token = resolveToken(apiUrl);
10717
- if (!token) {
10718
- console.log("[mmrc] Not logged in. Run `mmrc login` to authenticate.");
10719
- return;
10720
- }
10721
- try {
10722
- const res = await fetch(`${apiUrl}/auth/me`, {
10723
- headers: { Authorization: `Bearer ${token}` }
10724
- });
10725
- if (!res.ok) {
10726
- if (res.status === 401) {
10727
- console.log("[mmrc] Token is expired or invalid. Run `mmrc login` to re-authenticate.");
10728
- return;
10729
- }
10730
- console.log(`[mmrc] Failed to fetch user info: ${res.status}`);
10731
- return;
10732
- }
10733
- const user = await res.json();
10734
- console.log(`[mmrc] Logged in to ${apiUrl}`);
10735
- console.log(` Name: ${user.name ?? "(unknown)"}`);
10736
- console.log(` Email: ${user.email ?? "(unknown)"}`);
10737
- if (user.id) console.log(` ID: ${user.id}`);
10738
- if (user.role) console.log(` Role: ${user.role}`);
10739
- } catch (error) {
10740
- console.log(`[mmrc] Could not connect to ${apiUrl}: ${error.message}`);
10741
- }
10742
- }
10743
- var import_fs4, import_path3, import_os, import_readline, MMRC_DIR, CREDENTIALS_PATH;
10744
- var init_auth = __esm({
10745
- "src/cli/auth.ts"() {
10746
- "use strict";
10747
- import_fs4 = require("fs");
10748
- import_path3 = require("path");
10749
- import_os = require("os");
10750
- import_readline = require("readline");
10751
- MMRC_DIR = (0, import_path3.join)((0, import_os.homedir)(), ".mmrc");
10752
- CREDENTIALS_PATH = (0, import_path3.join)(MMRC_DIR, "credentials.json");
10753
- }
10754
- });
10755
-
10756
- // src/cli/deploy.ts
10757
- var deploy_exports = {};
10758
- __export(deploy_exports, {
10759
- deploy: () => deploy,
10760
- syncServices: () => syncServices
10761
- });
10762
- async function deploy(options) {
10763
- const dir = options.dir ?? "dist/workflows";
10764
- const targetLabel = options.targetName ? ` (target: ${options.targetName})` : "";
10765
- console.log(`[mindmatrix-react] Deploying workflows from ${dir} to ${options.apiUrl}${targetLabel}...`);
10766
- const files = await (0, import_glob2.glob)(`${dir}/**/*.workflow.json`);
10767
- if (files.length === 0) {
10768
- console.log(`[mindmatrix-react] No workflow files found in ${dir}`);
10769
- return { created: [], updated: [], versioned: [], skipped: [], failed: [] };
10770
- }
10771
- const result = {
10772
- created: [],
10773
- updated: [],
10774
- versioned: [],
10775
- skipped: [],
10776
- failed: []
10777
- };
10778
- const deployedIRs = [];
10779
- for (const file of files) {
10780
- try {
10781
- const ir = JSON.parse((0, import_fs5.readFileSync)(file, "utf-8"));
10782
- const slug = ir.slug;
10783
- if (options.dryRun) {
10784
- console.log(` [dry-run] Would deploy ${slug} (${(0, import_path4.basename)(file)})`);
10785
- continue;
10786
- }
10787
- const existing = await fetchExistingDefinition(options.apiUrl, options.token, slug);
10788
- if (!existing) {
10789
- await createDefinition(options.apiUrl, options.token, ir);
10790
- console.log(` \u2713 ${slug} (created)`);
10791
- result.created.push(slug);
10792
- } else if (existing.instanceCount === 0 || options.force) {
10793
- await updateDefinition(options.apiUrl, options.token, existing.id, ir);
10794
- console.log(` \u2713 ${slug} (updated)`);
10795
- result.updated.push(slug);
10796
- } else {
10797
- const newVersion = bumpVersion(existing.version);
10798
- ir.version = newVersion;
10799
- await createDefinition(options.apiUrl, options.token, ir);
10800
- console.log(` \u2713 ${slug} v${newVersion} (new version, ${existing.instanceCount} instances on v${existing.version})`);
10801
- result.versioned.push(slug);
10802
- }
10803
- deployedIRs.push(ir);
10804
- } catch (error) {
10805
- const slug = (0, import_path4.basename)(file).replace(".workflow.json", "");
10806
- const msg = error.message;
10807
- console.error(` \u2717 ${slug}: ${msg}`);
10808
- result.failed.push({ slug, error: msg });
10809
- }
10810
- }
10811
- if (!options.dryRun) {
10812
- for (const ir of deployedIRs) {
10813
- const serviceResult = await syncServices(options.apiUrl, options.token, ir);
10814
- if (serviceResult) {
10815
- if (!result.services) {
10816
- result.services = { registered: [], updated: [], failed: [] };
10817
- }
10818
- result.services.registered.push(...serviceResult.registered);
10819
- result.services.updated.push(...serviceResult.updated);
10820
- result.services.failed.push(...serviceResult.failed);
10821
- }
10822
- }
10823
- }
10824
- if (options.reportFile) {
10825
- (0, import_fs5.writeFileSync)(options.reportFile, JSON.stringify(result, null, 2), "utf-8");
10826
- console.log(`
10827
- Report written to ${options.reportFile}`);
10828
- }
10829
- const total = result.created.length + result.updated.length + result.versioned.length;
10830
- console.log(
10831
- `
10832
- [mindmatrix-react] Deployed ${total} workflows (${result.created.length} created, ${result.updated.length} updated, ${result.versioned.length} versioned, ${result.failed.length} failed)`
10833
- );
10834
- if (result.services) {
10835
- const svcTotal = result.services.registered.length + result.services.updated.length;
10836
- if (svcTotal > 0 || result.services.failed.length > 0) {
10837
- console.log(
10838
- `[mindmatrix-react] Synced ${svcTotal} services (${result.services.registered.length} registered, ${result.services.updated.length} updated, ${result.services.failed.length} failed)`
10839
- );
10840
- }
10841
- }
10842
- return result;
10843
- }
10844
- async function fetchExistingDefinition(apiUrl, token, slug) {
10845
- try {
10846
- const res = await fetch(`${apiUrl}/workflow/definitions?slug=${encodeURIComponent(slug)}`, {
10847
- headers: { Authorization: `Bearer ${token}` }
10848
- });
10849
- if (!res.ok) return null;
10850
- const data = await res.json();
10851
- const definitions = Array.isArray(data) ? data : data.items ?? data.data;
10852
- if (!definitions || definitions.length === 0) return null;
10853
- const def = definitions[0];
10854
- return {
10855
- id: def.id,
10856
- slug: def.slug,
10857
- version: def.version || "0.1.0",
10858
- instanceCount: def.instanceCount ?? def.instance_count ?? 0
10859
- };
10860
- } catch {
10861
- return null;
10862
- }
10863
- }
10864
- async function createDefinition(apiUrl, token, ir) {
10865
- const res = await fetch(`${apiUrl}/workflow/definitions`, {
10866
- method: "POST",
10867
- headers: {
10868
- "Content-Type": "application/json",
10869
- Authorization: `Bearer ${token}`
10870
- },
10871
- body: JSON.stringify(ir)
10872
- });
10873
- if (!res.ok) {
10874
- const errorText = await res.text();
10875
- throw new Error(`Create failed: ${res.status} ${errorText}`);
10876
- }
10877
- }
10878
- async function updateDefinition(apiUrl, token, id, ir) {
10879
- const { slug: _slug, ...updatePayload } = ir;
10880
- const res = await fetch(`${apiUrl}/workflow/definitions/${id}`, {
10881
- method: "PATCH",
10882
- headers: {
10883
- "Content-Type": "application/json",
10884
- Authorization: `Bearer ${token}`
10885
- },
10886
- body: JSON.stringify(updatePayload)
10887
- });
10888
- if (!res.ok) {
10889
- const errorText = await res.text();
10890
- throw new Error(`Update failed: ${res.status} ${errorText}`);
10891
- }
10892
- }
10893
- function bumpVersion(version) {
10894
- const parts = version.split(".");
10895
- if (parts.length !== 3) return `${version}.1`;
10896
- const patch = parseInt(parts[2], 10) || 0;
10897
- return `${parts[0]}.${parts[1]}.${patch + 1}`;
10898
- }
10899
- async function syncServices(apiUrl, token, ir) {
10900
- const metadata = ir.metadata;
10901
- const orchestration = metadata?.orchestration;
10902
- const services = orchestration?.services;
10903
- if (!services || Object.keys(services).length === 0) return null;
10904
- const result = { registered: [], updated: [], failed: [] };
10905
- for (const [name, config] of Object.entries(services)) {
10906
- try {
10907
- const registration = {
10908
- name,
10909
- connection: {
10910
- type: config.type || "webhook",
10911
- url: config.url,
10912
- queue: config.queue
10913
- },
10914
- actions: config.actions || [],
10915
- labels: config.labels || {}
10916
- };
10917
- const existing = await fetchExistingService(apiUrl, token, name);
10918
- if (existing) {
10919
- await fetch(`${apiUrl}/services/${existing.id}`, {
10920
- method: "PATCH",
10921
- headers: {
10922
- "Content-Type": "application/json",
10923
- Authorization: `Bearer ${token}`
10924
- },
10925
- body: JSON.stringify(registration)
10926
- });
10927
- console.log(` \u2713 service: ${name} (updated)`);
10928
- result.updated.push(name);
10929
- } else {
10930
- const res = await fetch(`${apiUrl}/services`, {
10931
- method: "POST",
10932
- headers: {
10933
- "Content-Type": "application/json",
10934
- Authorization: `Bearer ${token}`
10935
- },
10936
- body: JSON.stringify(registration)
10937
- });
10938
- if (!res.ok) {
10939
- const errorText = await res.text();
10940
- throw new Error(`Register failed: ${res.status} ${errorText}`);
10941
- }
10942
- console.log(` \u2713 service: ${name} (registered)`);
10943
- result.registered.push(name);
10944
- }
10945
- } catch (error) {
10946
- const msg = error.message;
10947
- console.error(` \u2717 service: ${name}: ${msg}`);
10948
- result.failed.push(name);
10949
- }
10950
- }
10951
- return result;
10952
- }
10953
- async function fetchExistingService(apiUrl, token, name) {
10954
- try {
10955
- const res = await fetch(`${apiUrl}/services?name=${encodeURIComponent(name)}`, {
10956
- headers: { Authorization: `Bearer ${token}` }
10957
- });
10958
- if (!res.ok) return null;
10959
- const data = await res.json();
10960
- const servicesList = Array.isArray(data) ? data : data.services ?? data.items ?? data.data;
10961
- if (!servicesList || servicesList.length === 0) return null;
10962
- const found = servicesList.find((s) => s.name === name);
10963
- return found ? { id: found.id, name: found.name } : null;
10964
- } catch {
10965
- return null;
10966
- }
10967
- }
10968
- var import_glob2, import_fs5, import_path4;
10969
- var init_deploy = __esm({
10970
- "src/cli/deploy.ts"() {
10971
- "use strict";
10972
- import_glob2 = require("glob");
10973
- import_fs5 = require("fs");
10974
- import_path4 = require("path");
10975
- }
10976
- });
10977
-
10978
- // src/cli/seed.ts
10979
- var seed_exports = {};
10980
- __export(seed_exports, {
10981
- generateFieldValue: () => generateFieldValue,
10982
- generateInstanceData: () => generateInstanceData,
10983
- seedInstances: () => seedInstances
10984
- });
10985
- function randomInt(min, max) {
10986
- return Math.floor(Math.random() * (max - min + 1)) + min;
10987
- }
10988
- function randomPick(arr) {
10989
- return arr[Math.floor(Math.random() * arr.length)];
10990
- }
10991
- function loremSentence(words = 5) {
10992
- const result = [];
10993
- for (let i = 0; i < words; i++) result.push(randomPick(LOREM_WORDS));
10994
- const s = result.join(" ");
10995
- return s.charAt(0).toUpperCase() + s.slice(1);
10996
- }
10997
- function generateFieldValue(field, index) {
10998
- if (field.default_value !== void 0 && field.default_value !== null) {
10999
- return field.default_value;
11000
- }
11001
- if (field.options && field.options.length > 0) {
11002
- return field.options[index % field.options.length].value;
11003
- }
11004
- const ft = (field.field_type ?? field.type ?? "text").toLowerCase();
11005
- switch (ft) {
11006
- case "text":
11007
- case "string":
11008
- case "textarea":
11009
- case "rich_text": {
11010
- const name = field.name.toLowerCase();
11011
- if (name.includes("email")) return `${randomPick(FIRST_NAMES).toLowerCase()}${++_counter}@${randomPick(DOMAINS)}`;
11012
- if (name.includes("name") && name.includes("first")) return randomPick(FIRST_NAMES);
11013
- if (name.includes("name") && name.includes("last")) return randomPick(LAST_NAMES);
11014
- if (name.includes("name") || name === "title") return `${randomPick(FIRST_NAMES)} ${randomPick(LAST_NAMES)}`;
11015
- if (name.includes("company") || name.includes("org")) return randomPick(COMPANIES);
11016
- if (name.includes("phone")) return `+1-555-${randomInt(100, 999)}-${randomInt(1e3, 9999)}`;
11017
- if (name.includes("url") || name.includes("website")) return `https://${randomPick(DOMAINS)}/${field.name}`;
11018
- if (name.includes("description") || name.includes("note") || name.includes("comment")) return loremSentence(randomInt(8, 15));
11019
- if (name.includes("address")) return `${randomInt(100, 9999)} ${loremSentence(2)} St`;
11020
- return loremSentence(randomInt(2, 5));
11021
- }
11022
- case "number":
11023
- case "numeric":
11024
- case "integer":
11025
- case "int": {
11026
- const name = field.name.toLowerCase();
11027
- if (name.includes("price") || name.includes("amount") || name.includes("cost") || name.includes("salary"))
11028
- return randomInt(1e3, 99999) / 100;
11029
- if (name.includes("age")) return randomInt(18, 65);
11030
- if (name.includes("quantity") || name.includes("count") || name.includes("qty")) return randomInt(1, 100);
11031
- if (name.includes("percent") || name.includes("rate")) return randomInt(1, 100);
11032
- return randomInt(1, 1e3);
11033
- }
11034
- case "currency":
11035
- case "decimal":
11036
- return randomInt(100, 999999) / 100;
11037
- case "boolean":
11038
- case "bool":
11039
- case "checkbox":
11040
- case "toggle":
11041
- return index % 2 === 0;
11042
- case "date":
11043
- case "datetime":
11044
- case "timestamptz": {
11045
- const d = /* @__PURE__ */ new Date();
11046
- d.setDate(d.getDate() - randomInt(0, 365));
11047
- return d.toISOString().split("T")[0];
11048
- }
11049
- case "select":
11050
- case "enum":
11051
- case "multi_select":
11052
- return field.options?.[index % (field.options?.length || 1)]?.value ?? "option_1";
11053
- case "email":
11054
- return `${randomPick(FIRST_NAMES).toLowerCase()}${++_counter}@${randomPick(DOMAINS)}`;
11055
- case "url":
11056
- return `https://${randomPick(DOMAINS)}/${field.name}`;
11057
- case "json":
11058
- case "object":
11059
- return {};
11060
- case "array":
11061
- return [];
11062
- default:
11063
- return loremSentence(3);
11064
- }
11065
- }
11066
- function generateInstanceData(fields, index) {
11067
- const data = {};
11068
- for (const field of fields) {
11069
- if (field.name === "id" || field.name === "created_at" || field.name === "updated_at") continue;
11070
- data[field.name] = generateFieldValue(field, index);
11071
- }
11072
- return data;
11073
- }
11074
- async function seedInstances(options) {
11075
- const dir = options.dir ?? "dist/workflows";
11076
- const count = options.count ?? 7;
11077
- const result = { created: 0, definitions: 0, errors: [] };
11078
- const files = await (0, import_glob3.glob)(`${dir}/**/*.workflow.json`);
11079
- if (files.length === 0) return result;
11080
- for (const file of files) {
11081
- let def;
11082
- try {
11083
- def = JSON.parse((0, import_fs6.readFileSync)(file, "utf-8"));
11084
- } catch {
11085
- continue;
11086
- }
11087
- if (!def.slug || !def.fields || def.fields.length === 0) continue;
11088
- const startState = def.states?.find((s) => s.state_type === "START")?.name ?? def.states?.[0]?.name ?? "initial";
11089
- let defCreated = 0;
11090
- for (let i = 0; i < count; i++) {
11091
- const stateData = generateInstanceData(def.fields, i);
11092
- try {
11093
- const resp = await fetch(`${options.apiUrl}/workflow/instances`, {
11094
- method: "POST",
11095
- headers: {
11096
- "Content-Type": "application/json",
11097
- "Authorization": `Bearer ${options.token}`
11098
- },
11099
- body: JSON.stringify({
11100
- definition_slug: def.slug,
11101
- initial_state: startState,
11102
- state_data: stateData
11103
- })
11104
- });
11105
- if (resp.ok) {
11106
- defCreated++;
11107
- } else {
11108
- const errText = await resp.text().catch(() => resp.statusText);
11109
- result.errors.push(`${def.slug}[${i}]: ${resp.status} ${errText}`);
11110
- }
11111
- } catch (e) {
11112
- result.errors.push(`${def.slug}[${i}]: ${e instanceof Error ? e.message : String(e)}`);
11113
- }
11114
- }
11115
- if (defCreated > 0) {
11116
- result.definitions++;
11117
- result.created += defCreated;
11118
- console.log(` [seed] ${def.slug}: ${defCreated} instances created`);
11119
- }
11120
- }
11121
- return result;
11122
- }
11123
- var import_fs6, import_glob3, FIRST_NAMES, LAST_NAMES, COMPANIES, LOREM_WORDS, DOMAINS, _counter;
11124
- var init_seed = __esm({
11125
- "src/cli/seed.ts"() {
11126
- "use strict";
11127
- import_fs6 = require("fs");
11128
- import_glob3 = require("glob");
11129
- FIRST_NAMES = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry"];
11130
- LAST_NAMES = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis"];
11131
- COMPANIES = ["Acme Corp", "TechStart Inc", "GlobalTrade Ltd", "DataFlow Systems", "CloudPeak"];
11132
- LOREM_WORDS = ["lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", "tempor"];
11133
- DOMAINS = ["example.com", "test.org", "demo.io", "sample.net"];
11134
- _counter = 0;
11135
- }
11136
- });
11137
-
11138
10592
  // src/dev-server.ts
11139
10593
  var dev_server_exports = {};
11140
10594
  __export(dev_server_exports, {
@@ -11701,560 +11155,7 @@ async function startWatchMode(options) {
11701
11155
  });
11702
11156
  }
11703
11157
 
11704
- // src/cli/local-server.ts
11705
- var http = __toESM(require("http"));
11706
- var import_node_crypto = require("crypto");
11707
- var MemoryStore = class {
11708
- constructor() {
11709
- this.definitions = /* @__PURE__ */ new Map();
11710
- this.instances = /* @__PURE__ */ new Map();
11711
- this.slugIndex = /* @__PURE__ */ new Map();
11712
- }
11713
- // slug → id
11714
- // ── Definitions ──────────────────────────────────────────────────────
11715
- createDefinition(input) {
11716
- if (this.slugIndex.has(input.slug)) {
11717
- const existing = this.definitions.get(this.slugIndex.get(input.slug));
11718
- if (existing) return existing;
11719
- }
11720
- const now = (/* @__PURE__ */ new Date()).toISOString();
11721
- const def = {
11722
- id: input.id ?? (0, import_node_crypto.randomUUID)(),
11723
- slug: input.slug,
11724
- name: input.name,
11725
- version: input.version ?? "1.0.0",
11726
- description: input.description ?? null,
11727
- category: input.category ?? "workflow",
11728
- fields: input.fields ?? [],
11729
- states: input.states ?? [],
11730
- transitions: input.transitions ?? [],
11731
- roles: input.roles ?? [],
11732
- experience: input.experience ?? null,
11733
- metadata: input.metadata ?? {},
11734
- child_definitions: input.child_definitions ?? [],
11735
- is_immutable: input.is_immutable ?? false,
11736
- tags: input.tags ?? [],
11737
- inline_tags: input.inline_tags ?? [],
11738
- created_at: now,
11739
- updated_at: now
11740
- };
11741
- this.definitions.set(def.id, def);
11742
- this.slugIndex.set(def.slug, def.id);
11743
- return def;
11744
- }
11745
- getDefinition(idOrSlug) {
11746
- const byId = this.definitions.get(idOrSlug);
11747
- if (byId) return byId;
11748
- const id = this.slugIndex.get(idOrSlug);
11749
- if (id) return this.definitions.get(id);
11750
- return void 0;
11751
- }
11752
- listDefinitions(opts) {
11753
- let items = Array.from(this.definitions.values());
11754
- if (opts?.category) {
11755
- items = items.filter((d) => d.category === opts.category);
11756
- }
11757
- const total = items.length;
11758
- const offset = opts?.offset ?? 0;
11759
- const limit = opts?.limit ?? 50;
11760
- items = items.slice(offset, offset + limit);
11761
- return { items, total };
11762
- }
11763
- patchDefinition(id, patch) {
11764
- const def = this.definitions.get(id);
11765
- if (!def) return void 0;
11766
- Object.assign(def, patch, { updated_at: (/* @__PURE__ */ new Date()).toISOString() });
11767
- return def;
11768
- }
11769
- deleteDefinition(id) {
11770
- const def = this.definitions.get(id);
11771
- if (!def) return false;
11772
- this.slugIndex.delete(def.slug);
11773
- this.definitions.delete(id);
11774
- return true;
11775
- }
11776
- // ── Instances ────────────────────────────────────────────────────────
11777
- createInstance(input) {
11778
- const def = this.getDefinition(input.definition_id) ?? this.getDefinition(input.definition_slug);
11779
- if (!def) return null;
11780
- const initialState = def.states.find((s) => s.type === "START" || s.type === "initial");
11781
- const stateName = initialState?.name ?? "initial";
11782
- const stateData = {};
11783
- for (const field of def.fields) {
11784
- if (field.default_value !== void 0) {
11785
- stateData[field.name] = field.default_value;
11786
- }
11787
- }
11788
- Object.assign(stateData, input.state_data ?? {});
11789
- const now = (/* @__PURE__ */ new Date()).toISOString();
11790
- const inst = {
11791
- id: (0, import_node_crypto.randomUUID)(),
11792
- definition_id: def.id,
11793
- definition_slug: def.slug,
11794
- current_state: stateName,
11795
- state_data: stateData,
11796
- execution_lock_version: 0,
11797
- event_log: [{
11798
- event_type: "transition",
11799
- message: `Instance created in state '${stateName}'`,
11800
- timestamp: now
11801
- }],
11802
- created_at: now,
11803
- updated_at: now
11804
- };
11805
- this.instances.set(inst.id, inst);
11806
- return inst;
11807
- }
11808
- getInstance(id) {
11809
- return this.instances.get(id);
11810
- }
11811
- listInstances(opts) {
11812
- let items = Array.from(this.instances.values());
11813
- if (opts?.definition_id) {
11814
- items = items.filter((i) => i.definition_id === opts.definition_id);
11815
- }
11816
- const total = items.length;
11817
- const offset = opts?.offset ?? 0;
11818
- const limit = opts?.limit ?? 50;
11819
- items = items.slice(offset, offset + limit);
11820
- return { items, total };
11821
- }
11822
- // ── Execute Action (Transition) ──────────────────────────────────────
11823
- executeAction(input) {
11824
- const def = this.getDefinition(input.definition_id);
11825
- if (!def) return { success: false, error: "Definition not found" };
11826
- let inst;
11827
- if (input.instance_id) {
11828
- const existing = this.instances.get(input.instance_id);
11829
- if (!existing) return { success: false, error: "Instance not found" };
11830
- inst = existing;
11831
- } else {
11832
- const created = this.createInstance({
11833
- definition_id: def.id,
11834
- definition_slug: def.slug,
11835
- state_data: input.payload
11836
- });
11837
- if (!created) return { success: false, error: "Failed to create instance" };
11838
- inst = created;
11839
- }
11840
- if (input.payload && input.instance_id) {
11841
- Object.assign(inst.state_data, input.payload);
11842
- }
11843
- const transition = def.transitions.find((t23) => t23.name === input.action_name && t23.from.includes(inst.current_state));
11844
- if (!transition) {
11845
- return {
11846
- success: false,
11847
- instance_id: inst.id,
11848
- from_state: inst.current_state,
11849
- to_state: null,
11850
- state_data: inst.state_data,
11851
- error: `No transition '${input.action_name}' from state '${inst.current_state}'`
11852
- };
11853
- }
11854
- const fromState = inst.current_state;
11855
- const now = (/* @__PURE__ */ new Date()).toISOString();
11856
- const events = [];
11857
- let lastEvalResult = null;
11858
- events.push({ event_type: "transition", message: `Transition '${transition.name}' started: ${fromState} \u2192 ${transition.to}`, timestamp: now });
11859
- for (const action of transition.actions ?? []) {
11860
- try {
11861
- if (action.type === "set_field") {
11862
- const field = action.config?.field;
11863
- if (action.config?.expression) {
11864
- const expr = action.config.expression;
11865
- const result = this.evaluateSimpleExpression(expr, inst.state_data);
11866
- inst.state_data[field] = result;
11867
- } else if (action.config?.value !== void 0) {
11868
- inst.state_data[field] = action.config.value;
11869
- }
11870
- events.push({ event_type: "action_executed", message: `transition action 'set_field' succeeded`, timestamp: now });
11871
- } else if (action.type === "eval") {
11872
- const expr = action.config?.expression;
11873
- lastEvalResult = this.evaluateSimpleExpression(expr, inst.state_data);
11874
- events.push({ event_type: "action_executed", message: `transition action 'eval' succeeded`, timestamp: now });
11875
- } else {
11876
- events.push({ event_type: "action_executed", message: `transition action '${action.type}' succeeded (no-op in local mode)`, timestamp: now });
11877
- }
11878
- } catch (err) {
11879
- const msg = err instanceof Error ? err.message : String(err);
11880
- events.push({ event_type: "action_failed", message: `transition action '${action.type}' failed: ${msg}`, timestamp: now });
11881
- return {
11882
- success: false,
11883
- instance_id: inst.id,
11884
- from_state: fromState,
11885
- to_state: null,
11886
- state_data: inst.state_data,
11887
- event_log: events,
11888
- error: `transition action failed: ${msg}`
11889
- };
11890
- }
11891
- }
11892
- inst.current_state = transition.to;
11893
- inst.execution_lock_version++;
11894
- inst.updated_at = now;
11895
- events.push({ event_type: "transition", message: `State changed: ${fromState} \u2192 ${transition.to}`, timestamp: now });
11896
- inst.event_log.push(...events);
11897
- return {
11898
- success: true,
11899
- instance_id: inst.id,
11900
- from_state: fromState,
11901
- to_state: transition.to,
11902
- state_data: inst.state_data,
11903
- result: lastEvalResult,
11904
- event_log: events
11905
- };
11906
- }
11907
- /**
11908
- * Minimal expression evaluator for local dev mode.
11909
- * Handles: field references, arithmetic, string literals, simple comparisons.
11910
- * Does NOT handle: while loops, if/else, function calls, multi-statement blocks.
11911
- * For full evaluation, use mm-napi when available.
11912
- */
11913
- evaluateSimpleExpression(expr, context) {
11914
- if (context[expr] !== void 0) return context[expr];
11915
- const arithMatch = expr.match(/^(\w+)\s*([+\-*/])\s*(\d+(?:\.\d+)?)$/);
11916
- if (arithMatch) {
11917
- const [, field, op, numStr] = arithMatch;
11918
- const left = Number(context[field] ?? 0);
11919
- const right = Number(numStr);
11920
- switch (op) {
11921
- case "+":
11922
- return left + right;
11923
- case "-":
11924
- return left - right;
11925
- case "*":
11926
- return left * right;
11927
- case "/":
11928
- return right !== 0 ? left / right : 0;
11929
- }
11930
- }
11931
- if (/^\d+(\.\d+)?$/.test(expr.trim())) {
11932
- return Number(expr.trim());
11933
- }
11934
- const strMatch = expr.match(/^["'](.*)["']$/);
11935
- if (strMatch) return strMatch[1];
11936
- try {
11937
- const keys = Object.keys(context);
11938
- const values = Object.values(context);
11939
- const fn = new Function(...keys, `"use strict"; return (${expr});`);
11940
- return fn(...values);
11941
- } catch {
11942
- return null;
11943
- }
11944
- }
11945
- };
11946
- async function startLocalServer(options = {}) {
11947
- const { port = 4200, noAuth = true } = options;
11948
- const store = new MemoryStore();
11949
- const startedAt = (/* @__PURE__ */ new Date()).toISOString();
11950
- function json(res, status, body) {
11951
- const data = JSON.stringify(body);
11952
- res.writeHead(status, {
11953
- "Content-Type": "application/json",
11954
- "Access-Control-Allow-Origin": "*",
11955
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
11956
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
11957
- "Content-Length": Buffer.byteLength(data)
11958
- });
11959
- res.end(data);
11960
- }
11961
- function readBody(req) {
11962
- return new Promise((resolve2, reject) => {
11963
- const chunks = [];
11964
- req.on("data", (chunk) => chunks.push(chunk));
11965
- req.on("end", () => resolve2(Buffer.concat(chunks).toString()));
11966
- req.on("error", reject);
11967
- });
11968
- }
11969
- function parseQuery(url) {
11970
- const idx = url.indexOf("?");
11971
- if (idx === -1) return {};
11972
- const params = {};
11973
- const qs = url.slice(idx + 1);
11974
- for (const pair of qs.split("&")) {
11975
- const [k, v] = pair.split("=");
11976
- if (k) params[decodeURIComponent(k)] = decodeURIComponent(v ?? "");
11977
- }
11978
- return params;
11979
- }
11980
- const server = http.createServer(async (req, res) => {
11981
- const method = req.method?.toUpperCase() ?? "GET";
11982
- const rawUrl = req.url ?? "/";
11983
- const queryStart = rawUrl.indexOf("?");
11984
- const path = queryStart >= 0 ? rawUrl.slice(0, queryStart) : rawUrl;
11985
- const query = parseQuery(rawUrl);
11986
- if (method === "OPTIONS") {
11987
- res.writeHead(204, {
11988
- "Access-Control-Allow-Origin": "*",
11989
- "Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
11990
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
11991
- "Access-Control-Max-Age": "86400"
11992
- });
11993
- res.end();
11994
- return;
11995
- }
11996
- try {
11997
- if (path === "/health" && method === "GET") {
11998
- return json(res, 200, {
11999
- status: "ok",
12000
- service: "mm-local-dev",
12001
- mode: "in-memory",
12002
- started_at: startedAt,
12003
- definitions: store.definitions.size,
12004
- instances: store.instances.size
12005
- });
12006
- }
12007
- if (path === "/api/v1/auth/login" && (method === "POST" || method === "GET")) {
12008
- return json(res, 200, {
12009
- token: "dev-token-local",
12010
- user: {
12011
- id: "dev-user-001",
12012
- email: "dev@localhost",
12013
- role: "admin",
12014
- name: "Local Developer"
12015
- }
12016
- });
12017
- }
12018
- if (path === "/api/v1/workflow/definitions" && method === "GET") {
12019
- const result = store.listDefinitions({
12020
- category: query.category,
12021
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
12022
- offset: query.offset ? parseInt(query.offset, 10) : void 0
12023
- });
12024
- if (query.slug) {
12025
- const def = store.getDefinition(query.slug);
12026
- return json(res, 200, { items: def ? [def] : [], total: def ? 1 : 0 });
12027
- }
12028
- return json(res, 200, result);
12029
- }
12030
- const defMatch = path.match(/^\/api\/v1\/workflow\/definitions\/([^/]+)$/);
12031
- if (defMatch && method === "GET") {
12032
- const def = store.getDefinition(defMatch[1]);
12033
- if (!def) return json(res, 404, { error: "Not found" });
12034
- return json(res, 200, def);
12035
- }
12036
- if (path === "/api/v1/workflow/definitions" && method === "POST") {
12037
- const body = JSON.parse(await readBody(req));
12038
- const def = store.createDefinition(body);
12039
- return json(res, 201, def);
12040
- }
12041
- if (defMatch && method === "PATCH") {
12042
- const body = JSON.parse(await readBody(req));
12043
- const updated = store.patchDefinition(defMatch[1], body);
12044
- if (!updated) return json(res, 404, { error: "Not found" });
12045
- return json(res, 200, updated);
12046
- }
12047
- if (defMatch && method === "DELETE") {
12048
- const deleted = store.deleteDefinition(defMatch[1]);
12049
- if (!deleted) return json(res, 404, { error: "Not found" });
12050
- return json(res, 204, null);
12051
- }
12052
- if (path === "/api/v1/workflow/instances" && method === "GET") {
12053
- const result = store.listInstances({
12054
- definition_id: query.definition_id,
12055
- limit: query.limit ? parseInt(query.limit, 10) : void 0,
12056
- offset: query.offset ? parseInt(query.offset, 10) : void 0
12057
- });
12058
- return json(res, 200, result);
12059
- }
12060
- if (path === "/api/v1/workflow/instances" && method === "POST") {
12061
- const body = JSON.parse(await readBody(req));
12062
- const inst = store.createInstance(body);
12063
- if (!inst) return json(res, 404, { error: "Definition not found" });
12064
- return json(res, 201, inst);
12065
- }
12066
- const instMatch = path.match(/^\/api\/v1\/workflow\/instances\/([^/]+)$/);
12067
- if (instMatch && method === "GET") {
12068
- const inst = store.getInstance(instMatch[1]);
12069
- if (!inst) return json(res, 404, { error: "Not found" });
12070
- return json(res, 200, inst);
12071
- }
12072
- if (path === "/api/v1/workflow/execute-action" && method === "POST") {
12073
- const body = JSON.parse(await readBody(req));
12074
- const result = store.executeAction(body);
12075
- return json(res, 200, result);
12076
- }
12077
- const dataMatch = path.match(/^\/api\/v1\/data\/([^/]+)$/);
12078
- if (dataMatch && method === "GET") {
12079
- const def = store.getDefinition(dataMatch[1]);
12080
- if (!def) return json(res, 404, { error: "Not found" });
12081
- const instances = store.listInstances({ definition_id: def.id });
12082
- return json(res, 200, instances);
12083
- }
12084
- if (path.startsWith("/api/v1/")) {
12085
- return json(res, 501, { error: "Not implemented in local dev mode", path, method });
12086
- }
12087
- return json(res, 404, { error: "Not found", path });
12088
- } catch (err) {
12089
- const message = err instanceof Error ? err.message : String(err);
12090
- console.error(`[mm-local] ${method} ${path} \u2014 Error: ${message}`);
12091
- return json(res, 500, { error: message });
12092
- }
12093
- });
12094
- return new Promise((resolve2, reject) => {
12095
- server.on("error", (err) => {
12096
- if (err.code === "EADDRINUSE") {
12097
- reject(new Error(`Port ${port} is already in use. Is another server running?`));
12098
- } else {
12099
- reject(err);
12100
- }
12101
- });
12102
- server.listen(port, () => {
12103
- console.log(`[mm-local] Local API server running at http://localhost:${port}`);
12104
- console.log(`[mm-local] Mode: in-memory (data lost on restart)`);
12105
- console.log(`[mm-local] Auth: disabled (all requests accepted)`);
12106
- resolve2({
12107
- server,
12108
- port,
12109
- store,
12110
- async close() {
12111
- return new Promise((res) => {
12112
- server.close(() => {
12113
- console.log("[mm-local] Local API server stopped");
12114
- res();
12115
- });
12116
- });
12117
- }
12118
- });
12119
- });
12120
- });
12121
- }
12122
-
12123
11158
  // src/dev-server.ts
12124
- var currentErrors = null;
12125
- function escapeHtml(s) {
12126
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12127
- }
12128
- function renderErrorOverlay(errors) {
12129
- const cards = errors.map((err) => {
12130
- const loc = err.line ? `${err.file}:${err.line}${err.column ? ":" + err.column : ""}` : err.file;
12131
- 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>` : "";
12132
- return `<div style="background:#2d1b1b;border:1px solid #5c2020;border-radius:8px;padding:16px 20px;margin-bottom:12px">
12133
- <div style="color:#ff6b6b;font-family:monospace;font-size:13px;margin-bottom:6px">${escapeHtml(loc)}</div>
12134
- <div style="color:#ffa0a0;font-size:15px;font-weight:500">${escapeHtml(err.message)}</div>${snippet}</div>`;
12135
- }).join("\n");
12136
- return `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
12137
- <title>Compile Error - MindMatrix Dev</title>
12138
- <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>
12139
- <body><div style="max-width:800px;margin:0 auto">
12140
- <div style="display:flex;align-items:center;gap:12px;margin-bottom:24px">
12141
- <div style="background:#5c2020;color:#ff6b6b;font-size:14px;font-weight:600;padding:4px 10px;border-radius:4px">COMPILE ERROR</div>
12142
- <div style="color:#888;font-size:13px">${errors.length} error${errors.length !== 1 ? "s" : ""}</div></div>
12143
- ${cards}
12144
- <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>
12145
- <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>
12146
- </body></html>`;
12147
- }
12148
- function errorOverlayMiddleware() {
12149
- return (req, res, next) => {
12150
- if (!currentErrors || !req.url) return next();
12151
- const url = req.url;
12152
- if (url.startsWith("/api") || url.startsWith("/health") || url.startsWith("/ws") || url.startsWith("/__mm_dev") || url.startsWith("/@") || url.startsWith("/node_modules")) return next();
12153
- const accept = req.headers?.accept ?? "";
12154
- if (!accept.includes("text/html")) return next();
12155
- res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
12156
- res.end(renderErrorOverlay(currentErrors));
12157
- };
12158
- }
12159
- async function resolveDevToken(apiUrl, explicit) {
12160
- if (explicit) return explicit;
12161
- try {
12162
- const { resolveToken: resolveToken2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
12163
- const s = resolveToken2(apiUrl);
12164
- if (s) return s;
12165
- } catch {
12166
- }
12167
- try {
12168
- const resp = await fetch(`${apiUrl}/auth/login`, {
12169
- method: "POST",
12170
- headers: { "Content-Type": "application/json" },
12171
- body: JSON.stringify({ email: "admin@mindmatrix.com", password: "Admin123!" })
12172
- });
12173
- if (resp.ok) {
12174
- const data = await resp.json();
12175
- const token = data.token ?? data.access_token;
12176
- if (token) {
12177
- try {
12178
- const { saveCredentials: saveCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
12179
- saveCredentials2(apiUrl, token);
12180
- } catch {
12181
- }
12182
- return token;
12183
- }
12184
- }
12185
- } catch {
12186
- }
12187
- return process.env.MINDMATRIX_TOKEN;
12188
- }
12189
- async function checkBackendHealth(apiUrl) {
12190
- try {
12191
- const base = apiUrl.replace(/\/api\/v1\/?$/, "");
12192
- const resp = await fetch(`${base}/health`, { signal: AbortSignal.timeout(5e3) });
12193
- if (resp.ok) {
12194
- const d = await resp.json();
12195
- return { ok: true, version: d.version, db: d.database };
12196
- }
12197
- return { ok: resp.status < 500 };
12198
- } catch {
12199
- return { ok: false };
12200
- }
12201
- }
12202
- async function initialBuildDeploy(src, outDir, mode, apiUrl, token) {
12203
- console.log("[mm-dev] Compiling project...");
12204
- const buildResult = await build({ src, outDir, mode, skipTypeCheck: true });
12205
- if (buildResult.errors > 0) {
12206
- currentErrors = buildResult.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
12207
- console.error(`[mm-dev] Build failed with ${buildResult.errors} error(s) -- error overlay active`);
12208
- return { buildResult, deployed: false, slug: void 0 };
12209
- }
12210
- currentErrors = null;
12211
- if (buildResult.compiled === 0) return { buildResult, deployed: false, slug: void 0 };
12212
- console.log(`[mm-dev] Compiled ${buildResult.compiled} definition(s)`);
12213
- try {
12214
- const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
12215
- const result = await deploy2({ apiUrl, token, dir: outDir });
12216
- const total = result.created.length + result.updated.length + result.versioned.length;
12217
- if (total > 0) console.log(`[mm-dev] Deployed: ${result.created.length} created, ${result.updated.length} updated`);
12218
- return { buildResult, deployed: true, slug: buildResult.definitions?.[0]?.slug };
12219
- } catch (e) {
12220
- console.warn(`[mm-dev] Deploy failed: ${e instanceof Error ? e.message : e}`);
12221
- return { buildResult, deployed: false, slug: void 0 };
12222
- }
12223
- }
12224
- function printBanner(o) {
12225
- const l = "-".repeat(58);
12226
- console.log(`
12227
- ${l}
12228
- MindMatrix Dev Server
12229
- ${l}
12230
- `);
12231
- console.log(` Preview: http://localhost:${o.port}`);
12232
- console.log(` API Proxy: /api/* -> ${o.apiUrl}`);
12233
- console.log(` WebSocket: ws://localhost:${o.port}/__mm_dev`);
12234
- console.log(` Watching: ${o.src} (${o.include.join(", ")})
12235
- `);
12236
- console.log(` Backend: ${o.health.ok ? "connected" : "unreachable"}${o.health.version ? ` (v${o.health.version})` : ""}`);
12237
- if (o.health.db) console.log(` Database: ${o.health.db}`);
12238
- console.log(` Auth: ${o.token ? "authenticated" : "no token"}`);
12239
- if (o.compiled > 0) {
12240
- console.log(` Blueprint: ${o.slug ?? "unknown"} (${o.compiled} defs)`);
12241
- console.log(` Deploy: ${o.deployed ? "synced" : "pending"}`);
12242
- }
12243
- if (o.errors > 0) console.log(` Errors: ${o.errors} compile error(s) -- overlay active`);
12244
- console.log(`
12245
- ${l}
12246
- `);
12247
- }
12248
- function broadcast(clients, data) {
12249
- const msg = JSON.stringify(data);
12250
- for (const c of clients) {
12251
- try {
12252
- if (c.readyState === 1) c.send(msg);
12253
- } catch {
12254
- clients.delete(c);
12255
- }
12256
- }
12257
- }
12258
11159
  async function createDevServer(options = {}) {
12259
11160
  const {
12260
11161
  port = 5199,
@@ -12263,87 +11164,44 @@ async function createDevServer(options = {}) {
12263
11164
  include = ["**/*.workflow.tsx"],
12264
11165
  outDir = "dist/workflows",
12265
11166
  seed = false,
12266
- apiUrl: rawApiUrl = "auto",
12267
- authToken: explicitToken,
11167
+ apiUrl = "http://localhost:4200/api/v1",
11168
+ authToken = process.env.MINDMATRIX_TOKEN,
12268
11169
  ws: enableWs = true,
12269
11170
  open = false
12270
11171
  } = options;
12271
11172
  const clients = /* @__PURE__ */ new Set();
12272
- let localServer = null;
12273
- let apiUrl;
12274
- let isLocalMode = false;
12275
- if (rawApiUrl === "local") {
12276
- localServer = await startLocalServer({ port: 4200 });
12277
- apiUrl = "http://localhost:4200/api/v1";
12278
- isLocalMode = true;
12279
- } else if (rawApiUrl === "auto") {
12280
- const defaultRemote = "https://dev.mindmatrix.club/api/v1";
12281
- const remoteHealth = await checkBackendHealth(defaultRemote);
12282
- if (remoteHealth.ok) {
12283
- apiUrl = defaultRemote;
12284
- } else {
12285
- const localHealth = await checkBackendHealth("http://localhost:4200/api/v1");
12286
- if (localHealth.ok) {
12287
- apiUrl = "http://localhost:4200/api/v1";
12288
- } else {
12289
- console.log("[mm-dev] No backend detected \u2014 starting local in-memory API server...");
12290
- localServer = await startLocalServer({ port: 4200 });
12291
- apiUrl = "http://localhost:4200/api/v1";
12292
- isLocalMode = true;
12293
- }
12294
- }
12295
- } else {
12296
- apiUrl = rawApiUrl;
12297
- }
12298
- const token = isLocalMode ? "dev-token-local" : await resolveDevToken(apiUrl, explicitToken);
12299
- const health = isLocalMode ? { ok: true, version: "local", db: "in-memory" } : await checkBackendHealth(apiUrl);
12300
- let initialSlug, initialCompiled = 0, initialDeployed = false, initialErrors = 0;
12301
- if (token && health.ok) {
12302
- const r = await initialBuildDeploy(src, outDir, mode, apiUrl, token);
12303
- initialCompiled = r.buildResult.compiled;
12304
- initialDeployed = r.deployed;
12305
- initialSlug = r.slug;
12306
- initialErrors = r.buildResult.errors;
12307
- }
12308
- if (seed && token && initialDeployed) {
12309
- try {
12310
- const { seedInstances: seedInstances2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
12311
- console.log("[mm-dev] Seeding sample instances...");
12312
- const sr = await seedInstances2({ apiUrl, token, dir: outDir });
12313
- console.log(`[mm-dev] Seeded ${sr.created} instance(s) across ${sr.definitions} definition(s)`);
12314
- } catch (e) {
12315
- console.warn(`[mm-dev] Seed failed: ${e instanceof Error ? e.message : e}`);
12316
- }
12317
- }
12318
- const pluginOpts = { mode, include, outDir, seedOnCompile: seed, apiUrl, authToken: token };
12319
- const proxyTarget = apiUrl.replace(/\/api\/v1\/?$/, "") || apiUrl;
12320
- let deployInFlight = false;
12321
- const compileDeployPlugin = {
12322
- name: "mindmatrix-dev-compile-deploy",
11173
+ const pluginOptions = {
11174
+ mode,
11175
+ include,
11176
+ outDir,
11177
+ seedOnCompile: seed,
11178
+ apiUrl,
11179
+ authToken
11180
+ };
11181
+ const notifyPlugin = {
11182
+ name: "mindmatrix-dev-notify",
12323
11183
  enforce: "post",
12324
- async handleHotUpdate(ctx) {
12325
- const isWf = include.some((p) => new RegExp(p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<G>>").replace(/\*/g, "[^/]*").replace(/<<G>>/g, ".*").replace(/\?/g, ".")).test(ctx.file));
12326
- if (!isWf) return;
12327
- const fn = ctx.file.split("/").pop() ?? ctx.file;
12328
- console.log(`[mm-dev] Recompiling ${fn}...`);
12329
- const br = await build({ src, outDir, mode, skipTypeCheck: true });
12330
- if (br.errors > 0) {
12331
- currentErrors = br.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
12332
- broadcast(clients, { type: "workflow:error", errors: br.errors, timestamp: ctx.timestamp });
12333
- return;
12334
- }
12335
- currentErrors = null;
12336
- if (token && !deployInFlight) {
12337
- deployInFlight = true;
11184
+ handleHotUpdate(ctx) {
11185
+ const isWorkflow = include.some((pattern) => {
11186
+ const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<GLOBSTAR>>").replace(/\*/g, "[^/]*").replace(/<<GLOBSTAR>>/g, ".*").replace(/\?/g, ".");
11187
+ return new RegExp(regex).test(ctx.file);
11188
+ });
11189
+ if (!isWorkflow) return;
11190
+ const message = JSON.stringify({
11191
+ type: "workflow:compiled",
11192
+ file: ctx.file,
11193
+ timestamp: ctx.timestamp
11194
+ });
11195
+ for (const client of clients) {
12338
11196
  try {
12339
- const { deploy: d } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
12340
- await d({ apiUrl, token, dir: outDir });
11197
+ if (client.readyState === 1) {
11198
+ client.send(message);
11199
+ }
12341
11200
  } catch {
12342
- } finally {
12343
- deployInFlight = false;
11201
+ clients.delete(client);
12344
11202
  }
12345
11203
  }
12346
- broadcast(clients, { type: "workflow:compiled", file: ctx.file, compiled: br.compiled, timestamp: ctx.timestamp });
11204
+ console.log(`[mm-dev] Compiled ${ctx.file.split("/").pop()} \u2014 notified ${clients.size} client(s)`);
12347
11205
  }
12348
11206
  };
12349
11207
  const viteConfig = {
@@ -12351,76 +11209,86 @@ async function createDevServer(options = {}) {
12351
11209
  server: {
12352
11210
  port,
12353
11211
  open,
12354
- host: true,
12355
- proxy: {
12356
- "/api": { target: proxyTarget, changeOrigin: true, secure: true, ws: true },
12357
- "/health": { target: proxyTarget, changeOrigin: true, secure: true },
12358
- "/ws": { target: proxyTarget.replace(/^http/, "ws"), changeOrigin: true, ws: true }
12359
- }
11212
+ host: true
12360
11213
  },
12361
11214
  plugins: [
12362
- mindmatrixReact(pluginOpts),
12363
- compileDeployPlugin,
12364
- { name: "mindmatrix-error-overlay", configureServer(server) {
12365
- server.middlewares.use(errorOverlayMiddleware());
12366
- } }
11215
+ mindmatrixReact(pluginOptions),
11216
+ notifyPlugin
12367
11217
  ],
12368
- logLevel: "warn"
11218
+ logLevel: "info"
12369
11219
  };
12370
- const { createServer: createServer2 } = await import("vite");
12371
- const vite = await createServer2(viteConfig);
11220
+ const { createServer } = await import("vite");
11221
+ const vite = await createServer(viteConfig);
12372
11222
  await vite.listen();
12373
11223
  const resolvedPort = vite.config.server.port ?? port;
12374
11224
  if (enableWs && vite.httpServer) {
12375
11225
  try {
12376
- const wsM = await Function('return import("ws")')();
12377
- const WSS = wsM.WebSocketServer ?? wsM.default?.WebSocketServer;
12378
- if (WSS) {
12379
- const wss = new WSS({ server: vite.httpServer, path: "/__mm_dev" });
12380
- wss.on("connection", (s) => {
12381
- clients.add(s);
12382
- s.on("close", () => clients.delete(s));
12383
- s.send(JSON.stringify({ type: "mm:connected", version: "0.1.0", capabilities: ["compile", "deploy", "proxy", "notify", "error-overlay"] }));
11226
+ const wsModule = await Function('return import("ws")')();
11227
+ const WebSocketServer = wsModule.WebSocketServer ?? wsModule.default?.WebSocketServer;
11228
+ if (WebSocketServer) {
11229
+ const wss = new WebSocketServer({
11230
+ server: vite.httpServer,
11231
+ path: "/__mm_dev"
11232
+ });
11233
+ wss.on("connection", (socket) => {
11234
+ clients.add(socket);
11235
+ console.log(`[mm-dev] Editor connected (${clients.size} total)`);
11236
+ socket.on("close", () => {
11237
+ clients.delete(socket);
11238
+ console.log(`[mm-dev] Editor disconnected (${clients.size} total)`);
11239
+ });
11240
+ socket.send(JSON.stringify({
11241
+ type: "mm:connected",
11242
+ version: "0.1.0",
11243
+ capabilities: ["compile", "seed", "notify"]
11244
+ }));
12384
11245
  });
12385
11246
  }
12386
11247
  } catch {
11248
+ console.warn("[mm-dev] ws package not available \u2014 WebSocket notifications disabled");
12387
11249
  }
12388
11250
  }
12389
- printBanner({ port: resolvedPort, apiUrl: isLocalMode ? `${apiUrl} (local in-memory)` : apiUrl, src, include, health, token: !!token, compiled: initialCompiled, deployed: initialDeployed, slug: initialSlug, errors: initialErrors });
11251
+ console.log(`
11252
+ [mm-dev] MindMatrix Dev Server running`);
11253
+ console.log(` Local: http://localhost:${resolvedPort}`);
11254
+ console.log(` WebSocket: ws://localhost:${resolvedPort}/__mm_dev`);
11255
+ console.log(` Watching: ${src} (${include.join(", ")})`);
11256
+ if (seed) {
11257
+ console.log(` Seeding: ${apiUrl}`);
11258
+ }
11259
+ console.log();
12390
11260
  return {
12391
11261
  vite,
12392
11262
  port: resolvedPort,
12393
11263
  clients,
12394
11264
  async rebuild() {
12395
- const r = await build({ src, outDir, mode });
12396
- if (r.errors > 0) {
12397
- currentErrors = r.errorDetails.map((e) => ({ file: e.file, message: e.message, line: e.line }));
12398
- } else {
12399
- currentErrors = null;
12400
- if (token) {
12401
- try {
12402
- const { deploy: d } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
12403
- await d({ apiUrl, token, dir: outDir });
12404
- } catch {
12405
- }
11265
+ console.log("[mm-dev] Full rebuild triggered...");
11266
+ const result = await build({ src, outDir, mode });
11267
+ const message = JSON.stringify({
11268
+ type: "workflow:rebuild",
11269
+ compiled: result.compiled,
11270
+ errors: result.errors,
11271
+ timestamp: Date.now()
11272
+ });
11273
+ for (const client of clients) {
11274
+ try {
11275
+ if (client.readyState === 1) client.send(message);
11276
+ } catch {
11277
+ clients.delete(client);
12406
11278
  }
12407
11279
  }
12408
- broadcast(clients, { type: "workflow:rebuild", compiled: r.compiled, errors: r.errors, timestamp: Date.now() });
12409
- return r;
11280
+ return result;
12410
11281
  },
12411
11282
  async close() {
12412
- for (const c of clients) {
11283
+ for (const client of clients) {
12413
11284
  try {
12414
- c.close();
11285
+ client.close();
12415
11286
  } catch {
12416
11287
  }
12417
11288
  }
12418
11289
  clients.clear();
12419
- currentErrors = null;
12420
11290
  await vite.close();
12421
- if (localServer) {
12422
- await localServer.close();
12423
- }
11291
+ console.log("[mm-dev] Server stopped");
12424
11292
  }
12425
11293
  };
12426
11294
  }