naro-cli 0.22.0 → 0.24.0

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.
@@ -0,0 +1,12 @@
1
+ import type { CommandContext } from "../context";
2
+ /**
3
+ * Whether a question could be put to anyone: not with `--json`, and not
4
+ * without a terminal. Only `--yes` answers it then (`confirmOrAbort`).
5
+ */
6
+ export declare function cannotAsk(context: CommandContext): boolean;
7
+ /**
8
+ * Gate for destructive actions. Throws instead of silently returning so a
9
+ * declined/unavailable confirmation is a real failure (exit 1, structured
10
+ * JSON) — CI must never read "nothing happened" as success.
11
+ */
12
+ export declare function confirmOrAbort(context: CommandContext, question: string): Promise<void>;
@@ -0,0 +1,32 @@
1
+ import type { CommandContext } from "../context";
2
+ /** How `db query` sees stdin — injectable so tests never touch the real one. */
3
+ export interface DbQueryDeps {
4
+ stdinIsTty(): boolean;
5
+ readStdin(): Promise<string>;
6
+ }
7
+ /** `512 B`, `1.5 KB`, `2.0 GB` — binary sizes, as `db dump` prints the file it wrote. */
8
+ export declare function humanSize(bytes: number): string;
9
+ /**
10
+ * `10 GB`, `100 KB`, `12.29 KB` — Cloudflare states D1's limits in decimal
11
+ * units, so `db info` prints them that way (PR D). Two decimals, rounded; a
12
+ * value that rounds to 1000 moves to the next unit (`999,995 B` is `1 MB`,
13
+ * not `1000 KB` — user review 3).
14
+ */
15
+ export declare function decimalSize(bytes: number): string;
16
+ /**
17
+ * A database's size on the `Size:` and `Storage:` lines. From 1 GB, decimal
18
+ * gigabytes FLOORED to two decimals: the 8 GB warning and the 10 GB limit are
19
+ * `>=` comparisons, and rounding showed `10.00 GB / 10 GB` for 9,996,000,000
20
+ * bytes that still took writes, and `8.00 GB` with no warning (user review
21
+ * 3). Under 1 GB, decimalSize — a new database is `12.29 KB`, not `0.00 GB`.
22
+ */
23
+ export declare function storageSize(bytes: number): string;
24
+ /** `naro db info` — provider, status, size, table count and the limits. */
25
+ export declare function runDbInfo(context: CommandContext): Promise<void>;
26
+ /** `naro db enable` — idempotent: creates the D1 if the project has none. */
27
+ export declare function runDbEnable(context: CommandContext): Promise<void>;
28
+ /**
29
+ * `naro db query <sql> | --file <path> | (stdin)` — runs the batch through the
30
+ * control plane, which classifies it, checks the role and executes it.
31
+ */
32
+ export declare function runDbQuery(context: CommandContext, deps?: DbQueryDeps): Promise<void>;
@@ -0,0 +1,78 @@
1
+ import { type MigrationInfo, type NaroClient } from "@next-deploy/sdk";
2
+ import type { CommandContext } from "../context";
3
+ import type { DbQueryDeps } from "./db";
4
+ /** `--dir` wins; otherwise `<--root>/migrations` (or `./migrations`). */
5
+ export declare function migrationsDir(context: CommandContext): string;
6
+ /** `relative()` returns "" for the cwd itself; `migration list` prints "." instead. */
7
+ export declare function relativeToCwd(context: CommandContext, path: string): string;
8
+ /** The ledger, or [] while the project has no database yet — a push creates it. */
9
+ export declare function appliedMigrations(client: NaroClient, projectId: string): Promise<MigrationInfo[]>;
10
+ export declare function printable(text: string): string;
11
+ /**
12
+ * Whether `printable` shows the text as it is. Text a command takes back —
13
+ * a CREATE POLICY statement, a condition — must not be printed with `?` in
14
+ * a character's place: pasted back, it would say something else (PR #74
15
+ * 리뷰 L2). What is not printable is not printed; `--json` has every byte.
16
+ */
17
+ export declare function isPrintable(text: string): boolean;
18
+ export declare const UNSHOWN_WARNING_LINE = "(a line of this warning has characters the terminal cannot show; run with --json to see it exactly)";
19
+ /**
20
+ * A server warning as terminal lines: `⚠ ` and its first line, then each
21
+ * further line indented. A warning can carry SQL to paste back — the
22
+ * policies a table rebuild took, one statement a line (P2-7b) — so a line
23
+ * break starts a new line rather than becoming a `?`; every other control
24
+ * character does in the first line. A further line it cannot show as it is
25
+ * is not printed at all — pasted back with a `?` in a character's place, it
26
+ * would say something else (as `naro policy list` holds a CREATE POLICY to,
27
+ * PR #74 리뷰 L2) — and `--json` has it exactly.
28
+ */
29
+ export declare function warningLines(message: string): string[];
30
+ /** Something said about one migration file: a server warning, a refusal. */
31
+ export interface MigrationMessage {
32
+ migration: string;
33
+ message: string;
34
+ }
35
+ /**
36
+ * What the control plane would refuse in each file before it runs any of
37
+ * it (P2-7b) — a policy statement its parser cannot read, DISABLE ROW LEVEL
38
+ * SECURITY, GRANT, REVOKE — said the way the server says it: its own
39
+ * planner over its own split. A file the split cannot read is left to the
40
+ * server, which says why. The guards (is the table there, is the policy)
41
+ * need the database and are not run.
42
+ */
43
+ export declare function policyProblems(dir: string, names: string[]): MigrationMessage[];
44
+ /**
45
+ * `naro migration new <name>` — creates `migrations/NNNN_<name>.sql` and
46
+ * never overwrites an existing file. No network: the file is all this writes.
47
+ */
48
+ export declare function runMigrationNew(context: CommandContext, deps?: DbQueryDeps): Promise<void>;
49
+ /** `naro migration list` — local files against the `d1_migrations` ledger. */
50
+ export declare function runMigrationList(context: CommandContext): Promise<void>;
51
+ /**
52
+ * Applies `names` from `dir` in order and answers with the ones that went
53
+ * through, and what the server warned about each (P2-7b: what their
54
+ * policies need — on stderr as `⚠` lines as they come). Each file is
55
+ * applied all-or-nothing (D1 runs it as one transaction); a failure stops
56
+ * the run and the files before it stay applied. Shared with `db reset`,
57
+ * which re-applies the same way after clearing the ledger — the apply loop
58
+ * exists once.
59
+ */
60
+ export declare function applyMigrationFiles(context: CommandContext, client: NaroClient, projectId: string, dir: string, names: string[]): Promise<{
61
+ applied: string[];
62
+ warnings: MigrationMessage[];
63
+ }>;
64
+ /**
65
+ * `naro migration repair <name> --status applied|reverted` — edits the
66
+ * `d1_migrations` ledger and nothing else. It never runs the migration's SQL:
67
+ * this is for a ledger that stopped matching the database (a record step that
68
+ * failed after the file ran, a `db pull` baseline being taken back). To run
69
+ * SQL, use `db push`.
70
+ */
71
+ export declare function runMigrationRepair(context: CommandContext): Promise<void>;
72
+ /**
73
+ * `naro migration up` (= `naro db push`) — applies every pending migration in
74
+ * order. Each file is applied all-or-nothing (D1 runs it as one transaction);
75
+ * a failure rolls that file back and stops the run, and the files before it
76
+ * stay applied (see the ledger via `migration list`).
77
+ */
78
+ export declare function runMigrationUp(context: CommandContext): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { NaroClient, type ProjectLink, type ResolvedAuth } from "@next-deploy/sdk";
2
+ import type { GlobalFlags } from "./args";
3
+ import { Output } from "./output";
4
+ import { type Prompter } from "./prompt";
5
+ export interface CommandContext {
6
+ cwd: string;
7
+ flags: GlobalFlags;
8
+ /** Positional args after the (sub)command, e.g. the KEY in `env add KEY`. */
9
+ positionals: string[];
10
+ output: Output;
11
+ prompter: Prompter;
12
+ /** Returns the first `count` positionals or fails with a usage message. */
13
+ positionalOrThrow(count: number, usage: string): string[];
14
+ /** Lazily authenticates; interactive login only in a TTY without --json/--yes. */
15
+ auth(): Promise<ResolvedAuth>;
16
+ client(): Promise<NaroClient>;
17
+ /** Resolves the target project id: --project flag > .naro/project.json. */
18
+ resolveProjectId(): Promise<string>;
19
+ projectLink(): ProjectLink | null;
20
+ }
21
+ export declare function createContext(flags: GlobalFlags, positionals?: string[]): CommandContext;
@@ -0,0 +1,36 @@
1
+ import { type NaroClient } from "@next-deploy/sdk";
2
+ import type { GlobalFlags } from "./args";
3
+ import type { CommandContext } from "./context";
4
+ export declare const DATA_ENV_MESSAGES: {
5
+ readonly name: "--env must be production or an environment name.";
6
+ readonly preview: "--env preview has no data of its own: preview deployments use production's. Drop --env, or name an environment.";
7
+ readonly projectWide: (command: string) => string;
8
+ };
9
+ /**
10
+ * The environment a data command acts on, or null for production. Throws for
11
+ * a value that names no environment — `preview`, an empty one, one that is no
12
+ * slug — before any request; whether the environment exists is the control
13
+ * plane's to answer (`ENVIRONMENT_NOT_FOUND`).
14
+ */
15
+ export declare function dataEnvironment(flags: Pick<GlobalFlags, "env">): string | null;
16
+ /** The command's client, acting on the data `--env` names. */
17
+ export declare function dataClient(context: Pick<CommandContext, "client" | "flags">): Promise<NaroClient>;
18
+ /** What a prompt and a result line call the database a command acts on. */
19
+ export declare function databaseName(environment: string | null): string;
20
+ /**
21
+ * The command that puts the backend (back) on: `naro backend enable` for
22
+ * production's, and for an environment `naro environments provision <slug>` —
23
+ * backend enable is project-wide and the router refuses it under `--env`.
24
+ */
25
+ export declare function enableBackendCommand(environment: string | null): string;
26
+ /** ` --env <name>` for a hint that names a command; nothing for production. */
27
+ export declare function envFlag(environment: string | null): string;
28
+ /**
29
+ * A hint, or a message the CLI prints, as the environment's: every command
30
+ * it names acts on that environment (`environmentGuidance`, PR #343 review
31
+ * 2) — a data command takes ` --env <slug>`, a backend repair becomes
32
+ * `naro environments provision <slug>`, and the backend's switch is said to
33
+ * be production's, which every environment follows. Production's text
34
+ * passes through byte for byte.
35
+ */
36
+ export declare function forEnvironment(text: string, environment: string | null): string;
package/dist/deploy.d.ts CHANGED
@@ -112,3 +112,4 @@ export interface DeployResult {
112
112
  * Shared by `naro deploy` and the MCP `deploy` tool.
113
113
  */
114
114
  export declare function deployDirectory(sourceDir: string, options: DeployOptions, log: (message: string) => void): Promise<DeployResult>;
115
+ export { assertFunctionsNode, deployFunctions, type DeployedFunction, type DeployFunctionsOptions, type DeployFunctionsResult, } from "./functions/deploy";
package/dist/deploy.js CHANGED
@@ -1,16 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ assertFunctionsNode,
3
4
  deployDirectory,
5
+ deployFunctions,
4
6
  eventsObserver,
5
7
  localDependencies,
6
8
  parseDotenv,
7
9
  readProjectEnv,
8
10
  slugify,
9
11
  workingTreeNotices
10
- } from "./chunk-MBSO3K6L.js";
12
+ } from "./chunk-XJIWWZ2T.js";
11
13
  import "./chunk-K3NQKI34.js";
