palbase 0.1.0 → 0.2.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 (45) 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/{QXUMLO7O.js → 5W6XJM46.js} +2 -2
  8. package/dist/chunks/{JAWWIVZH.js → 6OPBXB7Z.js} +2 -2
  9. package/dist/chunks/{3OGEBGYZ.js → 7LOMYBLN.js} +2 -2
  10. package/dist/chunks/AN5LCF5K.js +55 -0
  11. package/dist/chunks/ECUYQ73P.js +2 -0
  12. package/dist/chunks/{DAOLIUNZ.js → HDX6YUAB.js} +1 -1
  13. package/dist/chunks/HVC2C35F.js +2 -0
  14. package/dist/chunks/{LYEFPLJZ.js → I3JNX6MZ.js} +1 -1
  15. package/dist/chunks/JEJ5CFTK.js +2 -0
  16. package/dist/chunks/{E5Q4VTW4.js → K3C2IEDS.js} +2 -2
  17. package/dist/chunks/{6FWCNTAM.js → KRBVYYME.js} +1 -1
  18. package/dist/chunks/{3VASGTIN.js → NIJHTHNF.js} +2 -2
  19. package/dist/chunks/{45J7YXRB.js → TL4H6V3P.js} +1 -1
  20. package/dist/chunks/{UAY56IQR.js → UTRQWCMD.js} +2 -2
  21. package/dist/chunks/ZFPDYRRY.js +2 -0
  22. package/dist/cli.js +72 -72
  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 -0
  31. package/dist/web/vite.js +2 -2
  32. package/package.json +6 -2
  33. package/types/internal/src/modules/events.d.ts +2 -2
  34. package/types/internal/src/modules/purchases.d.ts +1213 -44
  35. package/types/web/src/index.d.ts +2 -0
  36. package/types/web/src/paywall/icons.d.ts +5 -0
  37. package/types/web/src/paywall/index.d.ts +5 -0
  38. package/types/web/src/paywall/placement.d.ts +85 -0
  39. package/types/web/src/paywall/prices.d.ts +40 -0
  40. package/types/web/src/paywall/render.d.ts +54 -0
  41. package/types/web/src/paywall/resolve.d.ts +149 -0
  42. package/types/web/src/purchases.d.ts +13 -0
  43. package/dist/chunks/3XT4L2XV.js +0 -2
  44. package/dist/chunks/HKJU2FKE.js +0 -2
  45. package/dist/chunks/IKVOXHEE.js +0 -2
