@lukoweb/apitogo 0.2.31 → 0.2.34

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.
Files changed (41) hide show
  1. package/dist/cli/cli.js +436 -153
  2. package/dist/declarations/app/entry.server.d.ts +2 -2
  3. package/dist/declarations/app/main.d.ts +3 -1
  4. package/dist/declarations/cli/platform/client/platform-api.d.ts +0 -4
  5. package/dist/declarations/cli/platform/helpers/deploy-artifact-hash.d.ts +1 -1
  6. package/dist/declarations/cli/platform/helpers/package-files.d.ts +1 -1
  7. package/dist/declarations/cli/platform/helpers/zip.d.ts +1 -1
  8. package/dist/declarations/cli/platform/tools/infrastructure.d.ts +0 -4
  9. package/dist/declarations/config/effective-redirects.d.ts +6 -0
  10. package/dist/declarations/config/header-navigation-guard.d.ts +2 -0
  11. package/dist/declarations/config/resolve-modules.d.ts +1 -4
  12. package/dist/declarations/config/validators/HeaderNavigationSchema.d.ts +1 -2
  13. package/docs/cli/commands.md +19 -0
  14. package/docs/configuration/gateway.md +52 -0
  15. package/docs/guides/customer-account.md +11 -1
  16. package/docs/mcp/tools.md +101 -102
  17. package/package.json +2 -1
  18. package/src/app/demo.tsx +78 -77
  19. package/src/app/entry.client.tsx +115 -107
  20. package/src/app/entry.server.tsx +164 -160
  21. package/src/app/main.tsx +175 -167
  22. package/src/app/standalone.tsx +61 -60
  23. package/src/config/effective-redirects.ts +31 -0
  24. package/src/config/header-navigation-guard.ts +13 -0
  25. package/src/config/resolve-modules.ts +331 -354
  26. package/src/config/v2/home-redirect.ts +104 -98
  27. package/src/config/v2/index.ts +127 -126
  28. package/src/config/v2/ledger.ts +242 -235
  29. package/src/config/v2/resolve.ts +12 -4
  30. package/src/config/v2/rules.ts +716 -714
  31. package/src/config/v2/services.ts +799 -663
  32. package/src/config/v2/workspace.ts +17 -1
  33. package/src/config/validators/HeaderNavigationSchema.ts +42 -44
  34. package/src/lib/assets/powered-by-icon.png +0 -0
  35. package/src/lib/authentication/providers/dev-portal-auth-pages.tsx +667 -602
  36. package/src/lib/authentication/providers/dev-portal.tsx +476 -448
  37. package/src/lib/components/HeaderNavigation.tsx +176 -176
  38. package/src/lib/components/MobileTopNavigation.tsx +283 -283
  39. package/src/lib/components/navigation/PoweredByZudoku.tsx +42 -39
  40. package/src/vite/plugin-offroot-resolve.ts +68 -67
  41. package/src/vite/prerender/prerender.ts +242 -242
@@ -1,7 +1,7 @@
1
1
  import { type RouteObject } from "react-router";
2
2
  import "vite/modulepreload-polyfill";
3
- import { getRoutesByConfig } from "./main.js";
4
- export { getRoutesByConfig };
3
+ import type { ApitogoConfig } from "../config/config.js";
4
+ export declare const getRoutesByConfig: (config: ApitogoConfig) => RouteObject[];
5
5
  export declare const handleRequest: ({ template, request, routes, basePath, bypassProtection, }: {
6
6
  template: string;
7
7
  request: Request;
@@ -2,6 +2,7 @@ import type { RouteObject } from "react-router";
2
2
  import type { HighlighterCore } from "shiki";
3
3
  import "virtual:zudoku-theme.css";
4
4
  import type { ApitogoConfig } from "../config/config.js";
5
+ import type { ResolvedModulesConfig } from "../config/validators/ModulesSchema.js";
5
6
  import "./main.css";
6
7
  import "./polyfills.js";
7
8
  import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
@@ -99,4 +100,5 @@ export declare const getRoutesByOptions: (options: ZudokuContextOptions, enableS
99
100
  ErrorBoundary?: (() => Promise<import("react").ComponentType<{}> | null | undefined>) | undefined;
100
101
  }) | import("react-router").LazyRouteFunction<RouteObject>;
101
102
  })[];
