naro-cli 0.23.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.
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.
@@ -877,6 +884,24 @@ An `--update-check` you give replaces the default: without
877
884
 
878
885
  ## Release notes
879
886
 
887
+ ### 0.24.0
888
+
889
+ - `naro deploy` names the service behind the env vars it is missing. Names that
890
+ are `SUPABASE_*` under any framework prefix (`NEXT_PUBLIC_`, `VITE_`,
891
+ `EXPO_PUBLIC_`, …) print `Supabase — in that project's dashboard:` beneath
892
+ the missing-keys line, then only the screens a missing value is actually on —
893
+ `the project URL — the Connect dialog at the top of the page` for a name
894
+ ending `_URL`, `the keys — Settings > API Keys` for one ending `_KEY`. A
895
+ `SUPABASE_*` name neither screen holds (`SUPABASE_ACCESS_TOKEN` is made on
896
+ the account, not in a project; `SUPABASE_DB_PASSWORD`, `SUPABASE_PROJECT_REF`
897
+ and `SUPABASE_JWT_SECRET` are elsewhere) gets no hint at all rather than a
898
+ screen it is not on. When other keys are missing too the line names only the
899
+ ones it placed. Nothing is sent to Supabase and no token is stored; the
900
+ values still come from `.env.local` with your consent or from
901
+ `naro env add`.
902
+ - `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`.
903
+ - naro-mcp 0.23.0 goes out with it (no tool changes).
904
+
880
905
  ### 0.23.0
881
906
 
882
907
  0.22.0 went out on 2026-10-31 without these.
@@ -320,6 +320,33 @@ var PHASES = [
320
320
  ];
321
321
  var ACTIVE_STATUSES = new Set(PHASES);
322
322
 
323
+ // ../../packages/core/src/dotenv.ts
324
+ var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/dgm;
325
+ var QUOTES = /* @__PURE__ */ new Set(["'", '"', "`"]);
326
+ function parseDotenvDetailed(text3) {
327
+ const vars = {};
328
+ const unclosedQuotes = [];
329
+ const lines = text3.replace(/\r\n?/g, "\n");
330
+ let line = 1;
331
+ let counted = 0;
332
+ for (const match of lines.matchAll(LINE)) {
333
+ const key = match[1];
334
+ const raw = match[2] ?? "";
335
+ let value = raw.trim();
336
+ const maybeQuote = value[0];
337
+ if (maybeQuote !== void 0 && QUOTES.has(maybeQuote) && !value.includes(maybeQuote, 1)) {
338
+ const at = (match.indices?.[2]?.[0] ?? match.index) + (raw.length - raw.trimStart().length);
339
+ for (; counted < at; counted += 1) if (lines[counted] === "\n") line += 1;
340
+ unclosedQuotes.push(line);
341
+ }
342
+ value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
343
+ if (maybeQuote === '"')
344
+ value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r");
345
+ vars[key] = value;
346
+ }
347
+ return { vars, unclosedQuotes };
348
+ }
349
+
323
350
  // ../../packages/core/src/deployment-stall.ts
324
351
  var STALL_WINDOW_MS = 10 * 6e4;
325
352
 
@@ -15223,13 +15250,22 @@ var RESERVED_SUBDOMAINS = [
15223
15250
  "www"
15224
15251
  ];
15225
15252
  var BACKEND_WORKER_NAME_PREFIX = "naro-backend-";
15253
+ var AUTH_WORKER_NAME_PREFIX = "naro-auth-";
15254
+ var DATA_WORKER_NAME_PREFIX = "naro-data-";
15255
+ var NARO_WORKER_NAME_PREFIXES = [
15256
+ BACKEND_WORKER_NAME_PREFIX,
15257
+ AUTH_WORKER_NAME_PREFIX,
15258
+ DATA_WORKER_NAME_PREFIX
15259
+ ];
15226
15260
  var SUBDOMAIN_PATTERN = /^[a-z0-9](-?[a-z0-9])*$/;
15227
15261
  var SUBDOMAIN_MAX_LENGTH = 54;
