@alzulejos/laranja-docs 0.2.4
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/content/getting-started/how-it-works.md +52 -0
- package/content/getting-started/installation.md +58 -0
- package/content/getting-started/introduction.md +97 -0
- package/content/getting-started/quickstart.md +164 -0
- package/content/guides/cron-jobs.md +129 -0
- package/content/guides/environment-variables.md +108 -0
- package/content/guides/http-apps.md +131 -0
- package/content/guides/queues.md +143 -0
- package/content/guides/schedules.md +117 -0
- package/content/guides/stages-and-environments.md +88 -0
- package/content/index.md +44 -0
- package/content/reference/commands.md +193 -0
- package/content/reference/config-file.md +114 -0
- package/content/reference/decorators-and-markers.md +310 -0
- package/content/reference/what-gets-deployed.md +84 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +38 -0
- package/package.json +30 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: HTTP apps
|
|
3
|
+
description: Deploy your HTTP app behind a public HTTPS endpoint.
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# HTTP apps
|
|
8
|
+
|
|
9
|
+
laranja deploys your whole HTTP app as a single proxy Lambda behind a public
|
|
10
|
+
[Function URL](../reference/what-gets-deployed.md#http-app--proxy-lambda--function-url).
|
|
11
|
+
laranja supports **Express** and **NestJS**.
|
|
12
|
+
|
|
13
|
+
## Declaring your app (the `http()` marker)
|
|
14
|
+
|
|
15
|
+
The code-first way: mark your app with the
|
|
16
|
+
[`http()`](../reference/decorators-and-markers.md#http) marker and export it.
|
|
17
|
+
laranja finds it by scanning your code — there's nothing to configure.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// src/app.ts
|
|
21
|
+
import express from "express";
|
|
22
|
+
import { http } from "@alzulejos/laranja-decorators";
|
|
23
|
+
|
|
24
|
+
const app = express();
|
|
25
|
+
app.use(express.json());
|
|
26
|
+
|
|
27
|
+
app.get("/", (_req, res) => res.json({ ok: true }));
|
|
28
|
+
app.post("/users", (req, res) => res.status(201).json(req.body));
|
|
29
|
+
|
|
30
|
+
export default http(app); // or: export const api = http(app);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`http()` returns the app untouched — it's a static marker, not a wrapper, so it
|
|
34
|
+
has no runtime effect. That's all you need: every route you register is served by
|
|
35
|
+
the deployed proxy. The marker is the only way to declare an HTTP app — there's
|
|
36
|
+
exactly one per project, and it must be exported so the scanner can find it.
|
|
37
|
+
|
|
38
|
+
## NestJS
|
|
39
|
+
|
|
40
|
+
Nest apps work the same way, with one difference: a Nest app only exists after an
|
|
41
|
+
async `NestFactory.create(...)`, so instead of a ready app object you wrap your
|
|
42
|
+
**bootstrap function** and have it `return` the app:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// src/main.ts
|
|
46
|
+
import { NestFactory } from "@nestjs/core";
|
|
47
|
+
import { http } from "@alzulejos/laranja-decorators";
|
|
48
|
+
import { AppModule } from "./app.module";
|
|
49
|
+
|
|
50
|
+
export async function bootstrap() {
|
|
51
|
+
const app = await NestFactory.create(AppModule);
|
|
52
|
+
// configure however you like — pipes, guards, middleware, raw body, cookies…
|
|
53
|
+
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
|
|
54
|
+
await app.listen(process.env.PORT ?? 3000); // fine to keep for local dev
|
|
55
|
+
return app; // ← the only change laranja needs
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Run locally with `npm run start`; skipped when laranja imports this file.
|
|
59
|
+
if (require.main === module) void bootstrap();
|
|
60
|
+
|
|
61
|
+
export default http(bootstrap); // wrap the factory, not a module
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
laranja runs your `bootstrap()` verbatim, so every pipe, guard, and piece of
|
|
65
|
+
middleware you configure is preserved — nothing is re-derived. You keep your
|
|
66
|
+
normal Nest project (`@nestjs/platform-express`); no laranja-specific
|
|
67
|
+
restructuring.
|
|
68
|
+
|
|
69
|
+
Two things to know:
|
|
70
|
+
|
|
71
|
+
- **Build before you deploy.** laranja packages your compiled output (`nest build`
|
|
72
|
+
→ `dist/`), because Nest's dependency injection relies on the decorator metadata
|
|
73
|
+
your own TypeScript build emits. laranja deploys what you build — it doesn't run
|
|
74
|
+
your build for you — so run `nest build` yourself after every code change.
|
|
75
|
+
Deploying without a `dist/` fails with a clear message, but a **stale** `dist/`
|
|
76
|
+
(source edited since your last build) deploys silently as outdated code, so make
|
|
77
|
+
the build part of your deploy step (e.g. `nest build && laranja deploy`).
|
|
78
|
+
- **Use the default Express platform.** The Fastify adapter isn't supported yet.
|
|
79
|
+
|
|
80
|
+
## Routing, middleware, and `STAGE`
|
|
81
|
+
|
|
82
|
+
Your app runs as-is inside Lambda. Standard Express features work — routing,
|
|
83
|
+
middleware, JSON bodies, route params. The active
|
|
84
|
+
[stage](./stages-and-environments.md) is available as
|
|
85
|
+
`process.env.STAGE`:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
app.get("/whoami", (_req, res) => res.json({ stage: process.env.STAGE }));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## CORS and auth
|
|
92
|
+
|
|
93
|
+
The Function URL is public with permissive CORS (all origins/methods/headers).
|
|
94
|
+
Handle authentication and any stricter CORS rules **inside your app**, the same
|
|
95
|
+
way you would anywhere else.
|
|
96
|
+
|
|
97
|
+
## Compute (memory & timeout)
|
|
98
|
+
|
|
99
|
+
The HTTP proxy Lambda's memory and timeout come from
|
|
100
|
+
[`compute`](../reference/config-file.md#compute) in your config — the scaffold
|
|
101
|
+
default is `{ memory: 256, timeout: 30 }`, and you can override it under the `http`
|
|
102
|
+
key in [`resources`](../reference/config-file.md#resources). Long-running work
|
|
103
|
+
belongs in a [cron job](./cron-jobs.md) or behind a [queue](./queues.md), not a
|
|
104
|
+
request.
|
|
105
|
+
|
|
106
|
+
## Workers-only deployments
|
|
107
|
+
|
|
108
|
+
If your HTTP API is hosted elsewhere and you only want to deploy scheduled jobs
|
|
109
|
+
and queue consumers, just don't add an `http()` marker — there's nothing to set
|
|
110
|
+
in config:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// laranja.config.ts
|
|
114
|
+
const config: LaranjaConfig = {
|
|
115
|
+
name: "my-workers",
|
|
116
|
+
env: { LOG_LEVEL: "info" },
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
With no marker, only your [`@Cron`](./cron-jobs.md) / [`@Queue`](./queues.md)
|
|
121
|
+
handlers are deployed — no HTTP proxy, no Function URL.
|
|
122
|
+
|
|
123
|
+
For a **workers-only Nest** app, there's no `http(bootstrap)` to build the DI
|
|
124
|
+
container from, so declare your module with the
|
|
125
|
+
[`workers()`](../reference/decorators-and-markers.md#workers) marker instead
|
|
126
|
+
(`export default workers(AppModule)`) — see [Cron jobs → NestJS](./cron-jobs.md#nestjs).
|
|
127
|
+
|
|
128
|
+
## Related
|
|
129
|
+
|
|
130
|
+
- [What gets deployed](../reference/what-gets-deployed.md)
|
|
131
|
+
- [Cron jobs](./cron-jobs.md) · [Queues](./queues.md)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Queues
|
|
3
|
+
description: Process SQS messages with @Queue or queue(), including FIFO.
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Queues
|
|
8
|
+
|
|
9
|
+
A queue consumer processes messages from an SQS queue. Each one becomes
|
|
10
|
+
[an SQS queue plus a consumer Lambda](../reference/what-gets-deployed.md#queue--sqs-queue--consumer-lambda).
|
|
11
|
+
|
|
12
|
+
## Class style — `@Queue`
|
|
13
|
+
|
|
14
|
+
Decorate a method with [`@Queue`](../reference/decorators-and-markers.md#queue):
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Queue } from "@alzulejos/laranja-decorators";
|
|
18
|
+
|
|
19
|
+
export class Workers {
|
|
20
|
+
@Queue({ name: "emails", batchSize: 10 })
|
|
21
|
+
async sendEmail(body: unknown) {
|
|
22
|
+
// `body` is the JSON-parsed message
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Function style — `queue()`
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { queue } from "@alzulejos/laranja-decorators";
|
|
31
|
+
|
|
32
|
+
export async function sendEmail(body: unknown) {
|
|
33
|
+
// …
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
queue({ name: "emails", batchSize: 10 }, sendEmail);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## NestJS
|
|
40
|
+
|
|
41
|
+
`@Queue` works on a Nest provider with injected dependencies. As with
|
|
42
|
+
[cron jobs](./cron-jobs.md#nestjs), laranja resolves the consumer through your
|
|
43
|
+
DI container, so declare your module once with the
|
|
44
|
+
[`workers()`](../reference/decorators-and-markers.md#workers) marker
|
|
45
|
+
(`export default workers(AppModule)`) and deploy your compiled `dist/` output.
|
|
46
|
+
Standalone `queue()` functions don't need it.
|
|
47
|
+
|
|
48
|
+
## Options
|
|
49
|
+
|
|
50
|
+
| Option | Default | Description |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `name` | _required_ | Queue name. A `.fifo` suffix marks a FIFO queue. |
|
|
53
|
+
| `batchSize` | `10` | Max messages delivered to the consumer per invocation. |
|
|
54
|
+
| `fifo` | `false` | Force a FIFO queue (or end `name` with `.fifo`). When set, laranja appends `.fifo` to `name` if you left it off. |
|
|
55
|
+
|
|
56
|
+
## How messages are delivered
|
|
57
|
+
|
|
58
|
+
- Your handler is invoked **once per message**, with the message **body already
|
|
59
|
+
JSON-parsed**.
|
|
60
|
+
- **Partial-batch failures** are enabled: if your handler throws for one message,
|
|
61
|
+
only that message is retried — the rest of the batch is still acknowledged.
|
|
62
|
+
- Consumer memory/timeout come from [`compute`](../reference/config-file.md#compute)
|
|
63
|
+
(default `{ memory: 256, timeout: 30 }`); the queue's visibility timeout is
|
|
64
|
+
derived to stay ≥ the consumer timeout (override it per queue via
|
|
65
|
+
[`resources`](../reference/config-file.md#resources)).
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
@Queue({ name: "orders" })
|
|
69
|
+
async processOrder(body: unknown) {
|
|
70
|
+
const order = body as { id: string };
|
|
71
|
+
if (!order.id) throw new Error("bad message"); // only THIS message is retried
|
|
72
|
+
// …
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## FIFO queues
|
|
77
|
+
|
|
78
|
+
End the name with `.fifo` (or set `fifo: true`) for ordered, exactly-once
|
|
79
|
+
processing. Content-based deduplication is enabled automatically:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
@Queue({ name: "orders.fifo", fifo: true })
|
|
83
|
+
async processOrder(body: unknown) {
|
|
84
|
+
// …
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
AWS requires FIFO queue names to end in `.fifo`. If you set `fifo: true` but
|
|
89
|
+
leave the suffix off, laranja appends it for you — so `{ name: "orders", fifo: true }`
|
|
90
|
+
deploys a queue named `orders.fifo`. The normalized name is what appears in
|
|
91
|
+
`laranja plan` and in the AWS console, so there's no surprise at deploy time.
|
|
92
|
+
|
|
93
|
+
## Sending messages
|
|
94
|
+
|
|
95
|
+
Consuming is only half the loop — to **produce** a message, call
|
|
96
|
+
[`getQueue`](../reference/decorators-and-markers.md#getqueue) with the queue's
|
|
97
|
+
`name` and `.send()` a payload:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { getQueue } from "@alzulejos/laranja-decorators";
|
|
101
|
+
|
|
102
|
+
app.post("/signup", async (req, res) => {
|
|
103
|
+
await getQueue("emails").send({ to: req.body.email, template: "welcome" });
|
|
104
|
+
res.sendStatus(202);
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Objects are JSON-serialized for you (strings are sent as-is), so the consumer
|
|
109
|
+
receives them already parsed — `getQueue("emails").send({ to })` on one end,
|
|
110
|
+
`async sendEmail(body)` on the other.
|
|
111
|
+
|
|
112
|
+
You can produce from **anywhere** in a deployed app — an HTTP route, a
|
|
113
|
+
[cron job](./cron-jobs.md), or another queue's consumer fanning out. laranja
|
|
114
|
+
injects each queue's URL into every function's environment at deploy and grants
|
|
115
|
+
`sqs:SendMessage`, so there's no client to configure, no URL to look up, and no
|
|
116
|
+
IAM to wire. It's a thin wrapper over one SQS `SendMessage` call — laranja
|
|
117
|
+
provisions the infrastructure; it deliberately does **not** add a job framework
|
|
118
|
+
(retries, scheduling, and job state stay with SQS and your consumer).
|
|
119
|
+
|
|
120
|
+
### FIFO and options
|
|
121
|
+
|
|
122
|
+
`.send()` takes a second options argument:
|
|
123
|
+
|
|
124
|
+
| Option | Applies to | Description |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `groupId` | FIFO (**required**) | `MessageGroupId` — messages with the same group are ordered. |
|
|
127
|
+
| `dedupId` | FIFO | `MessageDeduplicationId` — only needed when content-based dedup is off. |
|
|
128
|
+
| `delaySeconds` | Standard | Delay (0–900s) before the message becomes visible. Ignored by FIFO. |
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
// FIFO queues require a groupId — the send throws without one.
|
|
132
|
+
await getQueue("orders.fifo").send(order, { groupId: order.customerId });
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
> Prefer the raw SDK? The queue URL is also emitted as a stack output after
|
|
136
|
+
> deploy and visible in the AWS console — send with `@aws-sdk/client-sqs`
|
|
137
|
+
> directly if you'd rather.
|
|
138
|
+
|
|
139
|
+
## Related
|
|
140
|
+
|
|
141
|
+
- [`@Queue` / `queue()` reference](../reference/decorators-and-markers.md#queue)
|
|
142
|
+
- [What gets deployed](../reference/what-gets-deployed.md#queue--sqs-queue--consumer-lambda)
|
|
143
|
+
- [Cron jobs](./cron-jobs.md)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Schedules
|
|
3
|
+
description: The rate() and every() builders, and raw schedule expressions.
|
|
4
|
+
order: 4
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Schedules
|
|
8
|
+
|
|
9
|
+
Schedules drive [cron jobs](./cron-jobs.md). laranja stores them in a
|
|
10
|
+
**provider-neutral** form, so prefer the builders — they're portable across
|
|
11
|
+
clouds. A raw expression string is available as an escape hatch.
|
|
12
|
+
|
|
13
|
+
## `rate(value, unit)`
|
|
14
|
+
|
|
15
|
+
"Every N units." Portable everywhere.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { rate } from "@alzulejos/laranja-decorators";
|
|
19
|
+
|
|
20
|
+
rate(5, "minutes") // every 5 minutes
|
|
21
|
+
rate(1, "hour") // every hour
|
|
22
|
+
rate(2, "days") // every 2 days
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- `value` must be a **positive integer** (≥ 1).
|
|
26
|
+
- `unit` is one of `"minute"`, `"minutes"`, `"hour"`, `"hours"`, `"day"`,
|
|
27
|
+
`"days"` — singular or plural, your choice.
|
|
28
|
+
|
|
29
|
+
## `every(unit)`
|
|
30
|
+
|
|
31
|
+
Shorthand for `rate(1, unit)`. Takes a singular unit:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { every } from "@alzulejos/laranja-decorators";
|
|
35
|
+
|
|
36
|
+
every("minute") // = rate(1, "minute")
|
|
37
|
+
every("hour") // = rate(1, "hour")
|
|
38
|
+
every("day") // = rate(1, "day")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Raw AWS expressions (escape hatch)
|
|
42
|
+
|
|
43
|
+
When you need something the builders can't express (e.g. "noon UTC every day"),
|
|
44
|
+
pass a **wrapped** AWS schedule string — `cron(...)` or `rate(...)`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
@Cron({ schedule: "cron(0 12 * * ? *)", id: "daily-report" }) // 12:00 UTC daily
|
|
48
|
+
@Cron("rate(5 minutes)") // raw rate string
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
AWS cron has **six fields**: `cron(Minutes Hours Day-of-month Month Day-of-week
|
|
52
|
+
Year)`.
|
|
53
|
+
|
|
54
|
+
A few examples:
|
|
55
|
+
|
|
56
|
+
| Expression | Meaning |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `cron(0 12 * * ? *)` | 12:00 UTC every day |
|
|
59
|
+
| `cron(0/15 * * * ? *)` | every 15 minutes |
|
|
60
|
+
| `cron(0 8 ? * MON-FRI *)` | 08:00 UTC on weekdays |
|
|
61
|
+
| `cron(0 0 1 * ? *)` | midnight UTC on the 1st of each month |
|
|
62
|
+
|
|
63
|
+
## node-cron expressions (`@nestjs/schedule` compatibility)
|
|
64
|
+
|
|
65
|
+
A **bare** (unwrapped) string is read as a standard 5- or 6-field
|
|
66
|
+
[node-cron](https://github.com/kelektiv/node-cron) expression — the same syntax
|
|
67
|
+
`@nestjs/schedule`'s `@Cron` takes. laranja translates it to the AWS dialect for
|
|
68
|
+
you, so a Nest app can swap the import and keep its existing schedules:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
@Cron("0 12 * * *") // noon every day
|
|
72
|
+
@Cron("*/5 * * * *") // every 5 minutes
|
|
73
|
+
@Cron("0 0 * * 1-5") // midnight on weekdays
|
|
74
|
+
@Cron(CronExpression.EVERY_30_MINUTES) // the enum works too
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`CronExpression` (mirrored from `@nestjs/schedule`) is re-exported from
|
|
78
|
+
`@alzulejos/laranja-decorators`. Translation handles the day-of-week numbering difference
|
|
79
|
+
(Unix `0`=Sun → AWS `1`=Sun) and the day-of-month/day-of-week rule for you.
|
|
80
|
+
|
|
81
|
+
**What can't be translated is rejected at build time — never silently rounded:**
|
|
82
|
+
|
|
83
|
+
| Input | Why it's rejected |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `"*/30 * * * * *"`, `CronExpression.EVERY_30_SECONDS` | Sub-minute — EventBridge's floor is **1 minute**. |
|
|
86
|
+
| A seconds field other than `0` | Second-level offsets can't be expressed. |
|
|
87
|
+
| A cron constraining **both** day-of-month and day-of-week | EventBridge requires one to be `*`. |
|
|
88
|
+
|
|
89
|
+
## `@Interval(ms)`
|
|
90
|
+
|
|
91
|
+
`@nestjs/schedule`'s `@Interval` is supported and lowers to a `rate(...)`. The
|
|
92
|
+
interval must be a whole number of minutes (EventBridge's floor):
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
@Interval(300000) // every 5 minutes → rate(5, "minutes")
|
|
96
|
+
@Interval("poll", 300000) // named
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
> `@Timeout` (a one-shot timer relative to process start) has no serverless
|
|
100
|
+
> equivalent and is rejected with a clear message — use `@Cron` or `@Interval`.
|
|
101
|
+
|
|
102
|
+
## Where you can use them
|
|
103
|
+
|
|
104
|
+
Anywhere a schedule is expected — the decorator or the function marker — accepts
|
|
105
|
+
a builder result, a `Schedule` object, or a raw string:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
@Cron(rate(5, "minutes")) // builder
|
|
109
|
+
@Cron("rate(5 minutes)") // raw string
|
|
110
|
+
@Cron({ schedule: every("day"), id: "nightly" })// builder + explicit id
|
|
111
|
+
cron(rate(1, "hour"), refreshCache); // function marker
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Related
|
|
115
|
+
|
|
116
|
+
- [Cron jobs](./cron-jobs.md)
|
|
117
|
+
- [`@Cron` / `cron()` reference](../reference/decorators-and-markers.md#cron)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Stages & environments
|
|
3
|
+
description: Run dev, staging, and prod from one codebase with --stage.
|
|
4
|
+
order: 6
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Stages & environments
|
|
8
|
+
|
|
9
|
+
A **stage** is a named environment — `dev`, `staging`, `prod`, or anything you
|
|
10
|
+
like. laranja makes each stage a fully independent deployment from the same
|
|
11
|
+
codebase.
|
|
12
|
+
|
|
13
|
+
## Setting the stage
|
|
14
|
+
|
|
15
|
+
The default stage is `dev`. Set it in config:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// laranja.config.ts
|
|
19
|
+
const config: LaranjaConfig = { name: "my-api", stage: "dev" };
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
…or override it per command with `--stage` (alias `-s`):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
laranja deploy --stage prod
|
|
26
|
+
laranja deploy -s staging
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The flag wins over the config value, which is why the recommended setup keeps
|
|
30
|
+
`stage` at its default in config and lets each pipeline pass `--stage`.
|
|
31
|
+
|
|
32
|
+
`--stage` applies to every environment-aware command: `deploy`, `plan`,
|
|
33
|
+
`destroy`, `logs`, and `eject`.
|
|
34
|
+
|
|
35
|
+
## Each stage is its own stack
|
|
36
|
+
|
|
37
|
+
The stage is part of the **stack name** (`‹name›-‹stage›`) and every resource
|
|
38
|
+
name (`‹name›-‹fn›-‹stage›`). So `--stage dev` and `--stage prod` produce two
|
|
39
|
+
**independent CloudFormation stacks** that never collide — even in the same AWS
|
|
40
|
+
account.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
my-api-dev ← laranja deploy --stage dev
|
|
44
|
+
my-api-prod ← laranja deploy --stage prod
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Two ways to isolate environments
|
|
48
|
+
|
|
49
|
+
Both work, and they compose:
|
|
50
|
+
|
|
51
|
+
1. **One account, multiple stages.** The stage suffix keeps the stacks separate.
|
|
52
|
+
Good for small projects or non-prod environments.
|
|
53
|
+
2. **Separate accounts per stage.** Point each pipeline at different AWS
|
|
54
|
+
credentials (a dev account and a prod account). Here your **AWS credentials
|
|
55
|
+
are the real boundary**; the stack name can even repeat across accounts
|
|
56
|
+
without conflict.
|
|
57
|
+
|
|
58
|
+
## One pipeline per stage
|
|
59
|
+
|
|
60
|
+
The canonical CI/CD setup is one pipeline per environment, each running the same
|
|
61
|
+
command with a different flag:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
# dev pipeline → laranja deploy --stage dev
|
|
65
|
+
# staging pipeline → laranja deploy --stage staging
|
|
66
|
+
# prod pipeline → laranja deploy --stage prod
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Same repo, same command — only the flag differs. No per-environment config files
|
|
70
|
+
to keep in sync. Pair this with [per-stage env values](./environment-variables.md#per-stage-values)
|
|
71
|
+
to supply each environment's configuration.
|
|
72
|
+
|
|
73
|
+
> Consistency matters: a pipeline's `destroy`, `logs`, and `plan` must use the
|
|
74
|
+
> **same `--stage`** as its `deploy`, or they'll target a different stack.
|
|
75
|
+
|
|
76
|
+
## The `STAGE` env var
|
|
77
|
+
|
|
78
|
+
The active stage is injected into every Lambda as `process.env.STAGE`, so your
|
|
79
|
+
code can branch on it:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const isProd = process.env.STAGE === "prod";
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Related
|
|
86
|
+
|
|
87
|
+
- [Config file](../reference/config-file.md)
|
|
88
|
+
- [Environment variables](./environment-variables.md)
|
package/content/index.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Documentation
|
|
3
|
+
description: Code-first deploys for Node.js apps to your own AWS account.
|
|
4
|
+
order: 0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# laranja docs
|
|
8
|
+
|
|
9
|
+
**laranja** deploys your Node.js app to your own AWS account from your code — no
|
|
10
|
+
YAML, no console clicking, no separate infrastructure project. You write an
|
|
11
|
+
Express app plus a few functions or decorators; laranja reads the code, figures
|
|
12
|
+
out the infrastructure, and ships it.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -D @alzulejos/laranja
|
|
16
|
+
npx laranja deploy
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Start here
|
|
20
|
+
|
|
21
|
+
- **[Introduction](./getting-started/introduction.md)** — what laranja is and the ideas behind it.
|
|
22
|
+
- **[Installation](./getting-started/installation.md)** — prerequisites and setup.
|
|
23
|
+
- **[Quickstart](./getting-started/quickstart.md)** — from zero to a live URL.
|
|
24
|
+
- **[How it works](./getting-started/how-it-works.md)** — how your code becomes a running app on AWS.
|
|
25
|
+
|
|
26
|
+
## Guides
|
|
27
|
+
|
|
28
|
+
- **[HTTP apps](./guides/http-apps.md)** — deploy your app behind a public URL with the `http()` marker.
|
|
29
|
+
- **[Cron jobs](./guides/cron-jobs.md)** — scheduled functions with `@Cron` / `cron()`.
|
|
30
|
+
- **[Queues](./guides/queues.md)** — SQS consumers with `@Queue` / `queue()`.
|
|
31
|
+
- **[Schedules](./guides/schedules.md)** — the `rate()` / `every()` builders and raw expressions.
|
|
32
|
+
- **[Environment variables](./guides/environment-variables.md)** — `env`, `STAGE`, and resolution.
|
|
33
|
+
- **[Stages & environments](./guides/stages-and-environments.md)** — dev / staging / prod with one codebase.
|
|
34
|
+
|
|
35
|
+
## Reference
|
|
36
|
+
|
|
37
|
+
- **[CLI commands](./reference/commands.md)** — `init`, `logout`, `plan`, `deploy`, `destroy`, `logs`, `eject`.
|
|
38
|
+
- **[Config file](./reference/config-file.md)** — every field in `laranja.config.ts`.
|
|
39
|
+
- **[Decorators & markers](./reference/decorators-and-markers.md)** — `@Cron`, `@Queue`, `cron`, `queue`, `http`, `env`.
|
|
40
|
+
- **[What gets deployed](./reference/what-gets-deployed.md)** — the AWS resources and how they're named.
|
|
41
|
+
|
|
42
|
+
> **Status:** v1 targets **AWS** with **Express** today; **NestJS support is
|
|
43
|
+
> coming**. The internal model is provider- and framework-neutral, so new clouds
|
|
44
|
+
> and frameworks land without changing your app code.
|