@dreamboard-games/cli 0.1.30-alpha.2 → 0.1.30-alpha.3

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 (87) hide show
  1. package/dist/agent-verifier/agent-workspace-verifier.mjs +227 -0
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  3. package/dist/agent-verifier/chunk-3UKQVWLV.mjs +1744 -0
  4. package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
  5. package/dist/agent-verifier/chunk-776W3UGV.mjs +167 -0
  6. package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
  7. package/dist/agent-verifier/chunk-7WWGFAAU.mjs +729 -0
  8. package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
  9. package/dist/agent-verifier/chunk-A64ZZUZV.mjs +261 -0
  10. package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
  11. package/dist/agent-verifier/chunk-E7SSWJXJ.mjs +3137 -0
  12. package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
  13. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs +302 -0
  14. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  15. package/dist/agent-verifier/chunk-G42BGGG2.mjs +70 -0
  16. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
  17. package/dist/agent-verifier/chunk-H76MT5UR.mjs +57 -0
  18. package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
  19. package/dist/agent-verifier/chunk-HGMUAL33.mjs +39 -0
  20. package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
  21. package/dist/agent-verifier/chunk-IAYRNVUC.mjs +49 -0
  22. package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
  23. package/dist/agent-verifier/chunk-JGT4P4UD.mjs +45 -0
  24. package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
  25. package/dist/agent-verifier/chunk-LUZ7KE6H.mjs +79 -0
  26. package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
  27. package/dist/agent-verifier/chunk-NAK77WXW.mjs +767 -0
  28. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
  29. package/dist/agent-verifier/chunk-O4YCPU7C.mjs +2913 -0
  30. package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
  31. package/dist/agent-verifier/chunk-S34FRJHS.mjs +222 -0
  32. package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
  33. package/dist/agent-verifier/chunk-SH5JKYOB.mjs +226 -0
  34. package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
  35. package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
  36. package/dist/agent-verifier/chunk-SKI2ESE5.mjs.map +1 -0
  37. package/dist/agent-verifier/chunk-TAEQKBJB.mjs +107 -0
  38. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
  39. package/dist/agent-verifier/chunk-UIOLGH4A.mjs +150 -0
  40. package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
  41. package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
  42. package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
  43. package/dist/agent-verifier/chunk-VS573ERH.mjs +14523 -0
  44. package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
  45. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs +624 -0
  46. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
  47. package/dist/agent-verifier/chunk-XGWCY624.mjs +185 -0
  48. package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
  49. package/dist/agent-verifier/chunk-XQXDOBYB.mjs +382 -0
  50. package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
  51. package/dist/agent-verifier/chunk-YE7UAO3T.mjs +129 -0
  52. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  53. package/dist/agent-verifier/chunk-ZEELHSY3.mjs +20 -0
  54. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  55. package/dist/agent-verifier/compile-TEQVA46V.mjs +312 -0
  56. package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
  57. package/dist/agent-verifier/global-config-Y2NTSK4R.mjs +18 -0
  58. package/dist/agent-verifier/global-config-Y2NTSK4R.mjs.map +1 -0
  59. package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs +135 -0
  60. package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
  61. package/dist/agent-verifier/local-files-JFOQQZDL.mjs +45 -0
  62. package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
  63. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
  64. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
  65. package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs +89 -0
  66. package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
  67. package/dist/agent-verifier/project-state-K576C2TE.mjs +33 -0
  68. package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
  69. package/dist/agent-verifier/prompt-MJRJMOGQ.mjs +756 -0
  70. package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
  71. package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs +20 -0
  72. package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
  73. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
  74. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
  75. package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs +50 -0
  76. package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
  77. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
  78. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
  79. package/dist/agent-verifier/sync-THAI546U.mjs +588 -0
  80. package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
  81. package/dist/agent-verifier/test-AFAQFKOB.mjs +353 -0
  82. package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
  83. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
  84. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
  85. package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs +15 -0
  86. package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
  87. package/package.json +3 -2
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CLIENT_PROBLEM_TYPES,
4
+ SERVER_PROBLEM_TYPES,
5
+ zProblemDetails
6
+ } from "./chunk-O4YCPU7C.mjs";
7
+
8
+ // src/utils/problem-types.ts
9
+ var CLI_PROBLEM_TYPES = {
10
+ ...SERVER_PROBLEM_TYPES,
11
+ ...CLIENT_PROBLEM_TYPES
12
+ };
13
+
14
+ // src/utils/errors.ts
15
+ var STALE_CONTRACT_ARTIFACT_CODE = "STALE_CONTRACT_ARTIFACT";
16
+ var STALE_CONTRACT_ARTIFACT_EXIT_CODE = 42;
17
+ function isProblemViolationArray(value) {
18
+ return Array.isArray(value) && value.every(
19
+ (entry) => typeof entry === "object" && entry !== null && typeof entry.message === "string"
20
+ );
21
+ }
22
+ function isProblemDetails(value) {
23
+ return zProblemDetails.safeParse(value).success;
24
+ }
25
+ function coerceViolations(value) {
26
+ if (isProblemViolationArray(value)) {
27
+ return value;
28
+ }
29
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
30
+ return value.map((message) => ({ message }));
31
+ }
32
+ return void 0;
33
+ }
34
+ function getRequestId(response) {
35
+ return response?.headers?.get?.("X-Correlation-ID") ?? response?.headers?.get?.("x-correlation-id") ?? void 0;
36
+ }
37
+ function toApiProblem(error, response, fallback) {
38
+ if (isProblemDetails(error)) {
39
+ return {
40
+ ...error,
41
+ status: error.status || response?.status || 0,
42
+ requestId: error.requestId ?? getRequestId(response)
43
+ };
44
+ }
45
+ if (error instanceof Error) {
46
+ return {
47
+ type: CLI_PROBLEM_TYPES.TRANSPORT_ERROR,
48
+ title: response?.statusText || "API error",
49
+ status: response?.status ?? 0,
50
+ detail: error.message || fallback,
51
+ requestId: getRequestId(response)
52
+ };
53
+ }
54
+ if (error && typeof error === "object") {
55
+ const obj = error;
56
+ const detail2 = typeof obj.detail === "string" ? obj.detail : typeof obj.message === "string" ? obj.message : void 0;
57
+ const title = typeof obj.title === "string" ? obj.title : response?.statusText || "API error";
58
+ const violations = coerceViolations(obj.violations) ?? coerceViolations(obj.errors);
59
+ if (detail2) {
60
+ return {
61
+ type: typeof obj.type === "string" ? obj.type : CLI_PROBLEM_TYPES.UNKNOWN_API_ERROR,
62
+ title,
63
+ status: typeof obj.status === "number" ? obj.status : response?.status ?? 0,
64
+ detail: detail2,
65
+ requestId: typeof obj.requestId === "string" ? obj.requestId : getRequestId(response),
66
+ retryable: typeof obj.retryable === "boolean" ? obj.retryable : void 0,
67
+ context: typeof obj.context === "object" && obj.context !== null ? obj.context : void 0,
68
+ violations,
69
+ timestamp: typeof obj.timestamp === "string" ? obj.timestamp : void 0,
70
+ instance: typeof obj.instance === "string" ? obj.instance : void 0
71
+ };
72
+ }
73
+ }
74
+ const detail = typeof error === "string" ? error.trim() || fallback : fallback;
75
+ return {
76
+ type: CLI_PROBLEM_TYPES.UNKNOWN_API_ERROR,
77
+ title: response?.statusText || "API error",
78
+ status: response?.status ?? 0,
79
+ detail,
80
+ requestId: getRequestId(response)
81
+ };
82
+ }
83
+ function formatProblem(problem) {
84
+ const base = problem.detail || problem.title;
85
+ const violations = problem.violations && problem.violations.length > 0 ? ` (${problem.violations.map((entry) => entry.message).join("; ")})` : "";
86
+ const statusSuffix = problem.status && problem.status > 0 ? ` (HTTP ${problem.status})` : "";
87
+ return `${base}${violations}${statusSuffix}`;
88
+ }
89
+ var DreamboardApiError = class extends Error {
90
+ problem;
91
+ status;
92
+ requestId;
93
+ retryable;
94
+ constructor(problem, cause) {
95
+ super(formatProblem(problem), { cause });
96
+ this.name = "DreamboardApiError";
97
+ this.problem = problem;
98
+ this.status = problem.status;
99
+ this.requestId = problem.requestId;
100
+ this.retryable = problem.retryable;
101
+ }
102
+ };
103
+ function toDreamboardApiError(error, response, fallback) {
104
+ return new DreamboardApiError(toApiProblem(error, response, fallback), error);
105
+ }
106
+ function isDreamboardApiError(error) {
107
+ return error instanceof DreamboardApiError;
108
+ }
109
+ function getObjectStringProperty(value, property) {
110
+ return value && typeof value === "object" && typeof value[property] === "string" ? value[property] : void 0;
111
+ }
112
+ function isStaleContractArtifactMessage(message) {
113
+ return message.includes(STALE_CONTRACT_ARTIFACT_CODE) || message.includes("StaleContractArtifactError") || message.toLowerCase().includes("stale contract artifact");
114
+ }
115
+ function isStaleContractArtifactError(error) {
116
+ if (getObjectStringProperty(error, "code") === STALE_CONTRACT_ARTIFACT_CODE) {
117
+ return true;
118
+ }
119
+ if (getObjectStringProperty(error, "name") === "StaleContractArtifactError") {
120
+ return true;
121
+ }
122
+ const message = getObjectStringProperty(error, "message");
123
+ return message ? isStaleContractArtifactMessage(message) : false;
124
+ }
125
+ function isGameNotFoundProblem(problem) {
126
+ return problem.status === 404 && (problem.detail?.startsWith("Game not found: ") === true || problem.instance?.includes("/source-blobs/upload-sessions") === true);
127
+ }
128
+ function getProblemResolution(problem) {
129
+ if (isGameNotFoundProblem(problem)) {
130
+ return [
131
+ "Run `dreamboard sync --force` to recreate the remote game state from your current local files if this is a local workspace.",
132
+ "If you meant to use an existing remote game, check that your selected `--env` points at the backend that has that game."
133
+ ].join(" ");
134
+ }
135
+ switch (problem.type) {
136
+ case CLI_PROBLEM_TYPES.UNAUTHORIZED:
137
+ return "Run `dreamboard login` to authenticate again.";
138
+ case CLI_PROBLEM_TYPES.FORBIDDEN:
139
+ return "Check that the signed-in account has access to this game, or run `dreamboard login` with the correct account.";
140
+ case CLI_PROBLEM_TYPES.TOO_MANY_REQUESTS:
141
+ return "Wait a moment, then retry the command.";
142
+ case CLI_PROBLEM_TYPES.TRANSPORT_ERROR:
143
+ return "Check that the selected Dreamboard server is reachable and try again later.";
144
+ case CLI_PROBLEM_TYPES.VALIDATION_FAILED:
145
+ return "Fix the validation issue above, then retry the command.";
146
+ case CLI_PROBLEM_TYPES.ACTIVE_JOB_CONFLICT:
147
+ return "Wait for the active job to finish, then retry the command.";
148
+ case CLI_PROBLEM_TYPES.GAME_SLUG_CONFLICT:
149
+ return "Choose a different game slug, or use the existing workspace for that slug.";
150
+ case CLI_PROBLEM_TYPES.SOURCE_REVISION_NOT_FOUND:
151
+ return "Run `dreamboard sync --force` to recreate the remote source revision from your current local files.";
152
+ case CLI_PROBLEM_TYPES.SOURCE_REVISION_DRIFT:
153
+ case CLI_PROBLEM_TYPES.AUTHORING_STATE_DRIFT:
154
+ case CLI_PROBLEM_TYPES.STATE_CONFLICT:
155
+ return "Run `dreamboard pull` to reconcile remote changes before retrying. If this local workspace is the source of truth, rerun the command with `--force` when supported.";
156
+ case CLI_PROBLEM_TYPES.SOURCE_REVISION_BASE_MISSING:
157
+ case CLI_PROBLEM_TYPES.AUTHORING_STATE_BASE_MISSING:
158
+ return "Run `dreamboard pull --force` in a clean workspace to recover the remote authored state. If the remote has no authored state, run `dreamboard sync --force` from the local source-of-truth workspace.";
159
+ case CLI_PROBLEM_TYPES.INTERNAL_ERROR:
160
+ return "Retry the command. If it still fails, include the request id when asking for help.";
161
+ default:
162
+ return void 0;
163
+ }
164
+ }
165
+ function getProblemDetails(problem) {
166
+ return [
167
+ `Problem: ${problem.type}`,
168
+ problem.instance ? `Endpoint: ${problem.instance}` : void 0,
169
+ problem.requestId ? `Request ID: ${problem.requestId}` : void 0,
170
+ problem.timestamp ? `Timestamp: ${problem.timestamp}` : void 0
171
+ ].filter((detail) => Boolean(detail));
172
+ }
173
+ function presentCliError(error) {
174
+ if (isDreamboardApiError(error)) {
175
+ return {
176
+ message: formatProblem(error.problem),
177
+ resolution: getProblemResolution(error.problem),
178
+ details: getProblemDetails(error.problem)
179
+ };
180
+ }
181
+ if (error instanceof Error) {
182
+ return {
183
+ message: error.message,
184
+ details: []
185
+ };
186
+ }
187
+ if (typeof error === "object" && error !== null) {
188
+ let serialized;
189
+ try {
190
+ serialized = JSON.stringify(error);
191
+ } catch {
192
+ serialized = String(error);
193
+ }
194
+ return {
195
+ message: serialized,
196
+ details: []
197
+ };
198
+ }
199
+ return {
200
+ message: String(error),
201
+ details: []
202
+ };
203
+ }
204
+ function formatCliError(error) {
205
+ const presentation = presentCliError(error);
206
+ return [
207
+ presentation.message,
208
+ presentation.resolution ? `Resolution: ${presentation.resolution}` : void 0,
209
+ ...presentation.details
210
+ ].filter((line) => Boolean(line)).join("\n");
211
+ }
212
+
213
+ export {
214
+ STALE_CONTRACT_ARTIFACT_CODE,
215
+ STALE_CONTRACT_ARTIFACT_EXIT_CODE,
216
+ toDreamboardApiError,
217
+ isDreamboardApiError,
218
+ isStaleContractArtifactMessage,
219
+ isStaleContractArtifactError,
220
+ formatCliError
221
+ };
222
+ //# sourceMappingURL=chunk-S34FRJHS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/problem-types.ts","../../src/utils/errors.ts"],"sourcesContent":["import {\n CLIENT_PROBLEM_TYPES,\n SERVER_PROBLEM_TYPES,\n} from \"@dreamboard-games/api-client/problem-types\";\n\nexport { CLIENT_PROBLEM_TYPES, SERVER_PROBLEM_TYPES };\n\nexport const CLI_PROBLEM_TYPES = {\n ...SERVER_PROBLEM_TYPES,\n ...CLIENT_PROBLEM_TYPES,\n} as const;\n\nexport type CliProblemType =\n (typeof CLI_PROBLEM_TYPES)[keyof typeof CLI_PROBLEM_TYPES];\n","import type {\n ProblemDetails,\n ProblemViolation,\n} from \"@dreamboard-games/api-client\";\nimport { zProblemDetails } from \"@dreamboard-games/api-client/zod.gen\";\nimport { CLI_PROBLEM_TYPES } from \"./problem-types.js\";\nimport type { CliProblemType } from \"./problem-types.js\";\n\ntype ApiClientError =\n | ProblemDetails\n | Error\n | string\n | Record<string, unknown>\n | null\n | undefined;\n\ntype ApiProblem = Omit<ProblemDetails, \"type\"> & {\n type: CliProblemType | (string & {});\n};\n\ntype CliErrorPresentation = {\n message: string;\n resolution?: string;\n details: string[];\n};\n\nexport const STALE_CONTRACT_ARTIFACT_CODE = \"STALE_CONTRACT_ARTIFACT\";\nexport const STALE_CONTRACT_ARTIFACT_EXIT_CODE = 42;\n\ntype ResponseLike = {\n status?: number;\n statusText?: string;\n headers?: {\n get?: (name: string) => string | null | undefined;\n };\n};\n\nfunction isProblemViolationArray(value: unknown): value is ProblemViolation[] {\n return (\n Array.isArray(value) &&\n value.every(\n (entry) =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as { message?: unknown }).message === \"string\",\n )\n );\n}\n\nexport function isProblemDetails(value: unknown): value is ProblemDetails {\n return zProblemDetails.safeParse(value).success;\n}\n\nfunction coerceViolations(value: unknown): ProblemViolation[] | undefined {\n if (isProblemViolationArray(value)) {\n return value;\n }\n\n if (\n Array.isArray(value) &&\n value.every((entry) => typeof entry === \"string\")\n ) {\n return value.map((message) => ({ message }));\n }\n\n return undefined;\n}\n\nfunction getRequestId(response?: ResponseLike): string | undefined {\n return (\n response?.headers?.get?.(\"X-Correlation-ID\") ??\n response?.headers?.get?.(\"x-correlation-id\") ??\n undefined\n );\n}\n\nexport function toApiProblem(\n error: ApiClientError,\n response: ResponseLike | undefined,\n fallback: string,\n): ApiProblem {\n if (isProblemDetails(error)) {\n return {\n ...error,\n status: error.status || response?.status || 0,\n requestId: error.requestId ?? getRequestId(response),\n };\n }\n\n if (error instanceof Error) {\n return {\n type: CLI_PROBLEM_TYPES.TRANSPORT_ERROR,\n title: response?.statusText || \"API error\",\n status: response?.status ?? 0,\n detail: error.message || fallback,\n requestId: getRequestId(response),\n };\n }\n\n if (error && typeof error === \"object\") {\n const obj = error as Record<string, unknown>;\n const detail =\n typeof obj.detail === \"string\"\n ? obj.detail\n : typeof obj.message === \"string\"\n ? obj.message\n : undefined;\n const title =\n typeof obj.title === \"string\"\n ? obj.title\n : response?.statusText || \"API error\";\n const violations =\n coerceViolations(obj.violations) ?? coerceViolations(obj.errors);\n\n if (detail) {\n return {\n type:\n typeof obj.type === \"string\"\n ? obj.type\n : CLI_PROBLEM_TYPES.UNKNOWN_API_ERROR,\n title,\n status:\n typeof obj.status === \"number\" ? obj.status : (response?.status ?? 0),\n detail,\n requestId:\n typeof obj.requestId === \"string\"\n ? obj.requestId\n : getRequestId(response),\n retryable:\n typeof obj.retryable === \"boolean\" ? obj.retryable : undefined,\n context:\n typeof obj.context === \"object\" && obj.context !== null\n ? (obj.context as Record<string, string>)\n : undefined,\n violations,\n timestamp:\n typeof obj.timestamp === \"string\" ? obj.timestamp : undefined,\n instance: typeof obj.instance === \"string\" ? obj.instance : undefined,\n };\n }\n }\n\n const detail =\n typeof error === \"string\" ? error.trim() || fallback : fallback;\n\n return {\n type: CLI_PROBLEM_TYPES.UNKNOWN_API_ERROR,\n title: response?.statusText || \"API error\",\n status: response?.status ?? 0,\n detail,\n requestId: getRequestId(response),\n };\n}\n\nfunction formatProblem(problem: ApiProblem): string {\n const base = problem.detail || problem.title;\n const violations =\n problem.violations && problem.violations.length > 0\n ? ` (${problem.violations.map((entry) => entry.message).join(\"; \")})`\n : \"\";\n const statusSuffix =\n problem.status && problem.status > 0 ? ` (HTTP ${problem.status})` : \"\";\n return `${base}${violations}${statusSuffix}`;\n}\n\nexport class DreamboardApiError extends Error {\n readonly problem: ApiProblem;\n readonly status: number;\n readonly requestId?: string;\n readonly retryable?: boolean;\n\n constructor(problem: ApiProblem, cause?: unknown) {\n super(formatProblem(problem), { cause });\n this.name = \"DreamboardApiError\";\n this.problem = problem;\n this.status = problem.status;\n this.requestId = problem.requestId;\n this.retryable = problem.retryable;\n }\n}\n\nexport function toDreamboardApiError(\n error: ApiClientError,\n response: ResponseLike | undefined,\n fallback: string,\n): DreamboardApiError {\n return new DreamboardApiError(toApiProblem(error, response, fallback), error);\n}\n\nexport function formatApiError(\n error: ApiClientError,\n response: ResponseLike | undefined,\n fallback: string,\n): string {\n return formatProblem(toApiProblem(error, response, fallback));\n}\n\nexport function isDreamboardApiError(\n error: unknown,\n): error is DreamboardApiError {\n return error instanceof DreamboardApiError;\n}\n\nexport function isProblemType(error: unknown, ...types: string[]): boolean {\n return isDreamboardApiError(error) && types.includes(error.problem.type);\n}\n\nfunction getObjectStringProperty(\n value: unknown,\n property: string,\n): string | undefined {\n return value &&\n typeof value === \"object\" &&\n typeof (value as Record<string, unknown>)[property] === \"string\"\n ? ((value as Record<string, unknown>)[property] as string)\n : undefined;\n}\n\nexport function isStaleContractArtifactMessage(message: string): boolean {\n return (\n message.includes(STALE_CONTRACT_ARTIFACT_CODE) ||\n message.includes(\"StaleContractArtifactError\") ||\n message.toLowerCase().includes(\"stale contract artifact\")\n );\n}\n\nexport function isStaleContractArtifactError(error: unknown): boolean {\n if (getObjectStringProperty(error, \"code\") === STALE_CONTRACT_ARTIFACT_CODE) {\n return true;\n }\n if (getObjectStringProperty(error, \"name\") === \"StaleContractArtifactError\") {\n return true;\n }\n const message = getObjectStringProperty(error, \"message\");\n return message ? isStaleContractArtifactMessage(message) : false;\n}\n\nexport function getCliErrorExitCode(error: unknown): number {\n return isStaleContractArtifactError(error)\n ? STALE_CONTRACT_ARTIFACT_EXIT_CODE\n : 1;\n}\n\nexport function getProblemContext(\n error: unknown,\n): Record<string, string> | undefined {\n return isDreamboardApiError(error) ? error.problem.context : undefined;\n}\n\nexport function getProblemContextValue(\n error: unknown,\n key: string,\n): string | undefined {\n return getProblemContext(error)?.[key];\n}\n\nfunction isGameNotFoundProblem(problem: ApiProblem): boolean {\n return (\n problem.status === 404 &&\n (problem.detail?.startsWith(\"Game not found: \") === true ||\n problem.instance?.includes(\"/source-blobs/upload-sessions\") === true)\n );\n}\n\nfunction getProblemResolution(problem: ApiProblem): string | undefined {\n if (isGameNotFoundProblem(problem)) {\n return [\n \"Run `dreamboard sync --force` to recreate the remote game state from your current local files if this is a local workspace.\",\n \"If you meant to use an existing remote game, check that your selected `--env` points at the backend that has that game.\",\n ].join(\" \");\n }\n\n switch (problem.type) {\n case CLI_PROBLEM_TYPES.UNAUTHORIZED:\n return \"Run `dreamboard login` to authenticate again.\";\n case CLI_PROBLEM_TYPES.FORBIDDEN:\n return \"Check that the signed-in account has access to this game, or run `dreamboard login` with the correct account.\";\n case CLI_PROBLEM_TYPES.TOO_MANY_REQUESTS:\n return \"Wait a moment, then retry the command.\";\n case CLI_PROBLEM_TYPES.TRANSPORT_ERROR:\n return \"Check that the selected Dreamboard server is reachable and try again later.\";\n case CLI_PROBLEM_TYPES.VALIDATION_FAILED:\n return \"Fix the validation issue above, then retry the command.\";\n case CLI_PROBLEM_TYPES.ACTIVE_JOB_CONFLICT:\n return \"Wait for the active job to finish, then retry the command.\";\n case CLI_PROBLEM_TYPES.GAME_SLUG_CONFLICT:\n return \"Choose a different game slug, or use the existing workspace for that slug.\";\n case CLI_PROBLEM_TYPES.SOURCE_REVISION_NOT_FOUND:\n return \"Run `dreamboard sync --force` to recreate the remote source revision from your current local files.\";\n case CLI_PROBLEM_TYPES.SOURCE_REVISION_DRIFT:\n case CLI_PROBLEM_TYPES.AUTHORING_STATE_DRIFT:\n case CLI_PROBLEM_TYPES.STATE_CONFLICT:\n return \"Run `dreamboard pull` to reconcile remote changes before retrying. If this local workspace is the source of truth, rerun the command with `--force` when supported.\";\n case CLI_PROBLEM_TYPES.SOURCE_REVISION_BASE_MISSING:\n case CLI_PROBLEM_TYPES.AUTHORING_STATE_BASE_MISSING:\n return \"Run `dreamboard pull --force` in a clean workspace to recover the remote authored state. If the remote has no authored state, run `dreamboard sync --force` from the local source-of-truth workspace.\";\n case CLI_PROBLEM_TYPES.INTERNAL_ERROR:\n return \"Retry the command. If it still fails, include the request id when asking for help.\";\n default:\n return undefined;\n }\n}\n\nfunction getProblemDetails(problem: ApiProblem): string[] {\n return [\n `Problem: ${problem.type}`,\n problem.instance ? `Endpoint: ${problem.instance}` : undefined,\n problem.requestId ? `Request ID: ${problem.requestId}` : undefined,\n problem.timestamp ? `Timestamp: ${problem.timestamp}` : undefined,\n ].filter((detail): detail is string => Boolean(detail));\n}\n\nexport function presentCliError(error: unknown): CliErrorPresentation {\n if (isDreamboardApiError(error)) {\n return {\n message: formatProblem(error.problem),\n resolution: getProblemResolution(error.problem),\n details: getProblemDetails(error.problem),\n };\n }\n\n if (error instanceof Error) {\n return {\n message: error.message,\n details: [],\n };\n }\n\n if (typeof error === \"object\" && error !== null) {\n let serialized: string;\n try {\n serialized = JSON.stringify(error);\n } catch {\n serialized = String(error);\n }\n return {\n message: serialized,\n details: [],\n };\n }\n\n return {\n message: String(error),\n details: [],\n };\n}\n\nexport function formatCliError(error: unknown): string {\n const presentation = presentCliError(error);\n return [\n presentation.message,\n presentation.resolution\n ? `Resolution: ${presentation.resolution}`\n : undefined,\n ...presentation.details,\n ]\n .filter((line): line is string => Boolean(line))\n .join(\"\\n\");\n}\n"],"mappings":"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","names":["detail"]}
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ atomicWriteFile,
4
+ withFileLock
5
+ } from "./chunk-TAEQKBJB.mjs";
6
+ import {
7
+ ensureDir,
8
+ readJsonFile
9
+ } from "./chunk-IAYRNVUC.mjs";
10
+ import {
11
+ PROJECT_DIR_NAME
12
+ } from "./chunk-H76MT5UR.mjs";
13
+
14
+ // src/config/global-config.ts
15
+ import os2 from "os";
16
+ import path2 from "path";
17
+
18
+ // src/config/credential-store.ts
19
+ import os from "os";
20
+ import path from "path";
21
+ import { promises as fs } from "fs";
22
+ function getCredentialFilePath() {
23
+ return path.join(os.homedir(), PROJECT_DIR_NAME, "auth.json");
24
+ }
25
+ function getCredentialLockPath() {
26
+ return `${getCredentialFilePath()}.lock`;
27
+ }
28
+ async function fileRead() {
29
+ const filePath = getCredentialFilePath();
30
+ let data;
31
+ try {
32
+ data = await fs.readFile(filePath, "utf8");
33
+ } catch (err) {
34
+ if (err.code === "ENOENT") return null;
35
+ throw err;
36
+ }
37
+ if (data.trim().length === 0) {
38
+ return null;
39
+ }
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(data);
43
+ } catch {
44
+ return null;
45
+ }
46
+ const accessToken = parsed.accessToken ?? parsed.authToken;
47
+ const refreshToken = parsed.refreshToken;
48
+ if (!accessToken && !refreshToken) return null;
49
+ return {
50
+ accessToken: accessToken || void 0,
51
+ refreshToken: refreshToken || void 0,
52
+ tokenExpiresAt: parsed.tokenExpiresAt || void 0,
53
+ clerkOAuthIssuer: parsed.clerkOAuthIssuer || void 0,
54
+ clerkOAuthClientId: parsed.clerkOAuthClientId || void 0,
55
+ clerkOAuthTokenUrl: parsed.clerkOAuthTokenUrl || void 0,
56
+ environment: parsed.environment || void 0
57
+ };
58
+ }
59
+ async function writeFilePayload(payload) {
60
+ await atomicWriteFile(
61
+ getCredentialFilePath(),
62
+ `${JSON.stringify(payload, null, 2)}
63
+ `,
64
+ { mode: 384 }
65
+ );
66
+ }
67
+ async function fileWriteFull(creds) {
68
+ if (!creds.accessToken || !creds.refreshToken) {
69
+ throw new Error(
70
+ "Refusing to persist credentials with an empty accessToken or refreshToken."
71
+ );
72
+ }
73
+ await writeFilePayload({
74
+ authToken: creds.accessToken,
75
+ refreshToken: creds.refreshToken,
76
+ tokenExpiresAt: creds.tokenExpiresAt,
77
+ clerkOAuthIssuer: creds.clerkOAuthIssuer,
78
+ clerkOAuthClientId: creds.clerkOAuthClientId,
79
+ clerkOAuthTokenUrl: creds.clerkOAuthTokenUrl,
80
+ environment: creds.environment
81
+ });
82
+ }
83
+ async function fileWriteAccessOnly(accessToken) {
84
+ if (!accessToken) {
85
+ throw new Error("Refusing to persist an empty access token.");
86
+ }
87
+ await writeFilePayload({ authToken: accessToken });
88
+ }
89
+ async function fileClear() {
90
+ const filePath = getCredentialFilePath();
91
+ try {
92
+ await fs.unlink(filePath);
93
+ } catch (err) {
94
+ if (err.code !== "ENOENT") throw err;
95
+ }
96
+ }
97
+ var fileCredentialBackend = {
98
+ name: "file",
99
+ read: fileRead,
100
+ writeFull: fileWriteFull,
101
+ writeAccessOnly: fileWriteAccessOnly,
102
+ clear: fileClear
103
+ };
104
+ var cachedBackend = null;
105
+ var migrationCompleted = false;
106
+ var backendResolver = defaultBackendResolver;
107
+ async function defaultBackendResolver() {
108
+ const override = (process.env.DREAMBOARD_CREDENTIAL_BACKEND ?? "").trim().toLowerCase();
109
+ if (override === "file") {
110
+ return fileCredentialBackend;
111
+ }
112
+ if (override && override !== "keychain" && override !== "auto") {
113
+ throw new Error(
114
+ `Unknown DREAMBOARD_CREDENTIAL_BACKEND value "${override}" (expected "file", "keychain", or "auto").`
115
+ );
116
+ }
117
+ const useKeychain = override === "keychain" || await readCredentialBackendPreference();
118
+ if (!useKeychain) {
119
+ return fileCredentialBackend;
120
+ }
121
+ const { tryKeychainBackend } = await import("./keychain-backend-SPQWGKZN.mjs");
122
+ const keychain = await tryKeychainBackend();
123
+ if (keychain.available) {
124
+ return keychain.backend;
125
+ }
126
+ return fileCredentialBackend;
127
+ }
128
+ async function readCredentialBackendPreference() {
129
+ try {
130
+ const { loadGlobalConfig: loadGlobalConfig2 } = await import("./global-config-Y2NTSK4R.mjs");
131
+ const config = await loadGlobalConfig2();
132
+ return config.credentialBackend === "keychain";
133
+ } catch {
134
+ return false;
135
+ }
136
+ }
137
+ async function getCredentialBackend() {
138
+ if (cachedBackend === null) {
139
+ cachedBackend = await backendResolver();
140
+ if (!migrationCompleted && cachedBackend.name !== "file") {
141
+ await migrateFromFileBackendIfNeeded(cachedBackend);
142
+ }
143
+ migrationCompleted = true;
144
+ }
145
+ return cachedBackend;
146
+ }
147
+ async function migrateFromFileBackendIfNeeded(target) {
148
+ try {
149
+ const [onDisk, onTarget] = await Promise.all([
150
+ fileCredentialBackend.read(),
151
+ target.read()
152
+ ]);
153
+ if (!onDisk) return;
154
+ if (onTarget) {
155
+ await fileCredentialBackend.clear();
156
+ return;
157
+ }
158
+ if (onDisk.accessToken && onDisk.refreshToken) {
159
+ await target.writeFull({
160
+ accessToken: onDisk.accessToken,
161
+ refreshToken: onDisk.refreshToken
162
+ });
163
+ } else if (onDisk.accessToken) {
164
+ await target.writeAccessOnly(onDisk.accessToken);
165
+ } else {
166
+ return;
167
+ }
168
+ await fileCredentialBackend.clear();
169
+ } catch {
170
+ }
171
+ }
172
+ async function getStoredSession() {
173
+ const backend = await getCredentialBackend();
174
+ return backend.read();
175
+ }
176
+ async function setCredentials(creds) {
177
+ await withFileLock(getCredentialLockPath(), async () => {
178
+ const backend = await getCredentialBackend();
179
+ await backend.writeFull(creds);
180
+ });
181
+ }
182
+
183
+ // src/config/global-config.ts
184
+ function normalizeCredentialBackend(value) {
185
+ if (value === "file" || value === "keychain") return value;
186
+ return void 0;
187
+ }
188
+ function getGlobalConfigPath() {
189
+ return path2.join(os2.homedir(), PROJECT_DIR_NAME, "config.json");
190
+ }
191
+ function getGlobalAuthPath() {
192
+ return getCredentialFilePath();
193
+ }
194
+ async function loadGlobalConfig() {
195
+ const config = await readJsonFile(getGlobalConfigPath()).catch(
196
+ () => ({})
197
+ );
198
+ return {
199
+ environment: config.environment,
200
+ credentialBackend: normalizeCredentialBackend(config.credentialBackend)
201
+ };
202
+ }
203
+ async function saveGlobalConfig(config) {
204
+ const configDir = path2.join(os2.homedir(), PROJECT_DIR_NAME);
205
+ await ensureDir(configDir);
206
+ const normalized = {
207
+ environment: config.environment,
208
+ credentialBackend: normalizeCredentialBackend(config.credentialBackend)
209
+ };
210
+ await atomicWriteFile(
211
+ getGlobalConfigPath(),
212
+ `${JSON.stringify(normalized, null, 2)}
213
+ `,
214
+ { mode: 384 }
215
+ );
216
+ }
217
+
218
+ export {
219
+ getStoredSession,
220
+ setCredentials,
221
+ getGlobalConfigPath,
222
+ getGlobalAuthPath,
223
+ loadGlobalConfig,
224
+ saveGlobalConfig
225
+ };
226
+ //# sourceMappingURL=chunk-SH5JKYOB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/config/global-config.ts","../../src/config/credential-store.ts"],"sourcesContent":["import os from \"node:os\";\nimport path from \"node:path\";\nimport type { CredentialBackendPreference, GlobalConfig } from \"../types.js\";\nimport { PROJECT_DIR_NAME } from \"../constants.js\";\nimport { ensureDir, readJsonFile } from \"../utils/fs.js\";\nimport { atomicWriteFile } from \"../utils/atomic-file.js\";\nimport { getCredentialFilePath } from \"./credential-store.js\";\n\nfunction normalizeCredentialBackend(\n value: unknown,\n): CredentialBackendPreference | undefined {\n if (value === \"file\" || value === \"keychain\") return value;\n // Tolerate unknown / malformed values rather than refusing to load the\n // whole config - an unrecognised backend name should degrade to \"use\n // the default\" instead of locking the user out of their CLI.\n return undefined;\n}\n\nexport function getGlobalConfigPath(): string {\n return path.join(os.homedir(), PROJECT_DIR_NAME, \"config.json\");\n}\n\n/**\n * Path to the on-disk credential file used by the file backend of\n * `CredentialStore`. Re-exported here to avoid circular / ad-hoc imports\n * in UI surface (`auth status`, `config show`, etc).\n */\nexport function getGlobalAuthPath(): string {\n return getCredentialFilePath();\n}\n\n/**\n * Load non-credential CLI configuration.\n *\n * Note: this function used to also load `authToken` / `refreshToken`\n * from `auth.json` and flatten them onto `GlobalConfig`. That shape\n * enabled the refresh-token-wipe bug: `saveGlobalConfig({ ...config })`\n * without explicit auth fields erased the stored refresh token.\n *\n * Credentials are now owned exclusively by `CredentialStore`. Callers\n * that need them must import `getCredentials()` directly.\n */\nexport async function loadGlobalConfig(): Promise<GlobalConfig> {\n const config = await readJsonFile<GlobalConfig>(getGlobalConfigPath()).catch(\n () => ({}) as GlobalConfig,\n );\n return {\n environment: config.environment,\n credentialBackend: normalizeCredentialBackend(config.credentialBackend),\n };\n}\n\n/**\n * Persist non-credential CLI configuration.\n *\n * This function cannot write credentials, by construction: the\n * `GlobalConfig` type has no credential fields. Credentials must be\n * persisted through `setCredentials` / `clearCredentials` from\n * `credential-store.ts`.\n */\nexport async function saveGlobalConfig(config: GlobalConfig): Promise<void> {\n const configDir = path.join(os.homedir(), PROJECT_DIR_NAME);\n await ensureDir(configDir);\n const normalized: GlobalConfig = {\n environment: config.environment,\n credentialBackend: normalizeCredentialBackend(config.credentialBackend),\n };\n await atomicWriteFile(\n getGlobalConfigPath(),\n `${JSON.stringify(normalized, null, 2)}\\n`,\n { mode: 0o600 },\n );\n}\n","/**\n * Single writer for the long-lived Dreamboard session credentials.\n *\n * Design invariants (enforced at the type level and tested in\n * `credential-store.test.ts`):\n *\n * 1. This module is the ONLY place in the CLI that writes credentials to\n * disk or the OS keychain. `global-config.ts` used to own both the\n * config and the credentials via `saveGlobalConfig`, which made it\n * trivial to wipe a refresh token by accident. The `GlobalConfig` type\n * no longer carries credentials, so attempting to persist one through\n * the config path is a type error.\n *\n * 2. The mutating surface is intentionally narrow:\n * - `setCredentials(c)` for refreshable sessions (both tokens present)\n * - `setAccessOnlySession(accessToken)` for the `auth set` / `config set\n * --token` power-user path, which has no refresh token by\n * construction\n * - `clearCredentials()` wipes the file entirely\n * There is no \"partial update\" API. `Credentials` requires both\n * `accessToken` and `refreshToken`, so it is impossible to persist a\n * half-populated refreshable session.\n *\n * 3. Writes go through `atomicWriteFile` + `withFileLock`, so a crash or\n * interrupt during `dreamboard sync`/`compile` cannot leave `auth.json`\n * truncated, and parallel CLI invocations cannot clobber each other's\n * rotated refresh tokens.\n *\n * 4. The on-disk JSON shape for the file backend is kept backward\n * compatible: we continue to read/write `authToken` + `refreshToken`\n * so existing users are not forced to log in again after this change.\n * A newer `accessToken` key is also accepted for read to ease any\n * future format bump.\n *\n * 5. The file backend is the default. The OS keychain is opt-in via\n * `credentialBackend: \"keychain\"` in `~/.dreamboard/config.json`\n * because on macOS the first keychain write triggers a login-password\n * prompt, and re-prompts whenever the executing Node binary's code\n * signature changes (e.g. after an `nvm`/`volta` upgrade). Users who\n * want encrypted-at-rest storage can opt in explicitly; everyone else\n * gets a zero-prompt experience.\n */\n\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport { PROJECT_DIR_NAME } from \"../constants.js\";\nimport {\n atomicWriteFile,\n withFileLock,\n type FileLockOptions,\n} from \"../utils/atomic-file.js\";\n\n/** Fully refreshable session: both tokens required. */\nexport type Credentials = {\n readonly accessToken: string;\n readonly refreshToken: string;\n readonly tokenExpiresAt?: string;\n readonly clerkOAuthIssuer?: string;\n readonly clerkOAuthClientId?: string;\n readonly clerkOAuthTokenUrl?: string;\n readonly environment?: string;\n};\n\n/**\n * Raw on-disk snapshot. Either or both fields may be present. The refresh\n * coordinator only acts on snapshots that have both tokens populated.\n */\nexport type StoredSessionSnapshot = {\n readonly accessToken?: string;\n readonly refreshToken?: string;\n readonly tokenExpiresAt?: string;\n readonly clerkOAuthIssuer?: string;\n readonly clerkOAuthClientId?: string;\n readonly clerkOAuthTokenUrl?: string;\n readonly environment?: string;\n};\n\nexport type CredentialBackendName = \"file\" | \"keychain\";\n\nexport type CredentialBackend = {\n readonly name: CredentialBackendName;\n read(): Promise<StoredSessionSnapshot | null>;\n writeFull(creds: Credentials): Promise<void>;\n writeAccessOnly(accessToken: string): Promise<void>;\n clear(): Promise<void>;\n};\n\nexport type CredentialLockOps = {\n readonly backendName: CredentialBackendName;\n read(): Promise<StoredSessionSnapshot | null>;\n writeFull(creds: Credentials): Promise<void>;\n writeAccessOnly(accessToken: string): Promise<void>;\n clear(): Promise<void>;\n};\n\ntype DiskShape = Partial<{\n accessToken: string;\n authToken: string;\n refreshToken: string;\n tokenExpiresAt: string;\n clerkOAuthIssuer: string;\n clerkOAuthClientId: string;\n clerkOAuthTokenUrl: string;\n environment: string;\n}>;\n\nexport function getCredentialFilePath(): string {\n return path.join(os.homedir(), PROJECT_DIR_NAME, \"auth.json\");\n}\n\nfunction getCredentialLockPath(): string {\n return `${getCredentialFilePath()}.lock`;\n}\n\nasync function fileRead(): Promise<StoredSessionSnapshot | null> {\n const filePath = getCredentialFilePath();\n let data: string;\n try {\n data = await fs.readFile(filePath, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw err;\n }\n if (data.trim().length === 0) {\n return null;\n }\n let parsed: DiskShape;\n try {\n parsed = JSON.parse(data) as DiskShape;\n } catch {\n return null;\n }\n const accessToken = parsed.accessToken ?? parsed.authToken;\n const refreshToken = parsed.refreshToken;\n if (!accessToken && !refreshToken) return null;\n return {\n accessToken: accessToken || undefined,\n refreshToken: refreshToken || undefined,\n tokenExpiresAt: parsed.tokenExpiresAt || undefined,\n clerkOAuthIssuer: parsed.clerkOAuthIssuer || undefined,\n clerkOAuthClientId: parsed.clerkOAuthClientId || undefined,\n clerkOAuthTokenUrl: parsed.clerkOAuthTokenUrl || undefined,\n environment: parsed.environment || undefined,\n };\n}\n\nasync function writeFilePayload(payload: DiskShape): Promise<void> {\n await atomicWriteFile(\n getCredentialFilePath(),\n `${JSON.stringify(payload, null, 2)}\\n`,\n { mode: 0o600 },\n );\n}\n\nasync function fileWriteFull(creds: Credentials): Promise<void> {\n if (!creds.accessToken || !creds.refreshToken) {\n throw new Error(\n \"Refusing to persist credentials with an empty accessToken or refreshToken.\",\n );\n }\n await writeFilePayload({\n authToken: creds.accessToken,\n refreshToken: creds.refreshToken,\n tokenExpiresAt: creds.tokenExpiresAt,\n clerkOAuthIssuer: creds.clerkOAuthIssuer,\n clerkOAuthClientId: creds.clerkOAuthClientId,\n clerkOAuthTokenUrl: creds.clerkOAuthTokenUrl,\n environment: creds.environment,\n });\n}\n\nasync function fileWriteAccessOnly(accessToken: string): Promise<void> {\n if (!accessToken) {\n throw new Error(\"Refusing to persist an empty access token.\");\n }\n await writeFilePayload({ authToken: accessToken });\n}\n\nasync function fileClear(): Promise<void> {\n const filePath = getCredentialFilePath();\n try {\n await fs.unlink(filePath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n}\n\nexport const fileCredentialBackend: CredentialBackend = {\n name: \"file\",\n read: fileRead,\n writeFull: fileWriteFull,\n writeAccessOnly: fileWriteAccessOnly,\n clear: fileClear,\n};\n\nexport type BackendResolver = () =>\n | CredentialBackend\n | Promise<CredentialBackend>;\n\nlet cachedBackend: CredentialBackend | null = null;\nlet migrationCompleted = false;\nlet backendResolver: BackendResolver = defaultBackendResolver;\n\n/**\n * Default resolver precedence:\n *\n * 1. `DREAMBOARD_CREDENTIAL_BACKEND` env var (debugging / CI override).\n * - \"file\" -> force file\n * - \"keychain\" -> force keychain (falls back to file if the native\n * module or the OS keyring is unavailable)\n * - \"auto\" -> same as unset (use config)\n * - unknown -> throw so typos fail loud\n * 2. `credentialBackend` in `~/.dreamboard/config.json`.\n * - \"keychain\" -> opt in to the OS keychain (with file fallback)\n * - \"file\" / unset / malformed -> file\n * 3. Default: file backend.\n *\n * Keychain is opt-in because on macOS the OS login-keychain prompts for\n * the user's password the first time a new binary tries to write to an\n * item, and re-prompts whenever the Node binary signature changes. We\n * would rather ship a zero-prompt default and let users who care about\n * encrypted-at-rest storage enable it.\n *\n * The resolver is async because the keychain probe requires a dynamic\n * `@napi-rs/keyring` import.\n */\nasync function defaultBackendResolver(): Promise<CredentialBackend> {\n const override = (process.env.DREAMBOARD_CREDENTIAL_BACKEND ?? \"\")\n .trim()\n .toLowerCase();\n if (override === \"file\") {\n return fileCredentialBackend;\n }\n if (override && override !== \"keychain\" && override !== \"auto\") {\n // Fail loud on typos rather than silently falling back: this env\n // var exists specifically for users who are debugging auth issues\n // and need to know their override took effect.\n throw new Error(\n `Unknown DREAMBOARD_CREDENTIAL_BACKEND value \"${override}\" (expected \"file\", \"keychain\", or \"auto\").`,\n );\n }\n\n const useKeychain =\n override === \"keychain\" || (await readCredentialBackendPreference());\n if (!useKeychain) {\n return fileCredentialBackend;\n }\n\n const { tryKeychainBackend } = await import(\"./keychain-backend.js\");\n const keychain = await tryKeychainBackend();\n if (keychain.available) {\n return keychain.backend;\n }\n // The user explicitly asked for keychain but the platform can't\n // provide one (no libsecret on Linux, missing native module, etc).\n // Silently degrade to the file backend so the CLI stays usable; the\n // active backend is still visible through `dreamboard auth status`.\n return fileCredentialBackend;\n}\n\nasync function readCredentialBackendPreference(): Promise<boolean> {\n try {\n // Dynamic import to avoid a top-level cycle with `global-config.ts`\n // (which imports `getCredentialFilePath` from this module). Using\n // the async path keeps the cycle purely lazy.\n const { loadGlobalConfig } = await import(\"./global-config.js\");\n const config = await loadGlobalConfig();\n return config.credentialBackend === \"keychain\";\n } catch {\n // If the config file is unreadable or the dynamic import fails\n // (e.g. during early bootstrap), fall back to the file-backed\n // default rather than crashing credential lookups.\n return false;\n }\n}\n\n/**\n * Override which backend is used. Tests use this to inject in-memory\n * backends; production code uses the default keychain-first resolver.\n */\nexport function setCredentialBackendResolver(resolver: BackendResolver): void {\n backendResolver = resolver;\n cachedBackend = null;\n migrationCompleted = false;\n}\n\nexport async function getCredentialBackend(): Promise<CredentialBackend> {\n if (cachedBackend === null) {\n cachedBackend = await backendResolver();\n // One-time migration: if we resolved to a non-file backend and\n // `auth.json` still has credentials from the old layout, copy them\n // over and remove the file. We only do this when the new backend is\n // empty, so repeated migrations cannot stomp a newer keychain\n // session with a stale file session.\n if (!migrationCompleted && cachedBackend.name !== \"file\") {\n await migrateFromFileBackendIfNeeded(cachedBackend);\n }\n migrationCompleted = true;\n }\n return cachedBackend;\n}\n\nasync function migrateFromFileBackendIfNeeded(\n target: CredentialBackend,\n): Promise<void> {\n try {\n const [onDisk, onTarget] = await Promise.all([\n fileCredentialBackend.read(),\n target.read(),\n ]);\n if (!onDisk) return;\n if (onTarget) {\n // Target already has a session - the user has already migrated.\n // Remove the file so it cannot get re-used accidentally.\n await fileCredentialBackend.clear();\n return;\n }\n if (onDisk.accessToken && onDisk.refreshToken) {\n await target.writeFull({\n accessToken: onDisk.accessToken,\n refreshToken: onDisk.refreshToken,\n });\n } else if (onDisk.accessToken) {\n await target.writeAccessOnly(onDisk.accessToken);\n } else {\n return;\n }\n await fileCredentialBackend.clear();\n } catch {\n // Migration is best-effort. A failure here should not block CLI\n // operation; on next run the file backend is still consulted\n // directly because the keychain backend's `read` returns null and\n // callers fall through to \"missing session\" → login prompt.\n }\n}\n\nexport async function getActiveCredentialBackendName(): Promise<CredentialBackendName> {\n const backend = await getCredentialBackend();\n return backend.name;\n}\n\n/** Loose read: returns whatever is on disk, including access-only sessions. */\nexport async function getStoredSession(): Promise<StoredSessionSnapshot | null> {\n const backend = await getCredentialBackend();\n return backend.read();\n}\n\n/** Strict read: returns a refreshable pair, or null if either token is missing. */\nexport async function getCredentials(): Promise<Credentials | null> {\n const snapshot = await getStoredSession();\n if (!snapshot) return null;\n const { accessToken, refreshToken } = snapshot;\n if (!accessToken || !refreshToken) return null;\n return { accessToken, refreshToken };\n}\n\nexport async function setCredentials(creds: Credentials): Promise<void> {\n await withFileLock(getCredentialLockPath(), async () => {\n const backend = await getCredentialBackend();\n await backend.writeFull(creds);\n });\n}\n\nexport async function setAccessOnlySession(accessToken: string): Promise<void> {\n await withFileLock(getCredentialLockPath(), async () => {\n const backend = await getCredentialBackend();\n await backend.writeAccessOnly(accessToken);\n });\n}\n\nexport async function clearCredentials(): Promise<void> {\n await withFileLock(getCredentialLockPath(), async () => {\n const backend = await getCredentialBackend();\n await backend.clear();\n });\n}\n\n/**\n * Run `fn` while holding the cross-process credential lock. `fn` receives\n * an ops handle that reads/writes the active backend without re-acquiring\n * the lock (avoiding deadlock).\n *\n * This is the only correct way to perform a read-modify-write on stored\n * credentials (e.g. CLI refresh rotation) in the presence of\n * concurrent CLI invocations.\n */\nexport async function withCredentialLock<T>(\n fn: (ops: CredentialLockOps) => Promise<T>,\n options?: FileLockOptions,\n): Promise<T> {\n return withFileLock(\n getCredentialLockPath(),\n async () => {\n const backend = await getCredentialBackend();\n const ops: CredentialLockOps = {\n backendName: backend.name,\n read: () => backend.read(),\n writeFull: (creds) => backend.writeFull(creds),\n writeAccessOnly: (accessToken) => backend.writeAccessOnly(accessToken),\n clear: () => backend.clear(),\n };\n return fn(ops);\n },\n options,\n );\n}\n\n/** Test-only reset of module state. Not exported through the barrel. */\nexport function _resetCredentialStoreForTests(): void {\n cachedBackend = null;\n migrationCompleted = false;\n backendResolver = defaultBackendResolver;\n}\n"],"mappings":"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","names":["os","path","loadGlobalConfig","path","os"]}
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __export = (target, all) => {
18
+ for (var name in all)
19
+ __defProp(target, name, { get: all[name], enumerable: true });
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") {
23
+ for (let key of __getOwnPropNames(from))
24
+ if (!__hasOwnProp.call(to, key) && key !== except)
25
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
26
+ }
27
+ return to;
28
+ };
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
37
+
38
+ export {
39
+ __require,
40
+ __commonJS,
41
+ __export,
42
+ __toESM
43
+ };
44
+ //# sourceMappingURL=chunk-SKI2ESE5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}