102
- export declare const getRoutesByConfig: (config: ApitogoConfig) => RouteObject[];
103
+ export type ModulesResolver = (config: ApitogoConfig) => ResolvedModulesConfig;
104
+ export declare const getRoutesByConfig: (config: ApitogoConfig, resolveModules: ModulesResolver) => RouteObject[];
@@ -206,9 +206,6 @@ export interface CheckoutSessionResponse {
206
206
  url: string | null;
207
207
  granted?: boolean;
208
208
  }
209
- export interface DeploymentTokenResponse {
210
- token: string;
211
- }
212
209
  export interface ProvisioningJobListItemDto {
213
210
  id: string;
214
211
  resourceType: string;
@@ -538,7 +535,6 @@ export declare class PlatformApiClient {
538
535
  retryAzureInfrastructure(projectId: string): Promise<StartDeployResponse>;
539
536
  getAzureInfrastructureDeployStatus(projectId: string, jobId: string): Promise<DeployStatusResponse>;
540
537
  listProvisioningJobs(projectId: string): Promise<ProvisioningJobListResponse>;
541
- getDeploymentToken(projectId: string, regenerate?: boolean): Promise<DeploymentTokenResponse>;
542
538
  uploadStaticWebDeployment(projectId: string, archivePath: string, env?: string): Promise<StaticWebSiteDeploymentDto>;
543
539
  listSecrets(projectId: string): Promise<ProjectSecretListResponse>;
544
540
  setSecret(projectId: string, name: string, value: string): Promise<SetProjectSecretResponse>;
@@ -1,6 +1,6 @@
1
1
  export declare function sha256File(filePath: string): Promise<string>;
2
2
  export declare function sha256Buffer(data: Buffer | string): Promise<string>;
3
- export declare function hashDirectoryContents(rootDirectory: string): Promise<string>;
3
+ export declare function hashDirectoryContents(rootDirectory: string, extraExcludes?: readonly string[]): Promise<string>;
4
4
  export declare function hashDevPortalSiteSources(siteDirectory: string, options?: {
5
5
  gatewayUrl?: string | null;
6
6
  }): Promise<string>;
@@ -1 +1 @@
1
- export declare function collectPackageableFiles(sourceDirectory: string): Promise<string[]>;
1
+ export declare function collectPackageableFiles(sourceDirectory: string, extraExcludes?: readonly string[]): Promise<string[]>;
@@ -2,5 +2,5 @@ export interface PackageBackendResult {
2
2
  zipPath: string;
3
3
  byteSize: number;
4
4
  }
5
- export declare function packageBackendDirectory(sourceDirectory: string): Promise<PackageBackendResult>;
5
+ export declare function packageBackendDirectory(sourceDirectory: string, extraExcludes?: readonly string[]): Promise<PackageBackendResult>;
6
6
  export declare function cleanupZip(zipPath: string): Promise<void>;
@@ -21,10 +21,6 @@ export declare function handleRetryAzureInfrastructure(client: PlatformApiClient
21
21
  export declare function handleListProvisioningJobs(client: PlatformApiClient, config: ApitogoConfig, args: {
22
22
  projectId?: string;
23
23
  }): Promise<string>;
24
- export declare function handleGetDeploymentToken(client: PlatformApiClient, config: ApitogoConfig, args: {
25
- projectId?: string;
26
- regenerate?: boolean;
27
- }): Promise<string>;
28
24
  export declare function handleGetCustomDomain(client: PlatformApiClient, config: ApitogoConfig, args: {
29
25
  projectId?: string;
30
26
  }): Promise<string>;
@@ -0,0 +1,6 @@
1
+ import type { ResolvedModulesConfig } from "./validators/ModulesSchema.js";
2
+ import type { ZudokuConfig } from "./validators/ZudokuConfig.js";
3
+ export declare const getEffectiveRedirects: (config: ZudokuConfig, resolved: ResolvedModulesConfig) => {
4
+ from: string;
5
+ to: string;
6
+ }[];
@@ -0,0 +1,2 @@
1
+ import type { HeaderNavGroup, HeaderNavItem, HeaderNavLinkItem } from "./validators/HeaderNavigationSchema.js";
2
+ export declare const isHeaderNavGroup: (item: HeaderNavItem | HeaderNavLinkItem | HeaderNavGroup) => item is HeaderNavGroup;
@@ -8,10 +8,7 @@ export declare const resolveDashboardContent: (content?: DashboardContentConfig)
8
8
  export declare const resolveProfileContent: (content?: ProfileContentConfig) => ResolvedProfileContent;
9
9
  export declare const resolvePlansContent: (content?: PlansContentConfig) => ResolvedPlansContent;
10
10
  export declare const resolveModulesConfig: (config: ZudokuConfig) => ResolvedModulesConfig;
11
- export declare const getEffectiveRedirects: (config: ZudokuConfig, resolved: ResolvedModulesConfig) => {
12
- from: string;
13
- to: string;
14
- }[];
11
+ export { getEffectiveRedirects } from "./effective-redirects.js";
15
12
  export declare const getEffectiveDocsConfig: (_config: ZudokuConfig, resolved: ResolvedModulesConfig) => {
16
13
  files: string | string[];
17
14
  publishMarkdown: boolean;
@@ -15800,9 +15800,8 @@ export declare const HeaderNavigationSchema: z.ZodArray<z.ZodUnion<readonly [z.Z
15800
15800
  }, z.core.$strip>>;
15801
15801
  }, z.core.$strip>]>>;
15802
15802
  }, z.core.$strip>]>>;
