fresh-squeezy 0.1.9 → 0.1.11

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.es.md ADDED
@@ -0,0 +1,249 @@
1
+ <!-- Traducido de README.md; la versión en inglés es la fuente de verdad. -->
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/YosefHayim/fresh-squeezy">
5
+ <img src="assets/fresh-squeezy-hero.png" alt="fresh-squeezy — el doctor con enfoque en validación para tu configuración de Lemon Squeezy. Detecta errores de configuración de facturación y webhooks antes de que lleguen a producción." width="640" />
6
+ </a>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <strong>El doctor para tu configuración de Lemon Squeezy — detecta errores de configuración de facturación y webhooks antes de que lleguen a producción.</strong>
11
+ </p>
12
+
13
+ <!-- Badges. tests count is static; bump it on major test-suite changes. -->
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/fresh-squeezy"><img src="https://img.shields.io/npm/v/fresh-squeezy?logo=npm&amp;color=cb3837" alt="npm version" /></a>
16
+ <a href="https://www.npmjs.com/package/fresh-squeezy"><img src="https://img.shields.io/npm/dm/fresh-squeezy?logo=npm&amp;color=cb3837" alt="npm downloads per month" /></a>
17
+ <a href="https://github.com/YosefHayim/fresh-squeezy/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/YosefHayim/fresh-squeezy/ci.yml?branch=main&amp;logo=github&amp;label=CI" alt="CI status" /></a>
18
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/fresh-squeezy?color=3fb950" alt="MIT license" /></a>
19
+ <img src="https://img.shields.io/node/v/fresh-squeezy?logo=node.js&amp;logoColor=white&amp;color=339933" alt="Node.js 20 or newer" />
20
+ <img src="https://img.shields.io/npm/types/fresh-squeezy?logo=typescript&amp;logoColor=white" alt="TypeScript types included" />
21
+ <a href="https://packagephobia.com/result?p=fresh-squeezy"><img src="https://packagephobia.com/badge?p=fresh-squeezy" alt="install size" /></a>
22
+ <img src="https://img.shields.io/badge/tests-154%20passing-3fb950?logo=vitest&amp;logoColor=white" alt="154 tests passing" />
23
+ </p>
24
+
25
+ <p align="center">
26
+ <a href="./README.md">English</a> ·
27
+ <a href="./README.zh-CN.md">简体中文</a> ·
28
+ <a href="./README.ja.md">日本語</a> ·
29
+ <b>Español</b> ·
30
+ <a href="./README.pt-BR.md">Português</a>
31
+ </p>
32
+
33
+ > Las traducciones pueden estar desactualizadas. La versión canónica es el [README en inglés](./README.md).
34
+
35
+ <p align="center">
36
+ <a href="#inicio-en-30-segundos">Inicio rápido</a> ·
37
+ <a href="#lo-que-detecta-y-que-postman-y-el-sdk-oficial-no-detectan">Lo que detecta</a> ·
38
+ <a href="#fresh-squeezy-frente-a-las-alternativas">Comparación</a> ·
39
+ <a href="#cli">CLI</a> ·
40
+ <a href="#biblioteca">Biblioteca</a> ·
41
+ <a href="#códigos-de-incidencia">Códigos de incidencia</a> ·
42
+ <a href="#faq">FAQ</a>
43
+ </p>
44
+
45
+ ---
46
+
47
+ **fresh-squeezy** es una CLI y una biblioteca de TypeScript que valida tu integración de facturación de [Lemon Squeezy](https://www.lemonsqueezy.com/) — tiendas, productos, webhooks, descuentos, claves de licencia y planes de suscripción — y detecta errores de configuración antes de que lleguen a producción. Ejecútala como un único comando `doctor` localmente o en CI: devuelve [códigos de salida](#inicio-en-30-segundos) estables y JSON legible por máquina, y rastrea las desviaciones del [registro de cambios de la API de Lemon Squeezy](https://docs.lemonsqueezy.com/api/getting-started/changelog) que el SDK oficial aún no ha incorporado. Node 20+.
48
+
49
+ ## Inicio en 30 segundos
50
+
51
+ ```bash
52
+ npx fresh-squeezy
53
+ ```
54
+
55
+ La primera ejecución agrega `fresh-squeezy` a las devDependencies cuando no está presente, y luego inicia la configuración guiada. No hay que copiar un ID de tienda desde el panel — la CLI descubre por sí misma las tiendas accesibles. Usa `npx fresh-squeezy --no-install` para ejecutar la configuración sin modificar `package.json`.
56
+
57
+ | Salida | Significado |
58
+ |------|---------|
59
+ | `0` | Todos los validadores pasaron |
60
+ | `1` | Uno o más validadores reportaron incidencias de nivel `error` |
61
+ | `2` | Fatal (clave faltante, flags inválidos, fallo de red) |
62
+ | `130` | El usuario canceló un flujo interactivo |
63
+
64
+ ## Lo que detecta y que Postman y el SDK oficial no detectan
65
+
66
+ - **Clave de producción apuntando a staging.** `MODE_MISMATCH` se dispara cuando el verdadero `meta.test_mode` de la clave (registro de cambios de la API 2024-01-05) no coincide con el modo declarado. Doctor sale con 1. Ni el SDK ni un wrapper hecho a mano detectan esto por defecto.
67
+ - **Discrepancias silenciosas de propiedad de tienda.** Productos, descuentos, claves de licencia y planes de suscripción cuyo `store_id` no coincide con la tienda a la que limitaste la ejecución. Códigos estables: `PRODUCT_WRONG_STORE`, `DISCOUNT_STORE_MISMATCH`, `LICENSE_KEY_STORE_MISMATCH`, `PLAN_STORE_MISMATCH`.
68
+ - **Webhook suscrito a los eventos equivocados.** Comparación contra un manifiesto de eventos recomendados (ciclo de vida de pedidos/suscripciones, reembolsos) y eventos más recientes pero opcionales que el SDK no incluye.
69
+ - **Desviación de la plataforma.** Una GitHub Action semanal calcula el hash del [registro de cambios de la API de Lemon Squeezy](https://docs.lemonsqueezy.com/api/getting-started/changelog) contra `src/support/changelog-snapshot.json`, actualiza los tipos de la API derivados de la documentación y abre tareas de seguimiento cuando se necesitan decisiones de política. Las adiciones rastreadas incluyen `customer_updated` (2026-02-25), `payment_processor` en Subscription (2025-06-11), Affiliates + `affiliate_activated` (2025-01-21), `quantity` de los ítems de pedido (2024-12-06), estilos de checkout / `skip_trial` / `variant_quantities`, campos de reembolso de facturas de suscripción y `test_mode` en `/v1/users/me` (2024-01-05).
70
+ - **El ping-pong entre Postman y el panel.** Una sola llamada a `doctor` reemplaza el ciclo de copiar IDs de la interfaz, pegarlos en archivos de entorno y verificar cada uno a mano.
71
+
72
+ ## fresh-squeezy frente a las alternativas
73
+
74
+ Cómo se compara una verificación previa al lanzamiento típica de Lemon Squeezy entre las herramientas a las que un desarrollador recurriría de otro modo:
75
+
76
+ | Capacidad | fresh-squeezy | SDK oficial | Postman | Wrapper hecho a mano |
77
+ |---|:---:|:---:|:---:|:---:|
78
+ | Detección de discrepancia de modo / clave (`MODE_MISMATCH`) | ✅ | ❌ | ❌ | ❌ |
79
+ | Verificaciones cruzadas de propiedad de tienda | ✅ | ❌ | ❌ | ⚠️ manual |
80
+ | Comparación de cobertura de eventos de webhook | ✅ | ❌ | ⚠️ manual | ⚠️ manual |
81
+ | Validación de descuentos / claves de licencia / planes | ✅ | ❌ | ❌ | ⚠️ manual |
82
+ | Rastreo de desviación del registro de cambios | ✅ | ❌ | ❌ | ❌ |
83
+ | Códigos de salida + JSON estables y listos para CI | ✅ | ❌ | ❌ | ⚠️ manual |
84
+ | Barrido completo en un solo comando (`doctor`) | ✅ | ❌ | ❌ | ❌ |
85
+ | Respuestas de la API tipadas | ✅ | ✅ | ❌ | ⚠️ depende |
86
+
87
+ fresh-squeezy **no** es un reemplazo del SDK oficial — es la verificación previa que ejecutas *junto* a él. Usa el SDK para hacer llamadas a la API; usa fresh-squeezy para comprobar que tu configuración es correcta antes de que esas llamadas lleguen a producción.
88
+
89
+ ## CLI
90
+
91
+ ```bash
92
+ # First run: install as a dev dependency, then start guided setup
93
+ npx fresh-squeezy
94
+
95
+ # Guided setup only: reuse env values, pick a store, choose resource checks
96
+ npx fresh-squeezy init
97
+
98
+ # TTY: multi-select stores interactively, run doctor on each
99
+ npx fresh-squeezy doctor
100
+
101
+ # Full sweep across every reachable store and resource
102
+ npx fresh-squeezy doctor --all-stores --all-resources
103
+
104
+ # Machine-readable full sweep for CI
105
+ npx fresh-squeezy doctor --all-stores --all-resources --json
106
+
107
+ # Single validator, scoped to specific stores
108
+ npx fresh-squeezy validate webhook \
109
+ --store-ids 12,34 \
110
+ --webhook-url https://app.example.com/api/webhooks/lemon-squeezy
111
+ ```
112
+
113
+ Las tiendas se resuelven en este orden para cada comando con alcance de tienda: `--store-ids` explícito, luego `--all-stores`, luego una multiselección interactiva en una TTY, y por último una ejecución solo de conexión cuando no hay TTY ni flag (útil como verificación rápida en CI). `doctor` valida la conexión y el acceso a la tienda, además de cualquier flag de recurso explícito; agrega `--all-resources` para descubrir y validar todos los recursos compatibles en la(s) tienda(s) seleccionada(s).
114
+
115
+ **→ Referencia completa de comandos, flags y resolución de tiendas: [docs/cli-reference.md](./docs/cli-reference.md)**
116
+
117
+ ## Biblioteca
118
+
119
+ ```ts
120
+ import { createFreshSqueezy } from "fresh-squeezy";
121
+
122
+ const lemon = createFreshSqueezy(); // reads LEMON_SQUEEZY_API_KEY, LEMON_SQUEEZY_MODE
123
+
124
+ const report = await lemon.doctor({
125
+ storeId: 12, // library is single-store per call
126
+ productId: 987,
127
+ webhookUrl: "https://app.example.com/api/webhooks/lemon-squeezy",
128
+ });
129
+
130
+ if (!report.ok) {
131
+ for (const result of report.results) {
132
+ for (const issue of result.issues) {
133
+ console.error(`[${issue.severity}] ${issue.code}: ${issue.message}`);
134
+ }
135
+ }
136
+ process.exit(1);
137
+ }
138
+ ```
139
+
140
+ Para ejecuciones multitienda en la capa de biblioteca, llama a `doctor()` en un bucle — la CLI hace exactamente esto. Decide según `issue.code` en la lógica de CI; los códigos son estables entre versiones menores.
141
+
142
+ Tipos públicos: [`FreshSqueezyClient`](src/createFreshSqueezy.ts), [`ValidationResult<T>`](src/core/types.ts), [`DoctorReport`](src/core/types.ts), interfaces de atributos de recursos bajo [`src/resources`](src/resources), tipos de objetos de Lemon Squeezy generados a partir de la documentación en [`src/generated/lemonSqueezyApiTypes.ts`](src/generated/lemonSqueezyApiTypes.ts), y helpers de aumento del registro de cambios en [`src/augmentations.ts`](src/augmentations.ts).
143
+
144
+ Para endpoints que aún no están envueltos, usa la vía de escape sin procesar:
145
+
146
+ ```ts
147
+ const user = await lemon.request({ path: "/v1/users/me" });
148
+ ```
149
+
150
+ ## Sandbox frente a producción
151
+
152
+ Lemon Squeezy sirve ambos modos desde el mismo host de API; el modo se determina por la clave. `fresh-squeezy` compara el modo declarado contra `meta.test_mode` de `/v1/users/me`. Discrepancia = `MODE_MISMATCH`, doctor sale con 1 — la forma más rápida de detectar una clave de producción apuntando a staging antes de que cause daño.
153
+
154
+ ```ts
155
+ const lemon = createFreshSqueezy({ mode: "test" });
156
+ const result = await lemon.validateConnection();
157
+ result.mode; // "test" (declared)
158
+ result.resource?.actualMode; // "live" — alarm bell
159
+ ```
160
+
161
+ El valor por defecto de la CLI es `--mode test`. Anúlalo con `--mode live`. La configuración guiada pide confirmación explícita antes de continuar con una clave de modo live detectada. Para verificaciones nocturnas de desviación de la plataforma en CI, ejecuta `npm run test:live` con `LEMON_SQUEEZY_LIVE_SMOKE=1` y una clave de modo test.
162
+
163
+ ## Variables de entorno
164
+
165
+ | Variable | Requerida | Propósito |
166
+ |----------|----------|---------|
167
+ | `LEMON_SQUEEZY_API_KEY` | sí | Token Bearer (biblioteca + CLI) |
168
+ | `LEMON_SQUEEZY_MODE` | no | `test` (por defecto) o `live` |
169
+ | `LEMON_SQUEEZY_STORE_ID` | no | Valor por defecto de conveniencia para `client.doctor()` — solo biblioteca |
170
+
171
+ La CLI no lee `LEMON_SQUEEZY_STORE_ID`; usa `--store-ids` o `--all-stores` para que la selección de tienda siga siendo explícita en cada comando.
172
+
173
+ ## Códigos de incidencia
174
+
175
+ Decide según `issue.code` en CI — todos los códigos son estables entre versiones menores. Los más comunes:
176
+
177
+ | Código | Significado |
178
+ |------|---------|
179
+ | `AUTH_FAILED` | Clave de API inválida o faltante |
180
+ | `MODE_MISMATCH` | El modo declarado no coincide con el `meta.test_mode` de la clave |
181
+ | `STORE_NOT_FOUND` / `STORE_NOT_OWNED` | ID de tienda inválido o propiedad de otra cuenta |
182
+ | `PRODUCT_UNPUBLISHED` / `PRODUCT_WRONG_STORE` / `PRODUCT_NO_BUY_URL` | El producto no puede aceptar checkout |
183
+ | `WEBHOOK_NOT_FOUND` / `WEBHOOK_EVENTS_MISSING` | URL de webhook no registrada o con suscripción insuficiente |
184
+
185
+ **→ Referencia completa de códigos de incidencia (descuentos, claves de licencia, planes, variantes, red) con ejemplos de vía de escape: [docs/issue-codes.md](./docs/issue-codes.md)**
186
+
187
+ ## Referencia
188
+
189
+ Validadores — cada uno devuelve un `ValidationResult` estable:
190
+
191
+ - **`validateConnection`** — accesibilidad, validez de la clave, presencia de tienda, modo declarado frente al real. [→ código fuente](src/validate/connection.ts)
192
+ - **`validateStore`** — el ID de tienda existe y es propiedad de la cuenta de la clave. [→ código fuente](src/validate/store.ts)
193
+ - **`validateProduct`** — publicado, en la tienda esperada, tiene variantes activas y una URL de compra. [→ código fuente](src/validate/product.ts)
194
+ - **`validateWebhook`** — URL de webhook registrada y suscrita a los eventos recomendados. [→ código fuente](src/validate/webhook.ts)
195
+ - **`validateDiscount`** — activo, dentro de la ventana, importe válido, propiedad de tienda coincide. [→ código fuente](src/validate/discount.ts)
196
+ - **`validateLicenseKey`** — habilitada, no expirada, activaciones disponibles, propiedad de tienda coincide. [→ código fuente](src/validate/licenseKey.ts)
197
+ - **`validateSubscriptionPlan`** — tipo de suscripción, intervalo válido, precio distinto de cero, prueba consistente. [→ código fuente](src/validate/subscriptionPlan.ts)
198
+ - **`doctor`** — compone lo anterior en un único `DoctorReport`. [→ código fuente](src/validate/doctor.ts)
199
+
200
+ La cobertura de recursos se genera a partir de la documentación de objetos de Lemon Squeezy, por lo que la mayoría de los campos recién documentados no necesitan una edición manual:
201
+
202
+ ```bash
203
+ npm run generate:api-types
204
+ npm run check:api-types
205
+ ```
206
+
207
+ ## FAQ
208
+
209
+ ### ¿Cómo verifico si mi webhook de Lemon Squeezy está suscrito a los eventos correctos?
210
+
211
+ Ejecuta `npx fresh-squeezy validate webhook --store-ids <id> --webhook-url <url>`. fresh-squeezy compara los eventos suscritos de tu webhook contra un manifiesto de eventos recomendados de pedidos/suscripciones/reembolsos y reporta `WEBHOOK_EVENTS_MISSING` para las brechas, o `WEBHOOK_NOT_FOUND` si la URL no está registrada en absoluto.
212
+
213
+ ### ¿Cómo detecto una clave de producción de Lemon Squeezy apuntando a una tienda de prueba (staging)?
214
+
215
+ Esa es la verificación `MODE_MISMATCH`. fresh-squeezy compara el modo que declaraste (`--mode` o `LEMON_SQUEEZY_MODE`) contra el `meta.test_mode` real de la clave obtenido de `/v1/users/me`. Cuando no coinciden, `doctor` sale con 1 — así que una clave de producción usada por accidente en un despliegue de staging (o viceversa) falla la verificación antes de llegar a los usuarios.
216
+
217
+ ### ¿Funciona fresh-squeezy en CI?
218
+
219
+ Sí. Ejecuta `npx fresh-squeezy doctor --all-stores --all-resources --json` para un barrido completo legible por máquina. Devuelve [códigos de salida](#inicio-en-30-segundos) estables (`0` correcto, `1` errores de validación, `2` fatal) y cadenas `issue.code` estables sobre las que puedes hacer aserciones. No requiere TTY — sin flags de tienda recurre a una verificación rápida solo de conexión.
220
+
221
+ ### ¿Es fresh-squeezy un reemplazo del SDK oficial de Lemon Squeezy?
222
+
223
+ No. El [SDK oficial](https://github.com/lmsqueezy/lemonsqueezy.js) hace las llamadas a la API; fresh-squeezy es la verificación previa que comprueba que tu configuración es correcta *antes* de que esas llamadas lleguen a producción. Son complementarios — consulta la [tabla comparativa](#fresh-squeezy-frente-a-las-alternativas).
224
+
225
+ ### ¿Qué es la "desviación del registro de cambios" y por qué debería importarme?
226
+
227
+ Lemon Squeezy lanza cambios en la API (nuevos eventos, nuevos campos, nuevos recursos) más rápido de lo que los SDK cliente los adoptan. fresh-squeezy rastrea el [registro de cambios oficial](https://docs.lemonsqueezy.com/api/getting-started/changelog) contra una instantánea versionada mediante una GitHub Action semanal, de modo que los eventos de webhook o campos de respuesta recién recomendados afloran como trabajo accionable en lugar de quedar sin validar en silencio.
228
+
229
+ ### ¿Puedo usar fresh-squeezy como biblioteca en lugar de la CLI?
230
+
231
+ Sí. `import { createFreshSqueezy } from "fresh-squeezy"` y llama a `doctor()` o a cualquier validador individual. Cada validador devuelve un `ValidationResult` tipado y estable sobre el que puedes ramificar — consulta [Biblioteca](#biblioteca).
232
+
233
+ ### ¿Qué recursos de Lemon Squeezy puede validar?
234
+
235
+ Conexión/autenticación, tiendas, productos (y variantes), webhooks, descuentos, claves de licencia y planes de suscripción. Agrega `--all-resources` para descubrir y validar todos los recursos compatibles en la(s) tienda(s) seleccionada(s). Lista completa en la [referencia](#referencia).
236
+
237
+ ## Contribuir
238
+
239
+ Consulta [CONTRIBUTING.md](./CONTRIBUTING.md). Clona, `npm install`, `npm test`. El proyecto busca mantenerse pequeño y aburrido — con enfoque en validación, una sola capa HTTP y un contrato `issue.code` estable.
240
+
241
+ ## Colaboradores
242
+
243
+ <a href="https://github.com/YosefHayim/fresh-squeezy/graphs/contributors">
244
+ <img src="https://contrib.rocks/image?repo=YosefHayim/fresh-squeezy" alt="fresh-squeezy contributors" />
245
+ </a>
246
+
247
+ ## Licencia
248
+
249
+ MIT — consulta [LICENSE](./LICENSE).
package/README.ja.md ADDED
@@ -0,0 +1,249 @@
1
+ <!-- README.md からの翻訳です。英語版が正本です。 -->
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/YosefHayim/fresh-squeezy">
5
+ <img src="assets/fresh-squeezy-hero.png" alt="fresh-squeezy — Lemon Squeezy のセットアップを診断するバリデーター優先のドクター。請求と Webhook の設定ミスをリリース前に検出します。" width="640" />
6
+ </a>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <strong>Lemon Squeezy のセットアップを診断するドクター — 請求と Webhook の設定ミスをリリース前に検出します。</strong>
11
+ </p>
12
+
13
+ <!-- Badges. tests count is static; bump it on major test-suite changes. -->
14
+ <p align="center">
15
+ <a href="https://www.npmjs.com/package/fresh-squeezy"><img src="https://img.shields.io/npm/v/fresh-squeezy?logo=npm&amp;color=cb3837" alt="npm version" /></a>
16
+ <a href="https://www.npmjs.com/package/fresh-squeezy"><img src="https://img.shields.io/npm/dm/fresh-squeezy?logo=npm&amp;color=cb3837" alt="npm downloads per month" /></a>
17
+ <a href="https://github.com/YosefHayim/fresh-squeezy/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/YosefHayim/fresh-squeezy/ci.yml?branch=main&amp;logo=github&amp;label=CI" alt="CI status" /></a>
18
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/fresh-squeezy?color=3fb950" alt="MIT license" /></a>
19
+ <img src="https://img.shields.io/node/v/fresh-squeezy?logo=node.js&amp;logoColor=white&amp;color=339933" alt="Node.js 20 or newer" />
20
+ <img src="https://img.shields.io/npm/types/fresh-squeezy?logo=typescript&amp;logoColor=white" alt="TypeScript types included" />
21
+ <a href="https://packagephobia.com/result?p=fresh-squeezy"><img src="https://packagephobia.com/badge?p=fresh-squeezy" alt="install size" /></a>
22
+ <img src="https://img.shields.io/badge/tests-154%20passing-3fb950?logo=vitest&amp;logoColor=white" alt="154 tests passing" />
23
+ </p>
24
+
25
+ <p align="center">
26
+ <a href="./README.md">English</a> ·
27
+ <a href="./README.zh-CN.md">简体中文</a> ·
28
+ <b>日本語</b> ·
29
+ <a href="./README.es.md">Español</a> ·
30
+ <a href="./README.pt-BR.md">Português</a>
31
+ </p>
32
+
33
+ > 翻訳は最新版に遅れる場合があります。正本は [English README](./README.md) です。
34
+
35
+ <p align="center">
36
+ <a href="#30秒で開始">クイックスタート</a> ·
37
+ <a href="#postman-や公式-sdk-では検出できないものを検出">検出できるもの</a> ·
38
+ <a href="#fresh-squeezy-と代替手段の比較">比較</a> ·
39
+ <a href="#cli">CLI</a> ·
40
+ <a href="#ライブラリ">ライブラリ</a> ·
41
+ <a href="#イシューコード">イシューコード</a> ·
42
+ <a href="#faq">FAQ</a>
43
+ </p>
44
+
45
+ ---
46
+
47
+ **fresh-squeezy** は、[Lemon Squeezy](https://www.lemonsqueezy.com/) の請求連携 — ストア、製品、Webhook、割引、ライセンスキー、サブスクリプションプラン — を検証し、設定ミスをリリース前に検出する CLI および TypeScript ライブラリです。ローカルでも CI でもワンコマンドの `doctor` として実行でき、安定した [終了コード](#30秒で開始) と機械可読な JSON を返します。さらに、公式 SDK がまだ反映していない [Lemon Squeezy API チェンジログ](https://docs.lemonsqueezy.com/api/getting-started/changelog) のドリフトを追跡します。Node 20 以上。
48
+
49
+ ## 30秒で開始
50
+
51
+ ```bash
52
+ npx fresh-squeezy
53
+ ```
54
+
55
+ 初回実行時、`fresh-squeezy` が存在しなければ devDependencies に追加してから、ガイド付きセットアップを開始します。ダッシュボードからコピーするストア ID は不要です — CLI が到達可能なストアを自分で検出します。`package.json` を編集せずにセットアップを実行するには `npx fresh-squeezy --no-install` を使用してください。
56
+
57
+ | 終了コード | 意味 |
58
+ |------|---------|
59
+ | `0` | すべてのバリデーターが合格 |
60
+ | `1` | 1 つ以上のバリデーターが `error` レベルのイシューを報告 |
61
+ | `2` | 致命的エラー(キーの欠落、無効なフラグ、ネットワーク障害) |
62
+ | `130` | ユーザーが対話フローをキャンセル |
63
+
64
+ ## Postman や公式 SDK では検出できないものを検出
65
+
66
+ - **本番キーがステージングを指している。** キーの実際の `meta.test_mode`(API チェンジログ 2024-01-05)が宣言されたモードと一致しない場合に `MODE_MISMATCH` が発火します。doctor は 1 で終了します。SDK も手作りのラッパーも、デフォルトではこれを検出しません。
67
+ - **サイレントなストア所有権の不一致。** `store_id` が実行のスコープに指定したストアと一致しない製品、割引、ライセンスキー、サブスクリプションプラン。安定したコード: `PRODUCT_WRONG_STORE`、`DISCOUNT_STORE_MISMATCH`、`LICENSE_KEY_STORE_MISMATCH`、`PLAN_STORE_MISMATCH`。
68
+ - **間違ったイベントを購読している Webhook。** 推奨イベント(注文/サブスクリプションのライフサイクル、返金)のマニフェストと、SDK が反映していない新しいがオプションのイベントとの差分を取ります。
69
+ - **プラットフォームドリフト。** 週次の GitHub Action が [Lemon Squeezy API チェンジログ](https://docs.lemonsqueezy.com/api/getting-started/changelog) を `src/support/changelog-snapshot.json` に対してハッシュ化し、ドキュメント由来の API 型を更新し、ポリシー判断が必要な場合にフォローアップ作業をオープンします。追跡対象の追加には、`customer_updated`(2026-02-25)、Subscription の `payment_processor`(2025-06-11)、アフィリエイト + `affiliate_activated`(2025-01-21)、注文アイテムの `quantity`(2024-12-06)、チェックアウトのスタイリング / `skip_trial` / `variant_quantities`、サブスクリプションのインボイス返金フィールド、`/v1/users/me` の `test_mode`(2024-01-05)が含まれます。
70
+ - **Postman とダッシュボードの往復。** 1 回の `doctor` 呼び出しが、UI から ID をコピーし、それを env ファイルに貼り付け、1 つずつ手作業で確認するというループを置き換えます。
71
+
72
+ ## fresh-squeezy と代替手段の比較
73
+
74
+ 一般的な Lemon Squeezy のリリース前チェックを、開発者がそうでなければ手に取るであろう各ツール間で比較すると次のようになります:
75
+
76
+ | 機能 | fresh-squeezy | 公式 SDK | Postman | 手作りのラッパー |
77
+ |---|:---:|:---:|:---:|:---:|
78
+ | モード / キーの不一致検出(`MODE_MISMATCH`) | ✅ | ❌ | ❌ | ❌ |
79
+ | ストア所有権のクロスチェック | ✅ | ❌ | ❌ | ⚠️ 手動 |
80
+ | Webhook のイベントカバレッジ差分 | ✅ | ❌ | ⚠️ 手動 | ⚠️ 手動 |
81
+ | 割引 / ライセンスキー / プランの検証 | ✅ | ❌ | ❌ | ⚠️ 手動 |
82
+ | チェンジログドリフトの追跡 | ✅ | ❌ | ❌ | ❌ |
83
+ | 安定した CI 対応の終了コード + JSON | ✅ | ❌ | ❌ | ⚠️ 手動 |
84
+ | ワンコマンドの完全スイープ(`doctor`) | ✅ | ❌ | ❌ | ❌ |
85
+ | 型付き API レスポンス | ✅ | ✅ | ❌ | ⚠️ 場合による |
86
+
87
+ fresh-squeezy は公式 SDK の **代替ではありません** — それと *並行して* 実行するプリフライトチェックです。API 呼び出しには SDK を使い、それらの呼び出しが本番に届く前にセットアップが正しいことを証明するには fresh-squeezy を使ってください。
88
+
89
+ ## CLI
90
+
91
+ ```bash
92
+ # First run: install as a dev dependency, then start guided setup
93
+ npx fresh-squeezy
94
+
95
+ # Guided setup only: reuse env values, pick a store, choose resource checks
96
+ npx fresh-squeezy init
97
+
98
+ # TTY: multi-select stores interactively, run doctor on each
99
+ npx fresh-squeezy doctor
100
+
101
+ # Full sweep across every reachable store and resource
102
+ npx fresh-squeezy doctor --all-stores --all-resources
103
+
104
+ # Machine-readable full sweep for CI
105
+ npx fresh-squeezy doctor --all-stores --all-resources --json
106
+
107
+ # Single validator, scoped to specific stores
108
+ npx fresh-squeezy validate webhook \
109
+ --store-ids 12,34 \
110
+ --webhook-url https://app.example.com/api/webhooks/lemon-squeezy
111
+ ```
112
+
113
+ ストアスコープのすべてのコマンドにおいて、ストアは次の順序で解決されます: 明示的な `--store-ids`、次に `--all-stores`、次に TTY 上での対話的なマルチセレクト、最後にフラグも TTY もない場合の接続のみの実行(CI のスモークチェックとして有用)。`doctor` は接続とストアアクセスに加え、明示的なリソースフラグを検証します。選択したストア内のサポートされるすべてのリソースを検出・検証するには `--all-resources` を追加してください。
114
+
115
+ **→ 完全なコマンド、フラグ、ストア解決のリファレンス: [docs/cli-reference.md](./docs/cli-reference.md)**
116
+
117
+ ## ライブラリ
118
+
119
+ ```ts
120
+ import { createFreshSqueezy } from "fresh-squeezy";
121
+
122
+ const lemon = createFreshSqueezy(); // reads LEMON_SQUEEZY_API_KEY, LEMON_SQUEEZY_MODE
123
+
124
+ const report = await lemon.doctor({
125
+ storeId: 12, // library is single-store per call
126
+ productId: 987,
127
+ webhookUrl: "https://app.example.com/api/webhooks/lemon-squeezy",
128
+ });
129
+
130
+ if (!report.ok) {
131
+ for (const result of report.results) {
132
+ for (const issue of result.issues) {
133
+ console.error(`[${issue.severity}] ${issue.code}: ${issue.message}`);
134
+ }
135
+ }
136
+ process.exit(1);
137
+ }
138
+ ```
139
+
140
+ ライブラリ層でのマルチストア実行には、`doctor()` をループで呼び出してください — CLI はまさにこれを行っています。CI ロジックでは `issue.code` で分岐してください。コードはマイナーバージョン間で安定しています。
141
+
142
+ 公開型: [`FreshSqueezyClient`](src/createFreshSqueezy.ts)、[`ValidationResult<T>`](src/core/types.ts)、[`DoctorReport`](src/core/types.ts)、[`src/resources`](src/resources) 配下のリソース属性インターフェース、[`src/generated/lemonSqueezyApiTypes.ts`](src/generated/lemonSqueezyApiTypes.ts) のドキュメント生成された Lemon Squeezy オブジェクト型、[`src/augmentations.ts`](src/augmentations.ts) のチェンジログ拡張ヘルパー。
143
+
144
+ まだラップされていないエンドポイントには、生のエスケープハッチを使用してください:
145
+
146
+ ```ts
147
+ const user = await lemon.request({ path: "/v1/users/me" });
148
+ ```
149
+
150
+ ## サンドボックス vs ライブ
151
+
152
+ Lemon Squeezy は両方のモードを同じ API ホストから提供します。モードはキーによって決まります。`fresh-squeezy` は、宣言されたモードを `/v1/users/me` の `meta.test_mode` と照合します。不一致 = `MODE_MISMATCH` となり、doctor は 1 で終了します — 本番キーがステージングを指している状況を、被害が出る前に検出する最速の方法です。
153
+
154
+ ```ts
155
+ const lemon = createFreshSqueezy({ mode: "test" });
156
+ const result = await lemon.validateConnection();
157
+ result.mode; // "test" (declared)
158
+ result.resource?.actualMode; // "live" — alarm bell
159
+ ```
160
+
161
+ CLI のデフォルトは `--mode test` です。`--mode live` で上書きできます。ガイド付きセットアップは、ライブモードのキーが検出された場合、続行前に明示的な確認を求めます。CI での夜間プラットフォームドリフトチェックには、`LEMON_SQUEEZY_LIVE_SMOKE=1` とテストモードのキーを設定して `npm run test:live` を実行してください。
162
+
163
+ ## 環境変数
164
+
165
+ | 変数 | 必須 | 目的 |
166
+ |----------|----------|---------|
167
+ | `LEMON_SQUEEZY_API_KEY` | はい | Bearer トークン(ライブラリ + CLI) |
168
+ | `LEMON_SQUEEZY_MODE` | いいえ | `test`(デフォルト)または `live` |
169
+ | `LEMON_SQUEEZY_STORE_ID` | いいえ | `client.doctor()` の便宜的なデフォルト — ライブラリのみ |
170
+
171
+ CLI は `LEMON_SQUEEZY_STORE_ID` を読み取りません。ストア選択がコマンドごとに明示的なままになるよう、`--store-ids` または `--all-stores` を使用してください。
172
+
173
+ ## イシューコード
174
+
175
+ CI では `issue.code` で分岐してください — すべてのコードはマイナーバージョン間で安定しています。最も一般的なもの:
176
+
177
+ | コード | 意味 |
178
+ |------|---------|
179
+ | `AUTH_FAILED` | API キーが無効または欠落 |
180
+ | `MODE_MISMATCH` | 宣言されたモードがキーの `meta.test_mode` と一致しない |
181
+ | `STORE_NOT_FOUND` / `STORE_NOT_OWNED` | ストア ID が無効、または別のアカウントが所有 |
182
+ | `PRODUCT_UNPUBLISHED` / `PRODUCT_WRONG_STORE` / `PRODUCT_NO_BUY_URL` | 製品がチェックアウトを受け付けられない |
183
+ | `WEBHOOK_NOT_FOUND` / `WEBHOOK_EVENTS_MISSING` | Webhook URL が未登録、または購読が不足 |
184
+
185
+ **→ 完全なイシューコードリファレンス(割引、ライセンスキー、プラン、バリアント、ネットワーク)とエスケープハッチの例: [docs/issue-codes.md](./docs/issue-codes.md)**
186
+
187
+ ## リファレンス
188
+
189
+ バリデーター — それぞれが安定した `ValidationResult` を返します:
190
+
191
+ - **`validateConnection`** — 到達可能性、キーの有効性、ストアの存在、宣言モードと実モードの照合。[→ ソース](src/validate/connection.ts)
192
+ - **`validateStore`** — ストア ID が存在し、キーのアカウントが所有していること。[→ ソース](src/validate/store.ts)
193
+ - **`validateProduct`** — 公開済み、期待されるストア上、ライブバリアントと購入 URL がある。[→ ソース](src/validate/product.ts)
194
+ - **`validateWebhook`** — Webhook URL が登録され、推奨イベントを購読している。[→ ソース](src/validate/webhook.ts)
195
+ - **`validateDiscount`** — 有効、期間内、金額が妥当、ストア所有権が一致。[→ ソース](src/validate/discount.ts)
196
+ - **`validateLicenseKey`** — 有効、期限切れでない、アクティベーションに空きがある、ストア所有権が一致。[→ ソース](src/validate/licenseKey.ts)
197
+ - **`validateSubscriptionPlan`** — サブスクリプションタイプ、有効な間隔、ゼロでない価格、一貫したトライアル。[→ ソース](src/validate/subscriptionPlan.ts)
198
+ - **`doctor`** — 上記を 1 つの `DoctorReport` に構成します。[→ ソース](src/validate/doctor.ts)
199
+
200
+ リソースカバレッジは Lemon Squeezy のオブジェクトドキュメントから生成されるため、新たにドキュメント化されたフィールドのほとんどは手動編集を必要としません:
201
+
202
+ ```bash
203
+ npm run generate:api-types
204
+ npm run check:api-types
205
+ ```
206
+
207
+ ## FAQ
208
+
209
+ ### Lemon Squeezy の Webhook が正しいイベントを購読しているかを確認するには?
210
+
211
+ `npx fresh-squeezy validate webhook --store-ids <id> --webhook-url <url>` を実行してください。fresh-squeezy は Webhook の購読イベントを、推奨される注文/サブスクリプション/返金イベントのマニフェストと比較し、不足があれば `WEBHOOK_EVENTS_MISSING` を、URL がまったく登録されていなければ `WEBHOOK_NOT_FOUND` を報告します。
212
+
213
+ ### テスト(ステージング)ストアを指している Lemon Squeezy の本番キーを検出するには?
214
+
215
+ それが `MODE_MISMATCH` チェックです。fresh-squeezy は、あなたが宣言したモード(`--mode` または `LEMON_SQUEEZY_MODE`)を、`/v1/users/me` から取得したキーの実際の `meta.test_mode` と比較します。両者が一致しない場合、`doctor` は 1 で終了します — そのため、ステージングデプロイで誤って使われたライブキー(またはその逆)は、ユーザーに届く前にチェックで失敗します。
216
+
217
+ ### fresh-squeezy は CI で動作しますか?
218
+
219
+ はい。機械可読な完全スイープには `npx fresh-squeezy doctor --all-stores --all-resources --json` を実行してください。安定した [終了コード](#30秒で開始)(`0` 合格、`1` 検証エラー、`2` 致命的)と、アサート可能な安定した `issue.code` 文字列を返します。TTY は不要です — ストアフラグがない場合は接続のみのスモークチェックにフォールバックします。
220
+
221
+ ### fresh-squeezy は公式 Lemon Squeezy SDK の代替ですか?
222
+
223
+ いいえ。[公式 SDK](https://github.com/lmsqueezy/lemonsqueezy.js) は API 呼び出しを行います。fresh-squeezy は、それらの呼び出しが本番に届く *前に* セットアップが正しいことを証明するプリフライトチェックです。両者は補完的です — [比較表](#fresh-squeezy-と代替手段の比較) を参照してください。
224
+
225
+ ### 「チェンジログドリフト」とは何で、なぜ気にすべきですか?
226
+
227
+ Lemon Squeezy は、クライアント SDK が採用するよりも速く API の変更(新しいイベント、新しいフィールド、新しいリソース)をリリースします。fresh-squeezy は週次の GitHub Action を通じて [公式チェンジログ](https://docs.lemonsqueezy.com/api/getting-started/changelog) をコミット済みのスナップショットと照合するため、新たに推奨される Webhook イベントやレスポンスフィールドが、サイレントに未検証のままになるのではなく、対応可能な作業として浮上します。
228
+
229
+ ### CLI の代わりにライブラリとして fresh-squeezy を使えますか?
230
+
231
+ はい。`import { createFreshSqueezy } from "fresh-squeezy"` として、`doctor()` または個々のバリデーターを呼び出してください。すべてのバリデーターは、分岐に使える型付きで安定した `ValidationResult` を返します — [ライブラリ](#ライブラリ) を参照してください。
232
+
233
+ ### どの Lemon Squeezy リソースを検証できますか?
234
+
235
+ 接続/認証、ストア、製品(およびバリアント)、Webhook、割引、ライセンスキー、サブスクリプションプラン。選択したストア内のサポートされるすべてのリソースを検出・検証するには `--all-resources` を追加してください。完全な一覧は [リファレンス](#リファレンス) にあります。
236
+
237
+ ## コントリビューション
238
+
239
+ [CONTRIBUTING.md](./CONTRIBUTING.md) を参照してください。クローンし、`npm install`、`npm test` を実行します。本プロジェクトは小さく退屈であり続けることを目指しています — バリデーター優先、単一の HTTP レイヤー、安定した `issue.code` 契約。
240
+
241
+ ## コントリビューター
242
+
243
+ <a href="https://github.com/YosefHayim/fresh-squeezy/graphs/contributors">
244
+ <img src="https://contrib.rocks/image?repo=YosefHayim/fresh-squeezy" alt="fresh-squeezy contributors" />
245
+ </a>
246
+
247
+ ## ライセンス
248
+
249
+ MIT — [LICENSE](./LICENSE) を参照してください。