@daski/pay 0.1.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/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/bin/daski.d.ts +3 -0
- package/dist/bin/daski.d.ts.map +1 -0
- package/dist/bin/daski.js +187 -0
- package/dist/bin/daski.js.map +1 -0
- package/dist/cli/args.d.ts +11 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +82 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/errors.d.ts +24 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +23 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/output.d.ts +8 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +76 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +12 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +101 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/redact.d.ts +26 -0
- package/dist/cli/redact.d.ts.map +1 -0
- package/dist/cli/redact.js +55 -0
- package/dist/cli/redact.js.map +1 -0
- package/dist/commands/buy.d.ts +15 -0
- package/dist/commands/buy.d.ts.map +1 -0
- package/dist/commands/buy.js +276 -0
- package/dist/commands/buy.js.map +1 -0
- package/dist/commands/doctor.d.ts +29 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +173 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/order.d.ts +18 -0
- package/dist/commands/order.d.ts.map +1 -0
- package/dist/commands/order.js +256 -0
- package/dist/commands/order.js.map +1 -0
- package/dist/commands/signPayment.d.ts +10 -0
- package/dist/commands/signPayment.d.ts.map +1 -0
- package/dist/commands/signPayment.js +162 -0
- package/dist/commands/signPayment.js.map +1 -0
- package/dist/commands/wallet.d.ts +11 -0
- package/dist/commands/wallet.d.ts.map +1 -0
- package/dist/commands/wallet.js +104 -0
- package/dist/commands/wallet.js.map +1 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +200 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +36 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +54 -0
- package/dist/context.js.map +1 -0
- package/dist/gateway/balance.d.ts +16 -0
- package/dist/gateway/balance.d.ts.map +1 -0
- package/dist/gateway/balance.js +23 -0
- package/dist/gateway/balance.js.map +1 -0
- package/dist/gateway/catalog.d.ts +49 -0
- package/dist/gateway/catalog.d.ts.map +1 -0
- package/dist/gateway/catalog.js +161 -0
- package/dist/gateway/catalog.js.map +1 -0
- package/dist/gateway/client.d.ts +80 -0
- package/dist/gateway/client.d.ts.map +1 -0
- package/dist/gateway/client.js +128 -0
- package/dist/gateway/client.js.map +1 -0
- package/dist/gateway/lifecycle.d.ts +45 -0
- package/dist/gateway/lifecycle.d.ts.map +1 -0
- package/dist/gateway/lifecycle.js +96 -0
- package/dist/gateway/lifecycle.js.map +1 -0
- package/dist/gateway/purchase.d.ts +119 -0
- package/dist/gateway/purchase.d.ts.map +1 -0
- package/dist/gateway/purchase.js +250 -0
- package/dist/gateway/purchase.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +11 -0
- package/dist/paths.js.map +1 -0
- package/dist/signers/cdp.d.ts +7 -0
- package/dist/signers/cdp.d.ts.map +1 -0
- package/dist/signers/cdp.js +42 -0
- package/dist/signers/cdp.js.map +1 -0
- package/dist/signers/circle.d.ts +53 -0
- package/dist/signers/circle.d.ts.map +1 -0
- package/dist/signers/circle.js +136 -0
- package/dist/signers/circle.js.map +1 -0
- package/dist/signers/index.d.ts +23 -0
- package/dist/signers/index.d.ts.map +1 -0
- package/dist/signers/index.js +22 -0
- package/dist/signers/index.js.map +1 -0
- package/dist/signers/local.d.ts +3 -0
- package/dist/signers/local.d.ts.map +1 -0
- package/dist/signers/local.js +24 -0
- package/dist/signers/local.js.map +1 -0
- package/dist/signers/selfTest.d.ts +46 -0
- package/dist/signers/selfTest.d.ts.map +1 -0
- package/dist/signers/selfTest.js +113 -0
- package/dist/signers/selfTest.js.map +1 -0
- package/dist/store/keystore.d.ts +19 -0
- package/dist/store/keystore.d.ts.map +1 -0
- package/dist/store/keystore.js +226 -0
- package/dist/store/keystore.js.map +1 -0
- package/dist/store/orders.d.ts +39 -0
- package/dist/store/orders.d.ts.map +1 -0
- package/dist/store/orders.js +91 -0
- package/dist/store/orders.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +21 -0
- package/dist/version.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daski
|
|
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,102 @@
|
|
|
1
|
+
# `@daski/pay`
|
|
2
|
+
|
|
3
|
+
The Daski buyer bridge. A CLI that buys outcomes, tracks orders across
|
|
4
|
+
processes, and refuses to sign anything it has not independently checked.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx @daski/pay@0.1.0 doctor --json
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
> Server proposes; buyer bridge validates against its own expectations and
|
|
11
|
+
> recomputes; wallet signs; the gateway never sees the key.
|
|
12
|
+
|
|
13
|
+
## Commands
|
|
14
|
+
|
|
15
|
+
| Command | What it does |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `daski doctor` | Readiness report; exits 0 only when nothing blocks. Every issue carries a remediation |
|
|
18
|
+
| `daski wallet create` | Generate a local EOA — interactive human confirmation required |
|
|
19
|
+
| `daski wallet address` / `balance` | The active payer address; native + USDC balances |
|
|
20
|
+
| `daski buy --provider <id> --outcome <id> --request <file.json>` | Challenge → approve → validate → sign → submit → record |
|
|
21
|
+
| `daski order status <handle>` | Read an order's state |
|
|
22
|
+
| `daski order artifact <handle>` | Write the result **to a file**, never to stdout |
|
|
23
|
+
| `daski order confirm/input/cancel <handle>` | Mutating lifecycle actions |
|
|
24
|
+
| `daski sign-payment --challenge <file.json>` | Validate, recompute, sign; print the exact `paymentPayload` |
|
|
25
|
+
|
|
26
|
+
All support `--json`. Global flags: `--profile`, `--signer <local|cdp|circle>`,
|
|
27
|
+
`--cdp-account`, `--circle-wallet`, `--max-per-order`, `--session-cap`.
|
|
28
|
+
|
|
29
|
+
## Spend caps are yours, not the agent's
|
|
30
|
+
|
|
31
|
+
`maxPerOrderUsdc`, `sessionCapUsdc` and `requireApprovalAboveUsdc` live only
|
|
32
|
+
in `~/.daski/config.json`. **No flag and no environment variable can raise
|
|
33
|
+
them.** `--max-per-order` and `--session-cap` may lower a cap for a single
|
|
34
|
+
invocation; a value above the configured one is refused.
|
|
35
|
+
|
|
36
|
+
Above `requireApprovalAboveUsdc`, `daski buy` shows the approval summary and
|
|
37
|
+
waits for a human. In `--json` or non-TTY mode it does not quietly proceed —
|
|
38
|
+
it exits `2` and explains how a human can approve.
|
|
39
|
+
|
|
40
|
+
The running session total is read from `~/.daski/orders.json`, so the cap
|
|
41
|
+
holds across processes rather than resetting whenever an agent restarts.
|
|
42
|
+
|
|
43
|
+
## Orders survive the process that placed them
|
|
44
|
+
|
|
45
|
+
Every order is recorded in `~/.daski/orders.json` — handle, intent id,
|
|
46
|
+
provider/outcome, amount, state, read capability and expiry. `daski order
|
|
47
|
+
status` works from a cold start with nothing but the handle.
|
|
48
|
+
|
|
49
|
+
The intent is recorded **before** the signature goes out, which is what makes
|
|
50
|
+
an interrupted purchase recoverable.
|
|
51
|
+
|
|
52
|
+
## Interrupted purchases are reconciled, never re-signed
|
|
53
|
+
|
|
54
|
+
On a timeout, a `PAYMENT_PENDING_RECONCILIATION`, or a transport drop after
|
|
55
|
+
submit, the CLI replays the *identical* signed authorization — idempotent by
|
|
56
|
+
the gateway's own published retry policy — and corroborates against the
|
|
57
|
+
payer's own order history. Only when both agree no order exists does it report
|
|
58
|
+
the purchase as safely retryable.
|
|
59
|
+
|
|
60
|
+
A second signature over a fresh challenge is a second order, and a second
|
|
61
|
+
charge. See [reconciliation](../../docs/policy.md#reconciliation).
|
|
62
|
+
|
|
63
|
+
## Artifacts are written, not printed
|
|
64
|
+
|
|
65
|
+
`daski order artifact` writes the provider's bytes to a file and prints only
|
|
66
|
+
the envelope metadata. Provider results are validated but untrusted, and both
|
|
67
|
+
a terminal and an agent's context window are interpreters: dumping untrusted
|
|
68
|
+
content into one is how "here is your result" becomes "here are your
|
|
69
|
+
instructions".
|
|
70
|
+
|
|
71
|
+
## Signers
|
|
72
|
+
|
|
73
|
+
`local` is the default and the one adapter the conformance suite has verified.
|
|
74
|
+
`cdp` and `circle` are implemented and marked *candidate pending conformance*
|
|
75
|
+
until a run passes; `daski doctor` says so rather than implying otherwise. The
|
|
76
|
+
Circle adapter accepts EOA wallets only: a smart-contract account signs via
|
|
77
|
+
ERC-1271, which the gateway's plain ECDSA recovery cannot verify. Every
|
|
78
|
+
adapter has to pass the doctor self-test — sign a fixed, unsettleable vector
|
|
79
|
+
that recovers to its own address with a low-s signature — before it is
|
|
80
|
+
reported usable.
|
|
81
|
+
|
|
82
|
+
See [signer adapters](../../docs/signers.md).
|
|
83
|
+
|
|
84
|
+
## Keys
|
|
85
|
+
|
|
86
|
+
OS keychain by default, scrypt+AES-256-GCM file as a fallback,
|
|
87
|
+
`DASKI_PAYER_PRIVATE_KEY` for sandbox development (which `doctor` flags every
|
|
88
|
+
time). Keys never appear in logs, JSON output, or error messages.
|
|
89
|
+
|
|
90
|
+
See [key storage](../../docs/keys.md).
|
|
91
|
+
|
|
92
|
+
## Documentation
|
|
93
|
+
|
|
94
|
+
[Policy validator](../../docs/policy.md) ·
|
|
95
|
+
[Configuration](../../docs/config.md) ·
|
|
96
|
+
[Keys](../../docs/keys.md) ·
|
|
97
|
+
[Signers](../../docs/signers.md) ·
|
|
98
|
+
[Conformance](../../docs/conformance.md)
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daski.d.ts","sourceRoot":"","sources":["../../src/bin/daski.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `daski` entry point.
|
|
4
|
+
*
|
|
5
|
+
* Every command supports `--json`. Every failure exits non-zero with a code
|
|
6
|
+
* and a remediation. Nothing here signs anything: the commands do, and only
|
|
7
|
+
* through the §4 validator.
|
|
8
|
+
*/
|
|
9
|
+
import { assertKnownFlags, boolFlag, parseArgs, requireFlag, stringFlag } from "../cli/args.js";
|
|
10
|
+
import { CliError } from "../cli/errors.js";
|
|
11
|
+
import { emit, emitError } from "../cli/output.js";
|
|
12
|
+
import { runBuy } from "../commands/buy.js";
|
|
13
|
+
import { runDoctor } from "../commands/doctor.js";
|
|
14
|
+
import { orderArtifact, orderCancel, orderConfirm, orderInput, orderStatus, } from "../commands/order.js";
|
|
15
|
+
import { runSignPayment } from "../commands/signPayment.js";
|
|
16
|
+
import { createWallet, walletAddress, walletBalance } from "../commands/wallet.js";
|
|
17
|
+
import { CLI_VERSION } from "../version.js";
|
|
18
|
+
/** Flags every command accepts. */
|
|
19
|
+
const GLOBAL_FLAGS = [
|
|
20
|
+
"json", "profile", "signer", "cdp-account", "circle-wallet",
|
|
21
|
+
"max-per-order", "session-cap",
|
|
22
|
+
];
|
|
23
|
+
const USAGE = `daski ${CLI_VERSION} — the Daski buyer bridge
|
|
24
|
+
|
|
25
|
+
The server proposes; this bridge validates against its own expectations and
|
|
26
|
+
recomputes; your wallet signs; the gateway never sees your key.
|
|
27
|
+
|
|
28
|
+
Commands
|
|
29
|
+
doctor Readiness report, with a remediation per issue
|
|
30
|
+
wallet create Generate a local EOA (requires human confirmation)
|
|
31
|
+
wallet address Print the active payer address
|
|
32
|
+
wallet balance Print native + USDC balances
|
|
33
|
+
buy --provider <id> --outcome <id> --request <file.json> [--payer <addr>]
|
|
34
|
+
Challenge, approve, validate, sign, submit, record
|
|
35
|
+
order status <handle> Read an order's state
|
|
36
|
+
order artifact <handle> [--output <file>]
|
|
37
|
+
Write the result bytes to a file (never to stdout)
|
|
38
|
+
order confirm <handle> Confirm delivery
|
|
39
|
+
order input <handle> --request <file.json>
|
|
40
|
+
Submit requested customer input
|
|
41
|
+
order cancel <handle> Request cancellation
|
|
42
|
+
sign-payment --challenge <file.json> [--provider <id> --outcome <id>]
|
|
43
|
+
Validate, recompute, sign; print the paymentPayload
|
|
44
|
+
|
|
45
|
+
Global flags
|
|
46
|
+
--json Machine-readable output
|
|
47
|
+
--profile <name> Config profile (default: sandbox)
|
|
48
|
+
--signer <local|cdp|circle> Override the profile's signer
|
|
49
|
+
--cdp-account <name> CDP account for --signer cdp (or DASKI_CDP_ACCOUNT)
|
|
50
|
+
--circle-wallet <id> Circle wallet id for --signer circle (or DASKI_CIRCLE_WALLET)
|
|
51
|
+
--max-per-order <usdc> Lower the per-order cap for this run only
|
|
52
|
+
--session-cap <usdc> Lower the session cap for this run only
|
|
53
|
+
|
|
54
|
+
Caps live in ~/.daski/config.json and are human-owned: a flag may lower one,
|
|
55
|
+
never raise it. See https://github.com/daski-io/buyer#readme
|
|
56
|
+
`;
|
|
57
|
+
async function main(argv) {
|
|
58
|
+
const { command, flags } = parseArgs(argv);
|
|
59
|
+
const json = boolFlag(flags, "json");
|
|
60
|
+
const output = { json };
|
|
61
|
+
if (command.length === 0 || command[0] === "help" || boolFlag(flags, "help")) {
|
|
62
|
+
process.stdout.write(USAGE);
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (command[0] === "version" || boolFlag(flags, "version")) {
|
|
66
|
+
emit({ version: CLI_VERSION }, output);
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
const shared = {
|
|
70
|
+
profile: stringFlag(flags, "profile"),
|
|
71
|
+
signerOverride: stringFlag(flags, "signer"),
|
|
72
|
+
cdpAccount: stringFlag(flags, "cdp-account"),
|
|
73
|
+
circleWallet: stringFlag(flags, "circle-wallet"),
|
|
74
|
+
maxPerOrderUsdc: stringFlag(flags, "max-per-order"),
|
|
75
|
+
sessionCapUsdc: stringFlag(flags, "session-cap"),
|
|
76
|
+
};
|
|
77
|
+
switch (command[0]) {
|
|
78
|
+
case "doctor": {
|
|
79
|
+
assertKnownFlags(flags, GLOBAL_FLAGS);
|
|
80
|
+
const report = await runDoctor(shared);
|
|
81
|
+
emit({ ...report }, output);
|
|
82
|
+
return report.ok ? 0 : 1;
|
|
83
|
+
}
|
|
84
|
+
case "wallet": {
|
|
85
|
+
assertKnownFlags(flags, [...GLOBAL_FLAGS, "yes-human-approved"]);
|
|
86
|
+
const walletOptions = {
|
|
87
|
+
profile: shared.profile,
|
|
88
|
+
signerOverride: shared.signerOverride,
|
|
89
|
+
cdpAccount: shared.cdpAccount,
|
|
90
|
+
circleWallet: shared.circleWallet,
|
|
91
|
+
yesHumanApproved: boolFlag(flags, "yes-human-approved"),
|
|
92
|
+
};
|
|
93
|
+
switch (command[1]) {
|
|
94
|
+
case "create":
|
|
95
|
+
emit(await createWallet(walletOptions), output);
|
|
96
|
+
return 0;
|
|
97
|
+
case "address":
|
|
98
|
+
emit(await walletAddress(walletOptions), output);
|
|
99
|
+
return 0;
|
|
100
|
+
case "balance":
|
|
101
|
+
emit(await walletBalance(walletOptions), output);
|
|
102
|
+
return 0;
|
|
103
|
+
default:
|
|
104
|
+
throw unknownSubcommand("wallet", command[1], ["create", "address", "balance"]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
case "buy": {
|
|
108
|
+
assertKnownFlags(flags, [...GLOBAL_FLAGS, "provider", "outcome", "request", "payer", "legacy-arg", "yes"]);
|
|
109
|
+
const result = await runBuy({
|
|
110
|
+
...shared,
|
|
111
|
+
providerAgentId: requireFlag(flags, "provider"),
|
|
112
|
+
outcomeId: requireFlag(flags, "outcome"),
|
|
113
|
+
requestFile: requireFlag(flags, "request"),
|
|
114
|
+
payer: stringFlag(flags, "payer"),
|
|
115
|
+
legacyArg: boolFlag(flags, "legacy-arg"),
|
|
116
|
+
yes: boolFlag(flags, "yes"),
|
|
117
|
+
json,
|
|
118
|
+
});
|
|
119
|
+
emit(result, output);
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
case "order": {
|
|
123
|
+
const handle = command[2];
|
|
124
|
+
if (!handle) {
|
|
125
|
+
throw new CliError({
|
|
126
|
+
code: "DASKI_ORDER_HANDLE_REQUIRED",
|
|
127
|
+
message: `\`daski order ${command[1] ?? "<action>"}\` needs an order handle.`,
|
|
128
|
+
remediation: "Pass the handle printed by `daski buy`, or its intent id.",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const base = { ...shared, handle, json };
|
|
132
|
+
switch (command[1]) {
|
|
133
|
+
case "status":
|
|
134
|
+
assertKnownFlags(flags, GLOBAL_FLAGS);
|
|
135
|
+
emit(await orderStatus(base), output);
|
|
136
|
+
return 0;
|
|
137
|
+
case "artifact":
|
|
138
|
+
assertKnownFlags(flags, [...GLOBAL_FLAGS, "output"]);
|
|
139
|
+
emit(await orderArtifact({ ...base, output: stringFlag(flags, "output") }), output);
|
|
140
|
+
return 0;
|
|
141
|
+
case "confirm":
|
|
142
|
+
assertKnownFlags(flags, GLOBAL_FLAGS);
|
|
143
|
+
emit(await orderConfirm(base), output);
|
|
144
|
+
return 0;
|
|
145
|
+
case "cancel":
|
|
146
|
+
assertKnownFlags(flags, GLOBAL_FLAGS);
|
|
147
|
+
emit(await orderCancel(base), output);
|
|
148
|
+
return 0;
|
|
149
|
+
case "input":
|
|
150
|
+
assertKnownFlags(flags, [...GLOBAL_FLAGS, "request"]);
|
|
151
|
+
emit(await orderInput({ ...base, requestFile: requireFlag(flags, "request") }), output);
|
|
152
|
+
return 0;
|
|
153
|
+
default:
|
|
154
|
+
throw unknownSubcommand("order", command[1], ["status", "artifact", "confirm", "input", "cancel"]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
case "sign-payment": {
|
|
158
|
+
assertKnownFlags(flags, [...GLOBAL_FLAGS, "challenge", "provider", "outcome"]);
|
|
159
|
+
emit(await runSignPayment({
|
|
160
|
+
...shared,
|
|
161
|
+
challengeFile: requireFlag(flags, "challenge"),
|
|
162
|
+
providerAgentId: stringFlag(flags, "provider"),
|
|
163
|
+
outcomeId: stringFlag(flags, "outcome"),
|
|
164
|
+
json,
|
|
165
|
+
}), output);
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
default:
|
|
169
|
+
throw new CliError({
|
|
170
|
+
code: "DASKI_UNKNOWN_COMMAND",
|
|
171
|
+
message: `Unknown command "${command[0]}".`,
|
|
172
|
+
remediation: "Run `daski help` to see the available commands.",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function unknownSubcommand(group, given, known) {
|
|
177
|
+
return new CliError({
|
|
178
|
+
code: "DASKI_UNKNOWN_SUBCOMMAND",
|
|
179
|
+
message: `Unknown \`daski ${group}\` subcommand: ${given ?? "(none)"}`,
|
|
180
|
+
remediation: `Use one of: ${known.map((name) => `daski ${group} ${name}`).join(", ")}`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
const json = process.argv.includes("--json");
|
|
184
|
+
main(process.argv.slice(2))
|
|
185
|
+
.then((code) => { process.exitCode = code; })
|
|
186
|
+
.catch((error) => { process.exitCode = emitError(error, { json }); });
|
|
187
|
+
//# sourceMappingURL=daski.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daski.js","sourceRoot":"","sources":["../../src/bin/daski.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ParsedArgs {
|
|
2
|
+
command: string[];
|
|
3
|
+
flags: Record<string, string | boolean>;
|
|
4
|
+
}
|
|
5
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
6
|
+
export declare function stringFlag(flags: Record<string, string | boolean>, name: string): string | undefined;
|
|
7
|
+
export declare function boolFlag(flags: Record<string, string | boolean>, name: string): boolean;
|
|
8
|
+
export declare function requireFlag(flags: Record<string, string | boolean>, name: string): string;
|
|
9
|
+
/** Rejects flags the command does not understand, rather than ignoring them. */
|
|
10
|
+
export declare function assertKnownFlags(flags: Record<string, string | boolean>, known: readonly string[]): void;
|
|
11
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;CACzC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuBpD;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACvC,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACvC,IAAI,EAAE,MAAM,GACX,MAAM,CAUR;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACvC,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,IAAI,CAWN"}
|
package/dist/cli/args.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small, explicit argument parser.
|
|
3
|
+
*
|
|
4
|
+
* Explicit because the flag surface is a security boundary: an unknown flag is
|
|
5
|
+
* an error rather than something silently ignored, so a typo in
|
|
6
|
+
* `--max-per-order` can never be mistaken for a cap that was applied.
|
|
7
|
+
*/
|
|
8
|
+
import { CliError } from "./errors.js";
|
|
9
|
+
export function parseArgs(argv) {
|
|
10
|
+
const command = [];
|
|
11
|
+
const flags = {};
|
|
12
|
+
let index = 0;
|
|
13
|
+
for (; index < argv.length; index += 1) {
|
|
14
|
+
const token = argv[index];
|
|
15
|
+
if (token === "--") {
|
|
16
|
+
index += 1;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
if (!token.startsWith("-")) {
|
|
20
|
+
command.push(token);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const name = token.replace(/^--?/, "");
|
|
24
|
+
const [key, inlineValue] = name.includes("=")
|
|
25
|
+
? [name.slice(0, name.indexOf("=")), name.slice(name.indexOf("=") + 1)]
|
|
26
|
+
: [name, undefined];
|
|
27
|
+
if (inlineValue !== undefined) {
|
|
28
|
+
flags[key] = inlineValue;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const next = argv[index + 1];
|
|
32
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
33
|
+
flags[key] = next;
|
|
34
|
+
index += 1;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
flags[key] = true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
command.push(...argv.slice(index));
|
|
41
|
+
return { command, flags };
|
|
42
|
+
}
|
|
43
|
+
export function stringFlag(flags, name) {
|
|
44
|
+
const value = flags[name];
|
|
45
|
+
if (value === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (typeof value !== "string") {
|
|
48
|
+
throw new CliError({
|
|
49
|
+
code: "DASKI_FLAG_NEEDS_VALUE",
|
|
50
|
+
message: `--${name} needs a value.`,
|
|
51
|
+
remediation: `Pass a value, e.g. --${name} <value>`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
export function boolFlag(flags, name) {
|
|
57
|
+
return flags[name] === true || flags[name] === "true";
|
|
58
|
+
}
|
|
59
|
+
export function requireFlag(flags, name) {
|
|
60
|
+
const value = stringFlag(flags, name);
|
|
61
|
+
if (value === undefined) {
|
|
62
|
+
throw new CliError({
|
|
63
|
+
code: "DASKI_FLAG_REQUIRED",
|
|
64
|
+
message: `--${name} is required.`,
|
|
65
|
+
remediation: `Re-run with --${name} <value>. See \`daski help\`.`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
/** Rejects flags the command does not understand, rather than ignoring them. */
|
|
71
|
+
export function assertKnownFlags(flags, known) {
|
|
72
|
+
const unknown = Object.keys(flags).filter((flag) => !known.includes(flag));
|
|
73
|
+
if (unknown.length > 0) {
|
|
74
|
+
throw new CliError({
|
|
75
|
+
code: "DASKI_UNKNOWN_FLAG",
|
|
76
|
+
message: `Unknown flag${unknown.length > 1 ? "s" : ""}: ${unknown.map((f) => `--${f}`).join(", ")}`,
|
|
77
|
+
remediation: `This command accepts: ${known.map((f) => `--${f}`).join(", ")}. ` +
|
|
78
|
+
"An ignored flag could look like an applied spend cap, so unknown flags are refused.",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A CLI failure the operator can act on: a stable code, a sentence, and the
|
|
3
|
+
* exact next step. Anything that reaches the user without a remediation is a
|
|
4
|
+
* bug in this file's callers, not a UX preference.
|
|
5
|
+
*/
|
|
6
|
+
export interface CliErrorOptions {
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
remediation: string;
|
|
10
|
+
/** Extra machine-readable context. Never key material. */
|
|
11
|
+
details?: Record<string, unknown>;
|
|
12
|
+
/** Process exit code; defaults to 1. */
|
|
13
|
+
exitCode?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class CliError extends Error {
|
|
16
|
+
readonly name = "CliError";
|
|
17
|
+
readonly code: string;
|
|
18
|
+
readonly remediation: string;
|
|
19
|
+
readonly details: Record<string, unknown>;
|
|
20
|
+
readonly exitCode: number;
|
|
21
|
+
constructor(options: CliErrorOptions);
|
|
22
|
+
toJSON(): Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAkB,IAAI,cAAc;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,eAAe;IAQpC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class CliError extends Error {
|
|
2
|
+
name = "CliError";
|
|
3
|
+
code;
|
|
4
|
+
remediation;
|
|
5
|
+
details;
|
|
6
|
+
exitCode;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super(options.message);
|
|
9
|
+
this.code = options.code;
|
|
10
|
+
this.remediation = options.remediation;
|
|
11
|
+
this.details = options.details ?? {};
|
|
12
|
+
this.exitCode = options.exitCode ?? 1;
|
|
13
|
+
}
|
|
14
|
+
toJSON() {
|
|
15
|
+
return {
|
|
16
|
+
error: this.code,
|
|
17
|
+
message: this.message,
|
|
18
|
+
remediation: this.remediation,
|
|
19
|
+
...this.details,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACf,IAAI,GAAG,UAAU,CAAC;IAC3B,IAAI,CAAS;IACb,WAAW,CAAS;IACpB,OAAO,CAA0B;IACjC,QAAQ,CAAS;IAE1B,YAAY,OAAwB;QAClC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,MAAM;QACJ,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,IAAI,CAAC,OAAO;SAChB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface OutputOptions {
|
|
2
|
+
json: boolean;
|
|
3
|
+
}
|
|
4
|
+
export declare function emit(value: Record<string, unknown>, options: OutputOptions): void;
|
|
5
|
+
/** Human output goes to stdout; progress and prompts go to stderr. */
|
|
6
|
+
export declare function note(message: string): void;
|
|
7
|
+
export declare function emitError(error: unknown, options: OutputOptions): number;
|
|
8
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAMjF;AAED,sEAAsE;AACtE,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAaxE"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output. Two modes, one rule: everything is redacted on the way out.
|
|
3
|
+
*/
|
|
4
|
+
import { redactValue } from "./redact.js";
|
|
5
|
+
import { CliError } from "./errors.js";
|
|
6
|
+
export function emit(value, options) {
|
|
7
|
+
if (options.json) {
|
|
8
|
+
process.stdout.write(`${JSON.stringify(redactValue(value), null, 2)}\n`);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
process.stdout.write(`${renderHuman(redactValue(value))}\n`);
|
|
12
|
+
}
|
|
13
|
+
/** Human output goes to stdout; progress and prompts go to stderr. */
|
|
14
|
+
export function note(message) {
|
|
15
|
+
process.stderr.write(`${message}\n`);
|
|
16
|
+
}
|
|
17
|
+
export function emitError(error, options) {
|
|
18
|
+
const payload = errorPayload(error);
|
|
19
|
+
if (options.json) {
|
|
20
|
+
process.stdout.write(`${JSON.stringify(redactValue(payload), null, 2)}\n`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const redacted = redactValue(payload);
|
|
24
|
+
process.stderr.write(`error: ${String(redacted.message)}\n`);
|
|
25
|
+
if (redacted.check)
|
|
26
|
+
process.stderr.write(` failed check: ${String(redacted.check)}\n`);
|
|
27
|
+
if (redacted.expected)
|
|
28
|
+
process.stderr.write(` expected: ${String(redacted.expected)}\n`);
|
|
29
|
+
if (redacted.actual)
|
|
30
|
+
process.stderr.write(` actual: ${String(redacted.actual)}\n`);
|
|
31
|
+
process.stderr.write(` fix: ${String(redacted.remediation)}\n`);
|
|
32
|
+
}
|
|
33
|
+
return error instanceof CliError ? error.exitCode : 1;
|
|
34
|
+
}
|
|
35
|
+
function errorPayload(error) {
|
|
36
|
+
if (error && typeof error.toJSON === "function") {
|
|
37
|
+
return error.toJSON();
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
error: "DASKI_UNEXPECTED_ERROR",
|
|
41
|
+
message: error instanceof Error ? error.message : String(error),
|
|
42
|
+
remediation: "Re-run with --json for the full payload, and report this if it persists.",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function renderHuman(value, indent = "") {
|
|
46
|
+
const lines = [];
|
|
47
|
+
for (const [key, item] of Object.entries(value)) {
|
|
48
|
+
if (item === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
51
|
+
lines.push(`${indent}${key}:`);
|
|
52
|
+
lines.push(renderHuman(item, `${indent} `));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(item)) {
|
|
56
|
+
if (item.length === 0) {
|
|
57
|
+
lines.push(`${indent}${key}: (none)`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
lines.push(`${indent}${key}:`);
|
|
61
|
+
for (const entry of item) {
|
|
62
|
+
if (entry && typeof entry === "object") {
|
|
63
|
+
lines.push(renderHuman(entry, `${indent} - `.slice(0, -2) + " "));
|
|
64
|
+
lines.push("");
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
lines.push(`${indent} - ${String(entry)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
lines.push(`${indent}${key}: ${String(item)}`);
|
|
73
|
+
}
|
|
74
|
+
return lines.filter((line, index, all) => line !== "" || all[index + 1] !== undefined).join("\n");
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function isInteractive(): boolean;
|
|
2
|
+
/** Asks a yes/no question. Anything but an explicit yes is a no. */
|
|
3
|
+
export declare function confirm(question: string): Promise<boolean>;
|
|
4
|
+
/** Requires the operator to retype an exact phrase. Used for key creation. */
|
|
5
|
+
export declare function confirmPhrase(question: string, phrase: string): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Reads a passphrase without echoing it. The typed characters are never
|
|
8
|
+
* written back to the terminal and never leave this function except as the
|
|
9
|
+
* return value.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readPassphrase(prompt: string): Promise<string>;
|
|
12
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/cli/prompt.ts"],"names":[],"mappings":"AAcA,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,oEAAoE;AACpE,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAShE;AAED,8EAA8E;AAC9E,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAStF;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDpE"}
|