palbase 0.2.0 → 0.3.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.
Files changed (46) hide show
  1. package/dist/ai/index.js +2 -2
  2. package/dist/backend/engine.js +2 -2
  3. package/dist/backend/env.js +1 -1
  4. package/dist/backend/index.js +3 -3
  5. package/dist/backend/stack.js +1 -1
  6. package/dist/backend/test.js +2 -2
  7. package/dist/chunks/{NIJHTHNF.js → 4A6S7JKW.js} +2 -2
  8. package/dist/chunks/{6OPBXB7Z.js → 4LGRTNOK.js} +2 -2
  9. package/dist/chunks/{JEJ5CFTK.js → 6BUQ7N4I.js} +2 -2
  10. package/dist/chunks/7D5J3M3D.js +87 -0
  11. package/dist/chunks/{ZFPDYRRY.js → A4VJFSSX.js} +2 -2
  12. package/dist/chunks/AR6WQDU5.js +2 -0
  13. package/dist/chunks/{TL4H6V3P.js → BPWQDLXP.js} +1 -1
  14. package/dist/chunks/{HDX6YUAB.js → IQIXNAI4.js} +1 -1
  15. package/dist/chunks/{UTRQWCMD.js → LLBV62FM.js} +2 -2
  16. package/dist/chunks/{K3C2IEDS.js → MJ35SVVY.js} +2 -2
  17. package/dist/chunks/{5W6XJM46.js → NDJAXNM6.js} +2 -2
  18. package/dist/chunks/{ECUYQ73P.js → RK6M2LNY.js} +2 -2
  19. package/dist/chunks/{KRBVYYME.js → UNOLIHKD.js} +1 -1
  20. package/dist/chunks/{7LOMYBLN.js → W2GV6UU3.js} +2 -2
  21. package/dist/chunks/{I3JNX6MZ.js → YQYMP55L.js} +1 -1
  22. package/dist/cli.js +67 -67
  23. package/dist/refuse/ai.js +1 -1
  24. package/dist/refuse/backend.js +1 -1
  25. package/dist/refuse/server.js +1 -1
  26. package/dist/server/index.js +2 -2
  27. package/dist/server/testing.js +2 -2
  28. package/dist/web/index.js +2 -2
  29. package/dist/web/palbe.js +2 -2
  30. package/dist/web/paywall.js +2 -2
  31. package/dist/web/vite.js +2 -2
  32. package/package.json +2 -2
  33. package/types/internal/src/modules/ai.d.ts +811 -0
  34. package/types/internal/src/modules/purchases.d.ts +1601 -294
  35. package/types/internal/src/modules/storage.d.ts +1 -1
  36. package/types/web/src/client.d.ts +6 -0
  37. package/types/web/src/index.d.ts +1 -0
  38. package/types/web/src/paywall/assets.d.ts +51 -0
  39. package/types/web/src/paywall/attributes.d.ts +13 -0
  40. package/types/web/src/paywall/index.d.ts +4 -2
  41. package/types/web/src/paywall/placement.d.ts +21 -7
  42. package/types/web/src/paywall/render.d.ts +56 -17
  43. package/types/web/src/paywall/resolve.d.ts +150 -115
  44. package/types/web/src/purchases.d.ts +23 -4
  45. package/dist/chunks/AN5LCF5K.js +0 -55
  46. package/dist/chunks/HVC2C35F.js +0 -2