@@ -4,6 +4,8 @@ export { localStore, memoryStore, SessionChangedError, type AuthEvent, type Sess
4
4
  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
+ export type { Paywall, PaywallRenderOptions } from './paywall/placement.js';
8
+ export type { PaywallPackage, PaywallView } from './paywall/render.js';
7
9
  export { PalbaseError } from '../../internal/src/transport.js';
8
10
  export { BackendError, isBackendError, type BackendErrorKind, type FieldError } from './backend-error.js';
9
11
  export type { BackendBase, CallOptions, UploadOptions, UploadProgress } from './backends.js';
@@ -0,0 +1,5 @@
1
+ export declare const ICONS: Readonly<Record<string, readonly string[]>>;
2
+ /** The close button's mark: not one of the schema's icons. */
3
+ export declare const CLOSE: string[];
4
+ /** An icon as an inline SVG, sized in CSS pixels and colored by its text color; hidden from assistive technology. */
5
+ export declare function icon(doc: Document, paths: readonly string[], size: number): SVGSVGElement;
@@ -0,0 +1,5 @@
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';
3
+ export { formatPeriod, formatPrice, packageValues, parseDuration, type PricedPackage } from './prices.js';
4
+ export { ICONS as PAYWALL_ICONS } from './icons.js';
5
+ export { Paywall, defaultPaywall, type PaywallRenderOptions } from './placement.js';
@@ -0,0 +1,85 @@
1
+ import type { purchases as purchasesModule } from '../../../internal/src/modules/index.js';
2
+ import { type PricedPackage } from './prices.js';
3
+ import { type PaywallHandlers, type PaywallPackage, type PaywallView } from './render.js';
4
+ import { type Appearance, type PackageValues, type PaywallDefinition } from './resolve.js';
5
+ type Offerings = purchasesModule.Offerings;
6
+ type Api = ReturnType<typeof purchasesModule.client>;
7
+ export interface PaywallRenderOptions {
8
+ /** Stripe sends the customer back here after buying (one of the project's registered apps). */
9
+ successUrl: string;
10
+ /** … and here when they turn back. */
11
+ cancelUrl: string;
12
+ /** The system's, and kept with it as it changes, unless given. */
13
+ appearance?: Appearance;
14
+ /** The browser's language unless given. */
15
+ locale?: string;
16
+ /** The app's terms and privacy policy (https), for the definition's `terms` and `privacy` links. */
17
+ links?: {
18
+ terms?: string;
19
+ privacy?: string;
20
+ };
21
+ /** The close button; without one the paywall draws none. */
22
+ onClose?(): void;
23
+ /** A link the person opened; without one, the browser opens it in a new tab. */
24
+ onLink?(url: string): void;
25
+ /** Stripe Checkout's page for the package bought: the page goes there unless the app opens it itself. */
26
+ onCheckout?(url: string, pkg: PaywallPackage): void;
27
+ /** A purchase that could not start (no one signed in, a guest, the network). Without one it is thrown. */
28
+ onError?(error: unknown, pkg: PaywallPackage): void;
29
+ labels?: PaywallHandlers['labels'];
30
+ }
31
+ interface PaywallDeps {
32
+ checkout(opts: {
33
+ product: string;
34
+ plan: string;
35
+ successUrl: string;
36
+ cancelUrl: string;
37
+ }): Promise<string>;
38
+ expose(paywall: Paywall): Promise<void>;
39
+ }
40
+ /** What a placement shows: the paywall, where it came from, and what it sells. */
41
+ export declare class Paywall {
42
+ readonly placement: string;
43
+ /** 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
+ readonly source: 'server' | 'cache' | 'default';
45
+ readonly definition: PaywallDefinition;
46
+ /** What the paywall sells on the web, priced as the catalog prices it. */
47
+ readonly offerings: Offerings;
48
+ /** The paywall and the version shown, and the experiment's variant; absent for the SDK's own. */
49
+ readonly shown: {
50
+ paywallId: string;
51
+ version: number;
52
+ variant?: string;
53
+ } | undefined;
54
+ private deps;
55
+ private exposed;
56
+ constructor(placement: string, source: Paywall['source'], definition: PaywallDefinition, offerings: Offerings, shown: Paywall['shown'], deps: PaywallDeps);
57
+ /** The store's values of each package the paywall sells, in a language: what its texts' variables read. */
58
+ packages(locale: string): Record<string, PackageValues>;
59
+ /**
60
+ * Draws the paywall into a container and counts it shown — once, however
61
+ * often it is drawn. The purchase button opens Stripe Checkout for the
62
+ * package selected; the web has no restore button (a web purchase is the
63
+ * account's, wherever it signs in).
64
+ */
65
+ render(container: HTMLElement, opts: PaywallRenderOptions): PaywallView;
66
+ }
67
+ /** The packages the web sells of those named, priced as its catalog prices them. */
68
+ export declare function webPackages(offerings: Offerings, keys: readonly string[], locale: string): PricedPackage[];
69
+ /**
70
+ * 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.
74
+ */
75
+ export declare function defaultPaywall(offerings: Offerings): PaywallDefinition | null;
76
+ /** This browser's installation id: who a paywall is shown to before anyone signs in — the same experiment variant every time. */
77
+ export declare function installationId(ref: string): string;
78
+ /** The placement's paywall (see Purchases.paywall). */
79
+ export declare function loadPaywall(api: Api, ref: string, placement: string, checkout: (opts: {
80
+ product: string;
81
+ plan: string;
82
+ successUrl: string;
83
+ cancelUrl: string;
84
+ }) => Promise<string>, signal?: AbortSignal): Promise<Paywall | null>;
85
+ export {};
@@ -0,0 +1,40 @@
1
+ import type { PackageValues } from './resolve.js';
2
+ /** A package as a channel sells it: its product's name there, its price and, for a subscription, its period and trial. */
3
+ export interface PricedPackage {
4
+ /** `<product>.<plan>` */
5
+ key: string;
6
+ productName: string;
7
+ /** In the currency's minor units (999 is 9.99), as the catalog holds it. */
8
+ price: {
9
+ amount: number;
10
+ currency: string;
11
+ };
12
+ /** A subscription's billing period, ISO 8601 (P1M, P1Y …). */
13
+ period?: string;
14
+ /** An introductory offer; a free trial (mode free_trial) is the `{{trial}}` variable. */
15
+ intro?: {
16
+ mode: string;
17
+ duration: string;
18
+ };
19
+ }
20
+ interface Duration {
21
+ count: number;
22
+ unit: 'day' | 'week' | 'month' | 'year';
23
+ /** How many months it is, for a price per month. */
24
+ months: number;
25
+ }
26
+ /** P1Y, P3M, P1W, P7D — one unit, as the stores sell; null for anything else. */
27
+ export declare function parseDuration(iso: string | undefined): Duration | null;
28
+ /** An amount in minor units, in its currency as the language writes it. */
29
+ export declare function formatPrice(amount: number, currency: string, locale: string): string;
30
+ /** "month" for one, "3 months" for more — the language's own words (Intl's units). */
31
+ export declare function formatPeriod(d: Duration, locale: string): string;
32
+ /**
33
+ * The variables of each package, by key. `{{savings}}` is what a
34
+ * subscription saves a month against the dearest a month of the packages
35
+ * given in its currency (none for the dearest, nor below 1%); a package
36
+ * that is not a subscription has no `{{period}}`, `{{price_per_month}}` or
37
+ * `{{savings}}`, and one without a free trial no `{{trial}}`.
38
+ */
39
+ export declare function packageValues(packages: readonly PricedPackage[], locale: string): Record<string, PackageValues>;
40
+ export {};
@@ -0,0 +1,54 @@
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. */
3
+ export interface PaywallInput {
4
+ definition: PaywallDefinition;
5
+ /** The reader's language (`tr-TR`). */
6
+ locale: string;
7
+ appearance: Appearance;
8
+ /** The store's values of each package, by `<product>.<plan>`; a package without any is drawn, not sold. */
9
+ 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. */
11
+ links?: {
12
+ terms?: string;
13
+ privacy?: string;
14
+ };
15
+ }
16
+ /** A package of the catalog: what the purchase button buys. */
17
+ export interface PaywallPackage {
18
+ product: string;
19
+ plan: string;
20
+ }
21
+ export interface PaywallHandlers {
22
+ /** The purchase button, for the package selected; the button waits while a promise it returns runs. */
23
+ 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). */
25
+ onRestore?(): void | Promise<void>;
26
+ /** The close button; without one the paywall draws none. */
27
+ onClose?(): void;
28
+ /** A link the person opened; without one, the browser opens it in a new tab. */
29
+ onLink?(url: string): void;
30
+ /** Told when the person picks another package. */
31
+ onSelect?(pkg: PaywallPackage): void;
32
+ /** The paywall's own words, which the definition does not hold: the app's, in its language. */
33
+ labels?: {
34
+ packages?: string;
35
+ close?: string;
36
+ restore?: string;
37
+ };
38
+ }
39
+ export interface PaywallView {
40
+ /** The package selected now. */
41
+ readonly selected: PaywallPackage | null;
42
+ /** Selects a package (`<product>.<plan>`) as the person would. */
43
+ 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
+ /** Removes it from the page. */
47
+ destroy(): void;
48
+ }
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
+ /** Draws a paywall into a container (its content is replaced). */
54
+ export declare function renderPaywall(container: HTMLElement, input: PaywallInput, handlers: PaywallHandlers): PaywallView;
@@ -0,0 +1,149 @@
1
+ import type { purchases } from '../../../internal/src/modules/index.js';
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;
5
+ export type Appearance = 'light' | 'dark';
6
+ /** What the store gave a package, as the variables of its texts: `{{price}}` … */
7
+ export interface PackageValues {
8
+ price?: string;
9
+ price_per_month?: string;
10
+ period?: string;
11
+ trial?: string;
12
+ savings?: string;
13
+ product_name?: string;
14
+ }
15
+ export interface ResolveOptions {
16
+ /** The app's language (`tr-TR`): the definition's own, else its language without the region, else its default. */
17
+ locale: string;
18
+ appearance: Appearance;
19
+ /** The store's values of each package, by `<product>.<plan>`. */
20
+ 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
+ */
26
+ selected?: string;
27
+ }
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 = {
40
+ id?: string;
41
+ };
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;
58
+ color: string;
59
+ align: 'start' | 'center' | 'end';
60
+ weight?: 'regular' | 'medium' | 'semibold' | 'bold';
61
+ };
62
+ export type ResolvedImage = Base & {
63
+ type: 'image';
64
+ src: string;
65
+ fit: 'fit' | 'fill';
66
+ corner: number;
67
+ aspect?: number;
68
+ height?: number;
69
+ alt?: string;
70
+ };
71
+ export type ResolvedIcon = Base & {
72
+ type: 'icon';
73
+ name: string;
74
+ color: string;
75
+ 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. */
129
+ export interface ResolvedPaywall {
130
+ theme: ResolvedTheme;
131
+ root: ResolvedComponent;
132
+ }
133
+ /** Each component of the schema, by type: what a definition may hold and this renderer draws. */
134
+ 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;
141
+ /** A definition as drawn (contracts/paywall/README.md). */
142
+ 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;
149
+ export {};
@@ -2,6 +2,7 @@ import { purchases as purchasesModule } from '../../internal/src/modules/index.j
2
2
  import type { 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 Paywall } from './paywall/placement.js';
5
6
  type P = typeof purchasesModule;
6
7
  export type CustomerInfo = purchasesModule.CustomerInfo;
7
8
  export type Offerings = purchasesModule.Offerings;
@@ -24,6 +25,18 @@ export declare class Purchases {
24
25
  me(): Promise<CustomerInfo>;
25
26
  /** The paywall's catalog: each product's text and price on a channel — the web's unless another is named. */
26
27
  offerings(channel?: 'ios' | 'android' | 'web'): Promise<Offerings>;
28
+ /**
29
+ * 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
32
+ * variant while one runs there, the same for this person every time); the
33
+ * browser keeps it, to ask again with its ETag and to show offline. With
34
+ * nothing published there it is the SDK's own, of every plan the web
35
+ * sells; null when the web sells nothing.
36
+ */
37
+ paywall(placement: string, opts?: {
38
+ signal?: AbortSignal;
39
+ }): Promise<Paywall | null>;
27
40
  /**
28
41
  * Opens Stripe Checkout for the signed-in customer (not a guest) to buy a
29
42
  * product's plan sold on the web: the URL to send them to. Stripe sends
@@ -1,2 +0,0 @@
1
- /*! palbase 0.1.0 — Palbase SDK License (see LICENSE) */
2
- import{a as D}from"./6FWCNTAM.js";import{a as A,b as R,c as b,d as x,e as O,f as j,g as U,h as C,i as L,j as M,k as K,l as $}from"./IKVOXHEE.js";import{b as v,d as w,f as N,g as I}from"./HKJU2FKE.js";var ae=/^pb_[a-z0-9]+_s/;function E(n){if(D())throw new TypeError("palbase/server runs on a server: its secret key never goes into a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs) with the publishable key");if(typeof n.secretKey!="string"||!ae.test(n.secretKey))throw new TypeError("secretKey is the project secret key (pb_<ref>_s\u2026); a publishable key belongs in palbase/web");let e=I(w({baseUrl:n.url,credentials:{secretKey:n.secretKey},fetch:n.fetch,solveProofOfWork:n.solveProofOfWork??!1}),n.retry??N);return{ai:A.client(e),analytics:R.client(e),auth:b.client(e),cache:x.client(e),flags:O.client(e),machines:j.client(e),notify:U.client(e),purchases:C.client(e),realtime:L.client(e),secrets:M.client(e),storage:K.client(e),stores:$.client(e),transport:e,url:new URL(n.url).origin}}var f=class extends Error{code;constructor(e,t){super(t),this.name="WebhookSignatureError",this.code=e}},ue=300,de=/^[0-9]{1,12}$/,le=/^[0-9a-f]{64}$/,W=8,fe=/^whsec_[0-9A-Za-z]{32,}$/,he=1024*1024;async function B(n){if(typeof n.secret!="string"||!fe.test(n.secret))throw new TypeError("secret is the webhook endpoint secret (whsec_\u2026), not an API key");await F(n);let e;try{e=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(z(n.body)))}catch{throw new f("invalid_body","the signed body is not JSON")}if(!be(e))throw new f("invalid_body","the signed body is not a Palbase event (id, type, project_id, created_at, data)");return e}async function F(n){if(typeof n.secret!="string"||n.secret==="")throw new TypeError("secret is the key the request was signed with");let e=z(n.body),{t,v1:r}=H(n),s=await crypto.subtle.importKey("raw",new TextEncoder().encode(n.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),o=new Uint8Array(await crypto.subtle.sign("HMAC",s,we(new TextEncoder().encode(`${t}.`),e))),i=!1;for(let u of r)me(o,ge(u))&&(i=!0);if(!i)throw new f("signature_mismatch","no v1 in Palbase-Signature is this body signed with this secret")}function H(n){let e=n.toleranceSeconds??ue;if(!Number.isFinite(e)||e<0)throw new TypeError(`toleranceSeconds is a number of seconds, 0 or more (got ${String(n.toleranceSeconds)})`);let t=(n.now??Date.now)();if(!Number.isFinite(t))throw new TypeError(`now() returns epoch milliseconds (got ${String(t)})`);let r=n.signature;if(typeof r!="string"||r.trim()==="")throw new f("missing_signature","the request carries no Palbase-Signature header");let s,o=[];for(let i of r.split(",")){let u=i.indexOf("=");if(u<=0)throw new f("malformed_signature","Palbase-Signature is t=<seconds>,v1=<hex>");let c=i.slice(0,u).trim(),a=i.slice(u+1).trim();if(c==="t"){if(s!==void 0||!de.test(a))throw new f("malformed_signature","Palbase-Signature carries one t, in unix seconds");s=a}else if(c==="v1"){if(!le.test(a))throw new f("malformed_signature","a v1 is 64 lowercase hex characters");if(o.length===W)throw new f("malformed_signature",`Palbase-Signature carries at most ${W} v1`);o.push(a)}}if(s===void 0||o.length===0)throw new f("malformed_signature","Palbase-Signature is t=<seconds>,v1=<hex>");if(Math.abs(t/1e3-Number(s))>e)throw new f("stale_timestamp",`the signature's time is more than ${e} s from now: an old delivery sent again is not taken`);return{t:s,v1:o}}async function pe(n,e,t={}){let r=await ye(n,t.maxBytes??he);return B({toleranceSeconds:t.toleranceSeconds,now:t.now,secret:e,signature:n.headers.get("palbase-signature"),body:r})}async function ye(n,e){let t=()=>new f("body_too_large",`the body is larger than ${e} bytes`),r=Number(n.headers.get("content-length")??"NaN");if(Number.isFinite(r)&&r>e)throw t();if(!n.body)return new Uint8Array(0);let s=n.body.getReader(),o=[],i=0;for(;;){let{done:a,value:l}=await s.read();if(a)break;if(i+=l.byteLength,i>e)throw await s.cancel().catch(()=>{}),t();o.push(l)}let u=new Uint8Array(i),c=0;for(let a of o)u.set(a,c),c+=a.byteLength;return u}function z(n){if(typeof n=="string")return new TextEncoder().encode(n);if(n instanceof Uint8Array)return n;if(n instanceof ArrayBuffer)return new Uint8Array(n);throw new TypeError("body is the raw request body (string or bytes): a parsed object is not what was signed \u2014 read the body before any JSON middleware")}function ge(n){let e=new Uint8Array(n.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(n.slice(t*2,t*2+2),16);return e}function me(n,e){if(n.byteLength!==e.byteLength)return!1;let t=0;for(let r=0;r<n.byteLength;r++)t|=n[r]^e[r];return t===0}function we(n,e){let t=new Uint8Array(n.byteLength+e.byteLength);return t.set(n,0),t.set(e,n.byteLength),t}function be(n){if(typeof n!="object"||n===null)return!1;let e=n;return typeof e.id=="string"&&typeof e.type=="string"&&typeof e.project_id=="string"&&typeof e.created_at=="string"&&"data"in e}var V=60,ke=60,Se=8*1024,ve=1e5;function _(n){let e=n instanceof Uint8Array?n:new Uint8Array(n),t="";for(let r of e)t+=String.fromCharCode(r);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Y(n){let e=n.replace(/[\s=]+/g,"");if(!/^[A-Za-z0-9+/_-]*$/.test(e)||e.length%4===1)return;let t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),r=new Uint8Array(t.length);for(let s=0;s<t.length;s++)r[s]=t.charCodeAt(s);return r}function J(n){let e=Y(n);if(e)try{let t=JSON.parse(new TextDecoder().decode(e));return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0}catch{return}}var k=class{byKey=new Map;held=0;sweptAt=Number.NEGATIVE_INFINITY;max;constructor(e=ve){this.max=e}spend(e,t){if(t>=e.until)throw new d("proof","the DPoP proof is not taken: it was checked too long ago");let r=this.byKey.get(e.jkt);if(r){this.forgetOld(e.jkt,r,t);let s=r.get(e.jti);if(s!==void 0&&s>t)throw new d("proof","the DPoP proof is not taken: it was used before");s!==void 0&&r.delete(e.jti)&&this.held--}this.held>=this.max&&this.makeRoom(t),r=this.byKey.get(e.jkt),r||(r=new Map,this.byKey.set(e.jkt,r)),r.set(e.jti,e.until),this.held++}forgetOld(e,t,r){for(let[s,o]of t){if(o>r)break;t.delete(s),this.held--}t.size===0&&this.byKey.delete(e)}makeRoom(e){if(e-this.sweptAt>=1e3){this.sweptAt=e;for(let[r,s]of this.byKey){for(let[o,i]of s)i>e||(s.delete(o),this.held--);s.size===0&&this.byKey.delete(r)}this.held=0;for(let r of this.byKey.values())this.held+=r.size}if(this.held<this.max)return;let t=[...this.byKey].sort((r,s)=>s[1].size-r[1].size);for(let[r,s]of t){if(this.held<=this.max*.9)break;this.byKey.delete(r),this.held-=s.size}}};async function Ee(n,e){let t=`{"crv":"P-256","kty":"EC","x":"${n}","y":"${e}"}`;return _(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)))}function q(n){try{let e=new URL(n);return e.username!==""||e.password!==""?void 0:`${e.protocol}//${e.host}${e.pathname}`}catch{return}}async function G(n,e,t,r){let s=ie=>{throw new d("proof",`the DPoP proof is not taken: ${ie}`)},o=t.proof;if(!o)return s("there is none (a DPoP-bound token comes with a DPoP header)");if(o.length>Se)return s("it is too long");let i=o.split(".");if(i.length!==3)return s("it is not a JWS of three parts");let u=J(i[0]),c=J(i[1]);if(!u||!c)return s("its header or claims are not base64url JSON");if(u.typ!=="dpop+jwt")return s("its typ is not dpop+jwt");if(u.alg!=="ES256")return s(`it is signed with ${String(u.alg)}; only ES256 is taken`);let a=u.jwk;if(!a||typeof a!="object"||a.kty!=="EC"||a.crv!=="P-256"||typeof a.x!="string"||typeof a.y!="string")return s("its header carries no P-256 public key");if("d"in a)return s("its header carries a private key");if(await Ee(a.x,a.y)!==e)return s("it is signed by a key the token does not name");let l;try{l=await crypto.subtle.importKey("jwk",{kty:"EC",crv:"P-256",x:a.x,y:a.y,ext:!0},{name:"ECDSA",namedCurve:"P-256"},!1,["verify"])}catch{return s("its key is not a P-256 point")}let p=Y(i[2]);if(!p||!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},l,p,new TextEncoder().encode(`${i[0]}.${i[1]}`)).catch(()=>!1))return s("its signature does not verify");if(typeof c.htm!="string"||c.htm.toUpperCase()!==t.method.toUpperCase())return s(`it is for ${String(c.htm)}, not ${t.method}`);let h=typeof c.htu=="string"?q(c.htu):void 0,y=q(t.url);if(!h||!y||h!==y)return s(`it is for ${String(c.htu)}, not ${y??t.url}`);let re=r/1e3;if(typeof c.iat!="number"||Math.abs(c.iat-re)>V)return s("it was not made within a minute of now");let se=_(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n)));if(c.ath!==se)return s("it is not for this token (ath)");if(typeof c.jti!="string"||c.jti===""||c.jti.length>256)return s("it has no jti (or one longer than 256)");let oe=_(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(c.jti)));return{jkt:e,jti:oe,until:(c.iat+V+ke)*1e3+1}}var d=class extends Error{reason;constructor(e,t){super(t),this.name="TokenError",this.reason=e}},g=class extends Error{constructor(e,t){super(e,t),this.name="AuthUnavailable"}};function _e(n){return async e=>{let t=b.client(w({baseUrl:n.url,credentials:{secretKey:n.secretKey,accessToken:()=>e},fetch:n.fetch}));try{return await t.verifyTokenUser(),!0}catch(r){if(r instanceof v&&r.status===401)return!1;throw r}}}var T={ES256:{kty:"EC",import:{name:"ECDSA",namedCurve:"P-256"},verify:{name:"ECDSA",hash:"SHA-256"}},PS256:{kty:"RSA",import:{name:"RSA-PSS",hash:"SHA-256"},verify:{name:"RSA-PSS",saltLength:32}}},X=60,Te=16*1024,Pe=10*6e4,Ae=5e4,Z=n=>typeof n=="string"&&Object.hasOwn(T,n),P=class{issuer;projectId;fetchImpl;now;maxKeyAgeMs;refetchIntervalMs;fetchTimeoutMs;standing;standingTtlMs;standings=new Map;asking=new Map;keys=new Map;keysUntil=0;lastFetch=Number.NEGATIVE_INFINITY;lastFailure=void 0;inflight=null;seenProofs=new k;constructor(e){let t=new URL(e.issuer);if(t.origin!==e.issuer.replace(/\/$/,""))throw new TypeError(`issuer is the project's origin (https://<ref>.<domain>), not ${e.issuer}`);if(typeof e.projectId!="string"||e.projectId==="")throw new TypeError("projectId is the project id the tokens carry");if(this.issuer=t.origin,this.projectId=e.projectId,this.fetchImpl=e.fetch??globalThis.fetch,this.now=e.now??Date.now,this.maxKeyAgeMs=e.maxKeyAgeMs??60*6e4,this.refetchIntervalMs=e.refetchIntervalMs??3e4,this.fetchTimeoutMs=e.fetchTimeoutMs??5e3,typeof e.standing!="function")throw new TypeError("standing is how the verifier asks whether a token's session stands");this.standing=e.standing,this.standingTtlMs=e.standingTtlMs??15e3}async verify(e,t){if(typeof e!="string"||e.length===0||e.length>Te)throw new d("malformed","the token is not a JWT");let r=e.split(".");if(r.length!==3)throw new d("malformed","the token is not a JWS of three parts");let s=Q(r[0]),o=Q(r[1]);if(!s||!o)throw new d("malformed","the token header or claims are not base64url JSON");let i=s.alg;if(!Z(i))throw new d("algorithm",`the token is signed with ${String(i)}; only ES256 and PS256 are taken`);let u=s.kid;if(typeof u!="string"||u==="")throw new d("malformed","the token header names no kid");let c=await this.key(u);if(!c)throw new d("unknown_key",`no key ${u} in the project's key set`);if(c.alg!==i)throw new d("algorithm",`key ${u} is ${c.alg}, the token says ${i}`);let a=te(r[2]);if(!a)throw new d("malformed","the signature is not base64url");let l=new TextEncoder().encode(`${r[0]}.${r[1]}`);if(!await crypto.subtle.verify(T[c.alg].verify,c.key,a,l).catch(()=>!1))throw new d("signature","the signature does not verify");let m=this.check(o),h=o.cnf,y;if(h!==void 0){if(!t)throw new d("bound","the token is bound to a key (DPoP): it comes with the DPoP scheme and a proof, not as a Bearer");if(typeof h!="object"||h===null||typeof h.jkt!="string"||h.jkt==="")throw new d("bound","the token is bound to a key it does not name (cnf.jkt)");y=await G(e,h.jkt,t,this.now())}else if(t)throw new d("not_bound","the DPoP scheme came with a token bound to no key");if(!await this.stands(e,m.sessionId))throw new d("session_ended","the token's session has ended (signed out, revoked, or its user banned)");return y&&this.seenProofs.spend(y,this.now()),m}async verifyRequest(e){let t=e.headers instanceof Headers?e.headers:xe(e.headers),r=t.get("authorization")??"";if(r==="")return null;let s=/^(bearer|dpop)\s+(\S+)$/i.exec(r);if(!s)throw new d("malformed","the Authorization header is not a Bearer or DPoP token");let o=s[1].toLowerCase()==="dpop",i=new URL(e.url,`http://${t.get("host")??"localhost"}`);return this.verify(s[2],o?{proof:t.get("dpop"),method:e.method,url:ee(t,i)}:void 0)}async stands(e,t){let r=this.now(),s=this.standings.get(t);if(s&&r<s.until)return s.live;let o=this.asking.get(t);o||(o=this.standing(e,t).finally(()=>this.asking.delete(t)),this.asking.set(t,o));let i;try{i=await o}catch(u){throw new g("a session's standing cannot be read now",{cause:u})}return this.standings.delete(t),this.standings.set(t,{live:i,until:this.now()+this.standingTtlMs}),this.standings.size>Ae&&this.standings.delete(this.standings.keys().next().value),i}check(e){if(e.iss!==this.issuer)throw new d("issuer",`the token was issued by ${String(e.iss)}, not this project`);if(!(Array.isArray(e.aud)?e.aud:[e.aud]).includes(this.issuer))throw new d("audience","the token is not meant for this project");if(e.project_id!==this.projectId)throw new d("project","the token names another project");let r=this.now()/1e3;if(typeof e.exp!="number"||e.exp+X<=r)throw new d("expired","the token has expired");if(e.nbf!==void 0&&(typeof e.nbf!="number"||e.nbf-X>r))throw new d("not_yet_valid","the token is not valid yet");if(typeof e.sub!="string"||e.sub===""||typeof e.auth_time!="number")throw new d("not_a_user","the token is not a user's");if(typeof e.session_id!="string"||e.session_id==="")throw new d("not_a_session","the token is no session's");let s=e.custom_claims;if(s!==void 0&&(typeof s!="object"||s===null||s.type!==void 0))throw new d("not_a_session","the token is a custom one (an exchange or an approval), not a session's");return{id:e.sub,email:typeof e.email=="string"?e.email:null,emailVerified:e.email_verified===!0,role:typeof e.role=="string"?e.role:null,sessionId:typeof e.session_id=="string"?e.session_id:null,claims:Object.freeze({...e})}}async key(e){let t=this.now();if(t>=this.keysUntil){let s=this.keys.size>0&&t<this.keysUntil+Pe;if(this.lastFailure!==void 0&&t-this.lastFetch<this.refetchIntervalMs){if(!s)throw new g("the project's key set cannot be read now",{cause:this.lastFailure})}else try{await this.refresh()}catch(o){if(!s)throw o}}let r=this.keys.get(e);return!r&&t-this.lastFetch>=this.refetchIntervalMs&&(await this.refresh(),r=this.keys.get(e)),r}refresh(){if(this.inflight)return this.inflight;let e=this.load().finally(()=>{this.inflight=null});return this.inflight=e,e}async load(){this.lastFetch=this.now();let e,t;try{if(t=await this.fetchImpl(`${this.issuer}/.well-known/jwks.json`,{redirect:"error",headers:{accept:"application/json"},signal:AbortSignal.timeout(this.fetchTimeoutMs)}),!t.ok)throw new Error(`the project's key set answered ${t.status}`);e=await t.json()}catch(o){throw this.lastFailure=o,new g("the project's key set cannot be read now",{cause:o})}this.lastFailure=void 0;let r=new Map;for(let o of Array.isArray(e.keys)?e.keys:[]){let i=o.alg;if(typeof o.kid!="string"||!Z(i))continue;let u=T[i];if(o.kty!==u.kty||o.use!==void 0&&o.use!=="sig")continue;let{d:c,...a}=o;try{r.set(o.kid,{alg:i,key:await crypto.subtle.importKey("jwk",a,u.import,!1,["verify"])})}catch{}}this.keys=r;let s=Oe(t.headers.get("cache-control"))??this.maxKeyAgeMs;this.keysUntil=this.now()+Math.min(Math.max(s,this.refetchIntervalMs),this.maxKeyAgeMs)}};function ee(n,e){let t=n.get("x-forwarded-proto")?.split(",")[0]?.trim().toLowerCase(),r=t==="https"||t==="http"?t:e.protocol.slice(0,-1),s=n.get("host")??e.host;return Re.test(s)?`${r}://${s}${e.pathname}`:""}var Re=/^(?:[a-z0-9-]+(?:\.[a-z0-9-]+)*|\[[0-9a-f:.]+\])(?::[0-9]{1,5})?$/i;function xe(n){let e=new Headers;for(let[t,r]of Object.entries(n))if(r!==void 0)for(let s of Array.isArray(r)?r:[r])e.append(t,s);return e}function Oe(n){let e=/(?:^|,)\s*max-age=(\d+)/i.exec(n??"");return e?Number(e[1])*1e3:void 0}function te(n){if(!/^[A-Za-z0-9_-]*$/.test(n)||n.length%4===1)return null;let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function Q(n){let e=te(n);if(!e)return null;try{let t=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(e));return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:null}catch{return null}}function je(n,e,t=Date.now()){let r=Object.hasOwn(n.entitlements,e)?n.entitlements[e]:void 0;return r?.active?r.expires_at===null?!0:Date.parse(r.expires_at)>(typeof t=="number"?t:t.getTime()):!1}var S=class extends Error{receipt;constructor(e){super(`the reservation ${JSON.stringify(e.idempotency_key)} is ${e.status} already: its job is not run again (a new one is a new Idempotency-Key)`),this.name="ReservationSettled",this.receipt=e}};async function Ue(n,e,t,r){let{idempotencyKey:s,amount:o,ttlSeconds:i,metadata:u}=t;if(typeof s!="string"||s==="")throw new TypeError("idempotencyKey names the reservation for good: a retry with it is the same hold, never a second");let c={amount:o,...t.credits!==void 0?{credits:t.credits}:{limit:t.limit},...i!==void 0?{ttl_seconds:i}:{},...u!==void 0?{metadata:u}:{}},a=(await n.purchases.holdSpend({path:{customer_id:e},headers:{"Idempotency-Key":s},body:c})).data;if(a.status!=="held")throw new S(a);let l={customer_id:a.customer,spend_id:a.id},p;try{p=await r(a)}catch(m){throw await n.purchases.releaseSpend({path:l}).catch(()=>{}),m}return await n.purchases.commitSpend({path:l}),p}async function*Ce(n){let e,t=new Set;do{let r=(await n(e)).data;yield r;let s=r.next_cursor??void 0;if(s!==void 0&&t.has(s))throw new Error(`the listing answered a cursor it had answered before (${s})`);s!==void 0&&t.add(s),e=s}while(e)}var Le=/^[A-Za-z_][A-Za-z0-9_]{0,127}$/,Me=/^(PALBASE_|NODE_|BUN_|NPM_|LD_|DYLD_|GIT_|SSH_)|^(PATH|HOME|SHELL|USER|TMPDIR|TMP|TEMP|PWD|IFS|ENV|BASH_ENV|SSL_CERT_FILE|SSL_CERT_DIR|CURL_CA_BUNDLE|REQUESTS_CA_BUNDLE|NO_PROXY|ALL_PROXY|HTTP_PROXY|HTTPS_PROXY|PG\w*)$/i;function ne(n){return!Le.test(n)||Me.test(n)||/_PROXY$/i.test(n)}var Ke=/^(PORT|PALBASE_(URL|PROJECT_ID|REPLICAS|SECRET_KEY|WEBHOOK_SECRET|PLATFORM_SECRET|CONTRACT_OUT|SECRETS|DB_[A-Z0-9_]+))$/;function $e(n){return Ke.test(n)}async function Ne(n={}){let e=n.env??process.env,t=e.PALBASE_SECRETS;if(t===void 0||t==="")return;if(t!=="development"&&t!=="production")throw new TypeError(`PALBASE_SECRETS is development or production, not ${t}`);let r=n.url??e.PALBASE_URL??"",s=n.secretKey??e.PALBASE_SECRET_KEY??"";if(r===""||s==="")throw new TypeError("PALBASE_SECRETS reads the project's Secrets with PALBASE_URL and PALBASE_SECRET_KEY: give both (palbase env:pull writes them)");let o=E({url:new URL(r).origin,secretKey:s,fetch:n.fetch}),{data:i}=await o.secrets.getEnvironmentValues({path:{environment:t}}),u=[],c=[],a=[];for(let[l,p]of Object.entries(i.values)){if(ne(l)){a.push(l);continue}if(e[l]!==void 0&&e[l]!==""){c.push(l);continue}e[l]=p,u.push(l)}return{set:t,loaded:u.sort(),kept:c.sort(),refused:a.sort()}}export{E as a,f as b,B as c,F as d,H as e,pe as f,d as g,g as h,_e as i,P as j,ee as k,je as l,S as m,Ue as n,Ce as o,ne as p,$e as q,Ne as r};
@@ -1,2 +0,0 @@
1
- /*! palbase 0.1.0 — Palbase SDK License (see LICENSE) */
2
- import{a as w,b as g}from"./DAOLIUNZ.js";var A=Symbol.for("palbase.data"),S=globalThis,k=S[A]??=new WeakSet;function T(t){return t instanceof Date||ArrayBuffer.isView(t)||t instanceof ArrayBuffer}function R(t){let e=[t];for(;e.length>0;){let n=e.pop();if(!(typeof n!="object"||n===null||k.has(n)||T(n))){k.add(n);for(let o of Array.isArray(n)?n:Object.values(n))e.push(o)}}return t}var f=class extends Error{status;code;requestId;retryAfter;body;op;constructor(e){super(e.message,e.cause===void 0?void 0:{cause:e.cause}),this.name="PalbaseError",this.op=e.op,this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.retryAfter=e.retryAfter,this.body=e.body}};function M(t,e,n){let o=String(n);if(o===""||o==="."||o==="..")throw new f({op:t,status:0,code:"invalid_path_parameter",message:`${t}: ${e} cannot be ${o===""?"empty":JSON.stringify(o)}`});return encodeURIComponent(o)}var x=new Set(["apikey","authorization"]),E=64*1024;function V(t){let e=q(t.baseUrl),n=t.fetch??globalThis.fetch,o=t.solveProofOfWork??!0,i=async(r,a)=>{let d=v(e,r),s=new Headers;for(let[h,y]of Object.entries(r.headers??{}))y!=null&&!x.has(h.toLowerCase())&&s.set(h,String(y));for(let[h,y]of Object.entries(a))s.set(h,y);await P(r,t.credentials,s),s.has("accept")||s.set("accept","application/json");let l={method:r.method,headers:s,redirect:"manual",signal:r.signal,...r.keepalive?{keepalive:!0}:{}};r.body&&r.body.value!==void 0&&(s.set("content-type",r.body.contentType),l.body=L(r.body.kind,r.body.value),m(l.body)||(l.duplex="half"));let u;try{u=r.onUploadProgress&&t.xmlHttpRequest?await U(t.xmlHttpRequest,r.op,d,l,r.onUploadProgress):await n(d,l)}catch(h){throw r.signal?.aborted||h instanceof f?h:new f({op:r.op,status:0,code:"network_error",message:`${r.op}: the request did not reach ${e.origin}`,cause:h})}let c=r.answers[u.status];if(c===void 0)throw u.status>=200&&u.status<300?(await u.body?.cancel(),new f({op:r.op,status:u.status,code:"undeclared_answer",message:`${r.op}: the server answered ${u.status}, which its contract does not declare; the request may have taken effect`})):await O(r.op,u);let p;switch(c){case"json":try{p=R(await u.json())}catch(h){throw new f({op:r.op,status:u.status,code:"invalid_json",message:`${r.op}: the answer is not JSON`,cause:h})}break;case"raw":p=u;break;default:await u.body?.cancel(),p=void 0}return{status:u.status,data:p,headers:u.headers}};return{async send(r){try{return await i(r,{})}catch(a){let d=o&&a instanceof f&&a.status===403?w(a.body):null,s=r.body?.value;if(!d||r.body?.kind==="raw"&&!m(s))throw a;let l=a,u;try{u=await g(d,{signal:r.signal})}catch(c){throw r.signal?.aborted?c:new f({op:r.op,status:403,code:"pow_unsolved",message:`${r.op}: ${c instanceof Error?c.message:String(c)}`,requestId:l.requestId,body:l.body,cause:c})}return i(r,u)}}}}function U(t,e,n,o,i){return new Promise((r,a)=>{let d=o.signal;if(d?.aborted)return a(d.reason);let s=new t,l=()=>s.abort();d?.addEventListener("abort",l,{once:!0});let u=c=>{d?.removeEventListener("abort",l),c()};s.open(o.method??"GET",n.href),s.responseType="arraybuffer",new Headers(o.headers).forEach((c,p)=>s.setRequestHeader(p,c)),s.upload&&(s.upload.onprogress=c=>{c.lengthComputable&&i(c.loaded,c.total)}),s.onload=()=>u(()=>{if(s.responseURL!==""&&s.responseURL!==n.href){a(new f({op:e,status:0,code:"undeclared_redirect",message:`${e}: the server redirected; the answer is another address's, and was not read`}));return}if(s.status<200||s.status>599)return a(new TypeError(`${e}: answered ${s.status}`));let c=s.status===204||s.status===205||s.status===304;r(new Response(c?null:s.response,{status:s.status,statusText:s.statusText,headers:$(s.getAllResponseHeaders())}))}),s.onerror=()=>u(()=>a(new TypeError(`${e}: the request failed`))),s.onabort=()=>u(()=>a(d?.reason??new DOMException("The request was aborted","AbortError"))),s.send(o.body)})}function $(t){let e=new Headers;for(let n of t.split(/\r?\n/)){let o=n.indexOf(":");if(!(o<=0))try{e.append(n.slice(0,o).trim(),n.slice(o+1).trim())}catch{}}return e}function q(t){let e;try{e=new URL(t)}catch{throw new TypeError(`baseUrl ${JSON.stringify(t)} is not an absolute URL`)}let n=e.hostname==="localhost"||e.hostname.endsWith(".localhost")||e.hostname==="127.0.0.1"||e.hostname==="[::1]";if(e.protocol!=="https:"&&!(e.protocol==="http:"&&n))throw new TypeError(`baseUrl must be https (http only for a loopback address): ${e.origin}`);if(e.username||e.password||e.search||e.hash)throw new TypeError("baseUrl carries no user, query or fragment");if(e.pathname!=="/"&&e.pathname!=="")throw new TypeError("baseUrl is the project origin alone, with no path");return e}function v(t,e){if(!e.path.startsWith("/")||e.path.startsWith("//"))throw new f({op:e.op,status:0,code:"invalid_path",message:`${e.op}: path ${JSON.stringify(e.path)} is not absolute`});let n=new URL(e.path+j(e.query),t);if(n.origin!==t.origin)throw new f({op:e.op,status:0,code:"invalid_path",message:`${e.op}: path leaves the project's origin`});return n}async function P(t,e,n){if(t.auth.length===0)return;let o=t.auth.some(a=>a.includes("userJWT"))?await e.accessToken?.():void 0,i=a=>{switch(a){case"ApiKeyAuth":return!!(e.publishableKey??e.secretKey);case"SecretKeyAuth":case"AdminAuth":return!!e.secretKey;case"userJWT":return!!o;default:return!1}},r=t.auth.filter(a=>a.every(i)).reduce((a,d)=>a===void 0||d.length>a.length?d:a,void 0);if(!r)throw new f({op:t.op,status:0,code:"missing_credential",message:`${t.op} needs one of: ${t.auth.map(a=>a.length===0?"nothing":a.join(" + ")).join(" | ")}`});for(let a of r)a==="ApiKeyAuth"?n.set("apikey",e.publishableKey??e.secretKey):a==="SecretKeyAuth"||a==="AdminAuth"?n.set("apikey",e.secretKey):a==="userJWT"&&n.set("authorization",`Bearer ${o}`)}function L(t,e){switch(t){case"json":return JSON.stringify(e);case"form":{let n=new URLSearchParams;for(let[o,i]of Object.entries(e))b(n,o,i);return n}case"raw":return e}}function m(t){return!!(t==null||typeof t=="string"||t instanceof URLSearchParams||t instanceof Blob||t instanceof FormData||t instanceof ArrayBuffer||ArrayBuffer.isView(t))}function j(t){if(!t)return"";let e=new URLSearchParams;for(let[o,i]of Object.entries(t))b(e,o,i);let n=e.toString();return n===""?"":`?${n}`}function b(t,e,n){if(n!=null){if(Array.isArray(n)){for(let o of n)b(t,e,o);return}if(n instanceof Date){t.append(e,n.toISOString());return}t.append(e,typeof n=="object"?JSON.stringify(n):String(n))}}async function O(t,e){let n=await I(e,E).catch(()=>""),o;try{o=n===""?void 0:JSON.parse(n)}catch{o=n}let i=_(o)?o:void 0,r=Number(e.headers.get("retry-after")),a=e.status>=300&&e.status<400;return new f({op:t,status:e.status,code:i?.error??(a?"undeclared_redirect":`http_${e.status}`),message:i?.error_description??(a?`${t}: the server redirected (${e.status}); the request was not followed, its credentials stay here`:`${t}: ${e.status} ${e.statusText}`.trim()),requestId:i?.request_id??e.headers.get("x-request-id")??void 0,retryAfter:i?.retry_after??(Number.isFinite(r)&&r>0?r:void 0),body:o})}async function I(t,e){if(!t.body)return"";let n=t.body.getReader(),o=[],i=0;for(;i<e;){let{done:d,value:s}=await n.read();if(d)break;o.push(s),i+=s.byteLength}await n.cancel().catch(()=>{});let r=new Uint8Array(Math.min(i,e)),a=0;for(let d of o){let s=Math.min(d.byteLength,r.byteLength-a);if(r.set(d.subarray(0,s),a),a+=s,a>=r.byteLength)break}return new TextDecoder().decode(r)}function _(t){return typeof t=="object"&&t!==null&&typeof t.error=="string"}var K={attempts:3,maxWaitSeconds:30},B=new Set([429,502,503,504]);function Y(t,e=K){let n=e.sleep??W;return{async send(o){let i=C(o),r=i.body,a=!r||r.kind!=="raw"||m(r.value),d=(i.method==="GET"||i.method==="HEAD"||i.idempotent===!0)&&a;for(let s=1;;s++)try{return await t.send(i)}catch(l){if(!d||s>=e.attempts||!(l instanceof f)||i.signal?.aborted)throw l;let u=H(l,s,e.maxWaitSeconds);if(u===void 0)throw l;await n(u*1e3,i.signal)}}}}function C(t){return t.idempotent?Object.entries(t.headers??{}).some(([n,o])=>n.toLowerCase()==="idempotency-key"&&o!==void 0&&o!==null&&o!=="")?t:{...t,headers:{...t.headers,"Idempotency-Key":D()}}:t}function H(t,e,n){return B.has(t.status)||t.code==="network_error"?t.retryAfter!==void 0?t.retryAfter<=n?t.retryAfter:void 0:Math.min(.5*2**(e-1),n)*(.8+Math.random()*.4):void 0}function W(t,e){return new Promise((n,o)=>{if(e?.aborted)return o(e.reason);let i=()=>{clearTimeout(r),o(e?.reason)},r=setTimeout(()=>{e?.removeEventListener("abort",i),n()},t);e?.addEventListener("abort",i,{once:!0})})}function D(){if(typeof crypto.randomUUID=="function")return crypto.randomUUID();let t=crypto.getRandomValues(new Uint8Array(16));t[6]=t[6]&15|64,t[8]=t[8]&63|128;let e=[...t].map(n=>n.toString(16).padStart(2,"0")).join("");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}export{R as a,f as b,M as c,V as d,q as e,K as f,Y as g,D as h};