@igoruehara/canvas-flow 0.1.1 → 0.1.2

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.
@@ -50,6 +50,7 @@ Options:
50
50
  --edit Open config file with "init" or "config"
51
51
  --force Overwrite config on init
52
52
  --offline Skip network checks with "doctor"
53
+ --skip-mongo-check Start without preflight MongoDB connection check
53
54
  --strict Treat doctor warnings as failures
54
55
  --help Show this help
55
56
 
@@ -810,6 +811,48 @@ async function checkMongoReachability(uri) {
810
811
  };
811
812
  }
812
813
 
814
+ function sleep(ms) {
815
+ return new Promise((resolve) => setTimeout(resolve, ms));
816
+ }
817
+
818
+ function mongoConnectionOptions(config) {
819
+ return {
820
+ serverSelectionTimeoutMS: Number(config.database?.mongoServerSelectionTimeoutMs || 8000),
821
+ connectTimeoutMS: Number(config.database?.mongoConnectTimeoutMs || 8000),
822
+ };
823
+ }
824
+
825
+ async function checkMongoConnection(uri, options = {}) {
826
+ let connection;
827
+ try {
828
+ const mongoose = require('mongoose');
829
+ connection = mongoose.createConnection(uri, options);
830
+ await connection.asPromise();
831
+ return { ok: true, message: 'connected' };
832
+ } catch (error) {
833
+ return { ok: false, message: error && error.message ? error.message : String(error) };
834
+ } finally {
835
+ if (connection) {
836
+ await connection.close().catch(() => undefined);
837
+ }
838
+ }
839
+ }
840
+
841
+ function isLocalMongoUri(uri) {
842
+ return mongoTargetsFromUri(uri).some((target) => (
843
+ target.host === '127.0.0.1' ||
844
+ target.host === 'localhost' ||
845
+ target.host === '::1'
846
+ ));
847
+ }
848
+
849
+ function mongoConnectionHint(uri) {
850
+ if (isLocalMongoUri(uri)) {
851
+ return 'Start local Mongo with "canvas-flow infra up", or run with "canvas-flow --with-docker --open".';
852
+ }
853
+ return 'Check database.mongoUrl credentials, network access, and the MongoDB Atlas IP access list.';
854
+ }
855
+
813
856
  function dockerComposeBaseArgs() {
814
857
  return [
815
858
  'compose',
@@ -936,6 +979,7 @@ function createDoctorReporter(strict) {
936
979
 
937
980
  async function doctor(flags) {
938
981
  const reporter = createDoctorReporter(flags.strict === true);
982
+ addSourceDependencyFallback();
939
983
  const paths = resolvePaths(flags);
940
984
  ensureDir(paths.homeDir);
941
985
 
@@ -975,11 +1019,11 @@ async function doctor(flags) {
975
1019
  if (config.database.mongoUrl) {
976
1020
  reporter.pass('Mongo config', 'MONGO_DB_CONNECTION_STRING is set');
977
1021
  if (flags.offline === true) {
978
- reporter.warn('Mongo reachability', 'skipped because --offline was used');
1022
+ reporter.warn('Mongo connection', 'skipped because --offline was used');
979
1023
  } else {
980
- const mongoCheck = await checkMongoReachability(config.database.mongoUrl);
981
- if (mongoCheck.ok) reporter.pass('Mongo reachability', mongoCheck.message);
982
- else reporter.fail('Mongo reachability', `${mongoCheck.message}; run "canvas-flow infra up" to start local Mongo with Docker`);
1024
+ const mongoCheck = await checkMongoConnection(config.database.mongoUrl, mongoConnectionOptions(config));
1025
+ if (mongoCheck.ok) reporter.pass('Mongo connection', mongoCheck.message);
1026
+ else reporter.fail('Mongo connection', `${mongoCheck.message}; ${mongoConnectionHint(config.database.mongoUrl)}`);
983
1027
  }
984
1028
  } else {
985
1029
  reporter.fail('Mongo config', 'database.mongoUrl is required');
@@ -1044,7 +1088,41 @@ async function doctor(flags) {
1044
1088
  reporter.finish();
1045
1089
  }
1046
1090
 
1047
- function start(flags) {
1091
+ async function waitForMongo(config, flags, paths) {
1092
+ if (flags['skip-mongo-check'] === true) return;
1093
+ if (!config.database.mongoUrl) {
1094
+ throw new Error(`database.mongoUrl is required. Edit the config with: canvas-flow config --edit`);
1095
+ }
1096
+
1097
+ const attempts = (flags['with-docker'] === true || flags.infra === true) && isLocalMongoUri(config.database.mongoUrl)
1098
+ ? 20
1099
+ : 1;
1100
+ const options = mongoConnectionOptions(config);
1101
+ let lastMessage = '';
1102
+
1103
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
1104
+ const result = await checkMongoConnection(config.database.mongoUrl, options);
1105
+ if (result.ok) {
1106
+ console.log('MongoDB preflight: connected');
1107
+ return;
1108
+ }
1109
+
1110
+ lastMessage = result.message;
1111
+ if (attempt < attempts) {
1112
+ console.log(`MongoDB preflight waiting (${attempt}/${attempts}): ${result.message}`);
1113
+ await sleep(1500);
1114
+ }
1115
+ }
1116
+
1117
+ throw new Error([
1118
+ `MongoDB preflight failed: ${lastMessage}`,
1119
+ mongoConnectionHint(config.database.mongoUrl),
1120
+ `Config file: ${paths.configPath}`,
1121
+ 'Use "canvas-flow doctor" for a detailed readiness check.',
1122
+ ].join('\n'));
1123
+ }
1124
+
1125
+ async function start(flags) {
1048
1126
  assertBundleExists();
1049
1127
  addSourceDependencyFallback();
1050
1128
  if (flags['with-docker'] === true || flags.infra === true) {
@@ -1055,6 +1133,7 @@ function start(flags) {
1055
1133
  const configExisted = fs.existsSync(paths.configPath);
1056
1134
  const config = loadConfig(paths.configPath);
1057
1135
  const runtime = applyEnvironment(config, paths, flags);
1136
+ await waitForMongo(config, flags, paths);
1058
1137
 
1059
1138
  process.chdir(paths.homeDir);
1060
1139
 
@@ -1117,7 +1196,7 @@ async function main() {
1117
1196
  }
1118
1197
 
1119
1198
  if (args.command === 'start' || args.command === 'run') {
1120
- start(args.flags);
1199
+ await start(args.flags);
1121
1200
  return;
1122
1201
  }
1123
1202
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igoruehara/canvas-flow",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Standalone npm launcher for Canvas Flow multi-agent GenAI workflows.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -12,13 +12,17 @@ exports.databaseProviders = [
12
12
  const uri = configService.get('MONGO_DB_CONNECTION_STRING') ||
13
13
  'mongodb://127.0.0.1:27017/canvas_flow';
14
14
  mongoose.set('bufferCommands', false);
15
- await mongoose
16
- .connect(uri, {
17
- serverSelectionTimeoutMS: Number(configService.get('MONGO_SERVER_SELECTION_TIMEOUT_MS') || 8000),
18
- connectTimeoutMS: Number(configService.get('MONGO_CONNECT_TIMEOUT_MS') || 8000),
19
- })
20
- .then(() => console.log('MongoDB connected'))
21
- .catch((error) => console.warn(`MongoDB connection skipped: ${error?.message || String(error)}`));
15
+ try {
16
+ await mongoose.connect(uri, {
17
+ serverSelectionTimeoutMS: Number(configService.get('MONGO_SERVER_SELECTION_TIMEOUT_MS') || 8000),
18
+ connectTimeoutMS: Number(configService.get('MONGO_CONNECT_TIMEOUT_MS') || 8000),
19
+ });
20
+ console.log('MongoDB connected');
21
+ }
22
+ catch (error) {
23
+ console.error(`MongoDB connection failed: ${error?.message || String(error)}`);
24
+ throw error;
25
+ }
22
26
  return mongoose;
23
27
  },
24
28
  },
@@ -1 +1 @@
1
- {"version":3,"file":"database.providers.js","sourceRoot":"","sources":["../../src/database/database.providers.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACrC,2CAA+C;AAC/C,4DAAuE;AAE1D,QAAA,iBAAiB,GAAG;IAC/B;QACE,OAAO,EAAE,iDAA8B;QACvC,MAAM,EAAE,CAAC,sBAAa,CAAC;QACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAA4B,EAAE;YAC3E,MAAM,GAAG,GACP,aAAa,CAAC,GAAG,CAAS,4BAA4B,CAAC;gBACvD,uCAAuC,CAAC;YAC1C,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YACtC,MAAM,QAAQ;iBACX,OAAO,CAAC,GAAG,EAAE;gBACZ,wBAAwB,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,mCAAmC,CAAC,IAAI,IAAI,CAAC;gBAChG,gBAAgB,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC;aAChF,CAAC;iBACD,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;iBAC5C,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,+BAA+B,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YACpG,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"database.providers.js","sourceRoot":"","sources":["../../src/database/database.providers.ts"],"names":[],"mappings":";;;AAAA,qCAAqC;AACrC,2CAA+C;AAC/C,4DAAuE;AAE1D,QAAA,iBAAiB,GAAG;IAC/B;QACE,OAAO,EAAE,iDAA8B;QACvC,MAAM,EAAE,CAAC,sBAAa,CAAC;QACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAA4B,EAAE;YAC3E,MAAM,GAAG,GACP,aAAa,CAAC,GAAG,CAAS,4BAA4B,CAAC;gBACvD,uCAAuC,CAAC;YAC1C,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE;oBAC1B,wBAAwB,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,mCAAmC,CAAC,IAAI,IAAI,CAAC;oBAChG,gBAAgB,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC;iBAChF,CAAC,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC/E,MAAM,KAAK,CAAC;YACd,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF;CACF,CAAC"}