zuplo 7.13.3 → 7.13.5

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/docs/cli/lint.mdx CHANGED
@@ -96,6 +96,61 @@ applies_to:
96
96
  usage="$0 lint [options]"
97
97
  >
98
98
 
99
+ `zuplo lint` checks the OpenAPI files in your project's `config/` directory and
100
+ `config/policies.json` for missing fields, undefined policies, invalid policy
101
+ options, and Zuplo conventions. It runs locally and doesn't need an API key. See
102
+ [Linting your API](../articles/api-lint.mdx) for an overview of what it checks.
103
+
104
+ The command reads its settings from `zuplo.lint.jsonc` (or `zuplo.lint.json`)
105
+ in the project directory.
106
+ See [Lint configuration](../articles/api-lint-configuration.mdx) for presets,
107
+ rule severities, required policies, and breaking change detection.
108
+
109
+ ## Exit codes
110
+
111
+ | Code | Meaning |
112
+ | ---- | --------------------------------------------------------------------------------------------------- |
113
+ | `0` | No results at or above the failure threshold. |
114
+ | `1` | The linter found results at or above the failure threshold. |
115
+ | `2` | The linter couldn't run: the directory isn't a Zuplo project, or the configuration file is invalid. |
116
+
117
+ ## Common use cases
118
+
119
+ ### Lint before you commit
120
+
121
+ ```bash
122
+ npx zuplo lint
123
+ ```
124
+
125
+ ### Apply automatic fixes
126
+
127
+ `--fix` adds missing `operationId` values and removes empty inbound policy
128
+ arrays, then reports what's left. See
129
+ [Fix problems automatically](../articles/api-lint.mdx#fix-problems-automatically).
130
+
131
+ ```bash
132
+ npx zuplo lint --fix
133
+ ```
134
+
135
+ ### List the rules you can use
136
+
137
+ ```bash
138
+ npx zuplo lint --list-rules
139
+ ```
140
+
141
+ Add `--format json` for machine-readable output.
142
+
143
+ ### Lint in CI
144
+
145
+ ```bash
146
+ npx zuplo lint --format sarif > zuplo-lint.sarif
147
+ ```
148
+
149
+ See [Lint in CI/CD](../articles/api-lint-ci-cd.mdx) for GitHub Actions
150
+ workflows, including code scanning, and
151
+ [Breaking change detection](../articles/api-lint-breaking-changes.mdx) for
152
+ comparing your API against a Git branch.
153
+
99
154
  </CliCommand>
100
155
 
101
156
  ## Global options
@@ -104,3 +159,12 @@ The following global options are available for all commands:
104
159
 
105
160
  - [`--help`](./global-options.mdx#help)
106
161
  - [`--api-key`](./global-options.mdx#api-key)
162
+
163
+ ## Additional resources
164
+
165
+ - [Linting your API](../articles/api-lint.mdx)
166
+ - [Lint configuration](../articles/api-lint-configuration.mdx)
167
+ - [Lint rules reference](../articles/api-lint-rules.mdx)
168
+ - [Lint in CI/CD](../articles/api-lint-ci-cd.mdx)
169
+ - [Custom lint rules](../articles/api-lint-custom-rules.mdx)
170
+ - [Breaking change detection](../articles/api-lint-breaking-changes.mdx)
@@ -0,0 +1,70 @@
1
+ ---
2
+ additional-resources:
3
+ - name: Linting your API
4
+ href: ../articles/api-lint.mdx
5
+ - name: Lint configuration
6
+ href: ../articles/api-lint-configuration.mdx
7
+ - name: Lint rules reference
8
+ href: ../articles/api-lint-rules.mdx
9
+ - name: Lint in CI/CD
10
+ href: ../articles/api-lint-ci-cd.mdx
11
+ - name: Custom lint rules
12
+ href: ../articles/api-lint-custom-rules.mdx
13
+ - name: Breaking change detection
14
+ href: ../articles/api-lint-breaking-changes.mdx
15
+ ---
16
+
17
+ `zuplo lint` checks the OpenAPI files in your project's `config/` directory and
18
+ `config/policies.json` for missing fields, undefined policies, invalid policy
19
+ options, and Zuplo conventions. It runs locally and doesn't need an API key. See
20
+ [Linting your API](../articles/api-lint.mdx) for an overview of what it checks.
21
+
22
+ The command reads its settings from `zuplo.lint.jsonc` (or `zuplo.lint.json`)
23
+ in the project directory.
24
+ See [Lint configuration](../articles/api-lint-configuration.mdx) for presets,
25
+ rule severities, required policies, and breaking change detection.
26
+
27
+ ## Exit codes
28
+
29
+ | Code | Meaning |
30
+ | ---- | --------------------------------------------------------------------------------------------------- |
31
+ | `0` | No results at or above the failure threshold. |
32
+ | `1` | The linter found results at or above the failure threshold. |
33
+ | `2` | The linter couldn't run: the directory isn't a Zuplo project, or the configuration file is invalid. |
34
+
35
+ ## Common use cases
36
+
37
+ ### Lint before you commit
38
+
39
+ ```bash
40
+ npx zuplo lint
41
+ ```
42
+
43
+ ### Apply automatic fixes
44
+
45
+ `--fix` adds missing `operationId` values and removes empty inbound policy
46
+ arrays, then reports what's left. See
47
+ [Fix problems automatically](../articles/api-lint.mdx#fix-problems-automatically).
48
+
49
+ ```bash
50
+ npx zuplo lint --fix
51
+ ```
52
+
53
+ ### List the rules you can use
54
+
55
+ ```bash
56
+ npx zuplo lint --list-rules
57
+ ```
58
+
59
+ Add `--format json` for machine-readable output.
60
+
61
+ ### Lint in CI
62
+
63
+ ```bash
64
+ npx zuplo lint --format sarif > zuplo-lint.sarif
65
+ ```
66
+
67
+ See [Lint in CI/CD](../articles/api-lint-ci-cd.mdx) for GitHub Actions
68
+ workflows, including code scanning, and
69
+ [Breaking change detection](../articles/api-lint-breaking-changes.mdx) for
70
+ comparing your API against a Git branch.
@@ -9,6 +9,22 @@ applies_to:
9
9
  If you're dealing with multiple APIs and multiple OpenAPI files, the API Catalog comes in handy. It
10
10
  creates an overview of all your APIs and lets you organize them into categories and tags.
11
11
 
12
+ ## Categories and Tags
13
+
14
+ Each entry in an API's `categories` array has two fields, `label` and `tags`, which serve different
15
+ purposes:
16
+
17
+ - **`label`** is the primary grouping. The catalog page renders one filter chip per unique label, so
18
+ this is what users click to narrow the list. An API can belong to multiple categories by adding
19
+ multiple entries to the array.
20
+ - **`tags`** are secondary descriptors attached to that category. They do _not_ get their own filter
21
+ chip. Instead, they are matched against the search input and rendered as additional badges on the
22
+ API card (alongside the label). Use them for finer-grained keywords that should help users
23
+ discover an API without cluttering the top-level filters.
24
+
25
+ For example, `{ label: "Payments", tags: ["billing", "subscriptions"] }` puts the API under the
26
+ "Payments" filter chip and adds "billing" and "subscriptions" as searchable badges on its card.
27
+
12
28
  ## Enable API Catalog
13
29
 
14
30
  To enable the API Catalog, add a `catalogs` object to your Dev Portal configuration file.
@@ -0,0 +1,217 @@
1
+ ---
2
+ title: Blog
3
+ navigation_icon: newspaper
4
+ applies_to:
5
+ product: developer-portal
6
+ hosting: all
7
+ ---
8
+
9
+ Dev Portal can publish a blog next to your documentation and API reference. Posts are Markdown or MDX
10
+ files in a folder of your project: add a file and it shows up in the blog, with a paginated index,
11
+ tag pages, a "Recent posts" sidebar and an RSS feed.
12
+
13
+ :::caution{title="Beta"}
14
+
15
+ The blog plugin is in beta. Its options, frontmatter fields and generated URLs may still change in a
16
+ minor release. Feedback is welcome in [GitHub issues](https://github.com/zuplo/zudoku/issues).
17
+
18
+ :::
19
+
20
+ ## Enable the blog
21
+
22
+ Add the blog plugin to the `plugins` of your config. Every option has a default:
23
+
24
+ ```tsx title="zudoku.config.tsx"
25
+ import { blogPlugin } from "zudoku/plugins/blog";
26
+
27
+ export default {
28
+ plugins: [blogPlugin()],
29
+ };
30
+ ```
31
+
32
+ Then put your posts in the `blog` folder at the root of your project:
33
+
34
+ ```text title="File tree"
35
+ blog/
36
+ ├── 2025-03-14-hello-world.md → /blog/hello-world
37
+ ├── 2025-04-02-launch-week/
38
+ │ ├── index.mdx → /blog/launch-week
39
+ │ └── screenshot.png
40
+ └── release-notes/
41
+ └── 2025-05-20-v2.md → /blog/release-notes/v2
42
+ ```
43
+
44
+ To link to the blog from the top navigation, add a link to your [navigation](./navigation.mdx):
45
+
46
+ ```tsx title="zudoku.config.tsx"
47
+ export default {
48
+ navigation: [
49
+ // ...
50
+ { type: "link", to: "/blog", label: "Blog", icon: "newspaper" },
51
+ ],
52
+ };
53
+ ```
54
+
55
+ ## Writing posts
56
+
57
+ The file name sets the URL and the date of a post: a `YYYY-MM-DD-` prefix is the publish date and
58
+ the rest is the slug. A post can also be a folder with an `index.md` or `index.mdx` file, which
59
+ keeps its images next to it. Folders that aren't dated stay part of the URL.
60
+
61
+ Some files are not posts:
62
+
63
+ - Other Markdown files in a post's folder, such as partials imported by its `index.mdx` or a
64
+ `README.md`
65
+ - Files and folders whose name starts with `_`, e.g. `_drafts/` or `_snippet.mdx`
66
+ - Posts whose URL is taken by the blog's own pages: `<path>/tags`, `<path>/tags/*`, `<path>/page/*`
67
+ and `<path>/rss.xml`. These are skipped with a warning.
68
+
69
+ Link to other posts by their file, e.g. `[Launch](./2025-04-02-launch-week/index.mdx)`, and the link
70
+ points to the post's URL.
71
+
72
+ Posts support everything [Markdown and MDX pages](../markdown/overview.md) do, including
73
+ [admonitions](../markdown/admonitions.md), [code blocks](../markdown/code-blocks.md) and React
74
+ components.
75
+
76
+ ```md title="blog/2025-03-14-hello-world.md"
77
+ ---
78
+ title: Hello World
79
+ description: The first post on our new developer blog.
80
+ authors: [jane]
81
+ tags: [Announcements, API]
82
+ ---
83
+
84
+ This paragraph is the excerpt shown on the blog index page.
85
+
86
+ ## A section
87
+
88
+ The post continues here.
89
+ ```
90
+
91
+ ### Frontmatter
92
+
93
+ | Field | Description |
94
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
95
+ | `title` | Title of the post. Defaults to the first `# Heading`, which is then not repeated in the post body. |
96
+ | `description` | Shown on the index page, in the feed and as the meta description. Defaults to the first paragraph. |
97
+ | `date` | Publish date, e.g. `2025-03-14` or `2025-03-14T09:00:00Z`. Defaults to the date in the file name, then the date of the commit that added the file (needs the full git history), then the file's modification time. |
98
+ | `slug` | Overrides the URL: `slug: launch` serves the post at `/blog/launch`. |
99
+ | `authors` | Author keys from [`authors`](#authors), or inline objects such as `{ name: "Jane Doe", title: "Engineer" }`. |
100
+ | `tags` | List of tags. Each tag gets a page listing its posts. |
101
+ | `image` | Image used as `og:image` when the post is shared. An absolute URL or a path in the `public` folder, e.g. `/cover.png`. |
102
+ | `draft` | When `true`, the post is only shown in development. |
103
+ | `toc` | Set to `false` to hide the table of contents. |
104
+ | `seo` | `title` and `description` that override the browser title and meta description only. |
105
+
106
+ Posts are sorted by date, newest first.
107
+
108
+ ## Plugin options
109
+
110
+ ```tsx title="zudoku.config.tsx"
111
+ import { blogPlugin } from "zudoku/plugins/blog";
112
+
113
+ export default {
114
+ plugins: [
115
+ blogPlugin({
116
+ files: "/blog/**/*.{md,mdx}",
117
+ path: "/blog",
118
+ title: "Blog",
119
+ description: "News and updates from the team.",
120
+ postsPerPage: 10,
121
+ showReadingTime: true,
122
+ authors: {
123
+ jane: {
124
+ name: "Jane Doe",
125
+ title: "Developer Advocate",
126
+ url: "https://example.com/jane",
127
+ imageUrl: "https://example.com/jane.png",
128
+ },
129
+ },
130
+ sidebar: { title: "Recent posts", count: 5 },
131
+ feed: true,
132
+ }),
133
+ ],
134
+ };
135
+ ```
136
+
137
+ ### `files`
138
+
139
+ **Type:** `string | string[]`
140
+ **Default:** `"/blog/**/*.{md,mdx}"`
141
+
142
+ Glob patterns for the post files. Keep them outside of [`docs.files`](./docs.md#files) so a post
143
+ isn't also published as a documentation page.
144
+
145
+ ### `path`
146
+
147
+ **Type:** `string`
148
+ **Default:** `"/blog"`
149
+
150
+ The route the blog is served under. The index is at `path`, further index pages at `path/page/2`,
151
+ tags at `path/tags` and posts at `path/<slug>`.
152
+
153
+ ### `title` and `description`
154
+
155
+ **Type:** `string`
156
+ **Default:** `"Blog"` and none
157
+
158
+ Heading and introduction of the index page. Both are also used for the RSS feed.
159
+
160
+ ### `postsPerPage`
161
+
162
+ **Type:** `number`
163
+ **Default:** `10`
164
+
165
+ Number of posts on each page of the index.
166
+
167
+ ### `showReadingTime`
168
+
169
+ **Type:** `boolean`
170
+ **Default:** `true`
171
+
172
+ Shows an estimated reading time next to the date of each post.
173
+
174
+ ### `authors`
175
+
176
+ **Type:** `Record<string, { name: string; title?: string; url?: string; imageUrl?: string }>`
177
+ **Default:** `{}`
178
+
179
+ Authors that posts reference by key in their `authors` frontmatter, so their details are kept in one
180
+ place. Authors without an `imageUrl` show their initial instead.
181
+
182
+ ### `sidebar`
183
+
184
+ **Type:** `{ title?: string; count?: number } | false`
185
+ **Default:** `{ title: "Recent posts", count: 5 }`
186
+
187
+ Lists the most recent posts in the sidebar of all blog pages. Set to `false` to hide it.
188
+
189
+ ### `feed`
190
+
191
+ **Type:** `boolean`
192
+ **Default:** on when a site URL is configured
193
+
194
+ Generates an RSS feed at `<path>/rss.xml` and links it from every blog page. Feeds need absolute
195
+ links, so the site URL is taken from [`canonicalUrlOrigin`](./overview.md#canonicalurlorigin) or
196
+ [`sitemap.siteUrl`](./overview.md#sitemap). Without either, no feed is generated.
197
+
198
+ ## Multiple blogs
199
+
200
+ Add the plugin once per blog, each with its own `files` and `path`, for example a blog and a
201
+ changelog:
202
+
203
+ ```tsx title="zudoku.config.tsx"
204
+ import { blogPlugin } from "zudoku/plugins/blog";
205
+
206
+ export default {
207
+ plugins: [
208
+ blogPlugin({ files: "/blog/**/*.{md,mdx}", path: "/blog" }),
209
+ blogPlugin({
210
+ files: "/changelog/**/*.{md,mdx}",
211
+ path: "/changelog",
212
+ title: "Changelog",
213
+ sidebar: false,
214
+ }),
215
+ ],
216
+ };
217
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "7.13.3",
3
+ "version": "7.13.5",
4
4
  "type": "module",
5
5
  "description": "The official Zuplo CLI for local development and platform management",
6
6
  "homepage": "https://zuplo.com/docs/cli/overview",
@@ -32,9 +32,9 @@
32
32
  "zuplo": "zuplo.js"
33
33
  },
34
34
  "dependencies": {
35
- "@zuplo/cli": "7.13.3",
36
- "@zuplo/core": "7.13.3",
37
- "@zuplo/runtime": "7.13.3",
38
- "@zuplo/test": "7.13.3"
35
+ "@zuplo/cli": "7.13.5",
36
+ "@zuplo/core": "7.13.5",
37
+ "@zuplo/runtime": "7.13.5",
38
+ "@zuplo/test": "7.13.5"
39
39
  }
40
40
  }