@kirschbaum-development/sst-laravel 0.3.1 → 0.3.3
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 +40 -1
- package/dist/bin/cli.js +2 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/commands/command-run.d.ts +3 -0
- package/dist/bin/commands/command-run.js +69 -0
- package/dist/bin/commands/command-run.js.map +1 -0
- package/docs/api.md +125 -1
- package/laravel-sst.ts +229 -50
- package/package.json +1 -1
- package/src/reverb.ts +26 -0
- package/templates/sst.config.run.template +10 -0
package/README.md
CHANGED
|
@@ -88,6 +88,44 @@ const app = new LaravelService('MyLaravelApp', {
|
|
|
88
88
|
|
|
89
89
|
Check all the `web` options [here](https://github.com/kirschbaum-development/sst-laravel/blob/main/docs/api.md#web).
|
|
90
90
|
|
|
91
|
+
### Reverb
|
|
92
|
+
|
|
93
|
+
You can deploy a dedicated Laravel Reverb service for WebSocket traffic. Reverb runs as a worker-style container using `php artisan reverb:start`, but SST Laravel also attaches a load balancer so you can give it its own public domain.
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
const app = new LaravelService('MyLaravelApp', {
|
|
97
|
+
web: {
|
|
98
|
+
domain: 'app.example.com',
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
reverb: {
|
|
102
|
+
domain: {
|
|
103
|
+
dns: sst.cloudflare.dns(),
|
|
104
|
+
name: 'ws.example.com',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
url: app.url,
|
|
111
|
+
reverbUrl: app.reverbUrl,
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
When `reverb.domain` is configured, SST Laravel automatically injects the Reverb server variables:
|
|
116
|
+
|
|
117
|
+
```env
|
|
118
|
+
REVERB_SERVER_HOST=0.0.0.0
|
|
119
|
+
REVERB_SERVER_PORT=8080
|
|
120
|
+
REVERB_HOST=ws.example.com
|
|
121
|
+
REVERB_PORT=443
|
|
122
|
+
REVERB_SCHEME=https
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
If you enable horizontal scaling for Reverb, make sure your Laravel application is configured for Reverb scaling with Redis.
|
|
126
|
+
|
|
127
|
+
Check all the `reverb` options [here](https://github.com/kirschbaum-development/sst-laravel/blob/main/docs/api.md#reverb).
|
|
128
|
+
|
|
91
129
|
### Workers
|
|
92
130
|
|
|
93
131
|
Beyond HTTP requests, you can set up one or more `workers` for your Laravel application. Workers are meant to run background commands like Laravel Horizon, the Laravel Scheduler or any background command you may need to run.
|
|
@@ -407,6 +445,7 @@ This will list all running tasks in your cluster and let you choose which one to
|
|
|
407
445
|
```bash
|
|
408
446
|
npx sst-laravel ssh web --stage production
|
|
409
447
|
npx sst-laravel ssh worker --stage production
|
|
448
|
+
npx sst-laravel ssh reverb --stage production
|
|
410
449
|
```
|
|
411
450
|
|
|
412
451
|
If you are naming your workers differently, you can specify the worker name:
|
|
@@ -423,6 +462,7 @@ You can view the logs for your application using the `sst-laravel logs` command.
|
|
|
423
462
|
```bash
|
|
424
463
|
npx sst-laravel logs {service} --stage production
|
|
425
464
|
npx sst-laravel logs web --stage production
|
|
465
|
+
npx sst-laravel logs reverb --stage production
|
|
426
466
|
npx sst-laravel logs worker --stage production
|
|
427
467
|
```
|
|
428
468
|
|
|
@@ -474,7 +514,6 @@ In case your specified environment file does not contain the `APP_URL` variable,
|
|
|
474
514
|
* Ability to extend base Docker images;
|
|
475
515
|
* Add support for Inertia SSR;
|
|
476
516
|
* Add support for Octane with FrankedPHP;
|
|
477
|
-
* Add support for Laravel Reverb;
|
|
478
517
|
* Dev mode;
|
|
479
518
|
* ...what else are we missing?
|
|
480
519
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { initCommand } from './commands/init.js';
|
|
6
6
|
import { deployCommand } from './commands/deploy.js';
|
|
7
|
+
import { commandRunCommand } from './commands/command-run.js';
|
|
7
8
|
import { sshCommand } from './commands/ssh.js';
|
|
8
9
|
import { logsCommand } from './commands/logs.js';
|
|
9
10
|
import { githubIamCommand } from './commands/github-iam.js';
|
|
@@ -21,6 +22,7 @@ program
|
|
|
21
22
|
.version(version);
|
|
22
23
|
program.addCommand(initCommand);
|
|
23
24
|
program.addCommand(deployCommand);
|
|
25
|
+
program.addCommand(commandRunCommand);
|
|
24
26
|
program.addCommand(sshCommand);
|
|
25
27
|
program.addCommand(logsCommand);
|
|
26
28
|
program.addCommand(githubIamCommand);
|
package/dist/bin/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,CAAC;AACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,uCAAuC,CAAC;KACpD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,cAAc,CAAC,CAAC;AACpE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAEpC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,uCAAuC,CAAC;KACpD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { ECSClient } from '@aws-sdk/client-ecs';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { findClusterArn, findTask } from '../utils/ecs.js';
|
|
5
|
+
export function buildCommandToRun(commandParts, raw) {
|
|
6
|
+
if (commandParts.length === 0) {
|
|
7
|
+
throw new Error('Command is required.');
|
|
8
|
+
}
|
|
9
|
+
const command = commandParts.join(' ');
|
|
10
|
+
return raw ? command : `php artisan ${command}`;
|
|
11
|
+
}
|
|
12
|
+
export const commandRunCommand = new Command('command:run')
|
|
13
|
+
.description('Run a command in a running ECS task')
|
|
14
|
+
.argument('<command...>', 'Artisan command signature and options to run')
|
|
15
|
+
.allowUnknownOption(true)
|
|
16
|
+
.option('-s, --stage <stage>', 'SST stage name (required)')
|
|
17
|
+
.option('-c, --cluster <cluster>', 'ECS cluster name (optional, auto-detected from SST config)')
|
|
18
|
+
.option('-r, --region <region>', 'AWS region', process.env.AWS_REGION || 'us-east-1')
|
|
19
|
+
.option('--service <service>', 'Service to run the command against (web, worker, or worker name)', 'web')
|
|
20
|
+
.option('--container <container>', 'Container name override')
|
|
21
|
+
.option('--raw', 'Run the provided command instead of prefixing it with "php artisan"', false)
|
|
22
|
+
.action(async (commandParts, options) => {
|
|
23
|
+
try {
|
|
24
|
+
const region = options.region;
|
|
25
|
+
const stage = options.stage;
|
|
26
|
+
if (!stage) {
|
|
27
|
+
console.error('Error: Stage is required. Use --stage flag to specify the SST stage.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const ecsClient = new ECSClient({ region });
|
|
31
|
+
const clusterArn = await findClusterArn(ecsClient, stage, options.cluster);
|
|
32
|
+
const matchingTask = await findTask(ecsClient, clusterArn, options.service, 'Select a task to run the command in:');
|
|
33
|
+
const taskId = matchingTask.taskArn?.split('/').pop();
|
|
34
|
+
const containerName = options.container || matchingTask.containers?.[0]?.name;
|
|
35
|
+
const command = buildCommandToRun(commandParts, options.raw);
|
|
36
|
+
if (!taskId) {
|
|
37
|
+
console.error('Error: Could not determine ECS task ID.');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
if (!containerName) {
|
|
41
|
+
console.error('Error: Could not determine ECS container name.');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
console.log(`Running command in task: ${taskId}`);
|
|
45
|
+
console.log(`Container: ${containerName}`);
|
|
46
|
+
console.log(`Command: ${command}`);
|
|
47
|
+
console.log('');
|
|
48
|
+
const awsCommand = spawn('aws', [
|
|
49
|
+
'ecs',
|
|
50
|
+
'execute-command',
|
|
51
|
+
'--cluster', clusterArn,
|
|
52
|
+
'--task', taskId,
|
|
53
|
+
'--container', containerName,
|
|
54
|
+
'--interactive',
|
|
55
|
+
'--command', command,
|
|
56
|
+
], {
|
|
57
|
+
stdio: 'inherit',
|
|
58
|
+
env: { ...process.env, AWS_REGION: region },
|
|
59
|
+
});
|
|
60
|
+
awsCommand.on('exit', (code) => {
|
|
61
|
+
process.exit(code || 0);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error('Error:', error.message);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=command-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-run.js","sourceRoot":"","sources":["../../../bin/commands/command-run.ts"],"names":[],"mappings":"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"}
|
package/docs/api.md
CHANGED
|
@@ -97,6 +97,9 @@ new LaravelService("Laravel", {
|
|
|
97
97
|
web: {
|
|
98
98
|
domain: "example.com"
|
|
99
99
|
},
|
|
100
|
+
reverb: {
|
|
101
|
+
domain: "ws.example.com"
|
|
102
|
+
},
|
|
100
103
|
config: {
|
|
101
104
|
environment: {
|
|
102
105
|
secrets: env
|
|
@@ -348,6 +351,103 @@ workers: [
|
|
|
348
351
|
- **Type:** `ServiceArgs["permissions"]`
|
|
349
352
|
- **Description:** IAM permissions specific to this worker.
|
|
350
353
|
|
|
354
|
+
### `reverb`
|
|
355
|
+
- **Type:** `boolean | LaravelReverbArgs`
|
|
356
|
+
- **Default:** `false`
|
|
357
|
+
- **Description:** Configuration for a dedicated Laravel Reverb service. When enabled, SST Laravel creates a worker-style service that runs `php artisan reverb:start` and exposes it through a load balancer.
|
|
358
|
+
|
|
359
|
+
**Example:**
|
|
360
|
+
```typescript
|
|
361
|
+
reverb: {
|
|
362
|
+
domain: "ws.example.com",
|
|
363
|
+
scaling: {
|
|
364
|
+
min: 1,
|
|
365
|
+
max: 2
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
You can also enable Reverb with defaults:
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
reverb: true
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### `reverb.domain`
|
|
377
|
+
- **Type:** `Input<string | { name: Input<string>; cert?: Input<string>; dns?: Input<false | Dns> }>`
|
|
378
|
+
- **Description:** Custom domain for the Reverb service. If provided, SST Laravel routes HTTP and HTTPS traffic to Reverb's internal listener on port 8080 by default.
|
|
379
|
+
|
|
380
|
+
**Example (with custom DNS provider):**
|
|
381
|
+
```typescript
|
|
382
|
+
reverb: {
|
|
383
|
+
domain: {
|
|
384
|
+
name: "ws.example.com",
|
|
385
|
+
dns: sst.cloudflare.dns()
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
When `reverb.domain` is configured, SST Laravel auto-injects:
|
|
391
|
+
|
|
392
|
+
```env
|
|
393
|
+
REVERB_SERVER_HOST=0.0.0.0
|
|
394
|
+
REVERB_SERVER_PORT=8080
|
|
395
|
+
REVERB_HOST=ws.example.com
|
|
396
|
+
REVERB_PORT=443
|
|
397
|
+
REVERB_SCHEME=https
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### `reverb.host`
|
|
401
|
+
- **Type:** `string`
|
|
402
|
+
- **Default:** `"0.0.0.0"`
|
|
403
|
+
- **Description:** Host the Reverb server listens on inside the container.
|
|
404
|
+
|
|
405
|
+
#### `reverb.port`
|
|
406
|
+
- **Type:** `number`
|
|
407
|
+
- **Default:** `8080`
|
|
408
|
+
- **Description:** Port the Reverb server listens on inside the container. The default load balancer forwards traffic to this port.
|
|
409
|
+
|
|
410
|
+
#### `reverb.command`
|
|
411
|
+
- **Type:** `string`
|
|
412
|
+
- **Default:** `"php artisan reverb:start"`
|
|
413
|
+
- **Description:** Command used to start the Reverb service.
|
|
414
|
+
|
|
415
|
+
#### `reverb.architecture`
|
|
416
|
+
- **Type:** `ServiceArgs["architecture"]`
|
|
417
|
+
- **Description:** The CPU architecture for the Reverb service.
|
|
418
|
+
|
|
419
|
+
#### `reverb.cpu`
|
|
420
|
+
- **Type:** `ServiceArgs["cpu"]`
|
|
421
|
+
- **Description:** CPU units for the Reverb service.
|
|
422
|
+
|
|
423
|
+
#### `reverb.memory`
|
|
424
|
+
- **Type:** `ServiceArgs["memory"]`
|
|
425
|
+
- **Description:** Memory allocation for the Reverb service.
|
|
426
|
+
|
|
427
|
+
#### `reverb.storage`
|
|
428
|
+
- **Type:** `ServiceArgs["storage"]`
|
|
429
|
+
- **Description:** Storage configuration for the Reverb service.
|
|
430
|
+
|
|
431
|
+
#### `reverb.scaling`
|
|
432
|
+
- **Type:** `ServiceArgs["scaling"]`
|
|
433
|
+
- **Description:** Auto-scaling configuration for the Reverb service. Horizontal Reverb scaling requires Redis and `REVERB_SCALING_ENABLED=true` in your Laravel environment.
|
|
434
|
+
|
|
435
|
+
#### `reverb.logging`
|
|
436
|
+
- **Type:** `ServiceArgs["logging"]`
|
|
437
|
+
- **Description:** Logging configuration for the Reverb service.
|
|
438
|
+
|
|
439
|
+
#### `reverb.health`
|
|
440
|
+
- **Type:** `ServiceArgs["health"]`
|
|
441
|
+
- **Description:** ECS health check configuration for the Reverb service.
|
|
442
|
+
|
|
443
|
+
#### `reverb.executionRole`
|
|
444
|
+
- **Type:** `ServiceArgs["executionRole"]`
|
|
445
|
+
- **Description:** Execution role for the Reverb service.
|
|
446
|
+
|
|
447
|
+
#### `reverb.permissions`
|
|
448
|
+
- **Type:** `ServiceArgs["permissions"]`
|
|
449
|
+
- **Description:** IAM permissions specific to the Reverb service.
|
|
450
|
+
|
|
351
451
|
### `config`
|
|
352
452
|
- **Type:** `object`
|
|
353
453
|
- **Description:** Config settings.
|
|
@@ -449,6 +549,16 @@ const app = new LaravelService("MyApp", { ... });
|
|
|
449
549
|
console.log(app.url); // https://example.com or https://xyz.elb.amazonaws.com
|
|
450
550
|
```
|
|
451
551
|
|
|
552
|
+
### `reverbUrl`
|
|
553
|
+
- **Type:** `Output<string>`
|
|
554
|
+
- **Description:** The URL of the Reverb service. If `reverb.domain` is set, returns the custom domain URL. Otherwise, returns the auto-generated load balancer URL.
|
|
555
|
+
|
|
556
|
+
**Example:**
|
|
557
|
+
```typescript
|
|
558
|
+
const app = new LaravelService("MyApp", { ... });
|
|
559
|
+
console.log(app.reverbUrl); // https://ws.example.com or https://xyz.elb.amazonaws.com
|
|
560
|
+
```
|
|
561
|
+
|
|
452
562
|
## Complete Example
|
|
453
563
|
|
|
454
564
|
```typescript
|
|
@@ -477,6 +587,14 @@ const app = new LaravelService("MyApp", {
|
|
|
477
587
|
max: 10
|
|
478
588
|
}
|
|
479
589
|
},
|
|
590
|
+
|
|
591
|
+
reverb: {
|
|
592
|
+
domain: "ws.example.com",
|
|
593
|
+
scaling: {
|
|
594
|
+
min: 1,
|
|
595
|
+
max: 2
|
|
596
|
+
}
|
|
597
|
+
},
|
|
480
598
|
|
|
481
599
|
workers: [
|
|
482
600
|
{
|
|
@@ -510,7 +628,8 @@ const app = new LaravelService("MyApp", {
|
|
|
510
628
|
});
|
|
511
629
|
|
|
512
630
|
return {
|
|
513
|
-
url: app.url
|
|
631
|
+
url: app.url,
|
|
632
|
+
reverbUrl: app.reverbUrl
|
|
514
633
|
};
|
|
515
634
|
```
|
|
516
635
|
|
|
@@ -537,6 +656,10 @@ const app = new LaravelService("MyApp", {
|
|
|
537
656
|
max: 10
|
|
538
657
|
}
|
|
539
658
|
},
|
|
659
|
+
|
|
660
|
+
reverb: {
|
|
661
|
+
domain: "ws.example.com"
|
|
662
|
+
},
|
|
540
663
|
|
|
541
664
|
workers: [
|
|
542
665
|
{
|
|
@@ -565,6 +688,7 @@ const app = new LaravelService("MyApp", {
|
|
|
565
688
|
|
|
566
689
|
return {
|
|
567
690
|
url: app.url,
|
|
691
|
+
reverbUrl: app.reverbUrl,
|
|
568
692
|
secretsPath: env.path
|
|
569
693
|
};
|
|
570
694
|
```
|
package/laravel-sst.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { RemoteEnvVault, RemoteEnvVaultArgs } from './src/laravel-env-manager';
|
|
26
26
|
import { getPackagePath } from './src/config';
|
|
27
27
|
import { RemoteEnvFile } from './src/remote-env-file';
|
|
28
|
+
import { buildReverbEnvironmentVariables } from './src/reverb';
|
|
28
29
|
import { getSecretsFingerprint } from './src/secrets-manager';
|
|
29
30
|
|
|
30
31
|
// Re-export RemoteEnvVault for external use
|
|
@@ -44,6 +45,50 @@ enum ImageType {
|
|
|
44
45
|
Cli = 'cli',
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
export type LaravelDomain = Input<
|
|
49
|
+
| string
|
|
50
|
+
| {
|
|
51
|
+
/**
|
|
52
|
+
* Domain name. You are able to use variables from the SST config file here.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```js
|
|
56
|
+
* domain: {
|
|
57
|
+
* name: `${$app.stage}.example.com`,
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
name: Input<string>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Certificate ARN. Use this in case you are manually setting up the SSL certificate.
|
|
65
|
+
* This is usually needed when your DNS is not in the same AWS account or is outside of AWS.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```js
|
|
69
|
+
* domain: {
|
|
70
|
+
* cert: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
cert?: Input<string>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* SST DNS configuration. You can use this configuration if your DNS is in Cloudflare or another AWS account.
|
|
78
|
+
*
|
|
79
|
+
* @see https://sst.dev/docs/component/cloudflare/dns/
|
|
80
|
+
* @see https://sst.dev/docs/component/aws/dns/
|
|
81
|
+
* @example
|
|
82
|
+
* ```js
|
|
83
|
+
* domain: {
|
|
84
|
+
* dns: sst.cloudflare.dns(),
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
dns?: Input<false | (Dns & {})>;
|
|
89
|
+
}
|
|
90
|
+
>;
|
|
91
|
+
|
|
47
92
|
export interface LaravelServiceArgs {
|
|
48
93
|
architecture?: ServiceArgs['architecture'];
|
|
49
94
|
cpu?: ServiceArgs['cpu'];
|
|
@@ -91,49 +136,35 @@ export interface LaravelWebArgs extends LaravelServiceArgs {
|
|
|
91
136
|
/**
|
|
92
137
|
* Custom domain for the web layer. (if you don't provide a domain name, you will be able to use the load balancer domain for testing (http only))
|
|
93
138
|
*/
|
|
94
|
-
domain?:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* SST DNS configuration. You can use this configuration if your DNS is in Cloudflare or another AWS account.
|
|
124
|
-
*
|
|
125
|
-
* @see https://sst.dev/docs/component/cloudflare/dns/
|
|
126
|
-
* @see https://sst.dev/docs/component/aws/dns/
|
|
127
|
-
* @example
|
|
128
|
-
* ```js
|
|
129
|
-
* domain: {
|
|
130
|
-
* dns: sst.cloudflare.dns(),
|
|
131
|
-
* }
|
|
132
|
-
* ```
|
|
133
|
-
*/
|
|
134
|
-
dns?: Input<false | (Dns & {})>;
|
|
135
|
-
}
|
|
136
|
-
>;
|
|
139
|
+
domain?: LaravelDomain;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface LaravelReverbArgs extends LaravelServiceArgs {
|
|
143
|
+
/**
|
|
144
|
+
* Custom domain for the Reverb service. When provided, Reverb requests are routed over HTTPS to the Reverb server running on port 8080 by default.
|
|
145
|
+
*/
|
|
146
|
+
domain?: LaravelDomain;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Host the Reverb server listens on inside the container.
|
|
150
|
+
*
|
|
151
|
+
* @default `0.0.0.0`
|
|
152
|
+
*/
|
|
153
|
+
host?: string;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Port the Reverb server listens on inside the container.
|
|
157
|
+
*
|
|
158
|
+
* @default `8080`
|
|
159
|
+
*/
|
|
160
|
+
port?: number;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Command used to start Reverb.
|
|
164
|
+
*
|
|
165
|
+
* @default `php artisan reverb:start`
|
|
166
|
+
*/
|
|
167
|
+
command?: string;
|
|
137
168
|
}
|
|
138
169
|
|
|
139
170
|
export interface LaravelWorkerConfig extends LaravelServiceArgs {
|
|
@@ -185,6 +216,11 @@ export interface LaravelArgs extends ClusterArgs {
|
|
|
185
216
|
*/
|
|
186
217
|
workers?: LaravelWorkerConfig[];
|
|
187
218
|
|
|
219
|
+
/**
|
|
220
|
+
* If enabled, a public worker-style container will be created to run Laravel Reverb.
|
|
221
|
+
*/
|
|
222
|
+
reverb?: boolean | LaravelReverbArgs;
|
|
223
|
+
|
|
188
224
|
/**
|
|
189
225
|
* Config settings.
|
|
190
226
|
*/
|
|
@@ -292,6 +328,7 @@ export class LaravelService extends Component {
|
|
|
292
328
|
const sitePath = args.path ?? '.';
|
|
293
329
|
const absSitePath = path.resolve(sitePath.toString());
|
|
294
330
|
const nodeModulePath = getPackagePath();
|
|
331
|
+
const reverbConfig = normalizeReverbConfig(args.reverb);
|
|
295
332
|
|
|
296
333
|
// Determine the path where our plugin will save build files.
|
|
297
334
|
// SST sets __dirname to the .sst/platform directory.
|
|
@@ -375,7 +412,9 @@ export class LaravelService extends Component {
|
|
|
375
412
|
? args.web.loadBalancer
|
|
376
413
|
: {
|
|
377
414
|
domain: args.web?.domain,
|
|
378
|
-
ports: getDefaultPublicPorts(
|
|
415
|
+
ports: getDefaultPublicPorts(
|
|
416
|
+
args.web?.domain,
|
|
417
|
+
),
|
|
379
418
|
},
|
|
380
419
|
|
|
381
420
|
dev: {
|
|
@@ -472,6 +511,8 @@ export class LaravelService extends Component {
|
|
|
472
511
|
workerConfig: LaravelWorkerConfig,
|
|
473
512
|
serviceName: string,
|
|
474
513
|
workerBuildPath: string,
|
|
514
|
+
serviceKey = serviceName,
|
|
515
|
+
devCommand = `php ${sitePath}/artisan horizon`,
|
|
475
516
|
) => {
|
|
476
517
|
createWorkerTasks(workerConfig, workerBuildPath);
|
|
477
518
|
|
|
@@ -482,7 +523,7 @@ export class LaravelService extends Component {
|
|
|
482
523
|
CUSTOM_CONF_PATH: workerBuildPath.replace(absSitePath, ''),
|
|
483
524
|
};
|
|
484
525
|
|
|
485
|
-
this.services[
|
|
526
|
+
this.services[serviceKey] = new sst.aws.Service(
|
|
486
527
|
serviceName,
|
|
487
528
|
{
|
|
488
529
|
cluster,
|
|
@@ -492,9 +533,10 @@ export class LaravelService extends Component {
|
|
|
492
533
|
image: getImage(ImageType.Worker, imgBuildArgs),
|
|
493
534
|
scaling: workerConfig.scaling,
|
|
494
535
|
environment: getEnvironmentVariables(),
|
|
536
|
+
loadBalancer: workerConfig.loadBalancer,
|
|
495
537
|
|
|
496
538
|
dev: {
|
|
497
|
-
command:
|
|
539
|
+
command: devCommand,
|
|
498
540
|
},
|
|
499
541
|
|
|
500
542
|
transform: {
|
|
@@ -524,6 +566,44 @@ export class LaravelService extends Component {
|
|
|
524
566
|
);
|
|
525
567
|
};
|
|
526
568
|
|
|
569
|
+
function addReverbService() {
|
|
570
|
+
if (!reverbConfig) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const reverbPort: Port = `${reverbConfig.port}/http`;
|
|
575
|
+
const reverbWorkerConfig: LaravelWorkerConfig = {
|
|
576
|
+
...reverbConfig,
|
|
577
|
+
name: 'reverb',
|
|
578
|
+
loadBalancer: reverbConfig.loadBalancer ?? {
|
|
579
|
+
domain: reverbConfig.domain,
|
|
580
|
+
ports: getDefaultPublicPorts(
|
|
581
|
+
reverbConfig.domain,
|
|
582
|
+
reverbConfig.port,
|
|
583
|
+
),
|
|
584
|
+
health: {
|
|
585
|
+
[reverbPort]: {
|
|
586
|
+
path: '/apps',
|
|
587
|
+
successCodes: '200-499',
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
tasks: {
|
|
592
|
+
'laravel-reverb': {
|
|
593
|
+
command: reverbConfig.command,
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
createWorkerService(
|
|
599
|
+
reverbWorkerConfig,
|
|
600
|
+
`${name}-Reverb`,
|
|
601
|
+
path.resolve(pluginBuildPath, 'worker-reverb'),
|
|
602
|
+
'reverb',
|
|
603
|
+
`php ${sitePath}/artisan reverb:start`,
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
|
|
527
607
|
function addWorkerServices() {
|
|
528
608
|
args.workers?.forEach((workerConfig, index) => {
|
|
529
609
|
const workerName = workerConfig.name || `worker-${index + 1}`;
|
|
@@ -548,6 +628,10 @@ export class LaravelService extends Component {
|
|
|
548
628
|
addWorkerServices();
|
|
549
629
|
}
|
|
550
630
|
|
|
631
|
+
if (reverbConfig) {
|
|
632
|
+
addReverbService();
|
|
633
|
+
}
|
|
634
|
+
|
|
551
635
|
function normalizeClusterVpc(
|
|
552
636
|
vpc: LaravelArgs['vpc'],
|
|
553
637
|
): LaravelArgs['vpc'] {
|
|
@@ -576,13 +660,16 @@ export class LaravelService extends Component {
|
|
|
576
660
|
};
|
|
577
661
|
}
|
|
578
662
|
|
|
579
|
-
function getDefaultPublicPorts(
|
|
663
|
+
function getDefaultPublicPorts(
|
|
664
|
+
domain?: LaravelDomain,
|
|
665
|
+
forwardPortNumber = 8080,
|
|
666
|
+
): Ports {
|
|
580
667
|
let ports;
|
|
581
|
-
const forwardPort: Port =
|
|
668
|
+
const forwardPort: Port = `${forwardPortNumber}/http`;
|
|
582
669
|
const portHttp: Port = '80/http';
|
|
583
670
|
const portHttps: Port = '443/https';
|
|
584
671
|
|
|
585
|
-
if (
|
|
672
|
+
if (domain) {
|
|
586
673
|
ports = [
|
|
587
674
|
{ listen: portHttp, forward: forwardPort },
|
|
588
675
|
{ listen: portHttps, forward: forwardPort },
|
|
@@ -671,7 +758,12 @@ export class LaravelService extends Component {
|
|
|
671
758
|
function getEnvironmentVariables() {
|
|
672
759
|
const env = args.config?.environment?.vars || {};
|
|
673
760
|
|
|
674
|
-
return
|
|
761
|
+
return {
|
|
762
|
+
...(shouldAutoInjectEnvironment()
|
|
763
|
+
? getReverbEnvironmentVariables()
|
|
764
|
+
: {}),
|
|
765
|
+
...env,
|
|
766
|
+
};
|
|
675
767
|
}
|
|
676
768
|
|
|
677
769
|
function getLinkedEnvironmentData() {
|
|
@@ -712,6 +804,7 @@ export class LaravelService extends Component {
|
|
|
712
804
|
linkedEnvironment: {
|
|
713
805
|
...applyLinkedResourcesEnv(resources),
|
|
714
806
|
...customEnv,
|
|
807
|
+
...getReverbEnvironmentVariables(),
|
|
715
808
|
},
|
|
716
809
|
linkedSecrets: extractSecrets(resources).map((secret) => ({
|
|
717
810
|
name: secret.name,
|
|
@@ -861,6 +954,82 @@ export class LaravelService extends Component {
|
|
|
861
954
|
return undefined;
|
|
862
955
|
}
|
|
863
956
|
|
|
957
|
+
function getReverbEnvironmentVariables() {
|
|
958
|
+
if (!reverbConfig) {
|
|
959
|
+
return {};
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
const publicHost = getDomainName(reverbConfig.domain);
|
|
963
|
+
const serverVariables = buildReverbEnvironmentVariables({
|
|
964
|
+
serverHost: reverbConfig.host,
|
|
965
|
+
serverPort: reverbConfig.port,
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
if (!publicHost) {
|
|
969
|
+
return serverVariables;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
if (typeof publicHost === 'string') {
|
|
973
|
+
return buildReverbEnvironmentVariables({
|
|
974
|
+
publicHost,
|
|
975
|
+
serverHost: reverbConfig.host,
|
|
976
|
+
serverPort: reverbConfig.port,
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
return {
|
|
981
|
+
...serverVariables,
|
|
982
|
+
REVERB_HOST: publicHost,
|
|
983
|
+
REVERB_PORT: '443',
|
|
984
|
+
REVERB_SCHEME: 'https',
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
function shouldAutoInjectEnvironment(): boolean {
|
|
989
|
+
return args.config?.environment?.autoInject !== false;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function getDomainName(
|
|
993
|
+
domain?: LaravelDomain,
|
|
994
|
+
): PulumiInput<string | undefined> | undefined {
|
|
995
|
+
if (!domain) {
|
|
996
|
+
return undefined;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (typeof domain === 'string') {
|
|
1000
|
+
return domain;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
if (typeof domain === 'object' && 'name' in domain) {
|
|
1004
|
+
return output((domain as { name: Input<string> }).name).apply(
|
|
1005
|
+
(domainName) => domainName || undefined,
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
return undefined;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
function normalizeReverbConfig(
|
|
1013
|
+
config?: boolean | LaravelReverbArgs,
|
|
1014
|
+
): (LaravelReverbArgs & {
|
|
1015
|
+
command: string;
|
|
1016
|
+
host: string;
|
|
1017
|
+
port: number;
|
|
1018
|
+
}) | undefined {
|
|
1019
|
+
if (!config) {
|
|
1020
|
+
return undefined;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
const reverb = typeof config === 'boolean' ? {} : config;
|
|
1024
|
+
|
|
1025
|
+
return {
|
|
1026
|
+
...reverb,
|
|
1027
|
+
command: reverb.command ?? 'php artisan reverb:start',
|
|
1028
|
+
host: reverb.host ?? '0.0.0.0',
|
|
1029
|
+
port: reverb.port ?? 8080,
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
864
1033
|
function prepareDeploymentScript() {
|
|
865
1034
|
const deployDir = path.resolve(pluginBuildPath, 'deploy');
|
|
866
1035
|
const dst = path.resolve(deployDir, '60-deploy.sh');
|
|
@@ -896,6 +1065,16 @@ export class LaravelService extends Component {
|
|
|
896
1065
|
return this.services['web'].url;
|
|
897
1066
|
}
|
|
898
1067
|
|
|
1068
|
+
/**
|
|
1069
|
+
* The URL of the Reverb service.
|
|
1070
|
+
*
|
|
1071
|
+
* If `reverb.domain` is set, this is the URL with the custom domain.
|
|
1072
|
+
* Otherwise, it's the auto-generated load balancer URL.
|
|
1073
|
+
*/
|
|
1074
|
+
public get reverbUrl() {
|
|
1075
|
+
return this.services['reverb'].url;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
899
1078
|
/**
|
|
900
1079
|
* The messages from the service.
|
|
901
1080
|
*
|
package/package.json
CHANGED
package/src/reverb.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ReverbEnvironmentOptions {
|
|
2
|
+
serverHost?: string;
|
|
3
|
+
serverPort?: number;
|
|
4
|
+
publicHost?: string;
|
|
5
|
+
publicPort?: number;
|
|
6
|
+
publicScheme?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function buildReverbEnvironmentVariables(
|
|
10
|
+
options: ReverbEnvironmentOptions = {},
|
|
11
|
+
): Record<string, string> {
|
|
12
|
+
const vars: Record<string, string> = {
|
|
13
|
+
REVERB_SERVER_HOST: options.serverHost ?? '0.0.0.0',
|
|
14
|
+
REVERB_SERVER_PORT: (options.serverPort ?? 8080).toString(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (!options.publicHost) {
|
|
18
|
+
return vars;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
vars.REVERB_HOST = options.publicHost;
|
|
22
|
+
vars.REVERB_PORT = (options.publicPort ?? 443).toString();
|
|
23
|
+
vars.REVERB_SCHEME = options.publicScheme ?? 'https';
|
|
24
|
+
|
|
25
|
+
return vars;
|
|
26
|
+
}
|
|
@@ -46,6 +46,15 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
|
|
49
|
+
// this configuration will create a dedicated Reverb container for WebSocket traffic
|
|
50
|
+
// reverb: {
|
|
51
|
+
// domain: {
|
|
52
|
+
// name: $app.stage === "production"
|
|
53
|
+
// ? "ws.example.com"
|
|
54
|
+
// : `ws.${$app.stage}.example.com`,
|
|
55
|
+
// },
|
|
56
|
+
// },
|
|
57
|
+
|
|
49
58
|
// this configuration will create one worker container, which will run horizon and the laravel scheduler as background jobs
|
|
50
59
|
workers: [
|
|
51
60
|
{
|
|
@@ -57,4 +66,5 @@
|
|
|
57
66
|
|
|
58
67
|
return {
|
|
59
68
|
url: app.url,
|
|
69
|
+
// reverbUrl: app.reverbUrl,
|
|
60
70
|
};
|