@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.
- package/dist/babel/index.d.mts +2 -2
- package/dist/babel/index.d.ts +2 -2
- package/dist/babel/index.js +5 -5
- package/dist/babel/index.mjs +1 -1
- package/dist/cli/index.js +797 -1941
- package/dist/cli/index.mjs +179 -77
- package/dist/codemod/cli.js +1 -1
- package/dist/codemod/cli.mjs +1 -1
- package/dist/codemod/index.d.mts +3 -3
- package/dist/codemod/index.d.ts +3 -3
- package/dist/codemod/index.js +1 -1
- package/dist/codemod/index.mjs +1 -1
- package/dist/dev-server.d.mts +2 -2
- package/dist/dev-server.d.ts +2 -2
- package/dist/dev-server.js +86 -1218
- package/dist/dev-server.mjs +4 -4
- package/dist/envelope.d.mts +2 -2
- package/dist/envelope.d.ts +2 -2
- package/dist/envelope.js +5 -5
- package/dist/envelope.mjs +2 -2
- package/dist/index.d.mts +8 -8
- package/dist/index.d.ts +8 -8
- package/dist/index.js +342 -1266
- package/dist/index.mjs +8 -8
- package/dist/testing/index.d.mts +8 -8
- package/dist/testing/index.d.ts +8 -8
- package/dist/testing/index.js +5 -5
- package/dist/testing/index.mjs +1 -1
- package/dist/vite/index.d.mts +1 -1
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +5 -5
- package/dist/vite/index.mjs +2 -2
- package/examples/authentication/main.workflow.tsx +1 -1
- package/examples/authentication/mm.config.ts +1 -1
- package/examples/authentication/pages/LoginPage.tsx +2 -2
- package/examples/authentication/pages/SignupPage.tsx +2 -2
- package/examples/counter.workflow.tsx +1 -1
- package/examples/dashboard.workflow.tsx +1 -1
- package/examples/invoice-approval/actions/invoice.server.ts +1 -1
- package/examples/invoice-approval/main.workflow.tsx +1 -1
- package/examples/invoice-approval/mm.config.ts +1 -1
- package/examples/invoice-approval/pages/InvoiceDetailPage.tsx +1 -1
- package/examples/invoice-approval/pages/InvoiceFormPage.tsx +1 -1
- package/examples/invoice-approval/pages/InvoiceListPage.tsx +1 -1
- package/examples/todo-app.workflow.tsx +1 -1
- package/examples/uber-app/actions/matching.server.ts +1 -1
- package/examples/uber-app/actions/notifications.server.ts +1 -1
- package/examples/uber-app/actions/payments.server.ts +1 -1
- package/examples/uber-app/actions/pricing.server.ts +1 -1
- package/examples/uber-app/app/admin/analytics.tsx +2 -2
- package/examples/uber-app/app/admin/fleet.tsx +2 -2
- package/examples/uber-app/app/admin/surge-pricing.tsx +2 -2
- package/examples/uber-app/app/driver/dashboard.tsx +2 -2
- package/examples/uber-app/app/driver/earnings.tsx +2 -2
- package/examples/uber-app/app/driver/navigation.tsx +2 -2
- package/examples/uber-app/app/driver/ride-acceptance.tsx +2 -2
- package/examples/uber-app/app/rider/home.tsx +2 -2
- package/examples/uber-app/app/rider/payment-methods.tsx +2 -2
- package/examples/uber-app/app/rider/ride-history.tsx +2 -2
- package/examples/uber-app/app/rider/ride-tracking.tsx +2 -2
- package/examples/uber-app/components/DriverCard.tsx +1 -1
- package/examples/uber-app/components/MapView.tsx +3 -3
- package/examples/uber-app/components/RatingStars.tsx +2 -2
- package/examples/uber-app/components/RideCard.tsx +1 -1
- package/examples/uber-app/mm.config.ts +1 -1
- package/examples/uber-app/workflows/dispute-resolution.workflow.tsx +2 -2
- package/examples/uber-app/workflows/driver-onboarding.workflow.tsx +2 -2
- package/examples/uber-app/workflows/payment-processing.workflow.tsx +2 -2
- package/examples/uber-app/workflows/ride-request.workflow.tsx +2 -2
- package/package.json +13 -9
- package/dist/auth-3UK75242.mjs +0 -17
- package/dist/chunk-5FTDWKHH.mjs +0 -244
- package/dist/chunk-7JRAEFRB.mjs +0 -7510
- package/dist/chunk-7T6Q5KAA.mjs +0 -7506
- package/dist/chunk-ABYPKRSB.mjs +0 -215
- package/dist/chunk-BZEXUPDH.mjs +0 -175
- package/dist/chunk-HRYR54PT.mjs +0 -175
- package/dist/chunk-J3M4GUS7.mjs +0 -161
- package/dist/chunk-JRGFBWTN.mjs +0 -2918
- package/dist/chunk-O4AUS7EU.mjs +0 -148
- package/dist/chunk-R2DD5GTY.mjs +0 -186
- package/dist/chunk-UDDTWG5J.mjs +0 -734
- package/dist/chunk-VLTKQDJ3.mjs +0 -244
- package/dist/chunk-WVYY32LD.mjs +0 -939
- package/dist/chunk-XDVM4YHX.mjs +0 -3450
- package/dist/chunk-Z2G5RZ4H.mjs +0 -186
- package/dist/chunk-ZE3KCHBM.mjs +0 -2918
- package/dist/deploy-YAJGW6II.mjs +0 -9
- package/dist/dev-server-CrQ041KP.d.mts +0 -79
- package/dist/dev-server-CrQ041KP.d.ts +0 -79
- package/dist/envelope-ChEkuHij.d.mts +0 -265
- package/dist/envelope-ChEkuHij.d.ts +0 -265
- package/dist/index-CEKyyazf.d.mts +0 -104
- package/dist/index-CEKyyazf.d.ts +0 -104
- package/dist/init-7FJENUDK.mjs +0 -407
- package/dist/project-compiler-NNK32MPG.mjs +0 -10
- package/dist/project-compiler-ZB4RUYVL.mjs +0 -10
- package/dist/project-decompiler-U55HQUHW.mjs +0 -7
- package/dist/pull-KOL2QAYQ.mjs +0 -109
- package/dist/seed-KOGEPGOJ.mjs +0 -154
- package/dist/server-VW6UPCHO.mjs +0 -277
- package/dist/verify-BYHUKARQ.mjs +0 -1833
- package/dist/verify-OQDEQYMS.mjs +0 -1833
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("@
|
|
2683
|
+
import_player_core = require("@mindmatrix/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("@
|
|
5223
|
+
if (source.includes("@mmapp/react") || source.includes("@mindmatrix/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 @
|
|
7416
|
+
message: `${hookName}() is not allowed in strict mode. Use @mindmatrix/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("@
|
|
7508
|
+
if (source.startsWith("@mindmatrix/") || 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 @
|
|
7513
|
+
message: `Import from '${source}' is not allowed in strict mode. Only @mindmatrix/* 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,552 +10616,6 @@ 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
|
-
|
|
11165
10619
|
// src/index.ts
|
|
11166
10620
|
var index_exports = {};
|
|
11167
10621
|
__export(index_exports, {
|
|
@@ -11662,7 +11116,7 @@ function buildJSXTree(node, imports, symbols) {
|
|
|
11662
11116
|
}
|
|
11663
11117
|
const componentName = node.component;
|
|
11664
11118
|
if (REACT_ATOMS.has(componentName)) {
|
|
11665
|
-
addImport(imports, "@
|
|
11119
|
+
addImport(imports, "@mindmatrix/react", componentName);
|
|
11666
11120
|
}
|
|
11667
11121
|
const attributes = [];
|
|
11668
11122
|
if (node.config) {
|
|
@@ -11707,7 +11161,7 @@ function buildJSXTree(node, imports, symbols) {
|
|
|
11707
11161
|
isSelfClosing
|
|
11708
11162
|
);
|
|
11709
11163
|
if (node.visible_when) {
|
|
11710
|
-
addImport(imports, "@
|
|
11164
|
+
addImport(imports, "@mindmatrix/react", "Show");
|
|
11711
11165
|
return t8.jsxElement(
|
|
11712
11166
|
t8.jsxOpeningElement(
|
|
11713
11167
|
t8.jsxIdentifier("Show"),
|
|
@@ -11788,7 +11242,7 @@ function fieldTypeAnnotation(field) {
|
|
|
11788
11242
|
}
|
|
11789
11243
|
function emitFieldDeclarations(fields, imports) {
|
|
11790
11244
|
if (fields.length === 0) return [];
|
|
11791
|
-
addImport2(imports, "@
|
|
11245
|
+
addImport2(imports, "@mindmatrix/react", "useState");
|
|
11792
11246
|
const statements = [];
|
|
11793
11247
|
for (const field of fields) {
|
|
11794
11248
|
if (field.computed) continue;
|
|
@@ -11852,7 +11306,7 @@ function emitStateEffects(states, imports) {
|
|
|
11852
11306
|
const statements = [];
|
|
11853
11307
|
for (const state of states) {
|
|
11854
11308
|
if (state.on_enter.length > 0) {
|
|
11855
|
-
addImport2(imports, "@
|
|
11309
|
+
addImport2(imports, "@mindmatrix/react", "useOnEnter");
|
|
11856
11310
|
statements.push(
|
|
11857
11311
|
t9.expressionStatement(
|
|
11858
11312
|
t9.callExpression(t9.identifier("useOnEnter"), [
|
|
@@ -11863,7 +11317,7 @@ function emitStateEffects(states, imports) {
|
|
|
11863
11317
|
);
|
|
11864
11318
|
}
|
|
11865
11319
|
if (state.on_exit.length > 0) {
|
|
11866
|
-
addImport2(imports, "@
|
|
11320
|
+
addImport2(imports, "@mindmatrix/react", "useOnExit");
|
|
11867
11321
|
statements.push(
|
|
11868
11322
|
t9.expressionStatement(
|
|
11869
11323
|
t9.callExpression(t9.identifier("useOnExit"), [
|
|
@@ -11874,7 +11328,7 @@ function emitStateEffects(states, imports) {
|
|
|
11874
11328
|
);
|
|
11875
11329
|
}
|
|
11876
11330
|
if (state.during.length > 0) {
|
|
11877
|
-
addImport2(imports, "@
|
|
11331
|
+
addImport2(imports, "@mindmatrix/react", "useWhileIn");
|
|
11878
11332
|
for (const during of state.during) {
|
|
11879
11333
|
const args = [
|
|
11880
11334
|
t9.stringLiteral(state.name)
|
|
@@ -11895,7 +11349,7 @@ function emitStateEffects(states, imports) {
|
|
|
11895
11349
|
}
|
|
11896
11350
|
function emitTransitionDeclarations(transitions, imports) {
|
|
11897
11351
|
if (transitions.length === 0) return [];
|
|
11898
|
-
addImport2(imports, "@
|
|
11352
|
+
addImport2(imports, "@mindmatrix/react", "useTransition");
|
|
11899
11353
|
const correctedTransitions = correctFromFields(transitions);
|
|
11900
11354
|
const statements = [];
|
|
11901
11355
|
for (const transition of correctedTransitions) {
|
|
@@ -12130,7 +11584,7 @@ function emitSingleCondition(cond) {
|
|
|
12130
11584
|
function emitRoleDeclarations(metadata, imports) {
|
|
12131
11585
|
const roleDeps = metadata?.roleDependencies;
|
|
12132
11586
|
if (!roleDeps || roleDeps.length === 0) return [];
|
|
12133
|
-
addImport2(imports, "@
|
|
11587
|
+
addImport2(imports, "@mindmatrix/react", "useRole");
|
|
12134
11588
|
const statements = [];
|
|
12135
11589
|
for (const role of roleDeps) {
|
|
12136
11590
|
const varName = `is${toPascalCase(role)}`;
|
|
@@ -12151,7 +11605,7 @@ function emitQueryDeclarations(metadata, imports) {
|
|
|
12151
11605
|
const modelImports = metadata?.modelImports;
|
|
12152
11606
|
const addedModelImports = /* @__PURE__ */ new Set();
|
|
12153
11607
|
if (dataSources && dataSources.length > 0) {
|
|
12154
|
-
addImport2(imports, "@
|
|
11608
|
+
addImport2(imports, "@mindmatrix/react", "useQuery");
|
|
12155
11609
|
const usedVarNames = /* @__PURE__ */ new Set();
|
|
12156
11610
|
for (const ds of dataSources) {
|
|
12157
11611
|
if (ds.type !== "workflow") continue;
|
|
@@ -12218,7 +11672,7 @@ function emitQueryDeclarations(metadata, imports) {
|
|
|
12218
11672
|
}
|
|
12219
11673
|
const mutationTargets = metadata?.mutationTargets;
|
|
12220
11674
|
if (mutationTargets && mutationTargets.length > 0) {
|
|
12221
|
-
addImport2(imports, "@
|
|
11675
|
+
addImport2(imports, "@mindmatrix/react", "useMutation");
|
|
12222
11676
|
for (const slug of mutationTargets) {
|
|
12223
11677
|
const modelPath = modelImports?.[slug];
|
|
12224
11678
|
const modelVarName2 = modelPath ? `${toCamelCase2(slug.replace(/-/g, "_"))}Model` : void 0;
|
|
@@ -12243,7 +11697,7 @@ function emitQueryDeclarations(metadata, imports) {
|
|
|
12243
11697
|
function emitChangeWatchers(metadata, imports) {
|
|
12244
11698
|
const watchers = metadata?.fieldWatchers;
|
|
12245
11699
|
if (!watchers || watchers.length === 0) return [];
|
|
12246
|
-
addImport2(imports, "@
|
|
11700
|
+
addImport2(imports, "@mindmatrix/react", "useOnChange");
|
|
12247
11701
|
const statements = [];
|
|
12248
11702
|
for (const watcher of watchers) {
|
|
12249
11703
|
statements.push(
|
|
@@ -12259,7 +11713,7 @@ function emitChangeWatchers(metadata, imports) {
|
|
|
12259
11713
|
}
|
|
12260
11714
|
function emitEventSubscriptions(onEvent, imports) {
|
|
12261
11715
|
if (!onEvent || onEvent.length === 0) return [];
|
|
12262
|
-
addImport2(imports, "@
|
|
11716
|
+
addImport2(imports, "@mindmatrix/react", "useOnEvent");
|
|
12263
11717
|
const statements = [];
|
|
12264
11718
|
for (const sub of onEvent) {
|
|
12265
11719
|
const actions = sub.actions.map((a, i) => ({
|
|
@@ -12286,7 +11740,7 @@ function emitEventSubscriptions(onEvent, imports) {
|
|
|
12286
11740
|
function emitTransitionEffects(metadata, imports) {
|
|
12287
11741
|
const effects = metadata?.transitionEffects;
|
|
12288
11742
|
if (!effects || effects.length === 0) return [];
|
|
12289
|
-
addImport2(imports, "@
|
|
11743
|
+
addImport2(imports, "@mindmatrix/react", "useOnTransition");
|
|
12290
11744
|
const statements = [];
|
|
12291
11745
|
for (const effect of effects) {
|
|
12292
11746
|
statements.push(
|
|
@@ -12317,7 +11771,7 @@ function emitLocalDefaultDeclarations(experience, existingFields, imports) {
|
|
|
12317
11771
|
const camelName = toCamelCase2(key);
|
|
12318
11772
|
if (emittedCamelNames.has(camelName)) continue;
|
|
12319
11773
|
emittedCamelNames.add(camelName);
|
|
12320
|
-
addImport2(imports, "@
|
|
11774
|
+
addImport2(imports, "@mindmatrix/react", "useState");
|
|
12321
11775
|
const setter = `set${toPascalCase(key)}`;
|
|
12322
11776
|
let defaultExpr;
|
|
12323
11777
|
if (value === void 0 || value === null) {
|
|
@@ -12530,7 +11984,7 @@ function generateServerActionFile(actions) {
|
|
|
12530
11984
|
` * Each receives a TransitionContext with instance data and utilities.`,
|
|
12531
11985
|
` */`,
|
|
12532
11986
|
``,
|
|
12533
|
-
`import type { TransitionContext } from '@
|
|
11987
|
+
`import type { TransitionContext } from '@mindmatrix/react';`,
|
|
12534
11988
|
``
|
|
12535
11989
|
];
|
|
12536
11990
|
for (const action of actions) {
|
|
@@ -12603,7 +12057,7 @@ function generateConfigFile(def) {
|
|
|
12603
12057
|
` * Blueprint configuration for "${def.name || pascalCase(def.slug)}".`,
|
|
12604
12058
|
` */`,
|
|
12605
12059
|
``,
|
|
12606
|
-
`import { defineBlueprint } from '@
|
|
12060
|
+
`import { defineBlueprint } from '@mindmatrix/react';`,
|
|
12607
12061
|
``,
|
|
12608
12062
|
`export default defineBlueprint({`,
|
|
12609
12063
|
` slug: '${def.slug}',`,
|
|
@@ -12698,7 +12152,7 @@ function generateMainFile(def, pages, hasModel, serverActionNames, options) {
|
|
|
12698
12152
|
reactImports.add("Stack");
|
|
12699
12153
|
if (reactImports.size > 0) {
|
|
12700
12154
|
const sorted = [...reactImports].sort();
|
|
12701
|
-
importLines.push(`import { ${sorted.join(", ")} } from '@
|
|
12155
|
+
importLines.push(`import { ${sorted.join(", ")} } from '@mindmatrix/react';`);
|
|
12702
12156
|
}
|
|
12703
12157
|
if (hasModel) {
|
|
12704
12158
|
const typeName = pascalCase(slug);
|
|
@@ -13895,580 +13349,27 @@ async function startWatchMode(options) {
|
|
|
13895
13349
|
console.log(`
|
|
13896
13350
|
[mindmatrix-react] Watching ${srcDir} for changes... (Ctrl+C to stop)
|
|
13897
13351
|
`);
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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
|
-
}
|
|
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
|
+
});
|
|
14471
13370
|
}
|
|
13371
|
+
|
|
13372
|
+
// src/dev-server.ts
|
|
14472
13373
|
async function createDevServer(options = {}) {
|
|
14473
13374
|
const {
|
|
14474
13375
|
port = 5199,
|
|
@@ -14477,87 +13378,44 @@ async function createDevServer(options = {}) {
|
|
|
14477
13378
|
include = ["**/*.workflow.tsx"],
|
|
14478
13379
|
outDir = "dist/workflows",
|
|
14479
13380
|
seed = false,
|
|
14480
|
-
apiUrl
|
|
14481
|
-
authToken
|
|
13381
|
+
apiUrl = "http://localhost:4200/api/v1",
|
|
13382
|
+
authToken = process.env.MINDMATRIX_TOKEN,
|
|
14482
13383
|
ws: enableWs = true,
|
|
14483
13384
|
open = false
|
|
14484
13385
|
} = options;
|
|
14485
13386
|
const clients = /* @__PURE__ */ new Set();
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
14490
|
-
|
|
14491
|
-
apiUrl
|
|
14492
|
-
|
|
14493
|
-
}
|
|
14494
|
-
|
|
14495
|
-
|
|
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",
|
|
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",
|
|
14537
13397
|
enforce: "post",
|
|
14538
|
-
|
|
14539
|
-
const
|
|
14540
|
-
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
14544
|
-
|
|
14545
|
-
|
|
14546
|
-
|
|
14547
|
-
|
|
14548
|
-
}
|
|
14549
|
-
|
|
14550
|
-
if (token && !deployInFlight) {
|
|
14551
|
-
deployInFlight = true;
|
|
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) {
|
|
14552
13410
|
try {
|
|
14553
|
-
|
|
14554
|
-
|
|
13411
|
+
if (client.readyState === 1) {
|
|
13412
|
+
client.send(message);
|
|
13413
|
+
}
|
|
14555
13414
|
} catch {
|
|
14556
|
-
|
|
14557
|
-
deployInFlight = false;
|
|
13415
|
+
clients.delete(client);
|
|
14558
13416
|
}
|
|
14559
13417
|
}
|
|
14560
|
-
|
|
13418
|
+
console.log(`[mm-dev] Compiled ${ctx.file.split("/").pop()} \u2014 notified ${clients.size} client(s)`);
|
|
14561
13419
|
}
|
|
14562
13420
|
};
|
|
14563
13421
|
const viteConfig = {
|
|
@@ -14565,93 +13423,311 @@ async function createDevServer(options = {}) {
|
|
|
14565
13423
|
server: {
|
|
14566
13424
|
port,
|
|
14567
13425
|
open,
|
|
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
|
-
}
|
|
13426
|
+
host: true
|
|
14574
13427
|
},
|
|
14575
13428
|
plugins: [
|
|
14576
|
-
mindmatrixReact(
|
|
14577
|
-
|
|
14578
|
-
{ name: "mindmatrix-error-overlay", configureServer(server) {
|
|
14579
|
-
server.middlewares.use(errorOverlayMiddleware());
|
|
14580
|
-
} }
|
|
13429
|
+
mindmatrixReact(pluginOptions),
|
|
13430
|
+
notifyPlugin
|
|
14581
13431
|
],
|
|
14582
|
-
logLevel: "
|
|
13432
|
+
logLevel: "info"
|
|
14583
13433
|
};
|
|
14584
|
-
const { createServer
|
|
14585
|
-
const vite = await
|
|
13434
|
+
const { createServer } = await import("vite");
|
|
13435
|
+
const vite = await createServer(viteConfig);
|
|
14586
13436
|
await vite.listen();
|
|
14587
13437
|
const resolvedPort = vite.config.server.port ?? port;
|
|
14588
13438
|
if (enableWs && vite.httpServer) {
|
|
14589
13439
|
try {
|
|
14590
|
-
const
|
|
14591
|
-
const
|
|
14592
|
-
if (
|
|
14593
|
-
const wss = new
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
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
|
+
}));
|
|
14598
13459
|
});
|
|
14599
13460
|
}
|
|
14600
13461
|
} catch {
|
|
13462
|
+
console.warn("[mm-dev] ws package not available \u2014 WebSocket notifications disabled");
|
|
14601
13463
|
}
|
|
14602
13464
|
}
|
|
14603
|
-
|
|
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();
|
|
14604
13474
|
return {
|
|
14605
13475
|
vite,
|
|
14606
13476
|
port: resolvedPort,
|
|
14607
13477
|
clients,
|
|
14608
13478
|
async rebuild() {
|
|
14609
|
-
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
|
|
14614
|
-
|
|
14615
|
-
|
|
14616
|
-
|
|
14617
|
-
|
|
14618
|
-
|
|
14619
|
-
|
|
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);
|
|
14620
13492
|
}
|
|
14621
13493
|
}
|
|
14622
|
-
|
|
14623
|
-
return r;
|
|
13494
|
+
return result;
|
|
14624
13495
|
},
|
|
14625
13496
|
async close() {
|
|
14626
|
-
for (const
|
|
13497
|
+
for (const client of clients) {
|
|
14627
13498
|
try {
|
|
14628
|
-
|
|
13499
|
+
client.close();
|
|
14629
13500
|
} catch {
|
|
14630
13501
|
}
|
|
14631
13502
|
}
|
|
14632
13503
|
clients.clear();
|
|
14633
|
-
currentErrors = null;
|
|
14634
13504
|
await vite.close();
|
|
14635
|
-
|
|
14636
|
-
await localServer.close();
|
|
14637
|
-
}
|
|
13505
|
+
console.log("[mm-dev] Server stopped");
|
|
14638
13506
|
}
|
|
14639
13507
|
};
|
|
14640
13508
|
}
|
|
14641
13509
|
|
|
14642
|
-
// src/
|
|
14643
|
-
|
|
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
|
+
}
|
|
14644
13720
|
|
|
14645
13721
|
// src/envelope.ts
|
|
14646
13722
|
var import_crypto3 = require("crypto");
|
|
14647
|
-
var
|
|
14648
|
-
var
|
|
14649
|
-
var
|
|
13723
|
+
var import_fs5 = require("fs");
|
|
13724
|
+
var import_path4 = require("path");
|
|
13725
|
+
var import_glob3 = require("glob");
|
|
14650
13726
|
var import_core7 = require("@babel/core");
|
|
14651
13727
|
init_babel();
|
|
14652
13728
|
async function buildEnvelope(projectDir, options = {}) {
|
|
14653
|
-
const root = (0,
|
|
14654
|
-
const slug = options.slug ?? (0,
|
|
13729
|
+
const root = (0, import_path4.resolve)(projectDir);
|
|
13730
|
+
const slug = options.slug ?? (0, import_path4.basename)(root);
|
|
14655
13731
|
const version = options.version ?? "0.1.0";
|
|
14656
13732
|
const mode = options.mode ?? "infer";
|
|
14657
13733
|
const patterns = options.include ?? [
|
|
@@ -14661,11 +13737,11 @@ async function buildEnvelope(projectDir, options = {}) {
|
|
|
14661
13737
|
];
|
|
14662
13738
|
const discoveredFiles = [];
|
|
14663
13739
|
for (const pattern of patterns) {
|
|
14664
|
-
const matches = await (0,
|
|
13740
|
+
const matches = await (0, import_glob3.glob)(pattern, { absolute: true });
|
|
14665
13741
|
discoveredFiles.push(...matches);
|
|
14666
13742
|
}
|
|
14667
13743
|
const uniqueFiles = [...new Set(discoveredFiles)];
|
|
14668
|
-
const allSourceFiles = await (0,
|
|
13744
|
+
const allSourceFiles = await (0, import_glob3.glob)(`${root}/**/*.{ts,tsx,js,jsx,css,json}`, {
|
|
14669
13745
|
absolute: true,
|
|
14670
13746
|
ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"]
|
|
14671
13747
|
});
|
|
@@ -14675,10 +13751,10 @@ async function buildEnvelope(projectDir, options = {}) {
|
|
|
14675
13751
|
const errors = [];
|
|
14676
13752
|
const sourceBindings = [];
|
|
14677
13753
|
for (const file2 of uniqueFiles) {
|
|
14678
|
-
const relativePath = (0,
|
|
13754
|
+
const relativePath = (0, import_path4.relative)(root, file2);
|
|
14679
13755
|
let fileContent;
|
|
14680
13756
|
try {
|
|
14681
|
-
fileContent = (0,
|
|
13757
|
+
fileContent = (0, import_fs5.readFileSync)(file2);
|
|
14682
13758
|
} catch {
|
|
14683
13759
|
errors.push({ file: relativePath, message: "Could not read file" });
|
|
14684
13760
|
continue;
|