@dreamboard-games/cli 0.1.30-alpha.0 → 0.1.30-alpha.10

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.
Files changed (156) hide show
  1. package/README.md +179 -22
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +31 -30
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  4. package/dist/agent-verifier/{chunk-2NZNKIND.mjs → chunk-3IJBOLGT.mjs} +4 -12
  5. package/dist/agent-verifier/chunk-3IJBOLGT.mjs.map +1 -0
  6. package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-4GU3PCHV.mjs} +62 -99
  7. package/dist/agent-verifier/chunk-4GU3PCHV.mjs.map +1 -0
  8. package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-6XRC5PWB.mjs} +119 -310
  9. package/dist/agent-verifier/chunk-6XRC5PWB.mjs.map +1 -0
  10. package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-COB56ESI.mjs} +2 -1
  11. package/dist/agent-verifier/chunk-COB56ESI.mjs.map +1 -0
  12. package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
  13. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  14. package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
  15. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
  16. package/dist/agent-verifier/{chunk-XYDL7GY6.mjs → chunk-H6XDQJ3N.mjs} +1 -0
  17. package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
  18. package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
  19. package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-JZTH3EMV.mjs} +2 -1
  20. package/dist/agent-verifier/chunk-JZTH3EMV.mjs.map +1 -0
  21. package/dist/agent-verifier/chunk-KK47X7RV.mjs +14 -0
  22. package/dist/agent-verifier/chunk-KK47X7RV.mjs.map +1 -0
  23. package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-M7UVBANQ.mjs} +8 -9
  24. package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
  25. package/dist/agent-verifier/{chunk-RJBLBYHX.mjs → chunk-MGXX4WFR.mjs} +87 -22
  26. package/dist/agent-verifier/chunk-MGXX4WFR.mjs.map +1 -0
  27. package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
  28. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
  29. package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-POBFNXD4.mjs} +2 -1
  30. package/dist/agent-verifier/chunk-POBFNXD4.mjs.map +1 -0
  31. package/dist/agent-verifier/{chunk-6UUJEYDV.mjs → chunk-QBAF7EYR.mjs} +1 -0
  32. package/dist/agent-verifier/chunk-QBAF7EYR.mjs.map +1 -0
  33. package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-RHI6S4SU.mjs} +3 -2
  34. package/dist/agent-verifier/chunk-RHI6S4SU.mjs.map +1 -0
  35. package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
  36. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
  37. package/dist/agent-verifier/{chunk-PM3SVG6R.mjs → chunk-TLYGTHXU.mjs} +3 -2
  38. package/dist/agent-verifier/chunk-TLYGTHXU.mjs.map +1 -0
  39. package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-UWJIZML3.mjs} +13 -14
  40. package/dist/agent-verifier/chunk-UWJIZML3.mjs.map +1 -0
  41. package/dist/agent-verifier/{chunk-DTMJCPS4.mjs → chunk-VLOIZDR6.mjs} +15 -31
  42. package/dist/agent-verifier/chunk-VLOIZDR6.mjs.map +1 -0
  43. package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-W2MDP5ZN.mjs} +6 -5
  44. package/dist/agent-verifier/chunk-W2MDP5ZN.mjs.map +1 -0
  45. package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-XKCJBIRY.mjs} +2 -1
  46. package/dist/agent-verifier/chunk-XKCJBIRY.mjs.map +1 -0
  47. package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-YDIOW2BO.mjs} +2 -1
  48. package/dist/agent-verifier/chunk-YDIOW2BO.mjs.map +1 -0
  49. package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
  50. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  51. package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-YR664DJX.mjs} +111 -116
  52. package/dist/agent-verifier/chunk-YR664DJX.mjs.map +1 -0
  53. package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-Z6OZWUIZ.mjs} +6 -9
  54. package/dist/agent-verifier/chunk-Z6OZWUIZ.mjs.map +1 -0
  55. package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
  56. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  57. package/dist/agent-verifier/{compile-WNCQQVOF.mjs → compile-C2VIP6VC.mjs} +27 -27
  58. package/dist/agent-verifier/compile-C2VIP6VC.mjs.map +1 -0
  59. package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-XHL7BCKN.mjs} +6 -5
  60. package/dist/agent-verifier/global-config-XHL7BCKN.mjs.map +1 -0
  61. package/dist/agent-verifier/{keychain-backend-TNOPQV3Z.mjs → keychain-backend-A3MRWLPF.mjs} +2 -1
  62. package/dist/agent-verifier/keychain-backend-A3MRWLPF.mjs.map +1 -0
  63. package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-ZW52HSVT.mjs} +10 -11
  64. package/dist/agent-verifier/local-files-ZW52HSVT.mjs.map +1 -0
  65. package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs +10 -0
  66. package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs.map +1 -0
  67. package/dist/agent-verifier/{materialize-workspace-EWGZIVOY.mjs → materialize-workspace-BKZLLFI4.mjs} +20 -20
  68. package/dist/agent-verifier/materialize-workspace-BKZLLFI4.mjs.map +1 -0
  69. package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-XKUSCFSV.mjs} +3 -2
  70. package/dist/agent-verifier/project-state-XKUSCFSV.mjs.map +1 -0
  71. package/dist/agent-verifier/{prompt-3BAINGAQ.mjs → prompt-VKHMCQT6.mjs} +2 -1
  72. package/dist/agent-verifier/prompt-VKHMCQT6.mjs.map +1 -0
  73. package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-7NYZF5ZT.mjs} +6 -9
  74. package/dist/agent-verifier/reducer-bundle-preflight-7NYZF5ZT.mjs.map +1 -0
  75. package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs +11 -0
  76. package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs.map +1 -0
  77. package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-D4VWPIAC.mjs} +14 -17
  78. package/dist/agent-verifier/reducer-native-test-harness-D4VWPIAC.mjs.map +1 -0
  79. package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs +26 -0
  80. package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs.map +1 -0
  81. package/dist/agent-verifier/{sync-LOQAH4RC.mjs → sync-UTL2IIZV.mjs} +35 -39
  82. package/dist/agent-verifier/sync-UTL2IIZV.mjs.map +1 -0
  83. package/dist/agent-verifier/{test-YOJERVHN.mjs → test-H26XCBFA.mjs} +29 -31
  84. package/dist/agent-verifier/test-H26XCBFA.mjs.map +1 -0
  85. package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs +10 -0
  86. package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs.map +1 -0
  87. package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-ULZZZPNX.mjs} +5 -4
  88. package/dist/agent-verifier/workspace-dependencies-ULZZZPNX.mjs.map +1 -0
  89. package/dist/{chunk-TSJVWTJO.js → chunk-GXM7RRZJ.js} +14 -11
  90. package/dist/chunk-GXM7RRZJ.js.map +1 -0
  91. package/dist/{chunk-3XNJT3RK.js → chunk-P5TITCD3.js} +808 -17878
  92. package/dist/chunk-P5TITCD3.js.map +1 -0
  93. package/dist/{global-config-UKSWNDTX.js → global-config-WPJRXVDO.js} +2 -2
  94. package/dist/global-config-WPJRXVDO.js.map +1 -0
  95. package/dist/index.js +987 -255
  96. package/dist/index.js.map +1 -1
  97. package/dist/internal.js +2 -3
  98. package/package.json +8 -7
  99. package/skills/dreamboard/references/building-your-first-game.md +510 -0
  100. package/skills/dreamboard/references/cli.md +104 -0
  101. package/skills/dreamboard/references/game-interface.md +548 -0
  102. package/skills/dreamboard/references/manifest-authoring.md +597 -0
  103. package/skills/dreamboard/references/quickstart.md +66 -0
  104. package/skills/dreamboard/references/reducer.md +864 -0
  105. package/skills/dreamboard/references/rule-authoring.md +147 -0
  106. package/skills/dreamboard/references/testing.md +249 -0
  107. package/skills/dreamboard/scripts/events-extract.mjs +218 -0
  108. package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
  109. package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
  110. package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
  111. package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
  112. package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
  113. package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
  114. package/dist/agent-verifier/static-scaffold-4YEQME5N.mjs +0 -28
  115. package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
  116. package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
  117. package/dist/chunk-3XNJT3RK.js.map +0 -1
  118. package/dist/chunk-7FOO4AJI.js +0 -50
  119. package/dist/chunk-7FOO4AJI.js.map +0 -1
  120. package/dist/chunk-TSJVWTJO.js.map +0 -1
  121. package/dist/internal.d.ts +0 -311
  122. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
  123. package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
  124. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
  125. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
  126. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
  127. package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
  128. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
  129. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
  130. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
  131. package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
  132. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
  133. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
  134. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
  135. package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
  136. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
  137. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
  138. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
  139. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
  140. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
  141. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
  142. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
  143. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
  144. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
  145. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
  146. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
  147. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
  148. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
  149. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
  150. package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
  151. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
  152. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
  153. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
  154. package/dist/testing-KLSV6CPJ.js +0 -674
  155. package/dist/testing-KLSV6CPJ.js.map +0 -1
  156. /package/dist/{global-config-UKSWNDTX.js.map → agent-verifier/chunk-H6XDQJ3N.mjs.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
- createGameRevisionSdk,
16
+ createGameRevision,
16
17
  createPkcePair,
17
- createProjectSessionSdk,
18
+ createProjectSession,
19
+ createProjectSourceBlobUploadSession,
18
20
  createSessionFromScenario,
19
21
  didLocalMaintainerSnapshotChange,
20
- ensureProjectDevCompileSdk,
21
- ensureProjectSdk,
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
- getProjectBySlugSdk,
36
+ getProjectBySlug,
34
37
  getProjectCompileState,
35
38
  getProjectCompiledResultSdk,
36
39
  getProjectLocalMaintainerRegistry,
37
40
  getProjectPendingAuthoringSync,
38
- getProjectRevisionSourcesSdk,
39
- getProjectSourcesSdk,
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
- uploadInitialProjectionSdk,
96
- uploadProjectSourceBlobsSdk,
96
+ uploadInitialProjection,
97
97
  valueOrUndefined,
98
98
  waitForCompiledResultJobSdk,
99
99
  writeManifest,
@@ -101,18 +101,18 @@ import {
101
101
  writeSnapshot,
102
102
  writeSnapshotFromFiles,
103
103
  writeSourceFiles
104
- } from "./chunk-3XNJT3RK.js";
104
+ } from "./chunk-P5TITCD3.js";
105
105
  import {
106
106
  DEFAULT_LOGIN_TIMEOUT_MS,
107
107
  DEFAULT_WEB_BASE_URL,
108
108
  MANIFEST_FILE,
109
109
  MANIFEST_TYPECHECK_CONFIG_FILE,
110
- PROJECT_CONFIG_FILE,
111
110
  PROJECT_DIR_NAME,
112
111
  RULE_FILE,
113
112
  clearCredentials,
114
113
  ensureDir,
115
114
  exists,
115
+ getActiveCredentialBackendName,
116
116
  getGlobalAuthPath,
117
117
  getGlobalConfigPath,
118
118
  getStoredSession,
@@ -125,10 +125,12 @@ import {
125
125
  setCredentials,
126
126
  writeJsonFile,
127
127
  writeTextFile
128
- } from "./chunk-TSJVWTJO.js";
129
- import "./chunk-7FOO4AJI.js";
128
+ } from "./chunk-GXM7RRZJ.js";
130
129
  import "./chunk-2H7UOFLK.js";
