@homie-rocks/studio 0.33.1 → 0.35.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.
- package/CHANGELOG.md +53 -1
- package/README.md +18 -14
- package/bin/homie-studio.mjs +4 -4
- package/lib/build.mjs +3 -3
- package/lib/cloudflare.mjs +3 -2
- package/lib/doctor.mjs +11 -11
- package/lib/mcp-tools.mjs +15 -0
- package/lib/mcp.mjs +1 -0
- package/lib/scaffold.mjs +45 -39
- package/lib/shop-catalog.mjs +4 -4
- package/lib/shop-links.mjs +91 -0
- package/lib/shop.mjs +28 -20
- package/lib/stripe-connect.mjs +135 -0
- package/lib/template-history.json +84 -0
- package/package.json +1 -1
- package/shop/SELLING.md +15 -91
- package/shop/SHOP.md +185 -274
- package/shop/shop.ts +20 -5
- package/worker/index.mjs +7 -1
- package/worker/office.mjs +1 -1
- package/worker/players.mjs +1 -1
- package/worker/referrals.mjs +9 -12
- package/worker/shop-links.mjs +46 -0
- package/worker/shop-page.mjs +93 -31
- package/worker/shop-rules.mjs +39 -58
- package/worker/shop-store.mjs +101 -9
- package/worker/shop.mjs +638 -223
- package/worker/stripe.mjs +22 -13
- package/worker/version.mjs +1 -1
package/worker/stripe.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* THE STUDIO'S OWN STRIPE, from its Worker (@homie-rocks/studio 0.24.0). No SDK: a few form-encoded calls with the
|
|
3
|
-
* studio's
|
|
3
|
+
* studio's key (a Worker secret), and Stripe's documented webhook signature check with WebCrypto.
|
|
4
4
|
*
|
|
5
|
-
* createCheckoutSession(env, params) POST /v1/checkout/sessions (Stripe's hosted page
|
|
5
|
+
* createCheckoutSession(env, params) POST /v1/checkout/sessions (Stripe's hosted page)
|
|
6
6
|
* createRefund(env, params) POST /v1/refunds (only ever from the owner's tap, or a confirmed ask)
|
|
7
|
-
* webhook endpoints list, create and turn off:
|
|
7
|
+
* webhook endpoints list, create and turn off: the manual `homie-studio shop connect --manual` fallback calls these, on the
|
|
8
8
|
* owner's computer with the key the owner pasted there (0.24.3), so a new
|
|
9
9
|
* endpoint's signing secret goes straight to the Worker secret
|
|
10
10
|
* productIdOf(slug, item) the catalog Product a shop item is (`homie-studio shop catalog`, 0.24.3)
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
/** The API version the kit is written against: the first one Managed Payments takes ("2025-03-31.basil or later"). */
|
|
19
19
|
export const STRIPE_VERSION = '2025-03-31.basil';
|
|
20
20
|
export const STRIPE_API = 'https://api.stripe.com';
|
|
21
|
-
/**
|
|
21
|
+
/** Stripe's replay defense: https://docs.stripe.com/webhooks#preventing-replay-attacks */
|
|
22
22
|
export const TOLERANCE_S = 300;
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
export const KEY_SHAPE = /^(?:
|
|
26
|
-
export const WEBHOOK_SECRET_SHAPE = /^whsec_[A-Za-z0-9+/=_-]
|
|
24
|
+
/** Stripe key types: https://docs.stripe.com/keys — the studio chooses restricted or secret keys. */
|
|
25
|
+
export const KEY_SHAPE = /^(?:rk|sk)_(?:test|live)_[A-Za-z0-9]+$/;
|
|
26
|
+
export const WEBHOOK_SECRET_SHAPE = /^whsec_[A-Za-z0-9+/=_-]+$/;
|
|
27
27
|
|
|
28
28
|
/** test or live, from the key alone (never by calling Stripe). */
|
|
29
29
|
export const modeOf = (key) => (/^(?:rk|sk)_live_/.test(String(key ?? '')) ? 'live' : 'test');
|
|
@@ -51,14 +51,21 @@ export function formEncode(params, prefix = '', out = new URLSearchParams()) {
|
|
|
51
51
|
return out;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/** Redact before truncating: provider errors can echo authorization or client secrets. */
|
|
55
|
+
export function redactStripe(value, env = {}) {
|
|
56
|
+
let text = String(value ?? '');
|
|
57
|
+
for (const secret of [env.STRIPE_KEY, env.STRIPE_WEBHOOK_SECRET]) if (secret) text = text.replaceAll(String(secret), '[redacted]');
|
|
58
|
+
return text.replace(/(?:[rs]k_(?:test|live)_[A-Za-z0-9]+|whsec_[A-Za-z0-9+/=_-]+|[A-Za-z0-9_]+_secret_[A-Za-z0-9_-]+)/g, '[redacted]');
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
export class StripeError extends Error {
|
|
55
62
|
constructor(status, body) {
|
|
56
63
|
const e = body?.error ?? {};
|
|
57
|
-
super(e.message ?
|
|
64
|
+
super(e.message ? redactStripe(e.message).slice(0, 300) : `Stripe answered ${status}`);
|
|
58
65
|
this.status = status;
|
|
59
|
-
this.code = e.code ?? e.type ?? 'stripe';
|
|
60
|
-
this.type = e.type
|
|
61
|
-
this.param = typeof e.param === 'string' ? e.param.slice(0, 120) : null;
|
|
66
|
+
this.code = redactStripe(e.code ?? e.type ?? 'stripe');
|
|
67
|
+
this.type = e.type ? redactStripe(e.type) : null;
|
|
68
|
+
this.param = typeof e.param === 'string' ? redactStripe(e.param).slice(0, 120) : null;
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
|
|
@@ -91,7 +98,8 @@ export async function stripeCall(env, method, path, params = null, { idempotency
|
|
|
91
98
|
if (!KEY_SHAPE.test(key)) throw new StripeError(0, { error: { message: 'no Stripe key on this Worker', code: 'no-key' } });
|
|
92
99
|
const body = params && method !== 'GET' ? formEncode(params).toString() : null;
|
|
93
100
|
const query = params && method === 'GET' ? `?${formEncode(params).toString()}` : '';
|
|
94
|
-
|
|
101
|
+
let res;
|
|
102
|
+
try { res = await fetcher(`${apiBase(env)}${path}${query}`, {
|
|
95
103
|
method,
|
|
96
104
|
headers: {
|
|
97
105
|
authorization: `Bearer ${key}`,
|
|
@@ -102,9 +110,10 @@ export async function stripeCall(env, method, path, params = null, { idempotency
|
|
|
102
110
|
...(body !== null ? { body } : {}),
|
|
103
111
|
signal: AbortSignal.timeout(timeout),
|
|
104
112
|
});
|
|
113
|
+
} catch (error) { throw new StripeError(502, { error: { message: redactStripe(error?.message ?? 'Stripe did not answer', env), code: 'network' } }); }
|
|
105
114
|
let json = null;
|
|
106
115
|
try { json = await res.json(); } catch { json = null; }
|
|
107
|
-
if (!res.ok) throw new StripeError(res.status, json);
|
|
116
|
+
if (!res.ok) throw new StripeError(res.status, JSON.parse(redactStripe(JSON.stringify(json), env)));
|
|
108
117
|
return json;
|
|
109
118
|
}
|
|
110
119
|
|
package/worker/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** The @homie-rocks/studio version this Worker code is (package.json's; a test keeps them equal). Cache-busts /_homie/site.js. */
|
|
2
|
-
export const STUDIO_VERSION_TAG = '0.
|
|
2
|
+
export const STUDIO_VERSION_TAG = '0.35.0';
|