@cliftonc/cfld 0.2.3 → 0.2.4

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/cli.js CHANGED
@@ -1173,45 +1173,45 @@ async function runCommand(flags) {
1173
1173
  }
1174
1174
  const primary = routes[0];
1175
1175
  const certPath = await ensureCert(zone, { interactive });
1176
- const result = await reconcile(
1177
- { slug, tunnelName, zone, certPath, routes, projectDir: cwd, force: flags.force },
1178
- {
1179
- onStep: (s) => step(s),
1180
- confirmOverwrite: interactive ? (h, t) => askConfirm(`${h} already points to ${t}. Repoint it to this tunnel?`) : void 0
1181
- }
1182
- );
1183
- done(result.created ? `Created tunnel ${tunnelName}` : `Reusing tunnel ${tunnelName}`);
1184
- for (const r of routes) done(`DNS ${r.hostname} \u2192 :${r.port}`);
1185
- writeProjectConfig(cwd, {
1186
- name: slug,
1187
- zone,
1188
- uuid: result.uuid,
1189
- hostname: primary.hostname,
1190
- port: primary.port,
1191
- envKey
1192
- });
1193
- if (ensureGitignored(cwd, ".cfld.json")) info("Added .cfld.json to .gitignore.");
1194
- await launch(result, {
1176
+ await launch({
1195
1177
  cwd,
1178
+ slug,
1179
+ zone,
1196
1180
  envKey,
1197
1181
  noEnv: flags.noEnv,
1198
1182
  noUi: flags.noUi,
1183
+ url: `https://${primary.hostname}`,
1199
1184
  port: primary.port,
1200
- exec: flags.exec
1185
+ tunnelName,
1186
+ exec: flags.exec,
1187
+ runReconcile: (events) => reconcile(
1188
+ { slug, tunnelName, zone, certPath, routes, projectDir: cwd, force: flags.force },
1189
+ events
1190
+ ),
1191
+ onReconciled: (result, notify) => {
1192
+ writeProjectConfig(cwd, {
1193
+ name: slug,
1194
+ zone,
1195
+ uuid: result.uuid,
1196
+ hostname: primary.hostname,
1197
+ port: primary.port,
1198
+ envKey
1199
+ });
1200
+ if (ensureGitignored(cwd, ".cfld.json")) notify("Added .cfld.json to .gitignore.");
1201
+ }
1201
1202
  });
1202
1203
  }
1203
- async function launch(result, ctx) {
1204
- const metricsPort = await findFreePort();
1205
- const url = `https://${result.hostname}`;
1204
+ async function launch(ctx) {
1205
+ const url = ctx.url;
1206
1206
  const target = `localhost:${ctx.port}`;
1207
1207
  const interactive = isInteractive() && !ctx.noUi;
1208
1208
  let dashboard;
1209
1209
  if (interactive) {
1210
- const { startDashboard } = await import("./dashboard-Q6WI32AK.js");
1210
+ const { startDashboard } = await import("./dashboard-GA37Z4H4.js");
1211
1211
  dashboard = startDashboard({
1212
1212
  url,
1213
1213
  target,
1214
- tunnelName: result.tunnelName,
1214
+ tunnelName: ctx.tunnelName,
1215
1215
  status: "connecting",
1216
1216
  connections: 0,
1217
1217
  requests: 0,
@@ -1221,8 +1221,10 @@ async function launch(result, ctx) {
1221
1221
  devLogs: []
1222
1222
  });
1223
1223
  } else {
1224
- step("Connecting to Cloudflare edge\u2026");
1224
+ step("Setting up your tunnel\u2026");
1225
1225
  }
1226
+ const setupStep = (s) => dashboard ? dashboard.log(s, "tunnel") : step(s);
1227
+ const setupDone = (s) => dashboard ? dashboard.log(s, "tunnel") : done(s);
1226
1228
  const emitLine = (line) => {
1227
1229
  const formatted = formatLogLine(line);
1228
1230
  if (!formatted) return;
@@ -1251,21 +1253,15 @@ ${opts.reason}`);
1251
1253
  if (child) reapChild(child).then(finish, finish);
1252
1254
  else finish();
1253
1255
  };
1254
- runner = await startRunner({
1255
- configPath: result.configPath,
1256
- tunnelName: result.tunnelName,
1257
- certPath: result.certPath,
1258
- metricsPort,
1259
- onLine: (line) => emitLine(line),
1260
- onStatus: (status) => {
1261
- if (status === "reconnecting") dashboard?.update({ status: "reconnecting" });
1262
- else if (status === "connecting" && !dashboard) note("Reconnecting\u2026");
1263
- },
1264
- onFatal: (message) => {
1265
- warn(message);
1266
- shutdown({ code: 1 });
1267
- }
1268
- });
1256
+ process.once(
1257
+ "SIGINT",
1258
+ () => shutdown({ reason: "Stopping \u2014 your URL is preserved. Re-run `cfld`." })
1259
+ );
1260
+ process.once(
1261
+ "SIGTERM",
1262
+ () => shutdown({ reason: "Stopping \u2014 your URL is preserved." })
1263
+ );
1264
+ process.once("SIGHUP", () => shutdown({ reason: "Terminal closed \u2014 stopping." }));
1269
1265
  if (ctx.exec) {
1270
1266
  if (!dashboard) step(`Starting \`${describeCommand(ctx.exec)}\`\u2026`);
1271
1267
  child = startChild({
@@ -1283,15 +1279,42 @@ ${opts.reason}`);
1283
1279
  }
1284
1280
  });
1285
1281
  }
1286
- process.once(
1287
- "SIGINT",
1288
- () => shutdown({ reason: "Stopping \u2014 your URL is preserved. Re-run `cfld`." })
1282
+ const result = await ctx.runReconcile({
1283
+ onStep: (s) => setupStep(s),
1284
+ confirmOverwrite: interactive ? (h, t) => {
1285
+ const ask = () => askConfirm(`${h} already points to ${t}. Repoint it to this tunnel?`);
1286
+ return dashboard ? dashboard.suspend(ask) : ask();
1287
+ } : void 0
1288
+ }).catch(async (err) => {
1289
+ dashboard?.stop();
1290
+ if (child) await reapChild(child);
1291
+ throw err;
1292
+ });
1293
+ if (shuttingDown) return;
1294
+ setupDone(
1295
+ result.created ? `Created tunnel ${result.tunnelName}` : `Reusing tunnel ${result.tunnelName}`
1289
1296
  );
1290
- process.once(
1291
- "SIGTERM",
1292
- () => shutdown({ reason: "Stopping \u2014 your URL is preserved." })
1297
+ for (const r of result.routes) setupDone(`DNS ${r.hostname} \u2192 :${r.port}`);
1298
+ ctx.onReconciled?.(
1299
+ result,
1300
+ (msg) => dashboard ? dashboard.log(msg, "tunnel") : info(msg)
1293
1301
  );
1294
- process.once("SIGHUP", () => shutdown({ reason: "Terminal closed \u2014 stopping." }));
1302
+ const metricsPort = await findFreePort();
1303
+ runner = await startRunner({
1304
+ configPath: result.configPath,
1305
+ tunnelName: result.tunnelName,
1306
+ certPath: result.certPath,
1307
+ metricsPort,
1308
+ onLine: (line) => emitLine(line),
1309
+ onStatus: (status) => {
1310
+ if (status === "reconnecting") dashboard?.update({ status: "reconnecting" });
1311
+ else if (status === "connecting" && !dashboard) note("Reconnecting\u2026");
1312
+ },
1313
+ onFatal: (message) => {
1314
+ warn(message);
1315
+ shutdown({ code: 1 });
1316
+ }
1317
+ });
1295
1318
  const ready = await waitForReady(metricsPort).catch((err) => {
1296
1319
  child?.stop();
1297
1320
  runner?.stop();
@@ -1486,7 +1509,7 @@ ${opts.reason ?? "Stopped ephemeral tunnel."}`);
1486
1509
  });
1487
1510
  }
1488
1511
  if (interactive) {
1489
- const { startDashboard } = await import("./dashboard-Q6WI32AK.js");
1512
+ const { startDashboard } = await import("./dashboard-GA37Z4H4.js");
1490
1513
  dashboard = startDashboard({
1491
1514
  url,
1492
1515
  target,
@@ -1856,24 +1879,27 @@ async function upCommand(name) {
1856
1879
  }
1857
1880
  const slug = entry.name.replace(/^cfld-/, "");
1858
1881
  const routes = entry.routes?.length ? entry.routes : [{ hostname: entry.hostname, port: entry.port }];
1859
- const result = await reconcile(
1860
- {
1861
- slug,
1862
- tunnelName: entry.name,
1863
- zone: entry.zone,
1864
- certPath: cert,
1865
- routes,
1866
- projectDir: entry.projectDir
1867
- },
1868
- { onStep: (s) => step(s) }
1869
- );
1870
- done(result.created ? `Created tunnel ${entry.name}` : `Reusing tunnel ${entry.name}`);
1871
- await launch(result, {
1882
+ await launch({
1872
1883
  cwd: entry.projectDir,
1884
+ slug,
1885
+ zone: entry.zone,
1873
1886
  envKey: "PUBLIC_URL",
1874
1887
  noEnv: true,
1875
1888
  // don't touch a .env we may not be sitting in
1876
- port: entry.port
1889
+ url: `https://${entry.hostname}`,
1890
+ port: entry.port,
1891
+ tunnelName: entry.name,
1892
+ runReconcile: (events) => reconcile(
1893
+ {
1894
+ slug,
1895
+ tunnelName: entry.name,
1896
+ zone: entry.zone,
1897
+ certPath: cert,
1898
+ routes,
1899
+ projectDir: entry.projectDir
1900
+ },
1901
+ events
1902
+ )
1877
1903
  });
1878
1904
  }
1879
1905
 
@@ -126,14 +126,18 @@ function startDashboard(initial) {
126
126
  tunnelLogs: [...initial.tunnelLogs],
127
127
  devLogs: [...initial.devLogs]
128
128
  };
129
- process.stdout.write(ENTER_ALT_SCREEN);
130
- const instance = render(/* @__PURE__ */ jsx(Dashboard, { ...state }), {
129
+ const mount = () => render(/* @__PURE__ */ jsx(Dashboard, { ...state }), {
131
130
  stdout: process.stdout,
132
131
  // We drive graceful shutdown ourselves; ink's Ctrl-C simply resolves
133
132
  // waitUntilExit, and the caller then stops the runner (preserving state).
134
133
  exitOnCtrlC: true
135
134
  });
136
- const rerender = () => instance.rerender(/* @__PURE__ */ jsx(Dashboard, { ...state }));
135
+ process.stdout.write(ENTER_ALT_SCREEN);
136
+ let instance = mount();
137
+ let paused = false;
138
+ const rerender = () => {
139
+ if (!paused) instance.rerender(/* @__PURE__ */ jsx(Dashboard, { ...state }));
140
+ };
137
141
  let altActive = true;
138
142
  const leaveAltScreen = () => {
139
143
  if (!altActive) return;
@@ -141,6 +145,7 @@ function startDashboard(initial) {
141
145
  process.stdout.write(LEAVE_ALT_SCREEN);
142
146
  };
143
147
  const onResize = () => {
148
+ if (paused) return;
144
149
  instance.clear();
145
150
  rerender();
146
151
  };
@@ -159,6 +164,20 @@ function startDashboard(initial) {
159
164
  }
160
165
  rerender();
161
166
  },
167
+ async suspend(fn) {
168
+ paused = true;
169
+ instance.unmount();
170
+ leaveAltScreen();
171
+ try {
172
+ return await fn();
173
+ } finally {
174
+ process.stdout.write(ENTER_ALT_SCREEN);
175
+ altActive = true;
176
+ instance = mount();
177
+ paused = false;
178
+ rerender();
179
+ }
180
+ },
162
181
  waitUntilExit() {
163
182
  return instance.waitUntilExit();
164
183
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cliftonc/cfld",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Zero-token, persistent Cloudflare tunnel CLI for local dev — same public HTTPS URL every run.",
5
5
  "type": "module",
6
6
  "bin": {