@ashlr/stack-core 0.1.1 → 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/LICENSE +1 -1
- package/README.md +26 -15
- package/package.json +1 -1
- package/src/__tests__/_harness.ts +67 -7
- package/src/__tests__/agent-onboard.test.ts +217 -0
- package/src/__tests__/api-key-providers.test.ts +6 -2
- package/src/__tests__/base-urls.test.ts +162 -0
- package/src/__tests__/catalog-index.test.ts +14 -20
- package/src/__tests__/cloudflare-provider.test.ts +9 -10
- package/src/__tests__/completion-ci.test.ts +239 -23
- package/src/__tests__/config-own-services.test.ts +183 -0
- package/src/__tests__/config-split.test.ts +206 -2
- package/src/__tests__/config.test.ts +2 -1
- package/src/__tests__/credential-staging.test.ts +659 -0
- package/src/__tests__/deps.test.ts +2 -1
- package/src/__tests__/detect-source.test.ts +1 -1
- package/src/__tests__/github-provider.test.ts +3 -2
- package/src/__tests__/helpers.test.ts +24 -4
- package/src/__tests__/http.test.ts +2 -2
- package/src/__tests__/inference.test.ts +19 -13
- package/src/__tests__/interactive-prompt.test.ts +106 -0
- package/src/__tests__/mcp-mirror.test.ts +116 -0
- package/src/__tests__/neon-provider.test.ts +136 -3
- package/src/__tests__/new-providers.test.ts +470 -0
- package/src/__tests__/oauth-port.test.ts +84 -0
- package/src/__tests__/openai-provider.test.ts +1 -1
- package/src/__tests__/phantom-contract.test.ts +177 -0
- package/src/__tests__/phantom-harness.test.ts +125 -8
- package/src/__tests__/phantom-project-preflight.test.ts +118 -0
- package/src/__tests__/phantom-wire.test.ts +31 -20
- package/src/__tests__/pipeline-integration.test.ts +1 -1
- package/src/__tests__/pipeline-recovery.test.ts +29 -28
- package/src/__tests__/pipeline-rollback.test.ts +509 -0
- package/src/__tests__/pipeline.test.ts +3 -1
- package/src/__tests__/pm-detect.test.ts +113 -0
- package/src/__tests__/provider-deprovision.test.ts +269 -0
- package/src/__tests__/provider-parity.test.ts +46 -0
- package/src/__tests__/publish-script.test.ts +659 -0
- package/src/__tests__/recipe.test.ts +4 -2
- package/src/__tests__/recommend-apply-e2e.test.ts +14 -27
- package/src/__tests__/registry.test.ts +11 -2
- package/src/__tests__/release-artifacts.test.ts +55 -0
- package/src/__tests__/secret-redaction.test.ts +10 -10
- package/src/__tests__/security.test.ts +9 -10
- package/src/__tests__/supabase-provider.test.ts +6 -4
- package/src/__tests__/swap.test.ts +114 -0
- package/src/__tests__/telemetry.test.ts +354 -0
- package/src/__tests__/template-litellm-gateway.test.ts +41 -0
- package/src/__tests__/template-temporal-worker-phantom.test.ts +31 -0
- package/src/__tests__/templates.test.ts +1 -1
- package/src/__tests__/turso-provider.test.ts +2 -5
- package/src/agent-onboard.ts +346 -0
- package/src/ai/catalog-index.ts +68 -10
- package/src/ai/circuit-breaker.ts +3 -6
- package/src/ai/cost-tracker.ts +6 -15
- package/src/ai/inference.ts +19 -11
- package/src/ai/phantom-wire.ts +29 -52
- package/src/ai/recipe.ts +69 -0
- package/src/base-urls.ts +71 -0
- package/src/catalog.ts +281 -2
- package/src/config.ts +31 -18
- package/src/detect-source.ts +36 -8
- package/src/detect.ts +13 -5
- package/src/http.ts +6 -5
- package/src/index.ts +15 -0
- package/src/mcp-writer.ts +97 -2
- package/src/oauth.ts +85 -53
- package/src/phantom.ts +193 -15
- package/src/pipeline.ts +177 -68
- package/src/pm-detect.ts +56 -0
- package/src/providers/_api-key.ts +18 -17
- package/src/providers/_base.ts +28 -1
- package/src/providers/_credential-stage.ts +237 -0
- package/src/providers/_helpers.ts +55 -9
- package/src/providers/anthropic.ts +2 -1
- package/src/providers/auth0.ts +27 -0
- package/src/providers/aws.ts +32 -33
- package/src/providers/cloudflare.ts +18 -37
- package/src/providers/convex.ts +1 -2
- package/src/providers/datadog.ts +29 -0
- package/src/providers/digitalocean.ts +30 -0
- package/src/providers/gcp.ts +36 -0
- package/src/providers/github.ts +37 -35
- package/src/providers/grafana.ts +29 -0
- package/src/providers/hetzner.ts +29 -0
- package/src/providers/index.ts +13 -1
- package/src/providers/launchdarkly.ts +33 -0
- package/src/providers/mixpanel.ts +37 -0
- package/src/providers/neon.ts +50 -26
- package/src/providers/openai.ts +2 -1
- package/src/providers/plausible.ts +26 -0
- package/src/providers/sentry.ts +17 -17
- package/src/providers/stripe.ts +1 -2
- package/src/providers/supabase.ts +66 -37
- package/src/providers/turso.ts +49 -38
- package/src/providers/vercel.ts +50 -20
- package/src/providers/workos.ts +27 -0
- package/src/registry.ts +7 -11
- package/src/swap.ts +108 -0
- package/src/telemetry.ts +267 -0
- package/src/templates.ts +6 -2
package/src/catalog.ts
CHANGED
|
@@ -23,13 +23,14 @@ export interface ProviderRef {
|
|
|
23
23
|
| "Cloud"
|
|
24
24
|
| "AI"
|
|
25
25
|
| "Analytics"
|
|
26
|
+
| "Observability"
|
|
26
27
|
| "Errors"
|
|
27
28
|
| "Payments"
|
|
28
29
|
| "Code"
|
|
29
30
|
| "Tickets"
|
|
30
31
|
| "Email"
|
|
31
32
|
| "Auth"
|
|
32
|
-
| "
|
|
33
|
+
| "FeatureFlags";
|
|
33
34
|
authKind: CatalogAuthKind;
|
|
34
35
|
/** Canonical .env names this provider writes into Phantom. */
|
|
35
36
|
secrets: string[];
|
|
@@ -42,6 +43,13 @@ export interface ProviderRef {
|
|
|
42
43
|
preview?: boolean;
|
|
43
44
|
detail: string;
|
|
44
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* When true, the adapter only validates and stores the key — no upstream
|
|
48
|
+
* resource is created or configured. Absence of this flag means the adapter
|
|
49
|
+
* performs real provisioning (project/database/repo creation, token minting,
|
|
50
|
+
* etc.). v0.2 will bring provisioning to key-only providers over time.
|
|
51
|
+
*/
|
|
52
|
+
keyOnly?: boolean;
|
|
45
53
|
/** Dashboard URL `stack open <name>` lands on. */
|
|
46
54
|
dashboard: string;
|
|
47
55
|
/** Upstream reference docs URL for when something goes wrong. */
|
|
@@ -50,6 +58,14 @@ export interface ProviderRef {
|
|
|
50
58
|
howTo: string;
|
|
51
59
|
/** Free-form note about v1 limitations or caveats. */
|
|
52
60
|
notes?: string;
|
|
61
|
+
/**
|
|
62
|
+
* npm packages to install in the consuming project after `stack add <name>`
|
|
63
|
+
* succeeds — the SDK(s) you'd `import` from to actually use this provider.
|
|
64
|
+
* `stack add` prompts the user to install these with their detected package
|
|
65
|
+
* manager (bun / pnpm / npm / yarn). Leave empty for providers with no first-
|
|
66
|
+
* party SDK (e.g. shell-script-only providers or REST-only adapters).
|
|
67
|
+
*/
|
|
68
|
+
sdkPackages?: string[];
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
/** Back-compat re-export for call sites that still use `AuthKind`. */
|
|
@@ -74,6 +90,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
74
90
|
howTo: "Browser OAuth (PKCE) via the Ashlr Stack app.",
|
|
75
91
|
notes:
|
|
76
92
|
"v1 provisions a project and fetches service keys. Database password is auto-generated and stored in Phantom.",
|
|
93
|
+
sdkPackages: ["@supabase/supabase-js"],
|
|
77
94
|
},
|
|
78
95
|
{
|
|
79
96
|
name: "neon",
|
|
@@ -82,9 +99,16 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
82
99
|
authKind: "pat",
|
|
83
100
|
secrets: ["NEON_API_KEY", "DATABASE_URL"],
|
|
84
101
|
blurb: "Serverless Postgres. Creates a project and pools the connection string.",
|
|
102
|
+
mcp: {
|
|
103
|
+
name: "neon",
|
|
104
|
+
preview: true,
|
|
105
|
+
detail:
|
|
106
|
+
"@neondatabase/mcp-server-neon with NEON_API_KEY piped from Phantom — branch, migrate, and query from the agent.",
|
|
107
|
+
},
|
|
85
108
|
dashboard: "https://console.neon.tech",
|
|
86
109
|
docs: "https://neon.tech/docs/reference/api-reference",
|
|
87
110
|
howTo: "Paste a personal API key from https://console.neon.tech/app/settings/api-keys.",
|
|
111
|
+
sdkPackages: ["@neondatabase/serverless"],
|
|
88
112
|
},
|
|
89
113
|
{
|
|
90
114
|
name: "turso",
|
|
@@ -96,6 +120,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
96
120
|
dashboard: "https://app.turso.tech",
|
|
97
121
|
docs: "https://docs.turso.tech",
|
|
98
122
|
howTo: "Paste a platform token from https://app.turso.tech/account/api-tokens.",
|
|
123
|
+
sdkPackages: ["@libsql/client"],
|
|
99
124
|
},
|
|
100
125
|
{
|
|
101
126
|
name: "convex",
|
|
@@ -104,9 +129,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
104
129
|
authKind: "api_key",
|
|
105
130
|
secrets: ["CONVEX_DEPLOY_KEY"],
|
|
106
131
|
blurb: "Reactive backend-as-a-service. Deploy key stored in Phantom.",
|
|
132
|
+
keyOnly: true,
|
|
107
133
|
dashboard: "https://dashboard.convex.dev",
|
|
108
134
|
docs: "https://docs.convex.dev",
|
|
109
135
|
howTo: "Create a deploy key in the Convex dashboard and paste it.",
|
|
136
|
+
sdkPackages: ["convex"],
|
|
110
137
|
},
|
|
111
138
|
{
|
|
112
139
|
name: "upstash",
|
|
@@ -115,9 +142,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
115
142
|
authKind: "api_key",
|
|
116
143
|
secrets: ["UPSTASH_MANAGEMENT_TOKEN"],
|
|
117
144
|
blurb: "Serverless Redis + Kafka. Management token stored in Phantom.",
|
|
145
|
+
keyOnly: true,
|
|
118
146
|
dashboard: "https://console.upstash.com",
|
|
119
147
|
docs: "https://upstash.com/docs/devops/developer-api",
|
|
120
148
|
howTo: "Generate a management token from the Upstash console.",
|
|
149
|
+
sdkPackages: ["@upstash/redis"],
|
|
121
150
|
},
|
|
122
151
|
{
|
|
123
152
|
name: "firebase",
|
|
@@ -126,13 +155,28 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
126
155
|
authKind: "api_key",
|
|
127
156
|
secrets: ["FIREBASE_SERVICE_ACCOUNT_JSON"],
|
|
128
157
|
blurb: "Realtime DB + Auth. Service-account JSON stored verbatim in Phantom.",
|
|
158
|
+
keyOnly: true,
|
|
129
159
|
dashboard: "https://console.firebase.google.com",
|
|
130
160
|
docs: "https://firebase.google.com/docs/admin/setup",
|
|
131
161
|
howTo:
|
|
132
162
|
"Paste the full service-account JSON from Firebase → Project settings → Service accounts.",
|
|
163
|
+
sdkPackages: ["firebase"],
|
|
133
164
|
},
|
|
134
165
|
|
|
135
166
|
// ── Deploy ────────────────────────────────────────────────────────────────
|
|
167
|
+
{
|
|
168
|
+
name: "modal",
|
|
169
|
+
displayName: "Modal",
|
|
170
|
+
category: "Deploy",
|
|
171
|
+
authKind: "api_key",
|
|
172
|
+
secrets: ["MODAL_TOKEN"],
|
|
173
|
+
blurb: "Serverless compute for AI + data. Token stored in Phantom.",
|
|
174
|
+
keyOnly: true,
|
|
175
|
+
dashboard: "https://modal.com",
|
|
176
|
+
docs: "https://modal.com/docs",
|
|
177
|
+
howTo: "Create a token in the Modal dashboard and paste it.",
|
|
178
|
+
sdkPackages: [],
|
|
179
|
+
},
|
|
136
180
|
{
|
|
137
181
|
name: "vercel",
|
|
138
182
|
displayName: "Vercel",
|
|
@@ -140,9 +184,16 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
140
184
|
authKind: "pat",
|
|
141
185
|
secrets: ["VERCEL_TOKEN"],
|
|
142
186
|
blurb: "Frontend platform. Stores a scoped access token for deploys + env sync.",
|
|
187
|
+
mcp: {
|
|
188
|
+
name: "vercel",
|
|
189
|
+
preview: true,
|
|
190
|
+
detail:
|
|
191
|
+
"Vercel MCP server with VERCEL_TOKEN piped from Phantom — list deployments, tail logs, sync env.",
|
|
192
|
+
},
|
|
143
193
|
dashboard: "https://vercel.com/dashboard",
|
|
144
194
|
docs: "https://vercel.com/docs/rest-api",
|
|
145
195
|
howTo: "Paste a personal access token from https://vercel.com/account/tokens.",
|
|
196
|
+
sdkPackages: [],
|
|
146
197
|
},
|
|
147
198
|
{
|
|
148
199
|
name: "railway",
|
|
@@ -151,9 +202,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
151
202
|
authKind: "api_key",
|
|
152
203
|
secrets: ["RAILWAY_TOKEN"],
|
|
153
204
|
blurb: "Infra from a repo. Project-level token stored in Phantom.",
|
|
205
|
+
keyOnly: true,
|
|
154
206
|
dashboard: "https://railway.app/dashboard",
|
|
155
207
|
docs: "https://docs.railway.app/reference/public-api",
|
|
156
208
|
howTo: "Paste an API token from https://railway.app/account/tokens.",
|
|
209
|
+
sdkPackages: [],
|
|
157
210
|
},
|
|
158
211
|
{
|
|
159
212
|
name: "fly",
|
|
@@ -162,9 +215,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
162
215
|
authKind: "api_key",
|
|
163
216
|
secrets: ["FLY_API_TOKEN"],
|
|
164
217
|
blurb: "VMs at the edge. Machines API token stored in Phantom.",
|
|
218
|
+
keyOnly: true,
|
|
165
219
|
dashboard: "https://fly.io/dashboard",
|
|
166
220
|
docs: "https://fly.io/docs/machines/api",
|
|
167
221
|
howTo: "Paste an API token from https://fly.io/user/personal_access_tokens.",
|
|
222
|
+
sdkPackages: [],
|
|
168
223
|
},
|
|
169
224
|
{
|
|
170
225
|
name: "cloudflare",
|
|
@@ -173,9 +228,16 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
173
228
|
authKind: "pat",
|
|
174
229
|
secrets: ["CLOUDFLARE_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID"],
|
|
175
230
|
blurb: "Workers, R2, D1. Account id inferred from the token's scope.",
|
|
231
|
+
mcp: {
|
|
232
|
+
name: "cloudflare",
|
|
233
|
+
preview: true,
|
|
234
|
+
detail:
|
|
235
|
+
"Cloudflare MCP (Workers Bindings + R2 + D1) with CLOUDFLARE_API_TOKEN piped from Phantom.",
|
|
236
|
+
},
|
|
176
237
|
dashboard: "https://dash.cloudflare.com",
|
|
177
238
|
docs: "https://developers.cloudflare.com/api",
|
|
178
239
|
howTo: "Create a scoped API token at https://dash.cloudflare.com/profile/api-tokens.",
|
|
240
|
+
sdkPackages: [],
|
|
179
241
|
},
|
|
180
242
|
{
|
|
181
243
|
name: "render",
|
|
@@ -184,9 +246,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
184
246
|
authKind: "api_key",
|
|
185
247
|
secrets: ["RENDER_API_KEY"],
|
|
186
248
|
blurb: "Zero-config hosting. API key stored in Phantom.",
|
|
249
|
+
keyOnly: true,
|
|
187
250
|
dashboard: "https://dashboard.render.com",
|
|
188
251
|
docs: "https://api-docs.render.com",
|
|
189
252
|
howTo: "Generate a key at https://dashboard.render.com/u/settings#api-keys.",
|
|
253
|
+
sdkPackages: [],
|
|
190
254
|
},
|
|
191
255
|
|
|
192
256
|
// ── Cloud ─────────────────────────────────────────────────────────────────
|
|
@@ -197,10 +261,12 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
197
261
|
authKind: "api_key",
|
|
198
262
|
secrets: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"],
|
|
199
263
|
blurb: "S3, Lambda, RDS. IAM access keys stored in Phantom.",
|
|
264
|
+
keyOnly: true,
|
|
200
265
|
dashboard: "https://console.aws.amazon.com",
|
|
201
266
|
docs: "https://docs.aws.amazon.com/iam/",
|
|
202
267
|
howTo: "Create an IAM access key pair in the AWS console and paste both halves.",
|
|
203
268
|
notes: "v1 stores the keys only — no resource provisioning. Scope the IAM policy narrowly.",
|
|
269
|
+
sdkPackages: [],
|
|
204
270
|
},
|
|
205
271
|
|
|
206
272
|
// ── AI ────────────────────────────────────────────────────────────────────
|
|
@@ -211,9 +277,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
211
277
|
authKind: "api_key",
|
|
212
278
|
secrets: ["OPENAI_API_KEY"],
|
|
213
279
|
blurb: "GPT, Realtime, embeddings. Key verified against /v1/models on paste.",
|
|
280
|
+
keyOnly: true,
|
|
214
281
|
dashboard: "https://platform.openai.com",
|
|
215
282
|
docs: "https://platform.openai.com/docs/api-reference",
|
|
216
283
|
howTo: "Paste a secret key from https://platform.openai.com/api-keys.",
|
|
284
|
+
sdkPackages: ["openai"],
|
|
217
285
|
},
|
|
218
286
|
{
|
|
219
287
|
name: "anthropic",
|
|
@@ -222,9 +290,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
222
290
|
authKind: "api_key",
|
|
223
291
|
secrets: ["ANTHROPIC_API_KEY"],
|
|
224
292
|
blurb: "Claude models + MCP. Key verified against the Messages API on paste.",
|
|
293
|
+
keyOnly: true,
|
|
225
294
|
dashboard: "https://console.anthropic.com",
|
|
226
295
|
docs: "https://docs.anthropic.com/en/api",
|
|
227
296
|
howTo: "Paste a secret key from https://console.anthropic.com/settings/keys.",
|
|
297
|
+
sdkPackages: ["@anthropic-ai/sdk"],
|
|
228
298
|
},
|
|
229
299
|
{
|
|
230
300
|
name: "xai",
|
|
@@ -233,9 +303,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
233
303
|
authKind: "api_key",
|
|
234
304
|
secrets: ["XAI_API_KEY"],
|
|
235
305
|
blurb: "Grok + tool use. Key verified on paste.",
|
|
306
|
+
keyOnly: true,
|
|
236
307
|
dashboard: "https://console.x.ai",
|
|
237
308
|
docs: "https://docs.x.ai/api",
|
|
238
309
|
howTo: "Paste a key from https://console.x.ai.",
|
|
310
|
+
sdkPackages: ["openai"],
|
|
239
311
|
},
|
|
240
312
|
{
|
|
241
313
|
name: "deepseek",
|
|
@@ -244,9 +316,38 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
244
316
|
authKind: "api_key",
|
|
245
317
|
secrets: ["DEEPSEEK_API_KEY"],
|
|
246
318
|
blurb: "Open-weight models. Key verified on paste.",
|
|
319
|
+
keyOnly: true,
|
|
247
320
|
dashboard: "https://platform.deepseek.com",
|
|
248
321
|
docs: "https://api-docs.deepseek.com",
|
|
249
322
|
howTo: "Paste a key from https://platform.deepseek.com/api_keys.",
|
|
323
|
+
sdkPackages: ["openai"],
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: "replicate",
|
|
327
|
+
displayName: "Replicate",
|
|
328
|
+
category: "AI",
|
|
329
|
+
authKind: "pat",
|
|
330
|
+
secrets: ["REPLICATE_API_TOKEN"],
|
|
331
|
+
blurb: "Open-source model inference with per-second billing. API token stored in Phantom.",
|
|
332
|
+
keyOnly: true,
|
|
333
|
+
dashboard: "https://replicate.com",
|
|
334
|
+
docs: "https://replicate.com/docs/reference/http",
|
|
335
|
+
howTo: "Create a token at https://replicate.com/account/api-tokens.",
|
|
336
|
+
sdkPackages: ["replicate"],
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: "braintrust",
|
|
340
|
+
displayName: "Braintrust",
|
|
341
|
+
category: "AI",
|
|
342
|
+
authKind: "api_key",
|
|
343
|
+
secrets: ["BRAINTRUST_API_KEY"],
|
|
344
|
+
blurb:
|
|
345
|
+
"LLM evals + observability + prompt playground. Verified against /v1/organization on paste.",
|
|
346
|
+
keyOnly: true,
|
|
347
|
+
dashboard: "https://www.braintrust.dev/app",
|
|
348
|
+
docs: "https://www.braintrust.dev/docs",
|
|
349
|
+
howTo: "Create a key at https://www.braintrust.dev/app/settings/api-keys.",
|
|
350
|
+
sdkPackages: ["braintrust"],
|
|
250
351
|
},
|
|
251
352
|
|
|
252
353
|
// ── Analytics ─────────────────────────────────────────────────────────────
|
|
@@ -257,6 +358,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
257
358
|
authKind: "api_key",
|
|
258
359
|
secrets: ["POSTHOG_PERSONAL_API_KEY"],
|
|
259
360
|
blurb: "Product analytics + flags. Personal API key stored in Phantom.",
|
|
361
|
+
keyOnly: true,
|
|
260
362
|
mcp: {
|
|
261
363
|
name: "posthog",
|
|
262
364
|
detail:
|
|
@@ -265,6 +367,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
265
367
|
dashboard: "https://app.posthog.com",
|
|
266
368
|
docs: "https://posthog.com/docs/api",
|
|
267
369
|
howTo: "Create a personal API key at https://app.posthog.com/me/settings (scope: all).",
|
|
370
|
+
sdkPackages: ["posthog-node"],
|
|
268
371
|
},
|
|
269
372
|
|
|
270
373
|
// ── Errors ────────────────────────────────────────────────────────────────
|
|
@@ -274,7 +377,8 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
274
377
|
category: "Errors",
|
|
275
378
|
authKind: "pat",
|
|
276
379
|
secrets: ["SENTRY_AUTH_TOKEN", "SENTRY_DSN", "SENTRY_ORG", "SENTRY_PROJECT"],
|
|
277
|
-
blurb:
|
|
380
|
+
blurb:
|
|
381
|
+
"Error + performance tracking. Attaches to an existing project and reads its DSN when available.",
|
|
278
382
|
mcp: {
|
|
279
383
|
name: "sentry",
|
|
280
384
|
detail:
|
|
@@ -284,6 +388,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
284
388
|
docs: "https://docs.sentry.io/api/",
|
|
285
389
|
howTo:
|
|
286
390
|
"Paste an auth token from https://sentry.io/settings/account/api/auth-tokens/ (scopes: project:read, project:write).",
|
|
391
|
+
sdkPackages: ["@sentry/node"],
|
|
287
392
|
},
|
|
288
393
|
|
|
289
394
|
// ── Payments ──────────────────────────────────────────────────────────────
|
|
@@ -294,12 +399,20 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
294
399
|
authKind: "api_key",
|
|
295
400
|
secrets: ["STRIPE_SECRET_KEY"],
|
|
296
401
|
blurb: "Billing, subscriptions, tax. Restricted / test-mode secret key stored in Phantom.",
|
|
402
|
+
keyOnly: true,
|
|
403
|
+
mcp: {
|
|
404
|
+
name: "stripe",
|
|
405
|
+
preview: true,
|
|
406
|
+
detail:
|
|
407
|
+
"@stripe/mcp with STRIPE_SECRET_KEY piped from Phantom — create products, prices, and inspect events from the agent.",
|
|
408
|
+
},
|
|
297
409
|
dashboard: "https://dashboard.stripe.com",
|
|
298
410
|
docs: "https://docs.stripe.com/api",
|
|
299
411
|
howTo:
|
|
300
412
|
"Create a restricted key at https://dashboard.stripe.com/apikeys (use test mode for development).",
|
|
301
413
|
notes:
|
|
302
414
|
"v1 only stores the key. Full Stripe Connect / account linking lands when we register the Ashlr OAuth app.",
|
|
415
|
+
sdkPackages: ["stripe"],
|
|
303
416
|
},
|
|
304
417
|
|
|
305
418
|
// ── Code ──────────────────────────────────────────────────────────────────
|
|
@@ -318,6 +431,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
318
431
|
dashboard: "https://github.com",
|
|
319
432
|
docs: "https://docs.github.com/en/rest",
|
|
320
433
|
howTo: "Browser device-code flow — enter the code GitHub shows you, authorise, done.",
|
|
434
|
+
sdkPackages: ["octokit"],
|
|
321
435
|
},
|
|
322
436
|
|
|
323
437
|
// ── Tickets ───────────────────────────────────────────────────────────────
|
|
@@ -328,6 +442,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
328
442
|
authKind: "api_key",
|
|
329
443
|
secrets: ["LINEAR_API_KEY"],
|
|
330
444
|
blurb: "Issues, projects, cycles. Personal API key stored in Phantom.",
|
|
445
|
+
keyOnly: true,
|
|
331
446
|
mcp: {
|
|
332
447
|
name: "linear",
|
|
333
448
|
detail: "mcp-linear with LINEAR_API_KEY piped from Phantom.",
|
|
@@ -335,6 +450,7 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
335
450
|
dashboard: "https://linear.app",
|
|
336
451
|
docs: "https://developers.linear.app/docs",
|
|
337
452
|
howTo: "Create a personal API key at https://linear.app/settings/api.",
|
|
453
|
+
sdkPackages: ["@linear/sdk"],
|
|
338
454
|
},
|
|
339
455
|
|
|
340
456
|
// ── Email ─────────────────────────────────────────────────────────────────
|
|
@@ -345,9 +461,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
345
461
|
authKind: "api_key",
|
|
346
462
|
secrets: ["RESEND_API_KEY"],
|
|
347
463
|
blurb: "Transactional + React Email. API key stored in Phantom.",
|
|
464
|
+
keyOnly: true,
|
|
348
465
|
dashboard: "https://resend.com",
|
|
349
466
|
docs: "https://resend.com/docs",
|
|
350
467
|
howTo: "Paste an API key from https://resend.com/api-keys.",
|
|
468
|
+
sdkPackages: ["resend"],
|
|
351
469
|
},
|
|
352
470
|
{
|
|
353
471
|
name: "sendgrid",
|
|
@@ -356,9 +474,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
356
474
|
authKind: "api_key",
|
|
357
475
|
secrets: ["SENDGRID_API_KEY"],
|
|
358
476
|
blurb: "High-volume transactional mail. API key verified against /v3/scopes on paste.",
|
|
477
|
+
keyOnly: true,
|
|
359
478
|
dashboard: "https://app.sendgrid.com",
|
|
360
479
|
docs: "https://docs.sendgrid.com/api-reference",
|
|
361
480
|
howTo: "Paste an API key from https://app.sendgrid.com/settings/api_keys.",
|
|
481
|
+
sdkPackages: ["@sendgrid/mail"],
|
|
362
482
|
},
|
|
363
483
|
{
|
|
364
484
|
name: "mailgun",
|
|
@@ -367,9 +487,11 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
367
487
|
authKind: "api_key",
|
|
368
488
|
secrets: ["MAILGUN_API_KEY"],
|
|
369
489
|
blurb: "API-first email + routing. Key verified against /v3/domains on paste (HTTP Basic).",
|
|
490
|
+
keyOnly: true,
|
|
370
491
|
dashboard: "https://app.mailgun.com",
|
|
371
492
|
docs: "https://documentation.mailgun.com/docs/mailgun/api-reference/",
|
|
372
493
|
howTo: "Paste an API key from https://app.mailgun.com/settings/api_security.",
|
|
494
|
+
sdkPackages: ["mailgun.js", "form-data"],
|
|
373
495
|
},
|
|
374
496
|
{
|
|
375
497
|
name: "postmark",
|
|
@@ -379,12 +501,147 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
379
501
|
secrets: ["POSTMARK_ACCOUNT_TOKEN"],
|
|
380
502
|
blurb:
|
|
381
503
|
"Deliverability-focused transactional. Account token verified against /servers on paste.",
|
|
504
|
+
keyOnly: true,
|
|
382
505
|
dashboard: "https://account.postmarkapp.com",
|
|
383
506
|
docs: "https://postmarkapp.com/developer/api/overview",
|
|
384
507
|
howTo: "Paste an account token from https://account.postmarkapp.com/api_tokens.",
|
|
508
|
+
sdkPackages: ["postmark"],
|
|
509
|
+
},
|
|
510
|
+
|
|
511
|
+
// ── Analytics ─────────────────────────────────────────────────────────────
|
|
512
|
+
{
|
|
513
|
+
name: "mixpanel",
|
|
514
|
+
displayName: "Mixpanel",
|
|
515
|
+
category: "Analytics",
|
|
516
|
+
authKind: "api_key",
|
|
517
|
+
secrets: ["MIXPANEL_PROJECT_TOKEN", "MIXPANEL_API_SECRET"],
|
|
518
|
+
blurb: "Product analytics. Project token + optional API secret stored in Phantom.",
|
|
519
|
+
keyOnly: true,
|
|
520
|
+
dashboard: "https://mixpanel.com",
|
|
521
|
+
docs: "https://developer.mixpanel.com/reference/overview",
|
|
522
|
+
howTo: "Find your project token and API secret in Mixpanel → Settings → Project Settings.",
|
|
523
|
+
sdkPackages: ["mixpanel"],
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: "plausible",
|
|
527
|
+
displayName: "Plausible",
|
|
528
|
+
category: "Analytics",
|
|
529
|
+
authKind: "api_key",
|
|
530
|
+
secrets: ["PLAUSIBLE_API_KEY", "PLAUSIBLE_SITE_ID"],
|
|
531
|
+
blurb: "Privacy-friendly web analytics. API key verified against the stats API.",
|
|
532
|
+
keyOnly: true,
|
|
533
|
+
dashboard: "https://plausible.io",
|
|
534
|
+
docs: "https://plausible.io/docs/stats-api",
|
|
535
|
+
howTo: "Generate an API key at https://plausible.io/settings and note your site ID.",
|
|
536
|
+
sdkPackages: [],
|
|
537
|
+
},
|
|
538
|
+
|
|
539
|
+
// ── Observability ─────────────────────────────────────────────────────────
|
|
540
|
+
{
|
|
541
|
+
name: "datadog",
|
|
542
|
+
displayName: "Datadog",
|
|
543
|
+
category: "Observability",
|
|
544
|
+
authKind: "api_key",
|
|
545
|
+
secrets: ["DD_API_KEY"],
|
|
546
|
+
blurb:
|
|
547
|
+
"Metrics, traces, logs. Current adapter validates an API key via /api/v1/validate and stores that key only.",
|
|
548
|
+
keyOnly: true,
|
|
549
|
+
dashboard: "https://app.datadoghq.com",
|
|
550
|
+
docs: "https://docs.datadoghq.com/api/latest/",
|
|
551
|
+
howTo:
|
|
552
|
+
"Create an API key at https://app.datadoghq.com/organization-settings/api-keys. This adapter validates and stores that key only.",
|
|
553
|
+
sdkPackages: ["dd-trace"],
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
name: "grafana",
|
|
557
|
+
displayName: "Grafana",
|
|
558
|
+
category: "Observability",
|
|
559
|
+
authKind: "pat",
|
|
560
|
+
secrets: ["GRAFANA_API_KEY", "GRAFANA_URL"],
|
|
561
|
+
blurb: "Dashboards + alerting. Service-account token verified against your Grafana instance.",
|
|
562
|
+
keyOnly: true,
|
|
563
|
+
dashboard: "https://grafana.com",
|
|
564
|
+
docs: "https://grafana.com/docs/grafana/latest/developers/http_api/",
|
|
565
|
+
howTo:
|
|
566
|
+
"Create a service-account token in Grafana → Administration → Service accounts, and provide your Grafana base URL.",
|
|
567
|
+
sdkPackages: [],
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
// ── Cloud ─────────────────────────────────────────────────────────────────
|
|
571
|
+
{
|
|
572
|
+
name: "gcp",
|
|
573
|
+
displayName: "GCP",
|
|
574
|
+
category: "Cloud",
|
|
575
|
+
authKind: "api_key",
|
|
576
|
+
secrets: ["GCP_SERVICE_ACCOUNT_JSON", "GCP_PROJECT_ID"],
|
|
577
|
+
blurb: "Google Cloud Platform. Service-account JSON + project ID stored in Phantom.",
|
|
578
|
+
keyOnly: true,
|
|
579
|
+
dashboard: "https://console.cloud.google.com",
|
|
580
|
+
docs: "https://cloud.google.com/docs/authentication/getting-started",
|
|
581
|
+
howTo:
|
|
582
|
+
"Download a service-account JSON key from GCP → IAM & Admin → Service Accounts and paste the full JSON.",
|
|
583
|
+
notes:
|
|
584
|
+
"v1 validates JSON shape and project_id field only — live project endpoint verification requires an OAuth2 token exchange; deferred to v0.2.",
|
|
585
|
+
sdkPackages: [],
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
name: "digitalocean",
|
|
589
|
+
displayName: "DigitalOcean",
|
|
590
|
+
category: "Cloud",
|
|
591
|
+
authKind: "pat",
|
|
592
|
+
secrets: ["DIGITALOCEAN_TOKEN"],
|
|
593
|
+
blurb:
|
|
594
|
+
"Droplets, Kubernetes, managed databases. Personal access token verified via /v2/account.",
|
|
595
|
+
keyOnly: true,
|
|
596
|
+
dashboard: "https://cloud.digitalocean.com",
|
|
597
|
+
docs: "https://docs.digitalocean.com/reference/api/api-reference/",
|
|
598
|
+
howTo: "Create a personal access token at https://cloud.digitalocean.com/account/api/tokens.",
|
|
599
|
+
sdkPackages: [],
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
name: "hetzner",
|
|
603
|
+
displayName: "Hetzner",
|
|
604
|
+
category: "Cloud",
|
|
605
|
+
authKind: "api_key",
|
|
606
|
+
secrets: ["HETZNER_API_TOKEN"],
|
|
607
|
+
blurb: "Affordable European cloud servers. API token verified via /v1/locations.",
|
|
608
|
+
keyOnly: true,
|
|
609
|
+
dashboard: "https://console.hetzner.cloud",
|
|
610
|
+
docs: "https://docs.hetzner.cloud/",
|
|
611
|
+
howTo: "Create an API token in Hetzner Cloud Console → Project → Security → API Tokens.",
|
|
612
|
+
sdkPackages: [],
|
|
385
613
|
},
|
|
386
614
|
|
|
387
615
|
// ── Auth ──────────────────────────────────────────────────────────────────
|
|
616
|
+
{
|
|
617
|
+
name: "auth0",
|
|
618
|
+
displayName: "Auth0",
|
|
619
|
+
category: "Auth",
|
|
620
|
+
authKind: "api_key",
|
|
621
|
+
secrets: ["AUTH0_DOMAIN"],
|
|
622
|
+
blurb:
|
|
623
|
+
"Identity platform. Current adapter checks a domain's discovery endpoint and stores only the domain.",
|
|
624
|
+
keyOnly: true,
|
|
625
|
+
dashboard: "https://manage.auth0.com",
|
|
626
|
+
docs: "https://auth0.com/docs/api/management/v2",
|
|
627
|
+
howTo:
|
|
628
|
+
"Enter your Auth0 tenant domain, such as your-tenant.us.auth0.com. This adapter checks its discovery response and stores only that domain.",
|
|
629
|
+
notes: "Browser SDK: @auth0/auth0-spa-js. Server SDK: auth0 (bundled).",
|
|
630
|
+
sdkPackages: ["auth0"],
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
name: "workos",
|
|
634
|
+
displayName: "WorkOS",
|
|
635
|
+
category: "Auth",
|
|
636
|
+
authKind: "api_key",
|
|
637
|
+
secrets: ["WORKOS_API_KEY", "WORKOS_CLIENT_ID"],
|
|
638
|
+
blurb: "Enterprise SSO + Directory Sync. API key verified via GET /organizations.",
|
|
639
|
+
keyOnly: true,
|
|
640
|
+
dashboard: "https://dashboard.workos.com",
|
|
641
|
+
docs: "https://workos.com/docs/reference/api",
|
|
642
|
+
howTo: "Find your API key and client ID in the WorkOS dashboard → API Keys.",
|
|
643
|
+
sdkPackages: ["@workos-inc/node"],
|
|
644
|
+
},
|
|
388
645
|
{
|
|
389
646
|
name: "clerk",
|
|
390
647
|
displayName: "Clerk",
|
|
@@ -392,9 +649,28 @@ export const PROVIDERS_REF: ProviderRef[] = [
|
|
|
392
649
|
authKind: "api_key",
|
|
393
650
|
secrets: ["CLERK_SECRET_KEY"],
|
|
394
651
|
blurb: "Drop-in auth + users. Secret key stored in Phantom.",
|
|
652
|
+
keyOnly: true,
|
|
395
653
|
dashboard: "https://dashboard.clerk.com",
|
|
396
654
|
docs: "https://clerk.com/docs",
|
|
397
655
|
howTo: "Paste a secret key from https://dashboard.clerk.com (API Keys).",
|
|
656
|
+
sdkPackages: ["@clerk/backend"],
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
// ── FeatureFlags ──────────────────────────────────────────────────────────
|
|
660
|
+
{
|
|
661
|
+
name: "launchdarkly",
|
|
662
|
+
displayName: "LaunchDarkly",
|
|
663
|
+
category: "FeatureFlags",
|
|
664
|
+
authKind: "api_key",
|
|
665
|
+
secrets: ["LAUNCHDARKLY_SDK_KEY", "LAUNCHDARKLY_API_TOKEN"],
|
|
666
|
+
blurb:
|
|
667
|
+
"Feature flags + experimentation. SDK key + API token verified via /api/v2/caller-identity.",
|
|
668
|
+
keyOnly: true,
|
|
669
|
+
dashboard: "https://app.launchdarkly.com",
|
|
670
|
+
docs: "https://apidocs.launchdarkly.com/",
|
|
671
|
+
howTo:
|
|
672
|
+
"Find your SDK key in LaunchDarkly → Environments and create an API token at LaunchDarkly → Account settings → Authorization.",
|
|
673
|
+
sdkPackages: ["launchdarkly-node-server-sdk"],
|
|
398
674
|
},
|
|
399
675
|
];
|
|
400
676
|
|
|
@@ -404,13 +680,16 @@ export const PROVIDER_CATEGORIES = [
|
|
|
404
680
|
"Cloud",
|
|
405
681
|
"AI",
|
|
406
682
|
"Analytics",
|
|
683
|
+
"Observability",
|
|
407
684
|
"Errors",
|
|
408
685
|
"Payments",
|
|
409
686
|
"Code",
|
|
410
687
|
"Tickets",
|
|
411
688
|
"Email",
|
|
412
689
|
"Auth",
|
|
690
|
+
"FeatureFlags",
|
|
413
691
|
] as const;
|
|
692
|
+
// If you see "Features" anywhere, it's stale — no provider currently maps to it.
|
|
414
693
|
|
|
415
694
|
export function groupByCategory(): Record<string, ProviderRef[]> {
|
|
416
695
|
const out: Record<string, ProviderRef[]> = {};
|