gws-axi 0.1.0

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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/bin/gws-axi.d.ts +2 -0
  4. package/dist/bin/gws-axi.js +4 -0
  5. package/dist/bin/gws-axi.js.map +1 -0
  6. package/dist/src/auth/gcloud.d.ts +21 -0
  7. package/dist/src/auth/gcloud.js +134 -0
  8. package/dist/src/auth/gcloud.js.map +1 -0
  9. package/dist/src/auth/loopback.d.ts +50 -0
  10. package/dist/src/auth/loopback.js +420 -0
  11. package/dist/src/auth/loopback.js.map +1 -0
  12. package/dist/src/auth/pending.d.ts +15 -0
  13. package/dist/src/auth/pending.js +35 -0
  14. package/dist/src/auth/pending.js.map +1 -0
  15. package/dist/src/auth/scopes.d.ts +13 -0
  16. package/dist/src/auth/scopes.js +29 -0
  17. package/dist/src/auth/scopes.js.map +1 -0
  18. package/dist/src/auth/setup-html.d.ts +13 -0
  19. package/dist/src/auth/setup-html.js +245 -0
  20. package/dist/src/auth/setup-html.js.map +1 -0
  21. package/dist/src/auth/state.d.ts +4 -0
  22. package/dist/src/auth/state.js +41 -0
  23. package/dist/src/auth/state.js.map +1 -0
  24. package/dist/src/auth/steps.d.ts +30 -0
  25. package/dist/src/auth/steps.js +306 -0
  26. package/dist/src/auth/steps.js.map +1 -0
  27. package/dist/src/cli.d.ts +2 -0
  28. package/dist/src/cli.js +72 -0
  29. package/dist/src/cli.js.map +1 -0
  30. package/dist/src/commands/auth.d.ts +2 -0
  31. package/dist/src/commands/auth.js +453 -0
  32. package/dist/src/commands/auth.js.map +1 -0
  33. package/dist/src/commands/calendar/calendars.d.ts +2 -0
  34. package/dist/src/commands/calendar/calendars.js +98 -0
  35. package/dist/src/commands/calendar/calendars.js.map +1 -0
  36. package/dist/src/commands/calendar/events.d.ts +2 -0
  37. package/dist/src/commands/calendar/events.js +261 -0
  38. package/dist/src/commands/calendar/events.js.map +1 -0
  39. package/dist/src/commands/calendar/get.d.ts +2 -0
  40. package/dist/src/commands/calendar/get.js +176 -0
  41. package/dist/src/commands/calendar/get.js.map +1 -0
  42. package/dist/src/commands/calendar.d.ts +2 -0
  43. package/dist/src/commands/calendar.js +76 -0
  44. package/dist/src/commands/calendar.js.map +1 -0
  45. package/dist/src/commands/docs.d.ts +2 -0
  46. package/dist/src/commands/docs.js +19 -0
  47. package/dist/src/commands/docs.js.map +1 -0
  48. package/dist/src/commands/doctor.d.ts +2 -0
  49. package/dist/src/commands/doctor.js +213 -0
  50. package/dist/src/commands/doctor.js.map +1 -0
  51. package/dist/src/commands/drive.d.ts +2 -0
  52. package/dist/src/commands/drive.js +17 -0
  53. package/dist/src/commands/drive.js.map +1 -0
  54. package/dist/src/commands/gmail.d.ts +2 -0
  55. package/dist/src/commands/gmail.js +20 -0
  56. package/dist/src/commands/gmail.js.map +1 -0
  57. package/dist/src/commands/home.d.ts +1 -0
  58. package/dist/src/commands/home.js +42 -0
  59. package/dist/src/commands/home.js.map +1 -0
  60. package/dist/src/commands/service-stub.d.ts +8 -0
  61. package/dist/src/commands/service-stub.js +67 -0
  62. package/dist/src/commands/service-stub.js.map +1 -0
  63. package/dist/src/commands/slides.d.ts +2 -0
  64. package/dist/src/commands/slides.js +11 -0
  65. package/dist/src/commands/slides.js.map +1 -0
  66. package/dist/src/config.d.ts +46 -0
  67. package/dist/src/config.js +155 -0
  68. package/dist/src/config.js.map +1 -0
  69. package/dist/src/google/account.d.ts +12 -0
  70. package/dist/src/google/account.js +65 -0
  71. package/dist/src/google/account.js.map +1 -0
  72. package/dist/src/google/client.d.ts +29 -0
  73. package/dist/src/google/client.js +106 -0
  74. package/dist/src/google/client.js.map +1 -0
  75. package/dist/src/google/probe.d.ts +15 -0
  76. package/dist/src/google/probe.js +200 -0
  77. package/dist/src/google/probe.js.map +1 -0
  78. package/dist/src/google/tokens.d.ts +22 -0
  79. package/dist/src/google/tokens.js +91 -0
  80. package/dist/src/google/tokens.js.map +1 -0
  81. package/dist/src/output/index.d.ts +2 -0
  82. package/dist/src/output/index.js +3 -0
  83. package/dist/src/output/index.js.map +1 -0
  84. package/dist/src/output/render.d.ts +40 -0
  85. package/dist/src/output/render.js +65 -0
  86. package/dist/src/output/render.js.map +1 -0
  87. package/dist/src/output/schema.d.ts +32 -0
  88. package/dist/src/output/schema.js +69 -0
  89. package/dist/src/output/schema.js.map +1 -0
  90. package/package.json +61 -0
