@shbernal/buzon 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +151 -2
- package/bin/buzon +2 -0
- package/package.json +47 -4
- package/skills/README.md +15 -0
- package/skills/buzon/SKILL.md +79 -0
- package/src/bin.ts +3 -0
- package/src/cli.ts +149 -0
- package/src/commands/addresses.ts +319 -0
- package/src/commands/context.ts +13 -0
- package/src/commands/deploy.ts +188 -0
- package/src/commands/init.ts +81 -0
- package/src/commands/mail.ts +203 -0
- package/src/core/admin.ts +38 -0
- package/src/core/api.ts +101 -0
- package/src/core/args.ts +57 -0
- package/src/core/config.ts +84 -0
- package/src/core/credentials.ts +19 -0
- package/src/core/errors.ts +19 -0
- package/src/core/extract.ts +173 -0
- package/src/core/files.ts +40 -0
- package/src/core/help.ts +35 -0
- package/src/core/mail.ts +80 -0
- package/src/core/names.ts +77 -0
- package/src/core/paths.ts +43 -0
- package/src/core/prompt.ts +16 -0
- package/src/core/registry.ts +28 -0
- package/src/core/secrets.ts +62 -0
- package/src/core/time.ts +16 -0
- package/src/core/upstream.ts +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shbernal
|
|
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
CHANGED
|
@@ -1,3 +1,152 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/banner/banner-dark.svg">
|
|
5
|
+
<img alt="buzon: disposable and long-lived email addresses on your own domain, for you and your agents" src="assets/banner/banner-light.svg">
|
|
6
|
+
</picture>
|
|
7
|
+
|
|
8
|
+
[![License][license-badge]][license]
|
|
9
|
+
[![Bun][bun-badge]][bun]
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
[Install](#install) • [Quickstart](#quickstart) • [Commands](#commands) • [Agent skill](#agent-skill) • [How it works](#how-it-works) • [Docs](#docs)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<img alt="buzon new ste creates an address, buzon wait prints the verification code, buzon delete removes it, buzon list shows the registry" src="assets/demo/demo.gif">
|
|
20
|
+
|
|
21
|
+
buzon is a CLI for a self-hosted [cloudflare_temp_email](https://github.com/dreamhunter2333/cloudflare_temp_email)
|
|
22
|
+
instance, a mail server that runs on a Cloudflare Worker with D1.
|
|
23
|
+
It creates addresses on your domain, waits for the verification code or magic link, and keeps
|
|
24
|
+
a local record of which address belongs to which account.
|
|
25
|
+
|
|
26
|
+
- Three tiers in the address name: `ste` for one code, `mte` for a few weeks, `lte` for a real
|
|
27
|
+
account. The instance deletes expired ones by itself.
|
|
28
|
+
- `wait --code` and `wait --link` print just the code or the link, ready for a script or an
|
|
29
|
+
agent.
|
|
30
|
+
- A local registry of every address with its site and note, so "which address did I use for
|
|
31
|
+
GitHub?" has an answer.
|
|
32
|
+
- Deploys and upgrades of the upstream release, with every database patch shown and confirmed.
|
|
33
|
+
- An agent skill that tells an AI agent when to pick each tier and how to get a code.
|
|
34
|
+
|
|
35
|
+
## Why
|
|
36
|
+
|
|
37
|
+
Public temp-mail services are blocked by most sign-up forms, and their inboxes are readable by
|
|
38
|
+
anyone who guesses the name. A catch-all on your own domain avoids both, but turns into a pile
|
|
39
|
+
of addresses nobody remembers. buzon puts a lifetime on each address, cleans up the short ones,
|
|
40
|
+
and records the long ones.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
buzon runs on [Bun](https://bun.sh). It reads its passwords from `BUZON_SITE_PASSWORD` and
|
|
45
|
+
`BUZON_ADMIN_PASSWORD`, or else from the keyring: the Secret Service through `secret-tool` on
|
|
46
|
+
Linux, the Keychain on macOS.
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
bun add -g @shbernal/buzon
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
No instance yet? [docs/deploying.md](docs/deploying.md) goes from a domain on Cloudflare to a
|
|
53
|
+
running one.
|
|
54
|
+
|
|
55
|
+
## Quickstart
|
|
56
|
+
|
|
57
|
+
1. Store the instance's site password in the keyring, on Linux:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
secret-tool store --label="buzon site-password" service buzon key site-password
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On macOS:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
security add-generic-password -s buzon -a site-password -w
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Elsewhere, export `BUZON_SITE_PASSWORD` instead.
|
|
70
|
+
|
|
71
|
+
2. Point buzon at the instance. It checks that the instance answers, serves the domain and
|
|
72
|
+
accepts the password before writing anything:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
buzon init --url https://mail.example.com --domain example.com
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
3. Create a one-shot address and use it on a sign-up form:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
buzon new ste
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
4. Wait for the code, then delete the address:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
buzon wait ste-2610-9qa --code --since 10m
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
buzon delete ste-2610-9qa
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
For an account you will come back to, keep the address and say what it is for:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
buzon new lte --site github --note "GitHub account for side projects"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Commands
|
|
101
|
+
|
|
102
|
+
| Command | Does |
|
|
103
|
+
| -------------------------------- | ---------------------------------------------------------- |
|
|
104
|
+
| `new <ste\|mte\|lte>` | Create an address, with `--site` and `--note` |
|
|
105
|
+
| `new custom <name>` | Create an address with a name you choose, such as `jane` |
|
|
106
|
+
| `wait <address>` | Wait for new mail and print its `--code`, `--link` or text |
|
|
107
|
+
| `read <address>` | Print the latest mail, `--all`, or one `--id` |
|
|
108
|
+
| `list`, `show <address>` | Registry entries, filtered by `--tier` or `--site` |
|
|
109
|
+
| `note`, `delete`, `adopt` | Edit, remove, or take in an address made elsewhere |
|
|
110
|
+
| `deploy`, `upgrade`, `export-db` | Ship a release, move to a newer one, dump the database |
|
|
111
|
+
|
|
112
|
+
Every command takes `--json`. `buzon --help` lists every command and flag.
|
|
113
|
+
|
|
114
|
+
## Agent skill
|
|
115
|
+
|
|
116
|
+
<picture>
|
|
117
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/agent-session/agent-session-dark.svg">
|
|
118
|
+
<img alt="An agent signs up for a trial: it creates an mte address with buzon, submits the form, waits for the code and enters it" src="assets/agent-session/agent-session-light.svg">
|
|
119
|
+
</picture>
|
|
120
|
+
|
|
121
|
+
[`skills/buzon`](skills/buzon/SKILL.md) teaches an agent to pick the tier, get a code or link,
|
|
122
|
+
and find an address again later. Install it with:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npx skills add shbernal/buzon
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
A test fails the build when the skill names a command or flag the CLI does not have.
|
|
129
|
+
|
|
130
|
+
## How it works
|
|
131
|
+
|
|
132
|
+
<picture>
|
|
133
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/how-it-works/how-it-works-dark.svg">
|
|
134
|
+
<img alt="Mail to example.com goes through Cloudflare Email Routing to a Worker and D1; buzon talks to the Worker over HTTPS and keeps a local registry" src="assets/how-it-works/how-it-works-light.svg">
|
|
135
|
+
</picture>
|
|
136
|
+
|
|
137
|
+
Cloudflare Email Routing hands every message for your domain to the Worker, which stores it in D1.
|
|
138
|
+
A daily cron deletes expired `ste` and `mte` addresses by the tier in their name.
|
|
139
|
+
buzon talks to the Worker over its HTTPS API, and keeps the registry of sites and notes on your
|
|
140
|
+
machine only.
|
|
141
|
+
|
|
142
|
+
## Docs
|
|
143
|
+
|
|
144
|
+
- [Deploying an instance](docs/deploying.md)
|
|
145
|
+
- [Tiers and cleanup](docs/tiers.md)
|
|
146
|
+
- [Files](docs/files.md)
|
|
147
|
+
- [Upgrading](docs/upgrading.md)
|
|
148
|
+
|
|
149
|
+
[license]: LICENSE
|
|
150
|
+
[license-badge]: https://img.shields.io/github/license/shbernal/buzon?style=for-the-badge&color=c8452f
|
|
151
|
+
[bun]: https://bun.sh
|
|
152
|
+
[bun-badge]: https://img.shields.io/badge/bun-%E2%89%A51.4-2f5fa7?style=for-the-badge&logo=bun&logoColor=white
|
package/bin/buzon
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shbernal/buzon",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI and agent skill for a self-hosted cloudflare_temp_email instance: tiered addresses, codes and links, a local registry, and deploys.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent-skill",
|
|
7
|
+
"cli",
|
|
8
|
+
"cloudflare",
|
|
9
|
+
"disposable-email",
|
|
10
|
+
"temp-email"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "shbernal",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/shbernal/buzon.git"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"buzon": "bin/buzon"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"src",
|
|
24
|
+
"skills",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "bun test",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"lint": "oxlint --type-aware",
|
|
33
|
+
"format": "oxfmt .",
|
|
34
|
+
"format:check": "oxfmt --check .",
|
|
35
|
+
"prose": "charcheck"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/bun": "^1.4.3",
|
|
39
|
+
"charcheck": "^0.4.0",
|
|
40
|
+
"oxfmt": "^0.74.0",
|
|
41
|
+
"oxlint": "^1.89.0",
|
|
42
|
+
"oxlint-tsgolint": "^7.0.2004",
|
|
43
|
+
"typescript": "^7"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"bun": ">=1.4"
|
|
47
|
+
},
|
|
48
|
+
"packageManager": "bun@1.4.3"
|
|
49
|
+
}
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Skills
|
|
2
|
+
|
|
3
|
+
The agent-facing skill for buzon lives here so it versions with the CLI it describes.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx skills add shbernal/buzon
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
| Skill | Use it for |
|
|
10
|
+
| ------------------------- | ----------------------------------------------------------------------- |
|
|
11
|
+
| [`buzon`](buzon/SKILL.md) | Addresses for sign-ups and accounts, verification codes and magic links |
|
|
12
|
+
|
|
13
|
+
A skill that has drifted from the tool it describes is worse than no skill, so
|
|
14
|
+
`tests/skill.test.ts` fails the build when `SKILL.md` names a command or flag the CLI does
|
|
15
|
+
not have.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: buzon
|
|
3
|
+
description: Create email addresses on the user's own temp-mail domain and read what arrives, including verification codes and magic links. Use when a sign-up form, trial, job application or service needs an email address, when a site sends a code or confirmation link, or when asked which address was used for an account.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# buzon
|
|
7
|
+
|
|
8
|
+
`buzon` creates addresses on the user's self-hosted mail domain and reads their inbox. It
|
|
9
|
+
keeps a local registry of every address with its tier, site and note.
|
|
10
|
+
|
|
11
|
+
buzon is the only interface. Never call the mail API yourself, and never print, log or pass
|
|
12
|
+
on the tokens buzon stores. Add `--json` to any command for machine-readable output; errors
|
|
13
|
+
then come on stderr as `{"error": …, "causes": […]}`.
|
|
14
|
+
|
|
15
|
+
## Pick the tier
|
|
16
|
+
|
|
17
|
+
| Situation | Tier |
|
|
18
|
+
| --------------------------------------------------------------- | ------------------------------ |
|
|
19
|
+
| One code or link, then nothing more | `ste`, deleted after use |
|
|
20
|
+
| A process lasting weeks: a trial, one application cycle | `mte` |
|
|
21
|
+
| A real account the user may need again: a job portal, a service | `lte --site <site> --note "…"` |
|
|
22
|
+
|
|
23
|
+
When the user asks for a specific name, such as `jane@`, use `buzon new custom jane --note "…"`.
|
|
24
|
+
It is kept like `lte`.
|
|
25
|
+
|
|
26
|
+
When unsure between `mte` and `lte`, pick `lte`: buzon keeps it and its site and note make
|
|
27
|
+
the account findable later.
|
|
28
|
+
|
|
29
|
+
`--site` is 1 to 12 lowercase letters or digits naming the platform, such as `greenhouse`,
|
|
30
|
+
`lever` or `github`. `ste` takes no `--site`.
|
|
31
|
+
|
|
32
|
+
An `lte` note says what the account is for and when it was made, in the user's words where
|
|
33
|
+
possible: `--note "Greenhouse account for Acme job applications, 2026-10"`. Fix a note later
|
|
34
|
+
with `buzon note <address> "…"`.
|
|
35
|
+
|
|
36
|
+
## Get a code or a link
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
buzon new ste --json # prints the address
|
|
40
|
+
# submit the form with that address
|
|
41
|
+
buzon wait <address> --code --since 10m --json
|
|
42
|
+
buzon delete <address> # ste only
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Delete an `ste` as soon as its code or link is in hand, without asking. If another code is
|
|
46
|
+
needed later, a new `ste` costs nothing.
|
|
47
|
+
|
|
48
|
+
`wait` takes `--code` for a verification code, `--link` for a confirmation or magic link,
|
|
49
|
+
or neither for the whole mail. `--since 10m` also takes mail that landed before `wait`
|
|
50
|
+
started; without it, `wait` only sees mail that arrives after it starts. Narrow a busy inbox
|
|
51
|
+
with `--from <regex>` or `--subject <regex>`. It gives up after `--timeout 300` seconds and
|
|
52
|
+
exits 1.
|
|
53
|
+
|
|
54
|
+
To read mail that is already there: `buzon read <address>` for the latest, `--all` for every
|
|
55
|
+
mail, `--id <n>` for one.
|
|
56
|
+
|
|
57
|
+
## When nothing arrives
|
|
58
|
+
|
|
59
|
+
1. `buzon read <address> --all`: the mail may be there but not match your filters, or carry
|
|
60
|
+
the code in a form `--code` did not pick up.
|
|
61
|
+
2. Retry once: resend from the site if it offers that, then `wait` again.
|
|
62
|
+
3. Still nothing: stop and tell the user which address you used and what you waited for.
|
|
63
|
+
|
|
64
|
+
## Find and keep addresses
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
buzon list --site greenhouse --json # also --tier ste|mte|lte|custom
|
|
68
|
+
buzon show <address> --json # registry entry and mail count
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Before creating an `lte`, check `list --site` for one the user already has on that platform.
|
|
72
|
+
|
|
73
|
+
Never delete an `lte` or `custom` address unless the user asks. buzon refuses without
|
|
74
|
+
`--force`; pass it only on that explicit request.
|
|
75
|
+
|
|
76
|
+
## Privacy
|
|
77
|
+
|
|
78
|
+
Mail bodies are the user's private mail. Quote a code or link where the task needs it, and
|
|
79
|
+
keep the rest out of unrelated outputs, files and commits.
|
package/src/bin.ts
ADDED
package/src/cli.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { parseArgv, UsageError } from './core/args.ts'
|
|
2
|
+
import { causeChain } from './core/errors.ts'
|
|
3
|
+
import { HELP } from './core/help.ts'
|
|
4
|
+
import pkg from '../package.json' with { type: 'json' }
|
|
5
|
+
|
|
6
|
+
export const COMMANDS = [
|
|
7
|
+
'init',
|
|
8
|
+
'new',
|
|
9
|
+
'list',
|
|
10
|
+
'show',
|
|
11
|
+
'note',
|
|
12
|
+
'delete',
|
|
13
|
+
'reissue',
|
|
14
|
+
'adopt',
|
|
15
|
+
'read',
|
|
16
|
+
'wait',
|
|
17
|
+
'delete-mail',
|
|
18
|
+
'deploy',
|
|
19
|
+
'upgrade',
|
|
20
|
+
'export-db',
|
|
21
|
+
] as const
|
|
22
|
+
|
|
23
|
+
type Command = (typeof COMMANDS)[number]
|
|
24
|
+
|
|
25
|
+
const isCommand = (command: string): command is Command =>
|
|
26
|
+
(COMMANDS as readonly string[]).includes(command)
|
|
27
|
+
|
|
28
|
+
const interactive = () => process.stdout.isTTY && process.stdin.isTTY
|
|
29
|
+
|
|
30
|
+
function print<T>(json: boolean, payload: T, text: (payload: T) => string): void {
|
|
31
|
+
console.log(json ? JSON.stringify(payload, null, 2) : text(payload))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function createContext() {
|
|
35
|
+
const { readConfig } = await import('./core/config.ts')
|
|
36
|
+
const { createApi } = await import('./core/api.ts')
|
|
37
|
+
const config = readConfig()
|
|
38
|
+
return { config, api: createApi(config) }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function run(argv: string[]): Promise<number> {
|
|
42
|
+
const parsed = parseArgv(argv)
|
|
43
|
+
const { command, flags } = parsed
|
|
44
|
+
const json = flags.json === true
|
|
45
|
+
|
|
46
|
+
if (flags.help || flags.h || command === 'help' || command === '') {
|
|
47
|
+
console.log(HELP)
|
|
48
|
+
return 0
|
|
49
|
+
}
|
|
50
|
+
if (flags.version || flags.v) {
|
|
51
|
+
console.log(pkg.version)
|
|
52
|
+
return 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!isCommand(command)) throw new UsageError(`unknown command "${command}"\n\n${HELP}`)
|
|
56
|
+
switch (command) {
|
|
57
|
+
case 'init': {
|
|
58
|
+
const { init, initText } = await import('./commands/init.ts')
|
|
59
|
+
print(json, await init(flags, !json && interactive()), initText)
|
|
60
|
+
return 0
|
|
61
|
+
}
|
|
62
|
+
case 'new':
|
|
63
|
+
case 'list':
|
|
64
|
+
case 'show':
|
|
65
|
+
case 'note':
|
|
66
|
+
case 'delete':
|
|
67
|
+
case 'reissue':
|
|
68
|
+
case 'adopt': {
|
|
69
|
+
const commands = await import('./commands/addresses.ts')
|
|
70
|
+
const context = await createContext()
|
|
71
|
+
switch (command) {
|
|
72
|
+
case 'new':
|
|
73
|
+
print(json, await commands.create(parsed, context), commands.createText)
|
|
74
|
+
break
|
|
75
|
+
case 'list':
|
|
76
|
+
print(json, commands.list(parsed), commands.listText)
|
|
77
|
+
break
|
|
78
|
+
case 'show':
|
|
79
|
+
print(json, await commands.show(parsed, context), commands.showText)
|
|
80
|
+
break
|
|
81
|
+
case 'note':
|
|
82
|
+
print(json, commands.setNote(parsed, context), commands.setNoteText)
|
|
83
|
+
break
|
|
84
|
+
case 'delete':
|
|
85
|
+
print(json, await commands.remove(parsed, context), commands.removeText)
|
|
86
|
+
break
|
|
87
|
+
case 'reissue': {
|
|
88
|
+
const result = await commands.reissue(parsed, context)
|
|
89
|
+
print(json, result, commands.reissueText)
|
|
90
|
+
return result.missing.length > 0 ? 1 : 0
|
|
91
|
+
}
|
|
92
|
+
case 'adopt':
|
|
93
|
+
print(json, await commands.adopt(parsed, context), commands.adoptText)
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
return 0
|
|
97
|
+
}
|
|
98
|
+
case 'read':
|
|
99
|
+
case 'wait':
|
|
100
|
+
case 'delete-mail': {
|
|
101
|
+
const commands = await import('./commands/mail.ts')
|
|
102
|
+
const context = await createContext()
|
|
103
|
+
if (command === 'read') print(json, await commands.read(parsed, context), commands.readText)
|
|
104
|
+
if (command === 'wait') print(json, await commands.wait(parsed, context), commands.waitText)
|
|
105
|
+
if (command === 'delete-mail') {
|
|
106
|
+
print(json, await commands.removeMail(parsed, context), commands.removeMailText)
|
|
107
|
+
}
|
|
108
|
+
return 0
|
|
109
|
+
}
|
|
110
|
+
case 'deploy':
|
|
111
|
+
case 'upgrade':
|
|
112
|
+
case 'export-db': {
|
|
113
|
+
const commands = await import('./commands/deploy.ts')
|
|
114
|
+
const context = await createContext()
|
|
115
|
+
if (command === 'deploy')
|
|
116
|
+
print(json, await commands.deploy(parsed, context), commands.deployText)
|
|
117
|
+
if (command === 'upgrade') {
|
|
118
|
+
const result = await commands.upgrade(parsed, context, interactive())
|
|
119
|
+
print(json, result, commands.upgradeText)
|
|
120
|
+
}
|
|
121
|
+
if (command === 'export-db') {
|
|
122
|
+
print(json, await commands.exportDb(parsed, context), commands.exportDbText)
|
|
123
|
+
}
|
|
124
|
+
return 0
|
|
125
|
+
}
|
|
126
|
+
default:
|
|
127
|
+
return command satisfies never
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function main(argv: string[]): Promise<void> {
|
|
132
|
+
const json = argv.includes('--json')
|
|
133
|
+
try {
|
|
134
|
+
process.exitCode = await run(argv)
|
|
135
|
+
} catch (error) {
|
|
136
|
+
const usage = error instanceof UsageError
|
|
137
|
+
const [message, ...causes] = usage ? [error.message] : causeChain(error)
|
|
138
|
+
if (json) {
|
|
139
|
+
console.error(JSON.stringify({ error: message, causes }))
|
|
140
|
+
} else {
|
|
141
|
+
console.error(message)
|
|
142
|
+
for (const cause of causes) console.error(` caused by: ${cause}`)
|
|
143
|
+
}
|
|
144
|
+
if (process.env.BUZON_DEBUG && error instanceof Error && error.stack) {
|
|
145
|
+
console.error(error.stack)
|
|
146
|
+
}
|
|
147
|
+
process.exitCode = usage ? 2 : 1
|
|
148
|
+
}
|
|
149
|
+
}
|