diff --git a/src/pages/es/terms.astro b/src/pages/es/terms.astro index 02b71af6..e856ea9f 100644 --- a/src/pages/es/terms.astro +++ b/src/pages/es/terms.astro @@ -2,7 +2,7 @@ import Legal from '../../layouts/NanLegal.astro'; --- - +

NaN está operada por Helmcode S.L. (NIF B44788511), Avenida Quinto Centenario 27, Santiago del Teide, España. Contacto: info@helmcode.com. @@ -57,6 +57,23 @@ import Legal from '../../layouts/NanLegal.astro'; Las instantáneas borradas no se pueden recuperar.

+

+ Paquetes de tokens. Un paquete de tokens es una compra única de tokens extra para un solo modelo; + no es una suscripción y no se renueva. Los tokens comprados son válidos durante 6 meses desde tu última compra para + ese modelo: cada nueva compra para el mismo modelo suma sus tokens y amplía todo el saldo restante de ese modelo a + 6 meses desde esa compra. Los tokens caducados se pierden. Los tokens extra solo se usan cuando has agotado tu + cuota mensual o del periodo para ese modelo; la cuota se sigue renovando con normalidad y nunca consume ni + reinicia el saldo extra. Los tokens extra solo se pueden usar mientras tengas una membresía de inferencia activa + (y el tier premium para los modelos premium). Si tu membresía termina o pierdes el acceso a un modelo premium, el + saldo queda en pausa y la fecha de caducidad sigue corriendo. Los paquetes de tokens no son reembolsables. Según + la normativa de consumo de la UE, el contenido digital está sujeto normalmente a un derecho de desistimiento: los + paquetes de tokens se suministran de inmediato a petición expresa tuya, y aceptas que pierdes tu derecho de + desistimiento una vez suministrados. Un reembolso exigido por ley, o un contracargo o disputa del pago, retira + los tokens abonados por esa compra de tu saldo. Los paquetes de tokens no levantan ningún otro límite: siguen + aplicándose la concurrencia, límites de peticiones y uso razonable. Los precios se muestran antes de la compra e + incluyen impuestos; no se añade IVA en el pago. +

+

Uso aceptable de los workspaces

Este apartado se aplica desde el 6 de octubre de 2026. Los workspaces son máquinas personales para tu propio diff --git a/src/pages/terms.astro b/src/pages/terms.astro index e695dac4..a48bbe80 100644 --- a/src/pages/terms.astro +++ b/src/pages/terms.astro @@ -2,7 +2,7 @@ import Legal from '../layouts/NanLegal.astro'; --- - +

NaN is operated by Helmcode S.L. (NIF B44788511), Avenida Quinto Centenario 27, Santiago del Teide, Spain. Contact: info@helmcode.com. @@ -51,6 +51,22 @@ import Legal from '../layouts/NanLegal.astro'; older kept snapshots are deleted with the next daily backup. Deleted snapshots cannot be recovered.

+

+ Token packs. A token pack is a one-time purchase of extra tokens for a single model; it is not a + subscription and does not renew. Purchased tokens are valid for 6 months from your last purchase for that model: + each new purchase for the same model adds its tokens and extends the whole remaining balance of that model to 6 + months from that purchase. Expired tokens are lost. Extra tokens are only used once your monthly or period + allowance for that model is used up; the allowance keeps resetting as usual and never consumes or resets the extra + balance. Extra tokens are only usable while you have an active inference membership (and the premium tier for + premium models). If your membership ends or you lose access to a premium model, the balance is paused and the + expiry date keeps running. Token packs are non-refundable. Under EU consumer law, digital content is normally + subject to a right of withdrawal: token packs are supplied immediately at your express request, and you + acknowledge that you lose your right of withdrawal once they are supplied. A refund required by law, or a + chargeback or payment dispute, removes the tokens credited by that purchase from your balance. Token packs do not + lift any other limit: concurrency, rate limits and fair use still apply. Prices are shown before purchase and + include taxes; no VAT is added at checkout. +

+

Workspace acceptable use

