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 CHANGED
@@ -1,121 +1,50 @@
1
- # SPL Pay Per Suite
1
+ # spl-pay-per-suite
2
2
 
3
- **On-spot project quotes · dual payment rails · lab job intake** for Slid Phi Labs.
3
+ **SPL Pay Per Suite** freemium quotes, Stripe (humans) + x402 (agents). Library, CLI, and MCP.
4
4
 
5
- | Who | Rail |
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
- - **npm:** `spl-pay-per-suite`
11
- - **CLI:** `spl-pps` · `pay-per-suite`
12
- - **MCP:** stdio tools including `spl_pps_x402_*`
13
- - **Discovery:** `GET https://www.slidphilabs.com/api/agent`
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
- Private engines stay in the lab. This package quotes, routes payment, and submits jobs it does **not** ship proprietary codecs.
13
+ **Try Gate is retired.** Evaluate on free suite — not a $9 chip-in.
16
14
 
17
- ## Install
15
+ License packages (CDDG:Split, ZRW tiers, etc.) remain separate fixed SKUs via catalog/x402.
18
16
 
19
- ```bash
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
- ## CLI
19
+ ## Install
26
20
 
27
21
  ```bash
28
- spl-pps quote --bytes 5242880 --class mixed_ints --product auto --op compress
29
- spl-pps quote ./payload.bin
30
- spl-pps pay ./payload.bin --email you@company.com
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
- ## Library
27
+ ## Quote (local)
36
28
 
37
29
  ```js
38
- import { computeQuote, createCheckout, submitJob, quoteFile } from "spl-pay-per-suite";
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
- ## Agentic commerce (x402)
32
+ computeQuote({ product: "auto", op: "compress", bytes: 100e6 });
33
+ // → free: true, amount_cents: 0
58
34
 
59
- **All standing products** + **metered suite jobs**.
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-serve
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
- ```json
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
- ## License
48
+ ## IP Guard
120
49
 
121
- © 2026 Slid Phi Labs. Client tooling only; engines and commercial fulfillment remain proprietary.
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.2",
4
- "description": "SPL Pay Per Suite — on-spot quotes, Stripe (humans) + x402 agentic commerce (machines). Library, CLI, and MCP.",
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": "Modules: Compression (SPL Codec+CDDG) · Agent platform (CuNi+Rider+Quikgater). Commerce: GET https://www.slidphilabs.com/api/agent then x402 X-PAYMENT.",
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";
@@ -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: service name, site URL, Stripe (humans) + x402 (agents), products, data classes, ops.",
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 job endpoints, headers, flow. Stripe remains for humans.",
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 all standing Slid Phi Labs products agents can buy via x402 (CDDG:Split, ZRW tiers, Blackjack, shards, support, etc.) with USD prices.",
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 | try-gate",
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 (metered job) without paying. Returns 402 accepts[] for suite compress/decompress jobs.",
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 metered suite job via x402 (not fixed SKU). Pass paymentHeader after paying, or devBypass for staging.",
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 for an SPL Pay Per Suite project. Inputs: product, dataClass, op, bytes. Returns USD amount and breakdown.",
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
- "Create Stripe checkout URL for the quoted SPL Pay Per Suite amount. Prefer after spl_pps_quote.",
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 payment. Lab runs the best available tool and emails results. Requires email.",
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 engine (matches site /api/ppp-quote).
3
- * Price = product value base + size fee × data-class × operation.
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 PRODUCT_BASE = {
7
- auto: 2900,
8
- zrw: 2900,
9
- "cddg-split": 4900,
10
- blackjack: 3900,
11
- "shard-zip": 3900,
12
- "shard-tsdb": 3900,
13
- "slid-phi": 3900,
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.85,
18
- ramp: 0.95,
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 sizeFeeCents(bytes) {
44
- const mb = Math.max(0, Number(bytes) || 0) / (1024 * 1024);
45
- if (mb <= 0) return 0;
46
- if (mb <= 1) return Math.round(mb * 800);
47
- if (mb <= 10) return 800 + Math.round((mb - 1) * 450);
48
- if (mb <= 100) return 800 + 9 * 450 + Math.round((mb - 10) * 220);
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 = PRODUCT_BASE[product] != null ? product : "auto";
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, 5 * 1024 * 1024 * 1024));
65
- const base = PRODUCT_BASE[prod];
66
- const size = sizeFeeCents(b);
67
- const raw = Math.round((base + size) * DATA_MULT[cls] * OP_MULT[operation]);
68
- const cents = Math.min(MAX_CENTS, Math.max(MIN_CENTS, raw));
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
- product_base_cents: base,
79
- size_cents: size,
80
- data_class: cls,
81
- data_multiplier: DATA_MULT[cls],
82
- op: operation,
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 = [];