primcli 1.13.0 → 1.13.2
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 -6
- package/dist/oclif/index.js +74 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,15 +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
|
-
#
|
|
102
|
+
# locally with your wallet key AND sends the signed interaction.json in-thread,
|
|
103
|
+
# so you skip the manual sign-then-send dance. --in-reply-to is the inbound
|
|
104
|
+
# challenge email you received; it is fetched to address the payment to the
|
|
105
|
+
# payee and thread it under the challenge, with From defaulting to the payer it
|
|
106
|
+
# was sent to. The message carries a short default note alongside the
|
|
107
|
+
# attachment; pass --body to customize it.
|
|
106
108
|
primitive payments pay-email --challenge-file challenge.json \
|
|
107
109
|
--in-reply-to <inbound-challenge-email-id> --wait
|
|
108
110
|
|
|
109
111
|
# Advanced: sign only, without sending. Emits the portable interaction.json
|
|
110
|
-
# artifact you can attach
|
|
112
|
+
# artifact you can attach yourself (e.g. with `primitive send --attachment`).
|
|
111
113
|
primitive payments pay-email-step --challenge-file challenge.json > interaction.json
|
|
112
114
|
|
|
113
115
|
# Inspect a challenge by id, or list your registered payout addresses.
|
|
@@ -122,7 +124,7 @@ primitive payments update-spend-policy --max-per-payment 5000000
|
|
|
122
124
|
|
|
123
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.
|
|
124
126
|
|
|
125
|
-
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:
|
|
126
128
|
|
|
127
129
|
```bash
|
|
128
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.2";
|
|
23868
|
+
const CLI_VERSION_RANGE = "^1.13.2";
|
|
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,6 +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 DEFAULT_SUBJECT = "x402 payment authorization";
|
|
28297
|
+
const DEFAULT_BODY_TEXT = "x402 payment authorization attached (interaction.json).";
|
|
28296
28298
|
/** Build the `interaction.json` attachment from a signed payment step. */
|
|
28297
28299
|
function interactionAttachment(built) {
|
|
28298
28300
|
return {
|
|
@@ -28301,29 +28303,37 @@ function interactionAttachment(built) {
|
|
|
28301
28303
|
content_base64: Buffer.from(built.json, "utf8").toString("base64")
|
|
28302
28304
|
};
|
|
28303
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
|
+
}
|
|
28304
28314
|
var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
28305
|
-
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.
|
|
28306
28316
|
|
|
28307
28317
|
Reads the email challenge the payee issued (the JSON from
|
|
28308
28318
|
\`payments create-email-challenge\`), derives and signs the interaction-bound
|
|
28309
28319
|
EIP-3009 authorization locally with your wallet key (read from
|
|
28310
|
-
${PRIVATE_KEY_ENV} by default), and
|
|
28311
|
-
|
|
28312
|
-
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.
|
|
28313
28322
|
|
|
28314
28323
|
This is the recommended payer path. It replaces the two-step
|
|
28315
|
-
\`pay-email-step\` + \`
|
|
28324
|
+
\`pay-email-step\` + \`send --attachment interaction.json\` dance: no manual
|
|
28316
28325
|
address or threading wrangling. Use \`pay-email-step\` only when you need the
|
|
28317
28326
|
signed bytes as a portable artifact without sending.
|
|
28318
28327
|
|
|
28319
|
-
--in-reply-to is the id of the inbound challenge email you received
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
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), the
|
|
28330
|
+
From (you, the payer, from the inbound's recipient), and the In-Reply-To
|
|
28331
|
+
Message-Id used to thread the authorization under the challenge. Pass --from
|
|
28332
|
+
only to override the derived payer From.
|
|
28323
28333
|
|
|
28324
28334
|
Provide the challenge inline with --challenge, from a file with
|
|
28325
28335
|
--challenge-file, or piped on stdin.`;
|
|
28326
|
-
static summary = "Sign an email x402 challenge and send
|
|
28336
|
+
static summary = "Sign an email x402 challenge and send the signed interaction.json in-thread (one step)";
|
|
28327
28337
|
static examples = [
|
|
28328
28338
|
"<%= config.bin %> payments pay-email --challenge-file challenge.json --in-reply-to <inbound-email-id>",
|
|
28329
28339
|
"cat challenge.json | <%= config.bin %> payments pay-email --in-reply-to <inbound-email-id> --wait",
|
|
@@ -28352,11 +28362,12 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28352
28362
|
exclusive: ["challenge"]
|
|
28353
28363
|
}),
|
|
28354
28364
|
"in-reply-to": Flags.string({
|
|
28355
|
-
description: "Id of the inbound challenge email you received.
|
|
28365
|
+
description: "Id of the inbound challenge email you received. It is fetched to derive the payee recipient, the payer From, and the Message-Id used to thread the authorization.",
|
|
28356
28366
|
required: true
|
|
28357
28367
|
}),
|
|
28358
28368
|
from: Flags.string({ description: "Optional From header override. Defaults to the inbound's recipient (the payer the challenge was addressed to)." }),
|
|
28359
|
-
|
|
28369
|
+
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}".` }),
|
|
28370
|
+
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." }),
|
|
28360
28371
|
json: Flags.boolean({ description: "Print a JSON object with the signed interaction step and the send result." }),
|
|
28361
28372
|
time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
|
|
28362
28373
|
};
|
|
@@ -28389,14 +28400,51 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28389
28400
|
process.exitCode = 1;
|
|
28390
28401
|
return;
|
|
28391
28402
|
}
|
|
28392
|
-
const
|
|
28403
|
+
const inboundResult = await getEmail({
|
|
28404
|
+
client: apiClient.client,
|
|
28405
|
+
path: { id: flags["in-reply-to"] },
|
|
28406
|
+
responseStyle: "fields"
|
|
28407
|
+
});
|
|
28408
|
+
if (inboundResult.error) {
|
|
28409
|
+
const errorPayload = extractErrorPayload(inboundResult.error);
|
|
28410
|
+
writeErrorWithHints(errorPayload);
|
|
28411
|
+
surfaceUnauthorizedHint({
|
|
28412
|
+
...authFailureContext,
|
|
28413
|
+
payload: errorPayload
|
|
28414
|
+
});
|
|
28415
|
+
process.exitCode = 1;
|
|
28416
|
+
return;
|
|
28417
|
+
}
|
|
28418
|
+
const inbound = emailDetailFromEnvelope(inboundResult.data);
|
|
28419
|
+
if (!inbound) {
|
|
28420
|
+
process.stderr.write(`Could not load inbound challenge email ${flags["in-reply-to"]}: the API returned no email.\n`);
|
|
28421
|
+
process.exitCode = 1;
|
|
28422
|
+
return;
|
|
28423
|
+
}
|
|
28424
|
+
const payeeTo = inbound.from_email;
|
|
28425
|
+
const derivedPayerFrom = inbound.to_email || inbound.recipient;
|
|
28426
|
+
const from = flags.from ?? derivedPayerFrom;
|
|
28427
|
+
if (!payeeTo) {
|
|
28428
|
+
process.stderr.write(`Inbound challenge email ${flags["in-reply-to"]} has no resolvable sender to address the payment to.\n`);
|
|
28429
|
+
process.exitCode = 1;
|
|
28430
|
+
return;
|
|
28431
|
+
}
|
|
28432
|
+
if (!from) {
|
|
28433
|
+
process.stderr.write(`Could not derive the payer From from inbound challenge email ${flags["in-reply-to"]}; pass --from explicitly.\n`);
|
|
28434
|
+
process.exitCode = 1;
|
|
28435
|
+
return;
|
|
28436
|
+
}
|
|
28437
|
+
const result = await sendEmail({
|
|
28393
28438
|
body: {
|
|
28439
|
+
from,
|
|
28440
|
+
to: payeeTo,
|
|
28441
|
+
subject: DEFAULT_SUBJECT,
|
|
28442
|
+
body_text: flags.body?.trim() ? flags.body : DEFAULT_BODY_TEXT,
|
|
28394
28443
|
attachments: [interactionAttachment(built)],
|
|
28395
|
-
...
|
|
28444
|
+
...inbound.message_id ? { in_reply_to: inbound.message_id } : {},
|
|
28396
28445
|
...flags.wait !== void 0 ? { wait: flags.wait } : {}
|
|
28397
28446
|
},
|
|
28398
28447
|
client: apiClient.client,
|
|
28399
|
-
path: { id: flags["in-reply-to"] },
|
|
28400
28448
|
responseStyle: "fields"
|
|
28401
28449
|
});
|
|
28402
28450
|
if (result.error) {
|
|
@@ -28410,11 +28458,17 @@ var PaymentsPayEmailCommand = class PaymentsPayEmailCommand extends Command {
|
|
|
28410
28458
|
return;
|
|
28411
28459
|
}
|
|
28412
28460
|
const sent = result.data?.data ?? null;
|
|
28461
|
+
const replayed = sent?.idempotent_replay === true;
|
|
28462
|
+
if (replayed) writeIdempotentReplayBannerIfReplay(sent, { write: (chunk) => {
|
|
28463
|
+
process.stderr.write(chunk);
|
|
28464
|
+
} });
|
|
28413
28465
|
if (flags.json) this.log(JSON.stringify({
|
|
28414
28466
|
interaction: built.envelope,
|
|
28415
|
-
sent
|
|
28467
|
+
sent,
|
|
28468
|
+
idempotent_replay: replayed
|
|
28416
28469
|
}, null, 2));
|
|
28417
28470
|
else this.log(JSON.stringify(sent, null, 2));
|
|
28471
|
+
if (replayed) process.exitCode = 1;
|
|
28418
28472
|
});
|
|
28419
28473
|
}
|
|
28420
28474
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primcli",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.2",
|
|
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,
|