zuplo 6.70.48 → 6.70.49

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.
@@ -3,15 +3,6 @@ title: API Access
3
3
  sidebar_label: API Access
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  ## Buckets
16
7
 
17
8
  Each Zuplo project includes three isolated buckets that mirror your
@@ -3,15 +3,6 @@ title: Billing Models Guide
3
3
  sidebar_label: Billing Models
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Zuplo supports four billing models, each targeting different business needs. You
16
7
  can mix models on the same pricing page and even within the same plan.
17
8
 
@@ -141,15 +132,6 @@ advance.
141
132
 
142
133
  ## Pay-as-you-go
143
134
 
144
- :::caution{title="Coming Soon"}
145
-
146
- Pay-as-you-go billing is supported by the underlying monetization models, but
147
- the developer portal pricing table experience has not been fully tested for this
148
- billing model yet. If you need pure pay-as-you-go pricing, contact
149
- [support](mailto:support@zuplo.com) to discuss your use case.
150
-
151
- :::
152
-
153
135
  No upfront commitment. The customer provides a credit card, uses the API as much
154
136
  as they want, and is billed monthly in arrears for actual usage.
155
137
 
@@ -3,15 +3,6 @@ title: Developer Portal Setup
3
3
  sidebar_label: Developer Portal
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  The Developer Portal is the self-serve storefront for your monetized API.
16
7
  Customers browse plans, subscribe, manage their API keys, and monitor usage —
17
8
  all without contacting your team. The portal is built on
@@ -3,15 +3,6 @@ title: Features
3
3
  sidebar_label: Features
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Features describe what your API offers to customers. They represent the
16
7
  capabilities in your API product - access to specific endpoints, usage
17
8
  allowances, premium functionality, or any other aspect you want to track or
@@ -3,18 +3,9 @@ title: Going to Production with Monetization
3
3
  sidebar_label: Going to Production
4
4
  description:
5
5
  Pre-production checklist, Stripe live-mode cutover, billing model readiness,
6
- and beta limitations for launching Zuplo API monetization.
6
+ and known limitations for launching Zuplo API monetization.
7
7
  ---
8
8
 
9
- :::note{title="Beta"}
10
-
11
- API Monetization is in beta and free to try. The APIs are stable but should be
12
- evaluated in non-production environments first. To go to production, contact
13
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
14
- announced.
15
-
16
- :::
17
-
18
9
  You have built out your monetization configuration in Stripe test mode and your
19
10
  customers are ready to pay real money. This guide covers:
20
11
 
@@ -22,14 +13,13 @@ customers are ready to pay real money. This guide covers:
22
13
  - **Billing model readiness**: which pricing models are production-ready today
23
14
  - **Stripe live-mode cutover**: step-by-step instructions to connect live
24
15
  payments
25
- - **Beta limitations**: constraints to design around before launch
16
+ - **Known limitations**: constraints to design around before launch
26
17
 
27
18
  ## Before you start
28
19
 
29
- Going to production with monetization requires coordination with the Zuplo team.
30
- The monetization feature is currently in **public beta**. The APIs are stable
31
- and the core billing flows work end-to-end, but production pricing for the
32
- monetization feature itself has not yet been announced.
20
+ Going to production with monetization requires coordination with the Zuplo team
21
+ to confirm your configuration and enable your production bucket for live
22
+ billing.
33
23
 
34
24
  :::tip{title="Email sales to go live"}
35
25
 
@@ -43,8 +33,8 @@ Email [sales@zuplo.com](mailto:sales@zuplo.com) with:
43
33
  :::
44
34
 
45
35
  The Zuplo team will confirm your configuration, walk you through any
46
- beta-specific considerations for your use case, and enable your production
47
- bucket for live billing.
36
+ considerations for your use case, and enable your production bucket for live
37
+ billing.
48
38
 
49
39
  ## Pre-production checklist
50
40
 
@@ -219,15 +209,14 @@ Set the value to `0` to block access immediately when payment fails.
219
209
 
220
210
  ## Billing models in production
221
211
 
222
- Not all billing models have the same level of portal support today. Choose the
223
- right model for your launch based on current readiness.
212
+ Choose the right model for your launch based on current readiness.
224
213
 