@@ -262,7 +262,7 @@ export type StorageObject = {
262
262
  */
263
263
  export type StorageStats = {
264
264
  /**
265
- * Every bucket of the project, by name; an empty one with zeros.
265
+ * Every bucket of the project, by name; an empty one with zeros. A platform module's own bucket is listed with its share too, though the project does not reach it otherwise: _ai holds the pictures its agents' tools returned, deleted with their chat (or once a one-shot answer is answered) — counted in the project's storage as its other files are.
266
266
  */
267
267
  buckets: StorageStatsBucket[];
268
268
  /**
@@ -30,6 +30,12 @@ export interface ClientOptions {
30
30
  * Off unless given; events the app captures (`analytics.capture`) go either way.
31
31
  */
32
32
  analytics?: boolean | AnalyticsOptions;
33
+ /**
34
+ * The app's version, as its users see it ("2.4.1"): said with a paywall's
35
+ * request, for a placement's targeting rules that read it. Nothing is said
36
+ * without one.
37
+ */
38
+ appVersion?: string;
33
39
  }
34
40
  /**
35
41
  * The app's client. A backend's generated Palbe module (palbase apps:sync)
@@ -5,6 +5,7 @@ export { Channel, RealtimeSocket, type PushReply } from './socket.js';
5
5
  export { Analytics, type AnalyticsOptions } from './analytics.js';
6
6
  export { Purchases, type CustomerInfo, type CustomerInfoListener, type MergeGrant, type Offerings } from './purchases.js';
7
7
  export type { Paywall, PaywallRenderOptions } from './paywall/placement.js';
8
+ export type { PaywallAttribute } from './paywall/attributes.js';
8
9
  export type { PaywallPackage, PaywallView } from './paywall/render.js';
9
10
  export { PalbaseError } from '../../internal/src/transport.js';
10
11
  export { BackendError, isBackendError, type BackendErrorKind, type FieldError } from './backend-error.js';
@@ -0,0 +1,51 @@
1
+ /** An asset as the answer lists it (PaywallAssetRef). */
2
+ export interface PaywallAssetRef {
3
+ id: string;
4
+ kind: 'image' | 'video' | 'font' | 'html';
5
+ url: string;
6
+ sha256: string;
7
+ bytes: number;
8
+ }
9
+ /** An asset ready to draw. */
10
+ export interface PreparedAsset {
11
+ kind: PaywallAssetRef['kind'];
12
+ /** Where its checked bytes are: an object URL (or, unchecked, the https address Studio's preview draws from). */
13
+ url: string;
14
+ /** A font's family, registered with the page's fonts. */
15
+ family?: string;
16
+ /** An HTML block's document, every file of its zip inside it. */
17
+ html?: string;
18
+ }
19
+ /** The family a font asset is registered under. */
20
+ export declare const fontFamily: (id: string) => string;
21
+ /** The id an `asset:<id>` names; undefined for anything else. */
22
+ export declare function assetId(src: unknown): string | undefined;
23
+ export interface PrepareOptions {
24
+ fetch?: (input: string, init?: RequestInit) => Promise<Response>;
25
+ signal?: AbortSignal;
26
+ /** Where a font is registered: the page's fonts unless given. */
27
+ fonts?: FontFaceSet;
28
+ }
29
+ /**
30
+ * Downloads and checks every asset; those that pass are ready to draw, by
31
+ * id. Done when the paywall is fetched, before it is shown: what is shown
32
+ * then draws from memory.
33
+ */
34
+ export declare function prepareAssets(refs: readonly PaywallAssetRef[], opts?: PrepareOptions): Promise<Record<string, PreparedAsset>>;
35
+ /**
36
+ * What an asset's bytes are, among the formats its kind takes — the type its
37
+ * object URL is given: an image is PNG, JPEG or WebP; a video MP4, QuickTime
38
+ * or WebM; a font WOFF2, WOFF, TrueType or OpenType; an HTML block a zip.
39
+ * Undefined for anything else: the asset is not drawn.
40
+ */
41
+ export declare function formatOf(kind: PaywallAssetRef['kind'], b: Uint8Array): string | undefined;
42
+ /** The files of a zip, by path: stored and deflated entries (what the server takes). */
43
+ export declare function unzip(bytes: Uint8Array): Promise<Map<string, Uint8Array>>;
44
+ /** The content security of an HTML block: it loads what is inside its document, and nothing from anywhere else. */
45
+ export declare const HTML_BLOCK_CSP = "default-src 'none'; img-src data:; media-src data:; font-src data:; style-src 'unsafe-inline' data:; script-src 'unsafe-inline' data:";
46
+ /**
47
+ * An HTML block's document: its index.html with every file it names — a
48
+ * src, an href, a url() in its styles — written into it, and a policy that
49
+ * lets it load nothing else. Undefined without an index.html.
50
+ */
51
+ export declare function htmlDocument(files: Map<string, Uint8Array>): string | undefined;
@@ -0,0 +1,13 @@
1
+ /** An attribute's value: a text, a number or a yes/no. */
2
+ export type PaywallAttribute = string | number | boolean;
3
+ export declare const MAX_ATTRIBUTES = 20;
4
+ export declare const MAX_ATTRIBUTES_BYTES = 2048;
5
+ export declare const MAX_ATTRIBUTE_TEXT_BYTES = 256;
6
+ /**
7
+ * The attributes as the header carries them; undefined for none. Throws
8
+ * `invalid_attributes` for what the module would refuse: more than 20, a key
9
+ * that is not a letter then letters, digits and `_ . -` (40 at most), a text
10
+ * over 256 bytes, a number that is not finite, a value of another kind, or
11
+ * more than 2 KiB of them together.
12
+ */
13
+ export declare function attributesHeader(attributes: Readonly<Record<string, PaywallAttribute>> | undefined): string | undefined;
@@ -1,5 +1,7 @@
1
- export { PAYWALL_COMPONENTS, PAYWALL_SCHEMA, initialPackage, packagesOf, paywallLanguage, resolve as resolvePaywall, type Appearance, type PackageValues, type PaywallDefinition, type ResolveOptions, type ResolvedComponent, type ResolvedPaywall, type ResolvedTheme, } from './resolve.js';
2
- export { renderPaywall, type PaywallHandlers, type PaywallInput, type PaywallPackage, type PaywallView } from './render.js';
1
+ export { PAYWALL_COMPONENTS, PAYWALL_SCHEMA, countdownValues, packagesOf, resolution as resolvePaywallWithPaths, resolve as resolvePaywall, type Appearance, type PackageValues, type PaywallDefinition, type Platform, type ResolvedNode, type ResolvedPaywall, type ResolvedStyle, type Resolution, type ResolveOptions, } from './resolve.js';
2
+ export { renderPaywall, type PaywallHandlers, type PaywallInput, type PaywallPackage, type PaywallState, type PaywallView } from './render.js';
3
+ export { assetId, fontFamily, htmlDocument, prepareAssets, unzip, type PaywallAssetRef, type PreparedAsset } from './assets.js';
4
+ export { attributesHeader, type PaywallAttribute } from './attributes.js';
3
5
  export { formatPeriod, formatPrice, packageValues, parseDuration, type PricedPackage } from './prices.js';
4
6
  export { ICONS as PAYWALL_ICONS } from './icons.js';
5
7
  export { Paywall, defaultPaywall, type PaywallRenderOptions } from './placement.js';
@@ -1,4 +1,6 @@
1
1
  import type { purchases as purchasesModule } from '../../../internal/src/modules/index.js';
2
+ import { type PreparedAsset } from './assets.js';
3
+ import { type PaywallAttribute } from './attributes.js';
2
4
  import { type PricedPackage } from './prices.js';
3
5
  import { type PaywallHandlers, type PaywallPackage, type PaywallView } from './render.js';
4
6
  import { type Appearance, type PackageValues, type PaywallDefinition } from './resolve.js';
@@ -13,7 +15,7 @@ export interface PaywallRenderOptions {
13
15
  appearance?: Appearance;
14
16
  /** The browser's language unless given. */
15
17
  locale?: string;
16
- /** The app's terms and privacy policy (https), for the definition's `terms` and `privacy` links. */
18
+ /** The app's terms and privacy policy (https), for the definition's `terms` and `privacy` buttons. */
17
19
  links?: {
18
20
  terms?: string;
19
21
  privacy?: string;
@@ -43,17 +45,20 @@ export declare class Paywall {
43
45
  /** The server's answer now, the copy kept from before when it could not be asked, or the SDK's own from the catalog (nothing published there). */
44
46
  readonly source: 'server' | 'cache' | 'default';
45
47
  readonly definition: PaywallDefinition;
48
+ /** The paywall's assets, downloaded and checked: those that passed, by id. */
49
+ readonly assets: Record<string, PreparedAsset>;
46
50
  /** What the paywall sells on the web, priced as the catalog prices it. */
47
51
  readonly offerings: Offerings;
48
- /** The paywall and the version shown, and the experiment's variant; absent for the SDK's own. */
52
+ /** The paywall and the version shown, the experiment's variant or the placement's rule that chose it; absent for the SDK's own. */
49
53
  readonly shown: {
50
54
  paywallId: string;
51
55
  version: number;
52
56
  variant?: string;
57
+ ruleId?: string;
53
58
  } | undefined;
54
59
  private deps;
55
60
  private exposed;
56
- constructor(placement: string, source: Paywall['source'], definition: PaywallDefinition, offerings: Offerings, shown: Paywall['shown'], deps: PaywallDeps);
61
+ constructor(placement: string, source: Paywall['source'], definition: PaywallDefinition, offerings: Offerings, shown: Paywall['shown'], deps: PaywallDeps, assets?: Record<string, PreparedAsset>);
57
62
  /** The store's values of each package the paywall sells, in a language: what its texts' variables read. */
58
63
  packages(locale: string): Record<string, PackageValues>;
59
64
  /**
@@ -68,9 +73,9 @@ export declare class Paywall {
68
73
  export declare function webPackages(offerings: Offerings, keys: readonly string[], locale: string): PricedPackage[];
69
74
  /**
70
75
  * The SDK's own paywall, where nothing is published: every plan the web
71
- * sells (the first six), the purchase button with the selected one's price,
72
- * and the legal links — plain, in the system's colors. Null when the web
73
- * sells nothing.
76
+ * sells (the first six) as a card — its product, period and price —, the
77
+ * purchase button and the legal links; plain, in the system's colors. Null
78
+ * when the web sells nothing.
74
79
  */
75
80
  export declare function defaultPaywall(offerings: Offerings): PaywallDefinition | null;
76
81
  /** This browser's installation id: who a paywall is shown to before anyone signs in — the same experiment variant every time. */
@@ -81,5 +86,14 @@ export declare function loadPaywall(api: Api, ref: string, placement: string, ch
81
86
  plan: string;
82
87
  successUrl: string;
83
88
  cancelUrl: string;
84
- }) => Promise<string>, signal?: AbortSignal): Promise<Paywall | null>;
89
+ }) => Promise<string>, ask?: {
90
+ signal?: AbortSignal;
91
+ fetch?: (input: string, init?: RequestInit) => Promise<Response>;
92
+ /** What the app says of the person, for the placement's targeting rules. */
93
+ attributes?: Readonly<Record<string, PaywallAttribute>>;
94
+ /** The language the app shows, when it is not the browser's. */
95
+ locale?: string;
96
+ /** The app's version, when the client was given one. */
97
+ appVersion?: string;
98
+ }): Promise<Paywall | null>;
85
99
  export {};
