|
1 | 1 | import path from 'node:path' |
| 2 | +import os from 'node:os' |
2 | 3 | import { Readable } from 'node:stream' |
3 | 4 | import { defineCommand } from 'citty' |
4 | 5 | import { createCliFromSpec } from '@stripe/sync-ts-cli/openapi' |
@@ -125,6 +126,53 @@ const workerCmd = defineCommand({ |
125 | 126 | }, |
126 | 127 | }) |
127 | 128 |
|
| 129 | +// Standalone webhook ingress command (Temporal mode only) |
| 130 | +const webhookCmd = defineCommand({ |
| 131 | + meta: { name: 'webhook', description: 'Start the webhook ingress server (Temporal mode)' }, |
| 132 | + args: { |
| 133 | + port: { |
| 134 | + type: 'string', |
| 135 | + default: '4030', |
| 136 | + description: 'HTTP server port (default: 4030)', |
| 137 | + }, |
| 138 | + 'data-dir': { |
| 139 | + type: 'string', |
| 140 | + description: 'Data directory — must point at the same store as the sync service', |
| 141 | + }, |
| 142 | + 'temporal-address': { |
| 143 | + type: 'string', |
| 144 | + required: true, |
| 145 | + description: 'Temporal server address (e.g. localhost:7233)', |
| 146 | + }, |
| 147 | + 'temporal-task-queue': { |
| 148 | + type: 'string', |
| 149 | + default: 'sync-engine', |
| 150 | + description: 'Temporal task queue name (default: sync-engine)', |
| 151 | + }, |
| 152 | + }, |
| 153 | + async run({ args }) { |
| 154 | + const { fileConfigStore } = await import('../lib/stores-fs.js') |
| 155 | + const { TemporalBridge } = await import('../temporal/bridge.js') |
| 156 | + const { createWebhookApp } = await import('../api/webhook-app.js') |
| 157 | + |
| 158 | + const temporal = await createTemporalClient( |
| 159 | + args['temporal-address'], |
| 160 | + args['temporal-task-queue'] || 'sync-engine' |
| 161 | + ) |
| 162 | + const dataDir = |
| 163 | + args['data-dir'] || process.env.DATA_DIR || path.join(os.homedir(), '.stripe-sync') |
| 164 | + const configs = fileConfigStore(`${dataDir}/syncs`) |
| 165 | + const bridge = new TemporalBridge(temporal.client, temporal.taskQueue, configs) |
| 166 | + |
| 167 | + const app = createWebhookApp({ push_event: (id, e) => bridge.pushEvent(id, e) }) |
| 168 | + const port = Number(args.port) |
| 169 | + serve({ fetch: app.fetch, port }, () => { |
| 170 | + console.log(`Webhook server listening on http://localhost:${port}`) |
| 171 | + console.log(` Temporal: ${args['temporal-address']} (queue: ${args['temporal-task-queue'] || 'sync-engine'})`) |
| 172 | + }) |
| 173 | + }, |
| 174 | +}) |
| 175 | + |
128 | 176 | export async function createProgram(opts?: { dataDir?: string }) { |
129 | 177 | const app = createApp({ dataDir: opts?.dataDir }) |
130 | 178 | const res = await app.request('/openapi.json') |
@@ -155,6 +203,6 @@ export async function createProgram(opts?: { dataDir?: string }) { |
155 | 203 |
|
156 | 204 | return defineCommand({ |
157 | 205 | ...specCli, |
158 | | - subCommands: { serve: serveCmd, worker: workerCmd, ...specCli.subCommands }, |
| 206 | + subCommands: { serve: serveCmd, worker: workerCmd, webhook: webhookCmd, ...specCli.subCommands }, |
159 | 207 | }) |
160 | 208 | } |
0 commit comments