pricing.js
2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// pricing_config (dev-plan-4.md T23; schema: dressup-dance-room-mvcp.md
// M.12) — a JSON file, not SQLite: it's operator-edited config, not on the
// "spend + generate + refund" atomic path that's why credit_ledger (db.js)
// needed SQLite. Keyed by `key` (not an auto id), so this is deliberately
// its own tiny module rather than store.js's createStore.
const fs = require("fs");
const path = require("path");
const PRICING_PATH = process.env.PRICING_PATH || path.join(__dirname, "pricing.json");
// Real values are TBD (dev-plan-4.md §1.2 item 3) — these are placeholders
// so the spend/topup mechanism has something to read; change the numbers
// in pricing.json (or here, before first run) whenever real pricing lands.
const DEFAULTS = [
{ key: "spend_garment", kind: "spend", credits: 10, priceCents: null, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() },
// dev-plan-5.md T35: credits/segmentsPerUnit together mean "20 credits
// buys 1 ten-second segment" — cost = ceil(credits/segmentsPerUnit *
// requestedSegments). Placeholder, same as spend_garment above.
{ key: "spend_character_per_segment", kind: "spend", credits: 20, priceCents: null, segmentsPerUnit: 1, isActive: true, updatedAt: Date.now() },
{ key: "topup_tier_1", kind: "topup_tier", credits: 100, priceCents: 999, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() },
{ key: "topup_tier_2", kind: "topup_tier", credits: 550, priceCents: 4999, segmentsPerUnit: null, isActive: true, updatedAt: Date.now() },
];
function load(filePath) {
try {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch {
fs.writeFileSync(filePath, JSON.stringify(DEFAULTS, null, 2));
return DEFAULTS.slice();
}
}
function createPricingStore(filePath) {
function save(items) {
fs.writeFileSync(filePath, JSON.stringify(items, null, 2));
}
return {
list() {
return load(filePath);
},
get(key) {
return load(filePath).find((p) => p.key === key) || null;
},
upsert(key, patch) {
const items = load(filePath);
const idx = items.findIndex((p) => p.key === key);
const updated = idx === -1 ? { key, isActive: true, ...patch, updatedAt: Date.now() } : { ...items[idx], ...patch, key, updatedAt: Date.now() };
if (idx === -1) items.push(updated);
else items[idx] = updated;
save(items);
return updated;
},
};
}
module.exports = { createPricingStore, pricing: createPricingStore(PRICING_PATH) };