zuplo 6.69.0 → 6.69.2

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.
@@ -64,11 +64,26 @@ variable named `MY_VAR` can't be set on say the **Production** environments.
64
64
 
65
65
  ## Reserved Environment Variables
66
66
 
67
- Environment variables can't start with `ZUPLO` or `__ZUPLO`.
67
+ Environment variables can't start with `ZUPLO_` or `__ZUPLO`. The same
68
+ restriction applies to names beginning with `ZUDOKU_`.
69
+
70
+ If you need a variable that's exposed to the
71
+ [Developer Portal](../dev-portal/introduction.mdx) build, prefix it with
72
+ `ZUPLO_PUBLIC_` (or `ZUDOKU_PUBLIC_`). Public-prefixed variables are bundled
73
+ into the portal's static output and **must not contain secrets**, as they're
74
+ visible to anyone who loads the page.
68
75
 
69
76
  ## Using Environment Variables
70
77
 
71
- Environment variables can be used in several places within your Zuplo project:
78
+ Environment variables can be used in several places in your Zuplo project. Each
79
+ location has its own syntax:
80
+
81
+ | Location | Syntax | Resolved |
82
+ | ----------------------------------------------------- | ---------------------- | --------------------- |
83
+ | Custom code (handlers, policies, hooks) | `environment.VAR_NAME` | Runtime |
84
+ | Configuration files (`policies.json`, OpenAPI routes) | `$env(VAR_NAME)` | Build time |
85
+ | URL Rewrite, URL Forward, and WebSocket handlers | `${env.VAR_NAME}` | Runtime (per request) |
86
+ | Developer Portal config (`zudoku.config.ts`) | `process.env.VAR_NAME` | Portal build time |
72
87
 
73
88
  ### In Code
74
89
 
@@ -77,13 +92,44 @@ See the
77
92
  [Environment Variables API Reference](../programmable-api/environment.mdx) for
78
93
  detailed usage examples and patterns.
79
94
 
95
+ ```ts
96
+ import { environment } from "@zuplo/runtime";
97
+
98
+ const apiKey = environment.API_KEY; // string | undefined
99
+ ```
100
+
80
101
  ### In Configuration Files
81
102
 
82
- Inside some configuration files, environment variables can be referenced with
83
- the pattern `$env(MY_VAR)`.
103
+ Inside policy options, route handler options, and CORS policy options,
104
+ environment variables can be referenced with the `$env(VAR_NAME)` pattern.
105
+ Substitutions happen at build time — the build replaces each `$env()` expression
106
+ with a reference to the runtime `environment` object before the project is
107
+ deployed.
108
+
109
+ #### Where `$env()` is allowed
110
+
111
+ - `config/policies.json` — any property under `policies[].handler.options`,
112
+ including nested objects and array elements
113
+ - `config/policies.json` — any direct property of a `corsPolicies[]` entry, such
114
+ as `allowedOrigins`, `allowedHeaders`, `allowedMethods`, `exposeHeaders`, and
115
+ `maxAge`
116
+ - `config/routes.oas.json` (and other OpenAPI route files) — any property under
117
+ a route's `x-zuplo-route.handler.options`, including nested objects and array
118
+ elements
119
+
120
+ `$env()` is **not** allowed in other locations such as policy `name`,
121
+ `policyType`, `module`, route paths, or top-level OpenAPI fields. Using it
122
+ elsewhere produces a build error:
123
+
124
+ ```text
125
+ An $env() statement is not expected at this location.
126
+ ```
127
+
128
+ #### Standalone substitution
84
129
 
85
- For example, in the `policies.json` file, an environment variable could be set
86
- on a policy option.
130
+ When the value is _only_ an `$env()` expression, the variable's value is
131
+ inserted directly. The runtime type matches the type of the environment variable
132
+ (always a string when set, `undefined` when not).
87
133
 
88
134
  ```json
89
135
  {
@@ -93,23 +139,130 @@ on a policy option.
93
139
  "export": "default",
94
140
  "module": "$import(./modules/YOUR_MODULE)",
95
141
  "options": {
96
- "config1": "$env(MY_CONFIG_VAR)",
142
+ "apiKey": "$env(BACKEND_API_KEY)",
97
143
  "config2": true
98
144
  }
99
145
  }
100
146
  }
101
147
  ```
102
148
 