This section applies from October 6, 2026. Workspaces are personal machines for your own development work. You diff --git a/src/tests/legal/tokenPacksTerms.test.ts b/src/tests/legal/tokenPacksTerms.test.ts new file mode 100644 index 00000000..14e0c5dd --- /dev/null +++ b/src/tests/legal/tokenPacksTerms.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, test } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, resolve } from 'node:path'; + +/** + * Token packs (one-time purchase of extra tokens for one model): the terms are + * the contract the portal copy points at. These tests pin the commitments that + * must never drift: one model per pack, 6-month validity from the last purchase + * of that model (extending the whole remaining balance), consumed only after + * the period allowance, usable only with an active inference membership (and + * premium for premium models), paused otherwise while expiry keeps running, no + * refunds, EU withdrawal waiver on immediate supply, refunds/chargebacks remove + * the credited tokens, other limits still apply, prices with taxes included. + */ +const here = dirname(fileURLToPath(import.meta.url)); +const pages = resolve(here, '../../pages'); +const flat = (p: string) => readFileSync(resolve(pages, p), 'utf-8').replace(/\s+/g, ' '); + +function section(src: string): string { + const m = src.match(/

(.*?)<\/p>/); + expect(m, 'token-packs paragraph present').toBeTruthy(); + return m![1].replace(/<[^>]+>/g, ''); +} + +function sitsUnder(src: string, heading: string) { + const h = src.indexOf(`

${heading}

`); + const next = src.indexOf(' { + const src = flat('terms.astro'); + const p = section(src); + + test('sits under "Membership and payments"', () => sitsUnder(src, 'Membership and payments')); + + test('states every commitment', () => { + expect(p).toContain('one-time purchase of extra tokens for a single model'); + expect(p).toContain('valid for 6 months from your last purchase for that model'); + expect(p).toContain('extends the whole remaining balance of that model'); + expect(p).toContain('only used once your monthly or period allowance for that model is used up'); + expect(p).toContain('the allowance keeps resetting as usual'); + expect(p).toContain('only usable while you have an active inference membership'); + expect(p).toContain('premium tier for premium models'); + expect(p).toContain('paused and the expiry date keeps running'); + expect(p).toContain('Token packs are non-refundable'); + expect(p).toContain('supplied immediately at your express request'); + expect(p).toContain('you lose your right of withdrawal once they are supplied'); + expect(p).toContain('removes the tokens credited by that purchase'); + expect(p).toContain('concurrency, rate limits and fair use'); + expect(p).toContain('Prices are shown before purchase and include taxes; no VAT is added'); + }); +}); + +describe('terms: token packs (ES)', () => { + const src = flat('es/terms.astro'); + const p = section(src); + + test('sits under "Membresía y pagos"', () => sitsUnder(src, 'Membresía y pagos')); + + test('states every commitment', () => { + expect(p).toContain('compra única de tokens extra para un solo modelo'); + expect(p).toContain('válidos durante 6 meses desde tu última compra para ese modelo'); + expect(p).toContain('amplía todo el saldo restante de ese modelo'); + expect(p).toContain('solo se usan cuando has agotado tu cuota mensual o del periodo para ese modelo'); + expect(p).toContain('la cuota se sigue renovando con normalidad'); + expect(p).toContain('solo se pueden usar mientras tengas una membresía de inferencia activa'); + expect(p).toContain('tier premium para los modelos premium'); + expect(p).toContain('queda en pausa y la fecha de caducidad sigue corriendo'); + expect(p).toContain('Los paquetes de tokens no son reembolsables'); + expect(p).toContain('se suministran de inmediato a petición expresa tuya'); + expect(p).toContain('pierdes tu derecho de desistimiento una vez suministrados'); + expect(p).toContain('retira los tokens abonados por esa compra'); + expect(p).toContain('concurrencia, límites de peticiones y uso razonable'); + expect(p).toContain('Los precios se muestran antes de la compra e incluyen impuestos; no se añade IVA'); + }); +}); + +describe('terms: last updated', () => { + test.each(['terms.astro', 'es/terms.astro'])('%s', (f) => { + expect(flat(f)).toContain('updated="October 16, 2026"'); + }); +}); diff --git a/src/tests/legal/workspaceAcceptableUse.test.ts b/src/tests/legal/workspaceAcceptableUse.test.ts index 97478061..caf76512 100644 --- a/src/tests/legal/workspaceAcceptableUse.test.ts +++ b/src/tests/legal/workspaceAcceptableUse.test.ts @@ -79,8 +79,9 @@ describe.each(Object.entries(cases))('terms: workspace acceptable use (%s)', (_l test('marks the date it applies from, and the page date moved with it', () => { expect(s).toContain(c.since); - // Moved again on 2026-10-14 (open signup rewrote the community section). - expect(src).toContain('updated="October 14, 2026"'); + // Moved again on 2026-10-14 (open signup rewrote the community section) + // and on 2026-10-16 (token packs clause). + expect(src).toContain('updated="October 16, 2026"'); }); test.each(c.prohibited)('prohibits: %s', (item) => {