@dashai/cli 0.2.3 → 0.2.4
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 +260 -106
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -92,6 +92,94 @@ function isPlausibleConfig(v) {
|
|
|
92
92
|
if (typeof u.email !== "string") return false;
|
|
93
93
|
return true;
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
// src/lib/api-client.ts
|
|
97
|
+
var ApiError = class extends Error {
|
|
98
|
+
status;
|
|
99
|
+
code;
|
|
100
|
+
context;
|
|
101
|
+
retriable;
|
|
102
|
+
constructor(status, envelope, fallbackMessage) {
|
|
103
|
+
const code2 = envelope?.code ?? codeFromStatus(status);
|
|
104
|
+
const message = envelope?.message ?? fallbackMessage;
|
|
105
|
+
super(message);
|
|
106
|
+
this.name = "ApiError";
|
|
107
|
+
this.status = status;
|
|
108
|
+
this.code = code2;
|
|
109
|
+
this.context = envelope?.context;
|
|
110
|
+
this.retriable = envelope?.retriable ?? status >= 500;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
async function apiRequest(method, path, body, options = {}) {
|
|
114
|
+
const baseUrl = (options.baseUrl ?? resolveApiUrl()).replace(/\/+$/, "");
|
|
115
|
+
const url = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
116
|
+
const headers = {
|
|
117
|
+
Accept: "application/json",
|
|
118
|
+
...options.headers ?? {}
|
|
119
|
+
};
|
|
120
|
+
if (body !== void 0) {
|
|
121
|
+
headers["Content-Type"] = "application/json";
|
|
122
|
+
}
|
|
123
|
+
const authMode = options.auth ?? "auto";
|
|
124
|
+
if (authMode === "auto") {
|
|
125
|
+
const saved = readSavedToken();
|
|
126
|
+
if (saved) headers["Authorization"] = `Bearer ${saved}`;
|
|
127
|
+
} else if (typeof authMode === "object" && authMode.token) {
|
|
128
|
+
headers["Authorization"] = `Bearer ${authMode.token}`;
|
|
129
|
+
}
|
|
130
|
+
let res;
|
|
131
|
+
try {
|
|
132
|
+
res = await fetch(url, {
|
|
133
|
+
method,
|
|
134
|
+
headers,
|
|
135
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
136
|
+
});
|
|
137
|
+
} catch (err) {
|
|
138
|
+
throw new ApiError(0, { code: "NETWORK_ERROR", message: err.message }, "Network error");
|
|
139
|
+
}
|
|
140
|
+
if (res.status === 204) {
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
143
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
144
|
+
let parsed = null;
|
|
145
|
+
if (contentType.includes("application/json")) {
|
|
146
|
+
try {
|
|
147
|
+
parsed = await res.json();
|
|
148
|
+
} catch {
|
|
149
|
+
parsed = null;
|
|
150
|
+
}
|
|
151
|
+
} else if (res.status >= 400) {
|
|
152
|
+
try {
|
|
153
|
+
parsed = { message: await res.text() };
|
|
154
|
+
} catch {
|
|
155
|
+
parsed = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!res.ok) {
|
|
159
|
+
throw new ApiError(res.status, asEnvelope(parsed), `HTTP ${res.status}`);
|
|
160
|
+
}
|
|
161
|
+
return parsed;
|
|
162
|
+
}
|
|
163
|
+
function asEnvelope(v) {
|
|
164
|
+
if (!v || typeof v !== "object") return null;
|
|
165
|
+
const env = v;
|
|
166
|
+
const out2 = {};
|
|
167
|
+
if (typeof env.code === "string") out2.code = env.code;
|
|
168
|
+
if (typeof env.message === "string") out2.message = env.message;
|
|
169
|
+
if (typeof env.retriable === "boolean") out2.retriable = env.retriable;
|
|
170
|
+
if (env.context && typeof env.context === "object") {
|
|
171
|
+
out2.context = env.context;
|
|
172
|
+
}
|
|
173
|
+
return out2;
|
|
174
|
+
}
|
|
175
|
+
function codeFromStatus(status) {
|
|
176
|
+
if (status === 401) return "UNAUTHENTICATED";
|
|
177
|
+
if (status === 403) return "FORBIDDEN";
|
|
178
|
+
if (status === 404) return "NOT_FOUND";
|
|
179
|
+
if (status === 0) return "NETWORK_ERROR";
|
|
180
|
+
if (status >= 500) return "INTERNAL_ERROR";
|
|
181
|
+
return "HTTP_ERROR";
|
|
182
|
+
}
|
|
95
183
|
function success(msg) {
|
|
96
184
|
process.stderr.write(`${pc.green("\u2713")} ${msg}
|
|
97
185
|
`);
|
|
@@ -125,6 +213,7 @@ function dim(s) {
|
|
|
125
213
|
}
|
|
126
214
|
|
|
127
215
|
// src/commands/dev.ts
|
|
216
|
+
var DEFAULT_NEXT_PORT = 3e3;
|
|
128
217
|
var PREFIX_SDK = `\x1B[36m[sdk]\x1B[0m `;
|
|
129
218
|
var PREFIX_NEXT = `\x1B[35m[next]\x1B[0m `;
|
|
130
219
|
async function devCommand(options) {
|
|
@@ -157,17 +246,60 @@ async function devCommand(options) {
|
|
|
157
246
|
return 1;
|
|
158
247
|
}
|
|
159
248
|
const apiUrl = options.apiUrl ?? process.env.DASHWISE_API_URL ?? savedConfig?.apiUrl ?? "http://localhost:3000";
|
|
160
|
-
const
|
|
249
|
+
const port = options.port ?? DEFAULT_NEXT_PORT;
|
|
250
|
+
const explicitInstallationId = options.installationId ?? process.env.DASHWISE_INSTALLATION_ID;
|
|
251
|
+
const reuseDevSessionId = process.env.DASHWISE_DEV_SESSION_ID;
|
|
252
|
+
let installationIdEnv;
|
|
253
|
+
let devSessionIdEnv;
|
|
254
|
+
let revokeDevSession;
|
|
255
|
+
if (explicitInstallationId && explicitInstallationId !== "local") {
|
|
256
|
+
installationIdEnv = explicitInstallationId;
|
|
257
|
+
} else if (reuseDevSessionId) {
|
|
258
|
+
devSessionIdEnv = reuseDevSessionId;
|
|
259
|
+
} else {
|
|
260
|
+
let workspaceContext;
|
|
261
|
+
try {
|
|
262
|
+
workspaceContext = await resolveTargetWorkspace(apiUrl, apiToken, options.workspace);
|
|
263
|
+
} catch (err) {
|
|
264
|
+
fail(err.message);
|
|
265
|
+
return 1;
|
|
266
|
+
}
|
|
267
|
+
const callbackOrigins = computeCallbackOrigins(port, options.callbackOrigin ?? []);
|
|
268
|
+
try {
|
|
269
|
+
const session = await registerDevSession(apiUrl, apiToken, {
|
|
270
|
+
target_workspace_id: workspaceContext.id,
|
|
271
|
+
callback_origins: callbackOrigins
|
|
272
|
+
});
|
|
273
|
+
devSessionIdEnv = session.id;
|
|
274
|
+
revokeDevSession = () => revokeDevSessionBestEffort(apiUrl, apiToken, session.id);
|
|
275
|
+
info(` ${dim("dev session")} ${session.id}`);
|
|
276
|
+
info(` ${dim("workspace")} ${workspaceContext.name} (id=${workspaceContext.id}, slug=${workspaceContext.slug})`);
|
|
277
|
+
info(` ${dim("callbacks")} ${callbackOrigins.join(", ")}`);
|
|
278
|
+
info(` ${dim("expires")} ${session.expires_at}`);
|
|
279
|
+
} catch (err) {
|
|
280
|
+
if (err instanceof ApiError) {
|
|
281
|
+
fail(`Failed to register dev session: ${err.code} \u2014 ${err.message}`);
|
|
282
|
+
} else {
|
|
283
|
+
fail(`Failed to register dev session: ${err.message}`);
|
|
284
|
+
}
|
|
285
|
+
return 1;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
161
288
|
const childEnv = {
|
|
162
289
|
...process.env,
|
|
163
290
|
DASHWISE_API_URL: apiUrl,
|
|
164
291
|
DASHWISE_API_TOKEN: apiToken,
|
|
165
|
-
DASHWISE_INSTALLATION_ID:
|
|
292
|
+
DASHWISE_INSTALLATION_ID: installationIdEnv ?? "",
|
|
293
|
+
...devSessionIdEnv !== void 0 ? { DASHWISE_DEV_SESSION_ID: devSessionIdEnv } : {}
|
|
166
294
|
};
|
|
167
295
|
info(`Dev loop starting \u2014 Ctrl-C to stop.`);
|
|
168
|
-
info(` ${dim("api")}
|
|
169
|
-
|
|
170
|
-
|
|
296
|
+
info(` ${dim("api")} ${apiUrl}`);
|
|
297
|
+
if (installationIdEnv !== void 0) {
|
|
298
|
+
info(` ${dim("installation")} ${installationIdEnv} (prod-mode SSO)`);
|
|
299
|
+
} else {
|
|
300
|
+
info(` ${dim("mode")} dev (DASHWISE_DEV_SESSION_ID injected)`);
|
|
301
|
+
}
|
|
302
|
+
info(` ${dim("token")} ${maskedToken(apiToken)} ${dim(`(from ${apiToken === savedConfig?.token ? "~/.config/dashwise/auth.json" : "$DASHWISE_API_TOKEN"})`)}`);
|
|
171
303
|
info("");
|
|
172
304
|
const children = [];
|
|
173
305
|
if (!options.nextOnly) {
|
|
@@ -175,7 +307,7 @@ async function devCommand(options) {
|
|
|
175
307
|
children.push({ name: "sdk", child: sdkChild, prefix: PREFIX_SDK });
|
|
176
308
|
}
|
|
177
309
|
if (!options.sdkOnly) {
|
|
178
|
-
const nextChild = spawnNextDev(projectRoot, childEnv,
|
|
310
|
+
const nextChild = spawnNextDev(projectRoot, childEnv, port);
|
|
179
311
|
children.push({ name: "next", child: nextChild, prefix: PREFIX_NEXT });
|
|
180
312
|
}
|
|
181
313
|
for (const { child, prefix } of children) {
|
|
@@ -193,6 +325,10 @@ Received ${sig}, stopping children\u2026`);
|
|
|
193
325
|
child.kill(sig);
|
|
194
326
|
}
|
|
195
327
|
}
|
|
328
|
+
if (revokeDevSession) {
|
|
329
|
+
revokeDevSession().catch(() => {
|
|
330
|
+
});
|
|
331
|
+
}
|
|
196
332
|
};
|
|
197
333
|
process.on("SIGINT", () => forwardSignal("SIGINT"));
|
|
198
334
|
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
|
|
@@ -286,96 +422,60 @@ function maskedToken(token) {
|
|
|
286
422
|
const tail = token.slice(-4);
|
|
287
423
|
return `${prefix}\u2026${tail}`;
|
|
288
424
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
this.retriable = envelope?.retriable ?? status >= 500;
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
async function apiRequest(method, path, body, options = {}) {
|
|
308
|
-
const baseUrl = (options.baseUrl ?? resolveApiUrl()).replace(/\/+$/, "");
|
|
309
|
-
const url = `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
310
|
-
const headers = {
|
|
311
|
-
Accept: "application/json",
|
|
312
|
-
...options.headers ?? {}
|
|
313
|
-
};
|
|
314
|
-
if (body !== void 0) {
|
|
315
|
-
headers["Content-Type"] = "application/json";
|
|
316
|
-
}
|
|
317
|
-
const authMode = options.auth ?? "auto";
|
|
318
|
-
if (authMode === "auto") {
|
|
319
|
-
const saved = readSavedToken();
|
|
320
|
-
if (saved) headers["Authorization"] = `Bearer ${saved}`;
|
|
321
|
-
} else if (typeof authMode === "object" && authMode.token) {
|
|
322
|
-
headers["Authorization"] = `Bearer ${authMode.token}`;
|
|
323
|
-
}
|
|
324
|
-
let res;
|
|
325
|
-
try {
|
|
326
|
-
res = await fetch(url, {
|
|
327
|
-
method,
|
|
328
|
-
headers,
|
|
329
|
-
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
330
|
-
});
|
|
331
|
-
} catch (err) {
|
|
332
|
-
throw new ApiError(0, { code: "NETWORK_ERROR", message: err.message }, "Network error");
|
|
333
|
-
}
|
|
334
|
-
if (res.status === 204) {
|
|
335
|
-
return void 0;
|
|
425
|
+
function computeCallbackOrigins(port, extra) {
|
|
426
|
+
const def = `http://localhost:${port}`;
|
|
427
|
+
return Array.from(/* @__PURE__ */ new Set([def, ...extra]));
|
|
428
|
+
}
|
|
429
|
+
async function resolveTargetWorkspace(apiUrl, apiToken, flag) {
|
|
430
|
+
const workspaces = await apiRequest(
|
|
431
|
+
"GET",
|
|
432
|
+
"/api/workspaces",
|
|
433
|
+
void 0,
|
|
434
|
+
{ baseUrl: apiUrl, auth: { token: apiToken } }
|
|
435
|
+
);
|
|
436
|
+
if (workspaces.length === 0) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
"No workspaces found for your account. Create a workspace at the DashWise dashboard first."
|
|
439
|
+
);
|
|
336
440
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
parsed = await res.json();
|
|
342
|
-
} catch {
|
|
343
|
-
parsed = null;
|
|
344
|
-
}
|
|
345
|
-
} else if (res.status >= 400) {
|
|
346
|
-
try {
|
|
347
|
-
parsed = { message: await res.text() };
|
|
348
|
-
} catch {
|
|
349
|
-
parsed = null;
|
|
441
|
+
if (flag === void 0) {
|
|
442
|
+
if (workspaces.length === 1) {
|
|
443
|
+
return workspaces[0];
|
|
350
444
|
}
|
|
445
|
+
const list = workspaces.map((w) => ` - ${w.slug} (id=${w.id}, name="${w.name}")`).join("\n");
|
|
446
|
+
throw new Error(
|
|
447
|
+
`You have ${workspaces.length} workspaces. Re-run with --workspace <slug-or-id> to pick one:
|
|
448
|
+
${list}`
|
|
449
|
+
);
|
|
351
450
|
}
|
|
352
|
-
|
|
353
|
-
|
|
451
|
+
const asNumber = Number.parseInt(flag, 10);
|
|
452
|
+
const isNumeric = !Number.isNaN(asNumber) && String(asNumber) === flag;
|
|
453
|
+
const match = isNumeric ? workspaces.find((w) => w.id === asNumber) : workspaces.find((w) => w.slug === flag);
|
|
454
|
+
if (!match) {
|
|
455
|
+
const list = workspaces.map((w) => ` - ${w.slug} (id=${w.id})`).join("\n");
|
|
456
|
+
throw new Error(
|
|
457
|
+
`No workspace matching --workspace=${flag}. Available:
|
|
458
|
+
${list}`
|
|
459
|
+
);
|
|
354
460
|
}
|
|
355
|
-
return
|
|
461
|
+
return match;
|
|
356
462
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (env.context && typeof env.context === "object") {
|
|
365
|
-
out2.context = env.context;
|
|
366
|
-
}
|
|
367
|
-
return out2;
|
|
463
|
+
async function registerDevSession(apiUrl, apiToken, body) {
|
|
464
|
+
return apiRequest(
|
|
465
|
+
"POST",
|
|
466
|
+
"/api/auth/dev/sessions",
|
|
467
|
+
body,
|
|
468
|
+
{ baseUrl: apiUrl, auth: { token: apiToken } }
|
|
469
|
+
);
|
|
368
470
|
}
|
|
369
|
-
function
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
471
|
+
async function revokeDevSessionBestEffort(apiUrl, apiToken, id) {
|
|
472
|
+
await apiRequest(
|
|
473
|
+
"DELETE",
|
|
474
|
+
`/api/auth/dev/sessions/${encodeURIComponent(id)}`,
|
|
475
|
+
void 0,
|
|
476
|
+
{ baseUrl: apiUrl, auth: { token: apiToken } }
|
|
477
|
+
);
|
|
376
478
|
}
|
|
377
|
-
|
|
378
|
-
// src/commands/login.ts
|
|
379
479
|
var DEFAULT_TOKEN_NAME = "dashwise-cli";
|
|
380
480
|
async function loginCommand(options) {
|
|
381
481
|
const apiUrl = (options.apiUrl ?? resolveApiUrl()).replace(/\/+$/, "");
|
|
@@ -914,12 +1014,17 @@ function envLocal() {
|
|
|
914
1014
|
return [
|
|
915
1015
|
"# Local dev config \u2014 auto-generated by `dashwise module init`.",
|
|
916
1016
|
"# Gitignored; safe to edit. `dashwise dev` (the unified loop) auto-",
|
|
917
|
-
"# injects DASHWISE_API_TOKEN from ~/.config/dashwise/auth.json
|
|
918
|
-
"#
|
|
1017
|
+
"# injects DASHWISE_API_TOKEN from ~/.config/dashwise/auth.json AND",
|
|
1018
|
+
"# DASHWISE_DEV_SESSION_ID from the dev session it registers \u2014 so",
|
|
1019
|
+
"# you typically don't need to set either here. Change DASHWISE_API_URL",
|
|
919
1020
|
"# to point at a non-default backend (e.g. https://api.dashwise.net).",
|
|
1021
|
+
"#",
|
|
1022
|
+
"# DASHWISE_INSTALLATION_ID is only needed AFTER you publish + install",
|
|
1023
|
+
"# the module in a workspace; until then dev mode (DASHWISE_DEV_SESSION_ID,",
|
|
1024
|
+
"# auto-set by `dashwise dev`) is the auth path.",
|
|
920
1025
|
"DASHWISE_API_URL=http://localhost:3000",
|
|
921
1026
|
"DASHWISE_API_TOKEN=",
|
|
922
|
-
"DASHWISE_INSTALLATION_ID=
|
|
1027
|
+
"DASHWISE_INSTALLATION_ID=",
|
|
923
1028
|
""
|
|
924
1029
|
].join("\n");
|
|
925
1030
|
}
|
|
@@ -1357,11 +1462,23 @@ function Row({ label, value }: { label: string; value: string }) {
|
|
|
1357
1462
|
function appApiAuthSignInTs() {
|
|
1358
1463
|
return `// /api/auth/sign-in \u2014 kick off the SSO flow.
|
|
1359
1464
|
//
|
|
1360
|
-
// Reads \`?return_to=\` from the caller (defaults to '/')
|
|
1361
|
-
//
|
|
1362
|
-
//
|
|
1363
|
-
//
|
|
1364
|
-
//
|
|
1465
|
+
// Reads \`?return_to=\` from the caller (defaults to '/'). Branches
|
|
1466
|
+
// on env:
|
|
1467
|
+
//
|
|
1468
|
+
// - DASHWISE_DEV_SESSION_ID set (set automatically by
|
|
1469
|
+
// \`dashwise dev\`): hits /api/auth/dev/sso/start with the dev
|
|
1470
|
+
// session id. No installation_id required \u2014 the module isn't
|
|
1471
|
+
// installed in a workspace yet.
|
|
1472
|
+
//
|
|
1473
|
+
// - DASHWISE_INSTALLATION_ID set (production / installed-module
|
|
1474
|
+
// path): hits /api/auth/sso/start with the installation id.
|
|
1475
|
+
//
|
|
1476
|
+
// In both cases the backend mints an exchange code + 302s back to
|
|
1477
|
+
// \`/api/auth/callback?code=...\` where we set the session cookie.
|
|
1478
|
+
//
|
|
1479
|
+
// Unauthenticated browser hits to either backend endpoint 302 to
|
|
1480
|
+
// the DashWise FE \`/login?return_to=...\` automatically \u2014 you don't
|
|
1481
|
+
// need to handle the "user not logged in" case here.
|
|
1365
1482
|
import { NextResponse } from 'next/server';
|
|
1366
1483
|
|
|
1367
1484
|
export function GET(request: Request) {
|
|
@@ -1369,19 +1486,43 @@ export function GET(request: Request) {
|
|
|
1369
1486
|
const returnTo = url.searchParams.get('return_to') ?? '/';
|
|
1370
1487
|
const apiBaseUrl = process.env.DASHWISE_API_URL;
|
|
1371
1488
|
const installationId = process.env.DASHWISE_INSTALLATION_ID;
|
|
1372
|
-
|
|
1489
|
+
const devSessionId = process.env.DASHWISE_DEV_SESSION_ID;
|
|
1490
|
+
|
|
1491
|
+
if (!apiBaseUrl) {
|
|
1373
1492
|
return new NextResponse(
|
|
1374
|
-
'DASHWISE_API_URL
|
|
1493
|
+
'DASHWISE_API_URL must be set in .env.local',
|
|
1375
1494
|
{ status: 500 },
|
|
1376
1495
|
);
|
|
1377
1496
|
}
|
|
1497
|
+
if (!installationId && !devSessionId) {
|
|
1498
|
+
return new NextResponse(
|
|
1499
|
+
'Either DASHWISE_INSTALLATION_ID (installed module) or DASHWISE_DEV_SESSION_ID ' +
|
|
1500
|
+
'(local dev via \`dashwise dev\`) must be set. Run \`dashwise dev\` to register ' +
|
|
1501
|
+
'a dev session, or set DASHWISE_INSTALLATION_ID after publishing your module.',
|
|
1502
|
+
{ status: 500 },
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1378
1506
|
// Absolute URL for return_to so the backend knows which host to
|
|
1379
1507
|
// bounce back to (the callback path is fixed at /api/auth/callback
|
|
1380
1508
|
// by SDK convention).
|
|
1381
1509
|
const moduleOrigin = url.origin;
|
|
1382
|
-
const
|
|
1383
|
-
|
|
1384
|
-
ssoStart
|
|
1510
|
+
const absoluteReturnTo = \`\${moduleOrigin}\${returnTo}\`;
|
|
1511
|
+
|
|
1512
|
+
let ssoStart;
|
|
1513
|
+
if (devSessionId) {
|
|
1514
|
+
// Dev mode wins when both are set \u2014 \`dashwise dev\` injects
|
|
1515
|
+
// DASHWISE_DEV_SESSION_ID into the child env, which overrides
|
|
1516
|
+
// whatever was in .env.local. The dev session id keys back to
|
|
1517
|
+
// the dev's workspace + callback origin allowlist.
|
|
1518
|
+
ssoStart = new URL('/api/auth/dev/sso/start', apiBaseUrl);
|
|
1519
|
+
ssoStart.searchParams.set('return_to', absoluteReturnTo);
|
|
1520
|
+
ssoStart.searchParams.set('dev_session_id', devSessionId);
|
|
1521
|
+
} else {
|
|
1522
|
+
ssoStart = new URL('/api/auth/sso/start', apiBaseUrl);
|
|
1523
|
+
ssoStart.searchParams.set('return_to', absoluteReturnTo);
|
|
1524
|
+
ssoStart.searchParams.set('client_id', installationId);
|
|
1525
|
+
}
|
|
1385
1526
|
return NextResponse.redirect(ssoStart);
|
|
1386
1527
|
}
|
|
1387
1528
|
`;
|
|
@@ -4114,18 +4255,28 @@ workspace.command("use <slug>").description("Set the default workspace for subse
|
|
|
4114
4255
|
process.exitCode = await workspaceUseCommand(slug);
|
|
4115
4256
|
});
|
|
4116
4257
|
program.command("dev").description(
|
|
4117
|
-
"One-command local dev loop: runs the manifest watcher + Next.js dev server together
|
|
4258
|
+
"One-command local dev loop: runs the manifest watcher + Next.js dev server together. Registers a dev-mode SSO session with the backend so workspace members can sign into your locally-running module via DashWise SSO (no installation_id required). Auth + dev-session env auto-injected into both child processes from your saved CLI config. Run `dashwise login` first."
|
|
4118
4259
|
).option("--dir <path>", "Project root containing `module.json` (default: current directory).").option(
|
|
4119
4260
|
"--installation-id <id>",
|
|
4120
|
-
|
|
4261
|
+
"Use prod-mode SSO with this installation id instead of registering a dev session. The installation must already exist in the target workspace."
|
|
4262
|
+
).option(
|
|
4263
|
+
"--workspace <slug-or-id>",
|
|
4264
|
+
"Workspace to scope the dev session to (slug or numeric id). Required if your account belongs to more than one workspace; auto-picked if you have just one."
|
|
4265
|
+
).option(
|
|
4266
|
+
"--callback-origin <url>",
|
|
4267
|
+
"Additional callback origin to allowlist on the dev session (repeatable). The dev server URL (http://localhost:<port>) is always allowlisted; pass this for custom-domain local dev (e.g. https://myapp.local).",
|
|
4268
|
+
collectRepeated,
|
|
4269
|
+
[]
|
|
4121
4270
|
).option(
|
|
4122
4271
|
"--api-url <url>",
|
|
4123
4272
|
"Override the `DASHWISE_API_URL` env var passed to children (default: saved CLI config)."
|
|
4124
|
-
).option("--port <number>", "Port for `next dev` (default:
|
|
4273
|
+
).option("--port <number>", "Port for `next dev` (default: 3000).", parseIntOption).option("--sdk-only", "Only run the manifest watcher; skip `next dev`.").option("--next-only", "Only run `next dev`; skip the manifest watcher.").action(
|
|
4125
4274
|
async (cmdOpts) => {
|
|
4126
4275
|
process.exitCode = await devCommand({
|
|
4127
4276
|
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
4128
4277
|
...cmdOpts.installationId !== void 0 ? { installationId: cmdOpts.installationId } : {},
|
|
4278
|
+
...cmdOpts.workspace !== void 0 ? { workspace: cmdOpts.workspace } : {},
|
|
4279
|
+
...cmdOpts.callbackOrigin !== void 0 && cmdOpts.callbackOrigin.length > 0 ? { callbackOrigin: cmdOpts.callbackOrigin } : {},
|
|
4129
4280
|
...cmdOpts.apiUrl !== void 0 ? { apiUrl: cmdOpts.apiUrl } : {},
|
|
4130
4281
|
...cmdOpts.port !== void 0 ? { port: cmdOpts.port } : {},
|
|
4131
4282
|
...cmdOpts.sdkOnly !== void 0 ? { sdkOnly: cmdOpts.sdkOnly } : {},
|
|
@@ -4344,7 +4495,7 @@ moduleCmd.command("action-log").description(
|
|
|
4344
4495
|
}
|
|
4345
4496
|
})();
|
|
4346
4497
|
function getVersion() {
|
|
4347
|
-
return "0.2.
|
|
4498
|
+
return "0.2.4";
|
|
4348
4499
|
}
|
|
4349
4500
|
function parseIntOption(value) {
|
|
4350
4501
|
const n = Number.parseInt(value, 10);
|
|
@@ -4353,5 +4504,8 @@ function parseIntOption(value) {
|
|
|
4353
4504
|
}
|
|
4354
4505
|
return n;
|
|
4355
4506
|
}
|
|
4507
|
+
function collectRepeated(value, previous) {
|
|
4508
|
+
return [...previous, value];
|
|
4509
|
+
}
|
|
4356
4510
|
//# sourceMappingURL=bin.js.map
|
|
4357
4511
|
//# sourceMappingURL=bin.js.map
|