@ponharu/pkgflare 0.0.0
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/CONTRIBUTING.md +50 -0
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/SECURITY.md +13 -0
- package/dist/cli.js +528 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/worker.js +3245 -0
- package/dist/worker.js.map +1 -0
- package/docs/architecture.md +58 -0
- package/docs/operations.md +114 -0
- package/docs/specification.md +114 -0
- package/migrations/0001_initial.sql +34 -0
- package/package.json +93 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Bug reports, documentation improvements, and focused pull requests are welcome. For changes to registry behavior or product scope, open an issue describing the use case and proposed behavior before building a large change. Use [SECURITY.md](./SECURITY.md) for suspected vulnerabilities.
|
|
4
|
+
|
|
5
|
+
## Local setup
|
|
6
|
+
|
|
7
|
+
Install Node.js 22 or later and the Bun version declared in `package.json`, then run:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun install --frozen-lockfile
|
|
11
|
+
bun run check
|
|
12
|
+
bun run test
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Tests use local Cloudflare bindings and do not need deployment credentials. Use synthetic packages and credentials in examples and fixtures.
|
|
16
|
+
|
|
17
|
+
## Making a change
|
|
18
|
+
|
|
19
|
+
Read the [specification](./docs/specification.md) and [architecture](./docs/architecture.md) for the behavior the implementation must preserve. Keep changes focused and update the relevant documentation when behavior changes. Add regression coverage for bug fixes and boundary cases, especially parsing, authorization, concurrent publishing, and deployment recovery.
|
|
20
|
+
|
|
21
|
+
Run `bun run format` and `bun run check` before submitting. Choose further verification based on the affected behavior:
|
|
22
|
+
|
|
23
|
+
| Command | Coverage |
|
|
24
|
+
| ----------------------- | ------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `bun run test` | Unit tests and Worker integration tests with local D1/R2 |
|
|
26
|
+
| `bun run test:e2e` | Real npm/Bun publish, npm dist-tags, and cold-cache installs with npm/pnpm/Yarn Classic/Bun |
|
|
27
|
+
| `bun run test:package` | Packed package installed in a temporary project, CLI help, and Wrangler deployment dry-run |
|
|
28
|
+
| `bun run test:coverage` | Unit and Worker coverage reports |
|
|
29
|
+
|
|
30
|
+
The client and packaging checks require network access to install dependencies; they do not deploy to Cloudflare. CI runs check, test, E2E, and package verification. Local tests do not establish real-account permissions or production capacity.
|
|
31
|
+
|
|
32
|
+
## Database and packaging changes
|
|
33
|
+
|
|
34
|
+
Add a new numbered SQL migration for schema changes. Never rewrite a released migration, and keep the previously deployed Worker working after migration if deploying its replacement fails. Cover migration copying and retry behavior when changing the CLI.
|
|
35
|
+
|
|
36
|
+
The npm artifact must include its runtime, type declarations, migrations, and linked user documentation. Run the package check when changing build outputs or published files. Keep environment-specific paths, credentials, and private registry URLs out of artifacts and lockfiles.
|
|
37
|
+
|
|
38
|
+
## Pull requests
|
|
39
|
+
|
|
40
|
+
Explain the problem, the resulting behavior, and how you verified it. Call out compatibility or migration implications. Include sanitized reproduction steps for bugs; do not attach private packages, deployment credentials, or token values.
|
|
41
|
+
|
|
42
|
+
## Releases
|
|
43
|
+
|
|
44
|
+
Pull request titles use Conventional Commits and are checked by `semantic-pr.yml`. Use squash merges so the checked title becomes the commit subject on `main`. `fix:` produces a patch release, `feat:` a minor release, and `!` or a `BREAKING CHANGE:` footer a major release. Documentation and maintenance commits do not normally trigger a release.
|
|
45
|
+
|
|
46
|
+
On each push to `main`, `release.yml` calls `test.yml` for checks, unit/Worker tests, client compatibility, and package verification. Only after they pass does semantic-release determine the next version, publish to npm, and create a Git tag and GitHub Release. It does not commit version updates or a changelog back to the repository. Release notes live in GitHub Releases.
|
|
47
|
+
|
|
48
|
+
The npm package uses Trusted Publishing. In the npm settings for `@ponharu/pkgflare`, authorize GitHub owner `ponharu`, repository `pkgflare`, and workflow filename `release.yml`, with direct publishing allowed. The calling workflow is `release.yml`; `test.yml` is only the reusable verification workflow. No GitHub Environment is configured. Complete package ownership and trusted-publisher setup on npm before relying on automatic publication; see [npm's setup instructions](https://docs.npmjs.com/trusted-publishers/).
|
|
49
|
+
|
|
50
|
+
The release job uses GitHub-hosted runners, Node.js 24, and the locked semantic-release npm plugin with OIDC support. `id-token: write` supplies npm authentication, while `GITHUB_TOKEN` creates tags and GitHub Releases. No long-lived npm publish token is required. Issue/PR release comments and labels are disabled.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ponharu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# pkgflare
|
|
2
|
+
|
|
3
|
+
Deploy a scoped private npm registry to your own Cloudflare account.
|
|
4
|
+
|
|
5
|
+
`pkgflare` packages a Cloudflare Worker, D1 migrations, R2 bindings, authentication, and deployment tooling. Package authors and consumers continue to use standard npm-compatible clients; package data and registry infrastructure stay in the Cloudflare account you control.
|
|
6
|
+
|
|
7
|
+
## What it provides
|
|
8
|
+
|
|
9
|
+
- Standard scoped package publish and install endpoints
|
|
10
|
+
- Immutable tarballs in R2
|
|
11
|
+
- Package metadata and mutable dist-tags in D1
|
|
12
|
+
- Read and publish tokens stored as Cloudflare Secrets
|
|
13
|
+
- Repeatable deployment through one `pkgflare deploy` command
|
|
14
|
+
- npm-compatible metadata and tarball responses tested with npm, pnpm, Yarn Classic, and Bun
|
|
15
|
+
|
|
16
|
+
It intentionally does not provide a web UI, npmjs.org proxy, user database, team model, or a hosted registry service.
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- Node.js 22 or later
|
|
21
|
+
- A Cloudflare account with Workers, D1, and R2 available
|
|
22
|
+
- Wrangler authentication, either through `wrangler login` or supported environment credentials
|
|
23
|
+
|
|
24
|
+
## Set up a registry
|
|
25
|
+
|
|
26
|
+
### 1. Create the deployment project
|
|
27
|
+
|
|
28
|
+
Use a dedicated, private repository to keep your deployment configuration and state:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
mkdir acme-registry
|
|
32
|
+
cd acme-registry
|
|
33
|
+
npm init -y
|
|
34
|
+
npm install --save-dev @ponharu/pkgflare
|
|
35
|
+
npx pkgflare init
|
|
36
|
+
npx wrangler login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Edit the generated `pkgflare.config.ts`:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { defineConfig } from "@ponharu/pkgflare";
|
|
43
|
+
|
|
44
|
+
export default defineConfig({
|
|
45
|
+
name: "acme-registry",
|
|
46
|
+
// Use your Cloudflare account ID, not a zone ID.
|
|
47
|
+
accountId: "0123456789abcdef0123456789abcdef",
|
|
48
|
+
scopes: ["@acme"],
|
|
49
|
+
auth: {
|
|
50
|
+
provider: "secrets",
|
|
51
|
+
tokens: [
|
|
52
|
+
{ binding: "PKGFLARE_READ_TOKEN", permissions: ["read"] },
|
|
53
|
+
{ binding: "PKGFLARE_PUBLISH_TOKEN", permissions: ["publish"] },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Replace the account ID, deployment name, and scope with your own. `accountId` can be omitted when Wrangler can resolve exactly one account. The default endpoint uses `workers.dev`. An optional `hostname: "packages.example.com"` configures a [custom domain](./docs/operations.md#cloudflare-authentication-and-domains).
|
|
60
|
+
|
|
61
|
+
### 2. Deploy and register tokens
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npx pkgflare deploy
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The command creates the D1 database and R2 bucket, applies migrations, deploys the Worker, and prints its URL and Secret registration commands. Requests require a registered token before they can succeed.
|
|
68
|
+
|
|
69
|
+
Generate two different tokens by running this command twice, and save them in your password manager:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
npx pkgflare token generate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Register the read token, then the publish token. Paste each value at Wrangler's prompt:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npx wrangler secret put PKGFLARE_READ_TOKEN --config .pkgflare/wrangler.json
|
|
79
|
+
npx wrangler secret put PKGFLARE_PUBLISH_TOKEN --config .pkgflare/wrangler.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Keep token values out of source files and Git. Commit the deployment configuration, lockfile, and generated state files to your private deployment repository as described in [deployment state](./docs/operations.md#deployment-state).
|
|
83
|
+
|
|
84
|
+
### 3. Publish your first package
|
|
85
|
+
|
|
86
|
+
In a separate directory for the package you want to publish, create `.npmrc` with the URL printed by deploy. Replace the example hostname on **both** lines:
|
|
87
|
+
|
|
88
|
+
```ini
|
|
89
|
+
@acme:registry=https://acme-registry.example.workers.dev
|
|
90
|
+
//acme-registry.example.workers.dev/:_authToken=${NPM_TOKEN}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Set `NPM_TOKEN` in your shell to the **publish** token. For example, in Bash or Zsh, this prompts without displaying the token or putting its value in shell history:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
printf 'Publish token: '
|
|
97
|
+
read -r -s NPM_TOKEN
|
|
98
|
+
printf '\n'
|
|
99
|
+
export NPM_TOKEN
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For a minimal example package, create `package.json` and `index.js` in that directory:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"name": "@acme/example",
|
|
107
|
+
"version": "1.0.0",
|
|
108
|
+
"type": "module",
|
|
109
|
+
"exports": "./index.js",
|
|
110
|
+
"files": ["index.js"]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
export const greeting = "Hello from pkgflare";
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Publish and inspect it:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
npm publish
|
|
122
|
+
npm view @acme/example
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use an allowed scope and a new version for each publish. Do not set `"private": true` in the package manifest: npm uses that field to prevent publishing to any registry.
|
|
126
|
+
|
|
127
|
+
### 4. Install from a consumer project
|
|
128
|
+
|
|
129
|
+
In another project, copy the scope-specific `.npmrc` above. Set `NPM_TOKEN` to the **read** token using the same prompt, then run:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
npm install @acme/example
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `.npmrc` contains an environment variable reference and can be committed; the token value must stay in your shell environment or CI secret store. Public dependencies continue to use the client's default registry.
|
|
136
|
+
|
|
137
|
+
## Compatibility and permissions
|
|
138
|
+
|
|
139
|
+
| Operation | Supported clients |
|
|
140
|
+
| ------------------------------- | ---------------------------- |
|
|
141
|
+
| Publish | npm, Bun |
|
|
142
|
+
| Metadata and install | npm, pnpm, Yarn Classic, Bun |
|
|
143
|
+
| List, add, and remove dist-tags | npm |
|
|
144
|
+
|
|
145
|
+
Yarn Berry and other clients are outside the tested compatibility baseline. pkgflare does not implement `npm login`, `npm adduser`, `npm unpublish`, `npm deprecate`, search, or the npm audit API. It is a scoped private registry, not a complete replacement for the public npm service.
|
|
146
|
+
|
|
147
|
+
A read token can read every package in the registry. A publish token can also publish packages and change dist-tags across all configured scopes. Permissions are not restricted per package or scope; use separate registry deployments when readers or publishers need different trust boundaries.
|
|
148
|
+
|
|
149
|
+
Versions are immutable. To promote or roll back an existing version, use the publish token with `npm dist-tag`:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
npm dist-tag add @acme/example@1.1.0 latest
|
|
153
|
+
npm dist-tag add @acme/example@1.0.0 latest
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The first command assumes `1.1.0` has already been published. Moving a tag affects future tag-based resolution; it does not rewrite consumers' lockfiles or remove a version.
|
|
157
|
+
|
|
158
|
+
## CLI
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
pkgflare deploy [--config <path>] [--secrets-file <path>] [--adopt-existing]
|
|
162
|
+
pkgflare init
|
|
163
|
+
pkgflare token generate
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`token generate` creates a cryptographically random token locally and prints it once. pkgflare does not store, distribute, list, or revoke tokens.
|
|
167
|
+
|
|
168
|
+
## Publish consistency
|
|
169
|
+
|
|
170
|
+
A package version is immutable, while dist-tags remain mutable for promotion and rollback. pkgflare incrementally parses the standard npm publish document, decodes its Base64 attachment into fixed-size R2 multipart chunks, and calculates SHA-1 and SHA-512 without holding the complete tarball in Worker memory. A unique attempt object is published in D1 only after R2 completes; D1's package-and-version constraint chooses the sole winner of concurrent publishes.
|
|
171
|
+
|
|
172
|
+
If a D1 result is uncertain, pkgflare reads the version back before deciding whether the attempt succeeded or conflicted. An interrupted attempt can leave an unreachable R2 object, but it is never returned by metadata or install requests. Automatic orphan collection is not part of the initial release.
|
|
173
|
+
|
|
174
|
+
pkgflare does not add a tarball-size ceiling. The complete Base64-encoded npm publish request remains subject to Cloudflare's request-body and Worker CPU limits. Those limits are governed separately and can vary with the account and Workers usage model. Non-attachment JSON metadata is limited to 1 MiB, JSON nesting is limited to 128 levels, and tarball downloads are streamed from R2 with immutable caching and byte ranges. See [Cloudflare limits](https://developers.cloudflare.com/workers/platform/limits/) when choosing your deployment plan.
|
|
175
|
+
|
|
176
|
+
## Rotate tokens
|
|
177
|
+
|
|
178
|
+
To rotate a token without interrupting existing clients:
|
|
179
|
+
|
|
180
|
+
1. Add a new Secret binding to the config while retaining the old binding, then deploy.
|
|
181
|
+
2. Register the new Secret and switch clients to it.
|
|
182
|
+
3. Remove the old binding from the config and deploy again.
|
|
183
|
+
4. Delete the old Cloudflare Secret.
|
|
184
|
+
|
|
185
|
+
Missing configured Secret bindings are ignored as long as another configured token grants access. Secret values and Authorization headers are never logged.
|
|
186
|
+
|
|
187
|
+
## Updates and migrations
|
|
188
|
+
|
|
189
|
+
Updating the npm package and running `pkgflare deploy` copies every packaged migration, applies pending migrations, and then deploys the new Worker. Migrations are append-only and must remain compatible with the previously deployed Worker so that a failed deployment can be retried without taking the Registry offline.
|
|
190
|
+
|
|
191
|
+
See [operations](./docs/operations.md) for CI credentials, deployment recovery, backups, and troubleshooting. The complete behavior and failure contracts are described in [the specification](./docs/specification.md).
|
|
192
|
+
|
|
193
|
+
## Development
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
bun install
|
|
197
|
+
bun run check
|
|
198
|
+
bun run format
|
|
199
|
+
bun run test
|
|
200
|
+
bun run test:e2e
|
|
201
|
+
bun run build
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The integration suite runs the Worker with local D1 and R2 bindings through Cloudflare's Vitest integration. It does not require Cloudflare credentials. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the development workflow and [architecture](./docs/architecture.md) for design decisions and invariants.
|
|
205
|
+
|
|
206
|
+
## Security
|
|
207
|
+
|
|
208
|
+
Please report vulnerabilities using the process in [SECURITY.md](./SECURITY.md). Do not include tokens, authorization headers, Cloudflare credentials, or private package contents in public issues.
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please use GitHub's private vulnerability reporting feature for this repository. Do not open a public issue for a suspected vulnerability.
|
|
6
|
+
|
|
7
|
+
Include the affected version, impact, reproduction steps, and any suggested mitigation. Remove registry tokens, authorization headers, Cloudflare credentials, account identifiers, and private package contents from the report unless they are essential to reproduce the issue.
|
|
8
|
+
|
|
9
|
+
You should receive an acknowledgement within seven days. A fix and disclosure schedule will be coordinated after the report is validated.
|
|
10
|
+
|
|
11
|
+
## Deployment responsibility
|
|
12
|
+
|
|
13
|
+
pkgflare deploys into the user's Cloudflare account. Users are responsible for generating, storing, distributing, rotating, and revoking their registry tokens, and for limiting Cloudflare credentials to the permissions needed for deployment.
|