diff --git a/content/fpm/how-to/publish/en.md b/content/fpm/how-to/publish/en.md new file mode 100644 index 0000000..1e4263a --- /dev/null +++ b/content/fpm/how-to/publish/en.md @@ -0,0 +1,55 @@ +# Publish a package + +Use this guide when you already have a package directory and need to publish it to an FPM registry. + +## Before you publish + +The target directory must contain `package.json`. FPM requires a scoped package name and a valid version. The package name and version identify the release, so increment the version before publishing a new release of the same package. + +Review the package boundary before uploading. The `files` field limits the archive to matching entries; when it is absent, FPM considers files not excluded by `.gitignore`. FPM always includes `package.json`, and it excludes `.git`, `node_modules`, and other ignored metadata. Only regular files can be published. + +## Preview the archive + +Run a dry run from the package directory: + +```bash +fpm publish --dry-run +``` + +To preview another directory, pass its path: + +```bash +fpm publish ./packages/widget --dry-run +``` + +A dry run performs local packing and validation but does not acquire an upload session, upload bytes, or commit a release. + +## Publish to a selected registry + +The configured registry is used by default. Override it for one invocation with `--registry`: + +```bash +fpm publish ./packages/widget --registry https://registry.example.com/v1 +``` + +The token is resolved from `FPM_TOKEN` first and then from the local configuration created by `fpm login`. A command-line registry override changes the endpoint for that invocation; it does not rewrite the saved registry configuration. + +## Use JSON output in automation + +Use `--json` when a pipeline needs to consume the result: + +```bash +FPM_TOKEN="$FPM_PUBLISH_TOKEN" fpm publish ./packages/widget --json +``` + +The JSON result contains `name`, `version`, `tarball`, and `sha256`. Keep the token in the CI secret store and expose it only to the publishing step. Do not commit FPM configuration files or tokens to source control. + +## Understand the upload sequence + +FPM first sends the package name, version, and SHA-256 checksum to the registry to acquire an upload session. It then uploads the gzip archive to the returned upload URL and commits the session with the normalized manifest. Registry API requests use JSON and include the token as a Bearer authorization header when a token is configured. + +If a network or registry error is retryable, the upload step may be retried once. A successful publish prints the package identifier, tarball URL, and checksum. Save the checksum with the release metadata when you need to verify the uploaded archive later. + +## Troubleshoot common failures + +If FPM reports that no token is configured, run `fpm login` or set `FPM_TOKEN`. If the manifest name is rejected, change it to a scoped name such as `@example/widget`. If the version is invalid, use a valid Semantic Version. If a file is missing from the archive, check both the `files` field and `.gitignore` rules. diff --git a/content/fpm/how-to/publish/zh-hans.md b/content/fpm/how-to/publish/zh-hans.md new file mode 100644 index 0000000..f596273 --- /dev/null +++ b/content/fpm/how-to/publish/zh-hans.md @@ -0,0 +1,55 @@ +# 发布包 + +当你已经有一个包目录,并需要将它发布到 FPM 注册表时,可以使用本指南。 + +## 发布前检查 + +目标目录必须包含 `package.json`。FPM 要求包名带作用域,并且版本号有效。包名和版本共同标识一个发布版本,因此同一个包发布新版本前需要先递增版本号。 + +发布前请检查包的边界。`files` 字段会将归档限制为匹配的条目;未设置该字段时,FPM 会考虑未被 `.gitignore` 排除的文件。FPM 始终包含 `package.json`,并排除 `.git`、`node_modules` 以及其他被忽略的元数据。只有普通文件可以被发布。 + +## 预览归档 + +在包目录中执行 dry-run: + +```bash +fpm publish --dry-run +``` + +如果要预览其他目录,可以传入目录路径: + +```bash +fpm publish ./packages/widget --dry-run +``` + +dry-run 会执行本地打包和验证,但不会获取上传会话、上传字节或提交发布版本。 + +## 发布到指定注册表 + +默认使用已配置的注册表。可以使用 `--registry` 为单次执行覆盖注册表: + +```bash +fpm publish ./packages/widget --registry https://registry.example.com/v1 +``` + +令牌会优先从 `FPM_TOKEN` 读取;如果没有设置,则使用 `fpm login` 写入的本地配置。命令行传入的注册表只影响当前执行,不会改写已保存的注册表配置。 + +## 在自动化环境中使用 JSON 输出 + +流水线需要读取结果时,请使用 `--json`: + +```bash +FPM_TOKEN="$FPM_PUBLISH_TOKEN" fpm publish ./packages/widget --json +``` + +JSON 结果包含 `name`、`version`、`tarball` 和 `sha256`。请将令牌保存到 CI 的密钥存储中,并仅在发布步骤中注入。不要把 FPM 配置文件或令牌提交到源代码仓库。 + +## 了解上传流程 + +FPM 首先向注册表发送包名、版本和 SHA-256 校验和,以获取上传会话。随后,它将 gzip 归档上传到返回的 URL,并使用规范化后的包清单提交会话。注册表 API 请求使用 JSON;配置了令牌时,请求会将令牌放在 Bearer authorization header 中。 + +如果网络或注册表错误可重试,上传步骤最多会重试一次。发布成功后会输出包标识符、归档 URL 和校验和。如果之后需要验证上传的归档,可以将校验和保存到发布元数据中。 + +## 排查常见错误 + +如果 FPM 报告没有配置令牌,请执行 `fpm login` 或设置 `FPM_TOKEN`。如果包名校验失败,请改为 `@example/widget` 这样的带作用域名称。如果版本无效,请使用符合 Semantic Version 的版本号。如果归档缺少文件,请同时检查 `files` 字段和 `.gitignore` 规则。 diff --git a/content/fpm/overview/en.md b/content/fpm/overview/en.md new file mode 100644 index 0000000..3122ee4 --- /dev/null +++ b/content/fpm/overview/en.md @@ -0,0 +1,24 @@ +# FPM package publishing + +FPM is a package registry and command-line publishing tool for source packages. It helps package authors validate a package, create a deterministic archive, upload it to an FPM registry, and commit the published manifest. + +## Choose a path + +| If you want to... | Start here | +| :--- | :--- | +| Install FPM and publish your first package | [Get started](../tutorials/getting-started) | +| Publish an existing package from a specific directory | [Publish a package](../how-to/publish) | +| Check every command and option | [CLI reference](../reference/cli) | +| Understand the package and upload workflow | [CLI reference](../reference/cli#publish) | + +FPM is designed to be installed globally. After installation, use the `fpm` command directly instead of invoking the generated JavaScript file with Node.js. + +## What FPM publishes + +FPM reads the `package.json` in the target directory. The package must have a scoped name, such as `@example/widget`, and a valid Semantic Version. The archive includes the package manifest and the files selected by the manifest and `.gitignore` rules. Workspace dependency ranges are normalized before the manifest is committed. + +The publish operation uses a short-lived upload session: FPM acquires an upload URL, uploads the compressed archive with its SHA-256 checksum, and commits the manifest. The registry token is sent as a Bearer token and is stored locally with restrictive file permissions when you use `fpm login`. + +## Documentation model + +This module separates learning, task completion, and lookup. The tutorial gives a complete first-run path, the how-to guide focuses on publishing an existing package, and the reference describes command syntax and behavior. This separation follows the user-needs model described by [Diátaxis](https://diataxis.fr/) and the task-oriented navigation principles used by [Microsoft Learn](https://learn.microsoft.com/en-us/sharepoint/information-architecture-principles). diff --git a/content/fpm/overview/zh-hans.md b/content/fpm/overview/zh-hans.md new file mode 100644 index 0000000..aa484f7 --- /dev/null +++ b/content/fpm/overview/zh-hans.md @@ -0,0 +1,24 @@ +# FPM 包发布工具 + +FPM 是一个包注册表和命令行发布工具,面向源代码包作者。它可以验证包、生成确定性的压缩归档、将归档上传到 FPM 注册表,并提交已发布的包清单。 + +## 选择文档路径 + +| 你想要…… | 从这里开始 | +| :--- | :--- | +| 安装 FPM 并发布第一个包 | [快速上手](../tutorials/getting-started) | +| 从指定目录发布已有包 | [发布包](../how-to/publish) | +| 查看全部命令和选项 | [CLI 参考](../reference/cli) | +| 了解包和上传流程 | [CLI 参考:publish](../reference/cli#publish) | + +FPM 设计为全局安装。安装完成后,直接使用 `fpm` 命令即可,不需要再通过 Node.js 显式执行生成的 JavaScript 文件。 + +## FPM 发布什么内容 + +FPM 会读取目标目录中的 `package.json`。包名必须是带作用域的名称,例如 `@example/widget`,版本号必须符合 Semantic Version 规范。归档包含包清单,以及由清单和 `.gitignore` 规则选中的文件。提交清单前,workspace 依赖范围会被规范化。 + +发布过程使用短期上传会话:FPM 先获取上传 URL,再使用 SHA-256 校验和上传压缩归档,最后提交包清单。注册表令牌会作为 Bearer token 发送;使用 `fpm login` 时,令牌会以严格的本地文件权限保存。 + +## 文档组织方式 + +本模块将学习、完成任务和查找信息分开:教程提供完整的首次使用路径,操作指南聚焦发布已有包,参考页描述命令语法与行为。这种划分参考了 [Diátaxis](https://diataxis.fr/) 的用户需求模型,以及 [Microsoft Learn 信息架构原则](https://learn.microsoft.com/en-us/sharepoint/information-architecture-principles) 中以用户任务和可查找性为中心的导航方式。 diff --git a/content/fpm/reference/cli/en.md b/content/fpm/reference/cli/en.md new file mode 100644 index 0000000..4e51cfe --- /dev/null +++ b/content/fpm/reference/cli/en.md @@ -0,0 +1,74 @@ +# FPM CLI reference + +The global executable is `fpm`. Run `fpm help` to print the current command summary. + +## Commands + +| Command | Purpose | +| :--- | :--- | +| `fpm login [--registry ]` | Save a registry and personal access token locally. | +| `fpm logout` | Remove the saved token while retaining the registry setting. | +| `fpm whoami` | Query the registry for the authenticated user. | +| `fpm config` | Print the configured registry and whether a token is present. The token itself is never printed. | +| `fpm publish [directory] [options]` | Pack and publish a package. The directory defaults to `.`. | + +## `publish` + +```text +fpm publish [directory] [--dry-run] [--json] [--registry ] +``` + +The command reads `package.json`, validates the scoped name and Semantic Version, packs the selected files, and publishes the archive. `directory` is optional and defaults to the current working directory. + +| Option | Behavior | +| :--- | :--- | +| `--dry-run` | Pack and validate locally without contacting the registry. | +| `--json` | Print the result as one JSON object instead of human-readable lines. | +| `--registry ` | Use a registry URL for this invocation. | +| `--help`, `-h` | Print help. | +| `--version`, `-v` | Print the CLI version after a command has been selected. | + +A successful human-readable result contains the package identifier, tarball URL, and SHA-256 checksum: + +```text +Published @example/widget@1.0.0 +Tarball: https://registry.example.com/v1/packages/@example/widget/1.0.0.tgz +SHA-256: +``` + +The JSON form contains these keys: + +```json +{ + "name": "@example/widget", + "version": "1.0.0", + "tarball": "https://registry.example.com/v1/packages/@example/widget/1.0.0.tgz", + "sha256": "" +} +``` + +## Configuration + +The registry and token are resolved using the following precedence: + +| Value | Precedence | +| :--- | :--- | +| Registry | `--registry` for `publish`, then `FPM_REGISTRY`, then the saved configuration. | +| Token | `FPM_TOKEN`, then the saved configuration. | + +`fpm login` writes the configuration to `fpm/config.json` below the platform configuration directory. On systems that set `XDG_CONFIG_HOME`, FPM uses `$XDG_CONFIG_HOME/fpm/config.json`; otherwise it uses the user's platform configuration directory. The file is written with mode `0600`. + +## Package requirements + +A publishable package must have a `package.json` with a scoped `name` and a valid `version`. The packer includes `package.json`, respects the `files` field, applies `.gitignore` exclusions, excludes `.git` and `node_modules`, and rejects non-regular files. Workspace dependency ranges are rewritten to publishable version ranges when a workspace root can be found. + +## Runtime and installation + +Install the CLI globally with npm or pnpm: + +```bash +npm install --global @fuyeor/fpm-cli +pnpm add --global @fuyeor/fpm-cli +``` + +The package exposes `dist/cli.js` as the `fpm` binary through `package.json#bin`. The published package is built during packing, so consumers do not need the repository or TypeScript toolchain installed. diff --git a/content/fpm/reference/cli/zh-hans.md b/content/fpm/reference/cli/zh-hans.md new file mode 100644 index 0000000..5d44b99 --- /dev/null +++ b/content/fpm/reference/cli/zh-hans.md @@ -0,0 +1,74 @@ +# FPM CLI 参考 + +全局可执行命令为 `fpm`。运行 `fpm help` 可以输出当前命令摘要。 + +## 命令 + +| 命令 | 作用 | +| :--- | :--- | +| `fpm login [--registry ]` | 在本地保存注册表和个人访问令牌。 | +| `fpm logout` | 删除已保存的令牌,但保留注册表设置。 | +| `fpm whoami` | 向注册表查询当前已认证用户。 | +| `fpm config` | 输出已配置的注册表以及是否存在令牌;不会输出令牌本身。 | +| `fpm publish [directory] [options]` | 打包并发布包;目录默认为 `.`。 | + +## `publish` + +```text +fpm publish [directory] [--dry-run] [--json] [--registry ] +``` + +该命令读取 `package.json`,验证带作用域的包名和 Semantic Version,打包选中的文件,并发布归档。`directory` 是可选参数,默认为当前工作目录。 + +| 选项 | 行为 | +| :--- | :--- | +| `--dry-run` | 只在本地打包和验证,不访问注册表。 | +| `--json` | 将结果输出为单个 JSON 对象,而不是人类可读的多行文本。 | +| `--registry ` | 为本次执行使用指定的注册表 URL。 | +| `--help`、`-h` | 输出帮助。 | +| `--version`、`-v` | 在选定命令后输出 CLI 版本。 | + +成功执行后的人类可读输出包含包标识符、归档 URL 和 SHA-256 校验和: + +```text +Published @example/widget@1.0.0 +Tarball: https://registry.example.com/v1/packages/@example/widget/1.0.0.tgz +SHA-256: +``` + +JSON 输出包含以下字段: + +```json +{ + "name": "@example/widget", + "version": "1.0.0", + "tarball": "https://registry.example.com/v1/packages/@example/widget/1.0.0.tgz", + "sha256": "" +} +``` + +## 配置 + +注册表和令牌按以下优先级解析: + +| 值 | 优先级 | +| :--- | :--- | +| 注册表 | `publish` 的 `--registry`,然后是 `FPM_REGISTRY`,最后是已保存的配置。 | +| 令牌 | `FPM_TOKEN`,然后是已保存的配置。 | + +`fpm login` 会将配置写入平台配置目录下的 `fpm/config.json`。设置了 `XDG_CONFIG_HOME` 的系统使用 `$XDG_CONFIG_HOME/fpm/config.json`;否则使用当前用户的平台配置目录。文件以 `0600` 模式写入。 + +## 包要求 + +可发布的包必须有一个包含带作用域 `name` 和有效 `version` 的 `package.json`。打包器会包含 `package.json`,遵循 `files` 字段,应用 `.gitignore` 排除规则,排除 `.git` 和 `node_modules`,并拒绝非普通文件。当能够找到 workspace 根目录时,workspace 依赖范围会被改写为可发布的版本范围。 + +## 运行时与安装 + +使用 npm 或 pnpm 全局安装 CLI: + +```bash +npm install --global @fuyeor/fpm-cli +pnpm add --global @fuyeor/fpm-cli +``` + +该包通过 `package.json#bin` 将 `dist/cli.js` 暴露为 `fpm` 命令。发布包会在打包阶段构建,因此使用者不需要克隆仓库,也不需要安装 TypeScript 工具链。 diff --git a/content/fpm/structure.json b/content/fpm/structure.json new file mode 100644 index 0000000..1d8babc --- /dev/null +++ b/content/fpm/structure.json @@ -0,0 +1,37 @@ +{ + "title": { + "zh-hans": "FPM 包发布工具", + "en": "FPM Package Publishing" + }, + "description": { + "zh-hans": "FPM 包注册表与命令行发布工具的入门、操作指南和 CLI 参考。", + "en": "Getting started, how-to guides, and CLI reference for the FPM package registry and publishing tool." + }, + "navigation": [ + { "slug": "overview" }, + { + "slug": "tutorials", + "title": { + "zh-hans": "教程", + "en": "Tutorials" + }, + "navigation": [{ "slug": "getting-started" }] + }, + { + "slug": "how-to", + "title": { + "zh-hans": "操作指南", + "en": "How-to guides" + }, + "navigation": [{ "slug": "publish" }] + }, + { + "slug": "reference", + "title": { + "zh-hans": "参考", + "en": "Reference" + }, + "navigation": [{ "slug": "cli" }] + } + ] +} diff --git a/content/fpm/tutorials/getting-started/en.md b/content/fpm/tutorials/getting-started/en.md new file mode 100644 index 0000000..754f304 --- /dev/null +++ b/content/fpm/tutorials/getting-started/en.md @@ -0,0 +1,101 @@ +# Get started with FPM + +This tutorial takes you from an empty directory to a locally verified package publish. It assumes that Node.js 24.19 or later and npm or pnpm are available on your machine. + +## Install the CLI globally + +Install the published CLI with npm: + +```bash +npm install --global @fuyeor/fpm-cli +``` + +Or install it with pnpm: + +```bash +pnpm add --global @fuyeor/fpm-cli +``` + +The package declares the `fpm` binary in its `bin` field. The package manager therefore creates a global executable named `fpm`. + +Confirm that the command is available: + +```bash +fpm help +``` + +If you use pnpm, make sure the directory reported by `pnpm bin --global` is on your `PATH`. On a new pnpm installation, `pnpm setup` can configure the pnpm home directory for your shell. + +## Authenticate with the registry + +Run: + +```bash +fpm login +``` + +The command prompts for a personal access token and saves the registry and token in the FPM configuration file. To use a different registry, pass it explicitly: + +```bash +fpm login --registry https://registry.example.com/v1 +``` + +For automation, set the token through the environment instead of writing it in a script: + +```bash +export FPM_TOKEN='replace-with-a-token' +``` + +You can inspect the active registry without printing the token: + +```bash +fpm config +``` + +## Create a minimal package + +Create a directory with a manifest and one source file: + +```bash +mkdir hello-fpm +cd hello-fpm +cat > package.json <<'EOF' +{ + "name": "@example/hello-fpm", + "version": "1.0.0", + "description": "A minimal FPM package", + "type": "module", + "exports": "./index.js", + "files": ["index.js"] +} +EOF +printf 'export const message = "Hello from FPM";\n' > index.js +``` + +The name is scoped because FPM requires package names such as `@example/hello-fpm`. The version must be valid Semantic Version syntax. + +## Verify before publishing + +From the package directory, create a dry run: + +```bash +fpm publish --dry-run +``` + +The dry run packs and validates the package without contacting the registry. Review the manifest, selected files, and version before publishing. + +## Publish + +When the package is ready, publish it: + +```bash +fpm publish +``` + +For machine-readable output, add `--json`: + +```bash +fpm publish --json +``` + +The command prints the package name, version, tarball URL, and SHA-256 checksum. Continue with [Publish a package](../../how-to/publish) for CI and directory-specific workflows. diff --git a/content/fpm/tutorials/getting-started/zh-hans.md b/content/fpm/tutorials/getting-started/zh-hans.md new file mode 100644 index 0000000..b7fa99c --- /dev/null +++ b/content/fpm/tutorials/getting-started/zh-hans.md @@ -0,0 +1,101 @@ +# FPM 快速上手 + +本教程将带你从空目录开始,完成一个包的本地验证和发布。开始前,请确认机器上已经安装 Node.js 24.19 或更高版本,以及 npm 或 pnpm。 + +## 全局安装 CLI + +使用 npm 安装已发布的 CLI: + +```bash +npm install --global @fuyeor/fpm-cli +``` + +也可以使用 pnpm: + +```bash +pnpm add --global @fuyeor/fpm-cli +``` + +该包在 `bin` 字段中声明了 `fpm` 二进制入口,因此包管理器会创建名为 `fpm` 的全局可执行命令。 + +确认命令可用: + +```bash +fpm help +``` + +如果使用 pnpm,请确认 `pnpm bin --global` 输出的目录已经加入 `PATH`。全新安装 pnpm 时,可以运行 `pnpm setup` 为当前 shell 配置 pnpm home 目录。 + +## 登录注册表 + +运行: + +```bash +fpm login +``` + +命令会提示输入个人访问令牌,并将注册表地址和令牌保存到 FPM 配置文件中。若要使用其他注册表,请明确传入地址: + +```bash +fpm login --registry https://registry.example.com/v1 +``` + +在自动化环境中,应通过环境变量提供令牌,不要把令牌写入脚本: + +```bash +export FPM_TOKEN='replace-with-a-token' +``` + +可以查看当前注册表,但不会打印令牌: + +```bash +fpm config +``` + +## 创建最小包 + +创建包含清单和一个源文件的目录: + +```bash +mkdir hello-fpm +cd hello-fpm +cat > package.json <<'EOF' +{ + "name": "@example/hello-fpm", + "version": "1.0.0", + "description": "A minimal FPM package", + "type": "module", + "exports": "./index.js", + "files": ["index.js"] +} +EOF +printf 'export const message = "Hello from FPM";\n' > index.js +``` + +由于 FPM 要求使用形如 `@example/hello-fpm` 的包名,因此名称必须带作用域。版本号必须符合 Semantic Version 语法。 + +## 发布前验证 + +在包目录中执行 dry-run: + +```bash +fpm publish --dry-run +``` + +dry-run 会打包并验证包,但不会访问注册表。发布前请检查清单、选中的文件和版本号。 + +## 发布 + +包准备完成后执行: + +```bash +fpm publish +``` + +如果需要机器可读的输出,添加 `--json`: + +```bash +fpm publish --json +``` + +命令会输出包名、版本、归档 URL 和 SHA-256 校验和。CI 和指定目录发布方式请继续阅读[发布包](../../how-to/publish)。 diff --git a/content/index.en.json b/content/index.en.json index f9b0b52..866ff24 100644 --- a/content/index.en.json +++ b/content/index.en.json @@ -1,4 +1,9 @@ [ + { + "module": "fpm", + "title": "FPM Package Publishing", + "description": "Getting started, publishing workflows, and CLI reference for the FPM package registry." + }, { "module": "chemistry", "title": "Chemistry API", diff --git a/content/index.zh-hans.json b/content/index.zh-hans.json index 4342a48..4aefa1a 100644 --- a/content/index.zh-hans.json +++ b/content/index.zh-hans.json @@ -1,4 +1,9 @@ [ + { + "module": "fpm", + "title": "FPM 包发布工具", + "description": "FPM 包注册表的快速上手、发布流程和 CLI 参考。" + }, { "module": "chemistry", "title": "Chemistry API",