12
14
  export {
15
+ assertFunctionsNode,
13
16
  deployDirectory,
17
+ deployFunctions,
14
18
  eventsObserver,
15
19
  localDependencies,
16
20
  parseDotenv,
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Which outside service the env keys a deploy is missing belong to, and where
3
+ * that service keeps their values.
4
+ *
5
+ * The deploy already works out the names it needs by scanning the source
6
+ * (`scanEnvReferences`), but a list of bare names only helps someone who
7
+ * already knows where each value comes from. The first thing anyone moving an
8
+ * existing app here hits is exactly that gap: the app talks to a Supabase
9
+ * project that is already running, and the deploy asks for
10
+ * `NEXT_PUBLIC_SUPABASE_URL` without saying it is asking for something they
11
+ * have in another browser tab.
12
+ *
13
+ * This only names the service and the screen its values are on. Nothing here
14
+ * reaches Supabase's API, stores a token or creates anything there — the
15
+ * values still arrive the way every other env var does, from `.env.local`
16
+ * with the user's consent or from `naro env add`.
17
+ */
18
+ /** The key without that prefix. The longest match wins, so order is free. */
19
+ export declare function bareEnvKey(key: string): string;
20
+ /**
21
+ * The given keys that name a Supabase project, in the order given.
22
+ *
23
+ * Everything Supabase hands a project is `SUPABASE_*`: the project URL, the
24
+ * publishable and secret keys, the legacy `anon` and `service_role` keys, the
25
+ * JWT secret, the account's access token, the database password. Matching the
26
+ * prefix rather than a fixed list keeps a name we have not seen — Supabase
27
+ * renamed its keys once already — from dropping out. A name that merely
28
+ * contains the word (`MY_SUPABASE_URL`) is not one of theirs.
29
+ *
30
+ * Belonging to Supabase is not the same as being on one of the screens
31
+ * `envServiceHints` knows; that function decides which of these it can place.
32
+ */
33
+ export declare function supabaseKeys(keys: readonly string[]): string[];
34
+ /**
35
+ * Lines naming the service the missing keys belong to, to print under the
36
+ * "env var(s) needed" line. Empty when nothing is recognised, which is the
37
+ * common case — this adds to that line, it never replaces it.
38
+ *
39
+ * Adding a second service means another `supabaseKeys`-shaped filter and
40
+ * another branch here. It is deliberately not a table of services yet: the
41
+ * useful half of each entry is the screen its values are on, and that is
42
+ * prose we can only write for a dashboard we have actually checked.
43
+ */
44
+ export declare function envServiceHints(keys: readonly string[]): string[];
@@ -0,0 +1,70 @@
1
+ import { bootCheck, bundleFunction } from "@next-deploy/functions-bundler";
2
+ import { type FunctionUploadTarget, type NaroClient } from "@next-deploy/sdk";
3
+ export declare const PER_FUNCTION_CODES: ReadonlySet<string>;
4
+ export interface DeploySteps {
5
+ bundle: typeof bundleFunction;
6
+ boot: typeof bootCheck;
7
+ }
8
+ export interface DeployFunctionsOptions {
9
+ client: NaroClient;
10
+ projectId: string;
11
+ /** Where relative --root, --dir and --import-map start. */
12
+ cwd: string;
13
+ root?: string | undefined;
14
+ dir?: string | undefined;
15
+ /** Empty or absent: every function in the folder. */
16
+ names?: readonly string[] | undefined;
17
+ /**
18
+ * Wins over function.json either way: the CLI's `--no-verify-jwt` passes
19
+ * false, naro-mcp's `verifyJwt` passes what it was given — true is never
20
+ * dropped for function.json's false (PR #353 review).
21
+ */
22
+ verifyJwt?: boolean | undefined;
23
+ importMap?: string | undefined;
24
+ skipCheck?: boolean | undefined;
25
+ cliVersion?: string | undefined;
26
+ /**
27
+ * Tries after FUNCTIONS_RATE_LIMITED (3 by default, up to 300 s each).
28
+ * naro-mcp passes 0: one tool call must end within two minutes (plan Q6),
29
+ * so it hands the error and its retryAfter back instead (final review A-M4).
30
+ */
31
+ rateLimitRetries?: number | undefined;
32
+ /** Tries after FUNCTION_BUSY (3 by default, 5 s each); naro-mcp passes 0. */
33
+ busyRetries?: number | undefined;
34
+ /**
35
+ * The whole run's limit — naro-mcp passes 120 s, so one tool call ends
36
+ * within about two minutes after the bundle (plan Q6, PR #353 review). The
37
+ * secrets list, the boot check, making the version, the PUT and the deploy
38
+ * each get only what is left (never more than their own limit), and none
39
+ * starts once it is reached. Absent: each step's own limit, as for the CLI.
40
+ */
41
+ deadlineMs?: number | undefined;
42
+ /** Tests move the clock; `Date.now` by default. */
43
+ now?: (() => number) | undefined;
44
+ log?: ((line: string) => void) | undefined;
45
+ /** The presigned PUT's fetch; the global one by default. */
46
+ fetch?: typeof fetch | undefined;
47
+ sleep?: ((ms: number) => Promise<void>) | undefined;
48
+ /** Tests stand in for esbuild and workerd. */
49
+ steps?: DeploySteps | undefined;
50
+ /** `process.versions.node` by default. */
51
+ nodeVersion?: string | undefined;
52
+ }
53
+ export interface DeployedFunction {
54
+ name: string;
55
+ version: number | null;
56
+ url: string;
57
+ verifyJwt: boolean;
58
+ }
59
+ export interface DeployFunctionsResult {
60
+ deployed: DeployedFunction[];
61
+ }
62
+ export declare function assertFunctionsNode(version?: string): void;
63
+ /**
64
+ * The presigned PUT's time limit: as long as the URL still works (60 seconds
65
+ * at least) plus 30 seconds, so a hung connection ends instead of waiting
66
+ * for the OS; 15 minutes when the answer has no usable `expiresAt`.
67
+ */
68
+ export declare function uploadTimeoutMs(upload: FunctionUploadTarget, now?: number): number;
69
+ export declare const deadlineReached: (name: string, deadlineMs: number) => string;
70
+ export declare function deployFunctions(options: DeployFunctionsOptions): Promise<DeployFunctionsResult>;
@@ -0,0 +1,16 @@
1
+ import { type NaroError } from "@next-deploy/sdk";
2
+ export declare const FUNCTION_RETRIES = 3;
3
+ export declare const FUNCTION_BUSY_WAIT_MS = 5000;
4
+ export declare const FUNCTION_RATE_LIMIT_DEFAULT_SECONDS = 60;
5
+ export declare const FUNCTION_RATE_LIMIT_MAX_SECONDS = 300;
6
+ export declare function defaultSleep(ms: number): Promise<void>;
7
+ /** `details.retryAfter` rounded up, at most 300; 60 when it is missing. */
8
+ export declare function retryAfterSeconds(error: NaroError): number;
9
+ export declare function withFunctionRetries<T>(op: () => Promise<T>, name: string, io: {
10
+ sleep: (ms: number) => Promise<void>;
11
+ log: (line: string) => void;
12
+ /** Tries after FUNCTIONS_RATE_LIMITED: 3 by default; naro-mcp passes 0. */
13
+ rateLimitRetries?: number | undefined;
14
+ /** Tries after FUNCTION_BUSY: 3 by default; naro-mcp passes 0. */
15
+ busyRetries?: number | undefined;
16
+ }): Promise<T>;