@dreamboard-games/cli 0.1.30-alpha.30 → 0.1.30-alpha.32
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 +8 -8
- package/dist/agent-verifier/agent-workspace-verifier.mjs +243 -102
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -1
- package/dist/agent-verifier/{chunk-QMOBTQ5G.mjs → chunk-3SPDNMLA.mjs} +3 -3
- package/dist/agent-verifier/{chunk-QMOBTQ5G.mjs.map → chunk-3SPDNMLA.mjs.map} +1 -1
- package/dist/agent-verifier/{chunk-FNSHNMDY.mjs → chunk-MIRGCMUC.mjs} +3 -10
- package/dist/agent-verifier/chunk-MIRGCMUC.mjs.map +1 -0
- package/dist/agent-verifier/{global-config-SWWR2LP4.mjs → global-config-2NUESNEQ.mjs} +2 -2
- package/dist/agent-verifier/{keychain-backend-UF3Z26JM.mjs → keychain-backend-FF4I6ODB.mjs} +1 -1
- package/dist/agent-verifier/{keychain-backend-UF3Z26JM.mjs.map → keychain-backend-FF4I6ODB.mjs.map} +1 -1
- package/dist/agent-verifier/{materialize-workspace-K4WYFG5E.mjs → materialize-workspace-J2S4XIIC.mjs} +2 -2
- package/dist/agent-verifier/{static-scaffold-MHVM63HU.mjs → static-scaffold-56QBCO6P.mjs} +2 -2
- package/dist/authoring-compatibility-internal.js +1 -1
- package/dist/{chunk-UI7NWSYA.js → chunk-6NYVJYN4.js} +7 -28
- package/dist/chunk-6NYVJYN4.js.map +1 -0
- package/dist/{chunk-RTNKVNQA.js → chunk-DWWMZBFB.js} +247 -158
- package/dist/chunk-DWWMZBFB.js.map +1 -0
- package/dist/{chunk-I4SZ7FA4.js → chunk-TRF7IPXK.js} +3 -9
- package/dist/{chunk-I4SZ7FA4.js.map → chunk-TRF7IPXK.js.map} +1 -1
- package/dist/{global-config-GK2UC2X6.js → global-config-RBMW7IVA.js} +2 -2
- package/dist/index.js +123 -305
- package/dist/index.js.map +1 -1
- package/dist/internal.js +3 -3
- package/dist/internal.js.map +1 -1
- package/dist/{keychain-backend-GO34KGTG.js → keychain-backend-FSNTNTZE.js} +1 -1
- package/dist/{keychain-backend-GO34KGTG.js.map → keychain-backend-FSNTNTZE.js.map} +1 -1
- package/package.json +1 -1
- package/release/authoring-release-set.json +2 -2
- package/skills/dreamboard/SKILL.md +3 -3
- package/skills/dreamboard/references/building-your-first-game.md +1 -1
- package/skills/dreamboard/references/cli.md +20 -19
- package/skills/dreamboard/references/quickstart.md +3 -3
- package/dist/agent-verifier/chunk-FNSHNMDY.mjs.map +0 -1
- package/dist/chunk-RTNKVNQA.js.map +0 -1
- package/dist/chunk-UI7NWSYA.js.map +0 -1
- /package/dist/agent-verifier/{global-config-SWWR2LP4.mjs.map → global-config-2NUESNEQ.mjs.map} +0 -0
- /package/dist/agent-verifier/{materialize-workspace-K4WYFG5E.mjs.map → materialize-workspace-J2S4XIIC.mjs.map} +0 -0
- /package/dist/agent-verifier/{static-scaffold-MHVM63HU.mjs.map → static-scaffold-56QBCO6P.mjs.map} +0 -0
- /package/dist/{global-config-GK2UC2X6.js.map → global-config-RBMW7IVA.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dreamboard
|
|
2
2
|
|
|
3
|
-
Dreamboard
|
|
3
|
+
Dreamboard for working with Dreamboard games from your own editor/tooling.
|
|
4
4
|
|
|
5
5
|
Dreamboard is built to take you from napkin sketch to playable prototype without the paper cuts:
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ Published npm package:
|
|
|
18
18
|
npm install -g dreamboard
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
The published
|
|
21
|
+
The published `dreamboard` package targets Node 20+.
|
|
22
22
|
|
|
23
23
|
## Why Dreamboard
|
|
24
24
|
|
|
@@ -35,11 +35,11 @@ Use browser login:
|
|
|
35
35
|
dreamboard auth login
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Dreamboard stores your refreshable session in `~/.dreamboard/auth.json` by default. The file is written atomically with owner-only permissions (`0600`).
|
|
39
39
|
|
|
40
40
|
The operating system keychain is optional. Set `"credentialBackend": "keychain"` in `~/.dreamboard/config.json`, or use `DREAMBOARD_CREDENTIAL_BACKEND=keychain`, to opt in.
|
|
41
41
|
|
|
42
|
-
That stored session includes the Clerk refresh token
|
|
42
|
+
That stored session includes the Clerk refresh token Dreamboard needs to renew and exchange for short-lived Dreamboard API tokens automatically. Direct JWT injection is intentionally not part of the published Dreamboard flow.
|
|
43
43
|
|
|
44
44
|
## Source Checkout Setup
|
|
45
45
|
|
|
@@ -112,15 +112,15 @@ dreamboard dev
|
|
|
112
112
|
## Notes
|
|
113
113
|
|
|
114
114
|
- Project state lives in `.dreamboard/project.json`.
|
|
115
|
-
- Published/public
|
|
115
|
+
- Published/public `dreamboard` installs target Node 20+ and support commit-scoped
|
|
116
116
|
build, preview, release, and status workflows.
|
|
117
|
-
- Published
|
|
117
|
+
- Published stable `dreamboard` builds are production-only and do not support environment overrides or direct JWT injection. Published alpha builds allow `--env <local|staging|prod>` for operator verification, but still reject direct JWT injection.
|
|
118
118
|
- Local embedded-harness testing remains Bun-only and requires a source checkout with local backend support.
|
|
119
|
-
- Internal source-checkout builds may expose extra auth and environment helpers, but those are not part of the published
|
|
119
|
+
- Internal source-checkout builds may expose extra auth and environment helpers, but those are not part of the published Dreamboard contract.
|
|
120
120
|
|
|
121
121
|
## Skill Source
|
|
122
122
|
|
|
123
123
|
- Public skill source lives under `skills/dreamboard/`.
|
|
124
124
|
- `skills/dreamboard/references/*.md` are generated from `docs/` via `pnpm run sync:skill-docs`.
|
|
125
125
|
- `dreamboard project create` installs the bundled skill into `.agents/skills/dreamboard/` in the generated game project.
|
|
126
|
-
- Public GitHub repo for
|
|
126
|
+
- Public GitHub repo for Dreamboard is [dreamboard-games/dreamboard](https://github.com/dreamboard-games/dreamboard).
|
|
@@ -4,11 +4,10 @@ import {
|
|
|
4
4
|
loadProjectConfig
|
|
5
5
|
} from "./chunk-M6YNQZCC.mjs";
|
|
6
6
|
import {
|
|
7
|
-
clearCredentials,
|
|
8
7
|
getStoredSession,
|
|
9
8
|
loadGlobalConfig,
|
|
10
9
|
withCredentialLock
|
|
11
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MIRGCMUC.mjs";
|
|
12
11
|
import "./chunk-GWRZRWCF.mjs";
|
|
13
12
|
import {
|
|
14
13
|
readJsonFile,
|
|
@@ -1130,10 +1129,29 @@ var consola = createConsola2();
|
|
|
1130
1129
|
|
|
1131
1130
|
// src/build-target.ts
|
|
1132
1131
|
var injectedBuildChannel = true ? "development" : void 0;
|
|
1132
|
+
var injectedPackageVersion = typeof __DREAMBOARD_PACKAGE_VERSION__ === "string" ? __DREAMBOARD_PACKAGE_VERSION__ : void 0;
|
|
1133
1133
|
var BUILD_CHANNEL = injectedBuildChannel === "published" ? "published" : "development";
|
|
1134
|
+
var PACKAGE_VERSION = injectedPackageVersion ?? "0.0.0-development";
|
|
1135
|
+
function isAlphaReleaseVersion(version) {
|
|
1136
|
+
return /(?:^|-|\.)alpha(?:$|-|\.)/.test(version);
|
|
1137
|
+
}
|
|
1134
1138
|
var IS_PUBLISHED_BUILD = BUILD_CHANNEL === "published";
|
|
1139
|
+
var IS_ALPHA_RELEASE = isAlphaReleaseVersion(PACKAGE_VERSION);
|
|
1140
|
+
var CAN_SELECT_ENVIRONMENT = !IS_PUBLISHED_BUILD || IS_ALPHA_RELEASE;
|
|
1135
1141
|
var PUBLISHED_ENVIRONMENT = "prod";
|
|
1136
1142
|
|
|
1143
|
+
// src/auth/refresh-error.ts
|
|
1144
|
+
function classifyRefreshError(error) {
|
|
1145
|
+
const message = error.message?.toLowerCase() ?? "";
|
|
1146
|
+
if (error.status === 400 || error.status === 401 || message.includes("invalid_grant") || message.includes("refresh token") || message.includes("expired") || message.includes("revoked")) {
|
|
1147
|
+
return { kind: "permanent_invalid", reason: error.message };
|
|
1148
|
+
}
|
|
1149
|
+
if (error.status === 408 || error.status === 429 || typeof error.status === "number" && error.status >= 500 || message.includes("timeout") || message.includes("network") || message.includes("fetch failed")) {
|
|
1150
|
+
return { kind: "transient", reason: error.message };
|
|
1151
|
+
}
|
|
1152
|
+
return { kind: "unknown", reason: error.message };
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1137
1155
|
// src/auth/clerk-oauth.ts
|
|
1138
1156
|
import crypto from "crypto";
|
|
1139
1157
|
async function refreshClerkOAuthToken(input) {
|
|
@@ -1241,75 +1259,183 @@ async function exchangeDreamboardUserToken(input) {
|
|
|
1241
1259
|
};
|
|
1242
1260
|
}
|
|
1243
1261
|
|
|
1244
|
-
// src/auth/user-
|
|
1245
|
-
var
|
|
1246
|
-
function
|
|
1262
|
+
// src/auth/user-session-manager.ts
|
|
1263
|
+
var DEFAULT_TOKEN_MIN_VALIDITY_MS = 60 * 1e3;
|
|
1264
|
+
function createUserSessionManager(config) {
|
|
1247
1265
|
return {
|
|
1248
|
-
async
|
|
1249
|
-
const localOrInjected = resolveNonStoredToken(config, "dreamboard-api");
|
|
1250
|
-
if (localOrInjected) return localOrInjected;
|
|
1251
|
-
if (!usesStoredSession(config)) return null;
|
|
1266
|
+
async establishRefreshableSession(session) {
|
|
1252
1267
|
return withCredentialLock(async (ops) => {
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
if (apiToken) return apiToken;
|
|
1256
|
-
const clerk = await resolveFreshClerkAccessToken(config, stored);
|
|
1268
|
+
const credentials = credentialsFromRefreshableSession(session);
|
|
1269
|
+
await ops.writeFull(credentials);
|
|
1257
1270
|
const exchanged = await exchangeDreamboardUserToken({
|
|
1258
1271
|
apiBaseUrl: config.apiBaseUrl,
|
|
1259
|
-
clerkAccessToken:
|
|
1272
|
+
clerkAccessToken: credentials.accessToken,
|
|
1260
1273
|
audience: "dreamboard-api"
|
|
1261
1274
|
});
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1275
|
+
const apiToken = toAccessToken(exchanged);
|
|
1276
|
+
await ops.writeFull(withApiToken(credentials, apiToken));
|
|
1277
|
+
return apiToken;
|
|
1278
|
+
});
|
|
1279
|
+
},
|
|
1280
|
+
async establishAccessOnlySession(accessToken) {
|
|
1281
|
+
await withCredentialLock((ops) => ops.writeAccessOnly(accessToken));
|
|
1282
|
+
},
|
|
1283
|
+
async resolveApiToken(options) {
|
|
1284
|
+
const localOrInjected = resolveNonStoredToken(config, "dreamboard-api");
|
|
1285
|
+
if (localOrInjected) return localOrInjected;
|
|
1286
|
+
if (!usesStoredSession(config)) return null;
|
|
1287
|
+
const minValidityMs = options?.minValiditySeconds === void 0 ? DEFAULT_TOKEN_MIN_VALIDITY_MS : Math.max(0, options.minValiditySeconds * 1e3);
|
|
1288
|
+
return withCredentialLock(async (ops) => {
|
|
1289
|
+
const stored = await ops.read();
|
|
1290
|
+
return resolveStoredApiToken(ops, config, stored, minValidityMs);
|
|
1272
1291
|
});
|
|
1273
1292
|
},
|
|
1274
1293
|
async resolveGitToken() {
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
apiBaseUrl: config.apiBaseUrl,
|
|
1278
|
-
clerkAccessToken: config.authToken,
|
|
1279
|
-
audience: "dreamboard-git"
|
|
1280
|
-
});
|
|
1281
|
-
return {
|
|
1282
|
-
token: exchanged.accessToken,
|
|
1283
|
-
expiresAt: exchanged.expiresAt,
|
|
1284
|
-
audience: "dreamboard-git"
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1294
|
+
const localOrInjected = resolveNonStoredToken(config, "dreamboard-git");
|
|
1295
|
+
if (localOrInjected) return localOrInjected;
|
|
1287
1296
|
if (!usesStoredSession(config)) {
|
|
1288
|
-
throw
|
|
1289
|
-
|
|
1297
|
+
throw missingSessionError();
|
|
1298
|
+
}
|
|
1299
|
+
return withCredentialLock(async (ops) => {
|
|
1300
|
+
const stored = await ops.read();
|
|
1301
|
+
const clerk = await resolveFreshClerkSession(ops, config, stored);
|
|
1302
|
+
return toAccessToken(
|
|
1303
|
+
await exchangeDreamboardUserToken({
|
|
1304
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
1305
|
+
clerkAccessToken: clerk.accessToken,
|
|
1306
|
+
audience: "dreamboard-git"
|
|
1307
|
+
})
|
|
1290
1308
|
);
|
|
1309
|
+
});
|
|
1310
|
+
},
|
|
1311
|
+
async inspectSession() {
|
|
1312
|
+
const localOrInjected = resolveNonStoredToken(config, "dreamboard-api");
|
|
1313
|
+
if (localOrInjected) {
|
|
1314
|
+
return inspectAccessOnlyToken(localOrInjected);
|
|
1315
|
+
}
|
|
1316
|
+
if (!usesStoredSession(config)) {
|
|
1317
|
+
return { kind: "none" };
|
|
1291
1318
|
}
|
|
1292
1319
|
return withCredentialLock(async (ops) => {
|
|
1293
1320
|
const stored = await ops.read();
|
|
1294
|
-
|
|
1295
|
-
const
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1321
|
+
if (!stored) return { kind: "none" };
|
|
1322
|
+
const cached = freshStoredApiToken(
|
|
1323
|
+
stored,
|
|
1324
|
+
DEFAULT_TOKEN_MIN_VALIDITY_MS
|
|
1325
|
+
);
|
|
1326
|
+
if (cached) {
|
|
1327
|
+
return activeStatus("refreshable", cached, false);
|
|
1328
|
+
}
|
|
1329
|
+
try {
|
|
1330
|
+
const token = await resolveStoredApiToken(
|
|
1331
|
+
ops,
|
|
1332
|
+
config,
|
|
1333
|
+
stored,
|
|
1334
|
+
DEFAULT_TOKEN_MIN_VALIDITY_MS
|
|
1335
|
+
);
|
|
1336
|
+
return activeStatus("refreshable", token, true);
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
return failedRefreshableStatus(error);
|
|
1339
|
+
}
|
|
1306
1340
|
});
|
|
1307
1341
|
},
|
|
1308
1342
|
async logout() {
|
|
1309
|
-
await
|
|
1343
|
+
await withCredentialLock((ops) => ops.clear("logout_command"));
|
|
1310
1344
|
}
|
|
1311
1345
|
};
|
|
1312
1346
|
}
|
|
1347
|
+
async function resolveStoredApiToken(ops, config, stored, minValidityMs) {
|
|
1348
|
+
const cached = freshStoredApiToken(stored, minValidityMs);
|
|
1349
|
+
if (cached) return cached;
|
|
1350
|
+
const clerk = await resolveFreshClerkSession(ops, config, stored);
|
|
1351
|
+
const exchanged = await exchangeDreamboardUserToken({
|
|
1352
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
1353
|
+
clerkAccessToken: clerk.accessToken,
|
|
1354
|
+
audience: "dreamboard-api"
|
|
1355
|
+
});
|
|
1356
|
+
const apiToken = toAccessToken(exchanged);
|
|
1357
|
+
await ops.writeFull(withApiToken(clerk, apiToken));
|
|
1358
|
+
return apiToken;
|
|
1359
|
+
}
|
|
1360
|
+
async function resolveFreshClerkSession(ops, config, stored) {
|
|
1361
|
+
if (!stored) {
|
|
1362
|
+
throw missingSessionError();
|
|
1363
|
+
}
|
|
1364
|
+
if (!stored.refreshToken) {
|
|
1365
|
+
throw new Error(
|
|
1366
|
+
"Stored Dreamboard session is missing its refresh token. Run `dreamboard auth login` to authenticate again."
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
if (stored.accessToken && isFresh(
|
|
1370
|
+
stored.tokenExpiresAt,
|
|
1371
|
+
stored.accessToken,
|
|
1372
|
+
DEFAULT_TOKEN_MIN_VALIDITY_MS
|
|
1373
|
+
)) {
|
|
1374
|
+
return credentialsFromStored(config, stored);
|
|
1375
|
+
}
|
|
1376
|
+
const payload = await refreshClerkOAuthToken({
|
|
1377
|
+
config: {
|
|
1378
|
+
issuer: stored.clerkOAuthIssuer ?? config.clerkOAuthIssuer,
|
|
1379
|
+
clientId: stored.clerkOAuthClientId ?? config.clerkOAuthClientId,
|
|
1380
|
+
tokenUrl: stored.clerkOAuthTokenUrl ?? config.clerkOAuthTokenUrl
|
|
1381
|
+
},
|
|
1382
|
+
refreshToken: stored.refreshToken
|
|
1383
|
+
});
|
|
1384
|
+
const refreshed = {
|
|
1385
|
+
accessToken: payload.accessToken,
|
|
1386
|
+
refreshToken: payload.refreshToken,
|
|
1387
|
+
tokenExpiresAt: payload.expiresAt,
|
|
1388
|
+
dreamboardApiToken: stored.dreamboardApiToken,
|
|
1389
|
+
dreamboardApiExpiresAt: stored.dreamboardApiExpiresAt,
|
|
1390
|
+
clerkOAuthIssuer: stored.clerkOAuthIssuer ?? config.clerkOAuthIssuer,
|
|
1391
|
+
clerkOAuthClientId: stored.clerkOAuthClientId ?? config.clerkOAuthClientId,
|
|
1392
|
+
clerkOAuthTokenUrl: payload.tokenUrl,
|
|
1393
|
+
environment: stored.environment ?? config.environment
|
|
1394
|
+
};
|
|
1395
|
+
await ops.writeFull(refreshed);
|
|
1396
|
+
return refreshed;
|
|
1397
|
+
}
|
|
1398
|
+
function credentialsFromStored(config, stored) {
|
|
1399
|
+
if (!stored.accessToken || !stored.refreshToken) {
|
|
1400
|
+
throw missingSessionError();
|
|
1401
|
+
}
|
|
1402
|
+
return {
|
|
1403
|
+
accessToken: stored.accessToken,
|
|
1404
|
+
refreshToken: stored.refreshToken,
|
|
1405
|
+
tokenExpiresAt: stored.tokenExpiresAt,
|
|
1406
|
+
dreamboardApiToken: stored.dreamboardApiToken,
|
|
1407
|
+
dreamboardApiExpiresAt: stored.dreamboardApiExpiresAt,
|
|
1408
|
+
clerkOAuthIssuer: stored.clerkOAuthIssuer ?? config.clerkOAuthIssuer,
|
|
1409
|
+
clerkOAuthClientId: stored.clerkOAuthClientId ?? config.clerkOAuthClientId,
|
|
1410
|
+
clerkOAuthTokenUrl: stored.clerkOAuthTokenUrl ?? config.clerkOAuthTokenUrl,
|
|
1411
|
+
environment: stored.environment ?? config.environment
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function credentialsFromRefreshableSession(session) {
|
|
1415
|
+
return {
|
|
1416
|
+
accessToken: session.clerkAccessToken,
|
|
1417
|
+
refreshToken: session.refreshToken,
|
|
1418
|
+
tokenExpiresAt: session.clerkAccessExpiresAt,
|
|
1419
|
+
clerkOAuthIssuer: session.clerkOAuthIssuer,
|
|
1420
|
+
clerkOAuthClientId: session.clerkOAuthClientId,
|
|
1421
|
+
clerkOAuthTokenUrl: session.clerkOAuthTokenUrl,
|
|
1422
|
+
environment: session.environment
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
function withApiToken(credentials, token) {
|
|
1426
|
+
return {
|
|
1427
|
+
...credentials,
|
|
1428
|
+
dreamboardApiToken: token.token,
|
|
1429
|
+
dreamboardApiExpiresAt: token.expiresAt
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
function toAccessToken(token) {
|
|
1433
|
+
return {
|
|
1434
|
+
token: token.accessToken,
|
|
1435
|
+
expiresAt: token.expiresAt,
|
|
1436
|
+
audience: token.audience
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1313
1439
|
function resolveNonStoredToken(config, audience) {
|
|
1314
1440
|
if (usesStoredSession(config)) return null;
|
|
1315
1441
|
if (!config.authToken) return null;
|
|
@@ -1319,9 +1445,13 @@ function resolveNonStoredToken(config, audience) {
|
|
|
1319
1445
|
audience
|
|
1320
1446
|
};
|
|
1321
1447
|
}
|
|
1322
|
-
function freshStoredApiToken(stored) {
|
|
1448
|
+
function freshStoredApiToken(stored, minValidityMs) {
|
|
1323
1449
|
if (!stored?.dreamboardApiToken) return null;
|
|
1324
|
-
if (isFresh(
|
|
1450
|
+
if (isFresh(
|
|
1451
|
+
stored.dreamboardApiExpiresAt,
|
|
1452
|
+
stored.dreamboardApiToken,
|
|
1453
|
+
minValidityMs
|
|
1454
|
+
)) {
|
|
1325
1455
|
return {
|
|
1326
1456
|
token: stored.dreamboardApiToken,
|
|
1327
1457
|
expiresAt: stored.dreamboardApiExpiresAt,
|
|
@@ -1330,49 +1460,60 @@ function freshStoredApiToken(stored) {
|
|
|
1330
1460
|
}
|
|
1331
1461
|
return null;
|
|
1332
1462
|
}
|
|
1333
|
-
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
const tokenExpiresAt = stored?.tokenExpiresAt ?? config.clerkAccessExpiresAt;
|
|
1337
|
-
if (!refreshToken) {
|
|
1338
|
-
throw new Error(
|
|
1339
|
-
"Stored Dreamboard session is missing its refresh token. Run `dreamboard auth login` to authenticate again."
|
|
1340
|
-
);
|
|
1341
|
-
}
|
|
1342
|
-
if (accessToken && isFresh(tokenExpiresAt, accessToken)) {
|
|
1463
|
+
function inspectAccessOnlyToken(token) {
|
|
1464
|
+
const expiry = resolveExpiry(token.expiresAt, token.token);
|
|
1465
|
+
if (expiry && expiry.getTime() <= Date.now()) {
|
|
1343
1466
|
return {
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
dreamboardApiToken: stored?.dreamboardApiToken,
|
|
1348
|
-
dreamboardApiExpiresAt: stored?.dreamboardApiExpiresAt,
|
|
1349
|
-
clerkOAuthIssuer: stored?.clerkOAuthIssuer ?? config.clerkOAuthIssuer,
|
|
1350
|
-
clerkOAuthClientId: stored?.clerkOAuthClientId ?? config.clerkOAuthClientId,
|
|
1351
|
-
clerkOAuthTokenUrl: stored?.clerkOAuthTokenUrl ?? config.clerkOAuthTokenUrl,
|
|
1352
|
-
environment: stored?.environment ?? config.environment
|
|
1467
|
+
kind: "invalid",
|
|
1468
|
+
sessionKind: "access-only",
|
|
1469
|
+
message: "Stored Dreamboard access token is expired. Run `dreamboard auth login` to authenticate again."
|
|
1353
1470
|
};
|
|
1354
1471
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1472
|
+
return activeStatus("access-only", token, false);
|
|
1473
|
+
}
|
|
1474
|
+
function failedRefreshableStatus(error) {
|
|
1475
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1476
|
+
const errorStatus = typeof error === "object" && error !== null && "status" in error ? error.status : void 0;
|
|
1477
|
+
const classification = classifyRefreshError({
|
|
1478
|
+
message,
|
|
1479
|
+
status: typeof errorStatus === "number" ? errorStatus : void 0
|
|
1362
1480
|
});
|
|
1481
|
+
if (classification.kind === "permanent_invalid") {
|
|
1482
|
+
return {
|
|
1483
|
+
kind: "invalid",
|
|
1484
|
+
sessionKind: "refreshable",
|
|
1485
|
+
message
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1363
1488
|
return {
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
clerkOAuthIssuer: stored?.clerkOAuthIssuer ?? config.clerkOAuthIssuer,
|
|
1368
|
-
clerkOAuthClientId: stored?.clerkOAuthClientId ?? config.clerkOAuthClientId,
|
|
1369
|
-
clerkOAuthTokenUrl: payload.tokenUrl,
|
|
1370
|
-
environment: stored?.environment ?? config.environment
|
|
1489
|
+
kind: "degraded",
|
|
1490
|
+
sessionKind: "refreshable",
|
|
1491
|
+
message
|
|
1371
1492
|
};
|
|
1372
1493
|
}
|
|
1373
|
-
function
|
|
1374
|
-
|
|
1375
|
-
|
|
1494
|
+
function activeStatus(sessionKind, apiToken, repaired) {
|
|
1495
|
+
return {
|
|
1496
|
+
kind: "active",
|
|
1497
|
+
sessionKind,
|
|
1498
|
+
apiToken,
|
|
1499
|
+
repaired
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
function missingSessionError() {
|
|
1503
|
+
return new Error(
|
|
1504
|
+
"Missing Dreamboard session. Run `dreamboard auth login` to authenticate."
|
|
1505
|
+
);
|
|
1506
|
+
}
|
|
1507
|
+
function isFresh(expiresAt, token, minValidityMs) {
|
|
1508
|
+
const expiry = resolveExpiry(expiresAt, token);
|
|
1509
|
+
return expiry !== null && Number.isFinite(expiry.getTime()) && expiry.getTime() > Date.now() + minValidityMs;
|
|
1510
|
+
}
|
|
1511
|
+
function resolveExpiry(expiresAt, token) {
|
|
1512
|
+
if (expiresAt) {
|
|
1513
|
+
const parsed = new Date(expiresAt);
|
|
1514
|
+
return Number.isFinite(parsed.getTime()) ? parsed : null;
|
|
1515
|
+
}
|
|
1516
|
+
return getJwtExpiry(token);
|
|
1376
1517
|
}
|
|
1377
1518
|
function getJwtExpiry(accessToken) {
|
|
1378
1519
|
if (!accessToken) return null;
|
|
@@ -1479,21 +1620,20 @@ function isLocalAwsUrl(rawUrl) {
|
|
|
1479
1620
|
}
|
|
1480
1621
|
|
|
1481
1622
|
// src/config/resolve.ts
|
|
1482
|
-
var DEFAULT_REFRESH_WINDOW_MS = 5 * 60 * 1e3;
|
|
1483
1623
|
var TRANSIENT_READ_RETRY_DELAYS_MS = [100, 300];
|
|
1484
1624
|
function resolveConfig(globalConfig, flags, project, credentials) {
|
|
1485
1625
|
if (IS_PUBLISHED_BUILD) {
|
|
1486
1626
|
assertPublicRuntimeFlags(flags);
|
|
1487
1627
|
}
|
|
1488
|
-
const envEnvironment =
|
|
1489
|
-
const projectEnvironment =
|
|
1490
|
-
const environment =
|
|
1628
|
+
const envEnvironment = CAN_SELECT_ENVIRONMENT ? environmentFromProcess() : void 0;
|
|
1629
|
+
const projectEnvironment = CAN_SELECT_ENVIRONMENT ? project?.environment : void 0;
|
|
1630
|
+
const environment = CAN_SELECT_ENVIRONMENT ? flags.env || envEnvironment || projectEnvironment || globalConfig.environment || (IS_PUBLISHED_BUILD ? PUBLISHED_ENVIRONMENT : "staging") : PUBLISHED_ENVIRONMENT;
|
|
1491
1631
|
const envConfig = ENVIRONMENT_CONFIGS[environment];
|
|
1492
1632
|
const publishedEnvConfig = ENVIRONMENT_CONFIGS[PUBLISHED_ENVIRONMENT];
|
|
1493
|
-
const hasExplicitEnvironmentOverride =
|
|
1494
|
-
const resolvedApiBaseUrl = IS_PUBLISHED_BUILD ? publishedEnvConfig?.apiBaseUrl ?? DEFAULT_API_BASE_URL : hasExplicitEnvironmentOverride ? projectLocalBaseUrl(project?.apiBaseUrl, environment) || envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL : project?.apiBaseUrl || envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL;
|
|
1633
|
+
const hasExplicitEnvironmentOverride = CAN_SELECT_ENVIRONMENT && Boolean(flags.env || envEnvironment || projectEnvironment);
|
|
1634
|
+
const resolvedApiBaseUrl = IS_PUBLISHED_BUILD && !CAN_SELECT_ENVIRONMENT ? publishedEnvConfig?.apiBaseUrl ?? DEFAULT_API_BASE_URL : hasExplicitEnvironmentOverride ? projectLocalBaseUrl(project?.apiBaseUrl, environment) || envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL : project?.apiBaseUrl || envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL;
|
|
1495
1635
|
const apiBaseUrl = valueOrUndefined(process.env.DREAMBOARD_API_BASE_URL) ?? resolvedApiBaseUrl;
|
|
1496
|
-
const resolvedWebBaseUrl = IS_PUBLISHED_BUILD ? publishedEnvConfig?.webBaseUrl ?? DEFAULT_WEB_BASE_URL : hasExplicitEnvironmentOverride ? projectLocalBaseUrl(project?.webBaseUrl, environment) || envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL : project?.webBaseUrl || envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL;
|
|
1636
|
+
const resolvedWebBaseUrl = IS_PUBLISHED_BUILD && !CAN_SELECT_ENVIRONMENT ? publishedEnvConfig?.webBaseUrl ?? DEFAULT_WEB_BASE_URL : hasExplicitEnvironmentOverride ? projectLocalBaseUrl(project?.webBaseUrl, environment) || envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL : project?.webBaseUrl || envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL;
|
|
1497
1637
|
const webBaseUrl = valueOrUndefined(process.env.DREAMBOARD_WEB_BASE_URL) ?? resolvedWebBaseUrl;
|
|
1498
1638
|
const snapshot = buildCredentialSnapshot(flags, credentials, environment);
|
|
1499
1639
|
const oauthConfig = resolveEnvironmentOAuthConfig(environment, envConfig);
|
|
@@ -1598,9 +1738,10 @@ function projectLocalBaseUrl(rawUrl, environment) {
|
|
|
1598
1738
|
return void 0;
|
|
1599
1739
|
}
|
|
1600
1740
|
}
|
|
1601
|
-
function assertPublicRuntimeFlags(flags) {
|
|
1602
|
-
const
|
|
1603
|
-
|
|
1741
|
+
function assertPublicRuntimeFlags(flags, options = {}) {
|
|
1742
|
+
const canSelectEnvironment = options.canSelectEnvironment ?? CAN_SELECT_ENVIRONMENT;
|
|
1743
|
+
const argv2 = options.argv ?? process.argv.slice(2);
|
|
1744
|
+
if (!canSelectEnvironment && (flags.env || argv2.includes("--env"))) {
|
|
1604
1745
|
throw new Error(
|
|
1605
1746
|
"The published Dreamboard CLI is production-only and does not accept `--env`."
|
|
1606
1747
|
);
|
|
@@ -1618,7 +1759,7 @@ function assertPublicRuntimeFlags(flags) {
|
|
|
1618
1759
|
}
|
|
1619
1760
|
async function configureClient(config) {
|
|
1620
1761
|
const localHarnessToken = resolveLocalHarnessAccessToken(config);
|
|
1621
|
-
const resolvedToken = localHarnessToken ? { token: localHarnessToken } : await
|
|
1762
|
+
const resolvedToken = localHarnessToken ? { token: localHarnessToken } : await createUserSessionManager(config).resolveApiToken();
|
|
1622
1763
|
const effectiveAccessToken = resolvedToken?.token;
|
|
1623
1764
|
client.setConfig({
|
|
1624
1765
|
baseUrl: config.apiBaseUrl,
|
|
@@ -1879,7 +2020,7 @@ Usage:
|
|
|
1879
2020
|
}
|
|
1880
2021
|
async function materializePreparedWorkspace(args) {
|
|
1881
2022
|
const inputPath = readRequiredOption(args, "--input");
|
|
1882
|
-
const { materializeWorkspaceProject } = await import("./materialize-workspace-
|
|
2023
|
+
const { materializeWorkspaceProject } = await import("./materialize-workspace-J2S4XIIC.mjs");
|
|
1883
2024
|
const input = JSON.parse(await readFile(inputPath, "utf8"));
|
|
1884
2025
|
await materializeWorkspaceProject({
|
|
1885
2026
|
...input,
|
|
@@ -1947,7 +2088,7 @@ async function runCloudLocalVerification(projectRoot, projectConfig, config) {
|
|
|
1947
2088
|
{ assertReducerContractPreflight },
|
|
1948
2089
|
{ getProjectLocalMaintainerRegistry }
|
|
1949
2090
|
] = await Promise.all([
|
|
1950
|
-
import("./static-scaffold-
|
|
2091
|
+
import("./static-scaffold-56QBCO6P.mjs"),
|
|
1951
2092
|
import("./local-files-OF4QFISU.mjs"),
|
|
1952
2093
|
import("./workspace-codegen-SPPVHURX.mjs"),
|
|
1953
2094
|
import("./workspace-dependencies-5HEEKZFP.mjs"),
|