srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/export_store.js53
1 files changed, 53 insertions, 0 deletions
diff --git a/scripts/export_store.js b/scripts/export_store.js
new file mode 100644
index 0000000..d69ac29
--- /dev/null
+++ b/scripts/export_store.js
@@ -0,0 +1,53 @@
+#!/usr/bin/env node
+// Writes the store catalogue to web/src/data/store.json.
+//
+// The store reads its catalogue from the server. With no server the page
+// rendered its heading over an empty shop, which looks like a fault rather
+// than a feature that needs signing in. This file is the same fallback the
+// text packs already use: bundled with the client, served from the database
+// and merged over the top once a server exists.
+//
+// Run it after changing prices or adding items:
+// node scripts/export_store.js
+//
+// It shells out to psql so it needs no node dependencies, matching the rest
+// of the scripts here.
+const { execFileSync } = require('node:child_process');
+const { writeFileSync } = require('node:fs');
+const { join } = require('node:path');
+
+const URL = process.env.DATABASE_URL
+ || 'postgresql://typerpunk:typerpunk@localhost/typerpunk';
+
+function query(sql) {
+ const out = execFileSync('psql', [URL, '-At', '-c', sql], { encoding: 'utf8' });
+ return JSON.parse(out.trim() || '[]');
+}
+
+const cosmetics = query(`
+ SELECT COALESCE(json_agg(row_to_json(c) ORDER BY c.category, c.price_cents), '[]'::json)
+ FROM (SELECT id, name, category, price_cents, value FROM cosmetics) c`);
+
+const bundles = query(`
+ SELECT COALESCE(json_agg(b ORDER BY b.sort_order), '[]'::json) FROM (
+ SELECT b.id, b.name, b.description, b.price_cents, b.sort_order,
+ COALESCE(SUM(c.price_cents), 0)::int AS full_price_cents,
+ COALESCE(ARRAY_AGG(c.id ORDER BY c.id)
+ FILTER (WHERE c.id IS NOT NULL), '{}') AS items
+ FROM bundles b
+ LEFT JOIN bundle_items bi ON bi.bundle_id = b.id
+ LEFT JOIN cosmetics c ON c.id = bi.cosmetic_id
+ GROUP BY b.id, b.name, b.description, b.price_cents, b.sort_order
+ ) b`);
+
+const merch = query(`
+ SELECT COALESCE(json_agg(m ORDER BY m.sort_order), '[]'::json) FROM (
+ SELECT id, name, description, price_cents, shipping_cents, kind, variants, sort_order
+ FROM merch WHERE available
+ ) m`);
+
+for (const row of [...bundles, ...merch]) delete row.sort_order;
+
+const out = join(__dirname, '..', 'web', 'src', 'data', 'store.json');
+writeFileSync(out, JSON.stringify({ cosmetics, bundles, merch }, null, 2) + '\n');
+console.log(`Wrote ${cosmetics.length} cosmetics, ${bundles.length} bundles and ${merch.length} merch items to ${out}`);