spl-pay-per-suite 1.1.2 → 1.1.4
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 +26 -97
- package/package.json +18 -5
- package/src/index.mjs +14 -0
- package/src/mcp-server.mjs +25 -13
- package/src/quote.mjs +76 -59
package/README.md
CHANGED
|
@@ -1,121 +1,50 @@
|
|
|
1
|
-
#
|
|
1
|
+
# spl-pay-per-suite
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**SPL Pay Per Suite** — freemium quotes, Stripe (humans) + x402 (agents). Library, CLI, and MCP.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|-----|------|
|
|
7
|
-
| **Humans** | Stripe · [slidphilabs.com/pps](https://www.slidphilabs.com/pps) |
|
|
8
|
-
| **Agents** | **x402** · `POST /api/x402-suite` (402 → pay → retry) |
|
|
5
|
+
## Pricing (v2 freemium)
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
| Tier | Rule |
|
|
8
|
+
|------|------|
|
|
9
|
+
| **Free** | First **1 GiB per job** — $0 (showcase) |
|
|
10
|
+
| **Usage** | Bytes over free: **~ $0.03/GB** (2¢/GB after 50 GB over free) |
|
|
11
|
+
| **Min paid** | $2.00 once over free |
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
**Try Gate is retired.** Evaluate on free suite — not a $9 chip-in.
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
License packages (CDDG:Split, ZRW tiers, etc.) remain separate fixed SKUs via catalog/x402.
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
npm i spl-pay-per-suite
|
|
21
|
-
# or one-shot
|
|
22
|
-
npx spl-pay-per-suite quote --bytes 1048576 --class zeros --product zrw
|
|
23
|
-
```
|
|
17
|
+
Live: [www.slidphilabs.com/pps](https://www.slidphilabs.com/pps) · Discovery: [GET /api/agent](https://www.slidphilabs.com/api/agent)
|
|
24
18
|
|
|
25
|
-
##
|
|
19
|
+
## Install
|
|
26
20
|
|
|
27
21
|
```bash
|
|
28
|
-
spl-
|
|
29
|
-
|
|
30
|
-
spl-
|
|
31
|
-
spl-pps job --email you@company.com --paid --file ./payload.bin
|
|
32
|
-
spl-pps products
|
|
22
|
+
npm i spl-pay-per-suite
|
|
23
|
+
# or CLI
|
|
24
|
+
npx spl-pay-per-suite quote --bytes 500000000
|
|
33
25
|
```
|
|
34
26
|
|
|
35
|
-
##
|
|
27
|
+
## Quote (local)
|
|
36
28
|
|
|
37
29
|
```js
|
|
38
|
-
import { computeQuote
|
|
39
|
-
|
|
40
|
-
const q = computeQuote({ product: "zrw", dataClass: "zeros", op: "compress", bytes: 1_000_000 });
|
|
41
|
-
console.log(q.amount_display); // e.g. "37.00"
|
|
42
|
-
|
|
43
|
-
const pay = await createCheckout({ ...q.breakdown, email: "you@company.com" });
|
|
44
|
-
// open pay.url
|
|
45
|
-
|
|
46
|
-
await submitJob({
|
|
47
|
-
email: "you@company.com",
|
|
48
|
-
paidConfirm: true,
|
|
49
|
-
amount_display: q.amount_display,
|
|
50
|
-
product: "zrw",
|
|
51
|
-
dataClass: "zeros",
|
|
52
|
-
op: "compress",
|
|
53
|
-
bytes: 1_000_000,
|
|
54
|
-
});
|
|
55
|
-
```
|
|
30
|
+
import { computeQuote } from "spl-pay-per-suite";
|
|
56
31
|
|
|
57
|
-
|
|
32
|
+
computeQuote({ product: "auto", op: "compress", bytes: 100e6 });
|
|
33
|
+
// → free: true, amount_cents: 0
|
|
58
34
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# Discovery + catalog
|
|
63
|
-
curl -s https://www.slidphilabs.com/api/agent | jq .
|
|
64
|
-
curl -s https://www.slidphilabs.com/api/x402-products | jq .
|
|
65
|
-
spl-pps x402
|
|
66
|
-
spl-pps catalog
|
|
67
|
-
|
|
68
|
-
# Buy CDDG:Split (probe 402, then pay + retry)
|
|
69
|
-
spl-pps buy --sku cddg-split --email you@x.com
|
|
70
|
-
# payFetch("https://www.slidphilabs.com/api/x402-products", { method:"POST", body: JSON.stringify({ sku: "cddg-split", email }) })
|
|
71
|
-
|
|
72
|
-
# Metered suite job
|
|
73
|
-
spl-pps x402-req --bytes 1048576 --class zeros --product zrw
|
|
74
|
-
# payFetch("https://www.slidphilabs.com/api/x402-suite", { ... })
|
|
35
|
+
computeQuote({ product: "auto", op: "compress", bytes: 9e9 });
|
|
36
|
+
// → free: false, ~$2.00 class
|
|
75
37
|
```
|
|
76
38
|
|
|
77
|
-
**SKUs:** `cddg-split` · `zrw-n00b` · `zrw-pro` · `zrw-l33t` · `blackjack` · `shard-zip` · `shard-tsdb` · `slid-phi` · `support-integration` · `consulting` · `sponsor` · `donate` · `try-gate`
|
|
78
|
-
|
|
79
|
-
Server env (Vercel): `X402_PAY_TO`, `X402_ASSET`, `X402_NETWORK`, `SOLANA_RPC_URL`. Optional staging: `X402_DEV_BYPASS=1` + header `X-PAYMENT-DEV: ok`.
|
|
80
|
-
|
|
81
39
|
## MCP
|
|
82
40
|
|
|
83
41
|
```bash
|
|
84
|
-
npx spl-pay-per-suite mcp
|
|
42
|
+
npx spl-pay-per-suite mcp
|
|
43
|
+
# or: node node_modules/spl-pay-per-suite/src/mcp-server.mjs
|
|
85
44
|
```
|
|
86
45
|
|
|
87
|
-
|
|
88
|
-
{
|
|
89
|
-
"mcpServers": {
|
|
90
|
-
"spl-pay-per-suite": {
|
|
91
|
-
"command": "npx",
|
|
92
|
-
"args": ["-y", "spl-pay-per-suite", "mcp-serve"]
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**Tools:** `spl_pps_info` · `spl_pps_quote` · `spl_pps_checkout` · `spl_pps_submit_job` · `spl_pps_classify` · **`spl_pps_x402_info`** · **`spl_pps_x402_catalog`** · **`spl_pps_x402_buy`** · **`spl_pps_x402_requirements`** · **`spl_pps_x402_submit`**
|
|
99
|
-
|
|
100
|
-
## Pricing model (public)
|
|
101
|
-
|
|
102
|
-
| Factor | Role |
|
|
103
|
-
|--------|------|
|
|
104
|
-
| Product base | Service value (auto / ZRW / CDDG Split / family) |
|
|
105
|
-
| Size | Progressive $/MB |
|
|
106
|
-
| Data class | Shape multiplier |
|
|
107
|
-
| Operation | compress · decompress · roundtrip |
|
|
108
|
-
|
|
109
|
-
Min **$9** · max **$10,000** per job (Stripe custom-amount limit).
|
|
110
|
-
|
|
111
|
-
## Env (optional)
|
|
112
|
-
|
|
113
|
-
| Var | Default |
|
|
114
|
-
|-----|---------|
|
|
115
|
-
| `SPL_PPS_API` | `https://www.slidphilabs.com` |
|
|
116
|
-
| `SPL_PPS_SITE` | `https://www.slidphilabs.com/pps` |
|
|
117
|
-
| `SPL_PPS_PAYMENT_LINK` | live Stripe PPP / suite link |
|
|
46
|
+
Tools: `spl_pps_info`, `spl_pps_quote`, `spl_pps_checkout`, `spl_pps_submit_job`, `spl_pps_classify`, `spl_pps_x402_*`.
|
|
118
47
|
|
|
119
|
-
##
|
|
48
|
+
## IP Guard
|
|
120
49
|
|
|
121
|
-
|
|
50
|
+
Quotes and commerce rails only — no private compression process or engines in this package.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spl-pay-per-suite",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "SPL Pay Per Suite —
|
|
3
|
+
"version": "1.1.4",
|
|
4
|
+
"description": "SPL Pay Per Suite — freemium (free first 1 GB · then ~1.5¢/GB), Stripe + x402. Library, CLI, MCP. Try Gate retired.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.mjs",
|
|
7
7
|
"exports": {
|
|
@@ -46,7 +46,9 @@
|
|
|
46
46
|
"agent-platform",
|
|
47
47
|
"cuni",
|
|
48
48
|
"agent-rider",
|
|
49
|
-
"quikgater"
|
|
49
|
+
"quikgater",
|
|
50
|
+
"freemium",
|
|
51
|
+
"usage-pricing"
|
|
50
52
|
],
|
|
51
53
|
"author": "Slid Phi Labs",
|
|
52
54
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -82,12 +84,23 @@
|
|
|
82
84
|
"site": "https://www.slidphilabs.com",
|
|
83
85
|
"llms_txt": "https://www.slidphilabs.com/llms.txt",
|
|
84
86
|
"agents_json": "https://www.slidphilabs.com/agents.json",
|
|
85
|
-
"one_liner": "
|
|
87
|
+
"one_liner": "Free first 1 GB suite · then from $2 min · ~3¢/GB. GET https://www.slidphilabs.com/api/agent. Try Gate retired.",
|
|
86
88
|
"agent_platform": {
|
|
87
89
|
"cuni": "https://cuni-studio.fly.dev/",
|
|
88
90
|
"agent_rider": "https://agentrider.vercel.app/",
|
|
89
91
|
"quikgater": "https://github.com/ceedot-rock/quikgater"
|
|
90
|
-
}
|
|
92
|
+
},
|
|
93
|
+
"suite": "https://www.slidphilabs.com/pps",
|
|
94
|
+
"suite_pricing": {
|
|
95
|
+
"free_cap_gb": 1,
|
|
96
|
+
"min_paid_usd": 2,
|
|
97
|
+
"usd_per_gb_after_free": 0.03,
|
|
98
|
+
"usd_per_gb_bulk": 0.02,
|
|
99
|
+
"try_gate": "retired",
|
|
100
|
+
"model": "freemium_suite_v3_money"
|
|
101
|
+
},
|
|
102
|
+
"welcome": "https://www.slidphilabs.com/api/welcome",
|
|
103
|
+
"platform_json": "https://www.slidphilabs.com/platform.json"
|
|
91
104
|
},
|
|
92
105
|
"x402": {
|
|
93
106
|
"discovery": "https://www.slidphilabs.com/api/agent",
|
package/src/index.mjs
CHANGED
|
@@ -5,23 +5,37 @@
|
|
|
5
5
|
import {
|
|
6
6
|
computeQuote,
|
|
7
7
|
classifyBytes,
|
|
8
|
+
usageFeeCents,
|
|
8
9
|
STRIPE_PAYMENT_LINK,
|
|
9
10
|
SITE_PPS,
|
|
10
11
|
API_BASE,
|
|
11
12
|
PRODUCT_BASE,
|
|
13
|
+
PRODUCT_ADD_CENTS,
|
|
12
14
|
DATA_MULT,
|
|
13
15
|
OP_MULT,
|
|
16
|
+
FREE_BYTES,
|
|
17
|
+
MIN_PAID_CENTS,
|
|
18
|
+
MIN_CENTS,
|
|
19
|
+
MAX_CENTS,
|
|
20
|
+
MAX_BYTES,
|
|
14
21
|
} from "./quote.mjs";
|
|
15
22
|
|
|
16
23
|
export {
|
|
17
24
|
computeQuote,
|
|
18
25
|
classifyBytes,
|
|
26
|
+
usageFeeCents,
|
|
19
27
|
STRIPE_PAYMENT_LINK,
|
|
20
28
|
SITE_PPS,
|
|
21
29
|
API_BASE,
|
|
22
30
|
PRODUCT_BASE,
|
|
31
|
+
PRODUCT_ADD_CENTS,
|
|
23
32
|
DATA_MULT,
|
|
24
33
|
OP_MULT,
|
|
34
|
+
FREE_BYTES,
|
|
35
|
+
MIN_PAID_CENTS,
|
|
36
|
+
MIN_CENTS,
|
|
37
|
+
MAX_CENTS,
|
|
38
|
+
MAX_BYTES,
|
|
25
39
|
};
|
|
26
40
|
|
|
27
41
|
export const SERVICE_NAME = "SPL Pay Per Suite";
|
package/src/mcp-server.mjs
CHANGED
|
@@ -36,38 +36,40 @@ import {
|
|
|
36
36
|
PRODUCT_BASE,
|
|
37
37
|
DATA_MULT,
|
|
38
38
|
OP_MULT,
|
|
39
|
+
FREE_BYTES,
|
|
40
|
+
MIN_PAID_CENTS,
|
|
39
41
|
} from "./index.mjs";
|
|
40
42
|
|
|
41
43
|
const TOOLS = [
|
|
42
44
|
{
|
|
43
45
|
name: "spl_pps_info",
|
|
44
46
|
description:
|
|
45
|
-
"SPL Pay Per Suite overview:
|
|
47
|
+
"SPL Pay Per Suite overview: freemium suite (free first 1 GB then ~3¢/GB · min $2), Stripe (humans) + x402 (agents), products, data classes, ops. Try Gate retired.",
|
|
46
48
|
inputSchema: { type: "object", properties: {} },
|
|
47
49
|
},
|
|
48
50
|
{
|
|
49
51
|
name: "spl_pps_x402_info",
|
|
50
52
|
description:
|
|
51
|
-
"Agentic commerce discovery: standing product catalog + suite
|
|
53
|
+
"Agentic commerce discovery: standing product catalog + freemium suite jobs (free under 1 GB), headers, flow. Stripe remains for humans.",
|
|
52
54
|
inputSchema: { type: "object", properties: {} },
|
|
53
55
|
},
|
|
54
56
|
{
|
|
55
57
|
name: "spl_pps_x402_catalog",
|
|
56
58
|
description:
|
|
57
|
-
"List
|
|
59
|
+
"List standing Slid Phi Labs license products agents can buy via x402 (CDDG:Split, ZRW tiers, Blackjack, shards, support, etc.). No try-gate — use freemium suite for eval.",
|
|
58
60
|
inputSchema: { type: "object", properties: {} },
|
|
59
61
|
},
|
|
60
62
|
{
|
|
61
63
|
name: "spl_pps_x402_buy",
|
|
62
64
|
description:
|
|
63
|
-
"Buy a standing product via x402. Without paymentHeader → returns 402 requirements. With paymentHeader (or devBypass) → order_id + access_url.",
|
|
65
|
+
"Buy a standing license product via x402. Without paymentHeader → returns 402 requirements. With paymentHeader (or devBypass) → order_id + access_url. Not for suite jobs — use spl_pps_x402_submit.",
|
|
64
66
|
inputSchema: {
|
|
65
67
|
type: "object",
|
|
66
68
|
properties: {
|
|
67
69
|
sku: {
|
|
68
70
|
type: "string",
|
|
69
71
|
description:
|
|
70
|
-
"cddg-split | zrw-n00b | zrw-pro | zrw-l33t | blackjack | shard-zip | shard-tsdb | slid-phi | support-integration | consulting | sponsor | donate
|
|
72
|
+
"cddg-split | zrw-n00b | zrw-pro | zrw-l33t | blackjack | shard-zip | shard-tsdb | slid-phi | support-integration | consulting | sponsor | donate",
|
|
71
73
|
},
|
|
72
74
|
email: { type: "string" },
|
|
73
75
|
note: { type: "string" },
|
|
@@ -80,14 +82,14 @@ const TOOLS = [
|
|
|
80
82
|
{
|
|
81
83
|
name: "spl_pps_x402_requirements",
|
|
82
84
|
description:
|
|
83
|
-
"Probe POST /api/x402-suite (
|
|
85
|
+
"Probe POST /api/x402-suite. Free under 1 GB (no pay). Over free → 402 accepts[] for usage pricing (~3¢/GB · min $2).",
|
|
84
86
|
inputSchema: {
|
|
85
87
|
type: "object",
|
|
86
88
|
properties: {
|
|
87
89
|
product: { type: "string" },
|
|
88
90
|
dataClass: { type: "string" },
|
|
89
91
|
op: { type: "string" },
|
|
90
|
-
bytes: { type: "number" },
|
|
92
|
+
bytes: { type: "number", description: "≤1GiB free; over free requires payment" },
|
|
91
93
|
email: { type: "string" },
|
|
92
94
|
note: { type: "string" },
|
|
93
95
|
},
|
|
@@ -96,7 +98,7 @@ const TOOLS = [
|
|
|
96
98
|
{
|
|
97
99
|
name: "spl_pps_x402_submit",
|
|
98
100
|
description:
|
|
99
|
-
"Submit
|
|
101
|
+
"Submit freemium suite job via x402. Under 1 GB free (no paymentHeader). Over free: pass paymentHeader after paying, or devBypass for staging.",
|
|
100
102
|
inputSchema: {
|
|
101
103
|
type: "object",
|
|
102
104
|
properties: {
|
|
@@ -107,7 +109,7 @@ const TOOLS = [
|
|
|
107
109
|
email: { type: "string" },
|
|
108
110
|
note: { type: "string" },
|
|
109
111
|
fileName: { type: "string" },
|
|
110
|
-
paymentHeader: { type: "string", description: "Base64 X-PAYMENT proof" },
|
|
112
|
+
paymentHeader: { type: "string", description: "Base64 X-PAYMENT proof (only if over free cap)" },
|
|
111
113
|
devBypass: { type: "boolean", description: "Staging only if server allows" },
|
|
112
114
|
},
|
|
113
115
|
},
|
|
@@ -115,7 +117,7 @@ const TOOLS = [
|
|
|
115
117
|
{
|
|
116
118
|
name: "spl_pps_quote",
|
|
117
119
|
description:
|
|
118
|
-
"Instant quote
|
|
120
|
+
"Instant freemium quote: free first 1 GB ($0), then ~3¢/GB · min $2. Inputs: product, dataClass, op, bytes. Returns free flag + USD amount.",
|
|
119
121
|
inputSchema: {
|
|
120
122
|
type: "object",
|
|
121
123
|
properties: {
|
|
@@ -129,7 +131,7 @@ const TOOLS = [
|
|
|
129
131
|
"zeros | ramp | walk | mixed_ints | timeseries | json_series | binary | unknown",
|
|
130
132
|
},
|
|
131
133
|
op: { type: "string", description: "compress | decompress | roundtrip" },
|
|
132
|
-
bytes: { type: "number", description: "Payload size in bytes" },
|
|
134
|
+
bytes: { type: "number", description: "Payload size in bytes (≤1GiB = free)" },
|
|
133
135
|
remote: { type: "boolean", description: "If true, use live site API" },
|
|
134
136
|
},
|
|
135
137
|
},
|
|
@@ -137,7 +139,7 @@ const TOOLS = [
|
|
|
137
139
|
{
|
|
138
140
|
name: "spl_pps_checkout",
|
|
139
141
|
description:
|
|
140
|
-
"
|
|
142
|
+
"Checkout for suite quote. Under 1 GB returns free_showcase (no Stripe). Over free returns Stripe Checkout URL.",
|
|
141
143
|
inputSchema: {
|
|
142
144
|
type: "object",
|
|
143
145
|
properties: {
|
|
@@ -152,7 +154,7 @@ const TOOLS = [
|
|
|
152
154
|
{
|
|
153
155
|
name: "spl_pps_submit_job",
|
|
154
156
|
description:
|
|
155
|
-
"Submit a Pay Per Suite job after
|
|
157
|
+
"Submit a Pay Per Suite job (free under 1 GB after free_showcase, or after paid). Lab runs best tool and emails results. Requires email.",
|
|
156
158
|
inputSchema: {
|
|
157
159
|
type: "object",
|
|
158
160
|
properties: {
|
|
@@ -198,6 +200,15 @@ async function callTool(name, args = {}) {
|
|
|
198
200
|
return {
|
|
199
201
|
service: SERVICE_NAME,
|
|
200
202
|
site: SITE_PPS,
|
|
203
|
+
pricing: {
|
|
204
|
+
model: "freemium_suite_v2",
|
|
205
|
+
free_cap_bytes: FREE_BYTES,
|
|
206
|
+
free_cap_gb: 1,
|
|
207
|
+
usd_per_gb_after_free: 0.03,
|
|
208
|
+
usd_per_gb_bulk: 0.02,
|
|
209
|
+
min_paid_cents: MIN_PAID_CENTS,
|
|
210
|
+
try_gate: "retired",
|
|
211
|
+
},
|
|
201
212
|
pay_human: STRIPE_PAYMENT_LINK,
|
|
202
213
|
pay_agent_products: X402_PRODUCTS_URL,
|
|
203
214
|
pay_agent_jobs: X402_SUITE_URL,
|
|
@@ -207,6 +218,7 @@ async function callTool(name, args = {}) {
|
|
|
207
218
|
ops: Object.keys(OP_MULT),
|
|
208
219
|
npm: "spl-pay-per-suite",
|
|
209
220
|
cli: "npx spl-pay-per-suite quote|pay|job|x402|catalog|buy",
|
|
221
|
+
discovery: "https://www.slidphilabs.com/api/agent",
|
|
210
222
|
};
|
|
211
223
|
case "spl_pps_x402_info":
|
|
212
224
|
return agentDiscovery();
|
package/src/quote.mjs
CHANGED
|
@@ -1,100 +1,119 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SPL Pay Per Suite — local quote
|
|
3
|
-
*
|
|
2
|
+
* SPL Pay Per Suite — local quote (matches site freemium money model).
|
|
3
|
+
* Free first 1 GiB · over free: min $2 · ~3¢/GB (2¢ after 50 GB over free).
|
|
4
|
+
* Try Gate retired.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
export const FREE_BYTES = 1 * 1024 * 1024 * 1024;
|
|
8
|
+
export const MAX_BYTES = 100 * 1024 * 1024 * 1024;
|
|
9
|
+
export const MAX_CENTS = 1_000_000;
|
|
10
|
+
export const MIN_PAID_CENTS = 200; // $2.00
|
|
11
|
+
/** @deprecated free tier can be $0 */
|
|
12
|
+
export const MIN_CENTS = 0;
|
|
13
|
+
|
|
14
|
+
export const PRODUCT_ADD_CENTS = {
|
|
15
|
+
auto: 0,
|
|
16
|
+
zrw: 0,
|
|
17
|
+
"cddg-split": 100,
|
|
18
|
+
blackjack: 0,
|
|
19
|
+
"shard-zip": 0,
|
|
20
|
+
"shard-tsdb": 0,
|
|
21
|
+
"slid-phi": 0,
|
|
14
22
|
};
|
|
23
|
+
export const PRODUCT_BASE = PRODUCT_ADD_CENTS;
|
|
15
24
|
|
|
16
25
|
export const DATA_MULT = {
|
|
17
|
-
zeros: 0.
|
|
18
|
-
|
|
19
|
-
walk: 1.05,
|
|
20
|
-
mixed_ints: 1.15,
|
|
21
|
-
timeseries: 1.2,
|
|
22
|
-
json_series: 1.1,
|
|
23
|
-
binary: 1.25,
|
|
24
|
-
unknown: 1.15,
|
|
26
|
+
zeros: 0.9, ramp: 0.95, walk: 1.0, mixed_ints: 1.05,
|
|
27
|
+
timeseries: 1.05, json_series: 1.0, binary: 1.1, unknown: 1.0,
|
|
25
28
|
};
|
|
26
|
-
|
|
27
29
|
export const OP_MULT = {
|
|
28
|
-
compress: 1.0,
|
|
29
|
-
decompress: 0.85,
|
|
30
|
-
roundtrip: 1.35,
|
|
30
|
+
compress: 1.0, decompress: 0.75, roundtrip: 1.15,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
export const MIN_CENTS = 900;
|
|
34
|
-
export const MAX_CENTS = 1_000_000;
|
|
35
|
-
|
|
36
33
|
export const STRIPE_PAYMENT_LINK =
|
|
37
34
|
process.env.SPL_PPS_PAYMENT_LINK ||
|
|
38
35
|
"https://buy.stripe.com/aFa00k4B70OYetL0O46wE0g";
|
|
39
|
-
|
|
40
36
|
export const SITE_PPS = process.env.SPL_PPS_SITE || "https://www.slidphilabs.com/pps";
|
|
41
37
|
export const API_BASE = process.env.SPL_PPS_API || "https://www.slidphilabs.com";
|
|
42
38
|
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
return 800 + 9 * 450 + 90 * 220 + Math.round((mb - 100) * 90);
|
|
39
|
+
export function usageFeeCents(billableBytes) {
|
|
40
|
+
const b = Math.max(0, Number(billableBytes) || 0);
|
|
41
|
+
if (b <= 0) return 0;
|
|
42
|
+
const gb = b / (1024 * 1024 * 1024);
|
|
43
|
+
if (gb <= 50) return Math.round(gb * 3);
|
|
44
|
+
return Math.round(50 * 3 + (gb - 50) * 2);
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
/**
|
|
53
|
-
* @param {{ product?: string, dataClass?: string, op?: string, bytes?: number }} opts
|
|
54
|
-
*/
|
|
55
47
|
export function computeQuote({
|
|
56
48
|
product = "auto",
|
|
57
49
|
dataClass = "unknown",
|
|
58
50
|
op = "compress",
|
|
59
51
|
bytes = 0,
|
|
60
52
|
} = {}) {
|
|
61
|
-
const prod =
|
|
53
|
+
const prod = PRODUCT_ADD_CENTS[product] != null ? product : "auto";
|
|
62
54
|
const cls = DATA_MULT[dataClass] != null ? dataClass : "unknown";
|
|
63
55
|
const operation = OP_MULT[op] != null ? op : "compress";
|
|
64
|
-
const b = Math.max(0, Math.min(Number(bytes) || 0,
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
56
|
+
const b = Math.max(0, Math.min(Number(bytes) || 0, MAX_BYTES));
|
|
57
|
+
const free_bytes = FREE_BYTES;
|
|
58
|
+
const billable = Math.max(0, b - free_bytes);
|
|
59
|
+
const free = billable <= 0;
|
|
60
|
+
const rates = {
|
|
61
|
+
free_cap_gb: 1,
|
|
62
|
+
min_paid_usd: 2.0,
|
|
63
|
+
usd_per_gb_first_50: 0.03,
|
|
64
|
+
usd_per_gb_after_50: 0.02,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (free) {
|
|
68
|
+
return {
|
|
69
|
+
ok: true,
|
|
70
|
+
service: "SPL Pay Per Suite",
|
|
71
|
+
currency: "usd",
|
|
72
|
+
amount_cents: 0,
|
|
73
|
+
amount_display: "0.00",
|
|
74
|
+
free: true,
|
|
75
|
+
tier: "free_showcase",
|
|
76
|
+
message: "Free showcase — first 1 GB $0. Over free: from $2 min · ~3¢/GB.",
|
|
77
|
+
breakdown: {
|
|
78
|
+
product: prod, product_add_cents: 0, product_base_cents: 0,
|
|
79
|
+
free_bytes, free_gb: 1, billable_bytes: 0, usage_cents: 0, size_cents: 0,
|
|
80
|
+
data_class: cls, data_multiplier: DATA_MULT[cls],
|
|
81
|
+
op: operation, op_multiplier: OP_MULT[operation],
|
|
82
|
+
bytes: b, mb: +(b/1024/1024).toFixed(4), gb: +(b/1024/1024/1024).toFixed(6),
|
|
83
|
+
min_cents: 0, min_paid_cents: MIN_PAID_CENTS, max_cents: MAX_CENTS, rates,
|
|
84
|
+
},
|
|
85
|
+
pay_url: STRIPE_PAYMENT_LINK,
|
|
86
|
+
suite_url: SITE_PPS,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
69
89
|
|
|
90
|
+
const usage = usageFeeCents(billable);
|
|
91
|
+
const add = PRODUCT_ADD_CENTS[prod] || 0;
|
|
92
|
+
const raw = Math.round((usage + add) * DATA_MULT[cls] * OP_MULT[operation]);
|
|
93
|
+
const cents = Math.min(MAX_CENTS, Math.max(MIN_PAID_CENTS, raw));
|
|
70
94
|
return {
|
|
71
95
|
ok: true,
|
|
72
96
|
service: "SPL Pay Per Suite",
|
|
73
97
|
currency: "usd",
|
|
74
98
|
amount_cents: cents,
|
|
75
99
|
amount_display: (cents / 100).toFixed(2),
|
|
100
|
+
free: false,
|
|
101
|
+
tier: "usage",
|
|
102
|
+
message: "Usage — free 1 GB, then from $2 min · ~3¢/GB (2¢ after 50 GB over free).",
|
|
76
103
|
breakdown: {
|
|
77
|
-
product: prod,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
op_multiplier: OP_MULT[operation],
|
|
84
|
-
bytes: b,
|
|
85
|
-
mb: +(b / (1024 * 1024)).toFixed(4),
|
|
86
|
-
min_cents: MIN_CENTS,
|
|
87
|
-
max_cents: MAX_CENTS,
|
|
104
|
+
product: prod, product_add_cents: add, product_base_cents: add,
|
|
105
|
+
free_bytes, free_gb: 1, billable_bytes: billable, usage_cents: usage, size_cents: usage,
|
|
106
|
+
data_class: cls, data_multiplier: DATA_MULT[cls],
|
|
107
|
+
op: operation, op_multiplier: OP_MULT[operation],
|
|
108
|
+
bytes: b, mb: +(b/1024/1024).toFixed(4), gb: +(b/1024/1024/1024).toFixed(6),
|
|
109
|
+
min_cents: MIN_PAID_CENTS, min_paid_cents: MIN_PAID_CENTS, max_cents: MAX_CENTS, rates,
|
|
88
110
|
},
|
|
89
111
|
pay_url: STRIPE_PAYMENT_LINK,
|
|
90
112
|
suite_url: SITE_PPS,
|
|
91
113
|
};
|
|
92
114
|
}
|
|
93
115
|
|
|
94
|
-
|
|
95
|
-
* Lightweight data-class heuristic from a Buffer / Uint8Array sample.
|
|
96
|
-
* Does not run proprietary codecs.
|
|
97
|
-
*/
|
|
116
|
+
|
|
98
117
|
export function classifyBytes(buf) {
|
|
99
118
|
if (!buf || !buf.length) return { dataClass: "unknown", tool: "auto", confidence: 0 };
|
|
100
119
|
const u8 = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
@@ -108,12 +127,10 @@ export function classifyBytes(buf) {
|
|
|
108
127
|
const zeroRatio = zeros / n;
|
|
109
128
|
const printRatio = printable / n;
|
|
110
129
|
|
|
111
|
-
// JSON-ish
|
|
112
130
|
if (printRatio > 0.85 && (u8[0] === 0x7b || u8[0] === 0x5b)) {
|
|
113
131
|
return { dataClass: "json_series", tool: "zrw", confidence: 0.7 };
|
|
114
132
|
}
|
|
115
133
|
|
|
116
|
-
// Look for int32-like ramp/zeros if length multiple of 4
|
|
117
134
|
if (u8.length >= 16 && u8.length % 4 === 0) {
|
|
118
135
|
const view = new DataView(u8.buffer, u8.byteOffset, Math.min(u8.length, 400));
|
|
119
136
|
const ints = [];
|