feat: run this repo and vercel-labs emulators together via a single-process launcher#24
Conversation
Bump @emulators/core from ^0.6.0 to ^0.9.0 across all service packages so this repo's emulators dedup onto the same shared core as vercel-labs' @emulators/* packages (the two core versions are byte-identical, so no code changes were required). This is a prerequisite for running both sets of emulators in a single process.
Add scripts/emulate-all.ts, a single-process launcher that hosts this repo's services (via @pleaseai/emulate's createEmulator) alongside vercel-labs' @emulators/* services (via the shared core's createServer/serve) in one process. Services get stable per-service ports in separate ranges (this-repo 4000+, vercel-labs 4100+), share emulate.config.* seeding, guard against port-range overlap, and shut down gracefully. Export SERVICE_NAMES from @pleaseai/emulate's public API as the single source of truth for the service list, consumed by the launcher. Add the launcher's root devDependencies (bun's isolated linker requires them to be direct root deps): @emulators/core plus 12 vercel service packages, @pleaseai/emulate (workspace:*), picocolors, yaml, and the upstream emulate CLI for reference. Wire up the emulate:all script.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 1 critical 9 high |
🟢 Metrics 89 complexity · 1 duplication
Metric Results Complexity 89 Duplication 1
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
- thread the WebhookDispatcher into vercel seedFromConfig so stripe webhook seed config is actually registered (was silently dropped) - error on non-numeric --port/--vercel-port instead of silently falling back to the default - warn (not silently start everything) when a config has no recognized service keys - dedupe --service names to avoid a same-port bind crash - name the failing service and keep the stack on startup errors - guard a missing default export; log per-service close failures
Address the two genuine Codacy findings in the emulate-all launcher's server close handler (L217): - reject with a real Error when server.close reports one, instead of forwarding a possibly-undefined value (prefer-promise-reject-errors) - give the close callback a block body so the arrow no longer returns a void expression (no-confusing-void-expression) The remaining Codacy warnings are eslint-plugin-security false positives for a trusted dev CLI launcher; the repo's own ESLint config intentionally does not enforce those rules, and `eslint .` stays green.
There was a problem hiding this comment.
All reported issues were addressed across 18 files
Architecture diagram
sequenceDiagram
participant Dev as Developer
participant Launcher as emulate-all.ts
participant Core as @emulators/core
participant Please as @pleaseai/emulate
participant VercelPkg as @emulators/stripe (example)
participant ConfigFile as emulate.config.yaml
Dev->>Launcher: bun run emulate:all [--service=kakao,stripe] [--port=5000]
Note over Launcher: Parse args, compute stable base ports
Launcher->>Launcher: parseArgs(process.argv)
alt --port provided
Launcher->>Launcher: use given port for this-repo base
else
Launcher->>Launcher: check EMULATE_PORT, PORT env, default 4000
end
alt --vercel-port provided
Launcher->>Launcher: use given port for vercel-labs base
else
Launcher->>Launcher: vercelBase = pleaseBase + 100
end
Note over Launcher: Ensure range overlap guard
alt pleaseBase + len(PLEASE_ORDER) >= vercelBase
Launcher-->>Dev: ERROR: Port ranges overlap
Launcher->>Launcher: process.exit(1)
end
Note over Launcher: Load config file
alt --config provided
Launcher->>ConfigFile: load explicit path
else
Launcher->>ConfigFile: probe emulate.config.{yaml,yml,json}
end
ConfigFile-->>Launcher: parsed SeedConfig
Note over Launcher: Resolve service list
alt --service given
Launcher->>Launcher: split and dedupe services
else config present with known keys
Launcher->>Launcher: infer from config keys
else fallback
Launcher->>Launcher: include all services from both repos
end
Note over Launcher: Start services with stable ports
loop For each service
alt Service in PLEASE_SET (this-repo)
Launcher->>Please: createEmulator({service, port, seed})
Note right of Please: Uses @emulators/core internally
Please-->>Launcher: Emulator instance (url, close)
else Service in VERCEL_SET (vercel-labs)
Launcher->>VercelPkg: import default export (ServicePlugin)
Launcher->>Core: createServer(plugin, {port, baseUrl, tokens})
Core-->>Launcher: {app, store, webhooks}
alt config provides seed for this service
Launcher->>VercelPkg: seedFromConfig(store, baseUrl, svcConfig, webhooks)
Note right of VercelPkg: e.g. Stripe webhook registration
end
Launcher->>Core: serve({fetch: app.fetch, port})
Core-->>Launcher: server handle
Launcher->>Launcher: wrap close() to reject with Error
end
Launcher->>Launcher: store Running instance
end
Note over Launcher: Log started services with URLs
Launcher-->>Dev: All services ready (e.g. kakao:4000, stripe:4102)
Note over Launcher,Dev: Runtime operations… (services handle incoming requests)
Dev->>Launcher: SIGINT/SIGTERM
Launcher->>Launcher: gracefulShutdown()
loop For each Running service
Launcher->>Launcher: close() with timeout
alt close succeeds
Launcher->>Launcher: log success
else close fails
Launcher->>Launcher: log error
end
end
Launcher->>Launcher: exit(0)
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- startVercel: await 'listening'/reject on 'error' so an occupied Vercel port rejects into main()'s try/catch (closing already-started services) instead of crashing via an async listen error (cubic P2) - parseArgs: reject `--service` with no value instead of silently starting every emulator (cubic P3) - basePortFrom/vercelBaseFrom: use `!== undefined` so an explicit port 0 is honored rather than falling through as falsy (greptile P2) - startPlease: narrow with `name as ServiceName` instead of `name as never`, restoring type-checking at the call site (greptile P2) - resolveServices: route the "no known service keys" notice through console.warn (stderr → warn) so it doesn't read as an error (greptile P2)
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Follow-up to the review fixes, addressing cubic's re-review of the launcher: - parseArgs: reject `--service ""` (empty string is falsy, so it slipped past the `=== undefined` guard and started every emulator); the `!value` check also drops the "unnecessary conditional" warning since argv indexing is typed as string - resolveServices: reject a value that resolves to no names (e.g. `--service ,`) instead of starting nothing and idling - main: reject a base port of 0 or any range that spills past 65535 for the range in use. Honoring an explicit `--port 0` (from the earlier falsy-guard fix) otherwise produced bogus localhost:0 URLs; erroring loudly keeps that fix's "no silent override" intent while covering the CLI and env sources
|



Summary
Lets users run this repo's emulators (Kakao, Naver, Toss, Firebase, etc.) alongside vercel-labs' upstream
@emulators/*emulators (github,google,slack,stripe,aws, …) in one process, with one command.Changes
@emulators/coreversion^0.6.0→^0.9.0across all 14 packages. The 0.6.0 and 0.9.0 cores are byte-identical, so this is a pure version-alignment change (no code diff) that lets this repo's@emulators/*service packages dedup onto the same shared core vercel-labs' emulators depend on.scripts/emulate-all.ts(bun run emulate:all), a single-process launcher that hosts this repo's emulators and the upstream vercel-labs@emulators/*emulators together on the shared core.SERVICE_NAMESfrom the@pleaseai/emulatepublic API.emulate:allscript needed by the launcher.Behavior
bun run emulate:allstarts all requested emulators in a single process with stable per-service ports in separate ranges: this-repo services at4000+, vercel-labs services at4100+(stable regardless of selection order).emulate.config.*seeding across both emulator sets.--service,--port,--vercel-port,--config.Test Plan
Note for Reviewers
The launcher and its vercel
@emulators/*dependencies are root devDependencies only — the published@pleaseai/emulatepackage's dependency footprint is unchanged.Summary by cubic
Run this repo’s emulators and vercel-labs
@emulators/*together in one process with a new single-command launcher. Aligns all packages to@emulators/core@^0.9.0so both sets share the same core.New Features
bun run emulate:allto start selected services from both repos in one process.4000+, vercel-labs at4100+; configure with--portand--vercel-port.emulate.config.{yaml,yml,json}; supports--serviceand--config.SERVICE_NAMESfrom@pleaseai/emulate.Bug Fixes
--port/--vercel-port; reject missing or empty--serviceand empty lists; dedupe names; warn when config has no known services; reject base port0and ranges that exceed65535.WebhookDispatcherintoseedFromConfig(Stripe webhooks now register).server.closerejects with an Error; log per-service close failures; guard missing default exports.Written for commit 1c102f9. Summary will update on new commits.