15228
15262
  function subdomainProblem(value) {
15229
15263
  if (value.length < 1 || value.length > SUBDOMAIN_MAX_LENGTH) return "invalid";
15230
15264
  if (!SUBDOMAIN_PATTERN.test(value)) return "invalid";
15231
15265
  if (value.endsWith("-preview")) return "reserved";
15232
- if (value === BACKEND_WORKER_NAME_PREFIX.slice(0, -1) || value.startsWith(BACKEND_WORKER_NAME_PREFIX))
15266
+ if (NARO_WORKER_NAME_PREFIXES.some(
15267
+ (prefix) => value === prefix.slice(0, -1) || value.startsWith(prefix)
15268
+ ))
15233
15269
  return "reserved";
15234
15270
  if (value === FUNCTION_WORKER_NAME_PREFIX.slice(0, -1) || value.startsWith(FUNCTION_WORKER_NAME_PREFIX))
15235
15271
  return "reserved";
@@ -21316,6 +21352,23 @@ var BackendApi = class {
21316
21352
  );
21317
21353
  return { backend, key };
21318
21354
  }
21355
+ /**
21356
+ * Replaces the access JWT's signing key (design 2026-11-01). Signing moves
21357
+ * to the new key at once; tokens the old keys signed keep working until
21358
+ * `previousKeysExpireAt` (their own 15 minutes), so nobody is signed out.
21359
+ * The API keys and the sessions are untouched. A worker uploaded before
21360
+ * this answers `BACKEND_OUTDATED` — `enable` updates it.
21361
+ */
21362
+ async rotateSigningKey(projectId) {
21363
+ return this.client.request(
21364
+ this.path(projectId, "/signing-key/rotate"),
21365
+ {
21366
+ method: "POST",
21367
+ body: {},
21368
+ context: "Rotate signing key"
21369
+ }
21370
+ );
21371
+ }
21319
21372
  /**
21320
21373
  * The sign-in settings (spec P2-6 §12): email, Google and GitHub, the
21321
21374
  * allowed redirect origins, whether sign-in waits for a confirmed email,
@@ -22162,31 +22215,7 @@ function summarizeStatement(statement2) {
22162
22215
  // ../../packages/sdk/src/dotenv.ts
22163
22216
  import { existsSync, readFileSync as readFileSync2 } from "fs";
22164
22217
  import { join as join20 } from "path";
22165
- var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/dgm;
22166
- var QUOTES = /* @__PURE__ */ new Set(["'", '"', "`"]);
22167
- function parseDotenvDetailed(text3) {
22168
- const vars = {};
22169
- const unclosedQuotes = [];
22170
- const lines = text3.replace(/\r\n?/g, "\n");
22171
- let line = 1;
22172
- let counted = 0;
22173
- for (const match of lines.matchAll(LINE)) {
22174
- const key = match[1];
22175
- const raw = match[2] ?? "";
22176
- let value = raw.trim();
22177
- const maybeQuote = value[0];
22178
- if (maybeQuote !== void 0 && QUOTES.has(maybeQuote) && !value.includes(maybeQuote, 1)) {
22179
- const at = (match.indices?.[2]?.[0] ?? match.index) + (raw.length - raw.trimStart().length);
22180
- for (; counted < at; counted += 1) if (lines[counted] === "\n") line += 1;
22181
- unclosedQuotes.push(line);
22182
- }
22183
- value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2");
22184
- if (maybeQuote === '"')
22185
- value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r");
22186
- vars[key] = value;
22187
- }
22188
- return { vars, unclosedQuotes };
22189
- }
22218
+ var QUOTES2 = /* @__PURE__ */ new Set(["'", '"', "`"]);
22190
22219
  function parseDotenv(text3) {
22191
22220
  return parseDotenvDetailed(text3).vars;
22192
22221
  }
@@ -22199,7 +22228,7 @@ function readProjectEnv(dir) {
22199
22228
  }