131
130
 
131
+ // src/commands/auth.ts
132
+ import crypto2 from "crypto";
133
+
132
134
  // ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/_chunks/libs/scule.mjs
133
135
  var NUMBER_CHAR_RE = /\d/;
134
136
  var STR_SPLITTERS = [
@@ -1656,49 +1658,902 @@ ${indent}`);
1656
1658
  const _err = new Error("Trace: " + logObj.message);
1657
1659
  line += this.formatStack(_err.stack || "", _err.message);
1658
1660
  }
1659
- return isBadge ? "\n" + line + "\n" : line;
1661
+ return isBadge ? "\n" + line + "\n" : line;
1662
+ }
1663
+ };
1664
+ function characterFormat(str) {
1665
+ return str.replace(/`([^`]+)`/gm, (_2, m) => colors.cyan(m)).replace(/\s+_([^_]+)_\s+/gm, (_2, m) => ` ${colors.underline(m)} `);
1666
+ }
1667
+ function getColor2(color = "white") {
1668
+ return colors[color] || colors.white;
1669
+ }
1670
+ function getBgColor(color = "bgWhite") {
1671
+ return colors[`bg${color[0].toUpperCase()}${color.slice(1)}`] || colors.bgWhite;
1672
+ }
1673
+ function createConsola2(options = {}) {
1674
+ let level = _getDefaultLogLevel();
1675
+ if (process.env.CONSOLA_LEVEL) {
1676
+ level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level;
1677
+ }
1678
+ const consola2 = createConsola({
1679
+ level,
1680
+ defaults: { level },
1681
+ stdout: process.stdout,
1682
+ stderr: process.stderr,
1683
+ prompt: (...args) => import("./prompt-GMZABCJC.js").then((m) => m.prompt(...args)),
1684
+ reporters: options.reporters || [
1685
+ options.fancy ?? !(T || R) ? new FancyReporter() : new BasicReporter()
1686
+ ],
1687
+ ...options
1688
+ });
1689
+ return consola2;
1690
+ }
1691
+ function _getDefaultLogLevel() {
1692
+ if (g) {
1693
+ return LogLevels.debug;
1694
+ }
1695
+ if (R) {
1696
+ return LogLevels.warn;
1697
+ }
1698
+ return LogLevels.info;
1699
+ }
1700
+ var consola = createConsola2();
1701
+
1702
+ // src/auth/auth-server.ts
1703
+ import {
1704
+ createServer
1705
+ } from "http";
1706
+ import { spawn } from "child_process";
1707
+ var DEFAULT_OAUTH_CALLBACK_PORT = 49371;
1708
+ async function startOAuthCallbackServer(state, timeoutMs) {
1709
+ let resolveCode;
1710
+ let rejectCode;
1711
+ const waitForCode = new Promise((resolve, reject) => {
1712
+ resolveCode = resolve;
1713
+ rejectCode = reject;
1714
+ });
1715
+ const portCandidate = resolveOAuthCallbackPort();
1716
+ const server = createServer(
1717
+ async (request, response) => {
1718
+ try {
1719
+ const requestUrl = new URL(request.url ?? "/", "http://127.0.0.1");
1720
+ if (request.method === "GET" && requestUrl.pathname === "/oauth/callback") {
1721
+ const receivedState = requestUrl.searchParams.get("state");
1722
+ const code = requestUrl.searchParams.get("code");
1723
+ const error = requestUrl.searchParams.get("error");
1724
+ if (error) {
1725
+ throw new Error(`Clerk OAuth returned ${error}.`);
1726
+ }
1727
+ if (!code || receivedState !== state) {
1728
+ writeCorsResponse(request, response, 400, "Invalid OAuth callback");
1729
+ return;
1730
+ }
1731
+ resolveCode({ code });
1732
+ response.once("finish", () => server.close());
1733
+ writeHtmlResponse(
1734
+ response,
1735
+ 200,
1736
+ "Dreamboard CLI login complete. You can return to your terminal."
1737
+ );
1738
+ return;
1739
+ }
1740
+ writeHtmlResponse(
1741
+ response,
1742
+ 200,
1743
+ "Dreamboard CLI OAuth callback server"
1744
+ );
1745
+ } catch (error) {
1746
+ rejectCode(
1747
+ error instanceof Error ? error : new Error("Failed to handle OAuth callback.")
1748
+ );
1749
+ writeHtmlResponse(response, 500, "Dreamboard CLI login failed.");
1750
+ }
1751
+ }
1752
+ );
1753
+ try {
1754
+ await new Promise((resolve, reject) => {
1755
+ server.once("error", reject);
1756
+ server.listen(portCandidate, "127.0.0.1", () => {
1757
+ server.off("error", reject);
1758
+ resolve();
1759
+ });
1760
+ });
1761
+ } catch (error) {
1762
+ const portError = error instanceof Error ? error : new Error("Failed to start OAuth callback server");
1763
+ const configuredByEnv = Boolean(
1764
+ process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT
1765
+ );
1766
+ 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.`;
1767
+ const wrapped = new Error(`${message} ${portError.message}`);
1768
+ server.close();
1769
+ rejectCode(wrapped);
1770
+ throw wrapped;
1771
+ }
1772
+ if (!server.listening) {
1773
+ const error = new Error("Failed to start OAuth callback server.");
1774
+ rejectCode(error);
1775
+ throw error;
1776
+ }
1777
+ const timer = setTimeout(() => {
1778
+ rejectCode(new Error("Login timed out."));
1779
+ server?.close();
1780
+ }, timeoutMs);
1781
+ waitForCode.finally(() => clearTimeout(timer));
1782
+ const port = portCandidateFromServer(server);
1783
+ return {
1784
+ port,
1785
+ redirectUri: `http://127.0.0.1:${port}/oauth/callback`,
1786
+ waitForCode,
1787
+ close: () => server?.close()
1788
+ };
1789
+ }
1790
+ function resolveOAuthCallbackPort() {
1791
+ const rawPort = process.env.DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT?.trim();
1792
+ if (!rawPort) {
1793
+ return DEFAULT_OAUTH_CALLBACK_PORT;
1794
+ }
1795
+ const port = Number(rawPort);
1796
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
1797
+ throw new Error(
1798
+ `Invalid DREAMBOARD_CLERK_OAUTH_REDIRECT_PORT '${rawPort}'. Expected a TCP port from 1 to 65535.`
1799
+ );
1800
+ }
1801
+ return port;
1802
+ }
1803
+ function portCandidateFromServer(server) {
1804
+ const address = server.address();
1805
+ if (!address || typeof address === "string") {
1806
+ throw new Error("Auth callback server did not expose a bound port.");
1807
+ }
1808
+ return address.port;
1809
+ }
1810
+ function writeCorsResponse(request, response, statusCode, body) {
1811
+ const origin = request.headers.origin ?? "*";
1812
+ response.writeHead(statusCode, {
1813
+ "Access-Control-Allow-Origin": origin,
1814
+ "Access-Control-Allow-Methods": "POST, OPTIONS",
1815
+ "Access-Control-Allow-Headers": "Content-Type",
1816
+ "Content-Type": "text/plain; charset=utf-8"
1817
+ });
1818
+ response.end(body);
1819
+ }
1820
+ function writeHtmlResponse(response, statusCode, body) {
1821
+ response.writeHead(statusCode, {
1822
+ "Content-Type": "text/html; charset=utf-8"
1823
+ });
1824
+ response.end(
1825
+ `<!doctype html><meta charset="utf-8"><title>Dreamboard CLI</title><p>${escapeHtml(body)}</p>`
1826
+ );
1827
+ }
1828
+ function escapeHtml(value) {
1829
+ return value.replace(/[&<>"']/g, (char) => {
1830
+ switch (char) {
1831
+ case "&":
1832
+ return "&amp;";
1833
+ case "<":
1834
+ return "&lt;";
1835
+ case ">":
1836
+ return "&gt;";
1837
+ case '"':
1838
+ return "&quot;";
1839
+ default:
1840
+ return "&#39;";
1841
+ }
1842
+ });
1843
+ }
1844
+ function openBrowser(url) {
1845
+ const platform2 = process.platform;
1846
+ let command;
1847
+ if (platform2 === "darwin") {
1848
+ command = ["open", url];
1849
+ } else if (platform2 === "win32") {
1850
+ command = ["cmd", "/c", "start", "", url];
1851
+ } else {
1852
+ command = ["xdg-open", url];
1853
+ }
1854
+ const [commandName, ...commandArgs] = command;
1855
+ const child = spawn(commandName, commandArgs, {
1856
+ stdio: "ignore",
1857
+ detached: true
1858
+ });
1859
+ child.unref();
1860
+ }
1861
+
1862
+ // src/commands/auth.ts
1863
+ async function loginWithBrowser(config, quiet) {
1864
+ const state = crypto2.randomUUID();
1865
+ const pkce = createPkcePair();
1866
+ const server = await startOAuthCallbackServer(
1867
+ state,
1868
+ DEFAULT_LOGIN_TIMEOUT_MS
1869
+ );
1870
+ const loginUrl = buildClerkAuthorizationUrl({
1871
+ config: {
1872
+ issuer: config.clerkOAuthIssuer,
1873
+ clientId: config.clerkOAuthClientId,
1874
+ tokenUrl: config.clerkOAuthTokenUrl,
1875
+ scope: config.clerkOAuthScope
1876
+ },
1877
+ redirectUri: server.redirectUri,
1878
+ state,
1879
+ codeChallenge: pkce.challenge
1880
+ }).toString();
1881
+ if (!quiet) {
1882
+ consola.info("Opening browser for login...");
1883
+ consola.info(`If the browser does not open, visit: ${loginUrl}`);
1884
+ }
1885
+ openBrowser(loginUrl);
1886
+ if (!quiet) {
1887
+ consola.start("Waiting for login to complete...");
1888
+ }
1889
+ try {
1890
+ const { code } = await server.waitForCode;
1891
+ const tokenResponse = await exchangeClerkOAuthCode({
1892
+ config: {
1893
+ issuer: config.clerkOAuthIssuer,
1894
+ clientId: config.clerkOAuthClientId,
1895
+ tokenUrl: config.clerkOAuthTokenUrl
1896
+ },
1897
+ code,
1898
+ redirectUri: server.redirectUri,
1899
+ codeVerifier: pkce.verifier
1900
+ });
1901
+ return {
1902
+ token: tokenResponse.accessToken,
1903
+ refreshToken: tokenResponse.refreshToken,
1904
+ expiresAt: tokenResponse.expiresAt,
1905
+ tokenUrl: tokenResponse.tokenUrl
1906
+ };
1907
+ } finally {
1908
+ server.close();
1909
+ }
1910
+ }
1911
+ var auth_default = defineCommand({
1912
+ meta: { name: "auth", description: "Manage stored Dreamboard sessions" },
1913
+ args: {
1914
+ action: {
1915
+ type: "positional",
1916
+ description: IS_PUBLISHED_BUILD ? "Action: clear | login" : "Action: set | clear | login | env | status",
1917
+ required: true
1918
+ },
1919
+ ...IS_PUBLISHED_BUILD ? {} : {
1920
+ tokenValue: {
1921
+ type: "positional",
1922
+ description: "Token value (for set) or environment name (for env)",
1923
+ required: false
1924
+ },
1925
+ token: {
1926
+ type: "string",
1927
+ description: "Auth token (alternative)"
1928
+ },
1929
+ jwt: {
1930
+ type: "boolean",
1931
+ description: "Print auth token JSON to stdout"
1932
+ },
1933
+ env: {
1934
+ type: "string",
1935
+ description: "Environment: local | staging | prod"
1936
+ }
1937
+ }
1938
+ },
1939
+ async run({ args }) {
1940
+ const parsedArgs = parseAuthCommandArgs(args);
1941
+ const action = parsedArgs.action;
1942
+ const globalConfig = await loadGlobalConfig();
1943
+ if (IS_PUBLISHED_BUILD && action !== "login" && action !== "clear") {
1944
+ throw new Error(
1945
+ "The published Dreamboard CLI only supports browser login and logout. Use `dreamboard login` or `dreamboard logout`."
1946
+ );
1947
+ }
1948
+ if (action === "env") {
1949
+ if (IS_PUBLISHED_BUILD) {
1950
+ throw new Error(
1951
+ "The published Dreamboard CLI is production-only and does not support switching environments."
1952
+ );
1953
+ }
1954
+ const environment = parsedArgs.tokenValue ?? parsedArgs.env;
1955
+ if (!environment) {
1956
+ throw new Error("Usage: dreamboard auth env <local|staging|prod>");
1957
+ }
1958
+ if (!["local", "staging", "prod"].includes(environment)) {
1959
+ throw new Error(
1960
+ `Invalid environment '${environment}'. Valid options: local, staging, prod`
1961
+ );
1962
+ }
1963
+ await saveGlobalConfig({
1964
+ ...globalConfig,
1965
+ environment
1966
+ });
1967
+ consola.success(`Environment set to '${environment}'.`);
1968
+ return;
1969
+ }
1970
+ if (action === "set") {
1971
+ if (IS_PUBLISHED_BUILD) {
1972
+ throw new Error(
1973
+ "Direct JWT injection is not supported in the published Dreamboard CLI. Use `dreamboard login` so the CLI can store a refreshable session."
1974
+ );
1975
+ }
1976
+ const token = parsedArgs.tokenValue ?? parsedArgs.token ?? "";
1977
+ if (!token) throw new Error("Usage: dreamboard auth set <token>");
1978
+ await setAccessOnlySession(token);
1979
+ consola.success(`Auth token saved to ${getGlobalAuthPath()}.`);
1980
+ return;
1981
+ }
1982
+ if (action === "clear") {
1983
+ await clearCredentials();
1984
+ consola.success(
1985
+ `Stored Dreamboard session cleared from ${getGlobalAuthPath()}.`
1986
+ );
1987
+ return;
1988
+ }
1989
+ if (action === "login") {
1990
+ const shouldPrintJwt = !IS_PUBLISHED_BUILD && parsedArgs.jwt === true;
1991
+ const environment = IS_PUBLISHED_BUILD ? PUBLISHED_ENVIRONMENT : parsedArgs.env || globalConfig.environment || "staging";
1992
+ const storedSession = await getStoredSession();
1993
+ let accessToken = storedSession?.accessToken;
1994
+ let refreshToken = storedSession?.refreshToken;
1995
+ let tokenExpiresAt = storedSession?.tokenExpiresAt;
1996
+ let clerkOAuthTokenUrl = storedSession?.clerkOAuthTokenUrl;
1997
+ let didRefreshStoredSession = false;
1998
+ let didUseBrowserLogin = false;
1999
+ const resolvedConfig = resolveConfig(
2000
+ globalConfig,
2001
+ { env: environment },
2002
+ void 0,
2003
+ storedSession
2004
+ );
2005
+ if (accessToken && refreshToken) {
2006
+ try {
2007
+ const refreshed = await refreshResolvedAuthSession(resolvedConfig);
2008
+ accessToken = refreshed?.accessToken ?? accessToken;
2009
+ refreshToken = refreshed?.refreshToken ?? refreshToken;
2010
+ tokenExpiresAt = refreshed?.tokenExpiresAt ?? tokenExpiresAt;
2011
+ clerkOAuthTokenUrl = refreshed?.clerkOAuthTokenUrl ?? clerkOAuthTokenUrl;
2012
+ didRefreshStoredSession = Boolean(refreshed);
2013
+ } catch (error) {
2014
+ consola.warn(
2015
+ error instanceof Error ? error.message : "Stored Dreamboard CLI session refresh failed."
2016
+ );
2017
+ accessToken = void 0;
2018
+ refreshToken = void 0;
2019
+ }
2020
+ }
2021
+ if (!accessToken) {
2022
+ const browserLogin = await loginWithBrowser(
2023
+ resolvedConfig,
2024
+ shouldPrintJwt
2025
+ );
2026
+ accessToken = browserLogin.token;
2027
+ refreshToken = browserLogin.refreshToken;
2028
+ tokenExpiresAt = browserLogin.expiresAt;
2029
+ clerkOAuthTokenUrl = browserLogin.tokenUrl;
2030
+ didUseBrowserLogin = true;
2031
+ }
2032
+ if (!accessToken) {
2033
+ throw new Error("Login completed but no access token was returned.");
2034
+ }
2035
+ await saveGlobalConfig({
2036
+ ...globalConfig,
2037
+ environment
2038
+ });
2039
+ if (refreshToken) {
2040
+ await setCredentials({
2041
+ accessToken,
2042
+ refreshToken,
2043
+ tokenExpiresAt,
2044
+ clerkOAuthIssuer: resolvedConfig.clerkOAuthIssuer,
2045
+ clerkOAuthClientId: resolvedConfig.clerkOAuthClientId,
2046
+ clerkOAuthTokenUrl,
2047
+ environment
2048
+ });
2049
+ } else {
2050
+ await setAccessOnlySession(accessToken);
2051
+ }
2052
+ if (shouldPrintJwt) {
2053
+ process.stdout.write(
2054
+ `${JSON.stringify(
2055
+ {
2056
+ token: accessToken,
2057
+ refreshToken: refreshToken ?? null,
2058
+ environment
2059
+ },
2060
+ null,
2061
+ 2
2062
+ )}
2063
+ `
2064
+ );
2065
+ return;
2066
+ }
2067
+ if (didUseBrowserLogin) {
2068
+ consola.success(
2069
+ `Browser login successful. Session saved to ${getGlobalAuthPath()}`
2070
+ );
2071
+ } else if (storedSession?.accessToken && didRefreshStoredSession) {
2072
+ consola.success(
2073
+ `Stored auth session refreshed and saved to ${getGlobalAuthPath()}`
2074
+ );
2075
+ } else if (storedSession?.accessToken) {
2076
+ consola.success(
2077
+ `Stored auth token found. Session data remains in ${getGlobalAuthPath()}`
2078
+ );
2079
+ }
2080
+ return;
2081
+ }
2082
+ if (action === "status") {
2083
+ const storedSession = await getStoredSession();
2084
+ const resolvedConfig = resolveConfig(
2085
+ globalConfig,
2086
+ { env: parsedArgs.env },
2087
+ void 0,
2088
+ storedSession
2089
+ );
2090
+ const environment = parsedArgs.env || globalConfig.environment || "staging";
2091
+ const authTokenExpiry = getAuthTokenExpiry(resolvedConfig.authToken);
2092
+ const backendName = await getActiveCredentialBackendName();
2093
+ consola.log(`Environment: ${environment}`);
2094
+ consola.log(`Auth token source: ${resolvedConfig.authTokenSource}`);
2095
+ consola.log(`Refresh token source: ${resolvedConfig.refreshTokenSource}`);
2096
+ consola.log(
2097
+ `Credential backend: ${backendName}${backendName === "keychain" ? " (OS keychain via @napi-rs/keyring)" : ` (${getGlobalAuthPath()})`}`
2098
+ );
2099
+ const preference = globalConfig.credentialBackend;
2100
+ if (preference) {
2101
+ consola.log(`Credential backend preference (config): ${preference}`);
2102
+ } else {
2103
+ consola.log(
2104
+ 'Credential backend preference (config): file (default; set `"credentialBackend": "keychain"` in config.json to opt in)'
2105
+ );
2106
+ }
2107
+ if (process.env.DREAMBOARD_CREDENTIAL_BACKEND) {
2108
+ consola.log(
2109
+ `Backend override: DREAMBOARD_CREDENTIAL_BACKEND=${process.env.DREAMBOARD_CREDENTIAL_BACKEND}`
2110
+ );
2111
+ }
2112
+ consola.log(`Config path: ${getGlobalConfigPath()}`);
2113
+ if (!resolvedConfig.authToken) {
2114
+ consola.warn("No Dreamboard session found.");
2115
+ return;
2116
+ }
2117
+ if (authTokenExpiry) {
2118
+ const isExpired = authTokenExpiry.getTime() <= Date.now();
2119
+ consola.log(
2120
+ `Access token expires at: ${authTokenExpiry.toISOString()} (${isExpired ? "expired" : "active"})`
2121
+ );
2122
+ if (isExpired) {
2123
+ if (!resolvedConfig.refreshToken) {
2124
+ consola.warn(
2125
+ "Access token is expired and no refresh token is available. Run `dreamboard login` to authenticate again."
2126
+ );
2127
+ return;
2128
+ }
2129
+ const refreshed = await refreshResolvedAuthSession(resolvedConfig);
2130
+ if (!refreshed?.accessToken) {
2131
+ consola.warn(
2132
+ "Access token is expired and refresh did not return a new session."
2133
+ );
2134
+ return;
2135
+ }
2136
+ const refreshedExpiry = getAuthTokenExpiry(refreshed.accessToken);
2137
+ consola.success("Access token was expired and has been refreshed.");
2138
+ if (refreshedExpiry) {
2139
+ consola.log(
2140
+ `Refreshed access token expires at: ${refreshedExpiry.toISOString()}`
2141
+ );
2142
+ }
2143
+ return;
2144
+ }
2145
+ } else {
2146
+ consola.log("Access token expiry: unavailable");
2147
+ }
2148
+ consola.success("Dreamboard session is active.");
2149
+ return;
2150
+ }
2151
+ throw new Error(
2152
+ 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>]"
2153
+ );
2154
+ }
2155
+ });
2156
+
2157
+ // src/commands/query.ts
2158
+ var query_default = defineCommand({
2159
+ meta: {
2160
+ name: "query",
2161
+ description: "Query rulebook text by title"
2162
+ },
2163
+ args: {
2164
+ title: {
2165
+ type: "positional",
2166
+ description: "Board game title to search in the rulebook library",
2167
+ required: true
2168
+ },
2169
+ ...CONFIG_FLAG_ARGS
2170
+ },
2171
+ async run({ args }) {
2172
+ const parsedArgs = parseQueryCommandArgs(args);
2173
+ const [globalConfig, storedSession] = await Promise.all([
2174
+ loadGlobalConfig(),
2175
+ getStoredSession()
2176
+ ]);
2177
+ const config = resolveConfig(
2178
+ globalConfig,
2179
+ parsedArgs,
2180
+ void 0,
2181
+ storedSession
2182
+ );
2183
+ requireAuth(config);
2184
+ await configureClient(config);
2185
+ const { data, error, response } = await queryWorkshopRulebook({
2186
+ query: {
2187
+ title: parsedArgs.title
2188
+ }
2189
+ });
2190
+ if (!data) {
2191
+ throw toDreamboardApiError(
2192
+ error,
2193
+ response,
2194
+ `Failed to query rulebook for '${parsedArgs.title}'`
2195
+ );
2196
+ }
2197
+ console.log(data.ruleText);
2198
+ }
2199
+ });
2200
+
2201
+ // src/commands/clone.ts
2202
+ import path5 from "path";
2203
+
2204
+ // src/services/api/project-api.ts
2205
+ async function loadRemoteProjectIdentity() {
2206
+ const [versionResponse, userResponse] = await Promise.all([
2207
+ getApiVersion(),
2208
+ getCurrentAuthUser()
2209
+ ]);
2210
+ if (versionResponse.error || !versionResponse.data) {
2211
+ throw toDreamboardApiError(
2212
+ versionResponse.error,
2213
+ versionResponse.response,
2214
+ "Failed to resolve backend deployment identity"
2215
+ );
2216
+ }
2217
+ if (userResponse.error || !userResponse.data) {
2218
+ throw toDreamboardApiError(
2219
+ userResponse.error,
2220
+ userResponse.response,
2221
+ "Failed to resolve authenticated owner scope"
2222
+ );
2223
+ }
2224
+ const deploymentId = versionResponse.data.deploymentId;
2225
+ const ownerScopeId = userResponse.data.ownerScopeId;
2226
+ return {
2227
+ deploymentId,
2228
+ ownerScopeId,
2229
+ bindingKey: `${deploymentId}:${ownerScopeId}`
2230
+ };
2231
+ }
2232
+ async function ensureProjectSdk(options) {
2233
+ const { data, error, response } = await ensureProject({
2234
+ path: { projectId: options.projectId },
2235
+ body: {
2236
+ slug: options.slug,
2237
+ name: titleFromSlug(options.slug),
2238
+ description: options.description ?? `Dreamboard workspace for ${options.slug}.`,
2239
+ ...options.updateAlias ? { updateAlias: true } : {}
2240
+ }
2241
+ });
2242
+ if (error || !data) {
2243
+ throw toDreamboardApiError(error, response, "Failed to ensure project");
2244
+ }
2245
+ return data;
2246
+ }
2247
+ async function getProjectBySlugSdk(slug) {
2248
+ const { data, error, response } = await getProjectBySlug({
2249
+ path: { slug }
2250
+ });
2251
+ if (error || !data) {
2252
+ throw toDreamboardApiError(
2253
+ error,
2254
+ response,
2255
+ `Project '${slug}' not found`
2256
+ );
2257
+ }
2258
+ return data;
2259
+ }
2260
+ async function createGameRevisionSdk(options) {
2261
+ const { data, error, response } = await createGameRevision({
2262
+ path: { projectId: options.projectId },
2263
+ body: options.request
2264
+ });
2265
+ if (error || !data) {
2266
+ throw toDreamboardApiError(
2267
+ error,
2268
+ response,
2269
+ "Failed to create game revision"
2270
+ );
2271
+ }
2272
+ return data;
2273
+ }
2274
+ async function getProjectSourcesSdk(projectId) {
2275
+ const { data, error, response } = await getProjectSources({
2276
+ path: { projectId }
2277
+ });
2278
+ if (response?.status === 404) {
2279
+ return null;
2280
+ }
2281
+ if (error || !data) {
2282
+ throw toDreamboardApiError(
2283
+ error,
2284
+ response,
2285
+ "Failed to fetch project sources"
2286
+ );
2287
+ }
2288
+ return data;
2289
+ }
2290
+ async function getProjectRevisionSourcesSdk(options) {
2291
+ const { data, error, response } = await getProjectRevisionSources({
2292
+ path: {
2293
+ projectId: options.projectId,
2294
+ revisionDigest: options.revisionDigest
2295
+ }
2296
+ });
2297
+ if (error || !data) {
2298
+ throw toDreamboardApiError(
2299
+ error,
2300
+ response,
2301
+ "Failed to fetch project revision sources"
2302
+ );
2303
+ }
2304
+ return data;
2305
+ }
2306
+ async function ensureProjectDevCompileSdk(options) {
2307
+ const { data, error, response } = await ensureProjectDevCompile({
2308
+ path: { projectId: options.projectId },
2309
+ body: options.request
2310
+ });
2311
+ if (error || !data) {
2312
+ throw toDreamboardApiError(error, response, "Failed to ensure dev compile");
2313
+ }
2314
+ return data;
2315
+ }
2316
+ async function createProjectSessionSdk(options) {
2317
+ const { data, error, response } = await createProjectSession({
2318
+ path: { projectId: options.projectId },
2319
+ body: options.request
2320
+ });
2321
+ if (error || !data) {
2322
+ throw toDreamboardApiError(error, response, "Failed to create session");
2323
+ }
2324
+ return data;
2325
+ }
2326
+
2327
+ // src/services/api/preview-api.ts
2328
+ async function uploadInitialProjectionSdk(gameId, projectionJson) {
2329
+ const { error, response } = await uploadInitialProjection({
2330
+ path: { gameId },
2331
+ body: { projectionJson }
2332
+ });
2333
+ if (error) {
2334
+ throw toDreamboardApiError(
2335
+ error,
2336
+ response,
2337
+ "Failed to upload initial preview projection"
2338
+ );
2339
+ }
2340
+ }
2341
+
2342
+ // ../../packages/api-client/dist/source-revisions.js
2343
+ var textEncoder = new TextEncoder();
2344
+ var SOURCE_BLOB_UPLOAD_SESSION_BATCH_SIZE = 20;
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);
2436
+ }
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);
2448
+ }
2449
+ }
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
+ }
2476
+ }
2477
+ if (uniqueBlobs.size === 0) {
2478
+ return;
2479
+ }
2480
+ for (const uploadBatch of chunkSourceBlobs(Array.from(uniqueBlobs.values()), SOURCE_BLOB_UPLOAD_SESSION_BATCH_SIZE)) {
2481
+ const { data, error, response } = await requestUploadSession(uploadBatch.map(({ contentHash, byteSize }) => ({
2482
+ contentHash,
2483
+ byteSize
2484
+ })));
2485
+ if (error || !data) {
2486
+ throw new SourceBlobSessionRequestError("Failed to create source blob upload session", error, response);
2487
+ }
2488
+ assertSourceBlobUploadSession(data, response);
2489
+ for (const upload of data.uploads) {
2490
+ if (upload.status !== "upload_required") {
2491
+ continue;
2492
+ }
2493
+ const blob = uniqueBlobs.get(upload.contentHash);
2494
+ if (!blob) {
2495
+ throw new Error(`Upload session referenced unknown source blob ${upload.contentHash}.`);
2496
+ }
2497
+ if (!upload.uploadTarget) {
2498
+ throw new Error(`Upload target missing for source blob ${upload.contentHash}.`);
2499
+ }
2500
+ try {
2501
+ await uploadSourceBlob(upload.uploadTarget, blob.content);
2502
+ if (!await confirmSourceBlobAlreadyExists({ requestUploadSession, blob })) {
2503
+ throw new Error(`Source blob ${blob.contentHash} was uploaded but not registered.`);
2504
+ }
2505
+ } catch (error2) {
2506
+ if (isDuplicateDirectUploadError(error2) && await confirmSourceBlobAlreadyExists({ requestUploadSession, blob })) {
2507
+ continue;
2508
+ }
2509
+ throw error2;
2510
+ }
2511
+ }
1660
2512
  }
