@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,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: How it works
|
|
3
|
+
description: How laranja turns your code into a running app on AWS.
|
|
4
|
+
order: 4
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# How it works
|
|
8
|
+
|
|
9
|
+
You write your app; laranja deploys it to your own AWS account. Two things are
|
|
10
|
+
worth knowing about how it does that.
|
|
11
|
+
|
|
12
|
+
## It reads your code — it never runs it
|
|
13
|
+
|
|
14
|
+
laranja discovers your infrastructure by **reading** your source: your HTTP app
|
|
15
|
+
and its routes, your `@Cron` / `cron()` jobs and their schedules, your
|
|
16
|
+
`@Queue` / `queue()` consumers, and the env vars you wrap with `env()`. It does
|
|
17
|
+
this without executing your code, so planning a deploy is always safe — nothing
|
|
18
|
+
of yours runs just to figure out what to deploy.
|
|
19
|
+
|
|
20
|
+
That's also why a few things must be written so laranja can see them: schedules
|
|
21
|
+
use literal builders like `rate(5, "minutes")`, and `env("…")` takes a string
|
|
22
|
+
literal.
|
|
23
|
+
|
|
24
|
+
## It deploys into your AWS account
|
|
25
|
+
|
|
26
|
+
laranja turns what it found into AWS resources — a Lambda for your app, an
|
|
27
|
+
EventBridge rule per cron, an SQS queue per consumer — and deploys them with
|
|
28
|
+
**your** credentials into **your** account. See
|
|
29
|
+
[what gets deployed](../reference/what-gets-deployed.md) for the full mapping.
|
|
30
|
+
|
|
31
|
+
- The AWS CDK toolkit is embedded, so there's nothing extra to install.
|
|
32
|
+
- The first deploy to a new account/region runs a one-time **bootstrap**.
|
|
33
|
+
- [`plan`](../reference/commands.md#plan) previews what a deploy would change
|
|
34
|
+
(created/changed/unchanged); [`destroy`](../reference/commands.md#destroy)
|
|
35
|
+
tears the stack down.
|
|
36
|
+
- Outputs (your HTTPS URL, queue URLs) are printed when the deploy finishes.
|
|
37
|
+
|
|
38
|
+
## The template is built on the server — your code stays local
|
|
39
|
+
|
|
40
|
+
[`plan`](../reference/commands.md#plan) and [`deploy`](../reference/commands.md#deploy)
|
|
41
|
+
synthesize the deployment template on the **laranja server**. laranja scans and
|
|
42
|
+
bundles your code locally, then sends only a **description** of your
|
|
43
|
+
infrastructure (the internal model plus the asset hashes of your bundles) — your
|
|
44
|
+
source code and bundles never leave your machine. The returned template is then
|
|
45
|
+
applied to AWS with your **own** credentials. This is why these commands need a
|
|
46
|
+
`LARANJA_API_KEY` and a `projectId` (run [`laranja init`](../reference/commands.md#init)
|
|
47
|
+
once to set both up).
|
|
48
|
+
|
|
49
|
+
## Related
|
|
50
|
+
|
|
51
|
+
- [What gets deployed](../reference/what-gets-deployed.md)
|
|
52
|
+
- [Stages & environments](../guides/stages-and-environments.md)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: Prerequisites and how to add laranja to a project.
|
|
4
|
+
order: 2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Installation
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- **Node.js 20 or newer.** Deployed Lambdas run on the Node.js 20 runtime, and
|
|
12
|
+
the CLI targets the same.
|
|
13
|
+
- **A laranja account + API key.** laranja synthesizes your deployment template on
|
|
14
|
+
its server, so `plan`, `deploy`, and `eject` need an API key (created in the
|
|
15
|
+
dashboard) and a project to link to. You connect both by running
|
|
16
|
+
[`laranja init`](./quickstart.md#3-sign-in-and-configure) — see the Quickstart.
|
|
17
|
+
- **An AWS account** plus credentials on the standard AWS chain — any of:
|
|
18
|
+
- `aws configure` (a shared credentials file),
|
|
19
|
+
- AWS SSO (`aws sso login`),
|
|
20
|
+
- environment variables (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`),
|
|
21
|
+
- a named profile (set [`profile`](../reference/config-file.md) in config).
|
|
22
|
+
- **A region**, from `region` in your config or the `AWS_REGION` /
|
|
23
|
+
`AWS_DEFAULT_REGION` environment variable.
|
|
24
|
+
|
|
25
|
+
You do **not** need to install the AWS CDK or the AWS CLI separately — the CDK
|
|
26
|
+
toolkit is embedded in laranja.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Add the CLI as a dev dependency:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install -D @alzulejos/laranja
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If you use decorators or function markers for jobs and queues, also install:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @alzulejos/laranja-decorators
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> `@alzulejos/laranja-decorators` is a regular dependency (not dev-only) because your
|
|
43
|
+
> application imports `@Cron`, `@Queue`, `rate`, etc. at runtime.
|
|
44
|
+
|
|
45
|
+
## First-time AWS setup (bootstrap)
|
|
46
|
+
|
|
47
|
+
The first time you deploy to a given account + region, laranja runs a one-time
|
|
48
|
+
**bootstrap** that creates a small set of shared resources in _your_ account (an
|
|
49
|
+
S3 asset bucket and a few IAM roles). `laranja deploy` detects this and prompts
|
|
50
|
+
you before doing it — see [deploy](../reference/commands.md#deploy).
|
|
51
|
+
|
|
52
|
+
## Verify
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx laranja --help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
You're ready for the **[Quickstart](./quickstart.md)**.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Introduction
|
|
3
|
+
description: What laranja is, the problem it solves, and the principles behind it.
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Introduction
|
|
8
|
+
|
|
9
|
+
laranja is a **code-first deploy tool** for Node.js apps. You write your
|
|
10
|
+
application — an Express app, some scheduled jobs, some queue consumers — and
|
|
11
|
+
laranja deploys it to **your own AWS account**. There is no infrastructure
|
|
12
|
+
project to maintain, no YAML to write, and no cloud console to click through.
|
|
13
|
+
|
|
14
|
+
> laranja supports **Express** and **NestJS** — and because your app is reduced to
|
|
15
|
+
> a framework-neutral description internally, more frameworks can follow without
|
|
16
|
+
> changing how you write your code.
|
|
17
|
+
|
|
18
|
+
## The problem
|
|
19
|
+
|
|
20
|
+
Shipping a small Node service to AWS usually means choosing between:
|
|
21
|
+
|
|
22
|
+
- **A platform** (managed hosting) — fast, but you don't own the infrastructure
|
|
23
|
+
and you pay a markup to run in someone else's account.
|
|
24
|
+
- **Infrastructure-as-code** (CDK / Terraform / CloudFormation) — you own
|
|
25
|
+
everything, but now you maintain a second codebase that drifts from the app it
|
|
26
|
+
describes.
|
|
27
|
+
|
|
28
|
+
laranja takes a third path: **your application code _is_ the source of truth for
|
|
29
|
+
the infrastructure.** A route is an HTTP endpoint. A `@Cron` method is a
|
|
30
|
+
scheduled function. A `@Queue` method is an SQS consumer. laranja reads those
|
|
31
|
+
facts out of your code and provisions exactly what they imply.
|
|
32
|
+
|
|
33
|
+
## How it feels
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// src/app.ts — mark your HTTP app, code-first
|
|
37
|
+
import express from "express";
|
|
38
|
+
import { http } from "@alzulejos/laranja-decorators";
|
|
39
|
+
|
|
40
|
+
const app = express();
|
|
41
|
+
app.get("/health", (_req, res) => res.json({ ok: true }));
|
|
42
|
+
|
|
43
|
+
export default http(app);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Jobs and queues come in two styles — plain **functions** or **classes** with
|
|
47
|
+
decorators. Use whichever you prefer:
|
|
48
|
+
|
|
49
|
+
```ts tab="Function"
|
|
50
|
+
// src/jobs.ts
|
|
51
|
+
import { cron, rate } from "@alzulejos/laranja-decorators";
|
|
52
|
+
|
|
53
|
+
export async function refreshCache() { /* ... */ }
|
|
54
|
+
cron(rate(5, "minutes"), refreshCache);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```ts tab="Class"
|
|
58
|
+
// src/jobs.ts
|
|
59
|
+
import { Cron, rate } from "@alzulejos/laranja-decorators";
|
|
60
|
+
|
|
61
|
+
export class Jobs {
|
|
62
|
+
@Cron(rate(5, "minutes"))
|
|
63
|
+
async refreshCache() { /* ... */ }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx laranja deploy
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
You get a live HTTPS URL, an EventBridge schedule, and an SQS queue with a
|
|
72
|
+
consumer — all in your own account, named deterministically.
|
|
73
|
+
|
|
74
|
+
## Principles
|
|
75
|
+
|
|
76
|
+
- **Code is the source of truth.** Infrastructure is _derived_ from the app, not
|
|
77
|
+
declared alongside it. There's nothing to keep in sync.
|
|
78
|
+
- **Your account, your resources.** laranja deploys with your AWS credentials
|
|
79
|
+
into your account. You own every resource and can inspect it in the console.
|
|
80
|
+
- **Deterministic, no magic names.** Resources are named `‹app›-‹fn›-‹stage›` —
|
|
81
|
+
predictable and greppable, with no random suffixes.
|
|
82
|
+
- **Provider-neutral by design.** AWS is the first target, but laranja is built
|
|
83
|
+
so other clouds can follow without changing your app code.
|
|
84
|
+
- **An escape hatch when you need it.** Outgrow the abstraction? `laranja eject`
|
|
85
|
+
hands you a real, owned CDK project (see [eject](../reference/commands.md#eject)).
|
|
86
|
+
|
|
87
|
+
## What's in scope (v1)
|
|
88
|
+
|
|
89
|
+
| Capability | How you declare it |
|
|
90
|
+
|---|---|
|
|
91
|
+
| HTTP API | An Express or NestJS app, marked with the [`http()`](../reference/decorators-and-markers.md#http) marker. |
|
|
92
|
+
| Scheduled jobs | [`@Cron`](../reference/decorators-and-markers.md#cron) (class) or [`cron()`](../reference/decorators-and-markers.md#cron-marker) (function) |
|
|
93
|
+
| Queue consumers | [`@Queue`](../reference/decorators-and-markers.md#queue) (class) or [`queue()`](../reference/decorators-and-markers.md#queue-marker) (function) |
|
|
94
|
+
| Per-environment deploys | [Stages](../guides/stages-and-environments.md) (`--stage`) |
|
|
95
|
+
| Env vars | [`env`](../guides/environment-variables.md) in config |
|
|
96
|
+
|
|
97
|
+
Next: **[Installation](./installation.md)**.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quickstart
|
|
3
|
+
description: From an empty folder to a live HTTPS endpoint in a few minutes.
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Quickstart
|
|
8
|
+
|
|
9
|
+
This walks you from zero to a deployed app with an HTTP endpoint, a scheduled
|
|
10
|
+
job, and a queue consumer.
|
|
11
|
+
|
|
12
|
+
## 1. Create a project
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
mkdir my-api && cd my-api
|
|
16
|
+
npm init -y
|
|
17
|
+
npm install express
|
|
18
|
+
npm install -D @alzulejos/laranja typescript
|
|
19
|
+
npm install @alzulejos/laranja-decorators
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> laranja supports **Express** and **NestJS**. For Nest, see the
|
|
23
|
+
> [HTTP apps guide](../guides/http-apps.md#nestjs).
|
|
24
|
+
|
|
25
|
+
## 2. Write your app
|
|
26
|
+
|
|
27
|
+
Mark your app with [`http()`](../reference/decorators-and-markers.md#http) and
|
|
28
|
+
export it. laranja finds it by reading your code — so there's nothing to wire up
|
|
29
|
+
in config:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// src/app.ts
|
|
33
|
+
import express from "express";
|
|
34
|
+
import { http } from "@alzulejos/laranja-decorators";
|
|
35
|
+
|
|
36
|
+
const app = express();
|
|
37
|
+
app.get("/", (_req, res) => res.json({ ok: true, stage: process.env.STAGE }));
|
|
38
|
+
app.get("/users/:id", (req, res) => res.json({ id: req.params.id }));
|
|
39
|
+
|
|
40
|
+
export default http(app);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Add a scheduled job and a queue consumer (optional). There are two styles — pick
|
|
44
|
+
whichever fits your codebase.
|
|
45
|
+
|
|
46
|
+
```ts tab="Function"
|
|
47
|
+
// src/jobs.ts
|
|
48
|
+
import { cron, queue, rate } from "@alzulejos/laranja-decorators";
|
|
49
|
+
|
|
50
|
+
export async function refreshCache() {
|
|
51
|
+
console.log("refreshing cache…");
|
|
52
|
+
}
|
|
53
|
+
cron(rate(5, "minutes"), refreshCache);
|
|
54
|
+
|
|
55
|
+
export async function sendEmail(body: unknown) {
|
|
56
|
+
console.log("sending", body);
|
|
57
|
+
}
|
|
58
|
+
queue({ name: "emails", batchSize: 10 }, sendEmail);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```ts tab="Class"
|
|
62
|
+
// src/jobs.ts
|
|
63
|
+
import { Cron, Queue, rate } from "@alzulejos/laranja-decorators";
|
|
64
|
+
|
|
65
|
+
export class Jobs {
|
|
66
|
+
@Cron(rate(5, "minutes"))
|
|
67
|
+
async refreshCache() {}
|
|
68
|
+
|
|
69
|
+
@Queue({ name: "emails", batchSize: 10 })
|
|
70
|
+
async sendEmail(body: unknown) {}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 3. Sign in and configure
|
|
75
|
+
|
|
76
|
+
Run the scaffolder. It prompts for your **laranja API key** (from the dashboard),
|
|
77
|
+
validates it, stores it in `~/.laranja/auth.json`, and lets you pick or create a
|
|
78
|
+
**dashboard project** — filling in `name` and `projectId` for you:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx laranja init
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The generated `laranja.config.ts` looks like this (edit `region`, `env`, and
|
|
85
|
+
`compute` to taste):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// laranja.config.ts
|
|
89
|
+
import type { LaranjaConfig } from "@alzulejos/laranja-decorators";
|
|
90
|
+
|
|
91
|
+
const config: LaranjaConfig = {
|
|
92
|
+
name: "my-api",
|
|
93
|
+
// From your laranja dashboard — identifies this project on the server.
|
|
94
|
+
projectId: "proj_…",
|
|
95
|
+
region: "us-east-1",
|
|
96
|
+
env: { LOG_LEVEL: "info" },
|
|
97
|
+
// Default compute for every function (the HTTP proxy + each cron/queue).
|
|
98
|
+
compute: { memory: 256, timeout: 30 },
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default config;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Because the app is marked with `http()` in code, the config stays minimal — the
|
|
105
|
+
HTTP app is declared there, not in config. See the
|
|
106
|
+
**[config reference](../reference/config-file.md)**.
|
|
107
|
+
|
|
108
|
+
## 4. Preview the plan
|
|
109
|
+
|
|
110
|
+
`plan` shows what a deploy would do: it synthesizes your template on the server,
|
|
111
|
+
diffs it against what's deployed in your AWS account, and tags each resource
|
|
112
|
+
**created / changed / unchanged**. It's **read-only** — nothing is applied, and it
|
|
113
|
+
never counts against your deploy limit.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx laranja plan
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Plan for "my-api-dev"
|
|
121
|
+
|
|
122
|
+
+ http HTTP 2 routes → proxy Lambda + Function URL
|
|
123
|
+
+ daily Cron Lambda + EventBridge rule
|
|
124
|
+
+ emails Queue SQS + consumer Lambda
|
|
125
|
+
|
|
126
|
+
8 AWS resources +8 created =0 unchanged
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
On this first run nothing is deployed yet, so everything shows as `+` created.
|
|
130
|
+
|
|
131
|
+
## 5. Deploy
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx laranja deploy
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The first deploy to a new account/region prompts you to **bootstrap** (a
|
|
138
|
+
one-time setup in your account). When it finishes you'll see your live URL:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
🌐 http https://abc123.lambda-url.us-east-1.on.aws/
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Hit it:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
curl https://abc123.lambda-url.us-east-1.on.aws/
|
|
148
|
+
# {"ok":true,"stage":"dev"}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 6. Iterate
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npx laranja logs # tail CloudWatch logs (pick a function)
|
|
155
|
+
npx laranja plan # see what a deploy would change
|
|
156
|
+
npx laranja deploy # ship again
|
|
157
|
+
npx laranja destroy # tear it all down
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Next steps
|
|
161
|
+
|
|
162
|
+
- Ship to multiple environments: **[Stages & environments](../guides/stages-and-environments.md)**.
|
|
163
|
+
- Understand what was created: **[What gets deployed](../reference/what-gets-deployed.md)**.
|
|
164
|
+
- Go deeper on jobs and queues: **[Cron jobs](../guides/cron-jobs.md)**, **[Queues](../guides/queues.md)**.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cron jobs
|
|
3
|
+
description: Run functions on a schedule with @Cron or cron().
|
|
4
|
+
order: 2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Cron jobs
|
|
8
|
+
|
|
9
|
+
A cron job is a function that runs on a schedule. Each one becomes
|
|
10
|
+
[its own Lambda plus an EventBridge rule](../reference/what-gets-deployed.md#cron--lambda--eventbridge-rule).
|
|
11
|
+
|
|
12
|
+
## Class style — `@Cron`
|
|
13
|
+
|
|
14
|
+
Decorate a method with [`@Cron`](../reference/decorators-and-markers.md#cron) and
|
|
15
|
+
give it a [schedule](./schedules.md):
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Cron, rate, every } from "@alzulejos/laranja-decorators";
|
|
19
|
+
|
|
20
|
+
export class Jobs {
|
|
21
|
+
@Cron(rate(5, "minutes"))
|
|
22
|
+
async refreshCache() {
|
|
23
|
+
// …
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Cron(every("day"))
|
|
27
|
+
async nightlyCleanup() {
|
|
28
|
+
// …
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Cron({ schedule: "cron(0 12 * * ? *)", id: "daily-report" })
|
|
32
|
+
async sendReport() {
|
|
33
|
+
// …
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The handler's logical id defaults to `‹Class›-‹method›`; pass `id` to set a
|
|
39
|
+
stable, explicit name (which also drives the Lambda's name).
|
|
40
|
+
|
|
41
|
+
## Function style — `cron()`
|
|
42
|
+
|
|
43
|
+
If you don't use classes, register a standalone exported function with
|
|
44
|
+
[`cron()`](../reference/decorators-and-markers.md#cron-marker):
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { cron, rate } from "@alzulejos/laranja-decorators";
|
|
48
|
+
|
|
49
|
+
export async function refreshCache() {
|
|
50
|
+
// …
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
cron(rate(5, "minutes"), refreshCache);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The function's name becomes the resource id unless you pass an explicit `id`:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
cron({ schedule: every("hour"), id: "hourly-sync" }, refreshCache);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## NestJS
|
|
63
|
+
|
|
64
|
+
In a Nest app, `@Cron` goes on a normal provider — with injected dependencies —
|
|
65
|
+
and you can keep the schedule syntax you already use (a
|
|
66
|
+
[node-cron string or `CronExpression`](./schedules.md#node-cron-expressions-nestjsschedule-compatibility)).
|
|
67
|
+
Swapping the import from `@nestjs/schedule` is usually the only change:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// tasks.service.ts
|
|
71
|
+
import { Injectable } from "@nestjs/common";
|
|
72
|
+
import { Cron, CronExpression } from "@alzulejos/laranja-decorators"; // ← was @nestjs/schedule
|
|
73
|
+
|
|
74
|
+
@Injectable()
|
|
75
|
+
export class TasksService {
|
|
76
|
+
constructor(private readonly reports: ReportsService) {} // real DI
|
|
77
|
+
|
|
78
|
+
@Cron(CronExpression.EVERY_30_MINUTES)
|
|
79
|
+
async sweep() {
|
|
80
|
+
await this.reports.rebuild(); // `this.reports` is injected
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Because the method runs on a real provider, laranja resolves it through your
|
|
86
|
+
app's dependency-injection container instead of `new`-ing the class. Point it at
|
|
87
|
+
your module **once** with the [`workers()`](../reference/decorators-and-markers.md#workers)
|
|
88
|
+
marker:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// src/main.ts (or a dedicated file)
|
|
92
|
+
import { workers } from "@alzulejos/laranja-decorators";
|
|
93
|
+
import { AppModule } from "./app.module";
|
|
94
|
+
|
|
95
|
+
export default workers(AppModule); // build a DI context from this module
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Pass `AppModule` for the whole graph, or a leaner module you compose if you want
|
|
99
|
+
a smaller cold start. Like the Nest [HTTP path](./http-apps.md#nestjs), laranja
|
|
100
|
+
packages your **compiled** `dist/` output — run `nest build` before deploying so
|
|
101
|
+
the DI metadata exists.
|
|
102
|
+
|
|
103
|
+
## Schedules
|
|
104
|
+
|
|
105
|
+
Schedules are written with the portable `rate()` / `every()` builders, or as a
|
|
106
|
+
raw expression string. See the **[Schedules reference](./schedules.md)** for the
|
|
107
|
+
full set of options.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
@Cron(rate(30, "minutes")) // every 30 minutes
|
|
111
|
+
@Cron(every("hour")) // every hour (shorthand for rate(1, "hour"))
|
|
112
|
+
@Cron({ schedule: "cron(0 9 * * ? *)" }) // raw AWS cron: 09:00 UTC daily
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Runtime behavior
|
|
116
|
+
|
|
117
|
+
- Each cron runs in its **own Lambda**, isolated from your HTTP app and other
|
|
118
|
+
jobs.
|
|
119
|
+
- Memory and timeout come from [`compute`](../reference/config-file.md#compute)
|
|
120
|
+
(default `{ memory: 256, timeout: 30 }`) and can be overridden per cron id in
|
|
121
|
+
[`resources`](../reference/config-file.md#resources).
|
|
122
|
+
- All [config `env`](./environment-variables.md) and `STAGE` are
|
|
123
|
+
available via `process.env`.
|
|
124
|
+
|
|
125
|
+
## Related
|
|
126
|
+
|
|
127
|
+
- [Schedules](./schedules.md)
|
|
128
|
+
- [`@Cron` / `cron()` reference](../reference/decorators-and-markers.md#cron)
|
|
129
|
+
- [Queues](./queues.md)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Environment variables
|
|
3
|
+
description: Declare env vars in config or in code, and supply their values per stage.
|
|
4
|
+
order: 5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Environment variables
|
|
8
|
+
|
|
9
|
+
Every Lambda laranja deploys receives a set of environment variables, available
|
|
10
|
+
through `process.env` as usual. There are two ways to declare them.
|
|
11
|
+
|
|
12
|
+
## Static values in config
|
|
13
|
+
|
|
14
|
+
Put plain, commit-safe values in the `env` map in your config. They're injected
|
|
15
|
+
into **every** function (HTTP proxy, cron, and queue consumers):
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// laranja.config.ts
|
|
19
|
+
const config: LaranjaConfig = {
|
|
20
|
+
name: "my-api",
|
|
21
|
+
env: {
|
|
22
|
+
LOG_LEVEL: "info",
|
|
23
|
+
API_BASE_URL: "https://api.example.com",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// anywhere in your app
|
|
30
|
+
const level = process.env.LOG_LEVEL; // "info"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use this for non-sensitive configuration that's the same everywhere: log levels,
|
|
34
|
+
public URLs, feature flags.
|
|
35
|
+
|
|
36
|
+
## Values from your environment — `env()`
|
|
37
|
+
|
|
38
|
+
When a value should come from your shell or CI instead of your repo, wrap the
|
|
39
|
+
variable name with the `env()` helper where you read it:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { env } from "@alzulejos/laranja-decorators";
|
|
43
|
+
|
|
44
|
+
const dbUrl = env("DATABASE_URL"); // same as process.env.DATABASE_URL at runtime
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
laranja finds every `env("…")` in your code and makes sure that variable is set
|
|
48
|
+
on **every** deployed function — no more filling them in by hand in the AWS
|
|
49
|
+
console. At deploy time it reads each value from your own environment and sends
|
|
50
|
+
it straight to the function; the value is never written into your repo.
|
|
51
|
+
|
|
52
|
+
The name must be a **string literal** — `env("DATABASE_URL")`, not
|
|
53
|
+
`env(someVariable)` — so laranja can discover it just by reading your code.
|
|
54
|
+
|
|
55
|
+
### Supplying the values
|
|
56
|
+
|
|
57
|
+
Set the variables in the shell or CI job you deploy from:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
DATABASE_URL=postgres://… laranja deploy --stage prod
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- **Missing a value?** By default laranja deploys anyway and warns you which ones
|
|
64
|
+
were empty — a typo never blocks a deploy. Pass `--strict` to fail the deploy
|
|
65
|
+
instead.
|
|
66
|
+
- **Re-deploying without re-supplying a value?** The previously deployed value is
|
|
67
|
+
kept, so you don't have to pass every variable on every deploy.
|
|
68
|
+
|
|
69
|
+
## The `STAGE` variable
|
|
70
|
+
|
|
71
|
+
laranja always injects `STAGE`, set to the active [stage](./stages-and-environments.md)
|
|
72
|
+
(`"dev"` by default, or whatever `--stage` resolved to). You don't declare it:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
app.get("/", (_req, res) => res.json({ stage: process.env.STAGE }));
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If you also define `STAGE` in `env`, your value wins.
|
|
79
|
+
|
|
80
|
+
## Per-stage values
|
|
81
|
+
|
|
82
|
+
Because [`--stage`](./stages-and-environments.md) selects the
|
|
83
|
+
environment at deploy time, the common pattern is one pipeline per stage, each
|
|
84
|
+
supplying its own values:
|
|
85
|
+
|
|
86
|
+
- **Shared, non-sensitive defaults** → the `env` map in config.
|
|
87
|
+
- **Per-environment values** → declare them with `env()` and provide them from
|
|
88
|
+
each pipeline's environment.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# dev pipeline
|
|
92
|
+
LOG_LEVEL=debug laranja deploy --stage dev
|
|
93
|
+
# prod pipeline
|
|
94
|
+
LOG_LEVEL=warn laranja deploy --stage prod
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Secrets
|
|
98
|
+
|
|
99
|
+
`env()` keeps values out of your repo, but they still land in the Lambda's plain
|
|
100
|
+
environment — readable by anyone with access to the function's configuration. For
|
|
101
|
+
true secrets (API keys, DB passwords), that's not enough. First-class secrets
|
|
102
|
+
support is on the roadmap; until then, read them at runtime from a secret store
|
|
103
|
+
(e.g. AWS SSM Parameter Store / Secrets Manager) inside your handler.
|
|
104
|
+
|
|
105
|
+
## Related
|
|
106
|
+
|
|
107
|
+
- [Config file](../reference/config-file.md)
|
|
108
|
+
- [Stages & environments](./stages-and-environments.md)
|