hatchkit 0.1.47 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adopt.d.ts +61 -1
- package/dist/adopt.d.ts.map +1 -1
- package/dist/adopt.js +90 -86
- package/dist/adopt.js.map +1 -1
- package/dist/assets/env.d.ts +2 -2
- package/dist/assets/env.d.ts.map +1 -1
- package/dist/assets/index.js +11 -11
- package/dist/assets/index.js.map +1 -1
- package/dist/assets/mirror.js +1 -1
- package/dist/completion.d.ts.map +1 -1
- package/dist/completion.js +20 -2
- package/dist/completion.js.map +1 -1
- package/dist/config.d.ts +32 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +364 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy/coolify.d.ts +5 -0
- package/dist/deploy/coolify.d.ts.map +1 -1
- package/dist/deploy/coolify.js +67 -4
- package/dist/deploy/coolify.js.map +1 -1
- package/dist/deploy/ghcr.d.ts +1 -0
- package/dist/deploy/ghcr.d.ts.map +1 -1
- package/dist/deploy/ghcr.js +2 -2
- package/dist/deploy/ghcr.js.map +1 -1
- package/dist/deploy/github.d.ts.map +1 -1
- package/dist/deploy/github.js +3 -2
- package/dist/deploy/github.js.map +1 -1
- package/dist/deploy/rollback.d.ts.map +1 -1
- package/dist/deploy/rollback.js +9 -0
- package/dist/deploy/rollback.js.map +1 -1
- package/dist/dev-setup.d.ts +13 -5
- package/dist/dev-setup.d.ts.map +1 -1
- package/dist/dev-setup.js +268 -59
- package/dist/dev-setup.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +65 -1
- package/dist/doctor.js.map +1 -1
- package/dist/email/index.js +5 -5
- package/dist/email/index.js.map +1 -1
- package/dist/email/setup.d.ts +1 -1
- package/dist/email/setup.d.ts.map +1 -1
- package/dist/email/setup.js +3 -3
- package/dist/email/setup.js.map +1 -1
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +9 -8
- package/dist/explain.js.map +1 -1
- package/dist/index.js +523 -91
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +1 -0
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +2 -0
- package/dist/inventory.js.map +1 -1
- package/dist/onboarding/plan.d.ts +54 -0
- package/dist/onboarding/plan.d.ts.map +1 -0
- package/dist/onboarding/plan.js +143 -0
- package/dist/onboarding/plan.js.map +1 -0
- package/dist/onboarding/review.d.ts +27 -0
- package/dist/onboarding/review.d.ts.map +1 -0
- package/dist/onboarding/review.js +55 -0
- package/dist/onboarding/review.js.map +1 -0
- package/dist/prompts.d.ts +13 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +107 -89
- package/dist/prompts.js.map +1 -1
- package/dist/provision/glitchtip.d.ts +1 -0
- package/dist/provision/glitchtip.d.ts.map +1 -1
- package/dist/provision/glitchtip.js +16 -0
- package/dist/provision/glitchtip.js.map +1 -1
- package/dist/provision/index.d.ts +26 -3
- package/dist/provision/index.d.ts.map +1 -1
- package/dist/provision/index.js +215 -11
- package/dist/provision/index.js.map +1 -1
- package/dist/provision/openpanel.d.ts +1 -0
- package/dist/provision/openpanel.d.ts.map +1 -1
- package/dist/provision/openpanel.js +21 -0
- package/dist/provision/openpanel.js.map +1 -1
- package/dist/provision/plausible.d.ts +11 -0
- package/dist/provision/plausible.d.ts.map +1 -0
- package/dist/provision/plausible.js +108 -0
- package/dist/provision/plausible.js.map +1 -0
- package/dist/provision/resend.d.ts +4 -0
- package/dist/provision/resend.d.ts.map +1 -1
- package/dist/provision/resend.js +11 -6
- package/dist/provision/resend.js.map +1 -1
- package/dist/provision/search-console.d.ts +17 -0
- package/dist/provision/search-console.d.ts.map +1 -0
- package/dist/provision/search-console.js +142 -0
- package/dist/provision/search-console.js.map +1 -0
- package/dist/scaffold/app.d.ts +1 -0
- package/dist/scaffold/app.d.ts.map +1 -1
- package/dist/scaffold/app.js +6 -3
- package/dist/scaffold/app.js.map +1 -1
- package/dist/scaffold/infra.js +2 -0
- package/dist/scaffold/infra.js.map +1 -1
- package/dist/scaffold/manifest.d.ts +18 -2
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js +7 -1
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/server-add.d.ts +21 -0
- package/dist/scaffold/server-add.d.ts.map +1 -0
- package/dist/scaffold/server-add.js +275 -0
- package/dist/scaffold/server-add.js.map +1 -0
- package/dist/scaffold/starter-files.d.ts +3 -3
- package/dist/scaffold/starter-files.js +3 -3
- package/dist/scaffold/update.d.ts +1 -0
- package/dist/scaffold/update.d.ts.map +1 -1
- package/dist/scaffold/update.js +8 -5
- package/dist/scaffold/update.js.map +1 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +27 -1
- package/dist/status.js.map +1 -1
- package/dist/templates/base/env.example.hbs +3 -0
- package/dist/utils/cloudflare-api.d.ts +5 -0
- package/dist/utils/cloudflare-api.d.ts.map +1 -1
- package/dist/utils/cloudflare-api.js +19 -0
- package/dist/utils/cloudflare-api.js.map +1 -1
- package/dist/utils/coolify-api.d.ts +3 -2
- package/dist/utils/coolify-api.d.ts.map +1 -1
- package/dist/utils/coolify-api.js +19 -5
- package/dist/utils/coolify-api.js.map +1 -1
- package/dist/utils/flags.d.ts.map +1 -1
- package/dist/utils/flags.js +16 -0
- package/dist/utils/flags.js.map +1 -1
- package/dist/utils/run-ledger.d.ts +3 -0
- package/dist/utils/run-ledger.d.ts.map +1 -1
- package/dist/utils/run-ledger.js.map +1 -1
- package/dist/utils/secrets.d.ts +5 -0
- package/dist/utils/secrets.d.ts.map +1 -1
- package/dist/utils/secrets.js +5 -0
- package/dist/utils/secrets.js.map +1 -1
- package/package.json +24 -3
package/dist/completion.js
CHANGED
|
@@ -16,6 +16,7 @@ const TOP_LEVEL = [
|
|
|
16
16
|
"create",
|
|
17
17
|
"adopt",
|
|
18
18
|
"update",
|
|
19
|
+
"server",
|
|
19
20
|
"add",
|
|
20
21
|
"assets",
|
|
21
22
|
"keys",
|
|
@@ -36,11 +37,14 @@ const CONFIG_ADD = [
|
|
|
36
37
|
"replicate",
|
|
37
38
|
"glitchtip",
|
|
38
39
|
"openpanel",
|
|
40
|
+
"plausible",
|
|
39
41
|
"resend",
|
|
42
|
+
"search-console",
|
|
40
43
|
"stripe",
|
|
41
44
|
];
|
|
42
45
|
const CONFIG_SUB = ["add", "reset"];
|
|
43
46
|
const KEYS_SUB = ["show", "set", "rotate", "push"];
|
|
47
|
+
const SERVER_SUB = ["add"];
|
|
44
48
|
const SHELLS = ["zsh", "bash", "fish"];
|
|
45
49
|
export function renderCompletion(shell) {
|
|
46
50
|
if (shell === "zsh")
|
|
@@ -80,6 +84,9 @@ ${TOP_LEVEL.map((c) => ` '${c}:${topDesc(c)}'`).join("\n")}
|
|
|
80
84
|
keys)
|
|
81
85
|
_values 'keys subcommand' ${KEYS_SUB.map((s) => `'${s}'`).join(" ")}
|
|
82
86
|
;;
|
|
87
|
+
server)
|
|
88
|
+
_values 'server subcommand' ${SERVER_SUB.map((s) => `'${s}'`).join(" ")}
|
|
89
|
+
;;
|
|
83
90
|
assets)
|
|
84
91
|
_values 'assets subcommand' ${ASSETS_SUB.map((s) => `'${s}'`).join(" ")}
|
|
85
92
|
;;
|
|
@@ -117,6 +124,7 @@ _hatchkit_complete() {
|
|
|
117
124
|
local top="${TOP_LEVEL.join(" ")}"
|
|
118
125
|
local config_sub="${CONFIG_SUB.join(" ")}"
|
|
119
126
|
local keys_sub="${KEYS_SUB.join(" ")}"
|
|
127
|
+
local server_sub="${SERVER_SUB.join(" ")}"
|
|
120
128
|
local assets_sub="${ASSETS_SUB.join(" ")}"
|
|
121
129
|
local shells="${SHELLS.join(" ")}"
|
|
122
130
|
local providers="${CONFIG_ADD.join(" ")}"
|
|
@@ -139,6 +147,11 @@ _hatchkit_complete() {
|
|
|
139
147
|
COMPREPLY=( $(compgen -W "$keys_sub" -- "$cur") )
|
|
140
148
|
fi
|
|
141
149
|
;;
|
|
150
|
+
server)
|
|
151
|
+
if [[ $cword -eq 2 ]]; then
|
|
152
|
+
COMPREPLY=( $(compgen -W "$server_sub" -- "$cur") )
|
|
153
|
+
fi
|
|
154
|
+
;;
|
|
142
155
|
assets)
|
|
143
156
|
if [[ $cword -eq 2 ]]; then
|
|
144
157
|
COMPREPLY=( $(compgen -W "$assets_sub" -- "$cur") )
|
|
@@ -180,6 +193,9 @@ function fish() {
|
|
|
180
193
|
for (const s of KEYS_SUB) {
|
|
181
194
|
lines.push(`complete -c hatchkit -n "__fish_seen_subcommand_from keys" -a "${s}"`);
|
|
182
195
|
}
|
|
196
|
+
for (const s of SERVER_SUB) {
|
|
197
|
+
lines.push(`complete -c hatchkit -n "__fish_seen_subcommand_from server" -a "${s}"`);
|
|
198
|
+
}
|
|
183
199
|
for (const s of ASSETS_SUB) {
|
|
184
200
|
lines.push(`complete -c hatchkit -n "__fish_seen_subcommand_from assets" -a "${s}"`);
|
|
185
201
|
}
|
|
@@ -209,10 +225,12 @@ function topDesc(cmd) {
|
|
|
209
225
|
return "Adopt an existing project (run in project dir)";
|
|
210
226
|
case "update":
|
|
211
227
|
return "Add features to an already-scaffolded project";
|
|
228
|
+
case "server":
|
|
229
|
+
return "Retrofit a server into a client-only project";
|
|
212
230
|
case "add":
|
|
213
|
-
return "Provision GlitchTip / OpenPanel / Resend clients";
|
|
231
|
+
return "Provision GlitchTip / OpenPanel / Plausible / Resend clients";
|
|
214
232
|
case "assets":
|
|
215
|
-
return "Move bytes between local
|
|
233
|
+
return "Move bytes between local S3 and prod buckets";
|
|
216
234
|
case "keys":
|
|
217
235
|
return "Manage per-project dotenvx private keys";
|
|
218
236
|
case "config":
|
package/dist/completion.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,SAAS,GAAG;IAChB,OAAO;IACP,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,KAAK;IACL,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,YAAY;IACZ,MAAM;CACE,CAAC;AAEX,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAExE,MAAM,UAAU,GAAG;IACjB,SAAS;IACT,MAAM;IACN,SAAS;IACT,KAAK;IACL,IAAI;IACJ,OAAO;IACP,QAAQ;IACR,IAAI;IACJ,WAAW;IACX,WAAW;IACX,WAAW;IACX,QAAQ;IACR,QAAQ;CACA,CAAC;AAEX,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,OAAO,CAAU,CAAC;AAC7C,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAC5D,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAEhD,MAAM,UAAU,gBAAgB,CAAC,KAA8B;IAC7D,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,GAAG,EAAE,CAAC;IAClC,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,IAAI,EAAE,CAAC;IACpC,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,GAAG;IACV,OAAO;;;;;;;;;EASP,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;wCAgBrB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;sCAG3C,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;wCAGrC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;4BAGrD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;4BAGrC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;;;;;+BAOrC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;;;;;;CAQvE,CAAC;AACF,CAAC;AAED,SAAS,IAAI;IACX,OAAO;;;;;;;;;eASM,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;sBACZ,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;oBACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;sBAChB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;kBACxB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;qBACb,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -96,10 +96,26 @@ export interface OpenpanelMeta extends ProviderStatus {
|
|
|
96
96
|
* creating a new project/client via the dashboard. */
|
|
97
97
|
organizationSlug?: string;
|
|
98
98
|
}
|
|
99
|
+
export interface PlausibleMeta extends ProviderStatus {
|
|
100
|
+
/** Dashboard/API base URL. Cloud default is https://plausible.io. */
|
|
101
|
+
url: string;
|
|
102
|
+
/** Optional team id used when creating sites on multi-team accounts. */
|
|
103
|
+
teamId?: string;
|
|
104
|
+
/** IANA timezone sent for newly-created sites. */
|
|
105
|
+
timezone?: string;
|
|
106
|
+
}
|
|
99
107
|
export interface ResendMeta extends ProviderStatus {
|
|
100
108
|
/** Optional default region for new sending domains ("us-east-1", "eu-west-1"…). */
|
|
101
109
|
defaultRegion?: string;
|
|
102
110
|
}
|
|
111
|
+
export interface GoogleSearchConsoleMeta extends ProviderStatus {
|
|
112
|
+
/** Scopes granted to the stored refresh token. Non-sensitive; useful
|
|
113
|
+
* in status/doctor output when a user authorized only one API. */
|
|
114
|
+
scopes?: string[];
|
|
115
|
+
/** `hatchkit-pkce` uses Hatchkit's shipped public desktop OAuth client.
|
|
116
|
+
* `byo-client` is the legacy/user-owned Google Cloud OAuth client path. */
|
|
117
|
+
oauthMode?: "hatchkit-pkce" | "byo-client";
|
|
118
|
+
}
|
|
103
119
|
export interface StripeMeta extends ProviderStatus {
|
|
104
120
|
/** Account id (`acct_…`) derived from the live master key during
|
|
105
121
|
* verification. Surfaced in `hatchkit doctor` so a silent
|
|
@@ -149,9 +165,17 @@ export interface OpenpanelConfig extends OpenpanelMeta {
|
|
|
149
165
|
rootClientId: string;
|
|
150
166
|
rootClientSecret: string;
|
|
151
167
|
}
|
|
168
|
+
export interface PlausibleConfig extends PlausibleMeta {
|
|
169
|
+
apiKey: string;
|
|
170
|
+
}
|
|
152
171
|
export interface ResendConfig extends ResendMeta {
|
|
153
172
|
apiKey: string;
|
|
154
173
|
}
|
|
174
|
+
export interface GoogleSearchConsoleConfig extends GoogleSearchConsoleMeta {
|
|
175
|
+
clientId: string;
|
|
176
|
+
clientSecret?: string;
|
|
177
|
+
refreshToken: string;
|
|
178
|
+
}
|
|
155
179
|
export interface StripeConfig extends StripeMeta {
|
|
156
180
|
/** Master secret key for test/sandbox-mode operations. Used by
|
|
157
181
|
* hatchkit ONLY to mint webhook endpoints in test mode. Never
|
|
@@ -185,7 +209,9 @@ export interface CliConfig {
|
|
|
185
209
|
gpu: Record<string, GpuProviderMeta>;
|
|
186
210
|
glitchtip?: GlitchtipMeta;
|
|
187
211
|
openpanel?: OpenpanelMeta;
|
|
212
|
+
plausible?: PlausibleMeta;
|
|
188
213
|
resend?: ResendMeta;
|
|
214
|
+
googleSearchConsole?: GoogleSearchConsoleMeta;
|
|
189
215
|
stripe?: StripeMeta;
|
|
190
216
|
ghcr?: GhcrMeta;
|
|
191
217
|
};
|
|
@@ -261,14 +287,19 @@ export declare function ensureGlitchtip(): Promise<GlitchtipConfig>;
|
|
|
261
287
|
export declare function getGlitchtipConfig(): Promise<GlitchtipConfig | null>;
|
|
262
288
|
export declare function ensureOpenpanel(): Promise<OpenpanelConfig>;
|
|
263
289
|
export declare function getOpenpanelConfig(): Promise<OpenpanelConfig | null>;
|
|
290
|
+
export declare function ensurePlausible(): Promise<PlausibleConfig>;
|
|
291
|
+
export declare function getPlausibleConfig(): Promise<PlausibleConfig | null>;
|
|
264
292
|
export declare function ensureResend(): Promise<ResendConfig>;
|
|
265
293
|
export declare function getResendConfig(): Promise<ResendConfig | null>;
|
|
294
|
+
export declare function refreshGoogleSearchConsoleAccessToken(cfg: GoogleSearchConsoleConfig): Promise<string>;
|
|
295
|
+
export declare function ensureGoogleSearchConsole(): Promise<GoogleSearchConsoleConfig>;
|
|
296
|
+
export declare function getGoogleSearchConsoleConfig(): Promise<GoogleSearchConsoleConfig | null>;
|
|
266
297
|
export declare function ensureStripe(): Promise<StripeConfig>;
|
|
267
298
|
export declare function getStripeConfig(): Promise<StripeConfig | null>;
|
|
268
299
|
export declare function ensureGhcr(): Promise<GhcrConfig>;
|
|
269
300
|
export declare function getGhcrConfig(): Promise<GhcrConfig | null>;
|
|
270
301
|
export declare function isFirstRun(): Promise<boolean>;
|
|
271
|
-
type ReconfigurableProvider = "coolify" | "hetzner" | "dns" | "glitchtip" | "openpanel" | "resend" | "stripe" | "ghcr" | `s3.${"hetzner" | "aws" | "r2"}` | `gpu.${"modal" | "runpod" | "hf" | "replicate"}`;
|
|
302
|
+
type ReconfigurableProvider = "coolify" | "hetzner" | "dns" | "glitchtip" | "openpanel" | "plausible" | "resend" | "search-console" | "stripe" | "ghcr" | `s3.${"hetzner" | "aws" | "r2"}` | `gpu.${"modal" | "runpod" | "hf" | "replicate"}`;
|
|
272
303
|
/** Wipe + re-prompt for a single provider. Shared by the stepper and by
|
|
273
304
|
* `hatchkit config add <provider>` so both paths always re-prompt rather
|
|
274
305
|
* than silently no-op on already-configured providers. */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { createServer } from "node:http";
|
|
1
3
|
import { Separator, confirm, input, password, select } from "@inquirer/prompts";
|
|
2
4
|
import chalk from "chalk";
|
|
3
5
|
import Conf from "conf";
|
|
4
6
|
import ora from "ora";
|
|
5
7
|
import { verifyCoolify } from "./utils/coolify-api.js";
|
|
6
8
|
import { execOk } from "./utils/exec.js";
|
|
9
|
+
import { pickPort } from "./utils/ports.js";
|
|
7
10
|
import { SECRET_KEYS, clearAllSecrets, deleteSecret, getSecret, setSecret, } from "./utils/secrets.js";
|
|
8
11
|
import { validateRequired, validateUrl } from "./utils/validate.js";
|
|
9
12
|
/** Sanity-check an S3 access/secret pair against shape rules. Returns
|
|
@@ -925,6 +928,55 @@ export async function getOpenpanelConfig() {
|
|
|
925
928
|
return { ...meta, rootClientId, rootClientSecret };
|
|
926
929
|
}
|
|
927
930
|
// ---------------------------------------------------------------------------
|
|
931
|
+
// Provider: Plausible (privacy-friendly web analytics)
|
|
932
|
+
// ---------------------------------------------------------------------------
|
|
933
|
+
export async function ensurePlausible() {
|
|
934
|
+
const existing = store.get("providers.plausible");
|
|
935
|
+
const existingKey = await getSecret(SECRET_KEYS.plausibleApiKey);
|
|
936
|
+
if (existing?.status === "configured" && existingKey) {
|
|
937
|
+
return { ...existing, apiKey: existingKey };
|
|
938
|
+
}
|
|
939
|
+
console.log(chalk.yellow("\n Plausible is not configured yet. Let's set it up."));
|
|
940
|
+
const url = (await input({
|
|
941
|
+
message: "Plausible base URL:",
|
|
942
|
+
default: existing?.url ?? "https://plausible.io",
|
|
943
|
+
validate: (v) => validateUrl(v.trim()),
|
|
944
|
+
}))
|
|
945
|
+
.trim()
|
|
946
|
+
.replace(/\/$/, "");
|
|
947
|
+
tokenHint(`${url}/settings`, "Sites API key (can list/create/delete sites; Plausible Cloud requires a Sites API-enabled plan)");
|
|
948
|
+
const apiKey = await confirmPastedSecret("Plausible Sites API key");
|
|
949
|
+
const teamId = (await input({
|
|
950
|
+
message: "Plausible team id (optional):",
|
|
951
|
+
default: existing?.teamId ?? "",
|
|
952
|
+
})).trim();
|
|
953
|
+
const timezone = (await input({
|
|
954
|
+
message: "Default site timezone:",
|
|
955
|
+
default: existing?.timezone ?? "Etc/UTC",
|
|
956
|
+
validate: validateRequired,
|
|
957
|
+
})).trim();
|
|
958
|
+
const meta = {
|
|
959
|
+
status: "configured",
|
|
960
|
+
url,
|
|
961
|
+
teamId: teamId || undefined,
|
|
962
|
+
timezone,
|
|
963
|
+
lastVerified: new Date().toISOString(),
|
|
964
|
+
};
|
|
965
|
+
store.set("providers.plausible", meta);
|
|
966
|
+
await setSecret(SECRET_KEYS.plausibleApiKey, apiKey);
|
|
967
|
+
console.log(chalk.green(" ✓ Plausible configured"));
|
|
968
|
+
return { ...meta, apiKey };
|
|
969
|
+
}
|
|
970
|
+
export async function getPlausibleConfig() {
|
|
971
|
+
const meta = store.get("providers.plausible");
|
|
972
|
+
if (!meta || meta.status !== "configured")
|
|
973
|
+
return null;
|
|
974
|
+
const apiKey = await getSecret(SECRET_KEYS.plausibleApiKey);
|
|
975
|
+
if (!apiKey)
|
|
976
|
+
return null;
|
|
977
|
+
return { ...meta, apiKey };
|
|
978
|
+
}
|
|
979
|
+
// ---------------------------------------------------------------------------
|
|
928
980
|
// Provider: Resend (transactional email SaaS)
|
|
929
981
|
// ---------------------------------------------------------------------------
|
|
930
982
|
export async function ensureResend() {
|
|
@@ -968,6 +1020,279 @@ export async function getResendConfig() {
|
|
|
968
1020
|
return { ...meta, apiKey };
|
|
969
1021
|
}
|
|
970
1022
|
// ---------------------------------------------------------------------------
|
|
1023
|
+
// Provider: Google Search Console
|
|
1024
|
+
// ---------------------------------------------------------------------------
|
|
1025
|
+
const GOOGLE_SEARCH_CONSOLE_SCOPES = [
|
|
1026
|
+
"https://www.googleapis.com/auth/webmasters",
|
|
1027
|
+
"https://www.googleapis.com/auth/siteverification.verify_only",
|
|
1028
|
+
];
|
|
1029
|
+
// Public Desktop OAuth client id for Hatchkit's own Google Cloud project.
|
|
1030
|
+
// Desktop/installed clients are public clients, so this value is safe to ship.
|
|
1031
|
+
// Until the Hatchkit project is verified, dev builds can set
|
|
1032
|
+
// HATCHKIT_GOOGLE_SEARCH_CONSOLE_CLIENT_ID to exercise the packaged PKCE path.
|
|
1033
|
+
const PACKAGED_GOOGLE_SEARCH_CONSOLE_CLIENT_ID = "932614455438-s0ih891al5pkeo4aeafekf01t6pbqd21.apps.googleusercontent.com";
|
|
1034
|
+
function hatchkitGoogleSearchConsoleClientId() {
|
|
1035
|
+
const configured = process.env.HATCHKIT_GOOGLE_SEARCH_CONSOLE_CLIENT_ID?.trim() ||
|
|
1036
|
+
PACKAGED_GOOGLE_SEARCH_CONSOLE_CLIENT_ID.trim();
|
|
1037
|
+
return configured || null;
|
|
1038
|
+
}
|
|
1039
|
+
const GOOGLE_SEARCH_CONSOLE_SCOPE_REQUIREMENTS = [
|
|
1040
|
+
{
|
|
1041
|
+
label: "Search Console read/write",
|
|
1042
|
+
scopes: ["https://www.googleapis.com/auth/webmasters"],
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
label: "Site Verification verify-only",
|
|
1046
|
+
scopes: [
|
|
1047
|
+
"https://www.googleapis.com/auth/siteverification.verify_only",
|
|
1048
|
+
"https://www.googleapis.com/auth/siteverification",
|
|
1049
|
+
],
|
|
1050
|
+
},
|
|
1051
|
+
];
|
|
1052
|
+
function assertGoogleSearchConsoleScopes(scopes) {
|
|
1053
|
+
const granted = new Set(scopes);
|
|
1054
|
+
const missing = GOOGLE_SEARCH_CONSOLE_SCOPE_REQUIREMENTS.filter((req) => !req.scopes.some((scope) => granted.has(scope)));
|
|
1055
|
+
if (missing.length === 0)
|
|
1056
|
+
return;
|
|
1057
|
+
throw new Error("Google OAuth did not grant every scope Hatchkit needs. " +
|
|
1058
|
+
`Missing: ${missing.map((m) => m.label).join(", ")}. ` +
|
|
1059
|
+
"Re-run setup and approve both Search Console and Site Verification access.");
|
|
1060
|
+
}
|
|
1061
|
+
function base64Url(input) {
|
|
1062
|
+
return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
1063
|
+
}
|
|
1064
|
+
function createPkcePair() {
|
|
1065
|
+
const verifier = base64Url(randomBytes(64));
|
|
1066
|
+
const challenge = base64Url(createHash("sha256").update(verifier).digest());
|
|
1067
|
+
return { verifier, challenge };
|
|
1068
|
+
}
|
|
1069
|
+
async function exchangeGoogleCode(args) {
|
|
1070
|
+
const body = new URLSearchParams({
|
|
1071
|
+
client_id: args.clientId,
|
|
1072
|
+
code: args.code,
|
|
1073
|
+
grant_type: "authorization_code",
|
|
1074
|
+
redirect_uri: args.redirectUri,
|
|
1075
|
+
});
|
|
1076
|
+
if (args.clientSecret)
|
|
1077
|
+
body.set("client_secret", args.clientSecret);
|
|
1078
|
+
if (args.codeVerifier)
|
|
1079
|
+
body.set("code_verifier", args.codeVerifier);
|
|
1080
|
+
const res = await fetch("https://oauth2.googleapis.com/token", {
|
|
1081
|
+
method: "POST",
|
|
1082
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1083
|
+
body,
|
|
1084
|
+
});
|
|
1085
|
+
const json = (await res.json().catch(() => null));
|
|
1086
|
+
if (!res.ok || !json?.access_token) {
|
|
1087
|
+
const msg = json?.error_description ?? json?.error ?? `HTTP ${res.status}`;
|
|
1088
|
+
throw new Error(`Google OAuth token exchange failed: ${msg}`);
|
|
1089
|
+
}
|
|
1090
|
+
return {
|
|
1091
|
+
access_token: json.access_token,
|
|
1092
|
+
refresh_token: json.refresh_token,
|
|
1093
|
+
scope: json.scope,
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
async function runGoogleOAuthLoopback(args) {
|
|
1097
|
+
const port = await pickPort(49152, 65535, new Set());
|
|
1098
|
+
const state = randomBytes(18).toString("hex");
|
|
1099
|
+
const pkce = args.clientSecret ? null : createPkcePair();
|
|
1100
|
+
const redirectUri = `http://127.0.0.1:${port}/oauth/google/callback`;
|
|
1101
|
+
let settled = false;
|
|
1102
|
+
let resolveCode = () => { };
|
|
1103
|
+
let rejectCode = () => { };
|
|
1104
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
1105
|
+
resolveCode = resolve;
|
|
1106
|
+
rejectCode = reject;
|
|
1107
|
+
});
|
|
1108
|
+
const server = createServer((req, res) => {
|
|
1109
|
+
const url = new URL(req.url ?? "/", redirectUri);
|
|
1110
|
+
if (url.pathname !== "/oauth/google/callback") {
|
|
1111
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1112
|
+
res.end("Not found");
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
const gotState = url.searchParams.get("state");
|
|
1116
|
+
const code = url.searchParams.get("code");
|
|
1117
|
+
const error = url.searchParams.get("error");
|
|
1118
|
+
if (gotState !== state) {
|
|
1119
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1120
|
+
res.end("State mismatch. Return to the terminal and retry setup.");
|
|
1121
|
+
if (!settled) {
|
|
1122
|
+
settled = true;
|
|
1123
|
+
rejectCode(new Error("Google OAuth state mismatch."));
|
|
1124
|
+
}
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (error || !code) {
|
|
1128
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
1129
|
+
res.end("Google authorization failed. Return to the terminal and retry setup.");
|
|
1130
|
+
if (!settled) {
|
|
1131
|
+
settled = true;
|
|
1132
|
+
rejectCode(new Error(`Google OAuth failed: ${error ?? "missing code"}`));
|
|
1133
|
+
}
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
1137
|
+
res.end("Google Search Console authorization complete. You can close this tab.");
|
|
1138
|
+
if (!settled) {
|
|
1139
|
+
settled = true;
|
|
1140
|
+
resolveCode(code);
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
await new Promise((resolve, reject) => {
|
|
1144
|
+
server.once("error", reject);
|
|
1145
|
+
server.listen(port, "127.0.0.1", () => resolve());
|
|
1146
|
+
});
|
|
1147
|
+
const authUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
|
|
1148
|
+
authUrl.searchParams.set("client_id", args.clientId);
|
|
1149
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
1150
|
+
authUrl.searchParams.set("response_type", "code");
|
|
1151
|
+
authUrl.searchParams.set("scope", GOOGLE_SEARCH_CONSOLE_SCOPES.join(" "));
|
|
1152
|
+
authUrl.searchParams.set("access_type", "offline");
|
|
1153
|
+
authUrl.searchParams.set("prompt", "consent");
|
|
1154
|
+
authUrl.searchParams.set("state", state);
|
|
1155
|
+
if (pkce) {
|
|
1156
|
+
authUrl.searchParams.set("code_challenge", pkce.challenge);
|
|
1157
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
1158
|
+
}
|
|
1159
|
+
console.log(chalk.dim("\n Open this URL in your browser, approve access, then return here:"));
|
|
1160
|
+
console.log(chalk.cyan(` ${authUrl.toString()}\n`));
|
|
1161
|
+
try {
|
|
1162
|
+
const code = await codePromise;
|
|
1163
|
+
const token = await exchangeGoogleCode({
|
|
1164
|
+
clientId: args.clientId,
|
|
1165
|
+
clientSecret: args.clientSecret,
|
|
1166
|
+
code,
|
|
1167
|
+
redirectUri,
|
|
1168
|
+
codeVerifier: pkce?.verifier,
|
|
1169
|
+
});
|
|
1170
|
+
if (!token.refresh_token) {
|
|
1171
|
+
throw new Error("Google did not return a refresh token. Re-run setup and keep `prompt=consent`, or revoke the app at https://myaccount.google.com/permissions and try again.");
|
|
1172
|
+
}
|
|
1173
|
+
const scopes = token.scope?.split(/\s+/).filter(Boolean) ?? GOOGLE_SEARCH_CONSOLE_SCOPES;
|
|
1174
|
+
assertGoogleSearchConsoleScopes(scopes);
|
|
1175
|
+
return {
|
|
1176
|
+
refreshToken: token.refresh_token,
|
|
1177
|
+
scopes,
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
finally {
|
|
1181
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
export async function refreshGoogleSearchConsoleAccessToken(cfg) {
|
|
1185
|
+
const body = new URLSearchParams({
|
|
1186
|
+
client_id: cfg.clientId,
|
|
1187
|
+
refresh_token: cfg.refreshToken,
|
|
1188
|
+
grant_type: "refresh_token",
|
|
1189
|
+
});
|
|
1190
|
+
if (cfg.clientSecret)
|
|
1191
|
+
body.set("client_secret", cfg.clientSecret);
|
|
1192
|
+
const res = await fetch("https://oauth2.googleapis.com/token", {
|
|
1193
|
+
method: "POST",
|
|
1194
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1195
|
+
body,
|
|
1196
|
+
});
|
|
1197
|
+
const json = (await res.json().catch(() => null));
|
|
1198
|
+
if (!res.ok || !json?.access_token) {
|
|
1199
|
+
const msg = json?.error_description ?? json?.error ?? `HTTP ${res.status}`;
|
|
1200
|
+
throw new Error(`Google refresh token failed: ${msg}`);
|
|
1201
|
+
}
|
|
1202
|
+
return json.access_token;
|
|
1203
|
+
}
|
|
1204
|
+
export async function ensureGoogleSearchConsole() {
|
|
1205
|
+
const existing = store.get("providers.googleSearchConsole");
|
|
1206
|
+
const existingClientId = await getSecret(SECRET_KEYS.googleSearchConsoleClientId);
|
|
1207
|
+
const existingClientSecret = await getSecret(SECRET_KEYS.googleSearchConsoleClientSecret);
|
|
1208
|
+
const existingRefreshToken = await getSecret(SECRET_KEYS.googleSearchConsoleRefreshToken);
|
|
1209
|
+
const hatchkitClientId = hatchkitGoogleSearchConsoleClientId();
|
|
1210
|
+
const existingMode = existing?.oauthMode ?? (existingClientSecret ? "byo-client" : "hatchkit-pkce");
|
|
1211
|
+
if (existing?.status === "configured" && existingRefreshToken) {
|
|
1212
|
+
if (existingMode === "hatchkit-pkce" && hatchkitClientId) {
|
|
1213
|
+
return {
|
|
1214
|
+
...existing,
|
|
1215
|
+
oauthMode: "hatchkit-pkce",
|
|
1216
|
+
clientId: hatchkitClientId,
|
|
1217
|
+
refreshToken: existingRefreshToken,
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
if (existingClientId && existingClientSecret) {
|
|
1221
|
+
return {
|
|
1222
|
+
...existing,
|
|
1223
|
+
oauthMode: "byo-client",
|
|
1224
|
+
clientId: existingClientId,
|
|
1225
|
+
clientSecret: existingClientSecret,
|
|
1226
|
+
refreshToken: existingRefreshToken,
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
console.log(chalk.yellow("\n Google Search Console is not configured yet. Let's set it up."));
|
|
1231
|
+
console.log(chalk.dim(" Hatchkit uses Google OAuth for Search Console and Site Verification.\n" +
|
|
1232
|
+
" You sign in with your own Google account; Hatchkit stores only that\n" +
|
|
1233
|
+
" account's refresh token in your OS keychain on this machine.\n"));
|
|
1234
|
+
let clientId;
|
|
1235
|
+
let clientSecret;
|
|
1236
|
+
let oauthMode;
|
|
1237
|
+
if (hatchkitClientId) {
|
|
1238
|
+
clientId = hatchkitClientId;
|
|
1239
|
+
oauthMode = "hatchkit-pkce";
|
|
1240
|
+
console.log(chalk.dim(" Using Hatchkit's shipped Google OAuth client with PKCE. No Google Cloud setup or client secret is needed."));
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
oauthMode = "byo-client";
|
|
1244
|
+
console.log(chalk.dim(" No packaged Hatchkit Google OAuth client id is configured in this build.\n" +
|
|
1245
|
+
" Falling back to the legacy BYO Google Cloud OAuth client setup.\n"));
|
|
1246
|
+
tokenHint("https://console.cloud.google.com/apis/credentials", "OAuth client (Desktop app) with Search Console API + Site Verification API enabled", `Scopes: ${GOOGLE_SEARCH_CONSOLE_SCOPES.join(", ")}`);
|
|
1247
|
+
clientId = (await input({
|
|
1248
|
+
message: "Google OAuth client ID:",
|
|
1249
|
+
default: existingClientId ?? undefined,
|
|
1250
|
+
validate: validateRequired,
|
|
1251
|
+
})).trim();
|
|
1252
|
+
clientSecret = await confirmPastedSecret("Google OAuth client secret");
|
|
1253
|
+
}
|
|
1254
|
+
const oauth = await runGoogleOAuthLoopback({ clientId, clientSecret });
|
|
1255
|
+
const meta = {
|
|
1256
|
+
status: "configured",
|
|
1257
|
+
scopes: oauth.scopes,
|
|
1258
|
+
oauthMode,
|
|
1259
|
+
lastVerified: new Date().toISOString(),
|
|
1260
|
+
};
|
|
1261
|
+
store.set("providers.googleSearchConsole", meta);
|
|
1262
|
+
if (oauthMode === "byo-client") {
|
|
1263
|
+
await setSecret(SECRET_KEYS.googleSearchConsoleClientId, clientId);
|
|
1264
|
+
if (clientSecret)
|
|
1265
|
+
await setSecret(SECRET_KEYS.googleSearchConsoleClientSecret, clientSecret);
|
|
1266
|
+
}
|
|
1267
|
+
else {
|
|
1268
|
+
await deleteSecret(SECRET_KEYS.googleSearchConsoleClientId);
|
|
1269
|
+
await deleteSecret(SECRET_KEYS.googleSearchConsoleClientSecret);
|
|
1270
|
+
}
|
|
1271
|
+
await setSecret(SECRET_KEYS.googleSearchConsoleRefreshToken, oauth.refreshToken);
|
|
1272
|
+
console.log(chalk.green(" ✓ Google Search Console configured"));
|
|
1273
|
+
return { ...meta, clientId, clientSecret, refreshToken: oauth.refreshToken };
|
|
1274
|
+
}
|
|
1275
|
+
export async function getGoogleSearchConsoleConfig() {
|
|
1276
|
+
const meta = store.get("providers.googleSearchConsole");
|
|
1277
|
+
if (!meta || meta.status !== "configured")
|
|
1278
|
+
return null;
|
|
1279
|
+
const oauthMode = meta.oauthMode ?? "byo-client";
|
|
1280
|
+
const clientId = await getSecret(SECRET_KEYS.googleSearchConsoleClientId);
|
|
1281
|
+
const clientSecret = await getSecret(SECRET_KEYS.googleSearchConsoleClientSecret);
|
|
1282
|
+
const refreshToken = await getSecret(SECRET_KEYS.googleSearchConsoleRefreshToken);
|
|
1283
|
+
if (!refreshToken)
|
|
1284
|
+
return null;
|
|
1285
|
+
if (oauthMode === "hatchkit-pkce") {
|
|
1286
|
+
const hatchkitClientId = hatchkitGoogleSearchConsoleClientId();
|
|
1287
|
+
if (!hatchkitClientId)
|
|
1288
|
+
return null;
|
|
1289
|
+
return { ...meta, oauthMode, clientId: hatchkitClientId, refreshToken };
|
|
1290
|
+
}
|
|
1291
|
+
if (!clientId || !clientSecret)
|
|
1292
|
+
return null;
|
|
1293
|
+
return { ...meta, oauthMode: "byo-client", clientId, clientSecret, refreshToken };
|
|
1294
|
+
}
|
|
1295
|
+
// ---------------------------------------------------------------------------
|
|
971
1296
|
// Provider: Stripe (payments)
|
|
972
1297
|
// ---------------------------------------------------------------------------
|
|
973
1298
|
//
|
|
@@ -1250,10 +1575,22 @@ export async function reconfigureProvider(name) {
|
|
|
1250
1575
|
]);
|
|
1251
1576
|
await ensureOpenpanel();
|
|
1252
1577
|
}
|
|
1578
|
+
else if (name === "plausible") {
|
|
1579
|
+
await wipeProvider("providers.plausible", [SECRET_KEYS.plausibleApiKey]);
|
|
1580
|
+
await ensurePlausible();
|
|
1581
|
+
}
|
|
1253
1582
|
else if (name === "resend") {
|
|
1254
1583
|
await wipeProvider("providers.resend", [SECRET_KEYS.resendApiKey]);
|
|
1255
1584
|
await ensureResend();
|
|
1256
1585
|
}
|
|
1586
|
+
else if (name === "search-console") {
|
|
1587
|
+
await wipeProvider("providers.googleSearchConsole", [
|
|
1588
|
+
SECRET_KEYS.googleSearchConsoleClientId,
|
|
1589
|
+
SECRET_KEYS.googleSearchConsoleClientSecret,
|
|
1590
|
+
SECRET_KEYS.googleSearchConsoleRefreshToken,
|
|
1591
|
+
]);
|
|
1592
|
+
await ensureGoogleSearchConsole();
|
|
1593
|
+
}
|
|
1257
1594
|
else if (name === "stripe") {
|
|
1258
1595
|
// NB: per-project Stripe entries (`stripe:project:<name>:*`) are
|
|
1259
1596
|
// intentionally NOT swept here — those belong to individual scaffolded
|
|
@@ -1397,6 +1734,15 @@ function buildSetupGroups() {
|
|
|
1397
1734
|
},
|
|
1398
1735
|
run: () => reconfigureProvider("openpanel"),
|
|
1399
1736
|
},
|
|
1737
|
+
{
|
|
1738
|
+
key: "plausible",
|
|
1739
|
+
label: "Plausible (web analytics)",
|
|
1740
|
+
status: () => {
|
|
1741
|
+
const m = store.get("providers.plausible");
|
|
1742
|
+
return { configured: m?.status === "configured", summary: m?.url };
|
|
1743
|
+
},
|
|
1744
|
+
run: () => reconfigureProvider("plausible"),
|
|
1745
|
+
},
|
|
1400
1746
|
{
|
|
1401
1747
|
key: "resend",
|
|
1402
1748
|
label: "Resend (transactional email)",
|
|
@@ -1406,6 +1752,23 @@ function buildSetupGroups() {
|
|
|
1406
1752
|
},
|
|
1407
1753
|
run: () => reconfigureProvider("resend"),
|
|
1408
1754
|
},
|
|
1755
|
+
{
|
|
1756
|
+
key: "search-console",
|
|
1757
|
+
label: "Google Search Console",
|
|
1758
|
+
status: () => {
|
|
1759
|
+
const m = store.get("providers.googleSearchConsole");
|
|
1760
|
+
return {
|
|
1761
|
+
configured: m?.status === "configured",
|
|
1762
|
+
summary: [
|
|
1763
|
+
m?.oauthMode === "hatchkit-pkce" ? "Hatchkit OAuth" : m ? "BYO OAuth" : null,
|
|
1764
|
+
m?.scopes?.length ? `${m.scopes.length} scopes` : null,
|
|
1765
|
+
]
|
|
1766
|
+
.filter(Boolean)
|
|
1767
|
+
.join(", "),
|
|
1768
|
+
};
|
|
1769
|
+
},
|
|
1770
|
+
run: () => reconfigureProvider("search-console"),
|
|
1771
|
+
},
|
|
1409
1772
|
{
|
|
1410
1773
|
key: "defaultForwardingEmail",
|
|
1411
1774
|
label: "Default forwarding email",
|
|
@@ -1513,7 +1876,7 @@ export async function runOnboarding() {
|
|
|
1513
1876
|
console.log();
|
|
1514
1877
|
}
|
|
1515
1878
|
// Summary — show both what's configured and what's still missing so
|
|
1516
|
-
// the user notices optional-but-important steps (GlitchTip / OpenPanel
|
|
1879
|
+
// the user notices optional-but-important steps (GlitchTip / OpenPanel / Plausible
|
|
1517
1880
|
// / Resend) they may have skipped.
|
|
1518
1881
|
const configured = allSteps.filter((s) => s.status().configured);
|
|
1519
1882
|
const unconfigured = allSteps.filter((s) => !s.status().configured);
|