api-emulator 0.5.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.
- package/README.md +274 -0
- package/dist/api.d.ts +26 -0
- package/dist/api.js +561 -0
- package/dist/api.js.map +1 -0
- package/dist/fonts/GeistPixel-Square.woff2 +0 -0
- package/dist/fonts/favicon.ico +0 -0
- package/dist/fonts/geist-sans.woff2 +0 -0
- package/dist/index.js +887 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
package/dist/api.js
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
// src/external-plugin-adapter.ts
|
|
2
|
+
import { isAbsolute, resolve } from "path";
|
|
3
|
+
async function loadExternalPluginModule(specifier) {
|
|
4
|
+
const modulePath = specifier.startsWith(".") || isAbsolute(specifier) ? resolve(specifier) : specifier;
|
|
5
|
+
const mod = await import(modulePath);
|
|
6
|
+
const plugin = mod.plugin ?? mod.default;
|
|
7
|
+
if (!plugin || typeof plugin.register !== "function" || typeof plugin.name !== "string") {
|
|
8
|
+
throw new Error(`Plugin "${specifier}" must export a ServicePlugin (as "plugin" or default export)`);
|
|
9
|
+
}
|
|
10
|
+
const name = plugin.name;
|
|
11
|
+
return {
|
|
12
|
+
name,
|
|
13
|
+
label: mod.label ?? `${name} (external plugin)`,
|
|
14
|
+
endpoints: mod.endpoints ?? "",
|
|
15
|
+
async load() {
|
|
16
|
+
return {
|
|
17
|
+
plugin,
|
|
18
|
+
seedFromConfig: mod.seedFromConfig
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
defaultFallback: mod.defaultFallback ?? (() => ({ login: "admin", id: 1, scopes: [] })),
|
|
22
|
+
initConfig: mod.initConfig ?? {}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/default-plugin-catalog.ts
|
|
27
|
+
var DEFAULT_PLUGIN_REGISTRY = {
|
|
28
|
+
vercel: {
|
|
29
|
+
name: "vercel",
|
|
30
|
+
label: "Vercel REST API emulator",
|
|
31
|
+
endpoints: "projects, deployments, domains, env vars, users, teams, file uploads, protection bypass",
|
|
32
|
+
async load() {
|
|
33
|
+
const mod = await import("@emulators/vercel");
|
|
34
|
+
return { plugin: mod.vercelPlugin, seedFromConfig: mod.seedFromConfig };
|
|
35
|
+
},
|
|
36
|
+
defaultFallback(cfg) {
|
|
37
|
+
const firstLogin = cfg?.users?.[0]?.username ?? "admin";
|
|
38
|
+
return { login: firstLogin, id: 1, scopes: [] };
|
|
39
|
+
},
|
|
40
|
+
initConfig: {
|
|
41
|
+
vercel: {
|
|
42
|
+
users: [{ username: "developer", name: "Developer", email: "dev@example.com" }],
|
|
43
|
+
teams: [{ slug: "my-team", name: "My Team" }],
|
|
44
|
+
projects: [{ name: "my-app", team: "my-team", framework: "nextjs" }],
|
|
45
|
+
integrations: [
|
|
46
|
+
{
|
|
47
|
+
client_id: "oac_example_client_id",
|
|
48
|
+
client_secret: "example_client_secret",
|
|
49
|
+
name: "My Vercel App",
|
|
50
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/vercel"]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
github: {
|
|
57
|
+
name: "github",
|
|
58
|
+
label: "GitHub REST API emulator",
|
|
59
|
+
endpoints: "users, repos, issues, PRs, comments, reviews, labels, milestones, branches, git data, orgs, teams, releases, webhooks, search, actions, checks, rate limit",
|
|
60
|
+
async load() {
|
|
61
|
+
const mod = await import("@emulators/github");
|
|
62
|
+
return {
|
|
63
|
+
plugin: mod.githubPlugin,
|
|
64
|
+
seedFromConfig: mod.seedFromConfig,
|
|
65
|
+
createAppKeyResolver(store) {
|
|
66
|
+
return (appId) => {
|
|
67
|
+
try {
|
|
68
|
+
const gh = mod.getGitHubStore(store);
|
|
69
|
+
const ghApp = gh.apps.all().find((a) => a.app_id === appId);
|
|
70
|
+
if (!ghApp) return null;
|
|
71
|
+
return { privateKey: ghApp.private_key, slug: ghApp.slug, name: ghApp.name };
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
defaultFallback(cfg) {
|
|
80
|
+
const firstLogin = cfg?.users?.[0]?.login ?? "admin";
|
|
81
|
+
return { login: firstLogin, id: 1, scopes: ["repo", "user", "admin:org", "admin:repo_hook"] };
|
|
82
|
+
},
|
|
83
|
+
initConfig: {
|
|
84
|
+
github: {
|
|
85
|
+
users: [
|
|
86
|
+
{
|
|
87
|
+
login: "octocat",
|
|
88
|
+
name: "The Octocat",
|
|
89
|
+
email: "octocat@github.com",
|
|
90
|
+
bio: "I am the Octocat",
|
|
91
|
+
company: "GitHub",
|
|
92
|
+
location: "San Francisco"
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
orgs: [{ login: "my-org", name: "My Organization", description: "A test organization" }],
|
|
96
|
+
repos: [
|
|
97
|
+
{
|
|
98
|
+
owner: "octocat",
|
|
99
|
+
name: "hello-world",
|
|
100
|
+
description: "My first repository",
|
|
101
|
+
language: "JavaScript",
|
|
102
|
+
topics: ["hello", "world"],
|
|
103
|
+
auto_init: true
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
owner: "my-org",
|
|
107
|
+
name: "org-repo",
|
|
108
|
+
description: "An organization repository",
|
|
109
|
+
language: "TypeScript",
|
|
110
|
+
auto_init: true
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
oauth_apps: [
|
|
114
|
+
{
|
|
115
|
+
client_id: "Iv1.example_client_id",
|
|
116
|
+
client_secret: "example_client_secret",
|
|
117
|
+
name: "My App",
|
|
118
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/github"]
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
google: {
|
|
125
|
+
name: "google",
|
|
126
|
+
label: "Google OAuth 2.0 / OpenID Connect + Gmail, Calendar, and Drive emulator",
|
|
127
|
+
endpoints: "OAuth authorize, token exchange, userinfo, OIDC discovery, token revocation, Gmail messages/drafts/threads/labels/history/settings, Calendar lists/events/freebusy, Drive files/uploads",
|
|
128
|
+
async load() {
|
|
129
|
+
const mod = await import("@emulators/google");
|
|
130
|
+
return { plugin: mod.googlePlugin, seedFromConfig: mod.seedFromConfig };
|
|
131
|
+
},
|
|
132
|
+
defaultFallback(cfg) {
|
|
133
|
+
const firstEmail = cfg?.users?.[0]?.email ?? "testuser@gmail.com";
|
|
134
|
+
return { login: firstEmail, id: 1, scopes: ["openid", "email", "profile"] };
|
|
135
|
+
},
|
|
136
|
+
initConfig: {
|
|
137
|
+
google: {
|
|
138
|
+
users: [
|
|
139
|
+
{
|
|
140
|
+
email: "testuser@example.com",
|
|
141
|
+
name: "Test User",
|
|
142
|
+
picture: "https://lh3.googleusercontent.com/a/default-user",
|
|
143
|
+
email_verified: true
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
oauth_clients: [
|
|
147
|
+
{
|
|
148
|
+
client_id: "example-client-id.apps.googleusercontent.com",
|
|
149
|
+
client_secret: "GOCSPX-example_secret",
|
|
150
|
+
name: "Code App (Google)",
|
|
151
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/google"]
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
labels: [
|
|
155
|
+
{
|
|
156
|
+
id: "Label_ops",
|
|
157
|
+
user_email: "testuser@example.com",
|
|
158
|
+
name: "Ops/Review",
|
|
159
|
+
color_background: "#DDEEFF",
|
|
160
|
+
color_text: "#111111"
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
messages: [
|
|
164
|
+
{
|
|
165
|
+
id: "msg_welcome",
|
|
166
|
+
user_email: "testuser@example.com",
|
|
167
|
+
from: "welcome@example.com",
|
|
168
|
+
to: "testuser@example.com",
|
|
169
|
+
subject: "Welcome to the Gmail emulator",
|
|
170
|
+
body_text: "You can now test Gmail, Calendar, and Drive flows locally.",
|
|
171
|
+
label_ids: ["INBOX", "UNREAD", "CATEGORY_UPDATES"],
|
|
172
|
+
date: "2025-01-04T10:00:00.000Z"
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
calendars: [
|
|
176
|
+
{
|
|
177
|
+
id: "primary",
|
|
178
|
+
user_email: "testuser@example.com",
|
|
179
|
+
summary: "testuser@example.com",
|
|
180
|
+
primary: true,
|
|
181
|
+
selected: true,
|
|
182
|
+
time_zone: "UTC"
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
calendar_events: [
|
|
186
|
+
{
|
|
187
|
+
id: "evt_kickoff",
|
|
188
|
+
user_email: "testuser@example.com",
|
|
189
|
+
calendar_id: "primary",
|
|
190
|
+
summary: "Project Kickoff",
|
|
191
|
+
start_date_time: "2025-01-10T09:00:00.000Z",
|
|
192
|
+
end_date_time: "2025-01-10T09:30:00.000Z"
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
drive_items: [
|
|
196
|
+
{
|
|
197
|
+
id: "drv_docs",
|
|
198
|
+
user_email: "testuser@example.com",
|
|
199
|
+
name: "Docs",
|
|
200
|
+
mime_type: "application/vnd.google-apps.folder",
|
|
201
|
+
parent_ids: ["root"]
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
slack: {
|
|
208
|
+
name: "slack",
|
|
209
|
+
label: "Slack API emulator",
|
|
210
|
+
endpoints: "auth, chat, conversations, users, reactions, team, OAuth, incoming webhooks",
|
|
211
|
+
async load() {
|
|
212
|
+
const mod = await import("@emulators/slack");
|
|
213
|
+
return { plugin: mod.slackPlugin, seedFromConfig: mod.seedFromConfig };
|
|
214
|
+
},
|
|
215
|
+
defaultFallback() {
|
|
216
|
+
return { login: "U000000001", id: 1, scopes: ["chat:write", "channels:read", "users:read", "reactions:write"] };
|
|
217
|
+
},
|
|
218
|
+
initConfig: {
|
|
219
|
+
slack: {
|
|
220
|
+
team: { name: "My Workspace", domain: "my-workspace" },
|
|
221
|
+
users: [{ name: "developer", real_name: "Developer", email: "dev@example.com" }],
|
|
222
|
+
channels: [
|
|
223
|
+
{ name: "general", topic: "General discussion" },
|
|
224
|
+
{ name: "random", topic: "Random stuff" }
|
|
225
|
+
],
|
|
226
|
+
bots: [{ name: "my-bot" }],
|
|
227
|
+
oauth_apps: [
|
|
228
|
+
{
|
|
229
|
+
client_id: "12345.67890",
|
|
230
|
+
client_secret: "example_client_secret",
|
|
231
|
+
name: "My Slack App",
|
|
232
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/slack"]
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
apple: {
|
|
239
|
+
name: "apple",
|
|
240
|
+
label: "Apple Sign In / OAuth emulator",
|
|
241
|
+
endpoints: "OAuth authorize, token exchange, JWKS",
|
|
242
|
+
async load() {
|
|
243
|
+
const mod = await import("@emulators/apple");
|
|
244
|
+
return { plugin: mod.applePlugin, seedFromConfig: mod.seedFromConfig };
|
|
245
|
+
},
|
|
246
|
+
defaultFallback(cfg) {
|
|
247
|
+
const firstEmail = cfg?.users?.[0]?.email ?? "testuser@icloud.com";
|
|
248
|
+
return { login: firstEmail, id: 1, scopes: ["openid", "email", "name"] };
|
|
249
|
+
},
|
|
250
|
+
initConfig: {
|
|
251
|
+
apple: {
|
|
252
|
+
users: [{ email: "testuser@icloud.com", name: "Test User" }],
|
|
253
|
+
oauth_clients: [
|
|
254
|
+
{
|
|
255
|
+
client_id: "com.example.app",
|
|
256
|
+
team_id: "TEAM001",
|
|
257
|
+
name: "My Apple App",
|
|
258
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/apple"]
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
microsoft: {
|
|
265
|
+
name: "microsoft",
|
|
266
|
+
label: "Microsoft Entra ID OAuth 2.0 / OpenID Connect emulator",
|
|
267
|
+
endpoints: "OAuth authorize, token exchange, userinfo, OIDC discovery, Graph /me, logout, token revocation",
|
|
268
|
+
async load() {
|
|
269
|
+
const mod = await import("@emulators/microsoft");
|
|
270
|
+
return { plugin: mod.microsoftPlugin, seedFromConfig: mod.seedFromConfig };
|
|
271
|
+
},
|
|
272
|
+
defaultFallback(cfg) {
|
|
273
|
+
const firstEmail = cfg?.users?.[0]?.email ?? "testuser@outlook.com";
|
|
274
|
+
return { login: firstEmail, id: 1, scopes: ["openid", "email", "profile", "User.Read"] };
|
|
275
|
+
},
|
|
276
|
+
initConfig: {
|
|
277
|
+
microsoft: {
|
|
278
|
+
users: [{ email: "testuser@outlook.com", name: "Test User" }],
|
|
279
|
+
oauth_clients: [
|
|
280
|
+
{
|
|
281
|
+
client_id: "example-client-id",
|
|
282
|
+
client_secret: "example-client-secret",
|
|
283
|
+
name: "My Microsoft App",
|
|
284
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/microsoft-entra-id"]
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
okta: {
|
|
291
|
+
name: "okta",
|
|
292
|
+
label: "Okta OAuth 2.0 / OpenID Connect + management API emulator",
|
|
293
|
+
endpoints: "OIDC discovery, JWKS, OAuth authorize/token/userinfo/introspect/revoke/logout, users, groups, apps, authorization servers",
|
|
294
|
+
async load() {
|
|
295
|
+
const mod = await import("@emulators/okta");
|
|
296
|
+
return { plugin: mod.oktaPlugin, seedFromConfig: mod.seedFromConfig };
|
|
297
|
+
},
|
|
298
|
+
defaultFallback(cfg) {
|
|
299
|
+
const firstLogin = cfg?.users?.[0]?.login ?? cfg?.users?.[0]?.email ?? "testuser@okta.local";
|
|
300
|
+
return { login: firstLogin, id: 1, scopes: ["openid", "profile", "email", "groups"] };
|
|
301
|
+
},
|
|
302
|
+
initConfig: {
|
|
303
|
+
okta: {
|
|
304
|
+
users: [{ login: "testuser@okta.local", email: "testuser@okta.local", first_name: "Test", last_name: "User" }],
|
|
305
|
+
groups: [{ name: "Everyone", description: "All users", type: "BUILT_IN", okta_id: "00g_everyone" }],
|
|
306
|
+
authorization_servers: [{ id: "default", name: "default", audiences: ["api://default"] }],
|
|
307
|
+
oauth_clients: [
|
|
308
|
+
{
|
|
309
|
+
client_id: "okta-test-client",
|
|
310
|
+
client_secret: "okta-test-secret",
|
|
311
|
+
name: "Sample OIDC Client",
|
|
312
|
+
redirect_uris: ["http://localhost:3000/callback"],
|
|
313
|
+
auth_server_id: "default"
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
aws: {
|
|
320
|
+
name: "aws",
|
|
321
|
+
label: "AWS cloud service emulator",
|
|
322
|
+
endpoints: "S3 (buckets, objects), SQS (queues, messages), IAM (users, roles, access keys), STS (assume role, caller identity)",
|
|
323
|
+
async load() {
|
|
324
|
+
const mod = await import("@emulators/aws");
|
|
325
|
+
return { plugin: mod.awsPlugin, seedFromConfig: mod.seedFromConfig };
|
|
326
|
+
},
|
|
327
|
+
defaultFallback() {
|
|
328
|
+
return { login: "admin", id: 1, scopes: ["s3:*", "sqs:*", "iam:*", "sts:*"] };
|
|
329
|
+
},
|
|
330
|
+
initConfig: {
|
|
331
|
+
aws: {
|
|
332
|
+
region: "us-east-1",
|
|
333
|
+
s3: { buckets: [{ name: "my-app-bucket" }, { name: "my-app-uploads" }] },
|
|
334
|
+
sqs: { queues: [{ name: "my-app-events" }, { name: "my-app-dlq" }] },
|
|
335
|
+
iam: {
|
|
336
|
+
users: [{ user_name: "developer", create_access_key: true }],
|
|
337
|
+
roles: [{ role_name: "lambda-execution-role", description: "Role for Lambda function execution" }]
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
resend: {
|
|
343
|
+
name: "resend",
|
|
344
|
+
label: "Resend email API emulator",
|
|
345
|
+
endpoints: "emails, domains, contacts, API keys, inbox UI",
|
|
346
|
+
async load() {
|
|
347
|
+
const mod = await import("@emulators/resend");
|
|
348
|
+
return { plugin: mod.resendPlugin, seedFromConfig: mod.seedFromConfig };
|
|
349
|
+
},
|
|
350
|
+
defaultFallback() {
|
|
351
|
+
return { login: "re_test_admin", id: 1, scopes: [] };
|
|
352
|
+
},
|
|
353
|
+
initConfig: {
|
|
354
|
+
resend: {
|
|
355
|
+
domains: [{ name: "example.com", region: "us-east-1" }],
|
|
356
|
+
contacts: [{ email: "test@example.com", first_name: "Test", last_name: "User" }]
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
stripe: {
|
|
361
|
+
name: "stripe",
|
|
362
|
+
label: "Stripe payments emulator",
|
|
363
|
+
endpoints: "customers, payment methods, customer sessions, payment intents, charges, products, prices, checkout sessions, webhooks",
|
|
364
|
+
async load() {
|
|
365
|
+
const mod = await import("@emulators/stripe");
|
|
366
|
+
return { plugin: mod.stripePlugin, seedFromConfig: mod.seedFromConfig };
|
|
367
|
+
},
|
|
368
|
+
defaultFallback() {
|
|
369
|
+
return { login: "sk_test_admin", id: 1, scopes: [] };
|
|
370
|
+
},
|
|
371
|
+
initConfig: {
|
|
372
|
+
stripe: {
|
|
373
|
+
customers: [{ email: "test@example.com", name: "Test Customer" }],
|
|
374
|
+
products: [{ name: "Pro Plan", description: "Monthly pro subscription" }],
|
|
375
|
+
prices: [{ product_name: "Pro Plan", currency: "usd", unit_amount: 2e3 }]
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
mongoatlas: {
|
|
380
|
+
name: "mongoatlas",
|
|
381
|
+
label: "MongoDB Atlas service emulator",
|
|
382
|
+
endpoints: "Atlas Admin API v2 (projects, clusters, database users, databases, collections), Atlas Data API v1 (findOne, find, insertOne, insertMany, updateOne, updateMany, deleteOne, deleteMany, aggregate)",
|
|
383
|
+
async load() {
|
|
384
|
+
const mod = await import("@emulators/mongoatlas");
|
|
385
|
+
return { plugin: mod.mongoatlasPlugin, seedFromConfig: mod.seedFromConfig };
|
|
386
|
+
},
|
|
387
|
+
defaultFallback() {
|
|
388
|
+
return { login: "admin", id: 1, scopes: [] };
|
|
389
|
+
},
|
|
390
|
+
initConfig: {
|
|
391
|
+
mongoatlas: {
|
|
392
|
+
projects: [{ name: "Project0" }],
|
|
393
|
+
clusters: [{ name: "Cluster0", project: "Project0" }],
|
|
394
|
+
database_users: [{ username: "admin", project: "Project0" }],
|
|
395
|
+
databases: [{ cluster: "Cluster0", name: "test", collections: ["items"] }]
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
clerk: {
|
|
400
|
+
name: "clerk",
|
|
401
|
+
label: "Clerk authentication and user management emulator",
|
|
402
|
+
endpoints: "OIDC discovery, JWKS, OAuth authorize/token/userinfo, users, email addresses, organizations, memberships, invitations, sessions",
|
|
403
|
+
async load() {
|
|
404
|
+
const mod = await import("@emulators/clerk");
|
|
405
|
+
return { plugin: mod.clerkPlugin, seedFromConfig: mod.seedFromConfig };
|
|
406
|
+
},
|
|
407
|
+
defaultFallback(cfg) {
|
|
408
|
+
const firstEmail = cfg?.users?.[0]?.email_addresses?.[0] ?? "test@example.com";
|
|
409
|
+
return { login: firstEmail, id: 1, scopes: [] };
|
|
410
|
+
},
|
|
411
|
+
initConfig: {
|
|
412
|
+
clerk: {
|
|
413
|
+
users: [
|
|
414
|
+
{
|
|
415
|
+
first_name: "Test",
|
|
416
|
+
last_name: "User",
|
|
417
|
+
email_addresses: ["test@example.com"],
|
|
418
|
+
password: "clerk_test_password"
|
|
419
|
+
}
|
|
420
|
+
],
|
|
421
|
+
organizations: [
|
|
422
|
+
{
|
|
423
|
+
name: "My Company",
|
|
424
|
+
slug: "my-company",
|
|
425
|
+
members: [{ email: "test@example.com", role: "admin" }]
|
|
426
|
+
}
|
|
427
|
+
],
|
|
428
|
+
oauth_applications: [
|
|
429
|
+
{
|
|
430
|
+
client_id: "clerk_emulate_client",
|
|
431
|
+
client_secret: "clerk_emulate_secret",
|
|
432
|
+
name: "api-emulator App",
|
|
433
|
+
redirect_uris: ["http://localhost:3000/api/auth/callback/clerk"]
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// src/registry.ts
|
|
442
|
+
async function resolvePluginModules(pluginSpecifiers = []) {
|
|
443
|
+
const results = await Promise.all(pluginSpecifiers.map(loadExternalPluginModule));
|
|
444
|
+
const externalEntries = {};
|
|
445
|
+
for (const pluginModule of results) {
|
|
446
|
+
if (pluginModule.name in DEFAULT_PLUGIN_REGISTRY) {
|
|
447
|
+
throw new Error(`Plugin "${pluginModule.name}" conflicts with default plugin "${pluginModule.name}"`);
|
|
448
|
+
}
|
|
449
|
+
if (pluginModule.name in externalEntries) {
|
|
450
|
+
throw new Error(`Duplicate plugin name "${pluginModule.name}"`);
|
|
451
|
+
}
|
|
452
|
+
externalEntries[pluginModule.name] = pluginModule;
|
|
453
|
+
}
|
|
454
|
+
return { ...DEFAULT_PLUGIN_REGISTRY, ...externalEntries };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// src/base-url.ts
|
|
458
|
+
function resolveBaseUrl(opts) {
|
|
459
|
+
if (opts.seedBaseUrl) {
|
|
460
|
+
return opts.seedBaseUrl.replace(/\{service\}/g, opts.service);
|
|
461
|
+
}
|
|
462
|
+
if (opts.baseUrl) {
|
|
463
|
+
return opts.baseUrl.replace(/\{service\}/g, opts.service);
|
|
464
|
+
}
|
|
465
|
+
const envBaseUrl = process.env.API_EMULATOR_BASE_URL ?? process.env.EMULATE_BASE_URL;
|
|
466
|
+
if (envBaseUrl) {
|
|
467
|
+
return envBaseUrl.replace(/\{service\}/g, opts.service);
|
|
468
|
+
}
|
|
469
|
+
const portlessUrl = process.env.PORTLESS_URL;
|
|
470
|
+
if (portlessUrl) {
|
|
471
|
+
return portlessUrl.replace(/\{service\}/g, opts.service);
|
|
472
|
+
}
|
|
473
|
+
return `http://localhost:${opts.port}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/service-runtime.ts
|
|
477
|
+
import { createServer } from "@emulators/core";
|
|
478
|
+
import { serve } from "@hono/node-server";
|
|
479
|
+
function createAuthTokens(seedConfig) {
|
|
480
|
+
const tokens = {};
|
|
481
|
+
if (seedConfig?.tokens) {
|
|
482
|
+
let tokenId = 100;
|
|
483
|
+
for (const [token, user] of Object.entries(seedConfig.tokens)) {
|
|
484
|
+
tokens[token] = { login: user.login, id: tokenId++, scopes: user.scopes };
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
tokens["test_token_admin"] = { login: "admin", id: 2, scopes: ["repo", "user", "admin:org", "admin:repo_hook"] };
|
|
488
|
+
}
|
|
489
|
+
return tokens;
|
|
490
|
+
}
|
|
491
|
+
function createServiceRuntime(options) {
|
|
492
|
+
const { service, pluginModule, loadedPlugin, port, baseUrl, tokens, seedConfig } = options;
|
|
493
|
+
const resolverRef = {};
|
|
494
|
+
const appKeyResolver = loadedPlugin.createAppKeyResolver ? (appId) => resolverRef.current(appId) : void 0;
|
|
495
|
+
const fallbackUser = pluginModule.defaultFallback(seedConfig);
|
|
496
|
+
const { app, store, webhooks } = createServer(loadedPlugin.plugin, {
|
|
497
|
+
port,
|
|
498
|
+
baseUrl,
|
|
499
|
+
tokens,
|
|
500
|
+
appKeyResolver,
|
|
501
|
+
fallbackUser
|
|
502
|
+
});
|
|
503
|
+
resolverRef.current = loadedPlugin.createAppKeyResolver?.(store);
|
|
504
|
+
const seed = () => {
|
|
505
|
+
loadedPlugin.plugin.seed?.(store, baseUrl);
|
|
506
|
+
if (seedConfig && loadedPlugin.seedFromConfig) {
|
|
507
|
+
loadedPlugin.seedFromConfig(store, baseUrl, seedConfig, webhooks);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
seed();
|
|
511
|
+
const httpServer = serve({ fetch: app.fetch, port });
|
|
512
|
+
return {
|
|
513
|
+
service,
|
|
514
|
+
url: baseUrl,
|
|
515
|
+
store,
|
|
516
|
+
reset() {
|
|
517
|
+
store.reset();
|
|
518
|
+
seed();
|
|
519
|
+
},
|
|
520
|
+
close() {
|
|
521
|
+
return new Promise((resolve2, reject) => {
|
|
522
|
+
httpServer.close((err) => {
|
|
523
|
+
if (err) reject(err);
|
|
524
|
+
else resolve2();
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/api.ts
|
|
532
|
+
async function createEmulator(options) {
|
|
533
|
+
const { service, port = 4e3, seed: seedConfig, plugins = [] } = options;
|
|
534
|
+
const registry = await resolvePluginModules(plugins);
|
|
535
|
+
const pluginModule = registry[service];
|
|
536
|
+
if (!pluginModule) {
|
|
537
|
+
throw new Error(`Unknown service: ${service}`);
|
|
538
|
+
}
|
|
539
|
+
const loadedPlugin = await pluginModule.load();
|
|
540
|
+
const svcSeedConfig = seedConfig?.[service];
|
|
541
|
+
const seedBaseUrl = typeof svcSeedConfig?.baseUrl === "string" && svcSeedConfig.baseUrl.length > 0 ? svcSeedConfig.baseUrl : void 0;
|
|
542
|
+
const baseUrl = resolveBaseUrl({ service, port, baseUrl: options.baseUrl, seedBaseUrl });
|
|
543
|
+
const running = createServiceRuntime({
|
|
544
|
+
service,
|
|
545
|
+
pluginModule,
|
|
546
|
+
loadedPlugin,
|
|
547
|
+
port,
|
|
548
|
+
baseUrl,
|
|
549
|
+
tokens: createAuthTokens(seedConfig),
|
|
550
|
+
seedConfig: svcSeedConfig
|
|
551
|
+
});
|
|
552
|
+
return {
|
|
553
|
+
url: running.url,
|
|
554
|
+
reset: running.reset,
|
|
555
|
+
close: running.close
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
export {
|
|
559
|
+
createEmulator
|
|
560
|
+
};
|
|
561
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/external-plugin-adapter.ts","../src/default-plugin-catalog.ts","../src/registry.ts","../src/base-url.ts","../src/service-runtime.ts","../src/api.ts"],"sourcesContent":["import type { ServicePlugin, Store, AuthFallback, WebhookDispatcher } from \"@emulators/core\";\nimport { isAbsolute, resolve } from \"path\";\nimport type { PluginModule } from \"./plugin-types.js\";\n\nexport interface ExternalPluginModule {\n plugin?: ServicePlugin;\n default?: ServicePlugin;\n seedFromConfig?(store: Store, baseUrl: string, config: unknown, webhooks?: WebhookDispatcher): void;\n label?: string;\n endpoints?: string;\n defaultFallback?(svcSeedConfig?: Record<string, unknown>): AuthFallback;\n initConfig?: Record<string, unknown>;\n}\n\nexport async function loadExternalPluginModule(specifier: string): Promise<PluginModule> {\n const modulePath = specifier.startsWith(\".\") || isAbsolute(specifier) ? resolve(specifier) : specifier;\n\n const mod = (await import(modulePath)) as ExternalPluginModule;\n const plugin = mod.plugin ?? mod.default;\n if (!plugin || typeof plugin.register !== \"function\" || typeof plugin.name !== \"string\") {\n throw new Error(`Plugin \"${specifier}\" must export a ServicePlugin (as \"plugin\" or default export)`);\n }\n\n const name = plugin.name;\n return {\n name,\n label: mod.label ?? `${name} (external plugin)`,\n endpoints: mod.endpoints ?? \"\",\n async load() {\n return {\n plugin,\n seedFromConfig: mod.seedFromConfig,\n };\n },\n defaultFallback: mod.defaultFallback ?? (() => ({ login: \"admin\", id: 1, scopes: [] })),\n initConfig: mod.initConfig ?? {},\n };\n}\n\nexport async function loadExternalPlugin(specifier: string): Promise<{ name: string; entry: PluginModule }> {\n const pluginModule = await loadExternalPluginModule(specifier);\n return { name: pluginModule.name, entry: pluginModule };\n}\n","import type { Store, AppKeyResolver } from \"@emulators/core\";\nimport type { PluginModule } from \"./plugin-types.js\";\n\nconst DEFAULT_PLUGIN_NAME_LIST = [\n \"vercel\",\n \"github\",\n \"google\",\n \"slack\",\n \"apple\",\n \"microsoft\",\n \"okta\",\n \"aws\",\n \"resend\",\n \"stripe\",\n \"mongoatlas\",\n \"clerk\",\n] as const;\nexport type ServiceName = (typeof DEFAULT_PLUGIN_NAME_LIST)[number];\nexport const DEFAULT_PLUGIN_NAMES: readonly ServiceName[] = DEFAULT_PLUGIN_NAME_LIST;\nexport const SERVICE_NAMES: readonly ServiceName[] = DEFAULT_PLUGIN_NAMES;\n\nexport const DEFAULT_PLUGIN_REGISTRY: Record<ServiceName, PluginModule> = {\n vercel: {\n name: \"vercel\",\n label: \"Vercel REST API emulator\",\n endpoints: \"projects, deployments, domains, env vars, users, teams, file uploads, protection bypass\",\n async load() {\n const mod = await import(\"@emulators/vercel\");\n return { plugin: mod.vercelPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstLogin = (cfg?.users as Array<{ username?: string }> | undefined)?.[0]?.username ?? \"admin\";\n return { login: firstLogin, id: 1, scopes: [] };\n },\n initConfig: {\n vercel: {\n users: [{ username: \"developer\", name: \"Developer\", email: \"dev@example.com\" }],\n teams: [{ slug: \"my-team\", name: \"My Team\" }],\n projects: [{ name: \"my-app\", team: \"my-team\", framework: \"nextjs\" }],\n integrations: [\n {\n client_id: \"oac_example_client_id\",\n client_secret: \"example_client_secret\",\n name: \"My Vercel App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/vercel\"],\n },\n ],\n },\n },\n },\n\n github: {\n name: \"github\",\n label: \"GitHub REST API emulator\",\n endpoints:\n \"users, repos, issues, PRs, comments, reviews, labels, milestones, branches, git data, orgs, teams, releases, webhooks, search, actions, checks, rate limit\",\n async load() {\n const mod = await import(\"@emulators/github\");\n return {\n plugin: mod.githubPlugin,\n seedFromConfig: mod.seedFromConfig,\n createAppKeyResolver(store: Store): AppKeyResolver {\n return (appId: number) => {\n try {\n const gh = mod.getGitHubStore(store);\n const ghApp = gh.apps.all().find((a) => a.app_id === appId);\n if (!ghApp) return null;\n return { privateKey: ghApp.private_key, slug: ghApp.slug, name: ghApp.name };\n } catch {\n return null;\n }\n };\n },\n };\n },\n defaultFallback(cfg) {\n const firstLogin = (cfg?.users as Array<{ login?: string }> | undefined)?.[0]?.login ?? \"admin\";\n return { login: firstLogin, id: 1, scopes: [\"repo\", \"user\", \"admin:org\", \"admin:repo_hook\"] };\n },\n initConfig: {\n github: {\n users: [\n {\n login: \"octocat\",\n name: \"The Octocat\",\n email: \"octocat@github.com\",\n bio: \"I am the Octocat\",\n company: \"GitHub\",\n location: \"San Francisco\",\n },\n ],\n orgs: [{ login: \"my-org\", name: \"My Organization\", description: \"A test organization\" }],\n repos: [\n {\n owner: \"octocat\",\n name: \"hello-world\",\n description: \"My first repository\",\n language: \"JavaScript\",\n topics: [\"hello\", \"world\"],\n auto_init: true,\n },\n {\n owner: \"my-org\",\n name: \"org-repo\",\n description: \"An organization repository\",\n language: \"TypeScript\",\n auto_init: true,\n },\n ],\n oauth_apps: [\n {\n client_id: \"Iv1.example_client_id\",\n client_secret: \"example_client_secret\",\n name: \"My App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/github\"],\n },\n ],\n },\n },\n },\n\n google: {\n name: \"google\",\n label: \"Google OAuth 2.0 / OpenID Connect + Gmail, Calendar, and Drive emulator\",\n endpoints:\n \"OAuth authorize, token exchange, userinfo, OIDC discovery, token revocation, Gmail messages/drafts/threads/labels/history/settings, Calendar lists/events/freebusy, Drive files/uploads\",\n async load() {\n const mod = await import(\"@emulators/google\");\n return { plugin: mod.googlePlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstEmail = (cfg?.users as Array<{ email?: string }> | undefined)?.[0]?.email ?? \"testuser@gmail.com\";\n return { login: firstEmail, id: 1, scopes: [\"openid\", \"email\", \"profile\"] };\n },\n initConfig: {\n google: {\n users: [\n {\n email: \"testuser@example.com\",\n name: \"Test User\",\n picture: \"https://lh3.googleusercontent.com/a/default-user\",\n email_verified: true,\n },\n ],\n oauth_clients: [\n {\n client_id: \"example-client-id.apps.googleusercontent.com\",\n client_secret: \"GOCSPX-example_secret\",\n name: \"Code App (Google)\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/google\"],\n },\n ],\n labels: [\n {\n id: \"Label_ops\",\n user_email: \"testuser@example.com\",\n name: \"Ops/Review\",\n color_background: \"#DDEEFF\",\n color_text: \"#111111\",\n },\n ],\n messages: [\n {\n id: \"msg_welcome\",\n user_email: \"testuser@example.com\",\n from: \"welcome@example.com\",\n to: \"testuser@example.com\",\n subject: \"Welcome to the Gmail emulator\",\n body_text: \"You can now test Gmail, Calendar, and Drive flows locally.\",\n label_ids: [\"INBOX\", \"UNREAD\", \"CATEGORY_UPDATES\"],\n date: \"2025-01-04T10:00:00.000Z\",\n },\n ],\n calendars: [\n {\n id: \"primary\",\n user_email: \"testuser@example.com\",\n summary: \"testuser@example.com\",\n primary: true,\n selected: true,\n time_zone: \"UTC\",\n },\n ],\n calendar_events: [\n {\n id: \"evt_kickoff\",\n user_email: \"testuser@example.com\",\n calendar_id: \"primary\",\n summary: \"Project Kickoff\",\n start_date_time: \"2025-01-10T09:00:00.000Z\",\n end_date_time: \"2025-01-10T09:30:00.000Z\",\n },\n ],\n drive_items: [\n {\n id: \"drv_docs\",\n user_email: \"testuser@example.com\",\n name: \"Docs\",\n mime_type: \"application/vnd.google-apps.folder\",\n parent_ids: [\"root\"],\n },\n ],\n },\n },\n },\n\n slack: {\n name: \"slack\",\n label: \"Slack API emulator\",\n endpoints: \"auth, chat, conversations, users, reactions, team, OAuth, incoming webhooks\",\n async load() {\n const mod = await import(\"@emulators/slack\");\n return { plugin: mod.slackPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback() {\n return { login: \"U000000001\", id: 1, scopes: [\"chat:write\", \"channels:read\", \"users:read\", \"reactions:write\"] };\n },\n initConfig: {\n slack: {\n team: { name: \"My Workspace\", domain: \"my-workspace\" },\n users: [{ name: \"developer\", real_name: \"Developer\", email: \"dev@example.com\" }],\n channels: [\n { name: \"general\", topic: \"General discussion\" },\n { name: \"random\", topic: \"Random stuff\" },\n ],\n bots: [{ name: \"my-bot\" }],\n oauth_apps: [\n {\n client_id: \"12345.67890\",\n client_secret: \"example_client_secret\",\n name: \"My Slack App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/slack\"],\n },\n ],\n },\n },\n },\n\n apple: {\n name: \"apple\",\n label: \"Apple Sign In / OAuth emulator\",\n endpoints: \"OAuth authorize, token exchange, JWKS\",\n async load() {\n const mod = await import(\"@emulators/apple\");\n return { plugin: mod.applePlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstEmail = (cfg?.users as Array<{ email?: string }> | undefined)?.[0]?.email ?? \"testuser@icloud.com\";\n return { login: firstEmail, id: 1, scopes: [\"openid\", \"email\", \"name\"] };\n },\n initConfig: {\n apple: {\n users: [{ email: \"testuser@icloud.com\", name: \"Test User\" }],\n oauth_clients: [\n {\n client_id: \"com.example.app\",\n team_id: \"TEAM001\",\n name: \"My Apple App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/apple\"],\n },\n ],\n },\n },\n },\n\n microsoft: {\n name: \"microsoft\",\n label: \"Microsoft Entra ID OAuth 2.0 / OpenID Connect emulator\",\n endpoints: \"OAuth authorize, token exchange, userinfo, OIDC discovery, Graph /me, logout, token revocation\",\n async load() {\n const mod = await import(\"@emulators/microsoft\");\n return { plugin: mod.microsoftPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstEmail = (cfg?.users as Array<{ email?: string }> | undefined)?.[0]?.email ?? \"testuser@outlook.com\";\n return { login: firstEmail, id: 1, scopes: [\"openid\", \"email\", \"profile\", \"User.Read\"] };\n },\n initConfig: {\n microsoft: {\n users: [{ email: \"testuser@outlook.com\", name: \"Test User\" }],\n oauth_clients: [\n {\n client_id: \"example-client-id\",\n client_secret: \"example-client-secret\",\n name: \"My Microsoft App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/microsoft-entra-id\"],\n },\n ],\n },\n },\n },\n\n okta: {\n name: \"okta\",\n label: \"Okta OAuth 2.0 / OpenID Connect + management API emulator\",\n endpoints:\n \"OIDC discovery, JWKS, OAuth authorize/token/userinfo/introspect/revoke/logout, users, groups, apps, authorization servers\",\n async load() {\n const mod = await import(\"@emulators/okta\");\n return { plugin: mod.oktaPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstLogin =\n (cfg?.users as Array<{ login?: string; email?: string }> | undefined)?.[0]?.login ??\n (cfg?.users as Array<{ login?: string; email?: string }> | undefined)?.[0]?.email ??\n \"testuser@okta.local\";\n return { login: firstLogin, id: 1, scopes: [\"openid\", \"profile\", \"email\", \"groups\"] };\n },\n initConfig: {\n okta: {\n users: [{ login: \"testuser@okta.local\", email: \"testuser@okta.local\", first_name: \"Test\", last_name: \"User\" }],\n groups: [{ name: \"Everyone\", description: \"All users\", type: \"BUILT_IN\", okta_id: \"00g_everyone\" }],\n authorization_servers: [{ id: \"default\", name: \"default\", audiences: [\"api://default\"] }],\n oauth_clients: [\n {\n client_id: \"okta-test-client\",\n client_secret: \"okta-test-secret\",\n name: \"Sample OIDC Client\",\n redirect_uris: [\"http://localhost:3000/callback\"],\n auth_server_id: \"default\",\n },\n ],\n },\n },\n },\n\n aws: {\n name: \"aws\",\n label: \"AWS cloud service emulator\",\n endpoints:\n \"S3 (buckets, objects), SQS (queues, messages), IAM (users, roles, access keys), STS (assume role, caller identity)\",\n async load() {\n const mod = await import(\"@emulators/aws\");\n return { plugin: mod.awsPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback() {\n return { login: \"admin\", id: 1, scopes: [\"s3:*\", \"sqs:*\", \"iam:*\", \"sts:*\"] };\n },\n initConfig: {\n aws: {\n region: \"us-east-1\",\n s3: { buckets: [{ name: \"my-app-bucket\" }, { name: \"my-app-uploads\" }] },\n sqs: { queues: [{ name: \"my-app-events\" }, { name: \"my-app-dlq\" }] },\n iam: {\n users: [{ user_name: \"developer\", create_access_key: true }],\n roles: [{ role_name: \"lambda-execution-role\", description: \"Role for Lambda function execution\" }],\n },\n },\n },\n },\n resend: {\n name: \"resend\",\n label: \"Resend email API emulator\",\n endpoints: \"emails, domains, contacts, API keys, inbox UI\",\n async load() {\n const mod = await import(\"@emulators/resend\");\n return { plugin: mod.resendPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback() {\n return { login: \"re_test_admin\", id: 1, scopes: [] };\n },\n initConfig: {\n resend: {\n domains: [{ name: \"example.com\", region: \"us-east-1\" }],\n contacts: [{ email: \"test@example.com\", first_name: \"Test\", last_name: \"User\" }],\n },\n },\n },\n stripe: {\n name: \"stripe\",\n label: \"Stripe payments emulator\",\n endpoints:\n \"customers, payment methods, customer sessions, payment intents, charges, products, prices, checkout sessions, webhooks\",\n async load() {\n const mod = await import(\"@emulators/stripe\");\n return { plugin: mod.stripePlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback() {\n return { login: \"sk_test_admin\", id: 1, scopes: [] };\n },\n initConfig: {\n stripe: {\n customers: [{ email: \"test@example.com\", name: \"Test Customer\" }],\n products: [{ name: \"Pro Plan\", description: \"Monthly pro subscription\" }],\n prices: [{ product_name: \"Pro Plan\", currency: \"usd\", unit_amount: 2000 }],\n },\n },\n },\n mongoatlas: {\n name: \"mongoatlas\",\n label: \"MongoDB Atlas service emulator\",\n endpoints:\n \"Atlas Admin API v2 (projects, clusters, database users, databases, collections), Atlas Data API v1 (findOne, find, insertOne, insertMany, updateOne, updateMany, deleteOne, deleteMany, aggregate)\",\n async load() {\n const mod = await import(\"@emulators/mongoatlas\");\n return { plugin: mod.mongoatlasPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback() {\n return { login: \"admin\", id: 1, scopes: [] };\n },\n initConfig: {\n mongoatlas: {\n projects: [{ name: \"Project0\" }],\n clusters: [{ name: \"Cluster0\", project: \"Project0\" }],\n database_users: [{ username: \"admin\", project: \"Project0\" }],\n databases: [{ cluster: \"Cluster0\", name: \"test\", collections: [\"items\"] }],\n },\n },\n },\n clerk: {\n name: \"clerk\",\n label: \"Clerk authentication and user management emulator\",\n endpoints:\n \"OIDC discovery, JWKS, OAuth authorize/token/userinfo, users, email addresses, organizations, memberships, invitations, sessions\",\n async load() {\n const mod = await import(\"@emulators/clerk\");\n return { plugin: mod.clerkPlugin, seedFromConfig: mod.seedFromConfig };\n },\n defaultFallback(cfg) {\n const firstEmail =\n (cfg?.users as Array<{ email_addresses?: string[] }> | undefined)?.[0]?.email_addresses?.[0] ??\n \"test@example.com\";\n return { login: firstEmail, id: 1, scopes: [] };\n },\n initConfig: {\n clerk: {\n users: [\n {\n first_name: \"Test\",\n last_name: \"User\",\n email_addresses: [\"test@example.com\"],\n password: \"clerk_test_password\",\n },\n ],\n organizations: [\n {\n name: \"My Company\",\n slug: \"my-company\",\n members: [{ email: \"test@example.com\", role: \"admin\" }],\n },\n ],\n oauth_applications: [\n {\n client_id: \"clerk_emulate_client\",\n client_secret: \"clerk_emulate_secret\",\n name: \"api-emulator App\",\n redirect_uris: [\"http://localhost:3000/api/auth/callback/clerk\"],\n },\n ],\n },\n },\n },\n};\n","import { loadExternalPluginModule } from \"./external-plugin-adapter.js\";\nimport {\n DEFAULT_PLUGIN_REGISTRY,\n DEFAULT_PLUGIN_NAMES,\n SERVICE_NAMES,\n type ServiceName,\n} from \"./default-plugin-catalog.js\";\nimport type { PluginModule } from \"./plugin-types.js\";\nexport { DEFAULT_PLUGIN_REGISTRY, DEFAULT_PLUGIN_NAMES, SERVICE_NAMES, type ServiceName };\nexport type { LoadedPlugin, LoadedService, PluginModule, ServiceEntry } from \"./plugin-types.js\";\n\nexport const DEFAULT_TOKENS = {\n tokens: {\n test_token_admin: {\n login: \"admin\",\n scopes: [\"repo\", \"user\", \"admin:org\", \"admin:repo_hook\"],\n },\n test_token_user1: {\n login: \"octocat\",\n scopes: [\"repo\", \"user\"],\n },\n },\n};\n\nexport async function resolvePluginModules(pluginSpecifiers: string[] = []): Promise<Record<string, PluginModule>> {\n const results = await Promise.all(pluginSpecifiers.map(loadExternalPluginModule));\n\n const externalEntries: Record<string, PluginModule> = {};\n for (const pluginModule of results) {\n if (pluginModule.name in DEFAULT_PLUGIN_REGISTRY) {\n throw new Error(`Plugin \"${pluginModule.name}\" conflicts with default plugin \"${pluginModule.name}\"`);\n }\n if (pluginModule.name in externalEntries) {\n throw new Error(`Duplicate plugin name \"${pluginModule.name}\"`);\n }\n externalEntries[pluginModule.name] = pluginModule;\n }\n\n return { ...DEFAULT_PLUGIN_REGISTRY, ...externalEntries };\n}\n\nexport const resolveServiceEntries = resolvePluginModules;\n\nexport function getDefaultPluginNames(): string[] {\n return [...DEFAULT_PLUGIN_NAMES];\n}\n","export interface ResolveBaseUrlOptions {\n service: string;\n port: number;\n baseUrl?: string;\n seedBaseUrl?: string;\n}\n\n/**\n * Fallback chain:\n * 1. Per-service baseUrl from seed config\n * 2. Explicit baseUrl (CLI flag or programmatic option)\n * 3. API_EMULATOR_BASE_URL env var (with {service} interpolation)\n * 4. EMULATE_BASE_URL env var for backward compatibility (with {service} interpolation)\n * 5. PORTLESS_URL env var (with {service} interpolation)\n * 6. http://localhost:<port>\n */\nexport function resolveBaseUrl(opts: ResolveBaseUrlOptions): string {\n if (opts.seedBaseUrl) {\n return opts.seedBaseUrl.replace(/\\{service\\}/g, opts.service);\n }\n if (opts.baseUrl) {\n return opts.baseUrl.replace(/\\{service\\}/g, opts.service);\n }\n const envBaseUrl = process.env.API_EMULATOR_BASE_URL ?? process.env.EMULATE_BASE_URL;\n if (envBaseUrl) {\n return envBaseUrl.replace(/\\{service\\}/g, opts.service);\n }\n const portlessUrl = process.env.PORTLESS_URL;\n if (portlessUrl) {\n return portlessUrl.replace(/\\{service\\}/g, opts.service);\n }\n return `http://localhost:${opts.port}`;\n}\n","import { createServer, type AppKeyResolver, type Store } from \"@emulators/core\";\nimport { serve } from \"@hono/node-server\";\nimport type { LoadedPlugin, PluginModule } from \"./registry.js\";\n\nexport interface SeedConfig {\n tokens?: Record<string, { login: string; scopes?: string[] }>;\n [service: string]: unknown;\n}\n\nexport type TokenMap = Record<string, { login: string; id: number; scopes?: string[] }>;\n\nexport interface ServiceRuntimeOptions {\n service: string;\n pluginModule: PluginModule;\n loadedPlugin: LoadedPlugin;\n port: number;\n baseUrl: string;\n tokens: TokenMap;\n seedConfig?: Record<string, unknown>;\n}\n\nexport interface RunningService {\n service: string;\n url: string;\n store: Store;\n reset(): void;\n close(): Promise<void>;\n}\n\nexport function createAuthTokens(seedConfig?: SeedConfig | null): TokenMap {\n const tokens: TokenMap = {};\n if (seedConfig?.tokens) {\n let tokenId = 100;\n for (const [token, user] of Object.entries(seedConfig.tokens)) {\n tokens[token] = { login: user.login, id: tokenId++, scopes: user.scopes };\n }\n } else {\n tokens[\"test_token_admin\"] = { login: \"admin\", id: 2, scopes: [\"repo\", \"user\", \"admin:org\", \"admin:repo_hook\"] };\n }\n return tokens;\n}\n\nexport function createServiceRuntime(options: ServiceRuntimeOptions): RunningService {\n const { service, pluginModule, loadedPlugin, port, baseUrl, tokens, seedConfig } = options;\n\n const resolverRef: { current?: AppKeyResolver } = {};\n const appKeyResolver: AppKeyResolver | undefined = loadedPlugin.createAppKeyResolver\n ? (appId) => resolverRef.current!(appId)\n : undefined;\n const fallbackUser = pluginModule.defaultFallback(seedConfig);\n\n const { app, store, webhooks } = createServer(loadedPlugin.plugin, {\n port,\n baseUrl,\n tokens,\n appKeyResolver,\n fallbackUser,\n });\n resolverRef.current = loadedPlugin.createAppKeyResolver?.(store);\n\n const seed = () => {\n loadedPlugin.plugin.seed?.(store, baseUrl);\n if (seedConfig && loadedPlugin.seedFromConfig) {\n loadedPlugin.seedFromConfig(store, baseUrl, seedConfig, webhooks);\n }\n };\n seed();\n\n const httpServer = serve({ fetch: app.fetch, port });\n\n return {\n service,\n url: baseUrl,\n store,\n reset() {\n store.reset();\n seed();\n },\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n httpServer.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n },\n };\n}\n","import { resolvePluginModules } from \"./registry.js\";\nexport type { ServiceName } from \"./registry.js\";\nimport type { ServiceName } from \"./registry.js\";\nimport { resolveBaseUrl } from \"./base-url.js\";\nimport { createAuthTokens, createServiceRuntime, type SeedConfig } from \"./service-runtime.js\";\n\nexport type { SeedConfig };\n\nexport interface EmulatorOptions {\n service: ServiceName | (string & {});\n port?: number;\n seed?: SeedConfig;\n baseUrl?: string;\n plugins?: string[];\n}\n\nexport interface Emulator {\n url: string;\n reset(): void;\n close(): Promise<void>;\n}\n\nexport async function createEmulator(options: EmulatorOptions): Promise<Emulator> {\n const { service, port = 4000, seed: seedConfig, plugins = [] } = options;\n\n const registry = await resolvePluginModules(plugins);\n const pluginModule = registry[service];\n if (!pluginModule) {\n throw new Error(`Unknown service: ${service}`);\n }\n\n const loadedPlugin = await pluginModule.load();\n\n const svcSeedConfig = seedConfig?.[service] as Record<string, unknown> | undefined;\n const seedBaseUrl =\n typeof svcSeedConfig?.baseUrl === \"string\" && svcSeedConfig.baseUrl.length > 0 ? svcSeedConfig.baseUrl : undefined;\n const baseUrl = resolveBaseUrl({ service, port, baseUrl: options.baseUrl, seedBaseUrl });\n const running = createServiceRuntime({\n service,\n pluginModule,\n loadedPlugin,\n port,\n baseUrl,\n tokens: createAuthTokens(seedConfig),\n seedConfig: svcSeedConfig,\n });\n\n return {\n url: running.url,\n reset: running.reset,\n close: running.close,\n };\n}\n"],"mappings":"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","names":["resolve"]}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|