15803
- export declare const isHeaderNavGroup: (item: HeaderNavItem | HeaderNavLinkItem | HeaderNavGroup) => item is HeaderNavGroup;
15803
+ export { isHeaderNavGroup } from "../header-navigation-guard.js";
15804
15804
  export type HeaderNavLinkItem = z.infer<typeof HeaderNavLinkItemSchema>;
15805
15805
  export type HeaderNavGroup = z.infer<typeof HeaderNavGroupSchema>;
15806
15806
  export type HeaderNavItem = z.infer<typeof HeaderNavItemSchema>;
15807
15807
  export type HeaderNavigation = z.infer<typeof HeaderNavigationSchema>;
15808
- export {};
@@ -58,6 +58,25 @@ See [Make config (CLI)](../configuration/make-config.mdx) for all `config` flags
58
58
 
59
59
  Env: `APITOGO_API_KEY_ID`, `APITOGO_API_SECRET`. Optional: `APITOGO_API_URL`.
60
60
 
61
+ ## Config version 2: add a service
62
+
63
+ ```bash
64
+ npx apitogo add gateway
65
+ ```
66
+
67
+ `add` puts one service (`portal`, `gateway`, `identity` or `plans`) into `apitogo.config.json`. In a
68
+ terminal it **asks** for what you did not pass as a flag: for the gateway how it reaches your API
69
+ (an address you host, or code the platform runs, with the folder, runtime and version) and which
70
+ OpenAPI file to use. For an OIDC identity it asks for the issuer, and for external docs the address
71
+ of the docs site. It shows the change and asks before it writes.
72
+
73
+ Some services need another one. `plans` needs the gateway and an identity source, and a portal that
74
+ requires login needs an identity source. `add` then offers to add the missing service first, asks
75
+ for its values, and goes on with the one you named.
76
+
77
+ With `--yes`, `--json` or without a terminal it never asks: a missing value is an error that names
78
+ the flag to pass, and `--dry-run` shows the change without writing it.
79
+
61
80
  ## Config version 2: create the project, then deploy
62
81
 
