@siglume/direct-request-payment 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.
@@ -0,0 +1,116 @@
1
+ # API Reference
2
+
3
+ The TypeScript package is `@siglume/direct-request-payment`. The Python package
4
+ is `siglume-direct-request-payment` and imports as
5
+ `siglume_direct_request_payment`.
6
+
7
+ ## `createDirectRequestPaymentChallenge(input)` / `create_direct_request_payment_challenge(...)`
8
+
9
+ Creates the merchant-signed challenge required by Siglume.
10
+
11
+ ```ts
12
+ const challenge = await createDirectRequestPaymentChallenge({
13
+ merchant: "example_merchant",
14
+ amount_minor: 1200,
15
+ currency: "JPY",
16
+ secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
17
+ nonce: "order_123-attempt_1",
18
+ });
19
+ ```
20
+
21
+ ```py
22
+ import os
23
+
24
+ challenge = create_direct_request_payment_challenge(
25
+ merchant="example_merchant",
26
+ amount_minor=1200,
27
+ currency="JPY",
28
+ secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
29
+ nonce="order_123-attempt_1",
30
+ )
31
+ ```
32
+
33
+ Returns:
34
+
35
+ - `challenge`: value to pass to Siglume
36
+ - `challenge_hash`: value to store on the order
37
+ - `signature`: HMAC-SHA256 hex digest
38
+ - `nonce`
39
+
40
+ `nonce` must not contain `:` because the platform challenge string is delimited
41
+ as `scheme:nonce:signature`.
42
+
43
+ ## `verifyDirectRequestPaymentChallenge(secret, input)` / `verify_direct_request_payment_challenge(...)`
44
+
45
+ Verifies a challenge against merchant, amount, currency, and secret. This is
46
+ useful in tests and internal checkout assertions.
47
+
48
+ ## `DirectRequestPaymentClient`
49
+
50
+ Thin wrapper around the current Siglume Direct Request Payment HTTP contract.
51
+ Use it with the authenticated buyer's Siglume bearer token. Developer Portal
52
+ `cli_` API keys are not accepted by these buyer-authenticated routes.
53
+
54
+ Payment requirements include `fee_bps` from the Siglume platform. The SDK does
55
+ not calculate merchant plan fees locally; see [Pricing](./pricing.md).
56
+
57
+ ```ts
58
+ const siglume = new DirectRequestPaymentClient({
59
+ auth_token: buyerSiglumeBearerToken,
60
+ base_url: "https://siglume.com/v1",
61
+ });
62
+ ```
63
+
64
+ ```py
65
+ siglume = DirectRequestPaymentClient(
66
+ auth_token=buyer_siglume_bearer_token,
67
+ base_url="https://siglume.com/v1",
68
+ )
69
+ ```
70
+
71
+ ### `createPaymentRequirement(input)` / `create_payment_requirement(...)`
72
+
73
+ Calls:
74
+
75
+ ```text
76
+ POST /v1/market/api-store/direct-payments/requirements
77
+ ```
78
+
79
+ The SDK sends `mode="external_402"` internally.
80
+
81
+ ### `executeAllowanceTransaction(requirement)` / `execute_allowance_transaction(...)`
82
+
83
+ Executes `requirement.approve_transaction_request` through:
84
+
85
+ ```text
86
+ POST /v1/market/web3/transactions/execute-prepared
87
+ ```
88
+
89
+ Only call this when Siglume returned an approval transaction.
90
+
91
+ ### `executePaymentTransaction(requirement)` / `execute_payment_transaction(...)`
92
+
93
+ Executes `requirement.transaction_request` through the same prepared transaction
94
+ route.
95
+
96
+ ### `verifyPaymentRequirement(requirement_id, input)` / `verify_payment_requirement(...)`
97
+
98
+ Calls:
99
+
100
+ ```text
101
+ POST /v1/market/api-store/direct-payments/requirements/{requirement_id}/verify
102
+ ```
103
+
104
+ ## Webhook Helpers
105
+
106
+ - `buildWebhookSignatureHeader(secret, body)` for tests
107
+ - `verifyWebhookSignature(secret, body, header)`
108
+ - `verifyDirectRequestPaymentWebhook(secret, body, header)`
109
+ - `parseDirectRequestPaymentWebhookEvent(payload)`
110
+ - Python equivalents use snake_case:
111
+ `build_webhook_signature_header`, `verify_webhook_signature`,
112
+ `verify_direct_request_payment_webhook`, and
113
+ `parse_direct_request_payment_webhook_event`.
114
+
115
+ `verifyDirectRequestPaymentWebhook` verifies the signature and parses the event
116
+ in one call.
@@ -0,0 +1,255 @@
1
+ # Merchant Quickstart
2
+
3
+ This guide shows the minimum safe Siglume Direct Request Payment flow for an
4
+ external merchant.
5
+
6
+ ## Actors
7
+
8
+ - Merchant server: owns the order, amount, currency, challenge secret, webhook
9
+ endpoint, and order fulfillment.
10
+ - Buyer: owns the Siglume wallet that pays the DirectPaymentHub transaction.
11
+ - Siglume: creates the payment requirement, prepares the wallet transaction,
12
+ verifies the receipt, and emits signed webhooks.
13
+
14
+ The merchant server must not create charges with a customer wallet. It signs the
15
+ order challenge; the buyer-facing Siglume payment flow pays it.
16
+
17
+ ## 1. Configure the Merchant
18
+
19
+ During onboarding, Siglume assigns:
20
+
21
+ - `merchant` key, for example `example_merchant`
22
+ - challenge secret
23
+ - allowed currency and token, initially `JPY`/`JPYC`; `USD`/`USDC` requires
24
+ separately agreed merchant billing terms
25
+ - billing plan; see [Pricing](./pricing.md)
26
+
27
+ Keep the challenge secret server-side. Create a marketplace webhook subscription
28
+ to receive the `whsec_` signing secret.
29
+
30
+ ```bash
31
+ curl -X POST https://siglume.com/v1/market/webhooks/subscriptions \
32
+ -H "Authorization: Bearer <merchant-siglume-bearer-token>" \
33
+ -H "Content-Type: application/json" \
34
+ -d '{
35
+ "callback_url": "https://merchant.example/siglume/webhook",
36
+ "event_types": ["direct_payment.confirmed"],
37
+ "description": "Direct Request Payment production webhook"
38
+ }'
39
+ ```
40
+
41
+ The `signing_secret` is returned only when the subscription is created or
42
+ rotated. Store it as `SIGLUME_WEBHOOK_SECRET`.
43
+
44
+ ## 2. Create an Order and Challenge
45
+
46
+ The merchant server creates the order before asking Siglume for payment.
47
+
48
+ ```ts
49
+ import { createDirectRequestPaymentChallenge } from "@siglume/direct-request-payment";
50
+
51
+ const order = {
52
+ id: "order_123",
53
+ amount_minor: 1200,
54
+ currency: "JPY",
55
+ };
56
+
57
+ const challenge = await createDirectRequestPaymentChallenge({
58
+ merchant: "example_merchant",
59
+ amount_minor: order.amount_minor,
60
+ currency: order.currency,
61
+ secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
62
+ nonce: `${order.id}-attempt_1`,
63
+ });
64
+
65
+ await orders.update(order.id, {
66
+ siglume_challenge_hash: challenge.challenge_hash,
67
+ siglume_payment_status: "pending",
68
+ });
69
+
70
+ return {
71
+ order_id: order.id,
72
+ amount_minor: order.amount_minor,
73
+ currency: order.currency,
74
+ siglume_challenge: challenge.challenge,
75
+ };
76
+ ```
77
+
78
+ Python:
79
+
80
+ ```py
81
+ import os
82
+
83
+ from siglume_direct_request_payment import create_direct_request_payment_challenge
84
+
85
+ order = {
86
+ "id": "order_123",
87
+ "amount_minor": 1200,
88
+ "currency": "JPY",
89
+ }
90
+
91
+ challenge = create_direct_request_payment_challenge(
92
+ merchant="example_merchant",
93
+ amount_minor=order["amount_minor"],
94
+ currency=order["currency"],
95
+ secret=os.environ["SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET"],
96
+ nonce=f"{order['id']}-attempt_1",
97
+ )
98
+
99
+ orders.update(
100
+ order["id"],
101
+ {
102
+ "siglume_challenge_hash": challenge["challenge_hash"],
103
+ "siglume_payment_status": "pending",
104
+ },
105
+ )
106
+
107
+ return {
108
+ "order_id": order["id"],
109
+ "amount_minor": order["amount_minor"],
110
+ "currency": order["currency"],
111
+ "siglume_challenge": challenge["challenge"],
112
+ }
113
+ ```
114
+
115
+ Never calculate `amount_minor` from browser input.
116
+ The nonce must be unique per order payment attempt and must not contain `:`.
117
+
118
+ ## 3. Buyer Creates and Pays the Requirement
119
+
120
+ After the buyer authenticates with Siglume, create the payment requirement with
121
+ the buyer's Siglume bearer token. Do not use a Developer Portal `cli_` API key
122
+ or merchant API key here.
123
+
124
+ ```ts
125
+ import { DirectRequestPaymentClient } from "@siglume/direct-request-payment";
126
+
127
+ const siglume = new DirectRequestPaymentClient({
128
+ auth_token: buyerSiglumeBearerToken,
129
+ });
130
+
131
+ const requirement = await siglume.createPaymentRequirement({
132
+ merchant: "example_merchant",
133
+ amount_minor: order.amount_minor,
134
+ currency: order.currency,
135
+ challenge: order.siglume_challenge,
136
+ });
137
+ ```
138
+
139
+ Python:
140
+
141
+ ```py
142
+ from siglume_direct_request_payment import DirectRequestPaymentClient
143
+
144
+ siglume = DirectRequestPaymentClient(auth_token=buyer_siglume_bearer_token)
145
+
146
+ requirement = siglume.create_payment_requirement(
147
+ merchant="example_merchant",
148
+ amount_minor=order["amount_minor"],
149
+ currency=order["currency"],
150
+ challenge=order["siglume_challenge"],
151
+ )
152
+ ```
153
+
154
+ If Siglume returns `approve_transaction_request`, execute it first. Then execute
155
+ the payment transaction and verify the receipt.
156
+
157
+ ```ts
158
+ if (requirement.approve_transaction_request) {
159
+ await siglume.executeAllowanceTransaction(requirement, { await_finality: true });
160
+ }
161
+
162
+ const payment = await siglume.executePaymentTransaction(requirement, {
163
+ await_finality: true,
164
+ });
165
+
166
+ await siglume.verifyPaymentRequirement(requirement.requirement_id, {
167
+ receipt_id: String(payment.receipt?.receipt_id ?? ""),
168
+ });
169
+ ```
170
+
171
+ Python:
172
+
173
+ ```py
174
+ if requirement.get("approve_transaction_request"):
175
+ siglume.execute_allowance_transaction(requirement, await_finality=True)
176
+
177
+ payment = siglume.execute_payment_transaction(requirement, await_finality=True)
178
+
179
+ siglume.verify_payment_requirement(
180
+ requirement["requirement_id"],
181
+ receipt_id=str((payment.get("receipt") or {}).get("receipt_id") or ""),
182
+ )
183
+ ```
184
+
185
+ ## 4. Fulfill from Webhook
186
+
187
+ Use the webhook as the durable signal, not just the browser return path.
188
+
189
+ ```ts
190
+ import { verifyDirectRequestPaymentWebhook } from "@siglume/direct-request-payment";
191
+
192
+ const { event } = await verifyDirectRequestPaymentWebhook(
193
+ process.env.SIGLUME_WEBHOOK_SECRET!,
194
+ rawRequestBody,
195
+ siglumeSignatureHeader,
196
+ );
197
+
198
+ if (event.type === "direct_payment.confirmed") {
199
+ const data = event.data;
200
+ const order = await orders.findByChallengeHash(String(data.challenge_hash ?? ""));
201
+ if (!order) {
202
+ throw new Error("Unknown Siglume challenge hash");
203
+ }
204
+ await orders.markPaidOnce(order.id, {
205
+ siglume_requirement_id: String(data.requirement_id ?? data.direct_payment_requirement_id ?? ""),
206
+ });
207
+ }
208
+ ```
209
+
210
+ Python:
211
+
212
+ ```py
213
+ import os
214
+
215
+ from siglume_direct_request_payment import verify_direct_request_payment_webhook
216
+
217
+ verified = verify_direct_request_payment_webhook(
218
+ os.environ["SIGLUME_WEBHOOK_SECRET"],
219
+ raw_request_body,
220
+ siglume_signature_header,
221
+ )
222
+
223
+ if verified["event"]["type"] == "direct_payment.confirmed":
224
+ data = verified["event"]["data"]
225
+ order = orders.find_by_challenge_hash(str(data.get("challenge_hash") or ""))
226
+ if not order:
227
+ raise RuntimeError("Unknown Siglume challenge hash")
228
+ orders.mark_paid_once(
229
+ order["id"],
230
+ siglume_requirement_id=str(data.get("requirement_id") or data.get("direct_payment_requirement_id") or ""),
231
+ )
232
+ ```
233
+
234
+ ## Failure Handling
235
+
236
+ - `EXTERNAL_402_CHALLENGE_REQUIRED`: the merchant server did not provide a
237
+ challenge.
238
+ - `INVALID_EXTERNAL_402_CHALLENGE`: the amount, currency, merchant, nonce, or
239
+ signature does not match.
240
+ - `EXTERNAL_402_CHALLENGE_ALREADY_USED`: the challenge is already bound to a
241
+ different buyer.
242
+ - `EXTERNAL_402_MERCHANT_BILLING_SETUP_REQUIRED`: merchant onboarding is not
243
+ complete.
244
+ - `EXTERNAL_402_MERCHANT_BILLING_PAST_DUE` or
245
+ `EXTERNAL_402_MERCHANT_BILLING_SUSPENDED`: merchant billing must be fixed
246
+ before new payments can be accepted.
247
+
248
+ ## Go-Live Checklist
249
+
250
+ - Challenge secret is only in server-side environment variables.
251
+ - Webhook endpoint receives raw body and verifies `Siglume-Signature`.
252
+ - Orders store `challenge_hash`, `requirement_id`, and fulfillment status.
253
+ - Fulfillment is idempotent.
254
+ - Browser input cannot change the amount or currency.
255
+ - Nonces cannot be reused for separate order attempts.
@@ -0,0 +1,56 @@
1
+ # Pricing
2
+
3
+ This page documents the trial-phase merchant pricing for Siglume Direct Request
4
+ Payment as of 2026-06-11. Pricing can change by agreement or future product
5
+ release; the Siglume platform response is the source of truth for per-payment
6
+ fee data returned at runtime.
7
+
8
+ ## Trial Plans
9
+
10
+ | Plan | Monthly fee | Payment fee | Intended starting point |
11
+ | --- | ---: | ---: | --- |
12
+ | Launch | JPY 0 | 0% through 100 payments/month, then 1.8% | Proofs of concept and low-volume trials |
13
+ | Starter | JPY 980 | 1.0% | Early production checkout trials |
14
+ | Growth | JPY 2,980 | 0.7% | Growing EC, booking, membership, and API services |
15
+ | Pro | JPY 9,800 | 0.5% | Higher-volume merchant integrations |
16
+
17
+ The minimum fee is JPY 3 for each fee-bearing payment, including Launch-plan
18
+ payments after the included monthly allowance.
19
+
20
+ If no paid plan is selected during onboarding, the merchant account uses the
21
+ Launch plan. A merchant billing mandate is still required before accepting
22
+ payments so Siglume can collect fees automatically after the 100-payment monthly
23
+ allowance is exceeded.
24
+
25
+ The current Siglume API and merchant registry may still expose the internal
26
+ `billing_plan` value `free` for the Launch tier. Treat `free` as an internal
27
+ compatibility key, not the public plan name.
28
+
29
+ The 100-payment monthly allowance is not a hard processing cap. Payments after
30
+ the allowance can continue when merchant billing is active, and those payments
31
+ are fee-bearing at the Launch overage rate.
32
+
33
+ Per-payment fees are collected during payment settlement through the
34
+ DirectPaymentHub split. The merchant receives the net amount after that fee.
35
+ Monthly base fees are collected separately through the merchant billing mandate.
36
+
37
+ The public trial pricing above is JPY-denominated. If a merchant needs USD/USDC
38
+ settlement, agree the USD merchant billing terms during onboarding; do not infer
39
+ USD monthly or minimum fees from the JPY table.
40
+
41
+ ## SDK Behavior
42
+
43
+ The SDK does not calculate merchant invoices or enforce plan limits locally.
44
+ Instead, it exposes billing-related values returned by Siglume, including
45
+ `fee_bps` on a payment requirement. This keeps merchant billing centralized in
46
+ the Siglume platform and avoids stale client-side pricing logic.
47
+
48
+ ## Supported Use Cases
49
+
50
+ The trial pricing is intended for:
51
+
52
+ - Small EC checkout
53
+ - Booking and reservation services
54
+ - Membership services
55
+ - Paid API access
56
+ - Agent-to-agent payment experiments
@@ -0,0 +1,85 @@
1
+ # Security Guide
2
+
3
+ Direct Request Payment is a wallet payment rail. Treat it like payment
4
+ infrastructure, not like a generic API call.
5
+
6
+ ## Do Not Expose Secrets
7
+
8
+ These values must stay server-side:
9
+
10
+ - `SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET`
11
+ - `SIGLUME_WEBHOOK_SECRET`
12
+ - any merchant administrative credentials
13
+
14
+ The buyer-facing browser may receive the signed `challenge` string, but never
15
+ the secret that produced it.
16
+
17
+ ## Bind the Order Server-Side
18
+
19
+ The HMAC challenge covers:
20
+
21
+ ```text
22
+ merchant:amount_minor:currency:nonce
23
+ ```
24
+
25
+ Use a nonce derived from a durable order payment attempt, for example
26
+ `order_123-attempt_1`. The nonce must not contain `:` because the platform
27
+ challenge is encoded as `scheme:nonce:signature`. Store the returned
28
+ `challenge_hash` on the order. When a
29
+ webhook arrives, look up the order by `challenge_hash`.
30
+
31
+ ## Do Not Trust Browser Amounts
32
+
33
+ The merchant server owns:
34
+
35
+ - SKU or plan
36
+ - amount in minor units
37
+ - currency
38
+ - nonce
39
+
40
+ If a browser says the order total is 1200 JPY, treat that as display state only.
41
+ Re-read the order server-side before generating the challenge.
42
+
43
+ ## Webhook Verification
44
+
45
+ Verify the `Siglume-Signature` header using the raw request body. Do not parse
46
+ and re-stringify JSON before verification.
47
+
48
+ The SDK expects the Siglume signature format:
49
+
50
+ ```text
51
+ t=<unix timestamp>,v1=<hex hmac sha256>
52
+ ```
53
+
54
+ The signed payload is:
55
+
56
+ ```text
57
+ <timestamp>.<raw body>
58
+ ```
59
+
60
+ The default tolerance is 300 seconds.
61
+
62
+ ## Idempotency
63
+
64
+ Fulfill exactly once per order. Store at least:
65
+
66
+ - order id
67
+ - challenge hash
68
+ - Siglume requirement id
69
+ - on-chain receipt id or transaction hash if present
70
+ - fulfillment state
71
+
72
+ Duplicate webhook deliveries and manual redelivery can occur. A duplicate
73
+ webhook with the same requirement id must not ship the order twice.
74
+
75
+ ## What Direct Request Payment Is Not
76
+
77
+ Direct Request Payment is not:
78
+
79
+ - stored value
80
+ - prepaid points
81
+ - escrow
82
+ - a platform balance
83
+ - a card payment fallback
84
+
85
+ It is a one-request wallet payment gate backed by an on-chain receipt.
@@ -0,0 +1,105 @@
1
+ import express from "express";
2
+ import {
3
+ createDirectRequestPaymentChallenge,
4
+ DirectRequestPaymentClient,
5
+ verifyDirectRequestPaymentWebhook,
6
+ } from "@siglume/direct-request-payment";
7
+
8
+ const app = express();
9
+ const port = Number(process.env.PORT || 3000);
10
+
11
+ // Use JSON for normal routes. Use raw body only on the webhook route.
12
+ app.use((req, res, next) => {
13
+ if (req.path === "/siglume/webhook") {
14
+ next();
15
+ return;
16
+ }
17
+ express.json()(req, res, next);
18
+ });
19
+
20
+ const orders = new Map<string, any>();
21
+
22
+ const asyncRoute =
23
+ (handler: express.RequestHandler): express.RequestHandler =>
24
+ (req, res, next) => {
25
+ Promise.resolve(handler(req, res, next)).catch(next);
26
+ };
27
+
28
+ app.post("/checkout/siglume/start", asyncRoute(async (req, res) => {
29
+ const orderId = String(req.body.order_id || "");
30
+ const order = orders.get(orderId);
31
+ if (!order) {
32
+ res.status(404).json({ error: "order_not_found" });
33
+ return;
34
+ }
35
+
36
+ order.payment_attempt = Number(order.payment_attempt || 0) + 1;
37
+ const challenge = await createDirectRequestPaymentChallenge({
38
+ merchant: "example_merchant",
39
+ amount_minor: order.amount_minor,
40
+ currency: order.currency,
41
+ secret: process.env.SIGLUME_DIRECT_PAYMENT_CHALLENGE_SECRET!,
42
+ nonce: `${order.id}-attempt_${order.payment_attempt}`,
43
+ });
44
+
45
+ order.siglume_challenge_hash = challenge.challenge_hash;
46
+ order.siglume_payment_status = "pending";
47
+
48
+ res.json({
49
+ order_id: order.id,
50
+ amount_minor: order.amount_minor,
51
+ currency: order.currency,
52
+ siglume_challenge: challenge.challenge,
53
+ });
54
+ }));
55
+
56
+ app.post("/checkout/siglume/pay", asyncRoute(async (req, res) => {
57
+ const order = orders.get(String(req.body.order_id || ""));
58
+ if (!order) {
59
+ res.status(404).json({ error: "order_not_found" });
60
+ return;
61
+ }
62
+
63
+ // In production, obtain this from the authenticated buyer's Siglume session
64
+ // or a hosted Siglume payment confirmation flow. Do not use a merchant secret
65
+ // to charge a customer wallet.
66
+ const siglume = new DirectRequestPaymentClient({
67
+ auth_token: String(req.headers.authorization || "").replace(/^Bearer\s+/i, ""),
68
+ });
69
+
70
+ const requirement = await siglume.createPaymentRequirement({
71
+ merchant: "example_merchant",
72
+ amount_minor: order.amount_minor,
73
+ currency: order.currency,
74
+ challenge: String(req.body.siglume_challenge || ""),
75
+ });
76
+
77
+ res.json({ requirement });
78
+ }));
79
+
80
+ app.post("/siglume/webhook", express.raw({ type: "application/json" }), asyncRoute(async (req, res) => {
81
+ const header = String(req.headers["siglume-signature"] || "");
82
+ const { event } = await verifyDirectRequestPaymentWebhook(
83
+ process.env.SIGLUME_WEBHOOK_SECRET!,
84
+ req.body,
85
+ header,
86
+ );
87
+
88
+ if (event.type === "direct_payment.confirmed") {
89
+ const challengeHash = String(event.data.challenge_hash || "");
90
+ const order = [...orders.values()].find((item) => item.siglume_challenge_hash === challengeHash);
91
+ if (order) {
92
+ order.siglume_payment_status = "paid";
93
+ order.siglume_requirement_id = event.data.requirement_id || event.data.direct_payment_requirement_id;
94
+ }
95
+ }
96
+
97
+ res.status(204).send();
98
+ }));
99
+
100
+ app.use((error: unknown, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
101
+ const message = error instanceof Error ? error.message : "internal_error";
102
+ res.status(500).json({ error: message });
103
+ });
104
+
105
+ app.listen(port);
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@siglume/direct-request-payment",
3
+ "version": "0.1.0",
4
+ "description": "Merchant SDK for Siglume Direct Request Payment checkout integrations",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/taihei-05/siglume-direct-request-payment.git"
9
+ },
10
+ "type": "module",
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "sideEffects": false,
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/index.d.cts",
27
+ "default": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "docs",
38
+ "examples",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "lint": "npm run typecheck",
45
+ "prepack": "npm run build",
46
+ "prepublishOnly": "npm run build",
47
+ "typecheck": "tsc --noEmit",
48
+ "test": "vitest run",
49
+ "pack:check": "npm pack --json"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^20.16.5",
53
+ "tsup": "^8.3.0",
54
+ "typescript": "^5.6.3",
55
+ "vitest": "^2.1.8"
56
+ }
57
+ }