@@ -1,31 +1,58 @@
1
- import { type Appearance, type PackageValues, type PaywallDefinition } from './resolve.js';
2
- /** What a paywall is drawn from: its definition, and the moment it is drawn in. */
1
+ import { type PreparedAsset } from './assets.js';
2
+ import { type PaywallDefinition, type Platform, type Appearance, type PackageValues } from './resolve.js';
3
+ /** A package of the catalog: what the purchase button buys. */
4
+ export interface PaywallPackage {
5
+ product: string;
6
+ plan: string;
7
+ }
8
+ /** What a paywall is drawn from. */
3
9
  export interface PaywallInput {
4
10
  definition: PaywallDefinition;
5
11
  /** The reader's language (`tr-TR`). */
6
12
  locale: string;
7
13
  appearance: Appearance;
14
+ /** Where it is drawn: the web, unless a preview draws another platform's. */
15
+ platform?: Platform;
8
16
  /** The store's values of each package, by `<product>.<plan>`; a package without any is drawn, not sold. */
9
17
  packages: Record<string, PackageValues>;
10
- /** The app's own addresses of the definition's `terms` and `privacy` links (https); such a link is not drawn without one. */
18
+ /** The packages whose introductory offer the customer can still take. */
19
+ eligible?: readonly string[];
20
+ /** The app's own addresses of `terms` and `privacy` (https); a button or link to one is not drawn without it. */
11
21
  links?: {
12
22
  terms?: string;
13
23
  privacy?: string;
14
24
  };
25
+ /** The definition's assets ready to draw, by id (prepareAssets): one missing is drawn without. */
26
+ assets?: Record<string, PreparedAsset>;
27
+ /** The state to draw: a preview sets it; an app leaves it to the person. */
28
+ state?: PaywallState;
29
+ /** Entrances as components appear (true); never when the system asks for less motion. */
30
+ animate?: boolean;
31
+ /** Draws as if the system asked for less motion (a preview's choice); the system's own otherwise. */
32
+ reduceMotion?: boolean;
15
33
  }