63
82
  ```bash
@@ -194,6 +194,53 @@ npx apitogo secrets set GATEWAY_SECRET
194
194
  The value is a reference, never the secret itself. The secret is stored encrypted and never shown
195
195
  again. Then make your API refuse any call without that header.
196
196
 
197
+ ## Run your API on the platform (`managed` origin)
198
+
199
+ If you have no place to host your API, the platform can run your code. Set the origin mode to
200
+ `managed` and point `source` at the folder with your code:
201
+
202
+ ```json
203
+ "gateway": {
204
+ "origin": {
205
+ "mode": "managed",
206
+ "source": "backend",
207
+ "runtime": "nodejs",
208
+ "runtimeVersion": "NODE_22_LTS",
209
+ "healthPath": "/health",
210
+ "exclude": ["tests/"]
211
+ },
212
+ "specs": ["openapi.json"]
213
+ }
214
+ ```
215
+
216
+ | Field | Meaning |
217
+ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
218
+ | `source` | Folder with your code, relative to the config. Files in its `.gitignore` and in `exclude` are not uploaded. |
219
+ | `runtime` | `nodejs`, `python` or `dotnet`. |
220
+ | `runtimeVersion` | For example `NODE_22_LTS`. The platform lists the allowed values. |
221
+ | `healthPath` | Path the platform probes to check that your API is up. |
222
+ | `exclude` | More paths to leave out, in `.gitignore` syntax. |
223
+
224
+ `npx apitogo project create` prepares the hosting for your code. `npx apitogo deploy` then uploads
225
+ the OpenAPI file and the config, uploads your code and waits until it runs, and the gateway starts
226
+ sending calls to it. A deploy with the same code uploads nothing. A .NET project is published for
227
+ you (this needs the .NET SDK on your machine), or you can point `source` at a folder that is already
228
+ published.
229
+
230
+ Your code can also be reached by its own address, so check that a call came through the gateway. The
231
+ platform gives your code two settings for this: `APITOGO_ORIGIN_SECRET_HEADER` (the header name) and
232
+ `APITOGO_ORIGIN_SECRET` (the value). The gateway sends that header with every call. Refuse any
233
+ request without it, as in
234
+ [Keep your API from being called directly](#keep-your-api-from-being-called-directly):
235
+
236
+ ```js
237
+ const header = process.env.APITOGO_ORIGIN_SECRET_HEADER.toLowerCase();
238
+ if (req.headers[header] !== process.env.APITOGO_ORIGIN_SECRET) {
239
+ res.writeHead(403).end();
240
+ return;
241
+ }
242
+ ```
243
+
197
244
  ## 4. Try it and check it
198
245
 
199
246
  Run these before you deploy:
@@ -219,3 +266,8 @@ curl -i https://YOUR-GATEWAY-ADDRESS/orders
219
266
  | `404` | The path is not in your OpenAPI file. |
220
267
  | `429` | The rate limit was reached. |
221
268
  | `502` or `504` | Your API did not answer. Check `origin.url` and `healthPath`. |
269
+
270
+ A change is live a few seconds after `deploy` reports it ready: the gateway keeps answering with the
271
+ previous rules for up to about ten seconds. If a test right after a deploy shows the old behavior,
272
+ wait a moment and try again. The same delay applies when you remove a gateway: its keys stop working
273
+ within seconds, not at the same instant.
@@ -47,8 +47,18 @@ If a payment fails, Stripe retries it. The subscription shows as past due. When
47
47
  cancels it, the plan ends and its keys stop working with `401`. The customer is not moved to a free
48
48
  plan on their own. They can subscribe to one on the **Plans** page.
49
49
 
50
+ ## Cancelling and refunds
51
+
52
+ - **The customer cancels** on the **Plans** page. The subscription ends in Stripe at once, the plan
53
+ ends and the customer's keys stop working with `401`.
54
+ - **You cancel** a subscription in your Stripe dashboard. Stripe tells the portal, and the plan ends
55
+ the same way.
56
+ - **A refund** is made in your Stripe dashboard. A refund alone does not end the plan: the customer
57
+ keeps the key until the subscription is cancelled. Cancel it as well if the customer should lose
58
+ access. The portal has no refund screen.
59
+
50
60
  What you see is in your own Stripe account: payments, customers and refunds. APItoGo does not take a
51
- share and does not issue refunds. Tax, trials and refunds are not handled by the portal.
61
+ share and does not issue refunds. Tax and trials are not handled by the portal.
52
62
 
53
63
  ## API keys
54
64
 
package/docs/mcp/tools.md CHANGED
@@ -1,102 +1,101 @@
1
- ---
2
- title: MCP tools
3
- description: APItoGo MCP tool catalog by category and hand-edit exceptions.
4
- sidebar_icon: wrench
5
- ---
6
-
7
- Tools are exposed by the APItoGo MCP server. Prefer **`apply_product_intent`** for create / shape /
8
- go-live. Use granular tools for advanced edits, debugging, or CI.
9
-
10
- ## Lifecycle (prefer these)
11
-
12
- | Tool | Role |
13
- | ------------------------------------ | ---------------------------------------------- |
14
- | `apply_product_intent` | Shape or goLive from a product intent |
15
- | `create_dev_portal` | Scaffold site (+ optional project bootstrap) |
16
- | `check_dev_portal_publish_readiness` | Pre-publish checklist |
17
- | `publish_dev_portal` | Publish portal + plans (+ optional backend) |
18
- | `verify_dev_portal_live` | Post-publish verification |
19
- | `bootstrap_dev_portal` | CI one-shot provision + deploy |
20
- | `bootstrap_project` | Create platform project only (plan unselected) |
21
- | `teardown_project` | Tear down a project |
22
-
23
- ## Site shaping
24
-
25
- | Tool | Role |
26
- | ---------------------------------- | ------------------------------------------------------------------------- |
27
- | `update_dev_portal_manifest` | Plans, branding, backend, projectId |
28
- | `set_dev_portal_openapi` | OpenAPI / API reference |
29
- | `set_dev_portal_theme` | Colors and fonts |
30
- | `add_dev_portal_page` | Add a TSX docs page (site components; `template`: docs\|guide\|marketing) |
31
- | `update_dev_portal_page` | Edit a docs page |
32
- | `scaffold_dev_portal_landing_page` | Scaffold missing landing file |
33
- | `get_dev_portal_landing_guide` | Landing component catalog |
34
- | `preview_dev_portal_site` | Start / restart local preview |
35
- | `build_dev_portal_site` | Production build |
36
-
37
- Hosted page CRUD also exists (`list/create/delete/rename/reorder_dev_portal_pages`) for the platform
38
- API surface.
39
-
40
- ## Projects and platform billing
41
-
42
- | Tool | Role |
43
- | ------------------------------------------- | ------------------------------------- |
44
- | `whoami`, `list_projects`, `get_project`, … | Tenant / project CRUD |
45
- | `list_platform_plans` | Free / Starter / Professional + quota |
46
- | `ensure_platform_plan` | Select or checkout platform plan |
47
- | `wait_for_platform_plan` | Poll until active |
48
- | `get_subscription` | Current subscription |
49
- | `select_free_plan` | Free hosting |
50
- | `create_checkout_session` | Stripe checkout for paid hosting |
51
-
52
- ## Backend and OpenAPI
53
-
54
- | Tool | Role |
55
- | ----------------------- | ------------------------ |
56
- | `validate_openapi` | Validate OpenAPI |
57
- | `update_openapi` | Update stored OpenAPI |
58
- | `package_backend` | Package backend artifact |
59
- | `deploy_backend` | Deploy API hub |
60
- | `get_backend_summary` | Backend status |
61
- | `get_deployment_status` | Deployment job status |
62
- | `get_gateway_readiness` | Gateway readiness |
63
-
64
- ## Gateway
65
-
66
- | Tool | Role |
67
- | ------------------------------------------------------------------ | ------------------------ |
68
- | `list/get/create/update/patch_gateway_plan` | Plan CRUD |
69
- | `add_actions_to_gateway_plan` / `remove_actions_from_gateway_plan` | Attach ops |
70
- | `set_action_public` | Public routes |
71
- | `upsert_entitlement` | Entitlements |
72
- | `configure_gateway_baseline` | Baseline policies |
73
- | `get/update_gateway_settings` | Settings |
74
- | `get/update_gateway_auth` | Gateway auth |
75
- | `sync_gateway_plans_from_manifest` | Post-publish action sync |
76
- | `reorder_gateway_plans_from_manifest` | Plan order |
77
-
78
- ## Infrastructure and deploy
79
-
80
- | Tool | Role |
81
- | ------------------------------------------------------ | ---------------- |
82
- | `activate_module` | Activate modules |
83
- | `get_infrastructure_status` / Azure variants | Infra status |
84
- | `list_provisioning_jobs`, `wait_for_job` | Jobs |
85
- | `get_deployment_token` | CLI deploy token |
86
- | `get/set/delete_custom_domain` | Custom domain |
87
- | `get_dev_portal_deploy_config`, `deploy_dev_portal`, … | SWA deploy |
88
-
89
- ## Hand-edit exceptions
90
-
91
- | Change | Where |
92
- | ----------------- | -------------------------------------------------------- |
93
- | Home page content | `landing/LandingPage.tsx` |
94
- | Site footer | `apitogo.config.json` → `modules.landing.content.footer` |
95
-
96
- There is **no** `update_dev_portal_landing` tool for arbitrary home content.
97
-
98
- ## Related
99
-
100
- - [Overview](./overview.md)
101
- - [Shape](./shape.md)
102
- - [Go live](./go-live.md)
1
+ ---
2
+ title: MCP tools
3
+ description: APItoGo MCP tool catalog by category and hand-edit exceptions.
4
+ sidebar_icon: wrench
5
+ ---
6
+
7
+ Tools are exposed by the APItoGo MCP server. Prefer **`apply_product_intent`** for create / shape /
8
+ go-live. Use granular tools for advanced edits, debugging, or CI.
9
+
10
+ ## Lifecycle (prefer these)
11
+
12
+ | Tool | Role |
13
+ | ------------------------------------ | ---------------------------------------------- |
14
+ | `apply_product_intent` | Shape or goLive from a product intent |
15
+ | `create_dev_portal` | Scaffold site (+ optional project bootstrap) |
16
+ | `check_dev_portal_publish_readiness` | Pre-publish checklist |
17
+ | `publish_dev_portal` | Publish portal + plans (+ optional backend) |
18
+ | `verify_dev_portal_live` | Post-publish verification |
19
+ | `bootstrap_dev_portal` | CI one-shot provision + deploy |
20
+ | `bootstrap_project` | Create platform project only (plan unselected) |
21
+ | `teardown_project` | Tear down a project |
22
+
23
+ ## Site shaping
24
+
25
+ | Tool | Role |
26
+ | ---------------------------------- | ------------------------------------------------------------------------- |
27
+ | `update_dev_portal_manifest` | Plans, branding, backend, projectId |
28
+ | `set_dev_portal_openapi` | OpenAPI / API reference |
29
+ | `set_dev_portal_theme` | Colors and fonts |
30
+ | `add_dev_portal_page` | Add a TSX docs page (site components; `template`: docs\|guide\|marketing) |
31
+ | `update_dev_portal_page` | Edit a docs page |
32
+ | `scaffold_dev_portal_landing_page` | Scaffold missing landing file |
33
+ | `get_dev_portal_landing_guide` | Landing component catalog |
34
+ | `preview_dev_portal_site` | Start / restart local preview |
35
+ | `build_dev_portal_site` | Production build |
36
+
37
+ Hosted page CRUD also exists (`list/create/delete/rename/reorder_dev_portal_pages`) for the platform
38
+ API surface.
39
+
40
+ ## Projects and platform billing
41
+
42
+ | Tool | Role |
43
+ | ------------------------------------------- | ------------------------------------- |
44
+ | `whoami`, `list_projects`, `get_project`, … | Tenant / project CRUD |
45
+ | `list_platform_plans` | Free / Starter / Professional + quota |
46
+ | `ensure_platform_plan` | Select or checkout platform plan |
47
+ | `wait_for_platform_plan` | Poll until active |
48
+ | `get_subscription` | Current subscription |
49
+ | `select_free_plan` | Free hosting |
50
+ | `create_checkout_session` | Stripe checkout for paid hosting |
51
+
52
+ ## Backend and OpenAPI
53
+
54
+ | Tool | Role |
55
+ | ----------------------- | ------------------------ |
56
+ | `validate_openapi` | Validate OpenAPI |
57
+ | `update_openapi` | Update stored OpenAPI |
58
+ | `package_backend` | Package backend artifact |
59
+ | `deploy_backend` | Deploy API hub |
60
+ | `get_backend_summary` | Backend status |
61
+ | `get_deployment_status` | Deployment job status |
62
+ | `get_gateway_readiness` | Gateway readiness |
63
+
64
+ ## Gateway
65
+
66
+ | Tool | Role |
67
+ | ------------------------------------------------------------------ | ------------------------ |
68
+ | `list/get/create/update/patch_gateway_plan` | Plan CRUD |
69
+ | `add_actions_to_gateway_plan` / `remove_actions_from_gateway_plan` | Attach ops |
70
+ | `set_action_public` | Public routes |
71
+ | `upsert_entitlement` | Entitlements |
72
+ | `configure_gateway_baseline` | Baseline policies |
73
+ | `get/update_gateway_settings` | Settings |
74
+ | `get/update_gateway_auth` | Gateway auth |
75
+ | `sync_gateway_plans_from_manifest` | Post-publish action sync |
76
+ | `reorder_gateway_plans_from_manifest` | Plan order |
77
+
78
+ ## Infrastructure and deploy
79
+
80
+ | Tool | Role |
81
+ | ------------------------------------------------------ | ---------------- |
82
+ | `activate_module` | Activate modules |
83
+ | `get_infrastructure_status` / Azure variants | Infra status |
84
+ | `list_provisioning_jobs`, `wait_for_job` | Jobs |
85
+ | `get/set/delete_custom_domain` | Custom domain |
86
+ | `get_dev_portal_deploy_config`, `deploy_dev_portal`, … | SWA deploy |
87
+
88
+ ## Hand-edit exceptions
89
+
90
+ | Change | Where |
91
+ | ----------------- | -------------------------------------------------------- |
92
+ | Home page content | `landing/LandingPage.tsx` |
93
+ | Site footer | `apitogo.config.json` → `modules.landing.content.footer` |
94
+
95
+ There is **no** `update_dev_portal_landing` tool for arbitrary home content.
96
+
97
+ ## Related
98
+
99
+ - [Overview](./overview.md)
100
+ - [Shape](./shape.md)
101
+ - [Go live](./go-live.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lukoweb/apitogo",
3
- "version": "0.2.31",
3
+ "version": "0.2.34",
4
4
  "type": "module",
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -171,6 +171,7 @@
171
171
  "build": "esbuild src/cli/cli.ts src/vite/prerender/worker.ts --outdir=dist/cli --entry-names=[name] --bundle --format=esm --packages=external --target=node20 --platform=node --log-level=error",
172
172
  "postbuild": "tsx scripts/check-external-deps.ts",
173
173
  "typecheck": "tsc --project tsconfig.app.json --noEmit",
174
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
174
175
  "generate:types": "tsx scripts/generate-types.js && tsx scripts/generate-flat-config.js",
175
176
  "build:standalone": "vite build --mode standalone --config vite.standalone.config.ts --log-level=error",
176
177
  "prepack": "npm run build && tsx scripts/generate-publish-exports.ts",
package/src/app/demo.tsx CHANGED
@@ -1,77 +1,78 @@
1
- import logger from "loglevel";
2
- import { createRoot } from "react-dom/client";
3
- import { createBrowserRouter } from "react-router";
4
- import type { ZudokuConfig } from "../config/validators/ZudokuConfig.js";
5
- import { Bootstrap } from "../lib/components/Bootstrap.js";
6
- import DemoAnnouncement from "../lib/demo/DemoAnnouncement.js";
7
- import "../lib/util/logInit.js";
8
- import "./main.css";
9
- import { openApiPlugin } from "../lib/plugins/openapi/index.js";
10
- import { getRoutesByConfig } from "./main.js";
11
-
12
- const apiUrl = new URL(window.location.href).searchParams.get("api-url");
13
- const logoUrl = new URL(window.location.href).searchParams.get("logo-url");
14
- const logoWidth = new URL(window.location.href).searchParams.get("logo-width");
15
- const title =
16
- new URL(window.location.href).searchParams.get("title") ?? "Zudoku Demo";
17
-
18
- if (!apiUrl) {
19
- throw new Error(
20
- "No API URL in query parameters. Please provide an API URL using the `api-url` query parameter.",
21
- );
22
- }
23
-
24
- logger.info(`API URL: ${apiUrl}`);
25
-
26
- const root =
27
- document.getElementById("zudoku") ?? document.getElementById("root");
28
-
29
- if (!root) {
30
- throw new Error("No div found with id root");
31
- }
32
-
33
- // IMPORTANT: This component must not contain tailwind classes
34
- // This directory is not processed by the tailwind plugin
35
-
36
- const config: ZudokuConfig = {
37
- site: {
38
- title,
39
- banner: {
40
- message: <DemoAnnouncement />,
41
- },
42
- },
43
- navigation: [
44
- {
45
- type: "link",
46
- to: "/",
47
- label: "API Reference",
48
- },
49
- ],
50
- plugins: [
51
- // Using the plugin directly because there's no config file to load in the virtual plugins
52
- openApiPlugin({
53
- type: "url",
54
- input: apiUrl,
55
- path: "/",
56
- }),
57
- ],
58
- } satisfies ZudokuConfig;
59
-
60
- if (logoUrl && logoWidth) {
61
- config.site = {
62
- ...config.site,
63
- logo: {
64
- src: {
65
- light: logoUrl,
66
- dark: logoUrl,
67
- },
68
- width: logoWidth,
69
- },
70
- };
71
- }
72
-
73
- const routes = getRoutesByConfig(config);
74
- const router = createBrowserRouter(routes, {
75
- basename: window.location.pathname,
76
- });
77
- createRoot(root).render(<Bootstrap router={router} />);
1
+ import logger from "loglevel";
2
+ import { createRoot } from "react-dom/client";
3
+ import { createBrowserRouter } from "react-router";
4
+ import { resolveModulesConfig } from "../config/resolve-modules.js";
5
+ import type { ZudokuConfig } from "../config/validators/ZudokuConfig.js";
6
+ import { Bootstrap } from "../lib/components/Bootstrap.js";
7
+ import "../lib/util/logInit.js";
8
+ import "./main.css";
9
+ import DemoAnnouncement from "../lib/demo/DemoAnnouncement.js";
10
+ import { openApiPlugin } from "../lib/plugins/openapi/index.js";
11
+ import { getRoutesByConfig } from "./main.js";
12
+
13
+ const apiUrl = new URL(window.location.href).searchParams.get("api-url");
14
+ const logoUrl = new URL(window.location.href).searchParams.get("logo-url");
15
+ const logoWidth = new URL(window.location.href).searchParams.get("logo-width");
16
+ const title =
17
+ new URL(window.location.href).searchParams.get("title") ?? "Zudoku Demo";
18
+
19
+ if (!apiUrl) {
20
+ throw new Error(
21
+ "No API URL in query parameters. Please provide an API URL using the `api-url` query parameter.",
22
+ );
23
+ }
24
+
25
+ logger.info(`API URL: ${apiUrl}`);
26
+
27
+ const root =
28
+ document.getElementById("zudoku") ?? document.getElementById("root");
29
+
30
+ if (!root) {
31
+ throw new Error("No div found with id root");
32
+ }
33
+
34
+ // IMPORTANT: This component must not contain tailwind classes
35
+ // This directory is not processed by the tailwind plugin
36
+
37
+ const config: ZudokuConfig = {
38
+ site: {
39
+ title,
40
+ banner: {
41
+ message: <DemoAnnouncement />,
42
+ },
43
+ },
44
+ navigation: [
45
+ {
46
+ type: "link",
47
+ to: "/",
48
+ label: "API Reference",
49
+ },
50
+ ],
51
+ plugins: [
52
+ // Using the plugin directly because there's no config file to load in the virtual plugins
53
+ openApiPlugin({
54
+ type: "url",
55
+ input: apiUrl,
56
+ path: "/",
57
+ }),
58
+ ],
59
+ } satisfies ZudokuConfig;
60
+
61
+ if (logoUrl && logoWidth) {
62
+ config.site = {
63
+ ...config.site,
64
+ logo: {
65
+ src: {
66
+ light: logoUrl,
67
+ dark: logoUrl,
68
+ },
69
+ width: logoWidth,
70
+ },
71
+ };
72
+ }
73
+
74
+ const routes = getRoutesByConfig(config, resolveModulesConfig);
75
+ const router = createBrowserRouter(routes, {
76
+ basename: window.location.pathname,
77
+ });
78
+ createRoot(root).render(<Bootstrap router={router} />);