naro-cli 0.23.0 → 0.25.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.
- package/README.md +83 -18
- package/dist/args.d.ts +49 -0
- package/dist/{chunk-ALK4VTL2.js → chunk-R4XGSZQL.js} +1268 -513
- package/dist/chunk-X5TUBMEU.js +35536 -0
- package/dist/commands/confirm.d.ts +10 -0
- package/dist/commands/db-lint.d.ts +16 -0
- package/dist/deploy.d.ts +2 -0
- package/dist/deploy.js +5 -1
- package/dist/env-services.d.ts +44 -0
- package/dist/functions/read-capped.d.ts +1 -0
- package/dist/index.js +8901 -7750
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -23,6 +23,13 @@ asks before opening a dotenv file to fill what is missing. Decline and it
|
|
|
23
23
|
prints the `naro env add` commands instead. With `--yes`, `--json` or outside
|
|
24
24
|
a TTY it never asks — it just lists what is missing and deploys.
|
|
25
25
|
|
|
26
|
+
When those names give away a service you are already running, the deploy says
|
|
27
|
+
so instead of leaving you with a list of names. An app that talks to an
|
|
28
|
+
existing Supabase project prints `Supabase — in that project's dashboard:` and
|
|
29
|
+
the screen each missing value is on, so moving the app here is a copy from one
|
|
30
|
+
tab to another. Naro never calls Supabase: the values arrive like any other
|
|
31
|
+
env var, from `.env.local` once you agree or from `naro env add`.
|
|
32
|
+
|
|
26
33
|
Values you register are encrypted at rest, and `naro env pull` /
|
|
27
34
|
`naro env list --reveal` can read them back — your account credentials are
|
|
28
35
|
effectively your env credentials.
|
|
@@ -95,6 +102,8 @@ naro env remove DATABASE_URL The production, preview and all values; an en
|
|
|
95
102
|
naro env pull [.env.local] Preview's values by default; --env production, or --env qa for an environment
|
|
96
103
|
(its own value wins over all; an unknown name fails before anything is written,
|
|
97
104
|
and so does a value no dotenv line reads back)
|
|
105
|
+
naro supabase [list] The project's Supabase links, per target (connect in the dashboard)
|
|
106
|
+
naro supabase disconnect [target] Remove a target's link, or (no target or all) every link your role may change, with its env vars (asks first)
|
|
98
107
|
naro env import .env.qa qa Upload every variable in a dotenv file to one target (all by default; asks first,
|
|
99
108
|
--yes in CI; an unclosed quote, an invalid key, ASSETS or a value over 5 KB
|
|
100
109
|
stops it before any request, and so does a key a storage binding already uses
|
|
@@ -248,7 +257,7 @@ naro rollback [deployment-id] Back to the previous production build
|
|
|
248
257
|
|
|
249
258
|
`naro domains list` reads the stored status; `naro domains verify` is the one
|
|
250
259
|
that asks the DNS and Cloudflare again — and registers the domain on the spot
|
|
251
|
-
once its CNAME points at
|
|
260
|
+
once its CNAME points at Naro — so it is what turns a stuck "pending" into the
|
|
252
261
|
reason it is stuck. It exits non-zero while a domain is not live —
|
|
253
262
|
with or without `--wait` — so CI can gate on it:
|
|
254
263
|
|
|
@@ -271,7 +280,7 @@ The check lasts 7 days. `naro domains list` shows open checks with their
|
|
|
271
280
|
expiry, and adding the domain again prints the same token.
|
|
272
281
|
|
|
273
282
|
`naro db dump` asks Cloudflare for the dump and streams it straight from
|
|
274
|
-
Cloudflare's storage to the file — the bytes never pass through
|
|
283
|
+
Cloudflare's storage to the file — the bytes never pass through Naro. While the
|
|
275
284
|
export runs, Cloudflare holds every other query to the database, so dump a busy
|
|
276
285
|
production database when a short pause is acceptable. It ends with the bookmark
|
|
277
286
|
the dump reflects; `naro db restore --bookmark <that>` brings the database back
|
|
@@ -330,13 +339,13 @@ naro db lint --strict --json || exit 1
|
|
|
330
339
|
|
|
331
340
|
`db lint` changes nothing, but it needs **write** access to the database, not
|
|
332
341
|
read: its two checks (`foreign_key_check`, `quick_check`) are whole-database
|
|
333
|
-
scans, and
|
|
342
|
+
scans, and Naro classifies those as writes on purpose so a read-only role
|
|
334
343
|
cannot start them. That is also the cost warning — both walk every row that
|
|
335
344
|
has a foreign key, and `quick_check` walks the file, so on a large database
|
|
336
345
|
the lint is billed rows-read and can run into the 30-second query limit. Run
|
|
337
346
|
it in CI on a branch's own data, not on a busy production database.
|
|
338
347
|
|
|
339
|
-
`naro db table` and `naro db index` change the schema without SQL.
|
|
348
|
+
`naro db table` and `naro db index` change the schema without SQL. Naro
|
|
340
349
|
renders the DDL from checked input — every name quoted, types and defaults
|
|
341
350
|
from a fixed list — and applies it as one migration, recorded in
|
|
342
351
|
`d1_migrations` and written to `./migrations` as `NNNN_schema_<op>_<table>.sql`,
|
|
@@ -385,7 +394,7 @@ reads `members`. The command names each policy the change breaks and why;
|
|
|
385
394
|
|
|
386
395
|
SQLite cannot add a PRIMARY KEY, UNIQUE or NOT-NULL-without-default column, or
|
|
387
396
|
drop a primary key, a unique or indexed column, or a table another table
|
|
388
|
-
references;
|
|
397
|
+
references; Naro refuses those before it tries and says why. It also reads the
|
|
389
398
|
SQL of your triggers and views, and refuses to drop or rename a table or
|
|
390
399
|
column one of them uses (it warns when the SQL leaves that open) — drop or
|
|
391
400
|
recreate the trigger or view with a migration first. Changing a
|
|
@@ -436,7 +445,7 @@ are unchanged.
|
|
|
436
445
|
`naro backend` is the project's Naro backend: its own D1, email and password
|
|
437
446
|
sign-in, and a Data API that browser code calls through `naro-js` at the
|
|
438
447
|
project's URL. It is off until you turn it on, one project at a time:
|
|
439
|
-
`naro backend enable` (or the
|
|
448
|
+
`naro backend enable` (or Turn on in the Backend section of the project's Settings page in the dashboard). The anon key
|
|
440
449
|
is public — it identifies the project and grants nothing. The service key
|
|
441
450
|
skips every policy, so the CLI prints it only for
|
|
442
451
|
`naro backend keys --reveal` and for a rotation that made a new one; keep it
|
|
@@ -477,7 +486,7 @@ message that the worker may still expect the new key — run
|
|
|
477
486
|
`naro backend enable`; the CLI prints that hint (JSON `hint`) and exits 1.
|
|
478
487
|
For a few seconds during a rotation the worker can already refuse the old key.
|
|
479
488
|
|
|
480
|
-
Sign-in is
|
|
489
|
+
Sign-in is Naro Auth, the project's own (like Supabase Auth). Email and
|
|
481
490
|
password sign-up and sign-in work as soon as the backend is on, with nothing
|
|
482
491
|
to set up. `naro backend auth` adds the rest with the project's own
|
|
483
492
|
accounts — Naro runs no shared sender. Sending email (confirmation and
|
|
@@ -600,7 +609,7 @@ EXISTS` skips a missing table too, as in Postgres); `COMMENT ON POLICY p ON t
|
|
|
600
609
|
IS 'naro:owner <column>'`, which makes `p` the owner rule `naro policy set
|
|
601
610
|
--owner` writes (any other comment is ignored); and `ALTER TABLE t ENABLE |
|
|
602
611
|
FORCE | NO FORCE ROW LEVEL SECURITY`, which changes nothing because
|
|
603
|
-
row-level security is always on. Before anything runs,
|
|
612
|
+
row-level security is always on. Before anything runs, Naro refuses these with
|
|
604
613
|
`400 VALIDATION_FAILED` "Statement <i> of <n>: …":
|
|
605
614
|
|
|
606
615
|
- `ALTER TABLE … DISABLE ROW LEVEL SECURITY` — it is always on; to let
|
|
@@ -616,7 +625,7 @@ has no schema "public": write the table name without "public."`
|
|
|
616
625
|
or alters the policy's table or a table its subqueries read: `a later
|
|
617
626
|
statement changes a table, so name the table of every column inside this
|
|
618
627
|
policy's subqueries (for example members.user_id).` Postgres decides whose
|
|
619
|
-
column it is when the policy is created;
|
|
628
|
+
column it is when the policy is created; Naro binds it once the file is in,
|
|
620
629
|
when the later statement may have added that name to the subquery's table.
|
|
621
630
|
A later statement that changes only other tables — the next table of a file
|
|
622
631
|
grouped table by table — leaves the policy alone.
|
|
@@ -767,7 +776,7 @@ to write — as text, `'true'` would read as false. So is comparing text with
|
|
|
767
776
|
`IS DISTINCT FROM`, also through `coalesce` — since the text `'true'` is not
|
|
768
777
|
`TRUE`: `<> false` would hold for everyone.
|
|
769
778
|
|
|
770
|
-
Where
|
|
779
|
+
Where Naro differs from Postgres: no policy for a command is a 403, not zero
|
|
771
780
|
rows; row-level security is always on; roles are only `anon` and
|
|
772
781
|
`authenticated`, with no `security definer` functions; comparisons follow
|
|
773
782
|
SQLite (column affinity and collation), and `lower`, `upper` and `ILIKE` fold
|
|
@@ -877,6 +886,62 @@ An `--update-check` you give replaces the default: without
|
|
|
877
886
|
|
|
878
887
|
## Release notes
|
|
879
888
|
|
|
889
|
+
### 0.25.0
|
|
890
|
+
|
|
891
|
+
Everything the dashboard does, the CLI now does too, except what needs a
|
|
892
|
+
browser or your own folder (the capability registry in
|
|
893
|
+
`packages/core/src/capabilities.ts` says which and why).
|
|
894
|
+
|
|
895
|
+
- Teams: `naro teams`, `naro team create | set | delete`, `naro team members`
|
|
896
|
+
(`set`, `remove`) and `naro team invites` (`create`, `revoke`). Deleting a
|
|
897
|
+
team asks you to type its slug, or `--team` with `--yes` in CI.
|
|
898
|
+
- Projects: `naro project set` (name, subdomain), `naro project check
|
|
899
|
+
<subdomain>`, `naro project access` (`grant`, `revoke`) and `naro project
|
|
900
|
+
delete`, which asks you to type the project's name (`--yes` only with
|
|
901
|
+
`--project`).
|
|
902
|
+
- The edge: `naro firewall` (`add`, `enable`, `disable`, `remove`), `naro flags`
|
|
903
|
+
(`add`, `on`, `off`, `remove`) and `naro bindings` (`add`, `remove` — removing
|
|
904
|
+
deletes the R2 bucket, KV namespace or D1 database with its data, and asks).
|
|
905
|
+
- DNS: `naro dns` with `add`, `remove`, `check`, `mail`, `scan`, `import` and
|
|
906
|
+
`records` (`add`, `update`, `remove`).
|
|
907
|
+
- Readouts: `naro billing` and `naro observability`. `naro deployments create`
|
|
908
|
+
deploys a branch from Git (`--prod` for production; `--env production` is
|
|
909
|
+
refused).
|
|
910
|
+
- Data: `naro storage sign` (a download link without a key), `naro functions
|
|
911
|
+
update --verify-jwt <on|off>`, `naro functions invoke` (method, `--data`,
|
|
912
|
+
the first 64 KiB of the answer, 120 seconds), `naro policy rules` and
|
|
913
|
+
`naro backend signing-key rotate`.
|
|
914
|
+
- `naro supabase [list]` shows the Supabase project the dashboard connected
|
|
915
|
+
per target; `naro supabase disconnect [target]` removes a link with the env
|
|
916
|
+
vars it set (asks first). With no target, or `all`, it removes every link
|
|
917
|
+
your role may change and names the ones it could not.
|
|
918
|
+
- naro-mcp 0.24.0 goes out with it: tools for teams, DNS, the firewall, flags,
|
|
919
|
+
bindings, the backend and its sign-in settings, Realtime, Storage bucket
|
|
920
|
+
details, upload URLs and moves, policies and policy rules, `lint_database`,
|
|
921
|
+
`pull_database_schema`, billing, Observability, `check_promotion`,
|
|
922
|
+
`deploy_from_git` and the Supabase links. Destructive tools say so in their
|
|
923
|
+
description and set `destructiveHint`; tools that answer text someone else
|
|
924
|
+
typed wrap it as untrusted. It imports from this release, so publish
|
|
925
|
+
naro-cli first.
|
|
926
|
+
|
|
927
|
+
### 0.24.0
|
|
928
|
+
|
|
929
|
+
- `naro deploy` names the service behind the env vars it is missing. Names that
|
|
930
|
+
are `SUPABASE_*` under any framework prefix (`NEXT_PUBLIC_`, `VITE_`,
|
|
931
|
+
`EXPO_PUBLIC_`, …) print `Supabase — in that project's dashboard:` beneath
|
|
932
|
+
the missing-keys line, then only the screens a missing value is actually on —
|
|
933
|
+
`the project URL — the Connect dialog at the top of the page` for a name
|
|
934
|
+
ending `_URL`, `the keys — Settings > API Keys` for one ending `_KEY`. A
|
|
935
|
+
`SUPABASE_*` name neither screen holds (`SUPABASE_ACCESS_TOKEN` is made on
|
|
936
|
+
the account, not in a project; `SUPABASE_DB_PASSWORD`, `SUPABASE_PROJECT_REF`
|
|
937
|
+
and `SUPABASE_JWT_SECRET` are elsewhere) gets no hint at all rather than a
|
|
938
|
+
screen it is not on. When other keys are missing too the line names only the
|
|
939
|
+
ones it placed. Nothing is sent to Supabase and no token is stored; the
|
|
940
|
+
values still come from `.env.local` with your consent or from
|
|
941
|
+
`naro env add`.
|
|
942
|
+
- `naro realtime [status]` ends with the project's month of Realtime, across its environments: `This month (UTC, all environments): <n> messages · est. $<x.xx>`, or `This month (UTC): not metered yet` before the meter's first run (and from a control plane older than this). When an operator caps the project's monthly messages it adds `⚠ This project has used <p>% of its monthly realtime message limit (<limit>).` from 80%, and `⚠ This project has used its realtime messages for this month. Realtime resumes on the 1st at 00:00 UTC.` once new connections are refused. `--json` carries the same as `realtime.usage`.
|
|
943
|
+
- naro-mcp 0.23.0 goes out with it (no tool changes).
|
|
944
|
+
|
|
880
945
|
### 0.23.0
|
|
881
946
|
|
|
882
947
|
0.22.0 went out on 2026-10-31 without these.
|
|
@@ -895,7 +960,7 @@ An `--update-check` you give replaces the default: without
|
|
|
895
960
|
- `naro deploy --env <name>` builds with the values the control plane
|
|
896
961
|
chose for the environment, over the ones it sent (named environments 3d).
|
|
897
962
|
The control plane saves what the deploy sends for that environment first,
|
|
898
|
-
so the two differ only where
|
|
963
|
+
so the two differ only where Naro sets a name itself: for a project with a
|
|
899
964
|
Naro backend, an environment's build gets `NARO_URL`,
|
|
900
965
|
`NEXT_PUBLIC_NARO_URL`, `VITE_NARO_URL`, `PUBLIC_NARO_URL` and the four
|
|
901
966
|
`…_NARO_ANON_KEY` names set to that environment's own address and anon key.
|
|
@@ -931,7 +996,7 @@ An `--update-check` you give replaces the default: without
|
|
|
931
996
|
`naro environments delete` now says it removes the environment's data too.
|
|
932
997
|
- `naro deploy --env <name>` no longer asks for `NARO_URL`,
|
|
933
998
|
`NEXT_PUBLIC_NARO_URL`, `VITE_NARO_URL`, `PUBLIC_NARO_URL` or the four
|
|
934
|
-
`…_NARO_ANON_KEY` names when the project has a Naro backend:
|
|
999
|
+
`…_NARO_ANON_KEY` names when the project has a Naro backend: Naro sets them
|
|
935
1000
|
for the environment over any value, so a typed one only lost. It reads the
|
|
936
1001
|
project's backend once, and only when one of those names is missing
|
|
937
1002
|
(`▸ naro sets … for qa to its own backend's: not asked for`); a role that
|
|
@@ -1566,7 +1631,7 @@ RENAME` the way the control plane now reads it: a column rename whose
|
|
|
1566
1631
|
and `Next.js <version> is too old to deploy. Naro deploys Next.js 15 or newer. Upgrade to Next.js 16.`
|
|
1567
1632
|
- A Next.js app built with vinext reads its bindings with
|
|
1568
1633
|
`getCloudflareContext().env`, as under OpenNext. Before, `env` was missing
|
|
1569
|
-
there, so `env.MY_BUCKET` was `undefined` and nothing was thrown.
|
|
1634
|
+
there, so `env.MY_BUCKET` was `undefined` and nothing was thrown. Naro
|
|
1570
1635
|
writes this Worker entry as `naro-worker.js`, so a project with its own
|
|
1571
1636
|
file of that name is not built with vinext.
|
|
1572
1637
|
- Build logs hide more secrets: upper-case names that end in `TOKEN`,
|
|
@@ -1592,7 +1657,7 @@ RENAME` the way the control plane now reads it: a column rename whose
|
|
|
1592
1657
|
|
|
1593
1658
|
### 0.17.0
|
|
1594
1659
|
|
|
1595
|
-
- `naro domains add` prints one CNAME record and no TXT records.
|
|
1660
|
+
- `naro domains add` prints one CNAME record and no TXT records. Naro
|
|
1596
1661
|
registers the domain once the CNAME points at it, usually within about five
|
|
1597
1662
|
minutes. The status line reads `Waiting for DNS — add the CNAME above; naro
|
|
1598
1663
|
connects it within about five minutes.` `naro domains verify` registers it at
|
|
@@ -1700,10 +1765,10 @@ server.`), and the CLI prints that message. Before, the CLI got a 500.
|
|
|
1700
1765
|
and preview together (one switch, so `--env` is refused there).
|
|
1701
1766
|
- `naro protection` shows whether the project's preview URL is protected and
|
|
1702
1767
|
whether a bypass secret is set. Protection is on by default: only members
|
|
1703
|
-
of the project can open `<name>-preview.naro.sh`, after signing in to
|
|
1768
|
+
of the project can open `<name>-preview.naro.sh`, after signing in to Naro.
|
|
1704
1769
|
A GET or HEAD that is a page navigation (`Sec-Fetch-Mode: navigate`), or that
|
|
1705
1770
|
sends no `Sec-Fetch-Mode` and an `Accept` including `text/html`, is
|
|
1706
|
-
redirected to the
|
|
1771
|
+
redirected to the Naro sign-in; every other request gets
|
|
1707
1772
|
`401 PREVIEW_PROTECTED`. A request the browser sends without cookies (a
|
|
1708
1773
|
`<link rel="manifest">` without `crossorigin="use-credentials"`) gets 401
|
|
1709
1774
|
too.
|
|
@@ -1720,7 +1785,7 @@ server.`), and the CLI prints that message. Before, the CLI got a 500.
|
|
|
1720
1785
|
(public or private, the largest file, the types taken), and `ls`, `cp`
|
|
1721
1786
|
and `rm` work on `naro://<bucket>/<path>` with the project's service key
|
|
1722
1787
|
(`NARO_SERVICE_KEY`, or fetched with a warning) — the bytes go to the
|
|
1723
|
-
project's backend, not through
|
|
1788
|
+
project's backend, not through Naro. One request carries 50 MiB at most; a
|
|
1724
1789
|
larger file goes in parts since 0.16.0 (under 4 GiB).
|
|
1725
1790
|
`bucket update --public`, `empty`, `remove` and `rm` ask first; without a
|
|
1726
1791
|
terminal they need `--yes` (`CONFIRMATION_REQUIRED` otherwise, nothing
|
|
@@ -1759,7 +1824,7 @@ server.`), and the CLI prints that message. Before, the CLI got a 500.
|
|
|
1759
1824
|
INT, REAL, FLOA, DOUB, NUM, DEC, BOOL or BIT (a form's `"true"` for a
|
|
1760
1825
|
BOOLEAN, `"high"` for an INTEGER), even when no policy reads the column.
|
|
1761
1826
|
The backend worker takes this on at the project's next deploy or
|
|
1762
|
-
`naro backend enable`, not when
|
|
1827
|
+
`naro backend enable`, not when Naro itself updates. Before that, look for
|
|
1763
1828
|
such rows: `naro db query "select count(*) from t where typeof(c) = 'text'"`
|
|
1764
1829
|
for each number or boolean column — a count above 0 means a client writes
|
|
1765
1830
|
strings there and needs fixing first.
|
package/dist/args.d.ts
CHANGED
|
@@ -1,4 +1,53 @@
|
|
|
1
1
|
export interface GlobalFlags {
|
|
2
|
+
/**
|
|
3
|
+
* `naro dns records add|update`: the record's fields, passed as typed — the
|
|
4
|
+
* control plane checks them (apps/web/src/lib/dns-records.ts). CAA takes
|
|
5
|
+
* `--caa-flags --tag --value`, SRV `--priority --weight --port --target`.
|
|
6
|
+
*/
|
|
7
|
+
content?: string | undefined;
|
|
8
|
+
ttl?: string | undefined;
|
|
9
|
+
priority?: string | undefined;
|
|
10
|
+
caaFlags?: string | undefined;
|
|
11
|
+
tag?: string | undefined;
|
|
12
|
+
value?: string | undefined;
|
|
13
|
+
weight?: string | undefined;
|
|
14
|
+
port?: string | undefined;
|
|
15
|
+
target?: string | undefined;
|
|
16
|
+
/** `naro team set --slug <new-slug>`: the team's new slug. */
|
|
17
|
+
slug?: string | undefined;
|
|
18
|
+
/** `naro team members set <user-id> --role <role>`; the server checks it. */
|
|
19
|
+
role?: string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* `naro firewall add --kind <ip|country|path|rate_limit> --value <value>`;
|
|
22
|
+
* a rate limit also takes `--rate-limit <n> --period <seconds>`. Strings, as
|
|
23
|
+
* typed: the control plane checks them (apps/web/src/lib/firewall-input.ts).
|
|
24
|
+
*/
|
|
25
|
+
kind?: string | undefined;
|
|
26
|
+
rateLimit?: string | undefined;
|
|
27
|
+
period?: string | undefined;
|
|
28
|
+
/** `naro firewall add --disabled`: save the rule switched off. */
|
|
29
|
+
disabled?: boolean | undefined;
|
|
30
|
+
/** `naro flags add <name> --on`: the new flag starts on. */
|
|
31
|
+
on?: boolean | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* `naro project set`: the General settings, as typed — the control plane
|
|
34
|
+
* checks them. An empty value clears the setting back to the preset.
|
|
35
|
+
*/
|
|
36
|
+
subdomain?: string | undefined;
|
|
37
|
+
framework?: string | undefined;
|
|
38
|
+
buildCommand?: string | undefined;
|
|
39
|
+
outputDir?: string | undefined;
|
|
40
|
+
/** `naro project set --vinext on|off`. */
|
|
41
|
+
vinext?: string | undefined;
|
|
42
|
+
/** `naro storage sign --expires <seconds>`: 1-3600, an hour by default. */
|
|
43
|
+
expires?: string | undefined;
|
|
44
|
+
/** `naro storage sign --download`: the browser saves the file. */
|
|
45
|
+
download?: boolean | undefined;
|
|
46
|
+
/** `naro functions update <name> --verify-jwt on|off`. */
|
|
47
|
+
verifyJwt?: string | undefined;
|
|
48
|
+
/** `naro functions invoke <name> --method <M> --data <body>`. */
|
|
49
|
+
method?: string | undefined;
|
|
50
|
+
data?: string | undefined;
|
|
2
51
|
json: boolean;
|
|
3
52
|
yes: boolean;
|
|
4
53
|
debug: boolean;
|