16
- /** A package of the catalog: what the purchase button buys. */
17
- export interface PaywallPackage {
18
- product: string;
19
- plan: string;
34
+ /** What the person has done to the paywall, and its clock. */
35
+ export interface PaywallState {
36
+ /** The package the person selected. */
37
+ selected?: string;
38
+ /** Each tabs component's tab, and each switch's side, by the component's path. */
39
+ tabs?: Record<string, string>;
40
+ switches?: Record<string, boolean>;
41
+ /** The sheet open, by its id. */
42
+ sheet?: string | null;
43
+ /** When the paywall opened (ms since the epoch): a countdown from its opening counts from here. */
44
+ openedAt?: number;
45
+ /** A moment to draw, held still (ms since the epoch); the clock runs when absent. */
46
+ now?: number;
20
47
  }
21
48
  export interface PaywallHandlers {
22
- /** The purchase button, for the package selected; the button waits while a promise it returns runs. */
49
+ /** The purchase button, for its package (the one selected, unless it names one); the button waits while a promise it returns runs. */
23
50
  onPurchase(pkg: PaywallPackage): void | Promise<void>;
24
- /** The restore button; without one the paywall draws none (the web restores nothing: Stripe's purchases are the account's). */
51
+ /** A restore button; without this one is not drawn (the web restores nothing: Stripe's purchases are the account's). */
25
52
  onRestore?(): void | Promise<void>;
26
- /** The close button; without one the paywall draws none. */
53
+ /** A close button; without this one is not drawn (a close inside a sheet closes the sheet). */
27
54
  onClose?(): void;
28
- /** A link the person opened; without one, the browser opens it in a new tab. */
55
+ /** A link the person opened; without this the browser opens it in a new tab. */
29
56
  onLink?(url: string): void;
30
57
  /** Told when the person picks another package. */
31
58
  onSelect?(pkg: PaywallPackage): void;
@@ -35,20 +62,32 @@ export interface PaywallHandlers {
35
62
  close?: string;
36
63
  restore?: string;
37
64
  };
65
+ /** An offer code button: the web has none to redeem, so without this one is not drawn. */
66
+ onOfferCode?(): void | Promise<void>;
67
+ /** Told whenever the state changes: a preview keeps its controls with it. */
68
+ onState?(state: PaywallState): void;
69
+ /** A designer's canvas: a click picks the component under it (its definition path) instead of acting. */
70
+ editor?: {
71
+ onPick(path: string): void;
72
+ };
38
73
  }
39
74
  export interface PaywallView {
40
75
  /** The package selected now. */
41
76
  readonly selected: PaywallPackage | null;
42
77
  /** Selects a package (`<product>.<plan>`) as the person would. */
43
78
  select(key: string): void;
44
- /** Draws it again from what changed: a new definition, the other appearance, another language, new prices. */
45
- update(input: Partial<PaywallInput>): void;
46
79
  /** Removes it from the page. */
47
80
  destroy(): void;
81
+ /** Draws it again from what changed: a new definition, the other appearance, another language, new prices or assets, a state to show. */
82
+ update(input: Partial<PaywallInput>): void;
83
+ /** The state drawn now. */
84
+ readonly state: PaywallState;
85
+ /** Marks a component (by path) as a designer's canvas does; null clears it. */
86
+ highlight(path: string | null): void;
87
+ /** Plays every entrance again. */
88
+ replay(): void;
48
89
  }
49
- /** An https address, with a host and no credentials: the only images and links a paywall shows. */
50
- export declare function isHttps(s: unknown): s is string;
51
- /** Black or white, whichever reads on a color: a badge's text. */
52
- export declare function readableOn(hex: string): string;
53
90
  /** Draws a paywall into a container (its content is replaced). */
54
91
  export declare function renderPaywall(container: HTMLElement, input: PaywallInput, handlers: PaywallHandlers): PaywallView;
92
+ /** The paywall's styles in its shadow root: a constructed sheet where the browser has them, a style element elsewhere. */
93
+ export declare function adoptStyle(doc: Document, shadow: ShadowRoot, css: string): void;
@@ -1,7 +1,6 @@
1
1
  import type { purchases } from '../../../internal/src/modules/index.js';
2
2
  export type PaywallDefinition = purchases.PaywallDefinition;
3
- /** The newest schema of definition this renderer draws: what the SDK asks the server for (X-Palbase-Paywall-Schema). */
4
- export declare const PAYWALL_SCHEMA = 1;
3
+ export type Platform = 'ios' | 'android' | 'web';
5
4
  export type Appearance = 'light' | 'dark';
6
5
  /** What the store gave a package, as the variables of its texts: `{{price}}` … */
7
6
  export interface PackageValues {
@@ -12,138 +11,174 @@ export interface PackageValues {
12
11
  savings?: string;
13
12
  product_name?: string;
14
13
  }
14
+ /** The schema this renderer draws: what the SDK asks the server for (X-Palbase-Paywall-Schema). */
15
+ export declare const PAYWALL_SCHEMA = 2;
15
16
  export interface ResolveOptions {
16
- /** The app's language (`tr-TR`): the definition's own, else its language without the region, else its default. */
17
+ /** The app's language (`tr-TR`). */
17
18
  locale: string;
18
19
  appearance: Appearance;
20
+ platform: Platform;
19
21
  /** The store's values of each package, by `<product>.<plan>`. */
20
22
  packages: Record<string, PackageValues>;
21
- /**
22
- * The package selected now (`<product>.<plan>`), once the person picked
23
- * one; the one the definition marks, else the first, when absent or not
24
- * one of its packages.
25
- */
23
+ /** The packages whose introductory offer (a trial) the customer can still take. */
24
+ eligible?: readonly string[];
25
+ /** The package the customer selected; absent, the paywall's own selection. */
26
26
  selected?: string;
27
+ /** The tab shown in every tabs component, and each switch's side — the paywall's defaults when absent. */
28
+ tab?: string;
29
+ switch?: 'on' | 'off';
30
+ /** One tabs component's tab, or one switch's side, by the component's path (`root.children[3]`): what the person chose. */
31
+ tabs?: Record<string, string>;
32
+ switches?: Record<string, boolean>;
33
+ /** A countdown's time left: how long ago the paywall opened, and the moment it is drawn (ms since the epoch). */
34
+ openedSecondsAgo?: number;
35
+ now?: number;
27
36
  }
28
- export interface ResolvedTheme {
29
- background: string;
30
- surface: string;
31
- text: string;
32
- muted: string;
33
- accent: string;
34
- on_accent: string;
35
- badge: string;
36
- radius: number;
37
- font: 'system' | 'rounded' | 'serif';
38
- }
39
- type Base = {
37
+ /** A component resolved: its type, its fields with every token and default resolved. */
38
+ export type ResolvedNode = {
39
+ type: string;
40
40
  id?: string;
41
+ style?: ResolvedStyle;
42
+ animation?: ResolvedAnimation;
43
+ [field: string]: unknown;
41
44
  };
42
- export type Align = 'start' | 'center' | 'end' | 'stretch';
43
- export type ResolvedStack = Base & {
44
- type: 'stack';
45
- axis: 'vertical' | 'horizontal' | 'z';
46
- spacing: number;
47
- align: Align;
48
- padding: number;
49
- corner: number;
50
- background?: string;
51
- children: ResolvedComponent[];
52
- };
53
- export type TextStyle = 'large_title' | 'title' | 'headline' | 'body' | 'callout' | 'caption' | 'footnote';
54
- export type ResolvedText = Base & {
55
- type: 'text';
56
- text: string;
57
- style: TextStyle;
45
+ export interface ResolvedEdges {
46
+ top: number;
47
+ bottom: number;
48
+ leading: number;
49
+ trailing: number;
50
+ }
51
+ export interface ResolvedCorners {
52
+ top_leading: number;
53
+ top_trailing: number;
54
+ bottom_leading: number;
55
+ bottom_trailing: number;
56
+ }
57
+ export type ResolvedStop = {
58
58
  color: string;
59
- align: 'start' | 'center' | 'end';
60
- weight?: 'regular' | 'medium' | 'semibold' | 'bold';
59
+ at: number;
61
60
  };
62
- export type ResolvedImage = Base & {
61
+ export type ResolvedFill = {
62
+ type: 'color';
63
+ color: string;
64
+ } | {
65
+ type: 'linear';
66
+ angle: number;
67
+ stops: ResolvedStop[];
68
+ } | {
69
+ type: 'radial';
70
+ center_x: number;
71
+ center_y: number;
72
+ radius: number;
73
+ stops: ResolvedStop[];
74
+ } | {
63
75
  type: 'image';
64
76
  src: string;
65
77
  fit: 'fit' | 'fill';
66
- corner: number;
67
- aspect?: number;
68
- height?: number;
69
- alt?: string;
78
+ } | {
79
+ type: 'video';
80
+ src: string;
81
+ poster?: string;
82
+ loop: boolean;
70
83
  };
71
- export type ResolvedIcon = Base & {
72
- type: 'icon';
73
- name: string;
74
- color: string;
84
+ export interface ResolvedStyle {
85
+ padding?: ResolvedEdges;
86
+ margin?: ResolvedEdges;
87
+ width?: number | string;
88
+ height?: number | string;
89
+ max_width?: number;
90
+ background?: ResolvedFill;
91
+ border?: {
92
+ width: number;
93
+ color: string;
94
+ };
95
+ corners?: ResolvedCorners;
96
+ shadow?: {
97
+ color: string;
98
+ radius: number;
99
+ x: number;
100
+ y: number;
101
+ };
102
+ opacity?: number;
103
+ }
104
+ export interface ResolvedAnimation {
105
+ type: 'fade' | 'slide_up' | 'slide_down' | 'slide_leading' | 'slide_trailing' | 'scale';
106
+ duration_ms: number;
107
+ delay_ms: number;
108
+ easing: 'ease_out' | 'ease_in_out' | 'spring';
109
+ }
110
+ export interface ResolvedTypeStyle {
111
+ font: string;
75
112
  size: number;
76
- };
77
- export type ResolvedFeature = {
78
- icon: string;
79
- text: string;
80
- };
81
- export type ResolvedFeatures = Base & {
82
- type: 'features';
83
- items: ResolvedFeature[];
84
- icon_color: string;
85
- color: string;
86
- spacing: number;
87
- };
88
- export type ResolvedPackage = {
89
- product: string;
90
- plan: string;
91
- selected: boolean;
92
- title?: string;
93
- detail?: string;
94
- badge?: string;
95
- };
96
- export type ResolvedPackages = Base & {
97
- type: 'packages';
98
- layout: 'list' | 'cards' | 'segmented';
99
- items: ResolvedPackage[];
100
- };
101
- export type ResolvedPurchaseButton = Base & {
102
- type: 'purchase_button';
103
- text: string;
104
- sub_text?: string;
105
- };
106
- export type ResolvedRestoreButton = Base & {
107
- type: 'restore_button';
108
- text?: string;
109
- };
110
- export type ResolvedLink = Base & {
111
- type: 'link';
112
- text: string;
113
- url: string;
114
- };
115
- export type ResolvedCloseButton = Base & {
116
- type: 'close_button';
117
- color: string;
118
- };
119
- export type ResolvedSpacer = Base & {
120
- type: 'spacer';
121
- size?: number;
122
- };
123
- export type ResolvedDivider = Base & {
124
- type: 'divider';
125
- color: string;
126
- };
127
- export type ResolvedComponent = ResolvedStack | ResolvedText | ResolvedImage | ResolvedIcon | ResolvedFeatures | ResolvedPackages | ResolvedPurchaseButton | ResolvedRestoreButton | ResolvedLink | ResolvedCloseButton | ResolvedSpacer | ResolvedDivider;
128
- /** The definition as drawn: the palette of the appearance and the tree, nothing left to look up. */
113
+ weight: number;
114
+ line_height?: number;
115
+ letter_spacing: number;
116
+ text_style: string;
117
+ }
118
+ /** The definition as drawn, the contract's resolved tree. */
129
119
  export interface ResolvedPaywall {
130
- theme: ResolvedTheme;
131
- root: ResolvedComponent;
120
+ selected: string;
121
+ theme: {
122
+ colors: Record<string, string>;
123
+ typography: Record<string, ResolvedTypeStyle>;
124
+ radii: Record<string, number>;
125
+ spacing: Record<string, number>;
126
+ };
127
+ header?: ResolvedNode;
128
+ root?: ResolvedNode;
129
+ footer?: ResolvedNode;
130
+ sheets?: Record<string, ResolvedNode>;
131
+ }
132
+ /** Beside the tree: where in the definition each node is (its path, as the server's problems name it), and what is not part of the tree. */
133
+ export interface Resolution {
134
+ tree: ResolvedPaywall;
135
+ /** A node's path in the definition: `root.children[2]`, `sheets.offer.root`. */
136
+ pathOf(node: object): string | undefined;
137
+ /** The tab shown in each tabs component and each switch's side, by path. */
138
+ tabs: Record<string, string>;
139
+ switches: Record<string, boolean>;
140
+ /** Each sheet's title, in the language drawn. */
141
+ sheetTitles: Record<string, string>;
142
+ /** The time a counting countdown has left, by path: the renderer ticks while any does. */
143
+ countdowns: Record<string, number>;
144
+ /** The language the definition is drawn in. */
145
+ language: string;
132
146
  }
133
- /** Each component of the schema, by type: what a definition may hold and this renderer draws. */
147
+ type Value = 'plain' | 'color' | 'textColor' | 'spacing' | 'radius';
148
+ type Field = {
149
+ kind: 'value';
150
+ value: Value;
151
+ def?: unknown;
152
+ required?: boolean;
153
+ } | {
154
+ kind: 'text';
155
+ required?: boolean;
156
+ } | {
157
+ kind: 'list';
158
+ item: string;
159
+ required?: boolean;
160
+ } | {
161
+ kind: 'object';
162
+ item: string;
163
+ required?: boolean;
164
+ } | {
165
+ kind: 'component';
166
+ required?: boolean;
167
+ } | {
168
+ kind: 'components';
169
+ } | {
170
+ kind: 'edges' | 'corners' | 'fill';
171
+ };
172
+ type Spec = Record<string, Field>;
173
+ export declare const COMPONENT_FIELDS: Record<string, Spec>;
174
+ /** The components a definition has, by type. */
134
175
  export declare const PAYWALL_COMPONENTS: readonly string[];
135
- /** The package a definition selects at first: the one it marks, else the first of its packages component. */
136
- export declare function initialPackage(root: unknown): string;
137
- /** Every package a definition sells, `<product>.<plan>`, in its order. */
138
- export declare function packagesOf(root: unknown): string[];
139
- /** The language a definition is drawn in for an app's: its own, else without the region, else the default. */
140
- export declare function paywallLanguage(definition: PaywallDefinition, locale: string): string;
176
+ /** {{countdown}} and its parts for a time left, in seconds. */
177
+ export declare function countdownValues(left: number): Record<string, string>;
178
+ /** Every package a definition sells, `<product>.<plan>`, in the order it names them: the header, the root, the footer, then its sheets. */
179
+ export declare function packagesOf(definition: PaywallDefinition): string[];
141
180
  /** A definition as drawn (contracts/paywall/README.md). */
142
181
  export declare function resolve(definition: PaywallDefinition, opts: ResolveOptions): ResolvedPaywall;
143
- /**
144
- * The same, with a component that is not drawn left in its place as null:
145
- * two resolutions of one definition line up child by child, so the renderer
146
- * changes only what a new selection changed.
147
- */
148
- export declare function resolveAligned(definition: PaywallDefinition, opts: ResolveOptions): ResolvedPaywall;
182
+ /** The same, with each node's path in the definition and the state the renderer keeps. */
183
+ export declare function resolution(definition: PaywallDefinition, opts: ResolveOptions): Resolution;
149
184
  export {};
@@ -1,7 +1,8 @@
1
1
  import { purchases as purchasesModule } from '../../internal/src/modules/index.js';
2
- import type { Transport } from '../../internal/src/transport.js';
2
+ import type { Fetch, Transport } from '../../internal/src/transport.js';
3
3
  import type { SessionManager } from './session.js';
4
4
  import type { RealtimeSocket } from './socket.js';
5
+ import type { PaywallAttribute } from './paywall/attributes.js';
5
6
  import { type Paywall } from './paywall/placement.js';
6
7
  type P = typeof purchasesModule;
7
8
  export type CustomerInfo = purchasesModule.CustomerInfo;
@@ -15,26 +16,44 @@ export declare class Purchases {
15
16
  private session;
16
17
  private socket;
17
18
  private ref;
19
+ /** What a paywall's assets are downloaded with: the app's fetch, when it gave one. */
20
+ private fetch;
21
+ /** The app's version, when it gave one: a paywall's request says it. */
22
+ private appVersion;
18
23
  private listeners;
19
24
  private watch;
20
25
  private following;
21
26
  /** What listeners were last told: undefined until the first read (or sign-out) is known. */
22
27
  private last;
23
- constructor(transport: Transport, session: SessionManager, socket: RealtimeSocket, ref: string);
28
+ constructor(transport: Transport, session: SessionManager, socket: RealtimeSocket, ref: string, fetch?: Fetch, appVersion?: string);
24
29
  /** Everything the signed-in customer has, read now (the first read makes the user a customer). */
25
30
  me(): Promise<CustomerInfo>;
26
31
  /** The paywall's catalog: each product's text and price on a channel — the web's unless another is named. */
27
32
  offerings(channel?: 'ios' | 'android' | 'web'): Promise<Offerings>;
28
33
  /**
29
34
  * The paywall the project shows at a placement — the place in the app it
30
- * names (`onboarding`, `settings`) — to draw with render(). Its version
31
- * is the newest published in a schema this SDK draws (an experiment's
35
+ * names (`onboarding`, `settings`) — to draw with render(), its assets
36
+ * downloaded and checked first. Its version is the newest published in a
37
+ * schema this SDK draws (an experiment's
32
38
  * variant while one runs there, the same for this person every time); the
33
39
  * browser keeps it, to ask again with its ETag and to show offline. With
34
40
  * nothing published there it is the SDK's own, of every plan the web
35
41
  * sells; null when the web sells nothing.
42
+ *
43
+ * Which paywall a placement shows may depend on its targeting rules: they
44
+ * read what the request says of the app (the web, the SDK, the version the
45
+ * client was made with, where it is asked from), its language — the
46
+ * browser's, or `locale` when the app shows another — and `attributes`,
47
+ * what the app says of the person
48
+ * (`{ plan: 'free', sessions: 12 }`: texts, numbers, yes/no). An attribute
49
+ * the module would refuse throws `invalid_attributes` before anything is
50
+ * asked. Targeting picks what to show; it is not access control: the
51
+ * country, the attributes and the versions are what the app says of
52
+ * itself, so no price or region entitlement may hang on them.
36
53
  */
37
54
  paywall(placement: string, opts?: {
55
+ attributes?: Readonly<Record<string, PaywallAttribute>>;
56
+ locale?: string;
38
57
  signal?: AbortSignal;
39
58
  }): Promise<Paywall | null>;
40
59
  /**