225
- | Model | Status | Notes |
226
- | ---------------------------- | ---------------------- | ------------------------------------------------------------- |
227
- | Fixed monthly quotas | Production-ready | Fully supported end-to-end |
228
- | Monthly quotas with overages | Production-ready | Modeled as graduated tiered pricing with `isSoftLimit: true` |
229
- | Pay-as-you-go | Limited portal support | Underlying model works; portal pricing table not fully tested |
230
- | Credits / tokens (prepaid) | Limited portal support | Underlying model works; portal experience not fully tested |
214
+ | Model | Status | Notes |
215
+ | ---------------------------- | ---------------- | ------------------------------------------------------------ |
216
+ | Fixed monthly quotas | Production-ready | Fully supported end-to-end |
217
+ | Monthly quotas with overages | Production-ready | Modeled as graduated tiered pricing with `isSoftLimit: true` |
218
+ | Pay-as-you-go | Production-ready | Bill entirely in arrears for actual usage |
219
+ | Credits / tokens (prepaid) | Coming soon | Underlying model works; portal experience not yet shipped |
231
220
 
232
221
  ### Fixed monthly quotas (production-ready)
233
222
 
@@ -252,25 +241,19 @@ Fully supported end-to-end. See
252
241
  [Billing Models → Monthly quotas with overages](./billing-models.md#monthly-quotas-with-overages)
253
242
  for examples.
254
243
 
255
- ### Pay-as-you-go (limited portal support)
244
+ ### Pay-as-you-go (production-ready)
256
245
 
257
- Pure pay-as-you-go billing (no upfront cost, bill entirely in arrears for actual
258
- usage) is supported by the underlying monetization models, but the **Developer
259
- Portal pricing table experience has not been fully tested** for this billing
260
- model yet.
261
-
262
- If you need pay-as-you-go pricing in production, contact
263
- [support@zuplo.com](mailto:support@zuplo.com) to discuss your use case and
264
- current workarounds.
246
+ Pure pay-as-you-go billing no upfront cost, bill entirely in arrears for
247
+ actual usage is fully supported end-to-end.
265
248
 
266
249
  See [Billing Models → Pay-as-you-go](./billing-models.md#pay-as-you-go) for the
267
250
  data model and configuration.
268
251
 
269
- ### Credits / tokens (prepaid, limited portal support)
252
+ ### Credits / tokens (prepaid, coming soon)
270
253
 
271
254
  Credit/token-based billing is supported by the underlying data model, but the
272
- **Developer Portal experience has not been fully tested** for this billing
273
- model.
255
+ **Developer Portal experience has not been fully tested** for this billing model
256
+ yet.
274
257
 
275
258
  If you need prepaid credit billing, contact
276
259
  [sales@zuplo.com](mailto:sales@zuplo.com) to discuss your use case.
@@ -418,21 +401,19 @@ After going live, keep a close eye on:
418
401
  | Developer Portal → Usage Dashboard | Customer-facing usage numbers match your expectations |
419
402
  | API responses | Monetized routes return `200` for subscribed customers and `403` for over-quota requests |
420
403
 
421
- ## Known beta limitations
404
+ ## Known limitations
422
405
 
423
- The following limitations apply during the beta period. Design around them when
424
- planning your production launch. As noted in
425
- [Before you start](#before-you-start), production access requires coordination
426
- with the Zuplo sales team, and production pricing for the monetization feature
427
- has not yet been announced.
406
+ The following limitations apply today. Design around them when planning your
407
+ production launch. As noted in [Before you start](#before-you-start), production
408
+ access requires coordination with the Zuplo sales team.
428
409
 
429
410
  <details>
430
- <summary>Pay-as-you-go and credits portal experience</summary>
411
+ <summary>Credits / tokens portal experience</summary>
431
412
 
432
- Pure pay-as-you-go and credit/token-based billing models are supported by the
433
- underlying data model and APIs, but the Developer Portal pricing table has not
434
- been fully tested for these models. If your business requires either model,
435
- coordinate with Zuplo support for guidance on workarounds.
413
+ Credit/token-based billing is supported by the underlying data model and APIs,
414
+ but the Developer Portal pricing table has not been fully tested for this model.
415
+ If your business requires prepaid credits, coordinate with Zuplo support for
416
+ guidance on workarounds.
436
417
 
437
418
  </details>
438
419
 
@@ -463,30 +444,13 @@ for details on multi-subscription scenarios.
463
444
 
464
445
  ## Zuplo plan requirements for monetization
465
446
 
466
- Monetization is available during beta on all Zuplo plan tiers, including Free
467
- and Builder. However, production workloads typically need capabilities that
468
- exceed what the Free and Builder tiers offer.
469
-
470
- | Plan | Gateway devs | Custom domains | Support | Production fit |
471
- | ----------------------- | ------------ | -------------- | --------------------------- | ----------------------------------------------------------------- |
472
- | **Free** | Up to 2 | 0 | Community | Testing monetization only; not suitable for production billing |
473
- | **Builder** ($25/mo) | Up to 2 | 2 | Community | Small-scale production if you don't need more team members or SLA |
474
- | **Enterprise** (custom) | Custom | Custom | Priority, SLA up to 99.999% | Required for >2 devs, additional domains, log retention, or SLA |
475
-
476
- There is currently no self-serve plan between Builder and Enterprise. If you
477
- need capabilities beyond Builder but are not ready for a full Enterprise
478
- engagement, email [sales@zuplo.com](mailto:sales@zuplo.com) to discuss your
479
- options.
480
-
481
- For current plan details and pricing, see the
482
- [Zuplo pricing page](https://zuplo.com/pricing).
447
+ Monetization is available on all Zuplo plan tiers. For current plan details and
448
+ pricing, see the [Zuplo pricing page](https://zuplo.com/pricing).
483
449
 
484
450
  ## Getting help when going live
485
451
 
486
- | Situation | Contact |
487
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
488
- | Ready to enable production billing for the first time, discussing production pricing, multi-subscription support, or a plan between Builder and Enterprise | [sales@zuplo.com](mailto:sales@zuplo.com) |
489
- | Something is not working as expected, debugging a billing or metering issue, or questions about a beta limitation or workaround | [support@zuplo.com](mailto:support@zuplo.com) |
452
+ Email [sales@zuplo.com](mailto:sales@zuplo.com) when you're ready to enable
453
+ production billing for the first time, or to discuss multi-subscription support.
490
454
 
491
455
  ### What to include in your request
492
456
 
@@ -3,15 +3,6 @@ title: API Monetization with Zuplo
3
3
  sidebar_label: Overview
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Zuplo's API Monetization lets you charge for your API directly from your gateway
16
7
  — no external metering services, no webhook spaghetti, no state sync headaches.
17
8
  Define your pricing, connect Stripe, and start billing. Zuplo handles metering,
@@ -110,6 +101,6 @@ pricing, wire up Stripe, and configure your gateway to enforce quotas.
110
101
  | [Subscription Lifecycle](./monetization/subscription-lifecycle.md) | Managing trials, upgrades, downgrades, and cancellations |
111
102
  | [Private Plans](./monetization/private-plans.md) | Invite-only plans for specific users |
112
103
  | [Tax Collection](./monetization/tax-collection.md) | Enabling VAT, sales tax, or GST via Stripe Tax |
113
- | [Going to Production](./monetization/going-to-production.mdx) | Pre-launch checklist, Stripe live mode, and beta considerations |
104
+ | [Going to Production](./monetization/going-to-production.mdx) | Pre-launch checklist, Stripe live mode, and known limitations |
114
105
  | [Plan Examples](./monetization/plan-examples.mdx) | Real-world plan configurations |
115
106
  | [Troubleshooting](./monetization/troubleshooting.md) | Common issues, debugging, and FAQ |
@@ -3,15 +3,6 @@ title: Meters
3
3
  sidebar_label: Meters
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Meters aggregate usage data from your API. They watch for specific event types,
16
7
  extract numeric values, and sum them over configurable time windows.
17
8
 
@@ -3,15 +3,6 @@ title: Monetization Policy Reference
3
3
  sidebar_label: Monetization Policy
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  The `MonetizationInboundPolicy` is the gateway enforcement mechanism. It runs on
16
7
  every request to a protected route, authenticates the API key, checks the
17
8
  customer's subscription and payment status, enforces quota, meters the request,
@@ -3,15 +3,6 @@ title: Plan Examples
3
3
  sidebar_label: Plan Examples
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  This guide walks through progressively building a plan, starting simple and
16
7
  adding complexity. All examples assume you have already created:
17
8
 
@@ -3,15 +3,6 @@ title: Plans
3
3
  sidebar_label: Plans
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Plans are subscription tiers that package features together. They represent the
16
7
  rows on your pricing page - Free, Pro, Enterprise - each with different feature
17
8
  access and usage limits. Plans define what customers get when they subscribe.
@@ -3,15 +3,6 @@ title: Pricing Models
3
3
  sidebar_label: Pricing Models
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Pricing models define how charges are calculated within a
16
7
  [rate card](./rate-cards.mdx). Each model suits different business scenarios,
17
8
  from simple flat fees to complex usage-based pricing.
@@ -3,15 +3,6 @@ title: Private Plans — Invite-Only Subscriptions
3
3
  sidebar_label: Private Plans
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Private plans are hidden from the public pricing table and can only be accessed
16
7
  by users you explicitly invite. Use private plans for custom enterprise pricing,
17
8
  partner deals, or beta testing with specific users.
@@ -3,14 +3,6 @@ title: Quickstart — Monetize Your API
3
3
  sidebar_label: Quickstart
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com).
11
-
12
- :::
13
-
14
6
  This guide walks you through setting up API monetization from scratch.
15
7
 
16
8
  ## Outcomes
@@ -38,13 +30,6 @@ included request quotas, and per-request overage billing.
38
30
 
39
31
  ## Step 1: Create a new project
40
32
 
41
- :::caution
42
-
43
- Use a fresh project for this guide. Since monetization is still in preview, this
44
- keeps your existing work safe from any breaking changes.
45
-
46
- :::
47
-
48
33
  1. Go to [portal.zuplo.com](https://portal.zuplo.com) and sign in.
49
34
  2. Click **New Project** in the top right corner
50
35
  ([open](https://portal.zuplo.com/+/account/projects/new)).
@@ -3,15 +3,6 @@ title: Rate Cards
3
3
  sidebar_label: Rate Cards
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Rate cards define the pricing and entitlements for features within a plan. Each
16
7
  rate card connects a feature to a price and optionally sets usage limits or
17
8
  access controls. Rate cards are the building blocks that turn your product
@@ -3,15 +3,6 @@ title: Stripe Integration
3
3
  sidebar_label: Stripe Integration
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Zuplo uses Stripe to collect payments. Zuplo is the system of record for plans,
16
7
  subscriptions, features, entitlements, and metered usage; Stripe is the system
17
8
  of record for **money** — customers, invoices, and payment collection.
@@ -3,15 +3,6 @@ title: Subscription Lifecycle
3
3
  sidebar_label: Subscription Lifecycle
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  This guide covers the full lifecycle of a customer subscription: creation,
16
7
  trials, upgrades, downgrades, cancellation, and reactivation.
17
8
 
@@ -3,15 +3,6 @@ title: Tax Collection — Enabling Stripe Tax
3
3
  sidebar_label: Tax Collection
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  Zuplo supports automatic tax collection through Stripe Tax. When enabled, taxes
16
7
  (such as VAT, sales tax, or GST) are automatically calculated and added to your
17
8
  customers' invoices.
@@ -3,15 +3,6 @@ title: Troubleshooting & FAQ
3
3
  sidebar_label: Troubleshooting
4
4
  ---
5
5
 
6
- :::note{title="Beta"}
7
-
8
- API Monetization is in beta and free to try. The APIs are stable but should be
9
- evaluated in non-production environments first. To go to production, contact
10
- [sales@zuplo.com](mailto:sales@zuplo.com). Production pricing has not yet been
11
- announced.
12
-
13
- :::
14
-
15
6
  ## Common issues
16
7
 
17
8
  ### Customer gets 403 Forbidden instead of expected access
@@ -11,12 +11,17 @@ your [Dev Portal configuration](./overview.md). This requires [authentication](.
11
11
  be configured. The property supports two formats: a simple array of path patterns, or an advanced
12
12
  object format with custom authorization logic.
13
13
 
14
- :::note{title="Client-side protection only"}
14
+ :::note{title="SSR vs SSG protection"}
15
15
 
16
- `protectedRoutes` are client-side only. Do not rely on `protectedRoutes` to hide sensitive
17
- information.
16
+ In **SSR mode**, `protectedRoutes` is enforced both client-side (login dialog) and at the bundle
17
+ level. Chunks containing content for protected routes are isolated into a separate, auth-gated
18
+ directory and never served to unauthenticated clients. See the
19
+ [Server-side Content Protection guide](../guides/server-side-content-protection.md) for the full
20
+ mechanics and caveats.
18
21
 
19
- We are working on an additional offering that secures this data server-side.
22
+ In **SSG mode** there is no server, so `protectedRoutes` is client-side only. The JavaScript chunks
23
+ for protected routes are still fetchable by anyone who knows the URL. Don't rely on SSG
24
+ `protectedRoutes` to hide sensitive information.
20
25
 
21
26
  :::
22
27
 
@@ -143,7 +148,19 @@ For example:
143
148
  - `/docs/*` matches `/docs/getting-started` or `/docs/api/reference`
144
149
  - `/settings` matches only the exact path `/settings`
145
150
 
151
+ ## Server-side Protection (SSR mode)
152
+
153
+ In SSR mode, Dev Portal additionally isolates the JavaScript chunks for protected routes into an
154
+ auth-gated directory that unauthenticated users cannot fetch. This covers content sources that the
155
+ build can statically analyze (MDX docs, file-based OpenAPI, user custom pages with `lazy` imports)
156
+ and has caveats for dynamically-generated routes and inline content.
157
+
158
+ See the [Server-side Content Protection guide](../guides/server-side-content-protection.md) for the
159
+ full explanation, auto-detection rules, caveats, and pre-ship checklist.
160
+
146
161
  ## Next Steps
147
162
 
148
163
  - Learn about [authentication providers](./authentication.md#authentication-providers) supported by
149
164
  Dev Portal - Configure [user data](./authentication.md#user-data) display
165
+ - Read the [Server-side Content Protection guide](../guides/server-side-content-protection.md) if
166
+ you're deploying with an SSR adapter
@@ -0,0 +1,207 @@
1
+ ---
2
+ title: Server-side Content Protection
3
+ sidebar_icon: shield-check
4
+ description:
5
+ How Dev Portal isolates protected-route content at build time in SSR mode. Covers the auto-detection
6
+ rules, caveats for dynamic routes and inline content, and a pre-ship checklist.
7
+ ---
8
+
9
+ When you run Dev Portal in SSR mode, [`protectedRoutes`](../configuration/protected-routes.md) is
10
+ enforced beyond the runtime login dialog. The JavaScript chunks containing content for protected
11
+ routes are physically separated from the public bundle and served only through an auth-gated
12
+ endpoint. Unauthenticated users cannot fetch them even if they know the URL.
13
+
14
+ ## Why this exists
15
+
16
+ In a typical SPA build, every page's JavaScript is code-split into a chunk in `/assets/`. Any
17
+ browser can fetch any chunk URL. A runtime `RouteGuard` can block _rendering_ a protected page, but
18
+ the code itself is still downloadable.
19
+
20
+ In SSR mode, the build additionally:
21
+
22
+ 1. Classifies each code-split chunk as public or protected based on which routes it serves.
23
+ 2. Moves protected chunks from the public output into the server bundle, so they're no longer served
24
+ as plain static files.
25
+ 3. Registers an auth-gated route at `/_protected/*` on the SSR adapter that requires a valid session
26
+ cookie.
27
+
28
+ A request to a protected chunk URL without a session returns `401 Unauthorized`. Combined with
29
+ `RouteGuard` on render, protected content stays on the server.
30
+
31
+ ## How classification works
32
+
33
+ At build time, a Vite transform AST-scans your code for route-shaped dynamic imports and records
34
+ `{moduleId → subtree root}` entries in a registry. Two shapes are auto-detected.
35
+
36
+ ### Shape A: object literal with `path`
37
+
38
+ Any object literal with a string `path` property. Every dynamic `import()` inside the object's other
39
+ property values is registered as subtree-scoped at that path.
40
+
41
+ ```ts
42
+ // Standard React Router route
43
+ { path: "/admin", lazy: () => import("./AdminPage") }
44
+
45
+ // Also matches plugin-api's generated code
46
+ openApiPlugin({
47
+ path: "/my-api",
48
+ schemaImports: {
49
+ "...processed/file.js": () => import("...processed/file.js?d=..."),
50
+ },
51
+ });
52
+ ```
53
+
54
+ ### Shape B: dict keyed by route path
55
+
56
+ An object whose keys are route-path strings (start with `/`, contain no `.`) mapping to arrow
57
+ functions that call `import()`.
58
+
59
+ ```ts
60
+ const fileImports = {
61
+ "/docs/intro": () => import("./intro.mdx"),
62
+ "/docs/guides": () => import("./guides.mdx"),
63
+ };
64
+ ```
65
+
66
+ The dot guard keeps file-path dicts (like `{"/abs/path/x.js": ...}`) from being mistaken for route
67
+ dicts.
68
+
69
+ ### From registry to chunking
70
+
71
+ 1. The annotator transform scans every first-party module and populates the registry.
72
+ 2. Rolldown's `manualChunks` callback consults the registry for each module. If any registered
73
+ subtree for that module intersects a `protectedRoutes` pattern, the module goes into a
74
+ `protected-*` chunk.
75
+ 3. After bundling, protected chunks are renamed into a `_protected/` directory and moved from the
76
+ client output to the server output.
77
+ 4. A static-reachability assertion fails the build if any public chunk statically imports a
78
+ protected chunk (which would eagerly pull gated code into the public bundle).
79
+
80
+ ## What's covered out of the box
81
+
82
+ | Content source | Shape | Auto-detected? |
83
+ | -------------------------------- | ----------------------------- | -------------- |
84
+ | MDX docs (`plugin-docs`) | Shape B (route dict) | ✅ |
85
+ | File OpenAPI (`plugin-api`) | Shape A (via `openApiPlugin`) | ✅ |
86
+ | User custom pages with `lazy` | Shape A (`{path, lazy}`) | ✅ |
87
+ | User custom pages with `element` | Not code-split | ❌ (see below) |
88
+ | URL-based OpenAPI (`type: url`) | Fetched at runtime | ❌ (see below) |
89
+ | Raw inline OpenAPI (`type: raw`) | Inlined in main bundle | ❌ (see below) |
90
+
91
+ ## Caveats
92
+
93
+ ### Dynamic route paths
94
+
95
+ The annotator only recognizes string literals. Configs that generate routes with computed paths are
96
+ not detected:
97
+
98
+ ```ts
99
+ // Not detected: path and specifier are template literals.
100
+ navigation: items.map((i) => ({
101
+ type: "custom-page",
102
+ path: `/foo/${i.slug}`,
103
+ lazy: () => import(`./Foo-${i.slug}`),
104
+ }));
105
+ ```
106
+
107
+ **Fix:** nest the dynamic entries under a static-path ancestor so the outer Shape A match catches
108
+ them:
109
+
110
+ ```ts
111
+ {
112
+ type: "category",
113
+ path: "/foo",
114
+ items: items.map((i) => ({
115
+ type: "custom-page",
116
+ path: i.slug,
117
+ lazy: () => import(`./Foo-${i.slug}`),
118
+ })),
119
+ }
120
+ ```
121
+
122
+ The outer `{path: "/foo", ...}` registers every nested dynamic import as subtree-scoped at `/foo`,
123
+ so `protectedRoutes: ["/foo/*"]` covers them all. Alternatively, write the entries out with literal
124
+ paths.
125
+
126
+ ### Inline JSX custom pages
127
+
128
+ Writing
129
+
130
+ ```ts
131
+ { type: "custom-page", path: "/secret", element: <Secret /> }
132
+ ```
133
+
134
+ ships `<Secret />` directly in the main bundle. There's no chunk to gate and no URL to block; the
135
+ runtime `RouteGuard` prevents rendering but the JavaScript is already on the user's machine.
136
+
137
+ **Fix:** switch to `lazy`:
138
+
139
+ ```ts
140
+ { type: "custom-page", path: "/secret", lazy: () => import("./Secret") }
141
+ ```
142
+
143
+ ### URL-based OpenAPI specs
144
+
145
+ `{ type: "url", input: "https://example.com/api.yaml" }` fetches at runtime from whatever origin you
146
+ configure. Auth is your responsibility on that origin. Dev Portal cannot gate a URL it does not serve.
147
+
148
+ ### Raw inline OpenAPI specs
149
+
150
+ `{ type: "raw", input: {...} }` embeds the spec as a JS object literal in the bundle. Same situation
151
+ as inline custom pages: no chunk, no way to gate at the bundle level.
152
+
153
+ ### Third-party and custom plugins
154
+
155
+ If a plugin emits code-split routes in neither Shape A nor Shape B, its chunks aren't detected. Two
156
+ options:
157
+
158
+ 1. Have the plugin emit a detectable shape. Usually the easiest: wrap the generated routes in an
159
+ object with a string `path`.
160
+ 2. Register directly. Plugins can call
161
+ `registerProtectedScope(moduleId, {type: "subtree", root: "/your-path"})` from their Vite `load`
162
+ hook.
163
+
164
+ ## The build-time check
165
+
166
+ If a `protectedRoutes` pattern has no registered content, the build fails:
167
+
168
+ ```
169
+ [zudoku] protectedRoutes patterns with no matching content: "/admin/*".
170
+ Either the pattern is a typo, or the route uses an inline element / dynamic path
171
+ that isn't code-split. Load the route via dynamic import so it gets its own chunk,
172
+ otherwise its JS ships in the public bundle.
173
+ ```
174
+
175
+ Three things to check:
176
+
177
+ 1. **Typo.** Does the pattern match any real route?
178
+ 2. **Dynamic content.** Computed paths? Apply the nested-subtree fix above.
179
+ 3. **Inline content.** Is the route served by an inline JSX element or a raw spec? It cannot be
180
+ gated at the bundle level; move the content into a code-split module.
181
+
182
+ If none of those apply and you're sure the content should be detected, file an issue with a minimal
183
+ reproduction.
184
+
185
+ ## Dev mode and SSG
186
+
187
+ **Dev mode** doesn't chunk-split the same way as production, so the bundle-level gating is absent.
188
+ Only the runtime `RouteGuard` applies. Use a production SSR build to verify gating.
189
+
190
+ **SSG builds** have no server. `protectedRoutes` in SSG falls back to client-side enforcement only:
191
+ `RouteGuard` blocks rendering, but chunks remain publicly fetchable. If content must stay
192
+ server-side, use an SSR adapter.
193
+
194
+ ## Pre-ship checklist
195
+
196
+ - [ ] Build passes (any unmatched `protectedRoutes` pattern fails the build).
197
+ - [ ] Any custom pages meant to be protected use `lazy: () => import(...)`, not `element`.
198
+ - [ ] Any dynamically-generated protected routes are nested under a static-path ancestor.
199
+ - [ ] URL-based and raw inline OpenAPI specs have their own access control at their origin.
200
+ - [ ] Visit a protected chunk URL directly in an unauthenticated browser (grab one from DevTools)
201
+ and confirm you get `401 Unauthorized`.
202
+
203
+ ## Related
204
+
205
+ - [Protected Routes](../configuration/protected-routes.md): the `protectedRoutes` config API.
206
+ - [Authentication](../configuration/authentication.md): wiring up an auth provider so sessions
207
+ exist.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "6.70.48",
3
+ "version": "6.70.49",
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.70.48",
23
- "@zuplo/core": "6.70.48",
24
- "@zuplo/runtime": "6.70.48",
22
+ "@zuplo/cli": "6.70.49",
23
+ "@zuplo/core": "6.70.49",
24
+ "@zuplo/runtime": "6.70.49",
25
25
  "@zuplo/test": "1.4.0"
26
26
  }
27
27
  }