1661
- };
1662
- function characterFormat(str) {
1663
- return str.replace(/`([^`]+)`/gm, (_2, m) => colors.cyan(m)).replace(/\s+_([^_]+)_\s+/gm, (_2, m) => ` ${colors.underline(m)} `);
1664
- }
1665
- function getColor2(color = "white") {
1666
- return colors[color] || colors.white;
1667
- }
1668
- function getBgColor(color = "bgWhite") {
1669
- return colors[`bg${color[0].toUpperCase()}${color.slice(1)}`] || colors.bgWhite;
1670
2513
  }
1671
- function createConsola2(options = {}) {
1672
- let level = _getDefaultLogLevel();
1673
- if (process.env.CONSOLA_LEVEL) {
1674
- level = Number.parseInt(process.env.CONSOLA_LEVEL) ?? level;
1675
- }
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
2514
+ function chunkSourceBlobs(blobs, batchSize) {
2515
+ const chunks = [];
2516
+ for (let index = 0; index < blobs.length; index += batchSize) {
2517
+ chunks.push(blobs.slice(index, index + batchSize));
2518
+ }
2519
+ return chunks;
2520
+ }
2521
+ async function uploadProjectSourceBlobs(options) {
2522
+ const { projectId, blobs } = options;
2523
+ return uploadSourceBlobs({
2524
+ blobs,
2525
+ requestUploadSession: (uploadBlobs) => createProjectSourceBlobUploadSession({
2526
+ path: { projectId },
2527
+ body: { blobs: uploadBlobs }
2528
+ })
1686
2529
  });
1687
- return consola2;
1688
2530
  }
1689
- function _getDefaultLogLevel() {
1690
- if (g) {
1691
- return LogLevels.debug;
2531
+
2532
+ // src/services/api/source-revisions-api.ts
2533
+ var SOURCE_BLOB_UPLOAD_BATCH_SIZE = 20;
2534
+ async function uploadProjectSourceBlobsSdk(projectId, blobs) {
2535
+ try {
2536
+ for (const batch of chunkSourceBlobs2(blobs)) {
2537
+ await uploadProjectSourceBlobs({ projectId, blobs: batch });
2538
+ }
2539
+ } catch (error) {
2540
+ if (error instanceof SourceBlobSessionRequestError) {
2541
+ throw toDreamboardApiError(
2542
+ error.apiError,
2543
+ error.response,
2544
+ error.message
2545
+ );
2546
+ }
2547
+ throw error;
1692
2548
  }
1693
- if (R) {
1694
- return LogLevels.warn;
2549
+ }
2550
+ function chunkSourceBlobs2(blobs) {
2551
+ const chunks = [];
2552
+ for (let index = 0; index < blobs.length; index += SOURCE_BLOB_UPLOAD_BATCH_SIZE) {
2553
+ chunks.push(blobs.slice(index, index + SOURCE_BLOB_UPLOAD_BATCH_SIZE));
1695
2554
  }
1696
- return LogLevels.info;
2555
+ return chunks;
1697
2556
  }
1698
- var consola = createConsola2();
1699
-
1700
- // src/commands/clone.ts
1701
- import path5 from "path";
1702
2557
 
1703
2558
  // src/services/project/static-scaffold.ts
1704
2559
  import { existsSync, readFileSync } from "fs";
@@ -2208,24 +3063,12 @@ async function getDynamicStaticEntries(projectRoot, mode, options = {}) {
2208
3063
  }
2209
3064
  return entries;
2210
3065
  }
2211
- async function readProjectLocalMaintainerRegistry(projectRoot) {
2212
- const projectConfigPath = path.join(
2213
- projectRoot,
2214
- PROJECT_DIR_NAME,
2215
- PROJECT_CONFIG_FILE
2216
- );
2217
- if (!await exists(projectConfigPath)) {
2218
- return null;
2219
- }
2220
- const projectConfig = await loadProjectConfig(projectRoot);
2221
- return projectConfig.localMaintainerRegistry ?? null;
2222
- }
2223
3066
  async function getExpectedStaticEntries(projectRoot) {
2224
3067
  const entries = [
2225
- ...await getStaticAssetEntries(),
2226
- ...await getDynamicStaticEntries(projectRoot, "update", {
2227
- localMaintainerRegistry: await readProjectLocalMaintainerRegistry(projectRoot)
2228
- })
3068
+ ...(await getStaticAssetEntries()).filter(
3069
+ (entry) => entry.targetPath !== ".npmrc"
3070
+ ),
3071
+ ...await getDynamicStaticEntries(projectRoot, "update")
2229
3072
  ];
2230
3073
  entries.sort(
2231
3074
  (left, right) => left.targetPath.localeCompare(right.targetPath)
@@ -2406,8 +3249,8 @@ import { unlink as unlink2 } from "fs/promises";
2406
3249
  import path3 from "path";
2407
3250
 
2408
3251
  // src/services/project/workspace-dependencies.ts
2409
- import crypto from "crypto";
2410
- import { spawn } from "child_process";
3252
+ import crypto3 from "crypto";
3253
+ import { spawn as spawn2 } from "child_process";
2411
3254
  import "events";
2412
3255
  import { existsSync as existsSync2 } from "fs";
2413
3256
  import { mkdir, lstat, readFile as readFile2, rm as rm2, writeFile } from "fs/promises";
@@ -2666,7 +3509,7 @@ async function readRepoPackageManager() {
2666
3509
  return hasExactPnpmVersion(packageManager) ? packageManager : DEFAULT_PACKAGE_MANAGER;
2667
3510
  }
2668
3511
  function fingerprintContent(parts) {
2669
- return crypto.createHash("sha256").update(parts.join("\n---\n")).digest("hex");
3512
+ return crypto3.createHash("sha256").update(parts.join("\n---\n")).digest("hex");
2670
3513
  }
2671
3514
  function resolvePnpmInstallInvocation(installArgs) {
2672
3515
  const corepackPath = path2.join(path2.dirname(process.execPath), "corepack");
@@ -2684,7 +3527,7 @@ async function runPackageManagerCommand(projectRoot, command) {
2684
3527
  }
2685
3528
  async function runLockfileCommand(projectRoot, command) {
2686
3529
  await new Promise((resolve, reject) => {
2687
- const child = spawn(command.binary, command.args, {
3530
+ const child = spawn2(command.binary, command.args, {
2688
3531
  cwd: projectRoot,
2689
3532
  env: process.env,
2690
3533
  stdio: ["ignore", "pipe", "pipe"]
@@ -3003,7 +3846,7 @@ function buildRemoteAlignedSnapshotFiles(options) {
3003
3846
  }
3004
3847
 
3005
3848
  // src/services/project/local-maintainer-registry.ts
3006
- import { spawn as spawn2 } from "child_process";
3849
+ import { spawn as spawn3 } from "child_process";
3007
3850
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
3008
3851
  import path4 from "path";
3009
3852
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -3122,7 +3965,7 @@ function parseJsonPayload(output) {
3122
3965
  async function runLocalMaintainerScript(args) {
3123
3966
  const invocation = getScriptInvocation();
3124
3967
  return new Promise((resolve, reject) => {
3125
- const child = spawn2(invocation.command, [...invocation.args, ...args], {
3968
+ const child = spawn3(invocation.command, [...invocation.args, ...args], {
3126
3969
  cwd: invocation.cwd,
3127
3970
  stdio: ["ignore", "pipe", "pipe"],
3128
3971
  env: process.env
@@ -3333,6 +4176,10 @@ async function buildSourceDependencyProfile(options) {
3333
4176
  }
3334
4177
  async function assertCompilerPortableDependencies(options) {
3335
4178
  const packageJson = await readProjectPackageJson(options.projectRoot);
4179
+ const legacyProblems = collectLegacyDreamboardSpecifiers(packageJson);
4180
+ if (legacyProblems.length > 0) {
4181
+ throwLegacyDreamboardPackageError(legacyProblems);
4182
+ }
3336
4183
  const problems = collectUnportableDreamboardSpecifiers(packageJson);
3337
4184
  if (problems.length > 0) {
3338
4185
  const details = problems.map(
@@ -3342,7 +4189,7 @@ async function assertCompilerPortableDependencies(options) {
3342
4189
  [
3343
4190
  "Compiler-bound workspaces must install Dreamboard packages from a registry.",
3344
4191
  `Found unportable Dreamboard dependency specifier(s): ${details}.`,
3345
- "Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard/* and dreamboard versions before compiling."
4192
+ "Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard-games/* and dreamboard versions before compiling."
3346
4193
  ].join(" ")
3347
4194
  );
3348
4195
  }
@@ -3358,6 +4205,11 @@ async function assertCompilerPortableDependencies(options) {
3358
4205
  return profile;
3359
4206
  }
3360
4207
  async function assertReleaseEnvironmentPortableDependencies(options) {
4208
+ const packageJson = await readProjectPackageJson(options.projectRoot);
4209
+ const legacyProblems = collectLegacyDreamboardSpecifiers(packageJson);
4210
+ if (legacyProblems.length > 0) {
4211
+ throwLegacyDreamboardPackageError(legacyProblems);
4212
+ }
3361
4213
  const profile = await buildSourceDependencyProfile(options);
3362
4214
  if (!isReleaseEnvironment(options.environment)) {
3363
4215
  return profile;
@@ -3391,7 +4243,7 @@ function collectDreamboardPackageSpecifiers(packageJson) {
3391
4243
  const dependencies = packageJson[field];
3392
4244
  if (!dependencies) continue;
3393
4245
  for (const [packageName, specifier] of Object.entries(dependencies)) {
3394
- if (isDreamboardPackage(packageName)) {
4246
+ if (isPortableDreamboardPackage(packageName)) {
3395
4247
  packages[packageName] = specifier;
3396
4248
  }
3397
4249
  }
@@ -3399,7 +4251,7 @@ function collectDreamboardPackageSpecifiers(packageJson) {
3399
4251
  const overrides = packageJson.pnpm?.overrides;
3400
4252
  if (overrides) {
3401
4253
  for (const [packageName, specifier] of Object.entries(overrides)) {
3402
- if (isDreamboardPackage(packageName) && typeof specifier === "string" && packages[packageName] === void 0) {
4254
+ if (isPortableDreamboardPackage(packageName) && typeof specifier === "string" && packages[packageName] === void 0) {
3403
4255
  packages[packageName] = specifier;
3404
4256
  }
3405
4257
  }
@@ -3412,7 +4264,7 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
3412
4264
  const dependencies = packageJson[field];
3413
4265
  if (!dependencies) continue;
3414
4266
  for (const [packageName, specifier] of Object.entries(dependencies)) {
3415
- if (isDreamboardPackage(packageName) && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
4267
+ if (isPortableDreamboardPackage(packageName) && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
3416
4268
  problems.push({ location: field, packageName, specifier });
3417
4269
  }
3418
4270
  }
@@ -3420,7 +4272,7 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
3420
4272
  const overrides = packageJson.pnpm?.overrides;
3421
4273
  if (overrides) {
3422
4274
  for (const [packageName, specifier] of Object.entries(overrides)) {
3423
- if (isDreamboardPackage(packageName) && typeof specifier === "string" && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
4275
+ if (isPortableDreamboardPackage(packageName) && typeof specifier === "string" && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
3424
4276
  problems.push({
3425
4277
  location: "pnpm.overrides",
3426
4278
  packageName,
@@ -3431,8 +4283,42 @@ function collectUnportableDreamboardSpecifiers(packageJson) {
3431
4283
  }
3432
4284
  return problems;
3433
4285
  }
3434
- function isDreamboardPackage(packageName) {
3435
- return packageName === "dreamboard" || packageName.startsWith("@dreamboard/") || packageName.startsWith("@dreamboard-games/");
4286
+ function collectLegacyDreamboardSpecifiers(packageJson) {
4287
+ const problems = [];
4288
+ for (const field of DEPENDENCY_FIELDS) {
4289
+ const dependencies = packageJson[field];
4290
+ if (!dependencies) continue;
4291
+ for (const packageName of Object.keys(dependencies)) {
4292
+ if (isLegacyDreamboardPackage(packageName)) {
4293
+ problems.push({ location: field, packageName });
4294
+ }
4295
+ }
4296
+ }
4297
+ const overrides = packageJson.pnpm?.overrides;
4298
+ if (overrides) {
4299
+ for (const packageName of Object.keys(overrides)) {
4300
+ if (isLegacyDreamboardPackage(packageName)) {
4301
+ problems.push({ location: "pnpm.overrides", packageName });
4302
+ }
4303
+ }
4304
+ }
4305
+ return problems;
4306
+ }
4307
+ function throwLegacyDreamboardPackageError(problems) {
4308
+ const details = problems.map((problem) => `${problem.location} ${problem.packageName}`).join("; ");
4309
+ throw new Error(
4310
+ [
4311
+ "Legacy @dreamboard/* package dependencies are no longer supported in compiler-bound workspaces.",
4312
+ `Found ${details}.`,
4313
+ "Repin to the public @dreamboard-games/* packages and rerun the command."
4314
+ ].join(" ")
4315
+ );
4316
+ }
4317
+ function isPortableDreamboardPackage(packageName) {
4318
+ return packageName === "dreamboard" || packageName.startsWith("@dreamboard-games/");
4319
+ }
4320
+ function isLegacyDreamboardPackage(packageName) {
4321
+ return packageName.startsWith("@dreamboard/");
3436
4322
  }
3437
4323
  function isReleaseEnvironment(environment) {
3438
4324
  return environment === "staging" || environment === "prod";
@@ -3458,7 +4344,7 @@ async function readDreamboardRegistryFromNpmrc(projectRoot) {
3458
4344
  }
3459
4345
 
3460
4346
  // src/services/project/local-typecheck.ts
3461
- import { spawn as spawn3 } from "child_process";
4347
+ import { spawn as spawn4 } from "child_process";
3462
4348
  import { lstat as lstat2 } from "fs/promises";
3463
4349
  import { createRequire } from "module";
3464
4350
  import path7 from "path";
@@ -3512,7 +4398,7 @@ async function resolveTypecheckRunner(projectRoot) {
3512
4398
  };
3513
4399
  }
3514
4400
  const globalTscAvailable = await new Promise((resolve) => {
3515
- const child = spawn3("tsc", ["--version"], {
4401
+ const child = spawn4("tsc", ["--version"], {
3516
4402
  env: process.env,
3517
4403
  stdio: "ignore"
3518
4404
  });
@@ -3533,7 +4419,7 @@ async function resolveTypecheckRunner(projectRoot) {
3533
4419
  }
3534
4420
  async function runTypecheckProject(runner, projectRoot, projectPath) {
3535
4421
  return new Promise((resolve, reject) => {
3536
- const child = spawn3(
4422
+ const child = spawn4(
3537
4423
  runner.command,
3538
4424
  [...runner.argsPrefix, "--noEmit", "-p", projectPath],
3539
4425
  {
@@ -4052,166 +4938,6 @@ async function resolvePlayerCount(projectRoot, flags) {
4052
4938
  return Math.max(1, Math.floor(minPlayers));
4053
4939
  }
4054
4940
 
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 "&amp;";
4186
- case "<":
4187
- return "&lt;";
4188
- case ">":
4189
- return "&gt;";
4190
- case '"':
4191
- return "&quot;";
4192
- default:
4193
- return "&#39;";
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
4941
  // src/dev-host/start-dev-server.ts
4216
4942
  import { rmSync } from "fs";
4217
4943
  import { createRequire as createRequire3 } from "module";
@@ -5329,6 +6055,9 @@ async function assertReducerContractPreflight(projectRoot) {
5329
6055
 
5330
6056
  // src/services/project/reducer-bundle-preflight.ts
5331
6057
  import path13 from "path";
6058
+ import { isPerPlayer, perPlayerSchema } from "@dreamboard-games/sdk/reducer";
6059
+ import "@dreamboard-games/sdk/reducer-contract";
6060
+ import { materializeManifestTable } from "@dreamboard-games/sdk/codegen";
5332
6061
  globalThis.__DREAMBOARD_AUTHORING_WARNINGS__ = true;
5333
6062
  var REDUCER_BUNDLE_ENTRY_PATH = path13.join("app", "index.ts");
5334
6063
  var PREFLIGHT_RNG_SEED = 1337;
@@ -5574,7 +6303,7 @@ function isSourceRevisionPath(filePath) {
5574
6303
  return filePath !== RULE_FILE && isAllowedGamePath(filePath);
5575
6304
  }
5576
6305
  function shouldAlwaysUpsertSourcePath(filePath) {
5577
- return filePath === ".npmrc" || isAuthoritativeGeneratedPath(filePath);
6306
+ return filePath === ".npmrc" || isDynamicGeneratedPath(filePath);
5578
6307
  }
5579
6308
 
5580
6309
  // src/commands/dev.ts
@@ -6149,12 +6878,12 @@ async function readWorkspacePackageJson(projectRoot) {
6149
6878
  return {
6150
6879
  dependencies: Object.fromEntries(
6151
6880
  Object.entries(parsed.dependencies ?? {}).filter(
6152
- ([name]) => name.startsWith("@dreamboard/")
6881
+ ([name]) => isDreamboardPublicPackage(name)
6153
6882
  )
6154
6883
  ),
6155
6884
  devDependencies: Object.fromEntries(
6156
6885
  Object.entries(parsed.devDependencies ?? {}).filter(
6157
- ([name]) => name.startsWith("@dreamboard/")
6886
+ ([name]) => isDreamboardPublicPackage(name)
6158
6887
  )
6159
6888
  )
6160
6889
  };
@@ -6162,6 +6891,9 @@ async function readWorkspacePackageJson(projectRoot) {
6162
6891
  return null;
6163
6892
  }
6164
6893
  }
6894
+ function isDreamboardPublicPackage(packageName) {
6895
+ return packageName === "dreamboard" || packageName.startsWith("@dreamboard-games/");
6896
+ }
6165
6897
  function stableJson(value) {
6166
6898
  if (value === null || typeof value !== "object") {
6167
6899
  return JSON.stringify(value);
@@ -7291,7 +8023,7 @@ async function assertKnownPlayerId(sessionId, playerId) {
7291
8023
  }
7292
8024
 
7293
8025
  // src/commands/login.ts
7294
- import crypto2 from "crypto";
8026
+ import crypto4 from "crypto";
7295
8027
  var login_default = defineCommand({
7296
8028
  meta: {
7297
8029
  name: "login",
@@ -7317,7 +8049,7 @@ var login_default = defineCommand({
7317
8049
  void 0,
7318
8050
  storedSession
7319
8051
  );
7320
- const state = crypto2.randomUUID();
8052
+ const state = crypto4.randomUUID();
7321
8053
  const pkce = createPkcePair();
7322
8054
  const server = await startOAuthCallbackServer(
7323
8055
  state,
@@ -8468,6 +9200,6 @@ function runDreamboardCli(internalSubCommands = {}) {
8468
9200
  void runMain(main).catch(handleFatalError);
8469
9201
  }
8470
9202
 
8471
- // src/index.published.ts
8472
- runDreamboardCli();
9203
+ // src/index.ts
9204
+ runDreamboardCli({ query: query_default, auth: auth_default });
8473
9205
  //# sourceMappingURL=index.js.map