@dashai/cli 0.9.0 → 0.11.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/dist/bin.js +176 -43
- package/dist/bin.js.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -543,8 +543,11 @@ function manifestJson(opts) {
|
|
|
543
543
|
owns: {
|
|
544
544
|
tables: [
|
|
545
545
|
{
|
|
546
|
+
// NOTE: no `name` key here — the backend manifest validator
|
|
547
|
+
// (POST /api/installations/dev) is strict and rejects unrecognized
|
|
548
|
+
// table keys, and it derives the display name from the slug. A
|
|
549
|
+
// `name` here would fail provisioning's table materialization (#4).
|
|
546
550
|
slug: "items",
|
|
547
|
-
name: "Items",
|
|
548
551
|
fields: [
|
|
549
552
|
{ slug: "title", type: "text" },
|
|
550
553
|
{ slug: "done", type: "boolean" }
|
|
@@ -719,10 +722,12 @@ function envLocal(apiUrl = SCAFFOLD_DEFAULT_API_URL) {
|
|
|
719
722
|
"# There is no DASHWISE_INSTALLATION_ID \u2014 the API key resolves the",
|
|
720
723
|
"# install server-side.",
|
|
721
724
|
`DASHWISE_API_URL=${apiUrl}`,
|
|
722
|
-
"# Scoped `dwk_` key.
|
|
723
|
-
"#
|
|
724
|
-
"#
|
|
725
|
-
"
|
|
725
|
+
"# Scoped `dwk_` key. Commented out on purpose: `dashwise dev` injects",
|
|
726
|
+
"# the local-dev key from ~/.config/dashwise/auth.json, and an empty",
|
|
727
|
+
"# `DASHWISE_API_KEY=` here would SHADOW that (and make a bare `next dev`",
|
|
728
|
+
"# fail with a confusing empty-key error). For a standalone `next dev`,",
|
|
729
|
+
"# uncomment + paste a key from `dashwise api-keys create <name>`.",
|
|
730
|
+
"# DASHWISE_API_KEY=",
|
|
726
731
|
""
|
|
727
732
|
].join("\n");
|
|
728
733
|
}
|
|
@@ -924,6 +929,15 @@ export default withAuth({
|
|
|
924
929
|
// redirect-loop trying to re-authenticate.
|
|
925
930
|
publicPaths: ['/', '/about', '/sign-in-error'],
|
|
926
931
|
loginPath: '/api/auth/sign-in',
|
|
932
|
+
// Silent sign-in: when a signed-in DashWise user opens the module through
|
|
933
|
+
// the platform (in-app embed or the module subdomain), the SSO handshake
|
|
934
|
+
// completes with zero clicks \u2014 they land straight in the app, landing page
|
|
935
|
+
// included. It never touches:
|
|
936
|
+
// - anonymous visitors on public installs (no platform-session hint),
|
|
937
|
+
// - local \`dashwise dev\` (no platform proxy \u2192 no hint header) \u2014 the
|
|
938
|
+
// landing's "Sign in with DashWise" button stays your dev flow,
|
|
939
|
+
// - anything within 60s of a failed silent attempt (no redirect loops).
|
|
940
|
+
autoSignIn: true,
|
|
927
941
|
});
|
|
928
942
|
|
|
929
943
|
export const config = {
|
|
@@ -965,11 +979,13 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
965
979
|
function appPageCustomTsx(opts) {
|
|
966
980
|
return `// Public landing page \u2014 listed in middleware.ts publicPaths.
|
|
967
981
|
//
|
|
968
|
-
//
|
|
969
|
-
//
|
|
970
|
-
//
|
|
971
|
-
//
|
|
972
|
-
//
|
|
982
|
+
// NOTE: signed-in DashWise users usually never see this page \u2014 the
|
|
983
|
+
// middleware's \`autoSignIn\` signs them in silently and they land on the
|
|
984
|
+
// page they asked for. This landing serves anonymous visitors (public
|
|
985
|
+
// installs), local \`dashwise dev\`, and the rare failed silent attempt \u2014
|
|
986
|
+
// its "Sign in with DashWise" button is the manual fallback that kicks
|
|
987
|
+
// off the same SSO flow (via /api/auth/sign-in). After signing in, the
|
|
988
|
+
// user lands on /dashboard (Server Component, session-validated).
|
|
973
989
|
//
|
|
974
990
|
// Styling: shadcn/ui primitives (\`<Button>\`, \`<Card>\`) on Tailwind 4
|
|
975
991
|
// theme tokens. Add more blocks via \`npx shadcn add @shadcn-studio/...\`
|
|
@@ -1185,6 +1201,11 @@ import { getPublicOrigin } from '@/lib/request-origin';
|
|
|
1185
1201
|
export async function GET(request: Request) {
|
|
1186
1202
|
const url = new URL(request.url);
|
|
1187
1203
|
const returnTo = url.searchParams.get('return_to') ?? '/';
|
|
1204
|
+
// \`auto=1\` marks a SILENT attempt (the middleware's autoSignIn redirect,
|
|
1205
|
+
// no user click). Its failures degrade to the public landing page \u2014 where
|
|
1206
|
+
// the manual "Sign in with DashWise" button lives \u2014 instead of the error
|
|
1207
|
+
// page: the user never asked for anything, so don't show them an error.
|
|
1208
|
+
const isAuto = url.searchParams.get('auto') === '1';
|
|
1188
1209
|
const apiBaseUrl = process.env.DASHWISE_API_URL;
|
|
1189
1210
|
const apiKey = process.env.DASHWISE_API_KEY;
|
|
1190
1211
|
|
|
@@ -1211,6 +1232,16 @@ export async function GET(request: Request) {
|
|
|
1211
1232
|
const callback = new URL('/api/auth/callback', moduleOrigin);
|
|
1212
1233
|
callback.searchParams.set('return_to', returnTo);
|
|
1213
1234
|
|
|
1235
|
+
// Where a failed start lands: the error page for user-initiated sign-ins,
|
|
1236
|
+
// the landing page for silent (auto) attempts.
|
|
1237
|
+
const failTarget = (code: string, description?: string): URL => {
|
|
1238
|
+
if (isAuto) return new URL('/', moduleOrigin);
|
|
1239
|
+
const target = new URL('/sign-in-error', moduleOrigin);
|
|
1240
|
+
target.searchParams.set('code', code);
|
|
1241
|
+
if (description) target.searchParams.set('description', description);
|
|
1242
|
+
return target;
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1214
1245
|
let res: Response;
|
|
1215
1246
|
try {
|
|
1216
1247
|
res = await fetch(\`\${apiBaseUrl}/api/module-api/sso/start-url\`, {
|
|
@@ -1223,10 +1254,9 @@ export async function GET(request: Request) {
|
|
|
1223
1254
|
body: JSON.stringify({ callback_url: callback.toString() }),
|
|
1224
1255
|
});
|
|
1225
1256
|
} catch (err) {
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
return NextResponse.redirect(target);
|
|
1257
|
+
return NextResponse.redirect(
|
|
1258
|
+
failTarget('server_error', (err as Error).message),
|
|
1259
|
+
);
|
|
1230
1260
|
}
|
|
1231
1261
|
|
|
1232
1262
|
if (!res.ok) {
|
|
@@ -1236,23 +1266,18 @@ export async function GET(request: Request) {
|
|
|
1236
1266
|
const body = (await res.json().catch(() => null)) as
|
|
1237
1267
|
| { code?: string; message?: string }
|
|
1238
1268
|
| null;
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
return NextResponse.redirect(target);
|
|
1269
|
+
return NextResponse.redirect(
|
|
1270
|
+
failTarget(body?.code ?? 'invalid_request', body?.message),
|
|
1271
|
+
);
|
|
1243
1272
|
}
|
|
1244
1273
|
|
|
1245
1274
|
const body = (await res.json().catch(() => null)) as
|
|
1246
1275
|
| { redirect_url?: string }
|
|
1247
1276
|
| null;
|
|
1248
1277
|
if (!body?.redirect_url) {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
target.searchParams.set(
|
|
1252
|
-
'description',
|
|
1253
|
-
'start-url response missing redirect_url',
|
|
1278
|
+
return NextResponse.redirect(
|
|
1279
|
+
failTarget('server_error', 'start-url response missing redirect_url'),
|
|
1254
1280
|
);
|
|
1255
|
-
return NextResponse.redirect(target);
|
|
1256
1281
|
}
|
|
1257
1282
|
return NextResponse.redirect(body.redirect_url);
|
|
1258
1283
|
}
|
|
@@ -1288,7 +1313,13 @@ export async function GET(request: Request) {
|
|
|
1288
1313
|
return NextResponse.redirect(target);
|
|
1289
1314
|
}
|
|
1290
1315
|
const code = url.searchParams.get('code');
|
|
1291
|
-
|
|
1316
|
+
// Only ever redirect to a ROOT-RELATIVE, same-module path. \`return_to\`
|
|
1317
|
+
// rides through the SSO round-trip unvalidated (the backend checks only the
|
|
1318
|
+
// callback ORIGIN, not this sub-param), so an absolute (\`https://evil\`),
|
|
1319
|
+
// protocol-relative (\`//evil\`), or control-char-smuggled value would be a
|
|
1320
|
+
// post-auth open redirect off the module host. Reject anything that isn't a
|
|
1321
|
+
// clean root-relative path.
|
|
1322
|
+
const returnTo = safeReturnTo(url.searchParams.get('return_to'));
|
|
1292
1323
|
if (!code) {
|
|
1293
1324
|
const target = new URL('/sign-in-error', publicOrigin);
|
|
1294
1325
|
target.searchParams.set('code', 'missing_code');
|
|
@@ -1304,6 +1335,20 @@ export async function GET(request: Request) {
|
|
|
1304
1335
|
}
|
|
1305
1336
|
return NextResponse.redirect(new URL(returnTo, publicOrigin));
|
|
1306
1337
|
}
|
|
1338
|
+
|
|
1339
|
+
/** Root-relative in-module paths only \u2014 defends against open-redirect via
|
|
1340
|
+
* a crafted \`return_to\`. Rejects absolute/protocol-relative/backslash and
|
|
1341
|
+
* any ASCII control char (which WHATWG URL parsing strips, defeating a naive
|
|
1342
|
+
* prefix check). Falls back to '/'. */
|
|
1343
|
+
function safeReturnTo(raw: string | null): string {
|
|
1344
|
+
if (!raw || raw[0] !== '/') return '/';
|
|
1345
|
+
if (raw.startsWith('//') || raw.startsWith('/\\\\')) return '/';
|
|
1346
|
+
for (let i = 0; i < raw.length; i++) {
|
|
1347
|
+
const c = raw.charCodeAt(i);
|
|
1348
|
+
if (c < 0x20 || c === 0x7f) return '/';
|
|
1349
|
+
}
|
|
1350
|
+
return raw;
|
|
1351
|
+
}
|
|
1307
1352
|
`;
|
|
1308
1353
|
}
|
|
1309
1354
|
function appApiAuthSignOutTs() {
|
|
@@ -1919,6 +1964,29 @@ cached in \`~/.config/dashwise/auth.json#modules[${opts.slug}]\` after
|
|
|
1919
1964
|
as \`DASHWISE_API_KEY\` into the Next.js child env automatically. The
|
|
1920
1965
|
key binds the install server-side \u2014 there is no \`DASHWISE_INSTALLATION_ID\`.
|
|
1921
1966
|
|
|
1967
|
+
### Own tables vs. the shared Data Hub
|
|
1968
|
+
|
|
1969
|
+
The dev key \`dashwise init\` mints gives you **full access to your
|
|
1970
|
+
module's OWN tables** (\`owns.tables\` in \`module.json\`) through \`db\` /
|
|
1971
|
+
\`qb\` \u2014 no grant setup needed. That covers the common case.
|
|
1972
|
+
|
|
1973
|
+
The **shared workspace Data Hub** (other tables in the workspace, reached
|
|
1974
|
+
via \`datahub.table(<id>)\`) is separate: it is default-deny and returns
|
|
1975
|
+
**403** with the dev key until you mint a key that carries an explicit
|
|
1976
|
+
Data Hub grant. Do that with:
|
|
1977
|
+
|
|
1978
|
+
\`\`\`
|
|
1979
|
+
# read a specific Data Hub table:
|
|
1980
|
+
dashwise api-keys create datahub-read --grant datahub:table=<tableId>:read
|
|
1981
|
+
# or a whole database (application):
|
|
1982
|
+
dashwise api-keys create datahub-rw --grant datahub:app=<appId>:read,create,update
|
|
1983
|
+
\`\`\`
|
|
1984
|
+
|
|
1985
|
+
Paste the printed key as \`DASHWISE_API_KEY\` (or, for local dev, set it
|
|
1986
|
+
before \`dashwise dev\` so it wins over the auto-injected own-tables key).
|
|
1987
|
+
So: \`db\`/\`qb\` on your own tables works out of the box; \`datahub\` needs a
|
|
1988
|
+
granted key.
|
|
1989
|
+
|
|
1922
1990
|
## Auth in dev mode
|
|
1923
1991
|
|
|
1924
1992
|
\`dashwise dev\` registers a dev-mode SSO session with the backend so
|
|
@@ -2303,18 +2371,40 @@ async function moduleInitCommand(slugArg, options) {
|
|
|
2303
2371
|
let devInstall = null;
|
|
2304
2372
|
const wantsProvision = options.provision !== false;
|
|
2305
2373
|
if (wantsProvision) {
|
|
2374
|
+
const manifest = (() => {
|
|
2375
|
+
try {
|
|
2376
|
+
return readManifest(dir) ?? void 0;
|
|
2377
|
+
} catch {
|
|
2378
|
+
return void 0;
|
|
2379
|
+
}
|
|
2380
|
+
})();
|
|
2306
2381
|
devInstall = await tryProvisionDevInstall({
|
|
2307
2382
|
slug,
|
|
2308
2383
|
name,
|
|
2309
2384
|
description: options.description,
|
|
2310
2385
|
workspaceFlag: options.workspace,
|
|
2311
|
-
moduleKind: kind
|
|
2386
|
+
moduleKind: kind,
|
|
2387
|
+
...manifest !== void 0 ? { manifest } : {}
|
|
2312
2388
|
});
|
|
2313
2389
|
} else {
|
|
2314
2390
|
info(
|
|
2315
2391
|
`Skipping provisioning (${code("--no-provision")}). ${dim("Run with provisioning later to enable `dashwise dev` data-plane.")}`
|
|
2316
2392
|
);
|
|
2317
2393
|
}
|
|
2394
|
+
const keyCached = !wantsProvision || readModuleEntry(slug)?.apiKey ? true : false;
|
|
2395
|
+
if (wantsProvision && !keyCached) {
|
|
2396
|
+
fail(
|
|
2397
|
+
`NO API KEY WAS CACHED for ${code(slug)} \u2014 the scaffold is written, but ${code("dashwise dev")} will run with NO token (data-plane + sign-in will fail).`
|
|
2398
|
+
);
|
|
2399
|
+
info(
|
|
2400
|
+
`Fix it by re-running provisioning once the cause above is resolved:
|
|
2401
|
+
${code(`dashwise init ${slug} --force --workspace <your-workspace-slug>`)}
|
|
2402
|
+
Confirm success: the line ${code("\u2713 Provisioned dev install id=\u2026 API key cached")} must appear,
|
|
2403
|
+
and ${code("cat ~/.config/dashwise/auth.json")} must show a non-empty ${code(`modules.${slug}.apiKey`)} starting with ${code("dwk_")}.`
|
|
2404
|
+
);
|
|
2405
|
+
outro("Scaffold written, but provisioning failed \u2014 see above.");
|
|
2406
|
+
return 2;
|
|
2407
|
+
}
|
|
2318
2408
|
info(`Next steps:`);
|
|
2319
2409
|
process.stdout.write(`
|
|
2320
2410
|
${dim("1.")} ${code(`cd ${dir}`)}
|
|
@@ -2343,6 +2433,20 @@ async function tryProvisionDevInstall(args) {
|
|
|
2343
2433
|
warn("CLI config disappeared mid-init. Skipping provisioning.");
|
|
2344
2434
|
return null;
|
|
2345
2435
|
}
|
|
2436
|
+
const targetApiUrl = resolveApiUrl();
|
|
2437
|
+
info(`Backend: ${code(targetApiUrl)}`);
|
|
2438
|
+
const hostOf = (u) => {
|
|
2439
|
+
try {
|
|
2440
|
+
return new URL(u).host;
|
|
2441
|
+
} catch {
|
|
2442
|
+
return u;
|
|
2443
|
+
}
|
|
2444
|
+
};
|
|
2445
|
+
if (hostOf(targetApiUrl) !== hostOf(cfg.apiUrl)) {
|
|
2446
|
+
warn(
|
|
2447
|
+
`Your saved login is for ${code(cfg.apiUrl)} but this run targets ${code(targetApiUrl)}. Provisioning uses the saved token, which the target backend will reject (401). Log in against the target first: ${code(`dashwise login --api-url ${targetApiUrl}`)}.`
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2346
2450
|
let workspace2;
|
|
2347
2451
|
try {
|
|
2348
2452
|
workspace2 = await selectWorkspace({
|
|
@@ -2358,25 +2462,42 @@ async function tryProvisionDevInstall(args) {
|
|
|
2358
2462
|
info(
|
|
2359
2463
|
`Provisioning dev install in workspace ${code(workspace2.slug)} (id=${workspace2.id})\u2026`
|
|
2360
2464
|
);
|
|
2465
|
+
const baseBody = {
|
|
2466
|
+
slug: args.slug,
|
|
2467
|
+
name: args.name,
|
|
2468
|
+
...args.description !== void 0 ? { description: args.description } : {},
|
|
2469
|
+
workspaceId: workspace2.id,
|
|
2470
|
+
...args.moduleKind !== void 0 ? { moduleKind: args.moduleKind } : {}
|
|
2471
|
+
};
|
|
2472
|
+
const reqOpts = { baseUrl: resolveApiUrl(), auth: { token: cfg.token } };
|
|
2361
2473
|
let response;
|
|
2362
2474
|
try {
|
|
2363
2475
|
response = await createDevInstallation(
|
|
2364
|
-
{
|
|
2365
|
-
|
|
2366
|
-
name: args.name,
|
|
2367
|
-
...args.description !== void 0 ? { description: args.description } : {},
|
|
2368
|
-
workspaceId: workspace2.id,
|
|
2369
|
-
...args.moduleKind !== void 0 ? { moduleKind: args.moduleKind } : {}
|
|
2370
|
-
},
|
|
2371
|
-
{ baseUrl: resolveApiUrl(), auth: { token: cfg.token } }
|
|
2476
|
+
{ ...baseBody, ...args.manifest !== void 0 ? { manifest: args.manifest } : {} },
|
|
2477
|
+
reqOpts
|
|
2372
2478
|
);
|
|
2373
2479
|
} catch (err) {
|
|
2374
|
-
if (err instanceof ApiError) {
|
|
2480
|
+
if (err instanceof ApiError && err.code === "MANIFEST_INVALID" && args.manifest !== void 0) {
|
|
2481
|
+
warn(
|
|
2482
|
+
`Couldn't pre-materialize the seeded table(s) (${err.message}). Provisioning without them; add tables later with ${code("dashwise table create")}.`
|
|
2483
|
+
);
|
|
2484
|
+
try {
|
|
2485
|
+
response = await createDevInstallation(baseBody, reqOpts);
|
|
2486
|
+
} catch (err2) {
|
|
2487
|
+
if (err2 instanceof ApiError) {
|
|
2488
|
+
surfaceProvisionApiError(err2, args.slug);
|
|
2489
|
+
return null;
|
|
2490
|
+
}
|
|
2491
|
+
warn(`Provisioning failed: ${err2.message}`);
|
|
2492
|
+
return null;
|
|
2493
|
+
}
|
|
2494
|
+
} else if (err instanceof ApiError) {
|
|
2375
2495
|
surfaceProvisionApiError(err, args.slug);
|
|
2376
2496
|
return null;
|
|
2497
|
+
} else {
|
|
2498
|
+
warn(`Provisioning failed: ${err.message}`);
|
|
2499
|
+
return null;
|
|
2377
2500
|
}
|
|
2378
|
-
warn(`Provisioning failed: ${err.message}`);
|
|
2379
|
-
return null;
|
|
2380
2501
|
}
|
|
2381
2502
|
try {
|
|
2382
2503
|
upsertModuleEntry(args.slug, {
|
|
@@ -2394,7 +2515,7 @@ async function tryProvisionDevInstall(args) {
|
|
|
2394
2515
|
return response;
|
|
2395
2516
|
}
|
|
2396
2517
|
success(
|
|
2397
|
-
`Provisioned dev install id=${response.installation.id}. API key cached in your CLI config.`
|
|
2518
|
+
`Provisioned dev install id=${response.installation.id}. API key cached in your CLI config.` + (response.tables_applied > 0 ? ` ${response.tables_applied} seeded table(s) materialized.` : "")
|
|
2398
2519
|
);
|
|
2399
2520
|
return response;
|
|
2400
2521
|
}
|
|
@@ -2439,6 +2560,7 @@ var init_init = __esm({
|
|
|
2439
2560
|
init_output();
|
|
2440
2561
|
init_api_client();
|
|
2441
2562
|
init_config();
|
|
2563
|
+
init_manifest_io();
|
|
2442
2564
|
init_workspaces();
|
|
2443
2565
|
}
|
|
2444
2566
|
});
|
|
@@ -3353,8 +3475,13 @@ async function devCommand(options) {
|
|
|
3353
3475
|
` ${dim("api key")} ${maskedToken(apiKeyEnv)} ${dim(`(from ${source}${installId ? `, install id=${installId}` : ""})`)}`
|
|
3354
3476
|
);
|
|
3355
3477
|
} else if (manifestSlug !== void 0 && installationIdEnv === void 0) {
|
|
3356
|
-
|
|
3357
|
-
`No
|
|
3478
|
+
fail(
|
|
3479
|
+
`No ${code("dwk_")} API key for module ${code(manifestSlug)} \u2014 the module will run with NO token.`
|
|
3480
|
+
);
|
|
3481
|
+
info(
|
|
3482
|
+
` Data-plane calls (db, qb) AND sign-in will fail until you provision a dev install:
|
|
3483
|
+
${code(`dashwise init ${manifestSlug} --force --workspace <your-workspace-slug>`)}
|
|
3484
|
+
(Ensure you're logged into the right backend: ${code(`dashwise login --api-url ${apiUrl}`)}.)`
|
|
3358
3485
|
);
|
|
3359
3486
|
}
|
|
3360
3487
|
info("");
|
|
@@ -3528,9 +3655,9 @@ async function resolveModuleApiKey(slug, entry, apiUrl, cliBearer) {
|
|
|
3528
3655
|
if (process.env.DASHWISE_API_KEY) return null;
|
|
3529
3656
|
if (!entry) return null;
|
|
3530
3657
|
if (entry.apiKey) return null;
|
|
3531
|
-
if (!entry.
|
|
3658
|
+
if (!entry.installationId) return null;
|
|
3532
3659
|
info(
|
|
3533
|
-
`
|
|
3660
|
+
`No usable ${code("dwk_")} API key cached for ${code(slug)} \u2014 minting a fresh one against dev install ${entry.installationId} (a stale CLI can cache an empty key)\u2026`
|
|
3534
3661
|
);
|
|
3535
3662
|
let minted;
|
|
3536
3663
|
try {
|
|
@@ -8501,6 +8628,12 @@ program.name("dashwise").description("DashWise CLI \u2014 log in, author modules
|
|
|
8501
8628
|
"--api-url <url>",
|
|
8502
8629
|
"Override DashWise backend URL (default: $DASHWISE_API_URL or saved config or http://localhost:3000)"
|
|
8503
8630
|
);
|
|
8631
|
+
program.hook("preAction", () => {
|
|
8632
|
+
const apiUrl = program.opts().apiUrl?.trim();
|
|
8633
|
+
if (apiUrl) {
|
|
8634
|
+
process.env.DASHWISE_API_URL = apiUrl.replace(/\/+$/, "");
|
|
8635
|
+
}
|
|
8636
|
+
});
|
|
8504
8637
|
program.command("login").description("Sign in via the device-code flow.").option("--no-prompt", 'Skip the "open browser" prompt; just print the URL.').option("--name <name>", "Suggested name for the minted token (default: dashwise-cli).").action(async (cmdOpts) => {
|
|
8505
8638
|
const apiUrl = program.opts().apiUrl;
|
|
8506
8639
|
const exit = await loginCommand({
|
|
@@ -9138,7 +9271,7 @@ fieldCmd.command("set-type <table-slug> <field-slug> <new-type>").description(
|
|
|
9138
9271
|
}
|
|
9139
9272
|
})();
|
|
9140
9273
|
function getVersion() {
|
|
9141
|
-
return "0.
|
|
9274
|
+
return "0.11.0";
|
|
9142
9275
|
}
|
|
9143
9276
|
function parseIntOption(value) {
|
|
9144
9277
|
const n = Number.parseInt(value, 10);
|