22200
22229
  var PLAIN = /^[^\s"'#$`\\]*$/;
22201
22230
  function bareReadsBack(value) {
22202
- return !/[#\r\n\u2028\u2029]/.test(value) && value.trim() === value && !QUOTES.has(value[0] ?? "");
22231
+ return !/[#\r\n\u2028\u2029]/.test(value) && value.trim() === value && !QUOTES2.has(value[0] ?? "");
22203
22232
  }
22204
22233
  function dotenvValue(value) {
22205
22234
  if (PLAIN.test(value)) return value;
@@ -32031,6 +32060,43 @@ async function promptForMissingEnv(ctx, keys) {
32031
32060
  return collected;
32032
32061
  }
32033
32062
 
32063
+ // src/env-services.ts
32064
+ var PUBLIC_PREFIXES = [
32065
+ "NEXT_PUBLIC_",
32066
+ "NUXT_PUBLIC_",
32067
+ "EXPO_PUBLIC_",
32068
+ "REACT_APP_",
32069
+ "PUBLIC_",
32070
+ "GATSBY_",
32071
+ "VITE_"
32072
+ ];
32073
+ function bareEnvKey(key) {
32074
+ let longest = "";
32075
+ for (const prefix of PUBLIC_PREFIXES)
32076
+ if (key.startsWith(prefix) && prefix.length > longest.length)
32077
+ longest = prefix;
32078
+ return key.slice(longest.length);
32079
+ }
32080
+ function supabaseKeys(keys) {
32081
+ return keys.filter((key) => bareEnvKey(key).startsWith("SUPABASE_"));
32082
+ }
32083
+ function envServiceHints(keys) {
32084
+ const own2 = supabaseKeys(keys);
32085
+ const isUrl = (key) => bareEnvKey(key).endsWith("_URL");
32086
+ const isKey = (key) => bareEnvKey(key).endsWith("_KEY");
32087
+ const placed = own2.filter((key) => isUrl(key) || isKey(key));
32088
+ if (placed.length === 0) return [];
32089
+ const lines = [
32090
+ placed.length === keys.length ? " Supabase \u2014 in that project's dashboard:" : ` Supabase (${placed.join(", ")}) \u2014 in that project's dashboard:`
32091
+ ];
32092
+ if (placed.some(isUrl))
32093
+ lines.push(
32094
+ " the project URL \u2014 the Connect dialog at the top of the page"
32095
+ );
32096
+ if (placed.some(isKey)) lines.push(" the keys \u2014 Settings > API Keys");
32097
+ return lines;
32098
+ }
32099
+
32034
32100
  // src/env-surface.ts
32035
32101
  function pullEnv(rows, surface) {
32036
32102
  const chosen = /* @__PURE__ */ new Map();
@@ -34500,6 +34566,7 @@ async function deployDirectory(sourceDir, options, log2) {
34500
34566
  log2(
34501
34567
  `\u25B8 ${String(missing.length)} env var(s) needed, not set on this project: ${missing.join(", ")}`
34502
34568
  );
34569
+ for (const line of envServiceHints(missing)) log2(line);
34503
34570
  const canCollect = environment === void 0 || options.projectId;
34504
34571
  if (options.onMissingEnv && canCollect)
34505
34572
  collected = await options.onMissingEnv(missing);
@@ -34640,6 +34707,7 @@ function deploymentUrl(detail, ctx, production) {
34640
34707
  }
34641
34708
 
34642
34709
  export {
34710
+ parseDotenvDetailed,
34643
34711
  isFunctionName,
34644
34712
  parseGitHubRemote,
34645
34713
  schemaMigrationTitle,
@@ -34678,7 +34746,6 @@ export {
34678
34746
  cellText,
34679
34747
  renderRows,
34680
34748
  summarizeStatement,
34681
- parseDotenvDetailed,
34682
34749
  serializeDotenv,
34683
34750
  systemTablePredicate,
34684
34751
  MAX_SINGLE_UPLOAD_BYTES,
package/dist/deploy.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readProjectEnv,
10
10
  slugify,
11
11
  workingTreeNotices
12
- } from "./chunk-ALK4VTL2.js";
12
+ } from "./chunk-XJIWWZ2T.js";
13
13
  import "./chunk-K3NQKI34.js";
14
14
  export {
15
15
  assertFunctionsNode,
@@ -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[];
package/dist/index.js CHANGED
@@ -128,7 +128,7 @@ import {
128
128
  warningLines,
129
129
  withFunctionRetries,
130
130
  writeProjectLink
131
- } from "./chunk-ALK4VTL2.js";
131
+ } from "./chunk-XJIWWZ2T.js";
132
132
  import "./chunk-K3NQKI34.js";
133
133
 
134
134
  // src/args.ts
@@ -1244,6 +1244,23 @@ async function runBackendKeysRotate(context) {
1244
1244
  ]
1245
1245
  );
1246
1246
  }
1247
+ async function runBackendSigningKeyRotate(context) {
1248
+ const client = await dataClient(context);
1249
+ const environment = dataEnvironment(context.flags);
1250
+ const projectId = await context.resolveProjectId();
1251
+ await confirmOrAbort(
1252
+ context,
1253
+ "Replace the key that signs access tokens? New tokens are signed with the new key at once; tokens already issued keep working until they expire (up to 15 minutes). Nobody is signed out."
1254
+ );
1255
+ const rotated = await client.backend.rotateSigningKey(projectId);
1256
+ context.output.result(
1257
+ { projectId, ...rotated },
1258
+ [
1259
+ `\u2705 Replaced the signing key (kid ${rotated.kid}).`,
1260
+ `Tokens signed with the old key work until ${rotated.previousKeysExpireAt}.`
1261
+ ].map((line) => forEnvironment(line, environment))
1262
+ );
1263
+ }
1247
1264
 
1248
1265
  // src/commands/backend-auth.ts
1249
1266
  var processStdin = {
@@ -6234,6 +6251,21 @@ function tableName(table3) {
6234
6251
  function linesFor(lines, environment) {
6235
6252
  return lines.map((line) => forEnvironment(line, environment));
6236
6253
  }
6254
+ function usageLines2(usage) {
6255
+ if (usage === null) return ["This month (UTC): not metered yet"];
6256
+ const lines = [
6257
+ `This month (UTC, all environments): ${number(usage.messages)} messages \xB7 est. $${usage.estCostUsd.toFixed(2)}`
6258
+ ];
6259
+ if (usage.blocked)
6260
+ lines.push(
6261
+ "\u26A0 This project has used its realtime messages for this month. Realtime resumes on the 1st at 00:00 UTC."
6262
+ );
6263
+ else if (usage.messageLimit !== null && usage.messages >= Math.ceil(usage.messageLimit * 0.8))
6264
+ lines.push(
6265
+ `\u26A0 This project has used ${String(Math.floor(usage.messages * 100 / usage.messageLimit))}% of its monthly realtime message limit (${number(usage.messageLimit)}).`
6266
+ );
6267
+ return lines;
6268
+ }
6237
6269
  function realtimeLines(info) {
6238
6270
  if (!info.enabled)
6239
6271
  return [
@@ -6244,7 +6276,9 @@ function realtimeLines(info) {
6244
6276
  return [
6245
6277
  "Realtime: on (public channels: off)",
6246
6278
  info.tables.length === 0 ? "Published tables: none \u2014 naro realtime tables add <table>" : `Published tables: ${info.tables.map(tableName).join(", ")}`,
6247
- live2 === null ? "Connections now: not known \u2014 the backend is off or not ready, or the hub did not answer" : `Connections now: ${number(live2.connections)} \xB7 channels ${number(live2.channels)} \xB7 presences ${number(live2.presences)}`
6279
+ live2 === null ? "Connections now: not known \u2014 the backend is off or not ready, or the hub did not answer" : `Connections now: ${number(live2.connections)} \xB7 channels ${number(live2.channels)} \xB7 presences ${number(live2.presences)}`,
6280
+ // A control plane older than 3-2e sends no `usage`.
6281
+ ...usageLines2(info.usage ?? null)
6248
6282
  ];
6249
6283
  }
6250
6284
  async function enableRealtime(client, projectId, environment) {
@@ -7422,6 +7456,9 @@ var RETRY_AFTER_CODES = /* @__PURE__ */ new Set([
7422
7456
  "STORAGE_OPS_QUOTA_EXCEEDED",
7423
7457
  // Realtime's REST broadcast over the project's message budget (x-retry-after: 1).
7424
7458
  "TOO_MANY_MESSAGES",
7459
+ // The dispatcher's REST 429 of a project over its month of Realtime (3-2e):
7460
+ // `x-retry-after` is the seconds to the 1st at 00:00 UTC.
7461
+ "REALTIME_QUOTA_EXCEEDED",
7425
7462
  // Naro Functions (design F20): a team over its monthly function CPU, and
7426
7463
  // the control plane's Cloudflare limit. `invoke` reads x-retry-after on
7427
7464
  // every relay error anyway (invoke/client.ts).
@@ -9343,6 +9380,7 @@ var TableBuilder = class {
9343
9380
  var BACKOFF_STEPS_MS = [1e3, 2e3, 5e3, 1e4];
9344
9381
  var RATE_LIMITED_MIN_MS = 5e3;
9345
9382
  var IP_LIMIT_WAIT_MS = 6e4;
9383
+ var QUOTA_WAIT_MS = 9e5;
9346
9384
  var RESTART_JITTER_MS = 1e4;
9347
9385
  var UNOPENED_SLOWDOWN_AFTER = 6;
9348
9386
  var UNOPENED_DELAY_MS = 6e4;
@@ -9359,7 +9397,7 @@ function closeAction(code, reason) {
9359
9397
  if (code === 4401) return { kind: "session" };
9360
9398
  if (code === 4503) return { kind: "restart" };
9361
9399
  if (code === 4029)
9362
- return reason === "IP_RATE_LIMITED" ? { kind: "wait", ms: IP_LIMIT_WAIT_MS } : { kind: "retry", minMs: RATE_LIMITED_MIN_MS };
9400
+ return reason === "IP_RATE_LIMITED" ? { kind: "wait", ms: IP_LIMIT_WAIT_MS } : reason === "REALTIME_QUOTA_EXCEEDED" ? { kind: "wait", ms: QUOTA_WAIT_MS } : { kind: "retry", minMs: RATE_LIMITED_MIN_MS };
9363
9401
  return { kind: "retry", minMs: 0 };
9364
9402
  }
9365
9403
  function backoffMs(attempt22, random) {
@@ -13131,7 +13169,7 @@ function projectName(project) {
13131
13169
  return `Moved to another team ${printable(project.projectId)}`;
13132
13170
  return printable(project.name ?? project.projectId);
13133
13171
  }
13134
- function usageLines2(report, summary) {
13172
+ function usageLines3(report, summary) {
13135
13173
  const lines = [
13136
13174
  `${printable(report.team.slug)} \xB7 ${planName(report.team.plan)} plan \xB7 ${printable(report.month)} (UTC)`
13137
13175
  ];
@@ -13178,7 +13216,7 @@ async function runUsage(context) {
13178
13216
  month !== void 0 ? { month } : {}
13179
13217
  );
13180
13218
  const summary = summarizeTeamUsage(report, usageMonthOf(/* @__PURE__ */ new Date()));
13181
- context.output.result({ ...report, summary }, usageLines2(report, summary));
13219
+ context.output.result({ ...report, summary }, usageLines3(report, summary));
13182
13220
  }
13183
13221
 
13184
13222
  // src/router.ts
@@ -13303,6 +13341,8 @@ Usage:
13303
13341
  naro backend keys [--reveal] API keys; --reveal prints the service key (a secret; needs database write)
13304
13342
  naro backend keys rotate --anon|--service
13305
13343
  Replace a key; the old one stops working at once (asks first)
13344
+ naro backend signing-key rotate Replace the key that signs access tokens (if it may have leaked);
13345
+ tokens already issued keep working up to 15 minutes (asks first)
13306
13346
  naro backend auth Sign-in settings: email, Google, GitHub, redirects, callback URLs,
13307
13347
  sign-ups and the minimum password length
13308
13348
  naro backend auth signups <on|off>
@@ -14032,6 +14072,13 @@ function routeCommand(parsed) {
14032
14072
  positionals: positionals.slice(2)
14033
14073
  };
14034
14074
  return null;
14075
+ case "signing-key":
14076
+ if (positionals[1] === "rotate")
14077
+ return {
14078
+ handler: runBackendSigningKeyRotate,
14079
+ positionals: positionals.slice(2)
14080
+ };
14081
+ return null;
14035
14082
  case "auth":
14036
14083
  return routeBackendAuth(positionals.slice(1));
14037
14084
  case "users":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naro-cli",
3
- "version": "0.23.0",
3
+ "version": "0.24.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.0",
41
- "@next-deploy/config": "0.1.0",
42
40
  "@next-deploy/core": "0.1.0",
43
41
  "@next-deploy/build": "0.1.0",
44
42
  "@next-deploy/data-core": "0.1.0",
43
+ "naro-js": "0.7.1",
44
+ "@next-deploy/functions-bundler": "0.1.0",
45
45
  "@next-deploy/functions-runtime": "0.1.0",
46
46
  "@next-deploy/sdk": "0.1.0",
47
- "@next-deploy/functions-bundler": "0.1.0"
47
+ "@next-deploy/config": "0.1.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsup && pnpm build:types",