@@ -0,0 +1,245 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { configDir, getDefaultAccount, listAccounts, profilePathForAccount, readSetupState, tokensPathForAccount, SETUP_STEP_ORDER, } from "../config.js";
4
+ import { consoleUrl } from "./steps.js";
5
+ import { REQUIRED_APIS, SERVICES } from "./scopes.js";
6
+ const STEP_LABELS = {
7
+ gcp_project: "Choose or create GCP project",
8
+ apis_enabled: "Enable Google Workspace APIs",
9
+ oauth_client: "Create Desktop OAuth client",
10
+ credentials_saved: "Save credentials JSON to config dir",
11
+ consent_screen: "Configure OAuth consent screen",
12
+ test_user_added: "Add test users (each Google account you'll authenticate)",
13
+ tokens_obtained: "Run OAuth loopback flow to obtain tokens",
14
+ };
15
+ function linksForStep(key, projectId) {
16
+ switch (key) {
17
+ case "gcp_project":
18
+ return [
19
+ {
20
+ label: "Create project in Console",
21
+ url: "https://console.cloud.google.com/projectcreate",
22
+ },
23
+ ];
24
+ case "apis_enabled":
25
+ return SERVICES.map((s) => ({
26
+ label: `Enable ${s}`,
27
+ url: consoleUrl(`/apis/library/${REQUIRED_APIS[s]}`, projectId),
28
+ }));
29
+ case "oauth_client":
30
+ return [
31
+ {
32
+ label: "OAuth clients → Create client",
33
+ url: consoleUrl("/auth/clients", projectId),
34
+ },
35
+ ];
36
+ case "consent_screen":
37
+ return [
38
+ {
39
+ label: "Branding (app name, emails)",
40
+ url: consoleUrl("/auth/branding", projectId),
41
+ },
42
+ {
43
+ label: "Audience (user type)",
44
+ url: consoleUrl("/auth/audience", projectId),
45
+ },
46
+ ];
47
+ case "test_user_added":
48
+ return [
49
+ {
50
+ label: "Audience → Test users",
51
+ url: consoleUrl("/auth/audience", projectId),
52
+ },
53
+ ];
54
+ default:
55
+ return [];
56
+ }
57
+ }
58
+ export function setupHtmlPath() {
59
+ return join(configDir(), "setup.html");
60
+ }
61
+ function readAccountRows() {
62
+ const emails = listAccounts();
63
+ const defaultAccount = getDefaultAccount();
64
+ return emails.map((email) => {
65
+ const row = {
66
+ email,
67
+ scopeCount: 0,
68
+ isDefault: email === defaultAccount,
69
+ };
70
+ try {
71
+ const profile = JSON.parse(readFileSync(profilePathForAccount(email), "utf-8"));
72
+ row.name = profile.name;
73
+ }
74
+ catch {
75
+ // no profile yet
76
+ }
77
+ try {
78
+ const tokens = JSON.parse(readFileSync(tokensPathForAccount(email), "utf-8"));
79
+ row.obtainedAt = tokens.obtained_at;
80
+ row.scopeCount = tokens.scope
81
+ ? tokens.scope.split(" ").filter(Boolean).length
82
+ : 0;
83
+ }
84
+ catch {
85
+ // no tokens file
86
+ }
87
+ return row;
88
+ });
89
+ }
90
+ export function writeSetupHtml(options = {}) {
91
+ const state = readSetupState();
92
+ const projectId = state.steps.gcp_project.project_id;
93
+ const nextKey = SETUP_STEP_ORDER.find((k) => !state.steps[k].done);
94
+ const progress = SETUP_STEP_ORDER.filter((k) => state.steps[k].done).length;
95
+ const initialSetupDone = nextKey === undefined;
96
+ const accounts = readAccountRows();
97
+ const rows = SETUP_STEP_ORDER.map((key, idx) => {
98
+ const step = state.steps[key];
99
+ const isNext = key === nextKey;
100
+ const status = step.done ? "✓ done" : isNext ? "→ next" : "… pending";
101
+ const statusClass = step.done ? "done" : isNext ? "next" : "pending";
102
+ const links = linksForStep(key, projectId)
103
+ .map((l) => `<a href="${l.url}" target="_blank" rel="noopener">${l.label}</a>`)
104
+ .join(" · ");
105
+ return `<tr class="${statusClass}">
106
+ <td class="num">${idx + 1}</td>
107
+ <td class="status">${status}</td>
108
+ <td class="name">${STEP_LABELS[key]}</td>
109
+ <td class="links">${links || "<em>no external action needed</em>"}</td>
110
+ </tr>`;
111
+ }).join("\n");
112
+ const now = new Date();
113
+ const nowLabel = now.toLocaleTimeString();
114
+ const pendingAuthBlock = options.pendingAuth
115
+ ? `<div class="pending-auth">
116
+ <div class="pending-auth-title">Waiting for authentication${options.pendingAuth.account ? ` as <code>${options.pendingAuth.account}</code>` : ""}</div>
117
+ <p><strong>Wrong browser profile?</strong> If you're not currently signed into ${options.pendingAuth.account ? `<code>${options.pendingAuth.account}</code>` : "the target account"} in this browser, open <code>~/.config/gws-axi/setup.html</code> in the correct profile before clicking below — Google will pick up whichever account is active here.</p>
118
+ <a class="auth-button" href="${options.pendingAuth.url}" target="_blank" rel="noopener">Authenticate with Google &rarr;</a>
119
+ <p class="pending-auth-note">The CLI is listening for the callback on 127.0.0.1 — this button only works while <code>gws-axi auth login --wait</code> is blocking in your terminal. Sign in${options.pendingAuth.account ? ` as <code>${options.pendingAuth.account}</code>` : ""} at Google's prompt and approve the scopes.</p>
120
+ </div>`
121
+ : "";
122
+ const accountsBlock = accounts.length
123
+ ? `<div class="accounts-section">
124
+ <h2>Accounts (${accounts.length})</h2>
125
+ <table class="accounts">
126
+ <thead><tr><th>Email</th><th>Name</th><th>Scopes</th><th>Added</th><th>Default</th></tr></thead>
127
+ <tbody>
128
+ ${accounts
129
+ .map((a) => ` <tr>
130
+ <td><code>${a.email}</code></td>
131
+ <td>${a.name ?? "<em>—</em>"}</td>
132
+ <td>${a.scopeCount}</td>
133
+ <td>${a.obtainedAt ? new Date(a.obtainedAt).toLocaleString() : "<em>pending</em>"}</td>
134
+ <td>${a.isDefault ? "<span class=\"default-badge\">default</span>" : ""}</td>
135
+ </tr>`)
136
+ .join("\n")}
137
+ </tbody>
138
+ </table>
139
+ </div>`
140
+ : "";
141
+ const addAnotherBlock = initialSetupDone
142
+ ? `<div class="add-another">
143
+ <h3>Add another Google account</h3>
144
+ <p>The same OAuth client handles multiple Google accounts (e.g. personal + work). To add one:</p>
145
+ <ol>
146
+ <li>Make sure the account is added as a test user on the <a href="${consoleUrl("/auth/audience", projectId)}" target="_blank" rel="noopener">Audience page</a> (otherwise Google rejects with access_denied)</li>
147
+ <li>In your terminal, run <code>gws-axi auth login --account &lt;email&gt;</code></li>
148
+ <li>This page will show an "Authenticate with Google" button within 10 seconds — click it to consent as that account</li>
149
+ </ol>
150
+ </div>`
151
+ : "";
152
+ const footerText = initialSetupDone
153
+ ? `Setup is complete. Keep this tab open — it will show an "Authenticate" button when you run <code>gws-axi auth login --account &lt;email&gt;</code> to add a new account. Regenerated every time a gws-axi auth command runs.`
154
+ : `Click the links above to complete each step in <em>this</em> browser (so you stay in the Google account you're signed into). Regenerated every time you run <code>gws-axi auth setup</code>.`;
155
+ const summaryContent = initialSetupDone
156
+ ? `<strong>Status:</strong> Setup complete · OAuth client ready<br>
157
+ <strong>Project:</strong> ${projectId ? `<code>${projectId}</code>` : "(not set)"}<br>
158
+ <strong>Accounts:</strong> ${accounts.length} authenticated${accounts.length > 1 ? ` · write protection active (writes require <code>--account</code>)` : ""}`
159
+ : `<strong>Project:</strong> ${projectId ? `<code>${projectId}</code>` : "(not set yet)"}<br>
160
+ <strong>Progress:</strong> ${progress} of ${SETUP_STEP_ORDER.length} steps complete
161
+ ${nextKey ? `<br><strong>Next step:</strong> <code>${STEP_LABELS[nextKey]}</code> — click the buttons below, then run <code>gws-axi auth setup</code> to continue` : ""}`;
162
+ const html = `<!doctype html>
163
+ <html lang="en">
164
+ <head>
165
+ <meta charset="utf-8">
166
+ <meta http-equiv="refresh" content="10">
167
+ <title>gws-axi — setup</title>
168
+ <style>
169
+ body { font-family: -apple-system, system-ui, "Segoe UI", sans-serif; max-width: 900px; margin: 40px auto; padding: 24px; color: #222; }
170
+ h1 { margin-top: 0; }
171
+ h2 { margin-top: 28px; margin-bottom: 12px; font-size: 18px; }
172
+ h3 { margin-top: 24px; margin-bottom: 8px; font-size: 16px; }
173
+ .summary { background: #f4f8fb; border-left: 4px solid #3b82f6; padding: 12px 16px; border-radius: 4px; margin-bottom: 24px; }
174
+ .refresh { font-size: 12px; color: #6b7280; margin-top: 6px; }
175
+ .pending-auth { background: #fef3c7; border: 2px solid #f59e0b; padding: 20px 24px; border-radius: 6px; margin-bottom: 24px; }
176
+ .pending-auth-title { font-size: 18px; font-weight: 600; color: #92400e; margin-bottom: 8px; }
177
+ .pending-auth p { margin: 8px 0; }
178
+ .pending-auth-note { font-size: 13px; color: #78350f; }
179
+ .auth-button { display: inline-block; padding: 10px 20px; background: #4285f4; color: white; text-decoration: none; border-radius: 6px; font-weight: 500; margin: 8px 0; }
180
+ .auth-button:hover { background: #3367d6; }
181
+ table { width: 100%; border-collapse: collapse; }
182
+ th, td { padding: 10px 12px; text-align: left; border-bottom: 1px solid #e4e4e7; vertical-align: top; }
183
+ th { background: #fafafa; font-size: 13px; color: #555; text-transform: uppercase; letter-spacing: 0.5px; }
184
+ tr.done { opacity: 0.55; }
185
+ tr.done .status { color: #1a7f37; font-weight: 500; }
186
+ tr.next { background: #fffbeb; }
187
+ tr.next .status { color: #b45309; font-weight: 600; }
188
+ tr.pending .status { color: #8a5a00; }
189
+ td.num { font-family: ui-monospace, Menlo, monospace; color: #999; width: 32px; }
190
+ td.name { font-weight: 500; width: 260px; }
191
+ td.links { font-size: 14px; }
192
+ td.links a { display: inline-block; margin-right: 8px; padding: 4px 10px; border-radius: 4px; background: #eff6ff; color: #1d4ed8; text-decoration: none; font-size: 13px; }
193
+ td.links a:hover { background: #dbeafe; }
194
+ tr.done td.links a { background: #f4f4f5; color: #6b7280; }
195
+ .accounts-section { margin-top: 24px; }
196
+ .accounts { margin-bottom: 8px; }
197
+ .accounts td, .accounts th { font-size: 14px; }
198
+ .accounts td { vertical-align: middle; }
199
+ .default-badge { background: #dbeafe; color: #1d4ed8; font-size: 12px; padding: 2px 8px; border-radius: 10px; font-weight: 500; }
200
+ .add-another { margin-top: 24px; padding: 16px 20px; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 6px; }
201
+ .add-another ol { margin: 8px 0 0 20px; padding: 0; }
202
+ .add-another li { margin: 6px 0; }
203
+ details.steps { margin-top: 24px; }
204
+ details.steps summary { cursor: pointer; color: #4b5563; font-size: 14px; padding: 6px 0; }
205
+ details.steps summary:hover { color: #111827; }
206
+ footer { margin-top: 32px; font-size: 13px; color: #666; }
207
+ code { background: #f4f4f5; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
208
+ </style>
209
+ </head>
210
+ <body>
211
+ <h1>gws-axi · setup</h1>
212
+ ${pendingAuthBlock}
213
+ <div class="summary">
214
+ ${summaryContent}
215
+ <div class="refresh">Auto-refreshes every 10 seconds · last rendered at ${nowLabel}</div>
216
+ </div>
217
+ ${accountsBlock}
218
+ ${addAnotherBlock}
219
+ ${initialSetupDone
220
+ ? `<details class="steps"><summary>Show initial setup steps (all complete)</summary>
221
+ <table>
222
+ <thead><tr><th>#</th><th>Status</th><th>Step</th><th>Console links</th></tr></thead>
223
+ <tbody>
224
+ ${rows}
225
+ </tbody>
226
+ </table>
227
+ </details>`
228
+ : `<table>
229
+ <thead><tr><th>#</th><th>Status</th><th>Step</th><th>Console links</th></tr></thead>
230
+ <tbody>
231
+ ${rows}
232
+ </tbody>
233
+ </table>`}
234
+ <footer>
235
+ ${footerText}
236
+ </footer>
237
+ </body>
238
+ </html>
239
+ `;
240
+ const path = setupHtmlPath();
241
+ mkdirSync(dirname(path), { recursive: true });
242
+ writeFileSync(path, html);
243
+ return path;
244
+ }
245
+ //# sourceMappingURL=setup-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-html.js","sourceRoot":"","sources":["../../../src/auth/setup-html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type SetupState, type SetupStepKey } from "../config.js";
2
+ export declare function markStepDone(key: SetupStepKey, detail?: Record<string, unknown>): SetupState;
3
+ export declare function updateStepMetadata(key: SetupStepKey, detail: Record<string, unknown>): SetupState;
4
+ export declare function resetFrom(key: SetupStepKey | null): SetupState;
@@ -0,0 +1,41 @@
1
+ import { readSetupState, writeSetupState, SETUP_STEP_ORDER, } from "../config.js";
2
+ export function markStepDone(key, detail = {}) {
3
+ const state = readSetupState();
4
+ state.steps[key] = {
5
+ ...state.steps[key],
6
+ ...detail,
7
+ done: true,
8
+ at: new Date().toISOString(),
9
+ };
10
+ updateResumeHint(state);
11
+ writeSetupState(state);
12
+ return state;
13
+ }
14
+ export function updateStepMetadata(key, detail) {
15
+ const state = readSetupState();
16
+ state.steps[key] = { ...state.steps[key], ...detail };
17
+ updateResumeHint(state);
18
+ writeSetupState(state);
19
+ return state;
20
+ }
21
+ export function resetFrom(key) {
22
+ const state = readSetupState();
23
+ const startIndex = key ? SETUP_STEP_ORDER.indexOf(key) : 0;
24
+ for (let i = startIndex; i < SETUP_STEP_ORDER.length; i++) {
25
+ state.steps[SETUP_STEP_ORDER[i]] = { done: false };
26
+ }
27
+ updateResumeHint(state);
28
+ writeSetupState(state);
29
+ return state;
30
+ }
31
+ function updateResumeHint(state) {
32
+ const next = SETUP_STEP_ORDER.find((k) => !state.steps[k].done);
33
+ if (!next) {
34
+ state.last_action = "complete";
35
+ state.resume_hint = "Run `gws-axi doctor` to verify runtime health";
36
+ return;
37
+ }
38
+ state.last_action = `awaiting:${next}`;
39
+ state.resume_hint = `Run \`gws-axi auth setup\` to continue at step ${next}`;
40
+ }
41
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/auth/state.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,eAAe,EAGf,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,MAAM,UAAU,YAAY,CAC1B,GAAiB,EACjB,SAAkC,EAAE;IAEpC,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG;QACjB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QACnB,GAAG,MAAM;QACT,IAAI,EAAE,IAAI;QACV,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAC7B,CAAC;IACF,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxB,eAAe,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,GAAiB,EACjB,MAA+B;IAE/B,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;IACtD,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxB,eAAe,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAwB;IAChD,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1D,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACrD,CAAC;IACD,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACxB,eAAe,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAiB;IACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;QAC/B,KAAK,CAAC,WAAW,GAAG,+CAA+C,CAAC;QACpE,OAAO;IACT,CAAC;IACD,KAAK,CAAC,WAAW,GAAG,YAAY,IAAI,EAAE,CAAC;IACvC,KAAK,CAAC,WAAW,GAAG,kDAAkD,IAAI,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { type SetupState, type SetupStepKey } from "../config.js";
2
+ export interface SetupFlags {
3
+ projectId?: string;
4
+ createProject?: string;
5
+ projectName?: string;
6
+ credentialsJson?: string;
7
+ testUserEmail?: string;
8
+ port?: number;
9
+ }
10
+ export interface DeepLink {
11
+ label: string;
12
+ url: string;
13
+ }
14
+ export interface StepOutcome {
15
+ step: SetupStepKey;
16
+ advanced: boolean;
17
+ title: string;
18
+ detail?: Record<string, unknown>;
19
+ instructions?: string[];
20
+ deep_links?: DeepLink[];
21
+ error?: string;
22
+ code?: string;
23
+ }
24
+ export declare function consoleUrl(path: string, projectId?: string): string;
25
+ export declare function advanceGcpProject(flags: SetupFlags): Promise<StepOutcome>;
26
+ export declare function advanceApisEnabled(_flags: SetupFlags, state: SetupState): Promise<StepOutcome>;
27
+ export declare function advanceOauthClient(_flags: SetupFlags, _state: SetupState): Promise<StepOutcome>;
28
+ export declare function advanceCredentialsSaved(flags: SetupFlags): Promise<StepOutcome>;
29
+ export declare function advanceConsentScreen(_flags: SetupFlags, _state: SetupState): Promise<StepOutcome>;
30
+ export declare function advanceTestUserAdded(flags: SetupFlags, _state: SetupState): Promise<StepOutcome>;
@@ -0,0 +1,306 @@
1
+ import { copyFileSync, existsSync, readFileSync, mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { credentialsPath, } from "../config.js";
4
+ import { markStepDone, updateStepMetadata } from "./state.js";
5
+ import { createProject, enableApis, gcloudAccount, isGcloudInstalled, listEnabledApis, listProjects, } from "./gcloud.js";
6
+ import { allApis, REQUIRED_APIS, SERVICES } from "./scopes.js";
7
+ export function consoleUrl(path, projectId) {
8
+ const base = `https://console.cloud.google.com${path}`;
9
+ return projectId ? `${base}?project=${encodeURIComponent(projectId)}` : base;
10
+ }
11
+ // STEP 1 — gcp_project ─────────────────────────────────────────────
12
+ export async function advanceGcpProject(flags) {
13
+ const step = "gcp_project";
14
+ if (flags.projectId) {
15
+ if (isGcloudInstalled()) {
16
+ const projects = listProjects();
17
+ if (projects.ok) {
18
+ const found = projects.value.find((p) => p.projectId === flags.projectId);
19
+ if (!found) {
20
+ return {
21
+ step,
22
+ advanced: false,
23
+ title: "Project not found",
24
+ error: `No project with ID '${flags.projectId}' in this gcloud account`,
25
+ code: "PROJECT_NOT_FOUND",
26
+ instructions: [
27
+ "List available projects: `gcloud projects list`",
28
+ "Or create a new one: `gws-axi auth setup --create-project <id>`",
29
+ ],
30
+ };
31
+ }
32
+ }
33
+ }
34
+ markStepDone(step, {
35
+ project_id: flags.projectId,
36
+ created_by_us: false,
37
+ });
38
+ return {
39
+ step,
40
+ advanced: true,
41
+ title: "GCP project selected",
42
+ detail: { project_id: flags.projectId },
43
+ };
44
+ }
45
+ if (flags.createProject) {
46
+ if (!isGcloudInstalled()) {
47
+ return {
48
+ step,
49
+ advanced: false,
50
+ title: "gcloud CLI required for project creation",
51
+ error: "Cannot create a GCP project without the gcloud CLI",
52
+ code: "GCLOUD_REQUIRED",
53
+ instructions: [
54
+ "Install the gcloud CLI: https://cloud.google.com/sdk/docs/install",
55
+ "Or in your gws-axi setup page tab, click 'Create project in Console', then re-run with --project <id>",
56
+ ],
57
+ };
58
+ }
59
+ const displayName = flags.projectName ?? flags.createProject;
60
+ const result = createProject(flags.createProject, displayName);
61
+ if (!result.ok) {
62
+ return {
63
+ step,
64
+ advanced: false,
65
+ title: "Failed to create GCP project",
66
+ error: result.message,
67
+ code: result.code,
68
+ instructions: [
69
+ "Try a different project ID (must be globally unique, 6-30 chars)",
70
+ "Or create via Console and re-run with --project <id>",
71
+ ],
72
+ };
73
+ }
74
+ markStepDone(step, {
75
+ project_id: flags.createProject,
76
+ created_by_us: true,
77
+ display_name: displayName,
78
+ });
79
+ return {
80
+ step,
81
+ advanced: true,
82
+ title: "GCP project created",
83
+ detail: { project_id: flags.createProject },
84
+ };
85
+ }
86
+ if (!isGcloudInstalled()) {
87
+ return {
88
+ step,
89
+ advanced: false,
90
+ title: "Step 1 of 7: Choose a Google Cloud project",
91
+ instructions: [
92
+ "In your gws-axi setup page tab, click 'Create project in Console'",
93
+ "Copy the project ID once the project is created",
94
+ "Re-run: `gws-axi auth setup --project <your-project-id>`",
95
+ ],
96
+ };
97
+ }
98
+ const account = gcloudAccount();
99
+ if (!account.ok) {
100
+ return {
101
+ step,
102
+ advanced: false,
103
+ title: "gcloud not authenticated",
104
+ error: account.message,
105
+ code: account.code,
106
+ instructions: ["Run: `gcloud auth login`", "Then re-run: `gws-axi auth setup`"],
107
+ };
108
+ }
109
+ const projects = listProjects();
110
+ const projectList = projects.ok ? projects.value.slice(0, 10) : [];
111
+ return {
112
+ step,
113
+ advanced: false,
114
+ title: "Step 1 of 7: Choose or create a GCP project",
115
+ detail: {
116
+ gcloud_account: account.value,
117
+ existing_projects: projectList.map((p) => p.projectId),
118
+ },
119
+ instructions: [
120
+ `Use an existing project: \`gws-axi auth setup --project <id>\``,
121
+ `Or create a new one: \`gws-axi auth setup --create-project <id> --project-name "Name"\``,
122
+ `Project IDs must be globally unique, 6-30 chars, lowercase`,
123
+ ],
124
+ };
125
+ }
126
+ // STEP 2 — apis_enabled ────────────────────────────────────────────
127
+ export async function advanceApisEnabled(_flags, state) {
128
+ const step = "apis_enabled";
129
+ const projectId = state.steps.gcp_project.project_id;
130
+ if (typeof projectId !== "string") {
131
+ return {
132
+ step,
133
+ advanced: false,
134
+ title: "Cannot enable APIs — project not set",
135
+ error: "Step 1 must be completed before Step 2",
136
+ code: "PRECONDITION_FAILED",
137
+ instructions: ["Run `gws-axi auth setup --project <id>` first"],
138
+ };
139
+ }
140
+ if (!isGcloudInstalled()) {
141
+ return {
142
+ step,
143
+ advanced: false,
144
+ title: "Step 2 of 7: Enable required APIs",
145
+ instructions: [
146
+ "In your gws-axi setup page tab, click each 'Enable <service>' button to enable these APIs:",
147
+ ...SERVICES.map((s) => ` - ${s} (${REQUIRED_APIS[s]})`),
148
+ "Then re-run: `gws-axi auth setup`",
149
+ ],
150
+ };
151
+ }
152
+ const enabled = listEnabledApis(projectId);
153
+ const enabledSet = new Set(enabled.ok ? enabled.value : []);
154
+ const missing = allApis().filter((api) => !enabledSet.has(api));
155
+ if (missing.length > 0) {
156
+ const result = enableApis(projectId, missing);
157
+ if (!result.ok) {
158
+ return {
159
+ step,
160
+ advanced: false,
161
+ title: "Failed to enable APIs",
162
+ error: result.message,
163
+ code: result.code,
164
+ instructions: [
165
+ `Try enabling manually via: gcloud services enable ${missing.join(" ")} --project=${projectId}`,
166
+ "Or enable via Console and re-run `gws-axi auth setup`",
167
+ ],
168
+ };
169
+ }
170
+ }
171
+ markStepDone(step, { apis: allApis(), project_id: projectId });
172
+ return {
173
+ step,
174
+ advanced: true,
175
+ title: "APIs enabled",
176
+ detail: { apis: allApis(), project_id: projectId },
177
+ };
178
+ }
179
+ // STEP 3 — oauth_client (manual only) ──────────────────────────────
180
+ export async function advanceOauthClient(_flags, _state) {
181
+ const step = "oauth_client";
182
+ return {
183
+ step,
184
+ advanced: false,
185
+ title: "Step 3 of 7: Create a Desktop OAuth client (manual)",
186
+ instructions: [
187
+ "Google does not allow Desktop OAuth clients to be created via CLI/API — this step must be done in the Console",
188
+ "In your gws-axi setup page tab, click the 'OAuth clients → Create client' link",
189
+ "On the OAuth clients page, click '+ CREATE CLIENT'",
190
+ "If prompted to configure the consent screen first, complete Step 5 now and return",
191
+ 'Application type: "Desktop app", Name: "gws-axi" (or any name)',
192
+ "Click Create, then DOWNLOAD the credentials JSON",
193
+ "Re-run: `gws-axi auth setup --credentials-json <path-to-downloaded-json>`",
194
+ ],
195
+ };
196
+ }
197
+ // STEP 4 — credentials_saved ───────────────────────────────────────
198
+ export async function advanceCredentialsSaved(flags) {
199
+ const step = "credentials_saved";
200
+ if (!flags.credentialsJson) {
201
+ return {
202
+ step,
203
+ advanced: false,
204
+ title: "Step 4 of 7: Save OAuth credentials JSON",
205
+ instructions: [
206
+ "Re-run with: `gws-axi auth setup --credentials-json <path>`",
207
+ "Point to the JSON file you downloaded from the OAuth client creation page",
208
+ ],
209
+ };
210
+ }
211
+ if (!existsSync(flags.credentialsJson)) {
212
+ return {
213
+ step,
214
+ advanced: false,
215
+ title: "Credentials file not found",
216
+ error: `No file at: ${flags.credentialsJson}`,
217
+ code: "FILE_NOT_FOUND",
218
+ instructions: ["Check the path and re-run `gws-axi auth setup --credentials-json <path>`"],
219
+ };
220
+ }
221
+ let parsed;
222
+ try {
223
+ parsed = JSON.parse(readFileSync(flags.credentialsJson, "utf-8"));
224
+ }
225
+ catch {
226
+ return {
227
+ step,
228
+ advanced: false,
229
+ title: "Credentials file is not valid JSON",
230
+ error: "JSON parse failed",
231
+ code: "INVALID_JSON",
232
+ instructions: ["Re-download the credentials file from the Google Cloud Console"],
233
+ };
234
+ }
235
+ if (!parsed.installed?.client_id || !parsed.installed?.client_secret) {
236
+ return {
237
+ step,
238
+ advanced: false,
239
+ title: "Credentials file is not a Desktop OAuth client",
240
+ error: 'Expected an "installed" field with client_id and client_secret',
241
+ code: "WRONG_CLIENT_TYPE",
242
+ instructions: [
243
+ 'Make sure the OAuth client type was "Desktop app" (not Web/Service account)',
244
+ "Recreate the credentials in the Console if needed",
245
+ ],
246
+ };
247
+ }
248
+ const destPath = credentialsPath();
249
+ mkdirSync(dirname(destPath), { recursive: true });
250
+ copyFileSync(flags.credentialsJson, destPath);
251
+ markStepDone(step, {
252
+ path: destPath,
253
+ client_id: parsed.installed.client_id,
254
+ });
255
+ return {
256
+ step,
257
+ advanced: true,
258
+ title: "Credentials saved",
259
+ detail: { path: destPath },
260
+ };
261
+ }
262
+ // STEP 5 — consent_screen (manual only) ────────────────────────────
263
+ export async function advanceConsentScreen(_flags, _state) {
264
+ const step = "consent_screen";
265
+ return {
266
+ step,
267
+ advanced: false,
268
+ title: "Step 5 of 7: Configure the OAuth consent screen (manual)",
269
+ instructions: [
270
+ "Google split the OAuth consent screen into two pages — you'll need both",
271
+ "In your gws-axi setup page tab, click the 'Branding (app name, emails)' link",
272
+ " → App name: 'gws-axi' (or anything)",
273
+ " → User support email + Developer contact email: your email",
274
+ " → Leave logo / homepage / privacy policy blank (optional for Testing mode)",
275
+ " → Save",
276
+ "Then back on the setup page, click the 'Audience (user type)' link",
277
+ " → Verify 'Publishing status' shows 'Testing' — if it says 'In production', click 'Back to testing' (do NOT publish)",
278
+ " → Verify 'User type' shows 'External' — if it says 'Internal', click 'Make external' (required unless you have a Google Workspace domain and only want to use Workspace accounts)",
279
+ " → This page has no Save button — state changes take effect when you click those toggle buttons",
280
+ " → Staying in Testing mode means tokens expire every 7 days (expected, we'll handle this later)",
281
+ "When done, mark this step complete: `gws-axi auth setup --confirm-step consent_screen`",
282
+ ],
283
+ };
284
+ }
285
+ // STEP 6 — test_user_added (manual only) ───────────────────────────
286
+ export async function advanceTestUserAdded(flags, _state) {
287
+ const step = "test_user_added";
288
+ if (flags.testUserEmail) {
289
+ updateStepMetadata(step, { email: flags.testUserEmail });
290
+ }
291
+ return {
292
+ step,
293
+ advanced: false,
294
+ title: "Step 6 of 7: Add yourself as a test user (manual)",
295
+ instructions: [
296
+ "In your gws-axi setup page tab, click the 'Audience → Test users' link",
297
+ 'On that page, scroll to "Test users" and click "+ ADD USERS"',
298
+ "Enter each Google account you plan to authenticate (personal, work, etc.) and click Save",
299
+ "gws-axi supports multiple accounts with the same OAuth client — add them all now",
300
+ "Without this, the OAuth flow will reject those users with access_denied",
301
+ "When done, mark complete: `gws-axi auth setup --confirm-step test_user_added --test-user <primary-email>`",
302
+ "After setup completes, use `gws-axi auth login --account <email>` to authenticate each additional account",
303
+ ],
304
+ };
305
+ }
306
+ //# sourceMappingURL=steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.js","sourceRoot":"","sources":["../../../src/auth/steps.ts"],"names":[],"mappings":"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"}