naro-cli 0.25.0 → 0.26.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 +16 -2
- package/dist/{chunk-X5TUBMEU.js → chunk-RQJTCRKY.js} +2049 -143
- package/dist/deploy.js +1 -1
- package/dist/index.js +71 -80
- package/package.json +4 -4
- package/dist/chunk-R4XGSZQL.js +0 -35531
package/dist/deploy.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
BACKEND_STEPS,
|
|
5
5
|
BOOKMARK_FORMAT_MESSAGE,
|
|
6
6
|
BUNDLE_MESSAGES,
|
|
7
|
+
CAPABILITIES,
|
|
7
8
|
DATA_ENV_MESSAGES,
|
|
8
9
|
FUNCTION_INVOKE_MAX_RESPONSE_BYTES,
|
|
9
10
|
FUNCTION_INVOKE_METHODS,
|
|
@@ -36,6 +37,9 @@ import {
|
|
|
36
37
|
controlPlaneUrl,
|
|
37
38
|
createAuthClient,
|
|
38
39
|
createPrompter,
|
|
40
|
+
dashboardCapability,
|
|
41
|
+
dashboardLink,
|
|
42
|
+
dashboardNeeds,
|
|
39
43
|
dataClient,
|
|
40
44
|
dataEnvironment,
|
|
41
45
|
dataError,
|
|
@@ -125,7 +129,7 @@ import {
|
|
|
125
129
|
warningLines,
|
|
126
130
|
withFunctionRetries,
|
|
127
131
|
writeProjectLink
|
|
128
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-RQJTCRKY.js";
|
|
129
133
|
import "./chunk-K3NQKI34.js";
|
|
130
134
|
|
|
131
135
|
// src/args.ts
|
|
@@ -4754,7 +4758,7 @@ async function zoneNamed(context, usage) {
|
|
|
4754
4758
|
if (!zone)
|
|
4755
4759
|
throw new NaroError(
|
|
4756
4760
|
"NOT_FOUND",
|
|
4757
|
-
`${domain} is not on
|
|
4761
|
+
`${domain} is not on Naro DNS for team ${team}. \`naro dns\` lists the zones.`
|
|
4758
4762
|
);
|
|
4759
4763
|
return { client, team, zone };
|
|
4760
4764
|
}
|
|
@@ -4769,7 +4773,7 @@ async function runDns(context) {
|
|
|
4769
4773
|
const { client, team } = await teamAndClient(context);
|
|
4770
4774
|
const state = await client.dns.state(team);
|
|
4771
4775
|
context.output.result({ team, ...state }, [
|
|
4772
|
-
`
|
|
4776
|
+
`Naro DNS for ${team}${state.enabled ? "" : " (not enabled on this server)"}:`,
|
|
4773
4777
|
...state.zones.length === 0 ? [" No zones. `naro dns add <domain>` starts a move."] : state.zones.flatMap((zone) => zoneLines(zone).map((l) => ` ${l}`))
|
|
4774
4778
|
]);
|
|
4775
4779
|
}
|
|
@@ -4778,7 +4782,7 @@ async function runDnsAdd(context) {
|
|
|
4778
4782
|
const { client, team } = await teamAndClient(context);
|
|
4779
4783
|
const zone = await client.dns.addZone(team, domain);
|
|
4780
4784
|
context.output.result({ team, zone }, [
|
|
4781
|
-
`\u2705 Started moving ${zone.name} to
|
|
4785
|
+
`\u2705 Started moving ${zone.name} to Naro DNS`,
|
|
4782
4786
|
` Set these name servers at your registrar: ${zone.nameServers.join(", ")}`,
|
|
4783
4787
|
" `naro dns mail` shows the mail records to keep, `naro dns check` asks whether the move is done."
|
|
4784
4788
|
]);
|
|
@@ -4790,11 +4794,11 @@ async function runDnsRemove(context) {
|
|
|
4790
4794
|
);
|
|
4791
4795
|
await confirmOrAbort(
|
|
4792
4796
|
context,
|
|
4793
|
-
`Remove ${zone.name} from
|
|
4797
|
+
`Remove ${zone.name} from Naro DNS (${zone.status})?`
|
|
4794
4798
|
);
|
|
4795
4799
|
await client.dns.removeZone(team, zone.id);
|
|
4796
4800
|
context.output.result({ team, removed: zone.name }, [
|
|
4797
|
-
`\u2705 Removed ${zone.name} from
|
|
4801
|
+
`\u2705 Removed ${zone.name} from Naro DNS`
|
|
4798
4802
|
]);
|
|
4799
4803
|
}
|
|
4800
4804
|
async function runDnsCheck(context) {
|
|
@@ -5269,6 +5273,15 @@ async function accessJwtFor(config, jwtStore) {
|
|
|
5269
5273
|
}
|
|
5270
5274
|
return { error: invalidSession() };
|
|
5271
5275
|
}
|
|
5276
|
+
async function freshAccessJwt(config) {
|
|
5277
|
+
const jwtStore = config.accessJwt;
|
|
5278
|
+
if (jwtStore === void 0 || config.service) return;
|
|
5279
|
+
const jwt = await jwtStore.get();
|
|
5280
|
+
if (jwt === null) return;
|
|
5281
|
+
const expiry = localExpiry(config, jwt);
|
|
5282
|
+
if (expiry === null || expiry - ACCESS_JWT_MARGIN_MS > Date.now()) return;
|
|
5283
|
+
await accessJwtFor(config, jwtStore);
|
|
5284
|
+
}
|
|
5272
5285
|
async function bearerFor(config, path, withToken) {
|
|
5273
5286
|
if (!withToken) return { token: null, session: null };
|
|
5274
5287
|
const store = storeFor(config, path);
|
|
@@ -6205,6 +6218,7 @@ var AuthClient = class {
|
|
|
6205
6218
|
const renewed = tokenFrom(result.answer);
|
|
6206
6219
|
if (renewed !== null && token !== null && renewed !== token)
|
|
6207
6220
|
await tokens.replaceIf(token, renewed);
|
|
6221
|
+
await freshAccessJwt(this.#http);
|
|
6208
6222
|
return { data: { session: body.session, user }, error: null };
|
|
6209
6223
|
}
|
|
6210
6224
|
/** `{ data: { user } }`; `user` is null when signed out. */
|
|
@@ -9002,7 +9016,7 @@ var RealtimeChannel = class {
|
|
|
9002
9016
|
payload: isRecord(payload.payload) ? payload.payload : {}
|
|
9003
9017
|
};
|
|
9004
9018
|
for (const binding of this.#bindings)
|
|
9005
|
-
if (binding.type === "broadcast" && binding.event === event)
|
|
9019
|
+
if (binding.type === "broadcast" && (binding.event === event || binding.event === "*"))
|
|
9006
9020
|
safely(() => binding.callback(message));
|
|
9007
9021
|
}
|
|
9008
9022
|
#system(payload) {
|
|
@@ -11823,6 +11837,47 @@ async function runFunctionsInvoke(context) {
|
|
|
11823
11837
|
);
|
|
11824
11838
|
}
|
|
11825
11839
|
|
|
11840
|
+
// src/commands/dashboard.ts
|
|
11841
|
+
var WITH_PAGE = CAPABILITIES.filter(
|
|
11842
|
+
(capability) => typeof capability.dashboard === "string"
|
|
11843
|
+
);
|
|
11844
|
+
async function runDashboard(context) {
|
|
11845
|
+
const [id] = context.positionals;
|
|
11846
|
+
if (id === void 0) {
|
|
11847
|
+
const rows = WITH_PAGE.map((capability2) => ({
|
|
11848
|
+
capability: capability2.id,
|
|
11849
|
+
title: capability2.title,
|
|
11850
|
+
cli: capability2.cli.kind === "built" ? capability2.cli.commands ?? [] : []
|
|
11851
|
+
}));
|
|
11852
|
+
const width = Math.max(...rows.map((row) => row.capability.length));
|
|
11853
|
+
context.output.result({ capabilities: rows }, [
|
|
11854
|
+
"Pages in the dashboard (naro dashboard <capability> prints the URL):",
|
|
11855
|
+
...rows.map(
|
|
11856
|
+
(row) => ` ${row.capability.padEnd(width)} ${row.title}${row.cli.length === 0 ? " (dashboard only)" : ""}`
|
|
11857
|
+
)
|
|
11858
|
+
]);
|
|
11859
|
+
return;
|
|
11860
|
+
}
|
|
11861
|
+
const capability = dashboardCapability(id);
|
|
11862
|
+
const needs = dashboardNeeds(capability.dashboard);
|
|
11863
|
+
const client = await context.client();
|
|
11864
|
+
const target = needs.project ? { projectId: await context.resolveProjectId() } : needs.team ? {
|
|
11865
|
+
teamSlug: (await resolveTeam(context, await client.teams.list(), {
|
|
11866
|
+
intent: "read"
|
|
11867
|
+
})).slug
|
|
11868
|
+
} : {};
|
|
11869
|
+
const link = await dashboardLink(client, capability, target, {
|
|
11870
|
+
baseUrl: controlPlaneUrl(),
|
|
11871
|
+
client: "cli"
|
|
11872
|
+
});
|
|
11873
|
+
context.output.result({ link }, [
|
|
11874
|
+
link.url,
|
|
11875
|
+
` ${link.title}`,
|
|
11876
|
+
...link.reason ? [` Not in the CLI: ${link.reason.why}`] : [],
|
|
11877
|
+
...link.cli.length > 0 ? [` Or: ${link.cli.join(", ")}`] : []
|
|
11878
|
+
]);
|
|
11879
|
+
}
|
|
11880
|
+
|
|
11826
11881
|
// src/commands/readouts.ts
|
|
11827
11882
|
function money(cents) {
|
|
11828
11883
|
return `$${(cents / 100).toFixed(2)}`;
|
|
@@ -11841,7 +11896,9 @@ function billingLines(billing) {
|
|
|
11841
11896
|
...overage ? [
|
|
11842
11897
|
` overage ${overage.month}: ${money(overage.totalCents)} (requests ${money(overage.requestsCents)}, builds ${money(overage.buildsCents)}, domains ${money(overage.domainsCents)})`
|
|
11843
11898
|
] : [],
|
|
11844
|
-
...billing.canManage ? [
|
|
11899
|
+
...billing.canManage ? [
|
|
11900
|
+
" Change the plan in the dashboard: naro dashboard billing-checkout prints the page."
|
|
11901
|
+
] : []
|
|
11845
11902
|
];
|
|
11846
11903
|
}
|
|
11847
11904
|
async function runBilling(context) {
|
|
@@ -12176,61 +12233,6 @@ async function runFlagRemove(context) {
|
|
|
12176
12233
|
`\u2705 Removed flag ${flag.name}`
|
|
12177
12234
|
]);
|
|
12178
12235
|
}
|
|
12179
|
-
function bindingLine(binding) {
|
|
12180
|
-
return `${binding.bindingName.padEnd(16)} ${binding.type.padEnd(3)} ${binding.resourceName}${binding.provisioned ? "" : " (not provisioned)"}${binding.managed ? " (managed by naro)" : ""}`;
|
|
12181
|
-
}
|
|
12182
|
-
async function runBindings(context) {
|
|
12183
|
-
const { client, projectId } = await projectAndClient(context);
|
|
12184
|
-
const bindings = await client.bindings.list(projectId);
|
|
12185
|
-
context.output.result({ projectId, bindings }, [
|
|
12186
|
-
`Bindings (${String(bindings.length)}):`,
|
|
12187
|
-
...bindings.length === 0 ? [
|
|
12188
|
-
" None. `naro bindings add --type <r2|kv|d1> --name <BINDING>` creates one."
|
|
12189
|
-
] : bindings.map((binding) => ` ${bindingLine(binding)}`)
|
|
12190
|
-
]);
|
|
12191
|
-
}
|
|
12192
|
-
async function runBindingAdd(context) {
|
|
12193
|
-
const { type, name } = context.flags;
|
|
12194
|
-
if (!type || !name)
|
|
12195
|
-
throw new NaroError(
|
|
12196
|
-
"VALIDATION_FAILED",
|
|
12197
|
-
"Usage: naro bindings add --type <r2|kv|d1> --name <BINDING>"
|
|
12198
|
-
);
|
|
12199
|
-
const { client, projectId } = await projectAndClient(context);
|
|
12200
|
-
const binding = await client.bindings.add(projectId, type, name);
|
|
12201
|
-
context.output.result({ projectId, binding }, [
|
|
12202
|
-
`\u2705 Added ${bindingLine(binding)}`,
|
|
12203
|
-
" The worker sees it from the next deploy."
|
|
12204
|
-
]);
|
|
12205
|
-
}
|
|
12206
|
-
async function runBindingRemove(context) {
|
|
12207
|
-
const [name] = context.positionalOrThrow(
|
|
12208
|
-
1,
|
|
12209
|
-
"Usage: naro bindings remove <BINDING>"
|
|
12210
|
-
);
|
|
12211
|
-
const { client, projectId } = await projectAndClient(context);
|
|
12212
|
-
const binding = (await client.bindings.list(projectId)).find(
|
|
12213
|
-
(candidate) => candidate.bindingName === name
|
|
12214
|
-
);
|
|
12215
|
-
if (!binding)
|
|
12216
|
-
throw new NaroError(
|
|
12217
|
-
"NOT_FOUND",
|
|
12218
|
-
`No binding named ${name}. \`naro bindings\` lists them.`
|
|
12219
|
-
);
|
|
12220
|
-
if (binding.managed)
|
|
12221
|
-
throw new NaroError(
|
|
12222
|
-
"STORAGE_MANAGED",
|
|
12223
|
-
"The Naro database is removed when the project is deleted. Set the project's database to None to unbind it."
|
|
12224
|
-
);
|
|
12225
|
-
await confirmOrAbort(
|
|
12226
|
-
context,
|
|
12227
|
-
`Remove the binding ${binding.bindingName}? This deletes the ${binding.type} resource ${binding.resourceName} and everything in it.`
|
|
12228
|
-
);
|
|
12229
|
-
await client.bindings.remove(projectId, binding.id);
|
|
12230
|
-
context.output.result({ projectId, removed: binding.bindingName }, [
|
|
12231
|
-
`\u2705 Removed ${binding.bindingName} and its ${binding.type} resource`
|
|
12232
|
-
]);
|
|
12233
|
-
}
|
|
12234
12236
|
|
|
12235
12237
|
// src/commands/teams.ts
|
|
12236
12238
|
async function teamScope(context) {
|
|
@@ -14152,6 +14154,7 @@ Usage:
|
|
|
14152
14154
|
naro usage [--month YYYY-MM] [--team <slug>]
|
|
14153
14155
|
Team usage: requests, builds and custom domains against the plan, then by project
|
|
14154
14156
|
naro billing [--team <slug>] The team's plan, subscription and this month's overage; the plan changes in the dashboard
|
|
14157
|
+
naro dashboard [<capability>] The dashboard URL for what the CLI leaves there (payments, GitHub App, \u2026); no argument lists them
|
|
14155
14158
|
|
|
14156
14159
|
naro deploy [--prod] Build locally and deploy (preview by default)
|
|
14157
14160
|
[--root <dir>] [--name <name>] --root points at the app in a monorepo
|
|
@@ -14211,9 +14214,9 @@ Usage:
|
|
|
14211
14214
|
naro domains verify [host] [--wait] Re-check DNS and print what is missing
|
|
14212
14215
|
exits non-zero while a domain is not live yet
|
|
14213
14216
|
|
|
14214
|
-
naro dns [list] [--team <slug>]
|
|
14215
|
-
naro dns add <domain> Start moving a domain onto
|
|
14216
|
-
naro dns remove <domain> Cancel the move, or take the domain off
|
|
14217
|
+
naro dns [list] [--team <slug>] Naro DNS: the team's zones, their status and name servers
|
|
14218
|
+
naro dns add <domain> Start moving a domain onto Naro DNS; prints the name servers to set
|
|
14219
|
+
naro dns remove <domain> Cancel the move, or take the domain off Naro DNS (asks first; --yes in CI)
|
|
14217
14220
|
naro dns check <domain> Read the zone's status and ask Cloudflare whether the move is done
|
|
14218
14221
|
naro dns mail <domain> The mail records (MX, SPF, DMARC, DKIM) to keep before the move
|
|
14219
14222
|
naro dns scan <domain> The records Cloudflare found in the current DNS
|
|
@@ -14238,10 +14241,6 @@ Usage:
|
|
|
14238
14241
|
naro flags on <name> Turn a flag on; the live app follows within about a minute
|
|
14239
14242
|
naro flags off <name> Turn a flag off
|
|
14240
14243
|
naro flags remove <name> Remove a flag; code still reading it sees it off (asks first)
|
|
14241
|
-
naro bindings [list] The R2, KV and D1 resources bound to the worker
|
|
14242
|
-
naro bindings add --type <r2|kv|d1> --name <BINDING>
|
|
14243
|
-
Create a resource and bind it as env.<BINDING> from the next deploy
|
|
14244
|
-
naro bindings remove <BINDING> Delete the resource and everything in it (asks first; --yes in CI)
|
|
14245
14244
|
|
|
14246
14245
|
The data commands below (db, migration, gen, backend, policy, storage, realtime) take --env <name>:
|
|
14247
14246
|
a named environment's data instead of production's, which preview shares
|
|
@@ -14833,6 +14832,8 @@ function routeCommand(parsed) {
|
|
|
14833
14832
|
if (sub === void 0 || sub === "list")
|
|
14834
14833
|
return positionals.length <= 1 ? { handler: runSupabase, positionals: [] } : null;
|
|
14835
14834
|
return sub === "disconnect" && positionals.length <= 2 ? { handler: runSupabaseDisconnect, positionals: positionals.slice(1) } : null;
|
|
14835
|
+
case "dashboard":
|
|
14836
|
+
return positionals.length <= 1 ? { handler: runDashboard, positionals } : null;
|
|
14836
14837
|
case "billing":
|
|
14837
14838
|
return positionals.length === 0 ? { handler: runBilling, positionals: [] } : null;
|
|
14838
14839
|
case "observability":
|
|
@@ -15029,16 +15030,6 @@ function routeCommand(parsed) {
|
|
|
15029
15030
|
const command2 = commands[sub];
|
|
15030
15031
|
return command2 ? { handler: command2, positionals: positionals.slice(1) } : null;
|
|
15031
15032
|
}
|
|
15032
|
-
case "bindings": {
|
|
15033
|
-
if (sub === void 0 || sub === "list")
|
|
15034
|
-
return positionals.length <= 1 ? { handler: runBindings, positionals: [] } : null;
|
|
15035
|
-
const commands = {
|
|
15036
|
-
add: runBindingAdd,
|
|
15037
|
-
remove: runBindingRemove
|
|
15038
|
-
};
|
|
15039
|
-
const command2 = commands[sub];
|
|
15040
|
-
return command2 ? { handler: command2, positionals: positionals.slice(1) } : null;
|
|
15041
|
-
}
|
|
15042
15033
|
case "dns": {
|
|
15043
15034
|
if (sub === void 0 || sub === "list")
|
|
15044
15035
|
return positionals.length <= 1 ? { handler: runDns, positionals: [] } : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naro-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"naro": "./dist/index.js"
|
|
@@ -37,14 +37,14 @@
|
|
|
37
37
|
"tsx": "4.23.12",
|
|
38
38
|
"typescript": "7.0.2",
|
|
39
39
|
"vitest": "3.2.7",
|
|
40
|
-
"naro-js": "0.7.1",
|
|
41
40
|
"@next-deploy/build": "0.1.0",
|
|
41
|
+
"@next-deploy/data-core": "0.1.0",
|
|
42
42
|
"@next-deploy/config": "0.1.0",
|
|
43
|
-
"@next-deploy/functions-bundler": "0.1.0",
|
|
44
43
|
"@next-deploy/functions-runtime": "0.1.0",
|
|
44
|
+
"naro-js": "0.9.0",
|
|
45
45
|
"@next-deploy/sdk": "0.1.0",
|
|
46
46
|
"@next-deploy/core": "0.1.0",
|
|
47
|
-
"@next-deploy/
|
|
47
|
+
"@next-deploy/functions-bundler": "0.1.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsup && pnpm build:types",
|