From 6822cb01ead5925857c903618964486e83119125 Mon Sep 17 00:00:00 2001 From: Keysat Date: Sun, 10 May 2026 07:58:44 -0500 Subject: [PATCH] =?UTF-8?q?v0.3.0=20=E2=80=94=20entitlements=20catalog=20i?= =?UTF-8?q?n=20PublicPoliciesResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the Keysat migration 0014 server-side change. The product object on listPublicPolicies() now includes entitlementsCatalog — the closed list of {slug, name, description} the operator declared on the product. SDK consumers' in-app tier pickers can render the human-readable name ("AI summaries") with the description as a tooltip instead of the raw slug ("ai_summaries"). New exports: - EntitlementDef type - PublicPoliciesResponse.product.entitlementsCatalog: EntitlementDef[] Empty array on legacy products that don't have a catalog yet — SDK consumers fall back to rendering the raw policy.entitlements slugs directly. No breaking change to existing consumers. Bumps to 0.3.0 minor since the surface is purely additive. 15/15 crosscheck tests still pass. --- package.json | 2 +- src/index.ts | 1 + src/online.ts | 30 ++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c057de0..3574a0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@keysat/licensing-client", - "version": "0.2.0", + "version": "0.3.0", "description": "Client library for Keysat. Verifies signed license keys offline and wraps the HTTP API for purchase and revocation checks.", "type": "module", "main": "./dist/index.cjs", diff --git a/src/index.ts b/src/index.ts index 19d9a06..99a9a25 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ export { type StartPurchaseOptions, type PublicPolicy, type PublicPoliciesResponse, + type EntitlementDef, type RedeemFreeOptions, type RedeemFreeResponse, } from './online.js' diff --git a/src/online.ts b/src/online.ts index 9efb7d4..764df58 100644 --- a/src/online.ts +++ b/src/online.ts @@ -143,12 +143,35 @@ export interface PublicPolicy { trialDays: number } +/** + * One entry in a product's entitlements catalog. Defined by the + * operator in admin (Keysat migration 0014). Use + * {@link EntitlementDef.name} as the human-readable label when + * rendering an in-app tier picker — e.g. "AI summaries" instead + * of the raw `ai_summaries` slug. {@link EntitlementDef.description} + * is a one-sentence tooltip; may be empty. + */ +export interface EntitlementDef { + slug: string + name: string + description: string +} + export interface PublicPoliciesResponse { product: { slug: string name: string description: string basePriceSats: number + /** + * Closed list of entitlements this product offers, with display + * names + descriptions for buyer-facing rendering. Empty array + * when the operator hasn't defined a catalog (legacy "free-text" + * mode — render the raw slugs from {@link PublicPolicy.entitlements} + * directly, or replace underscores with spaces for a quick + * fallback). + */ + entitlementsCatalog: EntitlementDef[] } policies: PublicPolicy[] } @@ -296,6 +319,13 @@ export class Client { name: product.name as string, description: (product.description as string) ?? '', basePriceSats: product.base_price_sats as number, + entitlementsCatalog: ( + (product.entitlements_catalog as Array>) ?? [] + ).map((c) => ({ + slug: c.slug as string, + name: (c.name as string) ?? (c.slug as string), + description: (c.description as string) ?? '', + })), }, policies: policies.map((p) => ({ slug: p.slug as string,