103
- ### Rewrite & Forwarding Handler
149
+ #### String interpolation
150
+
151
+ You can mix `$env()` with literal text to compose a value. The build wraps the
152
+ result in a JavaScript template literal that's evaluated at runtime, so each
153
+ request gets the current value of the variable.
154
+
155
+ ```json
156
+ {
157
+ "options": {
158
+ "endpoint": "https://$env(API_HOST)/v1",
159
+ "userAgent": "MyGateway/$env(APP_VERSION) ($env(ENVIRONMENT_NAME))"
160
+ }
161
+ }
162
+ ```
163
+
164
+ :::note
165
+
166
+ If the variable isn't set, the interpolated portion resolves to an empty string.
167
+ For example, with `API_HOST` unset, `"https://$env(API_HOST)/v1"` becomes
168
+ `"https:///v1"`. Use a standalone `$env()` (no surrounding text) if you need to
169
+ detect an unset variable in your handler or policy code.
170
+
171
+ :::
172
+
173
+ #### In arrays
174
+
175
+ `$env()` works inside string array elements, including mixed arrays where some
176
+ elements are static and others are interpolated:
177
+
178
+ ```json
179
+ {
180
+ "options": {
181
+ "allowedKeys": ["$env(PRIMARY_KEY)", "$env(SECONDARY_KEY)"],
182
+ "tags": ["public", "$env(REGION)", "tier-$env(SERVICE_TIER)"]
183
+ }
184
+ }
185
+ ```
186
+
187
+ #### In nested objects
188
+
189
+ `$env()` works at any depth within a handler or policy `options` object:
190
+
191
+ ```json
192
+ {
193
+ "options": {
194
+ "database": {
195
+ "host": "$env(DB_HOST)",
196
+ "credentials": {
197
+ "username": "$env(DB_USER)",
198
+ "password": "$env(DB_PASSWORD)"
199
+ }
200
+ }
201
+ }
202
+ }
203
+ ```
204
+
205
+ #### Variable name rules
206
+
207
+ The name inside `$env(...)` is matched literally up to the first closing
208
+ parenthesis. Use only letters, digits, and underscores in the name — matching
209
+ what the [Zuplo Portal](#environment-variable-editor) accepts when you create
210
+ the variable.
211
+
212
+ ### Rewrite, Forwarding, and WebSocket Handlers
213
+
214
+ The URL Rewrite handler's `rewritePattern`, the URL Forward handler's `baseUrl`,
215
+ and the WebSocket handler's `rewritePattern` use a different syntax. These
216
+ options are evaluated as JavaScript template literals at request time, so you
217
+ reference variables with `${env.VAR_NAME}`:
218
+
219
+ ```json
220
+ {
221
+ "handler": {
222
+ "export": "urlForwardHandler",
223
+ "module": "$import(@zuplo/runtime)",
224
+ "options": {
225
+ "baseUrl": "https://${env.BACKEND_HOST}"
226
+ }
227
+ }
228
+ }
229
+ ```
230
+
231
+ Because `rewritePattern` and `baseUrl` run as code, they also have access to the
232
+ request, URL parts, route params, and query string. See the
233
+ [URL Rewrite Handler](../handlers/url-rewrite.mdx) docs for the full list of
234
+ available variables.
104
235
 
105
- When referencing environment variables inside of the URL Rewrite handler and the
106
- URL Forward handler, variables are substituted using JavaScript style string
107
- interpolation.
236
+ :::caution
108
237
 
109
- ```txt
110
- https://${env.API_URL}/path/to/call
238
+ Using `$env(VAR_NAME)` inside `rewritePattern` or `baseUrl` is the most common
239
+ mistake. The build will warn you when it detects this, but the value will be
240
+ passed through to the handler as a literal string and the rewrite will fail at
241
+ runtime. Always use `${env.VAR_NAME}` in these two options.
242
+
243
+ :::
244
+
245
+ ### In the Developer Portal
246
+
247
+ The Developer Portal's `zudoku.config.ts` runs in Node-like build tooling and
248
+ uses `process.env` rather than `$env()`:
249
+
250
+ ```ts title="zudoku.config.ts"
251
+ const config: ZudokuConfig = {
252
+ authentication: {
253
+ type: "auth0",
254
+ domain: process.env.ZUPLO_PUBLIC_AUTH0_DOMAIN,
255
+ clientId: process.env.ZUPLO_PUBLIC_AUTH0_CLIENT_ID,
256
+ },
257
+ };
258
+
259
+ export default config;
111
260
  ```
112
261
 
262
+ Only variables prefixed with `ZUPLO_PUBLIC_` (or `ZUDOKU_PUBLIC_`) are available
263
+ in the portal build, and their values are embedded into the client-side bundle.
264
+ Don't use this prefix for any value that should remain private.
265
+
113
266
  ## System Environment Variables
114
267
 
115
268
  The following variables are automatically set by the system and are available to
@@ -35,9 +35,9 @@ Track the total number of API requests:
35
35
 
36
36
  ```json
37
37
  {
38
- "slug": "requests",
38
+ "slug": "api_requests",
39
39
  "name": "API Requests",
40
- "eventType": "requests",
40
+ "eventType": "api_requests",
41
41
  "aggregation": "SUM",
42
42
  "valueProperty": "$.total"
43
43
  }
@@ -50,7 +50,7 @@ Each event contains the `subscription` ID linking it to a subscription and a
50
50
  {
51
51
  "id": "5c10fade-1c9e-4d6c-8275-c52c36731d3c",
52
52
  "specversion": "1.0",
53
- "type": "requests",
53
+ "type": "api_requests",
54
54
  "source": "monetization-policy",
55
55
  "subject": "customer-id",
56
56
  "subscription": "01KNVXHQG356VA7T7W0V9N21GH",
@@ -142,9 +142,9 @@ curl \
142
142
  --header "Content-Type: application/json" \
143
143
  --data @- << EOF
144
144
  {
145
- "slug": "requests",
145
+ "slug": "api_requests",
146
146
  "name": "API Requests",
147
- "eventType": "requests",
147
+ "eventType": "api_requests",
148
148
  "aggregation": "SUM",
149
149
  "valueProperty": "$.total"
150
150
  }
@@ -84,7 +84,8 @@ Add the monetization plugin to your Developer Portal configuration.
84
84
  ## Step 3: Configure the Monetization Service
85
85
 
86
86
  1. Navigate to the **Services** tab in your project.
87
- 2. Select the environment you want to configure (e.g., **Working Copy**).
87
+ 2. Select the environment you want to configure. We will use **Working Copy**
88
+ for this quickstart.
88
89
  3. Click **Configure** on the **Monetization Service** card.
89
90
 
90
91
  ## Step 4: Create a meter
@@ -93,11 +94,11 @@ Meters track what you want to measure — API calls, tokens processed, data
93
94
  transferred, etc.
94
95
 
95
96
  1. In the Monetization Service, click the **Meters** tab.
96
- 2. Click **Add Meter** and select **Blank Meter**.
97
- 3. Fill in the meter details:
98
- - **Name**: `Requests`
99
- - **Event**: `requests` — the type of event this meter listens for.
100
- - **Description**: `API Requests`
97
+ 2. Click **Add Meter** and select **API Requests** from the template list.
98
+ 3. Verify the pre-filled meter details:
99
+ - **Name**: `API Requests`
100
+ - **Event**: `api_requests` — the type of event this meter listens for.
101
+ - **Description**: `Counts all incoming API requests`
101
102
  - **Aggregation**: `SUM` — how values are combined (other options include
102
103
  `COUNT`, `MAX`, etc.).
103
104
  - **Value Property**: `$.total` — a JSONPath expression that extracts the
@@ -115,15 +116,18 @@ Feature** for each of the following:
115
116
 
116
117
  | Name | Key | Linked Meter | Purpose |
117
118
  | ---------------- | ------------------ | ------------ | ----------------------------- |
118
- | API Requests | `requests` | Requests | Usage-based (linked to meter) |
119
+ | API Requests | `api_requests` | API Requests | Usage-based (linked to meter) |
119
120
  | Monthly Fee | `monthly_fee` | — | Flat-rate billing |
120
121
  | Metadata Support | `metadata_support` | — | Boolean on/off feature |
121
122
 
122
123
  :::tip{title="Key Naming Conventions"}
123
124
 
124
- When creating features that are metered, the key must match the key you set for
125
- the associated meter. For example, if your Requests meter key is `requests`,
126
- then your Requests feature key must also be `requests`.
125
+ The meter key, the feature key, and the key in the monetization policy's
126
+ `meters` configuration must all match. For example, the API Requests meter key
127
+ is `api_requests`, the feature key must also be `api_requests`, and the policy
128
+ must use `"meters": { "api_requests": 1 }`.
129
+
130
+ See [Naming Consistency](./meters.mdx#naming-consistency) for the full rule.
127
131
 
128
132
  :::
129
133
 
@@ -243,10 +247,13 @@ charges.
243
247
 
244
248
  :::warning
245
249
 
246
- Always use your Stripe **test** key (`sk_test_...`) while following this guide.
247
- This creates a sandbox environment where you can safely test subscriptions and
248
- payments without processing real transactions. When you're ready for production,
249
- update to your live key (`sk_live_...`).
250
+ Always use your Stripe **test** key (`sk_test_...`) in the **Working Copy**
251
+ environment while following this guide. Stripe test keys run in a sandbox
252
+ environment where you can safely test subscriptions and payments without
253
+ processing real transactions. When you're ready for production, configure the
254
+ **Production** environment with a live key (`sk_live_...`). Do not replace a
255
+ test key with a live key in the same environment — use one key type per
256
+ environment.
250
257
 
251
258
  :::
252
259
 
@@ -265,9 +272,9 @@ directory.
265
272
 
266
273
  ![Monetization policy in the policy picker list](../../../public/media/monetization/monetization-policy.png)
267
274
 
268
- 3. In the **Meters** configuration field, you can keep the default value of
269
- `requests` set `1` to match the meter you created in _Step 4_. This field
270
- maps the meter slug to the number of units each request consumes.
275
+ 3. In the **Meters** configuration field, set the key to `api_requests` with a
276
+ value of `1` to match the meter you created in _Step 4_. This field maps the
277
+ meter slug to the number of units each request consumes.
271
278
 
272
279
  ```json
273
280
  {
@@ -276,7 +283,7 @@ directory.
276
283
  "options": {
277
284
  "cacheTtlSeconds": 60,
278
285
  "meters": {
279
- "requests": 1
286
+ "api_requests": 1
280
287
  }
281
288
  }
282
289
  }
@@ -54,13 +54,15 @@ Connect with a Stripe **test** key (`sk_test_...`) first to validate your
54
54
  configuration end-to-end. Test mode uses Stripe's test card numbers (e.g.,
55
55
  `4242 4242 4242 4242`) and never charges real money.
56
56
 
57
- When you're ready to go live, update to your live key (`sk_live_...`).
57
+ When you're ready to go live, configure a separate Zuplo environment (e.g.,
58
+ **Production**) with your live key (`sk_live_...`).
58
59
 
59
60
  :::caution
60
61
 
61
- Always use your Stripe **test** key while developing. Test mode and live mode
62
- are separate environments in Stripe. Products, customers, and subscriptions
63
- don't transfer between them.
62
+ Use one Stripe key type per Zuplo environment do not replace a test key with a
63
+ live key in the same environment. Test mode and live mode are separate
64
+ environments in Stripe. Products, customers, and subscriptions created in test
65
+ mode don't transfer to live mode and vice versa.
64
66
 
65
67
  :::
66
68
 
@@ -22,6 +22,26 @@ A tunnel is a way to expose your _internal services_ to the Zuplo gateway
22
22
  without exposing it to the public internet. Your Zuplo Gateway accesses those
23
23
  services through the `service://` protocol.
24
24
 
25
+ ## Create the tunnel
26
+
27
+ Before you deploy the tunnel container, create the tunnel in Zuplo using the
28
+ CLI. This gives you the tunnel record in your account and the token that you
29
+ will later provide to the container as `TUNNEL_TOKEN`.
30
+
31
+ ```bash
32
+ zuplo tunnel create --tunnel-name <your-tunnel-name>
33
+ zuplo tunnel list
34
+ zuplo tunnel describe --tunnel-id <your-tunnel-id>
35
+ ```
36
+
37
+ Use these commands as follows:
38
+
39
+ 1. Run `zuplo tunnel create` to create the tunnel.
40
+ 1. Run `zuplo tunnel list` to see the tunnels in your account and identify the
41
+ tunnel ID if you need it.
42
+ 1. Run `zuplo tunnel describe` with the tunnel ID to retrieve the tunnel details
43
+ and copy the token value you will use for `TUNNEL_TOKEN`.
44
+
25
45
  The easiest way to deploy your tunnel is using a Docker container. The three
26
46
  basic requirements for deploying a secure tunnel with Docker are:
27
47
 
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: "Zuplo CLI: Whoami"
3
+ sidebar_label: whoami
4
+ ---
5
+
6
+ <CliCommand
7
+ command="whoami"
8
+ description="Displays the currently authenticated user"
9
+ examples={[
10
+ [
11
+ "$0 whoami",
12
+ "Display the currently authenticated user"
13
+ ]
14
+ ]}
15
+ usage="$0 whoami [options]"
16
+ >
17
+
18
+ </CliCommand>
19
+
20
+ ## Global options
21
+
22
+ The following global options are available for all commands:
23
+
24
+ - [`--help`](./global-options.mdx#help)
25
+ - [`--api-key`](./global-options.mdx#api-key)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "6.69.0",
3
+ "version": "6.69.2",
4
4
  "type": "module",
5
5
  "description": "The programmable API Gateway",
6
6
  "author": "Zuplo, Inc.",
@@ -19,9 +19,9 @@
19
19
  "zuplo": "zuplo.js"
20
20
  },
21
21
  "dependencies": {
22
- "@zuplo/cli": "6.69.0",
23
- "@zuplo/core": "6.69.0",
24
- "@zuplo/runtime": "6.69.0",
22
+ "@zuplo/cli": "6.69.2",
23
+ "@zuplo/core": "6.69.2",
24
+ "@zuplo/runtime": "6.69.2",
25
25
  "@zuplo/test": "1.4.0"
26
26
  }
27
27
  }