@nifrajs/cli 0.1.0-alpha.1 → 0.1.0-alpha.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.
package/dist/port.js ADDED
@@ -0,0 +1,498 @@
1
+ /**
2
+ * `nifra port` — a portability linter. It scans an app's source for features whose runtime guarantees
3
+ * differ across deploy targets, prints a feature × target capability matrix, and (in CI mode) fails
4
+ * when a *detected* feature is unsupported on the app's resolved deploy target.
5
+ *
6
+ * The premise: nifra runs the same app on five targets (Bun, Node, Deno, Cloudflare Pages, Vercel), but
7
+ * a per-instance in-memory store, a long-lived in-process cron loop, or a `Bun.*` global is portable
8
+ * across some and a silent footgun on others. The framework's stores already *runtime*-guard this (e.g.
9
+ * `MemorySessionStore` throws under `NODE_ENV=production`); `port` is the *build-time* counterpart — it
10
+ * tells you before you deploy, and gates CI so the regression can't ship.
11
+ *
12
+ * Detection works on reliable import/symbol signals only (a real `@nifrajs/*` import paired with the
13
+ * exact exported symbol, a `node:` specifier, a `Bun.`/`Deno.` global), recording `file:line` evidence
14
+ * per hit. The pure scanners are unit-tested; correctness of detection IS the product for a linter.
15
+ */
16
+ import { join } from "node:path";
17
+ import { Glob } from "bun";
18
+ import { stripComments } from "./check.js";
19
+ /** The five deploy targets a nifra `site` app can build for (mirrors create-nifra's DEPLOY presets). */
20
+ export const TARGETS = ["bun", "node", "deno", "cf-pages", "vercel"];
21
+ const isTarget = (value) => TARGETS.includes(value);
22
+ /** The portability hazards `port` detects. Stable ids — they're part of the `--json` contract. */
23
+ export const FEATURE_IDS = [
24
+ "in-memory-session-store",
25
+ "in-memory-isr-cache",
26
+ "in-memory-rate-limit",
27
+ "in-process-cron",
28
+ "in-process-websocket",
29
+ "bun-runtime-api",
30
+ "deno-runtime-api",
31
+ "node-builtin",
32
+ ];
33
+ // In-memory stores (session/ISR/rate-limit) share a verdict shape: fine single-instance on a long-lived
34
+ // runtime (caveat — lost on restart, not shared across instances), unsupported on the distributed edge.
35
+ const inMemoryVerdicts = {
36
+ bun: "caveat",
37
+ node: "caveat",
38
+ deno: "caveat",
39
+ "cf-pages": "unsupported",
40
+ vercel: "unsupported",
41
+ };
42
+ const inMemoryReasons = (shared) => ({
43
+ bun: "ok single-instance; state is lost on restart and not shared across instances",
44
+ node: "ok single-instance; state is lost on restart and not shared across instances",
45
+ deno: "ok single-instance; state is lost on restart and not shared across instances",
46
+ "cf-pages": shared,
47
+ vercel: shared,
48
+ });
49
+ /**
50
+ * The capability matrix. The source of truth for every verdict + reason `port` prints. Verdicts mirror
51
+ * the framework's own runtime guards: the in-memory stores all `throw` under production multi-instance,
52
+ * cron documents the Workers `scheduled` trigger as its edge replacement, and the WS hub is the Workers
53
+ * cross-connection broadcast story.
54
+ */
55
+ export const FEATURES = {
56
+ "in-memory-session-store": {
57
+ label: "in-memory session store",
58
+ summary: "MemorySessionStore keeps sessions per-instance (@nifrajs/auth)",
59
+ verdicts: inMemoryVerdicts,
60
+ reasons: inMemoryReasons("distributed edge has no shared per-instance memory — use KVSessionStore (Workers KV) or another shared store"),
61
+ },
62
+ "in-memory-isr-cache": {
63
+ label: "in-memory ISR cache",
64
+ summary: "MemoryCacheStore caches rendered pages per-instance (@nifrajs/web)",
65
+ verdicts: inMemoryVerdicts,
66
+ reasons: inMemoryReasons("each edge instance caches separately and revalidation won't propagate — use KVCacheStore (Workers KV) or the platform Cache API"),
67
+ },
68
+ "in-memory-rate-limit": {
69
+ label: "in-memory rate limit",
70
+ summary: "MemoryStore counts hits per-instance (@nifrajs/middleware)",
71
+ verdicts: inMemoryVerdicts,
72
+ reasons: inMemoryReasons("a per-instance limiter doesn't hold across edge instances — use a shared store (Redis / Durable Object)"),
73
+ },
74
+ "in-process-cron": {
75
+ label: "in-process cron",
76
+ summary: "createScheduler runs a long-lived in-process loop (@nifrajs/cron)",
77
+ verdicts: {
78
+ bun: "ok",
79
+ node: "ok",
80
+ deno: "ok",
81
+ "cf-pages": "caveat",
82
+ vercel: "unsupported",
83
+ },
84
+ reasons: {
85
+ bun: "long-lived process runs the scheduler loop",
86
+ node: "long-lived process runs the scheduler loop",
87
+ deno: "long-lived process runs the scheduler loop",
88
+ "cf-pages": "no long-lived loop on Workers — use the platform `scheduled` trigger via toFetchHandler(app, { scheduled }) and a wrangler [triggers] cron",
89
+ vercel: "no long-lived process — use a Vercel Cron Job hitting an endpoint",
90
+ },
91
+ },
92
+ "in-process-websocket": {
93
+ label: "in-process WebSocket",
94
+ summary: "app.ws() without createWebSocketHub broadcasts only within one process",
95
+ verdicts: {
96
+ bun: "ok",
97
+ node: "ok",
98
+ deno: "ok",
99
+ "cf-pages": "caveat",
100
+ vercel: "unsupported",
101
+ },
102
+ reasons: {
103
+ bun: "all sockets live in one process; app.publish broadcasts to every client",
104
+ node: "all sockets live in one process; app.publish broadcasts to every client",
105
+ deno: "all sockets live in one process; app.publish broadcasts to every client",
106
+ "cf-pages": "a stateless fetch can't broadcast across isolates — wrap the app in createWebSocketHub (a Durable Object) from @nifrajs/workers",
107
+ vercel: "Vercel's serverless functions don't hold long-lived WebSocket connections",
108
+ },
109
+ },
110
+ "bun-runtime-api": {
111
+ label: "Bun.* runtime API",
112
+ summary: "Bun.* globals (Bun.serve, Bun.file, …) exist only on the Bun runtime",
113
+ verdicts: {
114
+ bun: "ok",
115
+ node: "unsupported",
116
+ deno: "unsupported",
117
+ "cf-pages": "unsupported",
118
+ vercel: "unsupported",
119
+ },
120
+ reasons: {
121
+ bun: "the Bun runtime provides the Bun global",
122
+ node: "no Bun global on Node — use the node: / Web equivalents",
123
+ deno: "no Bun global on Deno — use the Deno / Web equivalents",
124
+ "cf-pages": "no Bun global in the Workers runtime",
125
+ vercel: "no Bun global in the Vercel runtime",
126
+ },
127
+ },
128
+ "deno-runtime-api": {
129
+ label: "Deno.* runtime API",
130
+ summary: "Deno.* globals exist only on the Deno runtime",
131
+ verdicts: {
132
+ bun: "unsupported",
133
+ node: "unsupported",
134
+ deno: "ok",
135
+ "cf-pages": "unsupported",
136
+ vercel: "unsupported",
137
+ },
138
+ reasons: {
139
+ bun: "no Deno global on Bun — use the Bun / Web equivalents",
140
+ node: "no Deno global on Node — use the node: / Web equivalents",
141
+ deno: "the Deno runtime provides the Deno global",
142
+ "cf-pages": "no Deno global in the Workers runtime",
143
+ vercel: "no Deno global in the Vercel runtime",
144
+ },
145
+ },
146
+ "node-builtin": {
147
+ label: "node: builtin",
148
+ summary: "node:* builtins (node:fs, node:crypto, …) need a Node-compatible runtime",
149
+ verdicts: {
150
+ bun: "ok",
151
+ node: "ok",
152
+ deno: "ok",
153
+ "cf-pages": "caveat",
154
+ vercel: "caveat",
155
+ },
156
+ reasons: {
157
+ bun: "Bun implements the node: builtins",
158
+ node: "native node: builtins",
159
+ deno: "Deno implements the node: builtins",
160
+ "cf-pages": 'Workers needs `compatibility_flags = ["nodejs_compat"]` in wrangler.toml (and not every builtin is covered)',
161
+ vercel: "needs the Node.js runtime (not the Edge runtime) so node: builtins resolve",
162
+ },
163
+ },
164
+ };
165
+ /** Line number (1-based) of a string index. */
166
+ const lineAt = (content, index) => content.slice(0, index).split("\n").length;
167
+ // --- Detection signals (all matched against comment-stripped source so doc examples don't false-positive) ---
168
+ // A non-type import (static, side-effect, dynamic, or re-export) from one of these `@nifrajs/*` packages.
169
+ // Used to confirm a symbol like `MemoryStore` is the framework's, not a same-named local class.
170
+ const importsFrom = (code, pkg) => {
171
+ const escaped = pkg.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&");
172
+ // `from "@nifrajs/x"` | `from "@nifrajs/x/sub"` | `import("@nifrajs/x")` | `import "@nifrajs/x"`
173
+ const rx = new RegExp(`(?:from|import)\\s*\\(?\\s*["'\`]${escaped}(?:/[^"'\`]*)?["'\`]`);
174
+ return rx.test(code);
175
+ };
176
+ // `new MemorySessionStore(` / `MemorySessionStore` referenced as a value. We require the @nifrajs/auth
177
+ // import in the same file (importsFrom) so a same-named user class never trips it.
178
+ const SESSION_STORE = /(?<![.\w$])MemorySessionStore\b/g;
179
+ const ISR_CACHE = /(?<![.\w$])MemoryCacheStore\b/g;
180
+ // Rate-limit store. The exported symbol is the generic `MemoryStore`; require the @nifrajs/middleware
181
+ // import so it can't collide with an unrelated `MemoryStore` from elsewhere.
182
+ const RATE_LIMIT = /(?<![.\w$])MemoryStore\b/g;
183
+ // In-process cron: the scheduler factory. Paired with the @nifrajs/cron import.
184
+ const CRON_SCHEDULER = /(?<![.\w$])createScheduler\s*\(/g;
185
+ // `.ws(` method call — a WebSocket route registration on a nifra app. `(?<![.\w$])` keeps it from
186
+ // matching identifiers that merely END in `ws` (e.g. `rows(`, `views(`). It DOES match `app.ws(`,
187
+ // `server().ws(`, `x.ws(` — all the chained forms — because the dot is consumed by the call, and the
188
+ // negative lookbehind only guards the char BEFORE `ws`, which is the dot here. We exclude the dot from
189
+ // the lookbehind set on purpose: a method call is exactly what we want.
190
+ const WS_ROUTE = /\.ws\s*\(/g;
191
+ const WS_HUB = /(?<![.\w$])createWebSocketHub\b/;
192
+ // `Bun.` / `Deno.` runtime globals. `(?<![.\w$])` rejects `myBun.x`, `globalThis.Bun` stays a real use
193
+ // (we want it), and `obj.Bun.` won't match because the char before `Bun` would be `.`.
194
+ const BUN_GLOBAL = /(?<![.\w$])Bun\s*\./g;
195
+ const DENO_GLOBAL = /(?<![.\w$])Deno\s*\./g;
196
+ // `node:` builtin specifier in any import/require/export-from form.
197
+ const NODE_BUILTIN = /(?:from|import|require)\s*\(?\s*["'`](node:[A-Za-z0-9/_-]+)["'`]/g;
198
+ const pushHits = (out, file, content, code, rx) => {
199
+ rx.lastIndex = 0;
200
+ const lines = content.split("\n");
201
+ for (let m = rx.exec(code); m !== null; m = rx.exec(code)) {
202
+ const line = lineAt(code, m.index);
203
+ out.push({ file, line, snippet: (lines[line - 1] ?? "").trim() });
204
+ }
205
+ };
206
+ /**
207
+ * Scan one file's source for every feature signal, mutating `state`. Pure w.r.t. the filesystem (takes
208
+ * the already-read `content`). Comment- and template-literal-stripped first, so a usage example in a
209
+ * doc comment or a code-as-text string never false-positives (shared with `nifra check`/`doctor`).
210
+ */
211
+ export function scanFileForFeatures(file, content, state) {
212
+ const code = stripComments(content);
213
+ const add = (id) => {
214
+ const list = state.evidence.get(id) ?? [];
215
+ if (!state.evidence.has(id))
216
+ state.evidence.set(id, list);
217
+ return list;
218
+ };
219
+ if (WS_HUB.test(code))
220
+ state.hasWebSocketHub = true;
221
+ if (importsFrom(code, "@nifrajs/auth"))
222
+ pushHits(add("in-memory-session-store"), file, content, code, SESSION_STORE);
223
+ if (importsFrom(code, "@nifrajs/web"))
224
+ pushHits(add("in-memory-isr-cache"), file, content, code, ISR_CACHE);
225
+ if (importsFrom(code, "@nifrajs/middleware"))
226
+ pushHits(add("in-memory-rate-limit"), file, content, code, RATE_LIMIT);
227
+ if (importsFrom(code, "@nifrajs/cron"))
228
+ pushHits(add("in-process-cron"), file, content, code, CRON_SCHEDULER);
229
+ // WS routes are collected unconditionally; the hub-presence post-pass decides whether they're a hazard.
230
+ pushHits(add("in-process-websocket"), file, content, code, WS_ROUTE);
231
+ pushHits(add("bun-runtime-api"), file, content, code, BUN_GLOBAL);
232
+ pushHits(add("deno-runtime-api"), file, content, code, DENO_GLOBAL);
233
+ pushHits(add("node-builtin"), file, content, code, NODE_BUILTIN);
234
+ }
235
+ // Mirror nifra check/doctor's ignore set: deps, build output, generated/per-runtime dist dirs, VCS.
236
+ // PLUS *.config.* and obvious build scripts (build*.ts) — `port` scans request/app source, not tooling.
237
+ const IGNORED = /(^|\/)(node_modules|dist(-[a-z0-9]+)?|build|\.nifra|\.git|\.wrangler|coverage)\/|\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)[^/]*\.config\.[cm]?[jt]sx?$|(^|\/)build[^/]*\.[cm]?[jt]sx?$/;
238
+ /** Walk the project's source (same surface as `nifra check`, minus config + build scripts). */
239
+ async function walkPortSource(cwd, visit) {
240
+ for await (const rel of new Glob("**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}").scan({
241
+ cwd,
242
+ dot: false,
243
+ })) {
244
+ if (IGNORED.test(rel))
245
+ continue;
246
+ visit(rel, await Bun.file(join(cwd, rel)).text());
247
+ }
248
+ }
249
+ const byEvidence = (a, b) => a.file.localeCompare(b.file) || a.line - b.line;
250
+ /** Run every detector over the project and return the detected features (sorted, stable). */
251
+ export async function detectFeatures(cwd) {
252
+ const state = { evidence: new Map(), hasWebSocketHub: false };
253
+ await walkPortSource(cwd, (rel, content) => scanFileForFeatures(rel, content, state));
254
+ const detected = [];
255
+ for (const id of FEATURE_IDS) {
256
+ const evidence = state.evidence.get(id);
257
+ if (evidence === undefined || evidence.length === 0)
258
+ continue;
259
+ // in-process WebSocket is only a portability hazard when the app does NOT use createWebSocketHub
260
+ // (the Workers Durable Object hub) — its presence means the WS routes are already edge-ready.
261
+ if (id === "in-process-websocket" && state.hasWebSocketHub)
262
+ continue;
263
+ const spec = FEATURES[id];
264
+ detected.push({
265
+ id,
266
+ label: spec.label,
267
+ evidence: [...evidence].sort(byEvidence),
268
+ verdicts: spec.verdicts,
269
+ });
270
+ }
271
+ return detected;
272
+ }
273
+ const BUILD_SCRIPT_TARGET = [
274
+ // create-nifra's canonical per-target build scripts (build-bun.ts / build-node.ts / build-deno.ts /
275
+ // build-vercel.ts), plus the bare `build.ts` the cf-pages preset uses.
276
+ [/build-vercel\.[cm]?[jt]s\b/, "vercel"],
277
+ [/build-deno\.[cm]?[jt]s\b/, "deno"],
278
+ [/build-node\.[cm]?[jt]s\b/, "node"],
279
+ [/build-bun\.[cm]?[jt]s\b/, "bun"],
280
+ ];
281
+ const DEPLOY_SCRIPT_TARGET = [
282
+ [/\bvercel\s+deploy\b/, "vercel"],
283
+ [/\bdeployctl\b/, "deno"],
284
+ [/wrangler\s+pages\s+deploy\b/, "cf-pages"],
285
+ [/\bdocker\s+build\b/, "node"],
286
+ ];
287
+ /**
288
+ * Resolve the app's deploy target. `--target` (validated) always wins. Otherwise infer it, in priority
289
+ * order, from: the canonical `build` script (create-nifra's `build-<target>.ts`), the `deploy` script
290
+ * (the vendor CLI it shells out to), a `wrangler.toml` (Cloudflare Pages), or a `vercel.json`. Returns
291
+ * `undefined` when nothing signals a target (the matrix still prints; CI gating needs an explicit one).
292
+ */
293
+ export async function resolveTarget(cwd, override) {
294
+ if (override !== undefined) {
295
+ if (!isTarget(override)) {
296
+ throw new Error(`[nifra] invalid --target "${override}". options: ${TARGETS.join(", ")}`);
297
+ }
298
+ return { target: override, source: "flag" };
299
+ }
300
+ const pkg = await readJson(join(cwd, "package.json"));
301
+ const scripts = pkg?.scripts;
302
+ if (scripts !== undefined) {
303
+ const build = scripts.build ?? "";
304
+ for (const [rx, target] of BUILD_SCRIPT_TARGET) {
305
+ if (rx.test(build))
306
+ return { target, source: "package-json-build" };
307
+ }
308
+ const deploy = scripts.deploy ?? "";
309
+ for (const [rx, target] of DEPLOY_SCRIPT_TARGET) {
310
+ if (rx.test(deploy))
311
+ return { target, source: "package-json-deploy" };
312
+ }
313
+ }
314
+ if (await Bun.file(join(cwd, "wrangler.toml")).exists()) {
315
+ return { target: "cf-pages", source: "wrangler" };
316
+ }
317
+ if ((await Bun.file(join(cwd, "vercel.json")).exists()) ||
318
+ (await Bun.file(join(cwd, ".vercel", "project.json")).exists())) {
319
+ return { target: "vercel", source: "vercel" };
320
+ }
321
+ return undefined;
322
+ }
323
+ async function readJson(path) {
324
+ try {
325
+ const parsed = JSON.parse(await Bun.file(path).text());
326
+ return typeof parsed === "object" && parsed !== null ? parsed : undefined;
327
+ }
328
+ catch {
329
+ return undefined;
330
+ }
331
+ }
332
+ const evidenceStrings = (evidence) => evidence.map((e) => `${e.file}:${e.line}`);
333
+ /**
334
+ * Compute the full `port` result: detect features, resolve the target, and derive the blocking findings.
335
+ * A finding blocks when the detected feature is `unsupported` on the resolved target — always — and
336
+ * (with `strict`) also when it's a `caveat`. With no resolved target there's nothing to gate against,
337
+ * so `blocked` is empty and `ok` reflects "are there hazards at all" only when the caller asks.
338
+ */
339
+ export async function collectPortResult(cwd, opts = {}) {
340
+ const [detected, resolved] = await Promise.all([
341
+ detectFeatures(cwd),
342
+ resolveTarget(cwd, opts.target),
343
+ ]);
344
+ const blocked = [];
345
+ if (resolved !== undefined) {
346
+ for (const feature of detected) {
347
+ const verdict = feature.verdicts[resolved.target];
348
+ const blocks = verdict === "unsupported" || (verdict === "caveat" && opts.strict === true);
349
+ if (!blocks)
350
+ continue;
351
+ blocked.push({
352
+ feature: feature.id,
353
+ verdict,
354
+ reason: FEATURES[feature.id].reasons[resolved.target],
355
+ evidence: evidenceStrings(feature.evidence),
356
+ });
357
+ }
358
+ }
359
+ const json = {
360
+ target: resolved?.target ?? null,
361
+ targetSource: resolved?.source ?? null,
362
+ features: detected.map((f) => ({
363
+ id: f.id,
364
+ label: f.label,
365
+ evidence: evidenceStrings(f.evidence),
366
+ verdicts: f.verdicts,
367
+ })),
368
+ blocked,
369
+ ok: blocked.length === 0,
370
+ };
371
+ return { resolved, detected, json };
372
+ }
373
+ // --- Rendering ----------------------------------------------------------------------------------------
374
+ const CELL = { ok: "✓", caveat: "⚠", unsupported: "✗" };
375
+ const COL_WIDTH = 9; // widest target header ("cf-pages") + padding
376
+ const padCell = (s, width) => {
377
+ // Pad accounting for the symbol's display width (✓/⚠/✗ render as 1 cell in a monospace terminal).
378
+ const len = [...s].length;
379
+ return s + " ".repeat(Math.max(0, width - len));
380
+ };
381
+ /** Render the feature × target matrix + evidence + summary as a readable report. */
382
+ export function renderReport(result, opts) {
383
+ const { detected, resolved, json } = result;
384
+ const out = ["nifra port — portability matrix", ""];
385
+ if (resolved !== undefined) {
386
+ out.push(`target: ${resolved.target} (detected from ${describeSource(resolved.source)})`);
387
+ }
388
+ else {
389
+ out.push("target: not detected — pass --target <bun|node|deno|cf-pages|vercel> to gate against one");
390
+ }
391
+ out.push("");
392
+ if (detected.length === 0) {
393
+ out.push("✓ no portability hazards detected — this app is portable across all targets.");
394
+ return out.join("\n");
395
+ }
396
+ // Header row.
397
+ const labelWidth = Math.max(22, ...detected.map((f) => f.label.length)) + 2;
398
+ const header = padCell("feature", labelWidth) + TARGETS.map((t) => padCell(t, COL_WIDTH)).join("");
399
+ out.push(header);
400
+ out.push("-".repeat(header.length));
401
+ for (const feature of detected) {
402
+ const cells = TARGETS.map((t) => padCell(CELL[feature.verdicts[t]], COL_WIDTH)).join("");
403
+ out.push(padCell(feature.label, labelWidth) + cells);
404
+ }
405
+ out.push("");
406
+ out.push("legend: ✓ ok ⚠ caveat (works with a change) ✗ unsupported");
407
+ out.push("");
408
+ // Evidence per detected feature.
409
+ out.push("detected features + evidence:");
410
+ for (const feature of detected) {
411
+ out.push(` • ${feature.label} (${feature.id})`);
412
+ out.push(` why: ${FEATURES[feature.id].summary}`);
413
+ for (const e of feature.evidence) {
414
+ out.push(` ${e.file}:${e.line} ${e.snippet}`);
415
+ }
416
+ }
417
+ out.push("");
418
+ // Summary + blocking detail.
419
+ if (resolved === undefined) {
420
+ out.push(`• ${detected.length} portability hazard(s) detected; no target resolved, so nothing is gated. ` +
421
+ "Pass --target to check one.");
422
+ return out.join("\n");
423
+ }
424
+ if (json.blocked.length === 0) {
425
+ // With the gate passing, surface any caveats for the resolved target so the user still sees the
426
+ // "works, but with a change" cases (they don't fail without --strict, but they're not free either).
427
+ const caveatHere = detected.filter((f) => f.verdicts[resolved.target] === "caveat");
428
+ if (caveatHere.length === 0) {
429
+ out.push(`✓ portable to ${resolved.target}: every detected feature is supported there.`);
430
+ }
431
+ else {
432
+ out.push(`✓ no blockers for ${resolved.target}, but ${caveatHere.length} feature(s) need a change there:`);
433
+ for (const f of caveatHere) {
434
+ out.push(` ⚠ ${f.label} — ${FEATURES[f.id].reasons[resolved.target]}`);
435
+ }
436
+ out.push("\n(caveats don't fail the gate — run with --strict to treat them as blockers)");
437
+ }
438
+ return out.join("\n");
439
+ }
440
+ const unsupported = json.blocked.filter((b) => b.verdict === "unsupported");
441
+ const caveats = json.blocked.filter((b) => b.verdict === "caveat");
442
+ out.push(`✗ ${json.blocked.length} feature(s) block deploying to ${resolved.target}:`);
443
+ for (const b of [...unsupported, ...caveats]) {
444
+ const mark = b.verdict === "unsupported" ? "✗" : "⚠";
445
+ out.push(` ${mark} ${FEATURES[b.feature].label} — ${b.verdict} on ${resolved.target}`);
446
+ out.push(` fix: ${b.reason}`);
447
+ out.push(` at: ${b.evidence.join(", ")}`);
448
+ }
449
+ if (!opts.strict && unsupported.length === 0) {
450
+ out.push("\n(only caveats — run with --strict to fail on these)");
451
+ }
452
+ return out.join("\n");
453
+ }
454
+ function describeSource(source) {
455
+ switch (source) {
456
+ case "flag":
457
+ return "--target";
458
+ case "package-json-build":
459
+ return "the package.json build script";
460
+ case "package-json-deploy":
461
+ return "the package.json deploy script";
462
+ case "wrangler":
463
+ return "wrangler.toml";
464
+ case "vercel":
465
+ return "vercel config";
466
+ }
467
+ }
468
+ /**
469
+ * Run `nifra port`: detect, resolve, render. Returns `true` when the run "passes" — meaning either the
470
+ * gate is off, or the gate is on and nothing blocks. The caller maps `false` → exit 1.
471
+ *
472
+ * The gate fires when `--ci` is passed OR a `--target` is set (an explicit target signals intent to
473
+ * gate). With no resolved target and `--ci`, the run is a hard error: there's nothing to gate against.
474
+ */
475
+ export async function runPort(cwd, opts = {}) {
476
+ const result = await collectPortResult(cwd, {
477
+ ...(opts.target !== undefined ? { target: opts.target } : {}),
478
+ ...(opts.strict ? { strict: true } : {}),
479
+ });
480
+ // The gate is on when --ci or an explicit --target was given.
481
+ const gating = opts.ci === true || opts.target !== undefined;
482
+ if (opts.json) {
483
+ console.log(JSON.stringify(result.json, null, 2));
484
+ }
485
+ else {
486
+ console.log(renderReport(result, { strict: opts.strict ?? false }));
487
+ }
488
+ if (!gating)
489
+ return true;
490
+ if (result.resolved === undefined) {
491
+ if (!opts.json) {
492
+ console.error("\n[nifra] --ci needs a deploy target to gate against, and none was detected. Pass --target <bun|node|deno|cf-pages|vercel>.");
493
+ }
494
+ return false;
495
+ }
496
+ return result.json.blocked.length === 0;
497
+ }
498
+ //# sourceMappingURL=port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"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"}