@dreamboard-games/cli 0.1.30-alpha.0 → 0.1.30-alpha.2
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 +179 -22
- package/dist/{chunk-TSJVWTJO.js → chunk-N7XPNNUI.js} +14 -12
- package/dist/chunk-N7XPNNUI.js.map +1 -0
- package/dist/chunk-SEGVTWSK.js +44 -0
- package/dist/{chunk-3XNJT3RK.js → chunk-TAQKH67O.js} +21279 -35845
- package/dist/chunk-TAQKH67O.js.map +1 -0
- package/dist/{global-config-UKSWNDTX.js → global-config-S4ZIPECE.js} +3 -3
- package/dist/index.js +955 -230
- package/dist/index.js.map +1 -1
- package/dist/internal.js +3 -4
- package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
- package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
- package/package.json +6 -6
- package/skills/dreamboard/references/building-your-first-game.md +510 -0
- package/skills/dreamboard/references/cli.md +104 -0
- package/skills/dreamboard/references/game-interface.md +548 -0
- package/skills/dreamboard/references/manifest-authoring.md +597 -0
- package/skills/dreamboard/references/quickstart.md +66 -0
- package/skills/dreamboard/references/reducer.md +864 -0
- package/skills/dreamboard/references/rule-authoring.md +147 -0
- package/skills/dreamboard/references/testing.md +249 -0
- package/skills/dreamboard/scripts/events-extract.mjs +218 -0
- package/dist/agent-verifier/agent-workspace-verifier.mjs +0 -227
- package/dist/agent-verifier/chunk-2E5P5NWG.mjs +0 -835
- package/dist/agent-verifier/chunk-2GBBP27W.mjs +0 -301
- package/dist/agent-verifier/chunk-2NZNKIND.mjs +0 -166
- package/dist/agent-verifier/chunk-2QMNAVV4.mjs +0 -14522
- package/dist/agent-verifier/chunk-2SZHMP6F.mjs +0 -264
- package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
- package/dist/agent-verifier/chunk-6A5HRJMQ.mjs +0 -3174
- package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
- package/dist/agent-verifier/chunk-7653FPGJ.mjs +0 -381
- package/dist/agent-verifier/chunk-BVVNBJM4.mjs +0 -221
- package/dist/agent-verifier/chunk-CEDUHGNH.mjs +0 -74
- package/dist/agent-verifier/chunk-CEQ2VJWN.mjs +0 -149
- package/dist/agent-verifier/chunk-CFU5EWIC.mjs +0 -69
- package/dist/agent-verifier/chunk-DTMJCPS4.mjs +0 -730
- package/dist/agent-verifier/chunk-EIQWDQWJ.mjs +0 -186
- package/dist/agent-verifier/chunk-EOQIV6PS.mjs +0 -649
- package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
- package/dist/agent-verifier/chunk-HJFQDSTU.mjs +0 -225
- package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
- package/dist/agent-verifier/chunk-LM3OZLZG.mjs +0 -48
- package/dist/agent-verifier/chunk-MINCYHXN.mjs +0 -106
- package/dist/agent-verifier/chunk-MRCUP5SW.mjs +0 -128
- package/dist/agent-verifier/chunk-PM3SVG6R.mjs +0 -38
- package/dist/agent-verifier/chunk-RBDDIIPM.mjs +0 -19
- package/dist/agent-verifier/chunk-RJBLBYHX.mjs +0 -1681
- package/dist/agent-verifier/chunk-SHUMAVAP.mjs +0 -59
- package/dist/agent-verifier/chunk-SYPLYRGB.mjs +0 -2812
- package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
- package/dist/agent-verifier/chunk-VYJTHSYR.mjs +0 -44
- package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
- package/dist/agent-verifier/compile-WNCQQVOF.mjs +0 -313
- package/dist/agent-verifier/global-config-WX3ZZIVU.mjs +0 -17
- package/dist/agent-verifier/local-files-MTPLP62S.mjs +0 -46
- package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
- package/dist/agent-verifier/materialize-workspace-EWGZIVOY.mjs +0 -90
- package/dist/agent-verifier/project-state-7GR6BQTQ.mjs +0 -32
- package/dist/agent-verifier/reducer-bundle-preflight-C73LEXI2.mjs +0 -23
- package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
- package/dist/agent-verifier/reducer-native-test-harness-GMWBUISX.mjs +0 -53
- package/dist/agent-verifier/static-scaffold-4YEQME5N.mjs +0 -28
- package/dist/agent-verifier/sync-LOQAH4RC.mjs +0 -594
- package/dist/agent-verifier/test-YOJERVHN.mjs +0 -356
- package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
- package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
- package/dist/agent-verifier/workspace-dependencies-HZ6VVS4G.mjs +0 -14
- package/dist/chunk-2H7UOFLK.js +0 -11
- package/dist/chunk-3XNJT3RK.js.map +0 -1
- package/dist/chunk-7FOO4AJI.js +0 -50
- package/dist/chunk-7FOO4AJI.js.map +0 -1
- package/dist/chunk-TSJVWTJO.js.map +0 -1
- package/dist/internal.d.ts +0 -311
- package/dist/keychain-backend-JHTXAKWC.js +0 -135
- package/dist/prompt-GMZABCJC.js +0 -756
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
- package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
- package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
- package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
- package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
- package/dist/testing-KLSV6CPJ.js +0 -674
- package/dist/testing-KLSV6CPJ.js.map +0 -1
- /package/dist/{chunk-2H7UOFLK.js.map → chunk-SEGVTWSK.js.map} +0 -0
- /package/dist/{global-config-UKSWNDTX.js.map → global-config-S4ZIPECE.js.map} +0 -0
- /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
- /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
CONFIG_FLAG_ARGS,
|
|
4
4
|
IS_PUBLISHED_BUILD,
|
|
5
5
|
LOCAL_REGISTRY_URL,
|
|
6
|
+
PUBLISHED_ENVIRONMENT,
|
|
6
7
|
REDUCER_TESTING_TYPES_WRAPPER_CONTENT,
|
|
7
8
|
STALE_CONTRACT_ARTIFACT_CODE,
|
|
8
9
|
STALE_CONTRACT_ARTIFACT_EXIT_CODE,
|
|
@@ -12,13 +13,14 @@ import {
|
|
|
12
13
|
collectLocalFiles,
|
|
13
14
|
computeManifestHash,
|
|
14
15
|
configureClient,
|
|
15
|
-
|
|
16
|
+
createGameRevision,
|
|
16
17
|
createPkcePair,
|
|
17
|
-
|
|
18
|
+
createProjectSession,
|
|
19
|
+
createProjectSourceBlobUploadSession,
|
|
18
20
|
createSessionFromScenario,
|
|
19
21
|
didLocalMaintainerSnapshotChange,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
ensureProject,
|
|
23
|
+
ensureProjectDevCompile,
|
|
22
24
|
exchangeClerkOAuthCode,
|
|
23
25
|
external_exports,
|
|
24
26
|
findProjectCompiledResultsForRevision,
|
|
@@ -28,37 +30,34 @@ import {
|
|
|
28
30
|
getApiVersion,
|
|
29
31
|
getAuthTokenExpiry,
|
|
30
32
|
getCliErrorExitCode,
|
|
33
|
+
getCurrentAuthUser,
|
|
31
34
|
getLocalDiff,
|
|
32
35
|
getProjectAuthoringState,
|
|
33
|
-
|
|
36
|
+
getProjectBySlug,
|
|
34
37
|
getProjectCompileState,
|
|
35
38
|
getProjectCompiledResultSdk,
|
|
36
39
|
getProjectLocalMaintainerRegistry,
|
|
37
40
|
getProjectPendingAuthoringSync,
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
getProjectRevisionSources,
|
|
42
|
+
getProjectSources,
|
|
40
43
|
getSessionEventBatch,
|
|
41
44
|
getSessionSnapshot,
|
|
42
45
|
importTypeScriptModule,
|
|
43
46
|
isAllowedGamePath,
|
|
44
|
-
isAuthoritativeGeneratedPath,
|
|
45
47
|
isDreamboardApiError,
|
|
48
|
+
isDynamicGeneratedPath,
|
|
46
49
|
isDynamicSeedPath,
|
|
47
50
|
isLibraryPath,
|
|
48
51
|
isLocalMaintainerRegistryEnabled,
|
|
49
|
-
isPerPlayer,
|
|
50
52
|
isReducerNativeTestingWorkspace,
|
|
51
53
|
isStaleContractArtifactError,
|
|
52
54
|
isStaleContractArtifactMessage,
|
|
53
55
|
loadManifest,
|
|
54
56
|
loadProjectConfig,
|
|
55
|
-
loadRemoteProjectIdentity,
|
|
56
57
|
loadRule,
|
|
57
|
-
mapUpsertBlobContentsByContentHash,
|
|
58
58
|
materializeManifest,
|
|
59
|
-
materializeManifestTable,
|
|
60
|
-
materializeSourceChangeOperations,
|
|
61
59
|
normalizeSlug,
|
|
60
|
+
parseAuthCommandArgs,
|
|
62
61
|
parseCloneCommandArgs,
|
|
63
62
|
parseCompileCommandArgs,
|
|
64
63
|
parseConfigCommandArgs,
|
|
@@ -70,10 +69,11 @@ import {
|
|
|
70
69
|
parsePlayerCountFlags,
|
|
71
70
|
parsePositiveInt,
|
|
72
71
|
parsePullCommandArgs,
|
|
72
|
+
parseQueryCommandArgs,
|
|
73
73
|
parseStatusCommandArgs,
|
|
74
74
|
parseSyncCommandArgs,
|
|
75
|
-
perPlayerSchema,
|
|
76
75
|
projectIdFromSessionGameSource,
|
|
76
|
+
queryWorkshopRulebook,
|
|
77
77
|
queueProjectRevisionCompileSdk,
|
|
78
78
|
refreshResolvedAuthSession,
|
|
79
79
|
removeExtraneousFiles,
|
|
@@ -87,13 +87,13 @@ import {
|
|
|
87
87
|
setLatestCompileAttempt,
|
|
88
88
|
shortHash,
|
|
89
89
|
submitGameplayAuthorityAction,
|
|
90
|
+
titleFromSlug,
|
|
90
91
|
toApiProblem,
|
|
91
92
|
toDreamboardApiError,
|
|
92
93
|
updateProjectAuthoringState,
|
|
93
94
|
updateProjectLocalMaintainerRegistry,
|
|
94
95
|
updateProjectState,
|
|
95
|
-
|
|
96
|
-
uploadProjectSourceBlobsSdk,
|
|
96
|
+
uploadInitialProjection,
|
|
97
97
|
valueOrUndefined,
|
|
98
98
|
waitForCompiledResultJobSdk,
|
|
99
99
|
writeManifest,
|
|
@@ -101,7 +101,7 @@ import {
|
|
|
101
101
|
writeSnapshot,
|
|
102
102
|
writeSnapshotFromFiles,
|
|
103
103
|
writeSourceFiles
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-TAQKH67O.js";
|
|
105
105
|
import {
|
|
106
106
|
DEFAULT_LOGIN_TIMEOUT_MS,
|
|
107
107
|
DEFAULT_WEB_BASE_URL,
|
|
@@ -113,6 +113,7 @@ import {
|
|
|
113
113
|
clearCredentials,
|
|
114
114
|
ensureDir,
|
|
115
115
|
exists,
|
|
116
|
+
getActiveCredentialBackendName,
|
|
116
117
|
getGlobalAuthPath,
|
|
117
118
|
getGlobalConfigPath,
|
|
118
119
|
getStoredSession,
|
|
@@ -125,9 +126,11 @@ import {
|
|
|
125
126
|
setCredentials,
|
|
126
127
|
writeJsonFile,
|
|
127
128
|
writeTextFile
|
|
128
|
-
} from "./chunk-
|
|
129
|
-
import "./chunk-
|
|
130
|
-
|
|
129
|
+
} from "./chunk-N7XPNNUI.js";
|
|
130
|
+
import "./chunk-SEGVTWSK.js";
|
|
131
|
+
|
|
132
|
+
// src/commands/auth.ts
|
|
133
|
+
import crypto2 from "crypto";
|
|
131
134
|
|
|
132
135
|
// ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/_chunks/libs/scule.mjs
|
|
133
136
|
var NUMBER_CHAR_RE = /\d/;
|
|
@@ -1665,40 +1668,873 @@ function characterFormat(str) {
|
|
|
1665
1668
|
function getColor2(color = "white") {
|
|
1666
1669
|
return colors[color] || colors.white;
|
|
1667
1670
|
}
|
|
1668
|
-
function getBgColor(color = "bgWhite") {
|
|
1669
|
-
return colors[`bg${color[0].toUpperCase()}${color.slice(1)}`] || colors.bgWhite;
|
|
1671
|
+
function getBgColor(color = "bgWhite") {
|
|
1672
|
+
return colors[`bg${color[0].toUpperCase()}${color.slice(1)}`] || colors.bgWhite;
|
|
1673
|
+
}
|
|
1674
|
+
function createConsola2(options = {}) {
|
|
1675
|
+
let level = _getDefaultLogLevel();
|
|
1676
|
+
if (process.env.CONSOLA_LEVEL) {
|
|
1677
|
+
level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level;
|
|
1678
|
+
}
|
|
1679
|
+
const consola2 = createConsola({
|
|
1680
|
+
level,
|
|
1681
|
+
defaults: { level },
|
|
1682
|
+
stdout: process.stdout,
|
|
1683
|
+
stderr: process.stderr,
|
|
1684
|
+
prompt: (...args) => import("./prompt-NDV3AE5L.js").then((m) => m.prompt(...args)),
|
|
1685
|
+
reporters: options.reporters || [
|
|
1686
|
+
options.fancy ?? !(T || R) ? new FancyReporter() : new BasicReporter()
|
|
1687
|
+
],
|
|
1688
|
+
...options
|
|
1689
|
+
});
|
|
1690
|
+
return consola2;
|
|
1691
|
+
}
|
|
1692
|
+
function _getDefaultLogLevel() {
|
|
1693
|
+
if (g) {
|
|
1694
|
+
return LogLevels.debug;
|
|
1695
|
+
}
|
|
1696
|
+
if (R) {
|
|
1697
|
+
return LogLevels.warn;
|
|
1698
|
+
}
|
|
1699
|
+
return LogLevels.info;
|
|
1700
|
+
}
|
|
1701
|
+
var consola = createConsola2();
|
|
1702
|
+
|
|
1703
|
+
// src/auth/auth-server.ts
|
|
1704
|
+
import {
|
|
1705
|
+
createServer
|
|
1706
|
+
} from "http";
|
|
1707
|
+
import { spawn } from "child_process";
|
|
1708
|
+
var DEFAULT_OAUTH_CALLBACK_PORT = 49371;
|
|
1709
|
+
async function startOAuthCallbackServer(state, timeoutMs) {
|
|
1710
|
+
let resolveCode;
|
|
1711
|
+
let rejectCode;
|
|
1712
|
+
const waitForCode = new Promise((resolve, reject) => {
|
|
1713
|
+
resolveCode = resolve;
|
|
1714
|
+
rejectCode = reject;
|
|
1715
|
+
});
|
|
1716
|
+
const portCandidate = resolveOAuthCallbackPort();
|
|
1717
|
+
const server = createServer(
|
|
1718
|
+
async (request, response) => {
|
|
1719
|
+
try {
|
|
1720
|
+
const requestUrl = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
1721
|
+
if (request.method === "GET" && requestUrl.pathname === "/oauth/callback") {
|
|
1722
|
+
const receivedState = requestUrl.searchParams.get("state");
|
|
1723
|
+
const code = requestUrl.searchParams.get("code");
|
|
1724
|
+
const error = requestUrl.searchParams.get("error");
|
|
1725
|
+
if (error) {
|
|
1726
|
+
throw new Error(`Clerk OAuth returned ${error}.`);
|
|
1727
|
+
}
|
|
1728
|
+
if (!code || receivedState !== state) {
|
|
1729
|
+
writeCorsResponse(request, response, 400, "Invalid OAuth callback");
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
resolveCode({ code });
|
|
1733
|
+
response.once("finish", () => server.close());
|
|
1734
|
+
writeHtmlResponse(
|
|
1735
|
+
response,
|
|
1736
|
+
200,
|
|
1737
|
+
"Dreamboard CLI login complete. You can return to your terminal."
|
|
1738
|
+
);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
writeHtmlResponse(
|
|
1742
|
+
response,
|
|
1743
|
+
200,
|
|
1744
|
+
"Dreamboard CLI OAuth callback server"
|
|
1745
|
+
);
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
rejectCode(
|
|
1748
|
+
error instanceof Error ? error : new Error("Failed to handle OAuth callback.")
|
|
1749
|
+
);
|
|
1750
|
+
writeHtmlResponse(response, 500, "Dreamboard CLI login failed.");
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
);
|
|
1754
|
+
try {
|
|
1755
|
+
await new Promise((resolve, reject) => {
|
|
1756
|
+
server.once("error", reject);
|
|
1757
|
+
server.listen(portCandidate, "127.0.0.1", () => {
|
|
1758
|
+
server.off("error", reject);
|
|
1759
|
+
resolve();
|
|
1760
|
+
});
|
|
1761
|
+
});
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
const portError = error instanceof Error ? error : new Error("Failed to start OAuth callback server");
|
|
1764
|
+
const configuredByEnv = Boolean(
|
|
1765
|
+
process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT
|
|
1766
|
+
);
|
|
1767
|
+
const message = configuredByEnv ? `Failed to start OAuth callback server on configured port ${portCandidate}.` : `Failed to start OAuth callback server on port ${portCandidate}. Register this loopback redirect URI with Clerk and keep the port available, or set DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT.`;
|
|
1768
|
+
const wrapped = new Error(`${message} ${portError.message}`);
|
|
1769
|
+
server.close();
|
|
1770
|
+
rejectCode(wrapped);
|
|
1771
|
+
throw wrapped;
|
|
1772
|
+
}
|
|
1773
|
+
if (!server.listening) {
|
|
1774
|
+
const error = new Error("Failed to start OAuth callback server.");
|
|
1775
|
+
rejectCode(error);
|
|
1776
|
+
throw error;
|
|
1777
|
+
}
|
|
1778
|
+
const timer = setTimeout(() => {
|
|
1779
|
+
rejectCode(new Error("Login timed out."));
|
|
1780
|
+
server?.close();
|
|
1781
|
+
}, timeoutMs);
|
|
1782
|
+
waitForCode.finally(() => clearTimeout(timer));
|
|
1783
|
+
const port = portCandidateFromServer(server);
|
|
1784
|
+
return {
|
|
1785
|
+
port,
|
|
1786
|
+
redirectUri: `http://127.0.0.1:${port}/oauth/callback`,
|
|
1787
|
+
waitForCode,
|
|
1788
|
+
close: () => server?.close()
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
function resolveOAuthCallbackPort() {
|
|
1792
|
+
const rawPort = process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT?.trim();
|
|
1793
|
+
if (!rawPort) {
|
|
1794
|
+
return DEFAULT_OAUTH_CALLBACK_PORT;
|
|
1795
|
+
}
|
|
1796
|
+
const port = Number(rawPort);
|
|
1797
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
1798
|
+
throw new Error(
|
|
1799
|
+
`Invalid DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT '${rawPort}'. Expected a TCP port from 1 to 65535.`
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
return port;
|
|
1803
|
+
}
|
|
1804
|
+
function portCandidateFromServer(server) {
|
|
1805
|
+
const address = server.address();
|
|
1806
|
+
if (!address || typeof address === "string") {
|
|
1807
|
+
throw new Error("Auth callback server did not expose a bound port.");
|
|
1808
|
+
}
|
|
1809
|
+
return address.port;
|
|
1810
|
+
}
|
|
1811
|
+
function writeCorsResponse(request, response, statusCode, body) {
|
|
1812
|
+
const origin = request.headers.origin ?? "*";
|
|
1813
|
+
response.writeHead(statusCode, {
|
|
1814
|
+
"Access-Control-Allow-Origin": origin,
|
|
1815
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
1816
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
1817
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
1818
|
+
});
|
|
1819
|
+
response.end(body);
|
|
1820
|
+
}
|
|
1821
|
+
function writeHtmlResponse(response, statusCode, body) {
|
|
1822
|
+
response.writeHead(statusCode, {
|
|
1823
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1824
|
+
});
|
|
1825
|
+
response.end(
|
|
1826
|
+
`<!doctype html><meta charset="utf-8"><title>Dreamboard CLI</title><p>${escapeHtml(body)}</p>`
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
function escapeHtml(value) {
|
|
1830
|
+
return value.replace(/[&<>"']/g, (char) => {
|
|
1831
|
+
switch (char) {
|
|
1832
|
+
case "&":
|
|
1833
|
+
return "&";
|
|
1834
|
+
case "<":
|
|
1835
|
+
return "<";
|
|
1836
|
+
case ">":
|
|
1837
|
+
return ">";
|
|
1838
|
+
case '"':
|
|
1839
|
+
return """;
|
|
1840
|
+
default:
|
|
1841
|
+
return "'";
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
function openBrowser(url) {
|
|
1846
|
+
const platform2 = process.platform;
|
|
1847
|
+
let command;
|
|
1848
|
+
if (platform2 === "darwin") {
|
|
1849
|
+
command = ["open", url];
|
|
1850
|
+
} else if (platform2 === "win32") {
|
|
1851
|
+
command = ["cmd", "/c", "start", "", url];
|
|
1852
|
+
} else {
|
|
1853
|
+
command = ["xdg-open", url];
|
|
1854
|
+
}
|
|
1855
|
+
const [commandName, ...commandArgs] = command;
|
|
1856
|
+
const child = spawn(commandName, commandArgs, {
|
|
1857
|
+
stdio: "ignore",
|
|
1858
|
+
detached: true
|
|
1859
|
+
});
|
|
1860
|
+
child.unref();
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
// src/commands/auth.ts
|
|
1864
|
+
async function loginWithBrowser(config, quiet) {
|
|
1865
|
+
const state = crypto2.randomUUID();
|
|
1866
|
+
const pkce = createPkcePair();
|
|
1867
|
+
const server = await startOAuthCallbackServer(
|
|
1868
|
+
state,
|
|
1869
|
+
DEFAULT_LOGIN_TIMEOUT_MS
|
|
1870
|
+
);
|
|
1871
|
+
const loginUrl = buildClerkAuthorizationUrl({
|
|
1872
|
+
config: {
|
|
1873
|
+
issuer: config.clerkOAuthIssuer,
|
|
1874
|
+
clientId: config.clerkOAuthClientId,
|
|
1875
|
+
tokenUrl: config.clerkOAuthTokenUrl,
|
|
1876
|
+
scope: config.clerkOAuthScope
|
|
1877
|
+
},
|
|
1878
|
+
redirectUri: server.redirectUri,
|
|
1879
|
+
state,
|
|
1880
|
+
codeChallenge: pkce.challenge
|
|
1881
|
+
}).toString();
|
|
1882
|
+
if (!quiet) {
|
|
1883
|
+
consola.info("Opening browser for login...");
|
|
1884
|
+
consola.info(`If the browser does not open, visit: ${loginUrl}`);
|
|
1885
|
+
}
|
|
1886
|
+
openBrowser(loginUrl);
|
|
1887
|
+
if (!quiet) {
|
|
1888
|
+
consola.start("Waiting for login to complete...");
|
|
1889
|
+
}
|
|
1890
|
+
try {
|
|
1891
|
+
const { code } = await server.waitForCode;
|
|
1892
|
+
const tokenResponse = await exchangeClerkOAuthCode({
|
|
1893
|
+
config: {
|
|
1894
|
+
issuer: config.clerkOAuthIssuer,
|
|
1895
|
+
clientId: config.clerkOAuthClientId,
|
|
1896
|
+
tokenUrl: config.clerkOAuthTokenUrl
|
|
1897
|
+
},
|
|
1898
|
+
code,
|
|
1899
|
+
redirectUri: server.redirectUri,
|
|
1900
|
+
codeVerifier: pkce.verifier
|
|
1901
|
+
});
|
|
1902
|
+
return {
|
|
1903
|
+
token: tokenResponse.accessToken,
|
|
1904
|
+
refreshToken: tokenResponse.refreshToken,
|
|
1905
|
+
expiresAt: tokenResponse.expiresAt,
|
|
1906
|
+
tokenUrl: tokenResponse.tokenUrl
|
|
1907
|
+
};
|
|
1908
|
+
} finally {
|
|
1909
|
+
server.close();
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
var auth_default = defineCommand({
|
|
1913
|
+
meta: { name: "auth", description: "Manage stored Dreamboard sessions" },
|
|
1914
|
+
args: {
|
|
1915
|
+
action: {
|
|
1916
|
+
type: "positional",
|
|
1917
|
+
description: IS_PUBLISHED_BUILD ? "Action: clear | login" : "Action: set | clear | login | env | status",
|
|
1918
|
+
required: true
|
|
1919
|
+
},
|
|
1920
|
+
...IS_PUBLISHED_BUILD ? {} : {
|
|
1921
|
+
tokenValue: {
|
|
1922
|
+
type: "positional",
|
|
1923
|
+
description: "Token value (for set) or environment name (for env)",
|
|
1924
|
+
required: false
|
|
1925
|
+
},
|
|
1926
|
+
token: {
|
|
1927
|
+
type: "string",
|
|
1928
|
+
description: "Auth token (alternative)"
|
|
1929
|
+
},
|
|
1930
|
+
jwt: {
|
|
1931
|
+
type: "boolean",
|
|
1932
|
+
description: "Print auth token JSON to stdout"
|
|
1933
|
+
},
|
|
1934
|
+
env: {
|
|
1935
|
+
type: "string",
|
|
1936
|
+
description: "Environment: local | staging | prod"
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
},
|
|
1940
|
+
async run({ args }) {
|
|
1941
|
+
const parsedArgs = parseAuthCommandArgs(args);
|
|
1942
|
+
const action = parsedArgs.action;
|
|
1943
|
+
const globalConfig = await loadGlobalConfig();
|
|
1944
|
+
if (IS_PUBLISHED_BUILD && action !== "login" && action !== "clear") {
|
|
1945
|
+
throw new Error(
|
|
1946
|
+
"The published Dreamboard CLI only supports browser login and logout. Use `dreamboard login` or `dreamboard logout`."
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
if (action === "env") {
|
|
1950
|
+
if (IS_PUBLISHED_BUILD) {
|
|
1951
|
+
throw new Error(
|
|
1952
|
+
"The published Dreamboard CLI is production-only and does not support switching environments."
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
const environment = parsedArgs.tokenValue ?? parsedArgs.env;
|
|
1956
|
+
if (!environment) {
|
|
1957
|
+
throw new Error("Usage: dreamboard auth env <local|staging|prod>");
|
|
1958
|
+
}
|
|
1959
|
+
if (!["local", "staging", "prod"].includes(environment)) {
|
|
1960
|
+
throw new Error(
|
|
1961
|
+
`Invalid environment '${environment}'. Valid options: local, staging, prod`
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
await saveGlobalConfig({
|
|
1965
|
+
...globalConfig,
|
|
1966
|
+
environment
|
|
1967
|
+
});
|
|
1968
|
+
consola.success(`Environment set to '${environment}'.`);
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
if (action === "set") {
|
|
1972
|
+
if (IS_PUBLISHED_BUILD) {
|
|
1973
|
+
throw new Error(
|
|
1974
|
+
"Direct JWT injection is not supported in the published Dreamboard CLI. Use `dreamboard login` so the CLI can store a refreshable session."
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
const token = parsedArgs.tokenValue ?? parsedArgs.token ?? "";
|
|
1978
|
+
if (!token) throw new Error("Usage: dreamboard auth set <token>");
|
|
1979
|
+
await setAccessOnlySession(token);
|
|
1980
|
+
consola.success(`Auth token saved to ${getGlobalAuthPath()}.`);
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
if (action === "clear") {
|
|
1984
|
+
await clearCredentials();
|
|
1985
|
+
consola.success(
|
|
1986
|
+
`Stored Dreamboard session cleared from ${getGlobalAuthPath()}.`
|
|
1987
|
+
);
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
if (action === "login") {
|
|
1991
|
+
const shouldPrintJwt = !IS_PUBLISHED_BUILD && parsedArgs.jwt === true;
|
|
1992
|
+
const environment = IS_PUBLISHED_BUILD ? PUBLISHED_ENVIRONMENT : parsedArgs.env || globalConfig.environment || "staging";
|
|
1993
|
+
const storedSession = await getStoredSession();
|
|
1994
|
+
let accessToken = storedSession?.accessToken;
|
|
1995
|
+
let refreshToken = storedSession?.refreshToken;
|
|
1996
|
+
let tokenExpiresAt = storedSession?.tokenExpiresAt;
|
|
1997
|
+
let clerkOAuthTokenUrl = storedSession?.clerkOAuthTokenUrl;
|
|
1998
|
+
let didRefreshStoredSession = false;
|
|
1999
|
+
let didUseBrowserLogin = false;
|
|
2000
|
+
const resolvedConfig = resolveConfig(
|
|
2001
|
+
globalConfig,
|
|
2002
|
+
{ env: environment },
|
|
2003
|
+
void 0,
|
|
2004
|
+
storedSession
|
|
2005
|
+
);
|
|
2006
|
+
if (accessToken && refreshToken) {
|
|
2007
|
+
try {
|
|
2008
|
+
const refreshed = await refreshResolvedAuthSession(resolvedConfig);
|
|
2009
|
+
accessToken = refreshed?.accessToken ?? accessToken;
|
|
2010
|
+
refreshToken = refreshed?.refreshToken ?? refreshToken;
|
|
2011
|
+
tokenExpiresAt = refreshed?.tokenExpiresAt ?? tokenExpiresAt;
|
|
2012
|
+
clerkOAuthTokenUrl = refreshed?.clerkOAuthTokenUrl ?? clerkOAuthTokenUrl;
|
|
2013
|
+
didRefreshStoredSession = Boolean(refreshed);
|
|
2014
|
+
} catch (error) {
|
|
2015
|
+
consola.warn(
|
|
2016
|
+
error instanceof Error ? error.message : "Stored Dreamboard CLI session refresh failed."
|
|
2017
|
+
);
|
|
2018
|
+
accessToken = void 0;
|
|
2019
|
+
refreshToken = void 0;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
if (!accessToken) {
|
|
2023
|
+
const browserLogin = await loginWithBrowser(
|
|
2024
|
+
resolvedConfig,
|
|
2025
|
+
shouldPrintJwt
|
|
2026
|
+
);
|
|
2027
|
+
accessToken = browserLogin.token;
|
|
2028
|
+
refreshToken = browserLogin.refreshToken;
|
|
2029
|
+
tokenExpiresAt = browserLogin.expiresAt;
|
|
2030
|
+
clerkOAuthTokenUrl = browserLogin.tokenUrl;
|
|
2031
|
+
didUseBrowserLogin = true;
|
|
2032
|
+
}
|
|
2033
|
+
if (!accessToken) {
|
|
2034
|
+
throw new Error("Login completed but no access token was returned.");
|
|
2035
|
+
}
|
|
2036
|
+
await saveGlobalConfig({
|
|
2037
|
+
...globalConfig,
|
|
2038
|
+
environment
|
|
2039
|
+
});
|
|
2040
|
+
if (refreshToken) {
|
|
2041
|
+
await setCredentials({
|
|
2042
|
+
accessToken,
|
|
2043
|
+
refreshToken,
|
|
2044
|
+
tokenExpiresAt,
|
|
2045
|
+
clerkOAuthIssuer: resolvedConfig.clerkOAuthIssuer,
|
|
2046
|
+
clerkOAuthClientId: resolvedConfig.clerkOAuthClientId,
|
|
2047
|
+
clerkOAuthTokenUrl,
|
|
2048
|
+
environment
|
|
2049
|
+
});
|
|
2050
|
+
} else {
|
|
2051
|
+
await setAccessOnlySession(accessToken);
|
|
2052
|
+
}
|
|
2053
|
+
if (shouldPrintJwt) {
|
|
2054
|
+
process.stdout.write(
|
|
2055
|
+
`${JSON.stringify(
|
|
2056
|
+
{
|
|
2057
|
+
token: accessToken,
|
|
2058
|
+
refreshToken: refreshToken ?? null,
|
|
2059
|
+
environment
|
|
2060
|
+
},
|
|
2061
|
+
null,
|
|
2062
|
+
2
|
|
2063
|
+
)}
|
|
2064
|
+
`
|
|
2065
|
+
);
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
if (didUseBrowserLogin) {
|
|
2069
|
+
consola.success(
|
|
2070
|
+
`Browser login successful. Session saved to ${getGlobalAuthPath()}`
|
|
2071
|
+
);
|
|
2072
|
+
} else if (storedSession?.accessToken && didRefreshStoredSession) {
|
|
2073
|
+
consola.success(
|
|
2074
|
+
`Stored auth session refreshed and saved to ${getGlobalAuthPath()}`
|
|
2075
|
+
);
|
|
2076
|
+
} else if (storedSession?.accessToken) {
|
|
2077
|
+
consola.success(
|
|
2078
|
+
`Stored auth token found. Session data remains in ${getGlobalAuthPath()}`
|
|
2079
|
+
);
|
|
2080
|
+
}
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
if (action === "status") {
|
|
2084
|
+
const storedSession = await getStoredSession();
|
|
2085
|
+
const resolvedConfig = resolveConfig(
|
|
2086
|
+
globalConfig,
|
|
2087
|
+
{ env: parsedArgs.env },
|
|
2088
|
+
void 0,
|
|
2089
|
+
storedSession
|
|
2090
|
+
);
|
|
2091
|
+
const environment = parsedArgs.env || globalConfig.environment || "staging";
|
|
2092
|
+
const authTokenExpiry = getAuthTokenExpiry(resolvedConfig.authToken);
|
|
2093
|
+
const backendName = await getActiveCredentialBackendName();
|
|
2094
|
+
consola.log(`Environment: ${environment}`);
|
|
2095
|
+
consola.log(`Auth token source: ${resolvedConfig.authTokenSource}`);
|
|
2096
|
+
consola.log(`Refresh token source: ${resolvedConfig.refreshTokenSource}`);
|
|
2097
|
+
consola.log(
|
|
2098
|
+
`Credential backend: ${backendName}${backendName === "keychain" ? " (OS keychain via @napi-rs/keyring)" : ` (${getGlobalAuthPath()})`}`
|
|
2099
|
+
);
|
|
2100
|
+
const preference = globalConfig.credentialBackend;
|
|
2101
|
+
if (preference) {
|
|
2102
|
+
consola.log(`Credential backend preference (config): ${preference}`);
|
|
2103
|
+
} else {
|
|
2104
|
+
consola.log(
|
|
2105
|
+
'Credential backend preference (config): file (default; set `"credentialBackend": "keychain"` in config.json to opt in)'
|
|
2106
|
+
);
|
|
2107
|
+
}
|
|
2108
|
+
if (process.env.DREAMBOARD_CREDENTIAL_BACKEND) {
|
|
2109
|
+
consola.log(
|
|
2110
|
+
`Backend override: DREAMBOARD_CREDENTIAL_BACKEND=${process.env.DREAMBOARD_CREDENTIAL_BACKEND}`
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
consola.log(`Config path: ${getGlobalConfigPath()}`);
|
|
2114
|
+
if (!resolvedConfig.authToken) {
|
|
2115
|
+
consola.warn("No Dreamboard session found.");
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
if (authTokenExpiry) {
|
|
2119
|
+
const isExpired = authTokenExpiry.getTime() <= Date.now();
|
|
2120
|
+
consola.log(
|
|
2121
|
+
`Access token expires at: ${authTokenExpiry.toISOString()} (${isExpired ? "expired" : "active"})`
|
|
2122
|
+
);
|
|
2123
|
+
if (isExpired) {
|
|
2124
|
+
if (!resolvedConfig.refreshToken) {
|
|
2125
|
+
consola.warn(
|
|
2126
|
+
"Access token is expired and no refresh token is available. Run `dreamboard login` to authenticate again."
|
|
2127
|
+
);
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
const refreshed = await refreshResolvedAuthSession(resolvedConfig);
|
|
2131
|
+
if (!refreshed?.accessToken) {
|
|
2132
|
+
consola.warn(
|
|
2133
|
+
"Access token is expired and refresh did not return a new session."
|
|
2134
|
+
);
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
const refreshedExpiry = getAuthTokenExpiry(refreshed.accessToken);
|
|
2138
|
+
consola.success("Access token was expired and has been refreshed.");
|
|
2139
|
+
if (refreshedExpiry) {
|
|
2140
|
+
consola.log(
|
|
2141
|
+
`Refreshed access token expires at: ${refreshedExpiry.toISOString()}`
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
} else {
|
|
2147
|
+
consola.log("Access token expiry: unavailable");
|
|
2148
|
+
}
|
|
2149
|
+
consola.success("Dreamboard session is active.");
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
throw new Error(
|
|
2153
|
+
IS_PUBLISHED_BUILD ? "Usage:\n dreamboard auth clear\n dreamboard auth login" : "Usage:\n dreamboard auth clear\n dreamboard auth login [--env <local|staging|prod>] [--jwt]\n dreamboard auth set <token>\n dreamboard auth env <local|staging|prod>\n dreamboard auth status [--env <local|staging|prod>]"
|
|
2154
|
+
);
|
|
2155
|
+
}
|
|
2156
|
+
});
|
|
2157
|
+
|
|
2158
|
+
// src/commands/query.ts
|
|
2159
|
+
var query_default = defineCommand({
|
|
2160
|
+
meta: {
|
|
2161
|
+
name: "query",
|
|
2162
|
+
description: "Query rulebook text by title"
|
|
2163
|
+
},
|
|
2164
|
+
args: {
|
|
2165
|
+
title: {
|
|
2166
|
+
type: "positional",
|
|
2167
|
+
description: "Board game title to search in the rulebook library",
|
|
2168
|
+
required: true
|
|
2169
|
+
},
|
|
2170
|
+
...CONFIG_FLAG_ARGS
|
|
2171
|
+
},
|
|
2172
|
+
async run({ args }) {
|
|
2173
|
+
const parsedArgs = parseQueryCommandArgs(args);
|
|
2174
|
+
const [globalConfig, storedSession] = await Promise.all([
|
|
2175
|
+
loadGlobalConfig(),
|
|
2176
|
+
getStoredSession()
|
|
2177
|
+
]);
|
|
2178
|
+
const config = resolveConfig(
|
|
2179
|
+
globalConfig,
|
|
2180
|
+
parsedArgs,
|
|
2181
|
+
void 0,
|
|
2182
|
+
storedSession
|
|
2183
|
+
);
|
|
2184
|
+
requireAuth(config);
|
|
2185
|
+
await configureClient(config);
|
|
2186
|
+
const { data, error, response } = await queryWorkshopRulebook({
|
|
2187
|
+
query: {
|
|
2188
|
+
title: parsedArgs.title
|
|
2189
|
+
}
|
|
2190
|
+
});
|
|
2191
|
+
if (!data) {
|
|
2192
|
+
throw toDreamboardApiError(
|
|
2193
|
+
error,
|
|
2194
|
+
response,
|
|
2195
|
+
`Failed to query rulebook for '${parsedArgs.title}'`
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2198
|
+
console.log(data.ruleText);
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
|
|
2202
|
+
// src/commands/clone.ts
|
|
2203
|
+
import path5 from "path";
|
|
2204
|
+
|
|
2205
|
+
// src/services/api/project-api.ts
|
|
2206
|
+
async function loadRemoteProjectIdentity() {
|
|
2207
|
+
const [versionResponse, userResponse] = await Promise.all([
|
|
2208
|
+
getApiVersion(),
|
|
2209
|
+
getCurrentAuthUser()
|
|
2210
|
+
]);
|
|
2211
|
+
if (versionResponse.error || !versionResponse.data) {
|
|
2212
|
+
throw toDreamboardApiError(
|
|
2213
|
+
versionResponse.error,
|
|
2214
|
+
versionResponse.response,
|
|
2215
|
+
"Failed to resolve backend deployment identity"
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
if (userResponse.error || !userResponse.data) {
|
|
2219
|
+
throw toDreamboardApiError(
|
|
2220
|
+
userResponse.error,
|
|
2221
|
+
userResponse.response,
|
|
2222
|
+
"Failed to resolve authenticated owner scope"
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
const deploymentId = versionResponse.data.deploymentId;
|
|
2226
|
+
const ownerScopeId = userResponse.data.ownerScopeId;
|
|
2227
|
+
return {
|
|
2228
|
+
deploymentId,
|
|
2229
|
+
ownerScopeId,
|
|
2230
|
+
bindingKey: `${deploymentId}:${ownerScopeId}`
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
async function ensureProjectSdk(options) {
|
|
2234
|
+
const { data, error, response } = await ensureProject({
|
|
2235
|
+
path: { projectId: options.projectId },
|
|
2236
|
+
body: {
|
|
2237
|
+
slug: options.slug,
|
|
2238
|
+
name: titleFromSlug(options.slug),
|
|
2239
|
+
description: options.description ?? `Dreamboard workspace for ${options.slug}.`,
|
|
2240
|
+
...options.updateAlias ? { updateAlias: true } : {}
|
|
2241
|
+
}
|
|
2242
|
+
});
|
|
2243
|
+
if (error || !data) {
|
|
2244
|
+
throw toDreamboardApiError(error, response, "Failed to ensure project");
|
|
2245
|
+
}
|
|
2246
|
+
return data;
|
|
2247
|
+
}
|
|
2248
|
+
async function getProjectBySlugSdk(slug) {
|
|
2249
|
+
const { data, error, response } = await getProjectBySlug({
|
|
2250
|
+
path: { slug }
|
|
2251
|
+
});
|
|
2252
|
+
if (error || !data) {
|
|
2253
|
+
throw toDreamboardApiError(
|
|
2254
|
+
error,
|
|
2255
|
+
response,
|
|
2256
|
+
`Project '${slug}' not found`
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
return data;
|
|
2260
|
+
}
|
|
2261
|
+
async function createGameRevisionSdk(options) {
|
|
2262
|
+
const { data, error, response } = await createGameRevision({
|
|
2263
|
+
path: { projectId: options.projectId },
|
|
2264
|
+
body: options.request
|
|
2265
|
+
});
|
|
2266
|
+
if (error || !data) {
|
|
2267
|
+
throw toDreamboardApiError(
|
|
2268
|
+
error,
|
|
2269
|
+
response,
|
|
2270
|
+
"Failed to create game revision"
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
return data;
|
|
2274
|
+
}
|
|
2275
|
+
async function getProjectSourcesSdk(projectId) {
|
|
2276
|
+
const { data, error, response } = await getProjectSources({
|
|
2277
|
+
path: { projectId }
|
|
2278
|
+
});
|
|
2279
|
+
if (response?.status === 404) {
|
|
2280
|
+
return null;
|
|
2281
|
+
}
|
|
2282
|
+
if (error || !data) {
|
|
2283
|
+
throw toDreamboardApiError(
|
|
2284
|
+
error,
|
|
2285
|
+
response,
|
|
2286
|
+
"Failed to fetch project sources"
|
|
2287
|
+
);
|
|
2288
|
+
}
|
|
2289
|
+
return data;
|
|
2290
|
+
}
|
|
2291
|
+
async function getProjectRevisionSourcesSdk(options) {
|
|
2292
|
+
const { data, error, response } = await getProjectRevisionSources({
|
|
2293
|
+
path: {
|
|
2294
|
+
projectId: options.projectId,
|
|
2295
|
+
revisionDigest: options.revisionDigest
|
|
2296
|
+
}
|
|
2297
|
+
});
|
|
2298
|
+
if (error || !data) {
|
|
2299
|
+
throw toDreamboardApiError(
|
|
2300
|
+
error,
|
|
2301
|
+
response,
|
|
2302
|
+
"Failed to fetch project revision sources"
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
return data;
|
|
2306
|
+
}
|
|
2307
|
+
async function ensureProjectDevCompileSdk(options) {
|
|
2308
|
+
const { data, error, response } = await ensureProjectDevCompile({
|
|
2309
|
+
path: { projectId: options.projectId },
|
|
2310
|
+
body: options.request
|
|
2311
|
+
});
|
|
2312
|
+
if (error || !data) {
|
|
2313
|
+
throw toDreamboardApiError(error, response, "Failed to ensure dev compile");
|
|
2314
|
+
}
|
|
2315
|
+
return data;
|
|
2316
|
+
}
|
|
2317
|
+
async function createProjectSessionSdk(options) {
|
|
2318
|
+
const { data, error, response } = await createProjectSession({
|
|
2319
|
+
path: { projectId: options.projectId },
|
|
2320
|
+
body: options.request
|
|
2321
|
+
});
|
|
2322
|
+
if (error || !data) {
|
|
2323
|
+
throw toDreamboardApiError(error, response, "Failed to create session");
|
|
2324
|
+
}
|
|
2325
|
+
return data;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
// src/services/api/preview-api.ts
|
|
2329
|
+
async function uploadInitialProjectionSdk(gameId, projectionJson) {
|
|
2330
|
+
const { error, response } = await uploadInitialProjection({
|
|
2331
|
+
path: { gameId },
|
|
2332
|
+
body: { projectionJson }
|
|
2333
|
+
});
|
|
2334
|
+
if (error) {
|
|
2335
|
+
throw toDreamboardApiError(
|
|
2336
|
+
error,
|
|
2337
|
+
response,
|
|
2338
|
+
"Failed to upload initial preview projection"
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
// ../../packages/api-client/dist/source-revisions.js
|
|
2344
|
+
var textEncoder = new TextEncoder();
|
|
2345
|
+
function bytesToHex(bytes) {
|
|
2346
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2347
|
+
}
|
|
2348
|
+
async function sha256Hex(bytes) {
|
|
2349
|
+
const normalizedBytes = new Uint8Array(bytes.byteLength);
|
|
2350
|
+
normalizedBytes.set(bytes);
|
|
2351
|
+
const digest = await crypto.subtle.digest("SHA-256", normalizedBytes.buffer);
|
|
2352
|
+
return bytesToHex(new Uint8Array(digest));
|
|
2353
|
+
}
|
|
2354
|
+
function getUtf8ByteSize(content) {
|
|
2355
|
+
return textEncoder.encode(content).byteLength;
|
|
2356
|
+
}
|
|
2357
|
+
async function computeSourceContentHash(content) {
|
|
2358
|
+
return sha256Hex(textEncoder.encode(content));
|
|
2359
|
+
}
|
|
2360
|
+
async function describeSourceBlob(content) {
|
|
2361
|
+
return {
|
|
2362
|
+
contentHash: await computeSourceContentHash(content),
|
|
2363
|
+
byteSize: getUtf8ByteSize(content)
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
async function materializeSourceChangeOperations(changes) {
|
|
2367
|
+
const blobsByHash = /* @__PURE__ */ new Map();
|
|
2368
|
+
const materialized = await Promise.all(Array.from(changes, async (change) => {
|
|
2369
|
+
if (change.kind === "delete") {
|
|
2370
|
+
return change;
|
|
2371
|
+
}
|
|
2372
|
+
const blob = await describeSourceBlob(change.content);
|
|
2373
|
+
const existing = blobsByHash.get(blob.contentHash);
|
|
2374
|
+
if (!existing) {
|
|
2375
|
+
blobsByHash.set(blob.contentHash, blob);
|
|
2376
|
+
}
|
|
2377
|
+
return {
|
|
2378
|
+
kind: "upsert",
|
|
2379
|
+
path: change.path,
|
|
2380
|
+
contentHash: blob.contentHash,
|
|
2381
|
+
byteSize: blob.byteSize
|
|
2382
|
+
};
|
|
2383
|
+
}));
|
|
2384
|
+
return {
|
|
2385
|
+
blobs: Array.from(blobsByHash.values()).sort((left, right) => left.contentHash.localeCompare(right.contentHash)),
|
|
2386
|
+
changes: materialized
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
function mapUpsertBlobContentsByContentHash(localChanges, materializedChanges) {
|
|
2390
|
+
const uploadBlobs = /* @__PURE__ */ new Map();
|
|
2391
|
+
const length = Math.min(localChanges.length, materializedChanges.length);
|
|
2392
|
+
for (let index = 0; index < length; index += 1) {
|
|
2393
|
+
const localChange = localChanges[index];
|
|
2394
|
+
const materializedChange = materializedChanges[index];
|
|
2395
|
+
if (localChange?.kind !== "upsert" || materializedChange?.kind !== "upsert") {
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2398
|
+
uploadBlobs.set(materializedChange.contentHash, {
|
|
2399
|
+
contentHash: materializedChange.contentHash,
|
|
2400
|
+
byteSize: materializedChange.byteSize,
|
|
2401
|
+
content: localChange.content
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
return uploadBlobs;
|
|
2405
|
+
}
|
|
2406
|
+
var SourceBlobUploadError = class extends Error {
|
|
2407
|
+
constructor(status, details) {
|
|
2408
|
+
const suffix = details.trim().length > 0 ? `: ${details.trim()}` : "";
|
|
2409
|
+
super(`Failed to upload source blob (HTTP ${status}${suffix})`);
|
|
2410
|
+
this.name = "SourceBlobUploadError";
|
|
2411
|
+
this.status = status;
|
|
2412
|
+
this.details = details;
|
|
2413
|
+
}
|
|
2414
|
+
};
|
|
2415
|
+
function isDuplicateDirectUploadError(error) {
|
|
2416
|
+
if (!(error instanceof SourceBlobUploadError)) {
|
|
2417
|
+
return false;
|
|
2418
|
+
}
|
|
2419
|
+
if (error.status === 409) {
|
|
2420
|
+
return true;
|
|
2421
|
+
}
|
|
2422
|
+
const normalizedDetails = error.details.toLowerCase();
|
|
2423
|
+
return normalizedDetails.includes("duplicate") || normalizedDetails.includes("already exists") || normalizedDetails.includes("resource already exists");
|
|
2424
|
+
}
|
|
2425
|
+
async function uploadSourceBlob(uploadTarget, content) {
|
|
2426
|
+
const response = await fetch(uploadTarget.url, {
|
|
2427
|
+
method: uploadTarget.method,
|
|
2428
|
+
headers: uploadTarget.headers,
|
|
2429
|
+
body: textEncoder.encode(content)
|
|
2430
|
+
});
|
|
2431
|
+
if (response.ok) {
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2434
|
+
const details = await response.text().catch(() => "");
|
|
2435
|
+
throw new SourceBlobUploadError(response.status, details);
|
|
1670
2436
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
2437
|
+
var SourceBlobSessionRequestError = class extends Error {
|
|
2438
|
+
constructor(message, apiError, response) {
|
|
2439
|
+
super(message);
|
|
2440
|
+
this.name = "SourceBlobSessionRequestError";
|
|
2441
|
+
this.apiError = apiError;
|
|
2442
|
+
this.response = response;
|
|
2443
|
+
}
|
|
2444
|
+
};
|
|
2445
|
+
function assertSourceBlobUploadSession(data, response) {
|
|
2446
|
+
if (!data || typeof data !== "object" || !Array.isArray(data.uploads)) {
|
|
2447
|
+
throw new SourceBlobSessionRequestError("Source blob upload session response did not include an uploads array", data, response);
|
|
1675
2448
|
}
|
|
1676
|
-
const consola2 = createConsola({
|
|
1677
|
-
level,
|
|
1678
|
-
defaults: { level },
|
|
1679
|
-
stdout: process.stdout,
|
|
1680
|
-
stderr: process.stderr,
|
|
1681
|
-
prompt: (...args) => import("./prompt-GMZABCJC.js").then((m) => m.prompt(...args)),
|
|
1682
|
-
reporters: options.reporters || [
|
|
1683
|
-
options.fancy ?? !(T || R) ? new FancyReporter() : new BasicReporter()
|
|
1684
|
-
],
|
|
1685
|
-
...options
|
|
1686
|
-
});
|
|
1687
|
-
return consola2;
|
|
1688
2449
|
}
|
|
1689
|
-
function
|
|
1690
|
-
|
|
1691
|
-
|
|
2450
|
+
async function confirmSourceBlobAlreadyExists(options) {
|
|
2451
|
+
const { requestUploadSession, blob } = options;
|
|
2452
|
+
const { data, error, response } = await requestUploadSession([
|
|
2453
|
+
{
|
|
2454
|
+
contentHash: blob.contentHash,
|
|
2455
|
+
byteSize: blob.byteSize
|
|
2456
|
+
}
|
|
2457
|
+
]);
|
|
2458
|
+
if (error || !data) {
|
|
2459
|
+
throw new SourceBlobSessionRequestError("Failed to create source blob upload session", error, response);
|
|
2460
|
+
}
|
|
2461
|
+
assertSourceBlobUploadSession(data, response);
|
|
2462
|
+
return data.uploads[0]?.status === "exists";
|
|
2463
|
+
}
|
|
2464
|
+
async function uploadSourceBlobs(options) {
|
|
2465
|
+
const { blobs, requestUploadSession } = options;
|
|
2466
|
+
const uniqueBlobs = /* @__PURE__ */ new Map();
|
|
2467
|
+
for (const blob of blobs) {
|
|
2468
|
+
const existing = uniqueBlobs.get(blob.contentHash);
|
|
2469
|
+
if (!existing) {
|
|
2470
|
+
uniqueBlobs.set(blob.contentHash, blob);
|
|
2471
|
+
continue;
|
|
2472
|
+
}
|
|
2473
|
+
if (existing.byteSize !== blob.byteSize) {
|
|
2474
|
+
throw new Error(`Source blob ${blob.contentHash} has conflicting byte sizes.`);
|
|
2475
|
+
}
|
|
1692
2476
|
}
|
|
1693
|
-
if (
|
|
1694
|
-
return
|
|
2477
|
+
if (uniqueBlobs.size === 0) {
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
const { data, error, response } = await requestUploadSession(Array.from(uniqueBlobs.values(), ({ contentHash, byteSize }) => ({
|
|
2481
|
+
contentHash,
|
|
2482
|
+
byteSize
|
|
2483
|
+
})));
|
|
2484
|
+
if (error || !data) {
|
|
2485
|
+
throw new SourceBlobSessionRequestError("Failed to create source blob upload session", error, response);
|
|
2486
|
+
}
|
|
2487
|
+
assertSourceBlobUploadSession(data, response);
|
|
2488
|
+
for (const upload of data.uploads) {
|
|
2489
|
+
if (upload.status !== "upload_required") {
|
|
2490
|
+
continue;
|
|
2491
|
+
}
|
|
2492
|
+
const blob = uniqueBlobs.get(upload.contentHash);
|
|
2493
|
+
if (!blob) {
|
|
2494
|
+
throw new Error(`Upload session referenced unknown source blob ${upload.contentHash}.`);
|
|
2495
|
+
}
|
|
2496
|
+
if (!upload.uploadTarget) {
|
|
2497
|
+
throw new Error(`Upload target missing for source blob ${upload.contentHash}.`);
|
|
2498
|
+
}
|
|
2499
|
+
try {
|
|
2500
|
+
await uploadSourceBlob(upload.uploadTarget, blob.content);
|
|
2501
|
+
if (!await confirmSourceBlobAlreadyExists({ requestUploadSession, blob })) {
|
|
2502
|
+
throw new Error(`Source blob ${blob.contentHash} was uploaded but not registered.`);
|
|
2503
|
+
}
|
|
2504
|
+
} catch (error2) {
|
|
2505
|
+
if (isDuplicateDirectUploadError(error2) && await confirmSourceBlobAlreadyExists({ requestUploadSession, blob })) {
|
|
2506
|
+
continue;
|
|
2507
|
+
}
|
|
2508
|
+
throw error2;
|
|
2509
|
+
}
|
|
1695
2510
|
}
|
|
1696
|
-
return LogLevels.info;
|
|
1697
2511
|
}
|
|
1698
|
-
|
|
2512
|
+
async function uploadProjectSourceBlobs(options) {
|
|
2513
|
+
const { projectId, blobs } = options;
|
|
2514
|
+
return uploadSourceBlobs({
|
|
2515
|
+
blobs,
|
|
2516
|
+
requestUploadSession: (uploadBlobs) => createProjectSourceBlobUploadSession({
|
|
2517
|
+
path: { projectId },
|
|
2518
|
+
body: { blobs: uploadBlobs }
|
|
2519
|
+
})
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
1699
2522
|
|
|
1700
|
-
// src/
|
|
1701
|
-
|
|
2523
|
+
// src/services/api/source-revisions-api.ts
|
|
2524
|
+
async function uploadProjectSourceBlobsSdk(projectId, blobs) {
|
|
2525
|
+
try {
|
|
2526
|
+
await uploadProjectSourceBlobs({ projectId, blobs });
|
|
2527
|
+
} catch (error) {
|
|
2528
|
+
if (error instanceof SourceBlobSessionRequestError) {
|
|
2529
|
+
throw toDreamboardApiError(
|
|
2530
|
+
error.apiError,
|
|
2531
|
+
error.response,
|
|
2532
|
+
error.message
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
throw error;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
1702
2538
|
|
|
1703
2539
|
// src/services/project/static-scaffold.ts
|
|
1704
2540
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -2406,8 +3242,8 @@ import { unlink as unlink2 } from "fs/promises";
|
|
|
2406
3242
|
import path3 from "path";
|
|
2407
3243
|
|
|
2408
3244
|
// src/services/project/workspace-dependencies.ts
|
|
2409
|
-
import
|
|
2410
|
-
import { spawn } from "child_process";
|
|
3245
|
+
import crypto3 from "crypto";
|
|
3246
|
+
import { spawn as spawn2 } from "child_process";
|
|
2411
3247
|
import "events";
|
|
2412
3248
|
import { existsSync as existsSync2 } from "fs";
|
|
2413
3249
|
import { mkdir, lstat, readFile as readFile2, rm as rm2, writeFile } from "fs/promises";
|
|
@@ -2666,7 +3502,7 @@ async function readRepoPackageManager() {
|
|
|
2666
3502
|
return hasExactPnpmVersion(packageManager) ? packageManager : DEFAULT_PACKAGE_MANAGER;
|
|
2667
3503
|
}
|
|
2668
3504
|
function fingerprintContent(parts) {
|
|
2669
|
-
return
|
|
3505
|
+
return crypto3.createHash("sha256").update(parts.join("\n---\n")).digest("hex");
|
|
2670
3506
|
}
|
|
2671
3507
|
function resolvePnpmInstallInvocation(installArgs) {
|
|
2672
3508
|
const corepackPath = path2.join(path2.dirname(process.execPath), "corepack");
|
|
@@ -2684,7 +3520,7 @@ async function runPackageManagerCommand(projectRoot, command) {
|
|
|
2684
3520
|
}
|
|
2685
3521
|
async function runLockfileCommand(projectRoot, command) {
|
|
2686
3522
|
await new Promise((resolve, reject) => {
|
|
2687
|
-
const child =
|
|
3523
|
+
const child = spawn2(command.binary, command.args, {
|
|
2688
3524
|
cwd: projectRoot,
|
|
2689
3525
|
env: process.env,
|
|
2690
3526
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -3003,7 +3839,7 @@ function buildRemoteAlignedSnapshotFiles(options) {
|
|
|
3003
3839
|
}
|
|
3004
3840
|
|
|
3005
3841
|
// src/services/project/local-maintainer-registry.ts
|
|
3006
|
-
import { spawn as
|
|
3842
|
+
import { spawn as spawn3 } from "child_process";
|
|
3007
3843
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
3008
3844
|
import path4 from "path";
|
|
3009
3845
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -3122,7 +3958,7 @@ function parseJsonPayload(output) {
|
|
|
3122
3958
|
async function runLocalMaintainerScript(args) {
|
|
3123
3959
|
const invocation = getScriptInvocation();
|
|
3124
3960
|
return new Promise((resolve, reject) => {
|
|
3125
|
-
const child =
|
|
3961
|
+
const child = spawn3(invocation.command, [...invocation.args, ...args], {
|
|
3126
3962
|
cwd: invocation.cwd,
|
|
3127
3963
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3128
3964
|
env: process.env
|
|
@@ -3333,6 +4169,10 @@ async function buildSourceDependencyProfile(options) {
|
|
|
3333
4169
|
}
|
|
3334
4170
|
async function assertCompilerPortableDependencies(options) {
|
|
3335
4171
|
const packageJson = await readProjectPackageJson(options.projectRoot);
|
|
4172
|
+
const legacyProblems = collectLegacyDreamboardSpecifiers(packageJson);
|
|
4173
|
+
if (legacyProblems.length > 0) {
|
|
4174
|
+
throwLegacyDreamboardPackageError(legacyProblems);
|
|
4175
|
+
}
|
|
3336
4176
|
const problems = collectUnportableDreamboardSpecifiers(packageJson);
|
|
3337
4177
|
if (problems.length > 0) {
|
|
3338
4178
|
const details = problems.map(
|
|
@@ -3342,7 +4182,7 @@ async function assertCompilerPortableDependencies(options) {
|
|
|
3342
4182
|
[
|
|
3343
4183
|
"Compiler-bound workspaces must install Dreamboard packages from a registry.",
|
|
3344
4184
|
`Found unportable Dreamboard dependency specifier(s): ${details}.`,
|
|
3345
|
-
"Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard/* and dreamboard versions before compiling."
|
|
4185
|
+
"Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard-games/* and dreamboard versions before compiling."
|
|
3346
4186
|
].join(" ")
|
|
3347
4187
|
);
|
|
3348
4188
|
}
|
|
@@ -3358,6 +4198,11 @@ async function assertCompilerPortableDependencies(options) {
|
|
|
3358
4198
|
return profile;
|
|
3359
4199
|
}
|
|
3360
4200
|
async function assertReleaseEnvironmentPortableDependencies(options) {
|
|
4201
|
+
const packageJson = await readProjectPackageJson(options.projectRoot);
|
|
4202
|
+
const legacyProblems = collectLegacyDreamboardSpecifiers(packageJson);
|
|
4203
|
+
if (legacyProblems.length > 0) {
|
|
4204
|
+
throwLegacyDreamboardPackageError(legacyProblems);
|
|
4205
|
+
}
|
|
3361
4206
|
const profile = await buildSourceDependencyProfile(options);
|
|
3362
4207
|
if (!isReleaseEnvironment(options.environment)) {
|
|
3363
4208
|
return profile;
|
|
@@ -3391,7 +4236,7 @@ function collectDreamboardPackageSpecifiers(packageJson) {
|
|
|
3391
4236
|
const dependencies = packageJson[field];
|
|
3392
4237
|
if (!dependencies) continue;
|
|
3393
4238
|
for (const [packageName, specifier] of Object.entries(dependencies)) {
|
|
3394
|
-
if (
|
|
4239
|
+
if (isPortableDreamboardPackage(packageName)) {
|
|
3395
4240
|
packages[packageName] = specifier;
|
|
3396
4241
|
}
|
|
3397
4242
|
}
|
|
@@ -3399,7 +4244,7 @@ function collectDreamboardPackageSpecifiers(packageJson) {
|
|
|
3399
4244
|
const overrides = packageJson.pnpm?.overrides;
|
|
3400
4245
|
if (overrides) {
|
|
3401
4246
|
for (const [packageName, specifier] of Object.entries(overrides)) {
|
|
3402
|
-
if (
|
|
4247
|
+
if (isPortableDreamboardPackage(packageName) && typeof specifier === "string" && packages[packageName] === void 0) {
|
|
3403
4248
|
packages[packageName] = specifier;
|
|
3404
4249
|
}
|
|
3405
4250
|
}
|
|
@@ -3412,7 +4257,7 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
|
|
|
3412
4257
|
const dependencies = packageJson[field];
|
|
3413
4258
|
if (!dependencies) continue;
|
|
3414
4259
|
for (const [packageName, specifier] of Object.entries(dependencies)) {
|
|
3415
|
-
if (
|
|
4260
|
+
if (isPortableDreamboardPackage(packageName) && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
|
|
3416
4261
|
problems.push({ location: field, packageName, specifier });
|
|
3417
4262
|
}
|
|
3418
4263
|
}
|
|
@@ -3420,7 +4265,7 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
|
|
|
3420
4265
|
const overrides = packageJson.pnpm?.overrides;
|
|
3421
4266
|
if (overrides) {
|
|
3422
4267
|
for (const [packageName, specifier] of Object.entries(overrides)) {
|
|
3423
|
-
if (
|
|
4268
|
+
if (isPortableDreamboardPackage(packageName) && typeof specifier === "string" && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
|
|
3424
4269
|
problems.push({
|
|
3425
4270
|
location: "pnpm.overrides",
|
|
3426
4271
|
packageName,
|
|
@@ -3431,8 +4276,42 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
|
|
|
3431
4276
|
}
|
|
3432
4277
|
return problems;
|
|
3433
4278
|
}
|
|
3434
|
-
function
|
|
3435
|
-
|
|
4279
|
+
function collectLegacyDreamboardSpecifiers(packageJson) {
|
|
4280
|
+
const problems = [];
|
|
4281
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
4282
|
+
const dependencies = packageJson[field];
|
|
4283
|
+
if (!dependencies) continue;
|
|
4284
|
+
for (const packageName of Object.keys(dependencies)) {
|
|
4285
|
+
if (isLegacyDreamboardPackage(packageName)) {
|
|
4286
|
+
problems.push({ location: field, packageName });
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
const overrides = packageJson.pnpm?.overrides;
|
|
4291
|
+
if (overrides) {
|
|
4292
|
+
for (const packageName of Object.keys(overrides)) {
|
|
4293
|
+
if (isLegacyDreamboardPackage(packageName)) {
|
|
4294
|
+
problems.push({ location: "pnpm.overrides", packageName });
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
return problems;
|
|
4299
|
+
}
|
|
4300
|
+
function throwLegacyDreamboardPackageError(problems) {
|
|
4301
|
+
const details = problems.map((problem) => `${problem.location} ${problem.packageName}`).join("; ");
|
|
4302
|
+
throw new Error(
|
|
4303
|
+
[
|
|
4304
|
+
"Legacy @dreamboard/* package dependencies are no longer supported in compiler-bound workspaces.",
|
|
4305
|
+
`Found ${details}.`,
|
|
4306
|
+
"Repin to the public @dreamboard-games/* packages and rerun the command."
|
|
4307
|
+
].join(" ")
|
|
4308
|
+
);
|
|
4309
|
+
}
|
|
4310
|
+
function isPortableDreamboardPackage(packageName) {
|
|
4311
|
+
return packageName === "dreamboard" || packageName.startsWith("@dreamboard-games/");
|
|
4312
|
+
}
|
|
4313
|
+
function isLegacyDreamboardPackage(packageName) {
|
|
4314
|
+
return packageName.startsWith("@dreamboard/");
|
|
3436
4315
|
}
|
|
3437
4316
|
function isReleaseEnvironment(environment) {
|
|
3438
4317
|
return environment === "staging" || environment === "prod";
|
|
@@ -3458,7 +4337,7 @@ async function readDreamboardRegistryFromNpmrc(projectRoot) {
|
|
|
3458
4337
|
}
|
|
3459
4338
|
|
|
3460
4339
|
// src/services/project/local-typecheck.ts
|
|
3461
|
-
import { spawn as
|
|
4340
|
+
import { spawn as spawn4 } from "child_process";
|
|
3462
4341
|
import { lstat as lstat2 } from "fs/promises";
|
|
3463
4342
|
import { createRequire } from "module";
|
|
3464
4343
|
import path7 from "path";
|
|
@@ -3512,7 +4391,7 @@ async function resolveTypecheckRunner(projectRoot) {
|
|
|
3512
4391
|
};
|
|
3513
4392
|
}
|
|
3514
4393
|
const globalTscAvailable = await new Promise((resolve) => {
|
|
3515
|
-
const child =
|
|
4394
|
+
const child = spawn4("tsc", ["--version"], {
|
|
3516
4395
|
env: process.env,
|
|
3517
4396
|
stdio: "ignore"
|
|
3518
4397
|
});
|
|
@@ -3533,7 +4412,7 @@ async function resolveTypecheckRunner(projectRoot) {
|
|
|
3533
4412
|
}
|
|
3534
4413
|
async function runTypecheckProject(runner, projectRoot, projectPath) {
|
|
3535
4414
|
return new Promise((resolve, reject) => {
|
|
3536
|
-
const child =
|
|
4415
|
+
const child = spawn4(
|
|
3537
4416
|
runner.command,
|
|
3538
4417
|
[...runner.argsPrefix, "--noEmit", "-p", projectPath],
|
|
3539
4418
|
{
|
|
@@ -4052,166 +4931,6 @@ async function resolvePlayerCount(projectRoot, flags) {
|
|
|
4052
4931
|
return Math.max(1, Math.floor(minPlayers));
|
|
4053
4932
|
}
|
|
4054
4933
|
|
|
4055
|
-
// src/auth/auth-server.ts
|
|
4056
|
-
import {
|
|
4057
|
-
createServer
|
|
4058
|
-
} from "http";
|
|
4059
|
-
import { spawn as spawn4 } from "child_process";
|
|
4060
|
-
var DEFAULT_OAUTH_CALLBACK_PORT = 49371;
|
|
4061
|
-
async function startOAuthCallbackServer(state, timeoutMs) {
|
|
4062
|
-
let resolveCode;
|
|
4063
|
-
let rejectCode;
|
|
4064
|
-
const waitForCode = new Promise((resolve, reject) => {
|
|
4065
|
-
resolveCode = resolve;
|
|
4066
|
-
rejectCode = reject;
|
|
4067
|
-
});
|
|
4068
|
-
const portCandidate = resolveOAuthCallbackPort();
|
|
4069
|
-
const server = createServer(
|
|
4070
|
-
async (request, response) => {
|
|
4071
|
-
try {
|
|
4072
|
-
const requestUrl = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
4073
|
-
if (request.method === "GET" && requestUrl.pathname === "/oauth/callback") {
|
|
4074
|
-
const receivedState = requestUrl.searchParams.get("state");
|
|
4075
|
-
const code = requestUrl.searchParams.get("code");
|
|
4076
|
-
const error = requestUrl.searchParams.get("error");
|
|
4077
|
-
if (error) {
|
|
4078
|
-
throw new Error(`Clerk OAuth returned ${error}.`);
|
|
4079
|
-
}
|
|
4080
|
-
if (!code || receivedState !== state) {
|
|
4081
|
-
writeCorsResponse(request, response, 400, "Invalid OAuth callback");
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
|
-
resolveCode({ code });
|
|
4085
|
-
response.once("finish", () => server.close());
|
|
4086
|
-
writeHtmlResponse(
|
|
4087
|
-
response,
|
|
4088
|
-
200,
|
|
4089
|
-
"Dreamboard CLI login complete. You can return to your terminal."
|
|
4090
|
-
);
|
|
4091
|
-
return;
|
|
4092
|
-
}
|
|
4093
|
-
writeHtmlResponse(
|
|
4094
|
-
response,
|
|
4095
|
-
200,
|
|
4096
|
-
"Dreamboard CLI OAuth callback server"
|
|
4097
|
-
);
|
|
4098
|
-
} catch (error) {
|
|
4099
|
-
rejectCode(
|
|
4100
|
-
error instanceof Error ? error : new Error("Failed to handle OAuth callback.")
|
|
4101
|
-
);
|
|
4102
|
-
writeHtmlResponse(response, 500, "Dreamboard CLI login failed.");
|
|
4103
|
-
}
|
|
4104
|
-
}
|
|
4105
|
-
);
|
|
4106
|
-
try {
|
|
4107
|
-
await new Promise((resolve, reject) => {
|
|
4108
|
-
server.once("error", reject);
|
|
4109
|
-
server.listen(portCandidate, "127.0.0.1", () => {
|
|
4110
|
-
server.off("error", reject);
|
|
4111
|
-
resolve();
|
|
4112
|
-
});
|
|
4113
|
-
});
|
|
4114
|
-
} catch (error) {
|
|
4115
|
-
const portError = error instanceof Error ? error : new Error("Failed to start OAuth callback server");
|
|
4116
|
-
const configuredByEnv = Boolean(
|
|
4117
|
-
process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT
|
|
4118
|
-
);
|
|
4119
|
-
const message = configuredByEnv ? `Failed to start OAuth callback server on configured port ${portCandidate}.` : `Failed to start OAuth callback server on port ${portCandidate}. Register this loopback redirect URI with Clerk and keep the port available, or set DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT.`;
|
|
4120
|
-
const wrapped = new Error(`${message} ${portError.message}`);
|
|
4121
|
-
server.close();
|
|
4122
|
-
rejectCode(wrapped);
|
|
4123
|
-
throw wrapped;
|
|
4124
|
-
}
|
|
4125
|
-
if (!server.listening) {
|
|
4126
|
-
const error = new Error("Failed to start OAuth callback server.");
|
|
4127
|
-
rejectCode(error);
|
|
4128
|
-
throw error;
|
|
4129
|
-
}
|
|
4130
|
-
const timer = setTimeout(() => {
|
|
4131
|
-
rejectCode(new Error("Login timed out."));
|
|
4132
|
-
server?.close();
|
|
4133
|
-
}, timeoutMs);
|
|
4134
|
-
waitForCode.finally(() => clearTimeout(timer));
|
|
4135
|
-
const port = portCandidateFromServer(server);
|
|
4136
|
-
return {
|
|
4137
|
-
port,
|
|
4138
|
-
redirectUri: `http://127.0.0.1:${port}/oauth/callback`,
|
|
4139
|
-
waitForCode,
|
|
4140
|
-
close: () => server?.close()
|
|
4141
|
-
};
|
|
4142
|
-
}
|
|
4143
|
-
function resolveOAuthCallbackPort() {
|
|
4144
|
-
const rawPort = process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT?.trim();
|
|
4145
|
-
if (!rawPort) {
|
|
4146
|
-
return DEFAULT_OAUTH_CALLBACK_PORT;
|
|
4147
|
-
}
|
|
4148
|
-
const port = Number(rawPort);
|
|
4149
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
4150
|
-
throw new Error(
|
|
4151
|
-
`Invalid DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT '${rawPort}'. Expected a TCP port from 1 to 65535.`
|
|
4152
|
-
);
|
|
4153
|
-
}
|
|
4154
|
-
return port;
|
|
4155
|
-
}
|
|
4156
|
-
function portCandidateFromServer(server) {
|
|
4157
|
-
const address = server.address();
|
|
4158
|
-
if (!address || typeof address === "string") {
|
|
4159
|
-
throw new Error("Auth callback server did not expose a bound port.");
|
|
4160
|
-
}
|
|
4161
|
-
return address.port;
|
|
4162
|
-
}
|
|
4163
|
-
function writeCorsResponse(request, response, statusCode, body) {
|
|
4164
|
-
const origin = request.headers.origin ?? "*";
|
|
4165
|
-
response.writeHead(statusCode, {
|
|
4166
|
-
"Access-Control-Allow-Origin": origin,
|
|
4167
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
4168
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
4169
|
-
"Content-Type": "text/plain; charset=utf-8"
|
|
4170
|
-
});
|
|
4171
|
-
response.end(body);
|
|
4172
|
-
}
|
|
4173
|
-
function writeHtmlResponse(response, statusCode, body) {
|
|
4174
|
-
response.writeHead(statusCode, {
|
|
4175
|
-
"Content-Type": "text/html; charset=utf-8"
|
|
4176
|
-
});
|
|
4177
|
-
response.end(
|
|
4178
|
-
`<!doctype html><meta charset="utf-8"><title>Dreamboard CLI</title><p>${escapeHtml(body)}</p>`
|
|
4179
|
-
);
|
|
4180
|
-
}
|
|
4181
|
-
function escapeHtml(value) {
|
|
4182
|
-
return value.replace(/[&<>"']/g, (char) => {
|
|
4183
|
-
switch (char) {
|
|
4184
|
-
case "&":
|
|
4185
|
-
return "&";
|
|
4186
|
-
case "<":
|
|
4187
|
-
return "<";
|
|
4188
|
-
case ">":
|
|
4189
|
-
return ">";
|
|
4190
|
-
case '"':
|
|
4191
|
-
return """;
|
|
4192
|
-
default:
|
|
4193
|
-
return "'";
|
|
4194
|
-
}
|
|
4195
|
-
});
|
|
4196
|
-
}
|
|
4197
|
-
function openBrowser(url) {
|
|
4198
|
-
const platform2 = process.platform;
|
|
4199
|
-
let command;
|
|
4200
|
-
if (platform2 === "darwin") {
|
|
4201
|
-
command = ["open", url];
|
|
4202
|
-
} else if (platform2 === "win32") {
|
|
4203
|
-
command = ["cmd", "/c", "start", "", url];
|
|
4204
|
-
} else {
|
|
4205
|
-
command = ["xdg-open", url];
|
|
4206
|
-
}
|
|
4207
|
-
const [commandName, ...commandArgs] = command;
|
|
4208
|
-
const child = spawn4(commandName, commandArgs, {
|
|
4209
|
-
stdio: "ignore",
|
|
4210
|
-
detached: true
|
|
4211
|
-
});
|
|
4212
|
-
child.unref();
|
|
4213
|
-
}
|
|
4214
|
-
|
|
4215
4934
|
// src/dev-host/start-dev-server.ts
|
|
4216
4935
|
import { rmSync } from "fs";
|
|
4217
4936
|
import { createRequire as createRequire3 } from "module";
|
|
@@ -5329,6 +6048,9 @@ async function assertReducerContractPreflight(projectRoot) {
|
|
|
5329
6048
|
|
|
5330
6049
|
// src/services/project/reducer-bundle-preflight.ts
|
|
5331
6050
|
import path13 from "path";
|
|
6051
|
+
import { isPerPlayer, perPlayerSchema } from "@dreamboard-games/sdk/reducer";
|
|
6052
|
+
import "@dreamboard-games/sdk/reducer-contract";
|
|
6053
|
+
import { materializeManifestTable } from "@dreamboard-games/sdk/codegen";
|
|
5332
6054
|
globalThis.__DREAMBOARD_AUTHORING_WARNINGS__ = true;
|
|
5333
6055
|
var REDUCER_BUNDLE_ENTRY_PATH = path13.join("app", "index.ts");
|
|
5334
6056
|
var PREFLIGHT_RNG_SEED = 1337;
|
|
@@ -5574,7 +6296,7 @@ function isSourceRevisionPath(filePath) {
|
|
|
5574
6296
|
return filePath !== RULE_FILE && isAllowedGamePath(filePath);
|
|
5575
6297
|
}
|
|
5576
6298
|
function shouldAlwaysUpsertSourcePath(filePath) {
|
|
5577
|
-
return filePath === ".npmrc" ||
|
|
6299
|
+
return filePath === ".npmrc" || isDynamicGeneratedPath(filePath);
|
|
5578
6300
|
}
|
|
5579
6301
|
|
|
5580
6302
|
// src/commands/dev.ts
|
|
@@ -6149,12 +6871,12 @@ async function readWorkspacePackageJson(projectRoot) {
|
|
|
6149
6871
|
return {
|
|
6150
6872
|
dependencies: Object.fromEntries(
|
|
6151
6873
|
Object.entries(parsed.dependencies ?? {}).filter(
|
|
6152
|
-
([name]) => name
|
|
6874
|
+
([name]) => isDreamboardPublicPackage(name)
|
|
6153
6875
|
)
|
|
6154
6876
|
),
|
|
6155
6877
|
devDependencies: Object.fromEntries(
|
|
6156
6878
|
Object.entries(parsed.devDependencies ?? {}).filter(
|
|
6157
|
-
([name]) => name
|
|
6879
|
+
([name]) => isDreamboardPublicPackage(name)
|
|
6158
6880
|
)
|
|
6159
6881
|
)
|
|
6160
6882
|
};
|
|
@@ -6162,6 +6884,9 @@ async function readWorkspacePackageJson(projectRoot) {
|
|
|
6162
6884
|
return null;
|
|
6163
6885
|
}
|
|
6164
6886
|
}
|
|
6887
|
+
function isDreamboardPublicPackage(packageName) {
|
|
6888
|
+
return packageName === "dreamboard" || packageName.startsWith("@dreamboard-games/");
|
|
6889
|
+
}
|
|
6165
6890
|
function stableJson(value) {
|
|
6166
6891
|
if (value === null || typeof value !== "object") {
|
|
6167
6892
|
return JSON.stringify(value);
|
|
@@ -7291,7 +8016,7 @@ async function assertKnownPlayerId(sessionId, playerId) {
|
|
|
7291
8016
|
}
|
|
7292
8017
|
|
|
7293
8018
|
// src/commands/login.ts
|
|
7294
|
-
import
|
|
8019
|
+
import crypto4 from "crypto";
|
|
7295
8020
|
var login_default = defineCommand({
|
|
7296
8021
|
meta: {
|
|
7297
8022
|
name: "login",
|
|
@@ -7317,7 +8042,7 @@ var login_default = defineCommand({
|
|
|
7317
8042
|
void 0,
|
|
7318
8043
|
storedSession
|
|
7319
8044
|
);
|
|
7320
|
-
const state =
|
|
8045
|
+
const state = crypto4.randomUUID();
|
|
7321
8046
|
const pkce = createPkcePair();
|
|
7322
8047
|
const server = await startOAuthCallbackServer(
|
|
7323
8048
|
state,
|
|
@@ -8468,6 +9193,6 @@ function runDreamboardCli(internalSubCommands = {}) {
|
|
|
8468
9193
|
void runMain(main).catch(handleFatalError);
|
|
8469
9194
|
}
|
|
8470
9195
|
|
|
8471
|
-
// src/index.
|
|
8472
|
-
runDreamboardCli();
|
|
9196
|
+
// src/index.ts
|
|
9197
|
+
runDreamboardCli({ query: query_default, auth: auth_default });
|
|
8473
9198
|
//# sourceMappingURL=index.js.map
|