@mybase-dev/cli 1.0.7 → 1.0.8
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/mybase.js +166 -17
- package/package.json +1 -1
package/dist/mybase.js
CHANGED
|
@@ -116,6 +116,7 @@ var KEY_RESOURCES = [
|
|
|
116
116
|
{ id: "vector", name: "Vector search", description: "Indexes, documents, and queries (read), and changing them (write)" },
|
|
117
117
|
{ id: "users", name: "Users", description: "Your app's users and sessions (read), revoking and deleting them, and sending sign-in events (write)" },
|
|
118
118
|
{ id: "captcha", name: "Captcha", description: "Captcha settings (read), and verifying tokens (write)" },
|
|
119
|
+
{ id: "realtime", name: "Realtime", description: "Channels, members, and settings (read), and publishing messages (write)" },
|
|
119
120
|
{ id: "audit", name: "Audit log", description: "Who did what: sign-ins, key and project changes, secret reads (read only)" }
|
|
120
121
|
];
|
|
121
122
|
function parseDotenv(text) {
|
|
@@ -139,7 +140,7 @@ function parseDotenv(text) {
|
|
|
139
140
|
// package.json
|
|
140
141
|
var package_default = {
|
|
141
142
|
name: "@mybase-dev/cli",
|
|
142
|
-
version: "1.0.
|
|
143
|
+
version: "1.0.8",
|
|
143
144
|
description: "The mybase CLI: projects, keys, cron, queues, cache, rate limits, analytics, docs, and agent setup for a self-hosted mybase.",
|
|
144
145
|
type: "module",
|
|
145
146
|
repository: {
|
|
@@ -652,6 +653,9 @@ function contextMarkdown(c) {
|
|
|
652
653
|
}
|
|
653
654
|
if (c.captcha)
|
|
654
655
|
out.push("## Captcha", "", `Script: ${c.captcha.scriptUrl} (data-project="${c.project}"). Check tokens with \`createCaptchaClient\` (\`captcha:write\` key) or Better Auth's captcha plugin via \`mybaseCaptcha()\`.`, "");
|
|
656
|
+
if (c.realtime) {
|
|
657
|
+
out.push("## Realtime", "", `Browsers: \`connectRealtime({ apiUrl, project: "${c.project}", token })\` (socket ${c.realtime.socketUrl}) with tokens your server signs via \`createRealtimeToken(MYBASE_REALTIME_SECRET, \u2026)\`. Publish from the server: POST ${c.realtime.publishUrl} (\`realtime:write\` key, \`createRealtimeClient\`).`, "");
|
|
658
|
+
}
|
|
655
659
|
if (c.analytics)
|
|
656
660
|
out.push("## Analytics", "", `Public write key \`${c.analytics.writeKey}\`, script ${c.analytics.scriptUrl}`, "");
|
|
657
661
|
out.push("## Env vars", "", ...c.env.map((e) => `- \`${e.name}\`: ${e.description}`), "");
|
|
@@ -2077,6 +2081,145 @@ async function sync4(file, dryRun) {
|
|
|
2077
2081
|
printSync(config.project, dryRun, await api(`${base6(config.project)}/rules`, { method: "PUT", body: JSON.stringify(body) }));
|
|
2078
2082
|
}
|
|
2079
2083
|
|
|
2084
|
+
// src/realtime.ts
|
|
2085
|
+
var realtimeUsage = ` realtime enable <project> Turn on realtime and print the socket URL and secret
|
|
2086
|
+
realtime info <project> Settings, connections, and messages in the last 24 hours
|
|
2087
|
+
realtime key <project> [--rotate] Show (or replace) the secret that signs browser tokens and webhooks
|
|
2088
|
+
(rotating closes every open connection)
|
|
2089
|
+
realtime settings <project> [--origins a,b|none] [--public on|off] [--webhook <url>|none]
|
|
2090
|
+
[--events message,presence,channel] [--max-connections n]
|
|
2091
|
+
[--max-channels n] [--max-message-bytes n] [--max-rate n]
|
|
2092
|
+
realtime channels <project> [--prefix p] Channels with subscribers right now
|
|
2093
|
+
realtime publish <project> <channel> <event> [json] Send a message to everyone subscribed
|
|
2094
|
+
realtime disable <project> [--yes] Turn it off (closes every connection)`;
|
|
2095
|
+
var base7 = (project) => `/projects/${encodeURIComponent(project)}/realtime`;
|
|
2096
|
+
function printSettings3(s) {
|
|
2097
|
+
console.log(` socket ${s.socketUrl} (connectRealtime in @mybase-dev/sdk/realtime)`);
|
|
2098
|
+
console.log(` publish POST ${s.publishUrl} (realtime:write key)`);
|
|
2099
|
+
console.log(` secret ${s.secret} (server-side only: MYBASE_REALTIME_SECRET)`);
|
|
2100
|
+
console.log(` public ${s.publicChannels ? "on: public:\u2026 channels need no token" : "off: every connection needs a token"}`);
|
|
2101
|
+
console.log(` origins ${s.allowedOrigins.length ? s.allowedOrigins.join(", ") : "any"}`);
|
|
2102
|
+
console.log(` webhook ${s.webhookUrl ? `${s.webhookUrl} (${s.webhookEvents.join(", ") || "no events"})` : "none"}`);
|
|
2103
|
+
console.log(` limits ${s.maxConnections} connections, ${s.maxChannels} channels each, ${s.maxMessageBytes} B frames, ${s.maxRate}/s`);
|
|
2104
|
+
}
|
|
2105
|
+
var list2 = (value) => value === "none" ? [] : value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
2106
|
+
function onOff(value, name) {
|
|
2107
|
+
if (value === undefined)
|
|
2108
|
+
return;
|
|
2109
|
+
if (value === "on" || value === "off")
|
|
2110
|
+
return value === "on";
|
|
2111
|
+
throw usageError(`--${name} takes on or off`);
|
|
2112
|
+
}
|
|
2113
|
+
async function realtime(sub, args) {
|
|
2114
|
+
const { positional, flags } = parseArgs(args);
|
|
2115
|
+
const [project, channel, event, data] = positional;
|
|
2116
|
+
switch (sub) {
|
|
2117
|
+
case "enable": {
|
|
2118
|
+
const p = need(project, "project name");
|
|
2119
|
+
const { linked } = await enableService(p, "realtime", flags);
|
|
2120
|
+
const s = await api(base7(p));
|
|
2121
|
+
print({ enabled: "realtime", project: p, linked, ...s }, () => {
|
|
2122
|
+
console.log(`Realtime enabled for "${p}"
|
|
2123
|
+
`);
|
|
2124
|
+
printSettings3(s);
|
|
2125
|
+
printLinked(p, linked, flags);
|
|
2126
|
+
});
|
|
2127
|
+
return true;
|
|
2128
|
+
}
|
|
2129
|
+
case "info": {
|
|
2130
|
+
const p = need(project, "project name");
|
|
2131
|
+
const [s, stats] = await Promise.all([api(base7(p)), api(`${base7(p)}/stats`)]);
|
|
2132
|
+
const { secret: _secret, ...settings } = s;
|
|
2133
|
+
print({ ...settings, stats }, () => {
|
|
2134
|
+
printSettings3({ ...s, secret: "(mybase realtime key)" });
|
|
2135
|
+
const out = stats.hours.reduce((n, h) => n + h.messagesOut, 0);
|
|
2136
|
+
console.log(`
|
|
2137
|
+
now ${stats.connections} connections (peak ${stats.peakConnections}), ${stats.channels} channels`);
|
|
2138
|
+
console.log(` 24 hours ${out} messages delivered`);
|
|
2139
|
+
if (stats.webhook.lastError)
|
|
2140
|
+
console.log(` webhook failing: ${stats.webhook.lastError} (${stats.webhook.queued} queued, ${stats.webhook.dropped} dropped)`);
|
|
2141
|
+
});
|
|
2142
|
+
return true;
|
|
2143
|
+
}
|
|
2144
|
+
case "key": {
|
|
2145
|
+
const p = need(project, "project name");
|
|
2146
|
+
if (flags.has("rotate"))
|
|
2147
|
+
confirm(args.includes("--yes"), `Every open realtime connection on "${p}" closes, and tokens signed with the old secret stop working.`, p, "the project name");
|
|
2148
|
+
const s = flags.has("rotate") ? await api(`${base7(p)}/secret/rotate`, { method: "POST" }) : await api(base7(p));
|
|
2149
|
+
print({ secret: s.secret }, () => {
|
|
2150
|
+
if (flags.has("rotate"))
|
|
2151
|
+
console.log(`Rotated. Update MYBASE_REALTIME_SECRET where your server signs tokens.
|
|
2152
|
+
`);
|
|
2153
|
+
console.log(s.secret);
|
|
2154
|
+
});
|
|
2155
|
+
return true;
|
|
2156
|
+
}
|
|
2157
|
+
case "settings": {
|
|
2158
|
+
const p = need(project, "project name");
|
|
2159
|
+
const body = {};
|
|
2160
|
+
const origins = flagString(flags, "origins");
|
|
2161
|
+
if (origins !== undefined)
|
|
2162
|
+
body.allowedOrigins = list2(origins);
|
|
2163
|
+
const pub = onOff(flagString(flags, "public"), "public");
|
|
2164
|
+
if (pub !== undefined)
|
|
2165
|
+
body.publicChannels = pub;
|
|
2166
|
+
const webhook = flagString(flags, "webhook");
|
|
2167
|
+
if (webhook !== undefined)
|
|
2168
|
+
body.webhookUrl = webhook === "none" ? null : webhook;
|
|
2169
|
+
const events = flagString(flags, "events");
|
|
2170
|
+
if (events !== undefined)
|
|
2171
|
+
body.webhookEvents = list2(events);
|
|
2172
|
+
const ints = { maxConnections: "max-connections", maxChannels: "max-channels", maxMessageBytes: "max-message-bytes", maxRate: "max-rate" };
|
|
2173
|
+
for (const [key, flag] of Object.entries(ints)) {
|
|
2174
|
+
const n = flagInt(flags, flag);
|
|
2175
|
+
if (n !== undefined)
|
|
2176
|
+
body[key] = n;
|
|
2177
|
+
}
|
|
2178
|
+
const s = Object.keys(body).length ? await api(base7(p), { method: "PATCH", body: JSON.stringify(body) }) : await api(base7(p));
|
|
2179
|
+
const { secret: _secret, ...shown } = s;
|
|
2180
|
+
print(shown, () => printSettings3({ ...s, secret: "(mybase realtime key)" }));
|
|
2181
|
+
return true;
|
|
2182
|
+
}
|
|
2183
|
+
case "channels": {
|
|
2184
|
+
const p = need(project, "project name");
|
|
2185
|
+
const prefix = flagString(flags, "prefix");
|
|
2186
|
+
const { channels } = await api(`${base7(p)}/channels${prefix ? `?prefix=${encodeURIComponent(prefix)}` : ""}`);
|
|
2187
|
+
print(channels, () => {
|
|
2188
|
+
if (!channels.length)
|
|
2189
|
+
return console.log("No channels have subscribers right now.");
|
|
2190
|
+
for (const c of channels)
|
|
2191
|
+
console.log(`${c.channel} ${c.subscribers} subscribers${c.members === undefined ? "" : `, ${c.members} members`}`);
|
|
2192
|
+
});
|
|
2193
|
+
return true;
|
|
2194
|
+
}
|
|
2195
|
+
case "publish": {
|
|
2196
|
+
const p = need(project, "project name");
|
|
2197
|
+
let payload = null;
|
|
2198
|
+
if (data !== undefined) {
|
|
2199
|
+
try {
|
|
2200
|
+
payload = JSON.parse(data);
|
|
2201
|
+
} catch {
|
|
2202
|
+
payload = data;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
const { ids } = await api(`${base7(p)}/publish`, {
|
|
2206
|
+
method: "POST",
|
|
2207
|
+
body: JSON.stringify({ channel: need(channel, "channel"), event: need(event, "event"), data: payload })
|
|
2208
|
+
});
|
|
2209
|
+
print({ id: ids[0] }, () => console.log(`Published ${event} to ${channel}`));
|
|
2210
|
+
return true;
|
|
2211
|
+
}
|
|
2212
|
+
case "disable": {
|
|
2213
|
+
const p = need(project, "project name");
|
|
2214
|
+
confirm(args.includes("--yes"), `Every open realtime connection on "${p}" closes, and pages listening for updates stop getting them.`, p, "the project name");
|
|
2215
|
+
await api(`/projects/${encodeURIComponent(p)}/services/realtime`, { method: "DELETE" });
|
|
2216
|
+
print({ disabled: "realtime", project: p }, () => console.log(`Realtime disabled for "${p}"`));
|
|
2217
|
+
return true;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
return false;
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2080
2223
|
// src/run.ts
|
|
2081
2224
|
import { constants } from "os";
|
|
2082
2225
|
|
|
@@ -2113,8 +2256,8 @@ async function target(flags, needEnv = true) {
|
|
|
2113
2256
|
}
|
|
2114
2257
|
return { project, env: env ?? "" };
|
|
2115
2258
|
}
|
|
2116
|
-
var
|
|
2117
|
-
var envPath = (project, env, rest = "") => `${
|
|
2259
|
+
var base8 = (project) => `/projects/${encodeURIComponent(project)}/secrets`;
|
|
2260
|
+
var envPath = (project, env, rest = "") => `${base8(project)}/envs/${encodeURIComponent(env)}${rest}`;
|
|
2118
2261
|
var fetchSecrets = (project, env) => api(`/secrets/${encodeURIComponent(project)}/${encodeURIComponent(env)}`);
|
|
2119
2262
|
var describeEnv = (e) => [e.name, e.parent ? `branch of ${e.parent}` : "root", `${e.keys} keys`, `rev ${e.revision}`, e.linked ? "linked" : ""].filter(Boolean).join("\t");
|
|
2120
2263
|
async function readStdin() {
|
|
@@ -2133,7 +2276,7 @@ async function secrets(sub, args) {
|
|
|
2133
2276
|
case "enable": {
|
|
2134
2277
|
const p = need(positional[0] ?? flagString(flags, "project"), "project name");
|
|
2135
2278
|
await api(`/projects/${encodeURIComponent(p)}/services/secrets`, { method: "PUT" });
|
|
2136
|
-
const overview = await api(
|
|
2279
|
+
const overview = await api(base8(p));
|
|
2137
2280
|
print({ enabled: "secrets", project: p, ...overview }, () => {
|
|
2138
2281
|
console.log(`Secrets enabled for "${p}": ${overview.envs.map((e) => e.name).join(", ")}
|
|
2139
2282
|
`);
|
|
@@ -2153,7 +2296,7 @@ async function secrets(sub, args) {
|
|
|
2153
2296
|
}
|
|
2154
2297
|
case "setup": {
|
|
2155
2298
|
const { project, env } = await target(flags);
|
|
2156
|
-
const overview = await api(
|
|
2299
|
+
const overview = await api(base8(project));
|
|
2157
2300
|
if (!overview.envs.some((e) => e.name === env)) {
|
|
2158
2301
|
throw usageError(`"${project}" has no env "${env}" (envs: ${overview.envs.map((e) => e.name).join(", ")})`);
|
|
2159
2302
|
}
|
|
@@ -2163,7 +2306,7 @@ async function secrets(sub, args) {
|
|
|
2163
2306
|
}
|
|
2164
2307
|
case "envs": {
|
|
2165
2308
|
const { project } = await target(flags, false);
|
|
2166
|
-
const overview = await api(
|
|
2309
|
+
const overview = await api(base8(project));
|
|
2167
2310
|
print(overview.envs, () => {
|
|
2168
2311
|
for (const e of overview.envs)
|
|
2169
2312
|
console.log(describeEnv(e));
|
|
@@ -2174,7 +2317,7 @@ async function secrets(sub, args) {
|
|
|
2174
2317
|
const [action, name, next] = positional;
|
|
2175
2318
|
const { project } = await target(flags, false);
|
|
2176
2319
|
if (action === "create") {
|
|
2177
|
-
const env = await api(`${
|
|
2320
|
+
const env = await api(`${base8(project)}/envs`, {
|
|
2178
2321
|
method: "POST",
|
|
2179
2322
|
body: JSON.stringify({ name: need(name, "env name"), parent: flagString(flags, "from") ?? null })
|
|
2180
2323
|
});
|
|
@@ -2277,7 +2420,7 @@ async function secrets(sub, args) {
|
|
|
2277
2420
|
const { project, env } = await target(flags);
|
|
2278
2421
|
const envs = env.split(",").map((e) => e.trim()).filter(Boolean);
|
|
2279
2422
|
confirm(yes, `This rotates the credentials of "${project}" (database password, storage key, cache password if the cache is on, and the API key link made before) and stores the new ones, with the other services' keys, in ${envs.join(", ")} plus any env linked before. Apps still using the old credentials will stop working.`, project, "the project name");
|
|
2280
|
-
const result = await api(`${
|
|
2423
|
+
const result = await api(`${base8(project)}/link`, { method: "POST", body: JSON.stringify({ envs }) });
|
|
2281
2424
|
print(result, () => {
|
|
2282
2425
|
console.log(`Rotated and stored in ${result.envs.join(", ")}: ${result.keys.join(", ")}`);
|
|
2283
2426
|
console.log("Restart your apps with `mybase run` to pick them up.");
|
|
@@ -2287,7 +2430,7 @@ async function secrets(sub, args) {
|
|
|
2287
2430
|
case "unlink": {
|
|
2288
2431
|
const { project, env } = await target(flags);
|
|
2289
2432
|
confirm(yes, `This removes the project credentials from "${env}". They stay valid; nothing is rotated.`, env, "the env name");
|
|
2290
|
-
await api(`${
|
|
2433
|
+
await api(`${base8(project)}/link/${encodeURIComponent(env)}`, { method: "DELETE" });
|
|
2291
2434
|
print({ unlinked: env, project }, () => console.log(`Removed the credentials from "${env}"`));
|
|
2292
2435
|
return true;
|
|
2293
2436
|
}
|
|
@@ -3755,6 +3898,7 @@ var SERVICE_COLORS = {
|
|
|
3755
3898
|
alerts: color.red,
|
|
3756
3899
|
users: color.green,
|
|
3757
3900
|
captcha: color.blue,
|
|
3901
|
+
realtime: color.magenta,
|
|
3758
3902
|
"db-public": color.cyan,
|
|
3759
3903
|
dev: color.gray
|
|
3760
3904
|
};
|
|
@@ -5682,7 +5826,7 @@ var usersUsage = ` users enable <project> Turn on users: an auth schema
|
|
|
5682
5826
|
users revoke <project> <user-id> [<session-id>] Sign a user out (one session, or everywhere)
|
|
5683
5827
|
users delete <project> <user-id> [--yes] Delete a user and their sessions
|
|
5684
5828
|
users disable <project> [--yes] Turn it off, deleting every user account`;
|
|
5685
|
-
var
|
|
5829
|
+
var base9 = (project) => `/projects/${encodeURIComponent(project)}/users`;
|
|
5686
5830
|
function authSnippet(project, apiUrl) {
|
|
5687
5831
|
return `// auth.ts: npm i better-auth pg @mybase-dev/sdk
|
|
5688
5832
|
import { betterAuth } from "better-auth";
|
|
@@ -5713,7 +5857,7 @@ async function users(sub, args) {
|
|
|
5713
5857
|
case "enable": {
|
|
5714
5858
|
const p = need(project, "project name");
|
|
5715
5859
|
const { linked } = await enableService(p, "users", flags);
|
|
5716
|
-
const o = await api(
|
|
5860
|
+
const o = await api(base9(p));
|
|
5717
5861
|
print({ enabled: "users", project: p, linked, ...o }, () => {
|
|
5718
5862
|
console.log(`Users enabled for "${p}". Better Auth's tables go in the "${o.schema}" schema.
|
|
5719
5863
|
`);
|
|
@@ -5727,7 +5871,7 @@ async function users(sub, args) {
|
|
|
5727
5871
|
}
|
|
5728
5872
|
case "init": {
|
|
5729
5873
|
const p = need(project, "project name");
|
|
5730
|
-
const o = await api(
|
|
5874
|
+
const o = await api(base9(p));
|
|
5731
5875
|
const env = flagString(flags, "env");
|
|
5732
5876
|
let stored = null;
|
|
5733
5877
|
if (env) {
|
|
@@ -5750,7 +5894,7 @@ Set BETTER_AUTH_SECRET to 32+ random bytes (openssl rand -base64 32), or rerun w
|
|
|
5750
5894
|
case "list": {
|
|
5751
5895
|
const p = need(project, "project name");
|
|
5752
5896
|
const search = flagString(flags, "search");
|
|
5753
|
-
const list = await api(`${
|
|
5897
|
+
const list = await api(`${base9(p)}/accounts?limit=100${search ? `&search=${encodeURIComponent(search)}` : ""}`);
|
|
5754
5898
|
print(list, () => {
|
|
5755
5899
|
if (list.users.length === 0)
|
|
5756
5900
|
console.log(search ? "No users match." : "No users yet.");
|
|
@@ -5763,7 +5907,7 @@ Set BETTER_AUTH_SECRET to 32+ random bytes (openssl rand -base64 32), or rerun w
|
|
|
5763
5907
|
}
|
|
5764
5908
|
case "show": {
|
|
5765
5909
|
const p = need(project, "project name");
|
|
5766
|
-
const u = await api(`${
|
|
5910
|
+
const u = await api(`${base9(p)}/accounts/${encodeURIComponent(need(userId, "user id"))}`);
|
|
5767
5911
|
print(u, () => {
|
|
5768
5912
|
console.log(`${u.email ?? u.id}${u.name ? ` (${u.name})` : ""}${u.banned ? " BANNED" : ""}`);
|
|
5769
5913
|
console.log(` id ${u.id}`);
|
|
@@ -5781,10 +5925,10 @@ Active sessions (${u.sessions.length}):`);
|
|
|
5781
5925
|
const p = need(project, "project name");
|
|
5782
5926
|
const id = encodeURIComponent(need(userId, "user id"));
|
|
5783
5927
|
if (sessionId) {
|
|
5784
|
-
await api(`${
|
|
5928
|
+
await api(`${base9(p)}/accounts/${id}/sessions/${encodeURIComponent(sessionId)}`, { method: "DELETE" });
|
|
5785
5929
|
print({ revoked: 1 }, () => console.log("Signed out that session."));
|
|
5786
5930
|
} else {
|
|
5787
|
-
const r = await api(`${
|
|
5931
|
+
const r = await api(`${base9(p)}/accounts/${id}/sessions`, { method: "DELETE" });
|
|
5788
5932
|
print(r, () => console.log(`Signed out ${r.revoked} session(s).`));
|
|
5789
5933
|
}
|
|
5790
5934
|
return true;
|
|
@@ -5793,7 +5937,7 @@ Active sessions (${u.sessions.length}):`);
|
|
|
5793
5937
|
const p = need(project, "project name");
|
|
5794
5938
|
const id = need(userId, "user id");
|
|
5795
5939
|
confirm(args.includes("--yes"), `This deletes user ${id} of "${p}" and signs them out.`, id, "the user id");
|
|
5796
|
-
await api(`${
|
|
5940
|
+
await api(`${base9(p)}/accounts/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
5797
5941
|
print({ deleted: id }, () => console.log(`Deleted user ${id}`));
|
|
5798
5942
|
return true;
|
|
5799
5943
|
}
|
|
@@ -5835,6 +5979,7 @@ var USAGE = {
|
|
|
5835
5979
|
vector: vectorUsage,
|
|
5836
5980
|
users: usersUsage,
|
|
5837
5981
|
captcha: captchaUsage,
|
|
5982
|
+
realtime: realtimeUsage,
|
|
5838
5983
|
run: runUsage
|
|
5839
5984
|
};
|
|
5840
5985
|
var GLOBAL_FLAGS = ` --json Print results as JSON (errors too, on stderr)
|
|
@@ -5967,6 +6112,10 @@ async function main(args) {
|
|
|
5967
6112
|
if (await captcha(sub, rest))
|
|
5968
6113
|
return;
|
|
5969
6114
|
}
|
|
6115
|
+
if (command === "realtime" && sub) {
|
|
6116
|
+
if (await realtime(sub, rest))
|
|
6117
|
+
return;
|
|
6118
|
+
}
|
|
5970
6119
|
if (command && command !== "help")
|
|
5971
6120
|
throw usageError(`unknown command: mybase ${args.filter((a) => !a.startsWith("-")).slice(0, 2).join(" ")}
|
|
5972
6121
|
|
package/package.json
CHANGED