primcli 1.13.1 → 1.13.3
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/README.md +8 -8
- package/dist/oclif/index.js +75 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,17 +99,17 @@ cat challenge.json | primitive payments pay
|
|
|
99
99
|
primitive payments create-email-challenge --from payee@your-domain.example \
|
|
100
100
|
--to payer@their-domain.example --amount 10000 --network base-sepolia
|
|
101
101
|
# Payer (recommended): pay the email challenge in one step. Signs the challenge
|
|
102
|
-
# locally with your wallet key AND sends the signed interaction.json
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
# customize it.
|
|
102
|
+
# locally with your wallet key AND sends the signed interaction.json, so you
|
|
103
|
+
# skip the manual sign-then-send dance. --in-reply-to is the inbound challenge
|
|
104
|
+
# email you received; it is fetched to address the payment to the payee, with
|
|
105
|
+
# From defaulting to the payer it was sent to. The send is not threaded under
|
|
106
|
+
# the challenge (the payment associates by interaction_id). The message carries
|
|
107
|
+
# a short default note alongside the attachment; pass --body to customize it.
|
|
108
108
|
primitive payments pay-email --challenge-file challenge.json \
|
|
109
109
|
--in-reply-to <inbound-challenge-email-id> --wait
|
|
110
110
|
|
|
111
111
|
# Advanced: sign only, without sending. Emits the portable interaction.json
|
|
112
|
-
# artifact you can attach
|
|
112
|
+
# artifact you can attach yourself (e.g. with `primitive send --attachment`).
|
|
113
113
|
primitive payments pay-email-step --challenge-file challenge.json > interaction.json
|
|
114
114
|
|
|
115
115
|
# Inspect a challenge by id, or list your registered payout addresses.
|
|
@@ -124,7 +124,7 @@ primitive payments update-spend-policy --max-per-payment 5000000
|
|
|
124
124
|
|
|
125
125
|
`charge` is the friendly verb that matches the SDK `charge` and accepts `--amount-usdc`; `create-challenge` is the lower-level command that takes base-unit `--amount`. Either creates a challenge. The signing commands print a human-readable summary by default; pass `--json` for raw JSON suitable for piping.
|
|
126
126
|
|
|
127
|
-
The signing commands (`register-payout-address`, `pay`, `pay-email`, and `pay-email-step`) need your wallet key. `pay-email` is the recommended payer path for the email-native flow: it signs and
|
|
127
|
+
The signing commands (`register-payout-address`, `pay`, `pay-email`, and `pay-email-step`) need your wallet key. `pay-email` is the recommended payer path for the email-native flow: it signs and sends in one step. `pay-email-step` signs only and emits the `interaction.json` artifact for advanced use where you want to deliver it yourself. Set the key in `PRIMITIVE_X402_PRIVATE_KEY` (a `0x`-prefixed hex private key) so it never lands in shell history or the process list:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
130
|
export PRIMITIVE_X402_PRIVATE_KEY=0x...
|
package/dist/oclif/index.js
CHANGED
|
@@ -20955,7 +20955,7 @@ function assertParentMatchesRecipient(parent, recipient) {
|
|
|
20955
20955
|
if (normalizeEmailAddress(parent.from_email) === normalizeEmailAddress(recipient)) return;
|
|
20956
20956
|
throw cliError$6(`Inbound email ${parent.id} is from ${parent.from_email}, not ${recipient}. Use \`primitive chat ${parent.from_email} --reply <message> --reply-to-email-id ${parent.id}\` or omit --reply-to-email-id to continue the latest inbound from ${recipient}.`);
|
|
20957
20957
|
}
|
|
20958
|
-
function emailDetailFromEnvelope(envelope) {
|
|
20958
|
+
function emailDetailFromEnvelope$1(envelope) {
|
|
20959
20959
|
return envelope?.data ?? envelope ?? null;
|
|
20960
20960
|
}
|
|
20961
20961
|
function buildCommand(kind, description, argv, options = {}) {
|
|
@@ -21205,7 +21205,7 @@ async function loadInboundEmailDetail(params) {
|
|
|
21205
21205
|
});
|
|
21206
21206
|
throw new Errors.CLIError(`Could not load inbound email ${params.id}.`, { exit: 1 });
|
|
21207
21207
|
}
|
|
21208
|
-
const detail = emailDetailFromEnvelope(result.data);
|
|
21208
|
+
const detail = emailDetailFromEnvelope$1(result.data);
|
|
21209
21209
|
if (!detail) throw new Errors.CLIError(`Could not load inbound email ${params.id}: the API returned no email body.`, { exit: 1 });
|
|
21210
21210
|
return detail;
|
|
21211
21211
|
}
|
|
@@ -23864,8 +23864,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
23864
23864
|
name: "Primitive Team",
|
|
23865
23865
|
url: "https://primitive.dev"
|
|
23866
23866
|
};
|
|
23867
|
-
const SDK_VERSION_RANGE = "^1.13.
|
|
23868
|
-
const CLI_VERSION_RANGE = "^1.13.
|
|
23867
|
+
const SDK_VERSION_RANGE = "^1.13.3";
|
|
23868
|
+
const CLI_VERSION_RANGE = "^1.13.3";
|
|
23869
23869
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
23870
23870
|
function renderHandler() {
|
|
23871
23871
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -28293,7 +28293,8 @@ var PaymentsPayEmailStepCommand = class PaymentsPayEmailStepCommand extends Comm
|
|
|
28293
28293
|
/** The exact part name + content type the inbound matcher requires. */
|
|
28294
28294
|
const INTERACTION_PART_FILENAME = "interaction.json";
|
|
28295
28295
|
const INTERACTION_PART_CONTENT_TYPE = "application/json";
|
|
28296
|
-
const
|
|
28296
|
+
const DEFAULT_SUBJECT = "x402 payment authorization";
|
|
28297
|
+
const DEFAULT_BODY_TEXT = "x402 payment authorization attached (interaction.json).";
|
|
28297
28298
|
/** Build the `interaction.json` attachment from a signed payment step. */
|
|
28298
28299
|
function interactionAttachment(built) {
|
|
28299
28300
|
return {
|
|
@@ -28302,29 +28303,39 @@ function interactionAttachment(built) {
|
|
|
28302
28303
|
content_base64: Buffer.from(built.json, "utf8").toString("base64")
|
|
28303
28304
|
};
|
|
28304
28305
|
}
|
|
28306
|
+
/**
|
|
28307
|
+
* Pull the `EmailDetail` out of the get-email envelope. The fields wrapper
|
|
28308
|
+
* returns `{ data: { data: EmailDetail } }`; normalize to the inner detail or
|
|
28309
|
+
* null when the API returned no body.
|
|
28310
|
+
*/
|
|
28311
|
+
function emailDetailFromEnvelope(data) {
|
|
28312
|
+
return data?.data ?? null;
|
|
28313
|
+
}
|
|
28305
28314
|
var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
28306
|
-
static description = `Pay an email-native x402 challenge in one step: sign it and send the signed interaction.json
|
|
28315
|
+
static description = `Pay an email-native x402 challenge in one step: sign it and send the signed interaction.json in-thread.
|
|
28307
28316
|
|
|
28308
28317
|
Reads the email challenge the payee issued (the JSON from
|
|
28309
28318
|
\`payments create-email-challenge\`), derives and signs the interaction-bound
|
|
28310
28319
|
EIP-3009 authorization locally with your wallet key (read from
|
|
28311
|
-
${PRIVATE_KEY_ENV} by default), and
|
|
28312
|
-
|
|
28313
|
-
The key never leaves your machine.
|
|
28320
|
+
${PRIVATE_KEY_ENV} by default), and sends the signed \`interaction.json\`
|
|
28321
|
+
attached as an \`application/json\` part. The key never leaves your machine.
|
|
28314
28322
|
|
|
28315
28323
|
This is the recommended payer path. It replaces the two-step
|
|
28316
|
-
\`pay-email-step\` + \`
|
|
28324
|
+
\`pay-email-step\` + \`send --attachment interaction.json\` dance: no manual
|
|
28317
28325
|
address or threading wrangling. Use \`pay-email-step\` only when you need the
|
|
28318
28326
|
signed bytes as a portable artifact without sending.
|
|
28319
28327
|
|
|
28320
|
-
--in-reply-to is the id of the inbound challenge email you received
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28328
|
+
--in-reply-to is the id of the inbound challenge email you received. It is
|
|
28329
|
+
fetched to derive the recipient (the payee, from the inbound's sender) and the
|
|
28330
|
+
From (you, the payer, from the inbound's recipient). The outgoing send does
|
|
28331
|
+
NOT thread under the challenge: threading would trigger the send endpoint's
|
|
28332
|
+
parent-thread dedup and the payment would never settle. The interaction
|
|
28333
|
+
associates by interaction_id instead. Pass --from only to override the derived
|
|
28334
|
+
payer From.
|
|
28324
28335
|
|
|
28325
28336
|
Provide the challenge inline with --challenge, from a file with
|
|
28326
28337
|
--challenge-file, or piped on stdin.`;
|
|
28327
|
-
static summary = "Sign an email x402 challenge and send
|
|
28338
|
+
static summary = "Sign an email x402 challenge and send the signed interaction.json in-thread (one step)";
|
|
28328
28339
|
static examples = [
|
|
28329
28340
|
"<%= config.bin %> payments pay-email --challenge-file challenge.json --in-reply-to <inbound-email-id>",
|
|
28330
28341
|
"cat challenge.json | <%= config.bin %> payments pay-email --in-reply-to <inbound-email-id> --wait",
|
|
@@ -28353,12 +28364,12 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28353
28364
|
exclusive: ["challenge"]
|
|
28354
28365
|
}),
|
|
28355
28366
|
"in-reply-to": Flags.string({
|
|
28356
|
-
description: "Id of the inbound challenge email you received.
|
|
28367
|
+
description: "Id of the inbound challenge email you received. It is fetched to derive the payee recipient and the payer From. The outgoing send is not threaded under the challenge; the payment associates by interaction_id.",
|
|
28357
28368
|
required: true
|
|
28358
28369
|
}),
|
|
28359
28370
|
from: Flags.string({ description: "Optional From header override. Defaults to the inbound's recipient (the payer the challenge was addressed to)." }),
|
|
28360
|
-
body: Flags.string({ description: `Plain-text
|
|
28361
|
-
wait: Flags.boolean({ description: "Block until the receiving MTA returns an outcome. Without --wait, the call returns once Primitive has accepted the
|
|
28371
|
+
body: Flags.string({ description: `Plain-text body. The signed authorization travels in the interaction.json attachment; this is the human-readable accompanying note. Defaults to "${DEFAULT_BODY_TEXT}".` }),
|
|
28372
|
+
wait: Flags.boolean({ description: "Block until the receiving MTA returns an outcome. Without --wait, the call returns once Primitive has accepted the message for delivery." }),
|
|
28362
28373
|
json: Flags.boolean({ description: "Print a JSON object with the signed interaction step and the send result." }),
|
|
28363
28374
|
time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
|
|
28364
28375
|
};
|
|
@@ -28391,15 +28402,50 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28391
28402
|
process.exitCode = 1;
|
|
28392
28403
|
return;
|
|
28393
28404
|
}
|
|
28394
|
-
const
|
|
28405
|
+
const inboundResult = await getEmail({
|
|
28406
|
+
client: apiClient.client,
|
|
28407
|
+
path: { id: flags["in-reply-to"] },
|
|
28408
|
+
responseStyle: "fields"
|
|
28409
|
+
});
|
|
28410
|
+
if (inboundResult.error) {
|
|
28411
|
+
const errorPayload = extractErrorPayload(inboundResult.error);
|
|
28412
|
+
writeErrorWithHints(errorPayload);
|
|
28413
|
+
surfaceUnauthorizedHint({
|
|
28414
|
+
...authFailureContext,
|
|
28415
|
+
payload: errorPayload
|
|
28416
|
+
});
|
|
28417
|
+
process.exitCode = 1;
|
|
28418
|
+
return;
|
|
28419
|
+
}
|
|
28420
|
+
const inbound = emailDetailFromEnvelope(inboundResult.data);
|
|
28421
|
+
if (!inbound) {
|
|
28422
|
+
process.stderr.write(`Could not load inbound challenge email ${flags["in-reply-to"]}: the API returned no email.\n`);
|
|
28423
|
+
process.exitCode = 1;
|
|
28424
|
+
return;
|
|
28425
|
+
}
|
|
28426
|
+
const payeeTo = inbound.from_email;
|
|
28427
|
+
const derivedPayerFrom = inbound.to_email || inbound.recipient;
|
|
28428
|
+
const from = flags.from ?? derivedPayerFrom;
|
|
28429
|
+
if (!payeeTo) {
|
|
28430
|
+
process.stderr.write(`Inbound challenge email ${flags["in-reply-to"]} has no resolvable sender to address the payment to.\n`);
|
|
28431
|
+
process.exitCode = 1;
|
|
28432
|
+
return;
|
|
28433
|
+
}
|
|
28434
|
+
if (!from) {
|
|
28435
|
+
process.stderr.write(`Could not derive the payer From from inbound challenge email ${flags["in-reply-to"]}; pass --from explicitly.\n`);
|
|
28436
|
+
process.exitCode = 1;
|
|
28437
|
+
return;
|
|
28438
|
+
}
|
|
28439
|
+
const result = await sendEmail({
|
|
28395
28440
|
body: {
|
|
28396
|
-
|
|
28441
|
+
from,
|
|
28442
|
+
to: payeeTo,
|
|
28443
|
+
subject: DEFAULT_SUBJECT,
|
|
28444
|
+
body_text: flags.body?.trim() ? flags.body : DEFAULT_BODY_TEXT,
|
|
28397
28445
|
attachments: [interactionAttachment(built)],
|
|
28398
|
-
...flags.from !== void 0 ? { from: flags.from } : {},
|
|
28399
28446
|
...flags.wait !== void 0 ? { wait: flags.wait } : {}
|
|
28400
28447
|
},
|
|
28401
28448
|
client: apiClient.client,
|
|
28402
|
-
path: { id: flags["in-reply-to"] },
|
|
28403
28449
|
responseStyle: "fields"
|
|
28404
28450
|
});
|
|
28405
28451
|
if (result.error) {
|
|
@@ -28413,11 +28459,17 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28413
28459
|
return;
|
|
28414
28460
|
}
|
|
28415
28461
|
const sent = result.data?.data ?? null;
|
|
28462
|
+
const replayed = sent?.idempotent_replay === true;
|
|
28463
|
+
if (replayed) writeIdempotentReplayBannerIfReplay(sent, { write: (chunk) => {
|
|
28464
|
+
process.stderr.write(chunk);
|
|
28465
|
+
} });
|
|
28416
28466
|
if (flags.json) this.log(JSON.stringify({
|
|
28417
28467
|
interaction: built.envelope,
|
|
28418
|
-
sent
|
|
28468
|
+
sent,
|
|
28469
|
+
idempotent_replay: replayed
|
|
28419
28470
|
}, null, 2));
|
|
28420
28471
|
else this.log(JSON.stringify(sent, null, 2));
|
|
28472
|
+
if (replayed) process.exitCode = 1;
|
|
28421
28473
|
});
|
|
28422
28474
|
}
|
|
28423
28475
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primcli",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.3",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|