@palbase/backend 10.2.0 → 10.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.
package/dist/index.d.cts CHANGED
@@ -1,12 +1,68 @@
1
- import { C as CacheClient, b as PalbaseDocsClient, c as PalbaseFlagsClient, L as Logger, d as PalbaseNotificationsClient, Q as QueueClient, e as PalbaseRealtimeClient, D as DBClient, f as PalbaseStorageClient, A as AuthSpec, R as RateLimitConfig, H as HttpError, U as User$1 } from './endpoint-Cn3ICGTf.cjs';
2
- export { g as AuthConfig, B as BadRequest, h as ClientInfo, i as Conflict, j as DBOps, E as ErrorDef, k as ErrorMap, l as ErrorThrowers, F as FileContext, m as Forbidden, n as HttpMethod, M as Middleware, o as MiddlewareContext, p as MiddlewareHandler, N as NotFound, P as PBRequest, q as PalError, r as PalbaseAnalyticsClient, s as PalbaseAnalyticsManagementNamespace, t as PalbaseAnalyticsProperties, u as PalbaseAnalyticsQueryNamespace, v as PalbaseAttestAndroidParams, w as PalbaseAttestAndroidResult, x as PalbaseAttestiOSParams, y as PalbaseAttestiOSResult, z as PalbaseAuthClient, G as PalbaseBatchOverrideOperation, I as PalbaseBatchSetOverridesResult, J as PalbaseBindDeviceParams, K as PalbaseBucketClient, O as PalbaseClearAllOverridesResult, S as PalbaseClearOverrideResult, T as PalbaseCohortQueryInput, V as PalbaseCohortResult, W as PalbaseCollectionRef, X as PalbaseCountQueryInput, Y as PalbaseCountResult, Z as PalbaseCreateLinkParams, _ as PalbaseDeviceInfo, $ as PalbaseDeviceTokenView, a0 as PalbaseDocumentRef, a1 as PalbaseDocumentSnapshot, a2 as PalbaseEmailClient, a3 as PalbaseEmailSendParams, a4 as PalbaseEmailSendResponse, a5 as PalbaseEventNamesResult, a6 as PalbaseEventsQueryInput, a7 as PalbaseEventsResult, a8 as PalbaseFileObject, a9 as PalbaseFlag, aa as PalbaseFlagContext, ab as PalbaseFlagSource, ac as PalbaseFlagValue, ad as PalbaseFlagVariant, ae as PalbaseFlagsServiceClient, af as PalbaseFunctionsClient, ag as PalbaseFunnelQueryInput, ah as PalbaseFunnelResult, ai as PalbaseIdentifyTraits, aj as PalbaseInboxClient, ak as PalbaseInboxListOptions, al as PalbaseInboxListResult, am as PalbaseInboxMessage, an as PalbaseInboxSendParams, ao as PalbaseInboxSendResponse, ap as PalbaseInitialLink, aq as PalbaseInvokeOptions, ar as PalbaseLink, as as PalbaseLinkAnalytics, at as PalbaseLinkDetails, au as PalbaseLinksClient, av as PalbaseListLinksOptions, aw as PalbaseListLinksResult, ax as PalbaseListOptions, ay as PalbaseMatchParams, az as PalbaseMultiChannelResponse, aA as PalbaseOverviewResult, aB as PalbasePreferences, aC as PalbasePreferencesClient, aD as PalbasePublicUrlResponse, aE as PalbasePushClient, aF as PalbasePushSendParams, aG as PalbasePushSendResponse, aH as PalbaseQrCodeOptions, aI as PalbaseQuerySnapshot, aJ as PalbaseRegisterDeviceParams, aK as PalbaseResult, aL as PalbaseRetentionQueryInput, aM as PalbaseRetentionResult, aN as PalbaseSession, aO as PalbaseSetOverrideResult, aP as PalbaseSetOverridesResult, aQ as PalbaseSignedUrlResponse, aR as PalbaseSmsClient, aS as PalbaseSmsSendParams, aT as PalbaseSmsSendResponse, aU as PalbaseTransformOptions, aV as PalbaseUpdateLinkParams, aW as PalbaseUploadOptions, aX as PalbaseUser, aY as PalbaseUserDetailResult, aZ as PalbaseUsersQueryInput, a_ as PalbaseUsersResult, a$ as PalbaseVerifyRequestSignatureParams, b0 as PalbaseWhereOperator, b1 as TooManyRequests, b2 as TxClient, b3 as Unauthorized, b4 as VerifiedDevice, b5 as defineMiddleware } from './endpoint-Cn3ICGTf.cjs';
1
+ import { C as CacheClient, b as PalbaseDocsClient, c as PalbaseFlagsClient, L as Logger, d as PalbaseNotificationsClient, Q as QueueClient, e as PalbaseRealtimeClient, D as DBClient, f as PalbaseStorageClient, A as AuthSpec, R as RateLimitConfig, H as HttpError, U as User$1 } from './endpoint-92kVepng.cjs';
2
+ export { g as AuthConfig, B as BadRequest, h as ClientInfo, i as Conflict, j as DBOps, E as ErrorDef, k as ErrorMap, l as ErrorThrowers, F as FileContext, m as Forbidden, n as HttpMethod, M as Middleware, o as MiddlewareContext, p as MiddlewareHandler, N as NotFound, P as PBRequest, q as PalError, r as PalbaseAnalyticsClient, s as PalbaseAnalyticsManagementNamespace, t as PalbaseAnalyticsProperties, u as PalbaseAnalyticsQueryNamespace, v as PalbaseAttestAndroidParams, w as PalbaseAttestAndroidResult, x as PalbaseAttestiOSParams, y as PalbaseAttestiOSResult, z as PalbaseAuthClient, G as PalbaseBatchOverrideOperation, I as PalbaseBatchSetOverridesResult, J as PalbaseBindDeviceParams, K as PalbaseBucketClient, O as PalbaseClearAllOverridesResult, S as PalbaseClearOverrideResult, T as PalbaseCohortQueryInput, V as PalbaseCohortResult, W as PalbaseCollectionRef, X as PalbaseCountQueryInput, Y as PalbaseCountResult, Z as PalbaseCreateLinkParams, _ as PalbaseDeviceInfo, $ as PalbaseDeviceTokenView, a0 as PalbaseDocumentRef, a1 as PalbaseDocumentSnapshot, a2 as PalbaseEmailClient, a3 as PalbaseEmailSendParams, a4 as PalbaseEmailSendResponse, a5 as PalbaseEventNamesResult, a6 as PalbaseEventsQueryInput, a7 as PalbaseEventsResult, a8 as PalbaseFileObject, a9 as PalbaseFlag, aa as PalbaseFlagContext, ab as PalbaseFlagSource, ac as PalbaseFlagValue, ad as PalbaseFlagVariant, ae as PalbaseFlagsServiceClient, af as PalbaseFunctionsClient, ag as PalbaseFunnelQueryInput, ah as PalbaseFunnelResult, ai as PalbaseIdentifyTraits, aj as PalbaseInboxClient, ak as PalbaseInboxListOptions, al as PalbaseInboxListResult, am as PalbaseInboxMessage, an as PalbaseInboxSendParams, ao as PalbaseInboxSendResponse, ap as PalbaseInitialLink, aq as PalbaseInvokeOptions, ar as PalbaseLink, as as PalbaseLinkAnalytics, at as PalbaseLinkDetails, au as PalbaseLinksClient, av as PalbaseListLinksOptions, aw as PalbaseListLinksResult, ax as PalbaseListOptions, ay as PalbaseMatchParams, az as PalbaseMultiChannelResponse, aA as PalbaseOverviewResult, aB as PalbasePreferences, aC as PalbasePreferencesClient, aD as PalbasePublicUrlResponse, aE as PalbasePushClient, aF as PalbasePushSendParams, aG as PalbasePushSendResponse, aH as PalbaseQrCodeOptions, aI as PalbaseQuerySnapshot, aJ as PalbaseRegisterDeviceParams, aK as PalbaseResult, aL as PalbaseRetentionQueryInput, aM as PalbaseRetentionResult, aN as PalbaseSession, aO as PalbaseSetOverrideResult, aP as PalbaseSetOverridesResult, aQ as PalbaseSignedUrlResponse, aR as PalbaseSmsClient, aS as PalbaseSmsSendParams, aT as PalbaseSmsSendResponse, aU as PalbaseTransformOptions, aV as PalbaseUpdateLinkParams, aW as PalbaseUploadOptions, aX as PalbaseUser, aY as PalbaseUserDetailResult, aZ as PalbaseUsersQueryInput, a_ as PalbaseUsersResult, a$ as PalbaseVerifyRequestSignatureParams, b0 as PalbaseWhereOperator, b1 as TooManyRequests, b2 as TxClient, b3 as Unauthorized, b4 as VerifiedDevice, b5 as defineMiddleware } from './endpoint-92kVepng.cjs';
3
3
  import { AsyncLocalStorage } from 'node:async_hooks';
4
- import { E as EnvTypedDatabase, S as SchemaDef } from './index-Bt7UHkAM.cjs';
5
- export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EnvServiceDatabase, f as EnvTables, g as EnvTypedTable, h as EnvTypedTx, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, o as SchemaInput, T as TableDef, p as TableInput, q as TypedDB, r as TypedTable, s as TypedTx, t as bigint, u as boolean, v as defineSchema, w as enumType, x as integer, y as isPalbaseExtension, z as jsonb, A as makeTypedDB, B as numeric, D as policy, F as raw, G as text, H as timestamp, J as uuid } from './index-Bt7UHkAM.cjs';
4
+ import { E as EnvTypedDatabase, S as SchemaDef } from './index-BaHs33jr.cjs';
5
+ export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EnvServiceDatabase, f as EnvTables, g as EnvTypedTable, h as EnvTypedTx, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, o as SchemaInput, T as TableDef, p as TableInput, q as TypedDB, r as TypedTable, s as TypedTx, t as bigint, u as boolean, v as defineSchema, w as enumType, x as integer, y as isPalbaseExtension, z as jsonb, A as makeTypedDB, B as numeric, D as policy, F as raw, G as text, H as timestamp, J as uuid } from './index-BaHs33jr.cjs';
6
+ import { EntitlementKey, LimitKey } from './purchases/keys.cjs';
6
7
  import { TableTypes, Tables } from './db/env.cjs';
7
8
  import { ZodTypeAny, z } from 'zod';
8
9
  export { z } from 'zod';
9
10
 
11
+ /**
12
+ * The purchases surface the decorators need, declared as a NARROW STRUCTURAL
13
+ * interface rather than an import of `@palstore/purchases`.
14
+ *
15
+ * `PurchasesClient` (palstore's `sk_` backend SDK) satisfies this shape as-is,
16
+ * so the runtime injects the real client with no adapter — but `@palbase/backend`
17
+ * itself gains no dependency on it. That matters: this package is published
18
+ * public and baked into the br-pod image from a tarball, so a dependency on an
19
+ * unpublished sibling would break `npm install palbase-backend.tgz`. It is also
20
+ * the pattern `withSpend` already uses for the same reason (`SpendCapableClient`
21
+ * in palstore's own spend.ts: "a narrow structural interface … so this file has
22
+ * no dependency on client.ts").
23
+ *
24
+ * The methods here are a SUBSET of `PurchasesClient` — only what the two
25
+ * decorators call. Grants, refunds, credits and customer-info reads stay off
26
+ * this interface: a tenant that wants them imports the palstore SDK directly.
27
+ */
28
+ /** Store environment a subject is fixed to. Mirrors `StoreEnv` in `@palstore/purchases`. */
29
+ type StoreEnv = "production" | "sandbox";
30
+ /** Quota/credit state carried by a 429. Mirrors `LimitState` in `@palstore/purchases`
31
+ * (SPEC-purchases-v1 §11) — re-declared, not imported, for the reason above. */
32
+ interface LimitState {
33
+ key: string;
34
+ scope: string;
35
+ window: string;
36
+ used: number;
37
+ reserved: number;
38
+ max: number;
39
+ remaining: number;
40
+ resetAt: string;
41
+ }
42
+ /** Options for one spend. `idempotencyKey` is required by the server (§9). */
43
+ interface SpendOptions {
44
+ /** Defaults to 1. */
45
+ count?: number;
46
+ idempotencyKey: string;
47
+ }
48
+ interface PurchasesService {
49
+ /** Map a tenant-side user reference to its palstore subject, creating one on
50
+ * first sight. Server-authoritative — the caller never names a subject. */
51
+ resolveSubject(input: {
52
+ userRef: string;
53
+ storeEnv: StoreEnv;
54
+ }): Promise<{
55
+ subjectId: string;
56
+ }>;
57
+ /** Resolve silently when `entitlementKey` is active for `subjectId`; throw
58
+ * `EntitlementRequiredError` otherwise. Consumes nothing. */
59
+ require(subjectId: string, entitlementKey: string): Promise<void>;
60
+ /** Reserve → run `handler` → commit on success, cancel on throw, always
61
+ * rethrowing the handler's own error. The whole reason the decorators are a
62
+ * thin layer: this lifecycle is already written and tested in palstore's SDK. */
63
+ withSpend<T>(subjectId: string, key: string, opts: SpendOptions, handler: () => Promise<T>): Promise<T>;
64
+ }
65
+
10
66
  /**
11
67
  * runtime.ts — request-scoped service singletons.
12
68
  *
@@ -66,6 +122,28 @@ interface RuntimeServices {
66
122
  Notifications: PalbaseNotificationsClient;
67
123
  Flags: PalbaseFlagsClient;
68
124
  Realtime: PalbaseRealtimeClient;
125
+ Purchases: PurchasesService;
126
+ }
127
+ /**
128
+ * The per-request ALS box.
129
+ *
130
+ * `runtime` is the service bundle. `userId` is the request's authenticated user
131
+ * id, written by the runtime immediately after it assembles the request object
132
+ * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and
133
+ * `null` on an anonymous request. It was already being written there for the
134
+ * Flags client's auto-bind; declaring it here makes the existing contract typed
135
+ * instead of implicit, which is what lets `currentSubjectId()` read a
136
+ * server-owned identity rather than trusting anything the caller sent.
137
+ */
138
+ interface RequestStore {
139
+ runtime: RuntimeServices;
140
+ userId?: string | null;
141
+ /** This request's id (`req_…`), written by the runtime. Used as the spend
142
+ * idempotency scope when the caller supplied no `Idempotency-Key`. */
143
+ requestId?: string;
144
+ /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a
145
+ * client's retry replay its first result instead of charging twice. */
146
+ idempotencyKey?: string | null;
69
147
  }
70
148
  /**
71
149
  * Per-request store. The persistent runtime runs each request inside
@@ -76,9 +154,7 @@ interface RuntimeServices {
76
154
  * instance across the one module instance — two ALS instances would silently
77
155
  * not see each other's stores. NOT part of the public author-facing API.
78
156
  */
79
- declare const __requestALS: AsyncLocalStorage<{
80
- runtime: RuntimeServices;
81
- }>;
157
+ declare const __requestALS: AsyncLocalStorage<RequestStore>;
82
158
  /** Install the live clients in the process-global fallback slot.
83
159
  *
84
160
  * Persistent-server requests should use {@link __runWithRuntime} instead; this
@@ -129,6 +205,15 @@ declare const Queue: QueueClient;
129
205
  declare const Log: Logger;
130
206
  /** Push / email / SMS / in-app notifications. */
131
207
  declare const Notifications: PalbaseNotificationsClient;
208
+ /**
209
+ * Palstore purchases (entitlements + quota/credit spend).
210
+ *
211
+ * Reached by handlers through the `@RequireEntitlement` / `@Spend` decorators
212
+ * rather than called directly in the common case; exposed as a singleton for
213
+ * the cases the decorators deliberately do not cover (a dynamic spend count,
214
+ * which must run BEFORE the billable side-effect).
215
+ */
216
+ declare const Purchases: PurchasesService;
132
217
  /**
133
218
  * Feature flags.
134
219
  *
@@ -161,11 +246,120 @@ declare const Flags: PalbaseFlagsClient;
161
246
  */
162
247
  declare const Realtime: PalbaseRealtimeClient;
163
248
 
249
+ /**
250
+ * `@RequireEntitlement` and `@Spend` — access and metering at the decorator
251
+ * level, so a controller method says what it costs instead of wiring it.
252
+ *
253
+ * TWO decorators, deliberately, because not every subscription is limit-based.
254
+ * Most products just say "pro users may call this" and consume nothing; a
255
+ * zero-count spend would express that badly and run the whole reserve/commit
256
+ * machine for no reason.
257
+ *
258
+ * @RequireEntitlement('pro') pure gate → 403, consumes nothing
259
+ * @Spend('bookCreate') consumption → 429 when exhausted
260
+ *
261
+ * ORDER IS FIXED, and not by where you wrote them. Both decorators record
262
+ * metadata and share ONE installed wrapper that always runs the entitlement
263
+ * gate before it reserves quota. Reserving for someone who is about to get a
264
+ * 403 is wasted work and a race window, so the source order of the two
265
+ * decorators cannot introduce it.
266
+ */
267
+
268
+ type MethodDecorator$2 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
269
+ /**
270
+ * Require an active entitlement. Answers 403 `entitlement_required` when it is
271
+ * absent and consumes nothing.
272
+ *
273
+ * The key is a member of the generated `EntitlementKey` union, so a typo is a
274
+ * compile error rather than a gate that silently never matches.
275
+ */
276
+ declare function RequireEntitlement(key: EntitlementKey): MethodDecorator$2;
277
+ /**
278
+ * Consume one unit of a limit or credit for the request's subject.
279
+ *
280
+ * Reserves before the handler runs and commits only if it returns; a throw
281
+ * cancels the hold, so a user is never charged for work that did not complete.
282
+ * Answers 429 `quota_exceeded` (carrying the `LimitState`) when exhausted.
283
+ *
284
+ * The count is fixed at 1. A DYNAMIC amount is deliberately not expressible
285
+ * here: it has to be decided inside the handler and spent BEFORE the billable
286
+ * side-effect, which is an explicit `Purchases.withSpend(...)` call, not a
287
+ * decorator.
288
+ */
289
+ declare function Spend(key: LimitKey): MethodDecorator$2;
290
+
291
+ /**
292
+ * keys-gen.ts — generate the `palbase-purchases.d.ts` text from a catalog
293
+ * manifest.
294
+ *
295
+ * The twin of `db/env-gen.ts`: the CLI / deploy pipeline calls
296
+ * {@link makePurchasesDts} with the project's catalog revision and writes the
297
+ * result to `palbase-purchases.d.ts` at the project root. That file augments
298
+ * the `@palbase/backend/purchases` `Entitlements` / `Limits` interfaces, so
299
+ * `@RequireEntitlement(...)` and `@Spend(...)` accept the project's real keys
300
+ * and nothing else.
301
+ *
302
+ * Same catalog, two languages: this is the TypeScript half of what swiftgen
303
+ * already emits for iOS. Neither side is hand-maintained, so the two cannot
304
+ * drift from each other or from the manifest the server validated.
305
+ *
306
+ * The emitted file ends in `export {};` — same as `makeEnvDts`. Without it the
307
+ * `.d.ts` is a global script, and `declare module "…"` there DECLARES an
308
+ * ambient module (shadowing the real one, so every key silently becomes
309
+ * invalid) instead of AUGMENTING it.
310
+ */
311
+ /** A catalog entry that may be tombstoned. */
312
+ interface Removable {
313
+ removed?: boolean;
314
+ }
315
+ /**
316
+ * The slice of `pur_catalogs.manifest` this generator reads. Deliberately
317
+ * partial and permissive: the server already validated the manifest (its models
318
+ * are `extra="forbid"`), so re-checking here would be a second, weaker copy of
319
+ * that authority.
320
+ */
321
+ interface PurchasesManifest {
322
+ limits?: Record<string, Removable>;
323
+ credits?: Record<string, Removable>;
324
+ entitlements?: Record<string, Removable>;
325
+ }
326
+ /**
327
+ * Render the project's `palbase-purchases.d.ts`.
328
+ *
329
+ * `Limits` carries BOTH limits and credits: `@Spend` consumes either, and the
330
+ * server answers both with a 429 (`quota_exceeded` / `credit_insufficient`), so
331
+ * splitting them into two unions would make the author pick the right decorator
332
+ * for a distinction the spend path does not make.
333
+ */
334
+ declare function makePurchasesDts(manifest: PurchasesManifest): string;
335
+
336
+ /**
337
+ * Per-method purchases metadata, stored on the controller class the same way
338
+ * `decorators/registry.ts` stores routes: a symbol-keyed static, plain data, no
339
+ * `reflect-metadata`.
340
+ *
341
+ * Its only consumer is the OpenAPI step, which needs to know that a route is
342
+ * gated (declare 403) or metered (declare 429) so the iOS client codegen emits
343
+ * TYPED errors instead of a bare status number. Enforcement does NOT read this
344
+ * — the decorators wrap the method directly — so a stale registry can never
345
+ * cause a missed gate.
346
+ */
347
+
348
+ /** What `@Spend` recorded for one method. */
349
+ interface SpendMeta {
350
+ key: LimitKey;
351
+ count: number;
352
+ }
353
+ /** The entitlement `fnName` is gated on, or undefined when it is not gated. */
354
+ declare function entitlementFor(ctor: object, fnName: string): EntitlementKey | undefined;
355
+ /** What `fnName` spends, or undefined when it spends nothing. */
356
+ declare function spendFor(ctor: object, fnName: string): SpendMeta | undefined;
357
+
164
358
  /**
165
359
  * env-gen.ts — generate the `palbase-env.d.ts` text from a `defineSchema()`
166
360
  * result.
167
361
  *
168
- * The CLI (`palbase serve` / codegen) and the deploy pipeline call
362
+ * The CLI (`palbase db types` / codegen) and the deploy pipeline call
169
363
  * {@link makeEnvDts} with the project's schema and write the returned string to
170
364
  * `palbase-env.d.ts` at the project root. That file AUGMENTS the
171
365
  * `@palbase/backend/env` `Tables` interface (controlled global augmentation,
@@ -1654,4 +1848,4 @@ declare const documents: {
1654
1848
  onDocumentDeleted(handler: HookHandler<DocumentDeletedEvent>): ResolvedHook<DocumentDeletedEvent>;
1655
1849
  };
1656
1850
 
1657
- export { type AcsOptions, type ApnsOptions, type BackoffStrategy, Body, type BucketDef, type BucketOptions, Cache, CacheClient, Client, Controller, type ControllerOptions, type CustomWebhookConfig, DBClient, Database, type DefinedError, type DefinedErrorWithData, Delete, type DocumentCreatedEvent, type DocumentDeletedEvent, type DocumentUpdatedEvent, Documents, EGRESS_CONFIG_KIND, type EgressConfig, type EgressInput, type EnvSecretRef, EnvTypedDatabase, FLAGS_CONFIG_KIND, type FcmOptions, type FileDeletedEvent, type FileUploadedEvent, type FlagDef, type FlagJsonObject, type FlagJsonValue, type FlagOptions, type FlagType, type FlagValue, Flags, type FlagsConfig, type FlagsInput, Get, Headers, type HookHandler, type HookMeta, HttpError, type HttpMethodUpper, type JobConfig, type JobMeta, Log, Logger, NOTIFICATIONS_CONFIG_KIND, Notifications, type NotificationsConfig, type NotificationsInput, OptionalUser, type OwnedTablesOf, PROVIDER_CATALOG, PalbaseDocsClient, PalbaseFlagsClient, PalbaseNotificationsClient, PalbaseRealtimeClient, PalbaseStorageClient, Param, type ParamKind, type ParamMeta, type PasswordResetEvent, Patch, Post, type ProviderCatalogEntry, type ProviderDef, type ProviderEventMap, type ProviderName, type ProviderOptions, type ProviderWebhookConfig, Put, Query, QueryParams, Queue, QueueClient, RESERVED_SECRET_PREFIX, RateLimitConfig, Realtime, type RegisteredError, Req, RequestId, type ResolvedCustomWebhook, type ResolvedHook, type ResolvedJobConfig, type ResolvedProviderWebhook, type ResolvedWebhookConfig, type ResolvedWorkerConfig, Resource, type ResourceEnv, type RouteMeta, type RouteOptions, type RuntimeServices, STORAGE_CONFIG_KIND, SchemaDef, type Seed, type SeedFor, type SeedJson, type SeedRowFor, type SendgridOptions, type SesOptions, type SignInEvent, type SignOutEvent, type SmtpOptions, Storage, type StorageConfig, type StorageInput, TEST_USERS_CONFIG_KIND, type TableGraph, TableTypes, Tables, type TestUserDef, type TestUserOptions, type TestUsersConfig, type TestUsersInput, type ThrowDescriptor, TraceId, type TwilioOptions, Upload, type UploadConfig, UploadedObject, User, type UserCreatedEvent, User$1 as UserT, type WebhookEventHandler, type WebhookMeta, type WebhookProvider, type WebhookRequest, type WorkerConfig, type WorkerMeta, __getRuntime, __registerResource, __requestALS, __runResourceBoot, __runWithRuntime, __setRuntime, __shutdownResources, auth, bucket, buildProvider, defineEgress, defineError, defineFlags, defineJob, defineNotifications, defineStorage, defineTestUsers, defineWebhook, defineWorker, documents, flag, getErrorRegistry, getRoutes, makeEnvDts, parseFileSizeLimit, recordThrows, reservedSecretKey, storage, testUser, validateUploadAgainstStorage };
1851
+ export { type AcsOptions, type ApnsOptions, type BackoffStrategy, Body, type BucketDef, type BucketOptions, Cache, CacheClient, Client, Controller, type ControllerOptions, type CustomWebhookConfig, DBClient, Database, type DefinedError, type DefinedErrorWithData, Delete, type DocumentCreatedEvent, type DocumentDeletedEvent, type DocumentUpdatedEvent, Documents, EGRESS_CONFIG_KIND, type EgressConfig, type EgressInput, EntitlementKey, type EnvSecretRef, EnvTypedDatabase, FLAGS_CONFIG_KIND, type FcmOptions, type FileDeletedEvent, type FileUploadedEvent, type FlagDef, type FlagJsonObject, type FlagJsonValue, type FlagOptions, type FlagType, type FlagValue, Flags, type FlagsConfig, type FlagsInput, Get, Headers, type HookHandler, type HookMeta, HttpError, type HttpMethodUpper, type JobConfig, type JobMeta, LimitKey, type LimitState, Log, Logger, NOTIFICATIONS_CONFIG_KIND, Notifications, type NotificationsConfig, type NotificationsInput, OptionalUser, type OwnedTablesOf, PROVIDER_CATALOG, PalbaseDocsClient, PalbaseFlagsClient, PalbaseNotificationsClient, PalbaseRealtimeClient, PalbaseStorageClient, Param, type ParamKind, type ParamMeta, type PasswordResetEvent, Patch, Post, type ProviderCatalogEntry, type ProviderDef, type ProviderEventMap, type ProviderName, type ProviderOptions, type ProviderWebhookConfig, Purchases, type PurchasesManifest, type PurchasesService, Put, Query, QueryParams, Queue, QueueClient, RESERVED_SECRET_PREFIX, RateLimitConfig, Realtime, type RegisteredError, Req, RequestId, type RequestStore, RequireEntitlement, type ResolvedCustomWebhook, type ResolvedHook, type ResolvedJobConfig, type ResolvedProviderWebhook, type ResolvedWebhookConfig, type ResolvedWorkerConfig, Resource, type ResourceEnv, type RouteMeta, type RouteOptions, type RuntimeServices, STORAGE_CONFIG_KIND, SchemaDef, type Seed, type SeedFor, type SeedJson, type SeedRowFor, type SendgridOptions, type SesOptions, type SignInEvent, type SignOutEvent, type SmtpOptions, Spend, type SpendMeta, type SpendOptions, Storage, type StorageConfig, type StorageInput, type StoreEnv, TEST_USERS_CONFIG_KIND, type TableGraph, TableTypes, Tables, type TestUserDef, type TestUserOptions, type TestUsersConfig, type TestUsersInput, type ThrowDescriptor, TraceId, type TwilioOptions, Upload, type UploadConfig, UploadedObject, User, type UserCreatedEvent, User$1 as UserT, type WebhookEventHandler, type WebhookMeta, type WebhookProvider, type WebhookRequest, type WorkerConfig, type WorkerMeta, __getRuntime, __registerResource, __requestALS, __runResourceBoot, __runWithRuntime, __setRuntime, __shutdownResources, auth, bucket, buildProvider, defineEgress, defineError, defineFlags, defineJob, defineNotifications, defineStorage, defineTestUsers, defineWebhook, defineWorker, documents, entitlementFor, flag, getErrorRegistry, getRoutes, makeEnvDts, makePurchasesDts, parseFileSizeLimit, recordThrows, reservedSecretKey, spendFor, storage, testUser, validateUploadAgainstStorage };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,68 @@
1
- import { C as CacheClient, b as PalbaseDocsClient, c as PalbaseFlagsClient, L as Logger, d as PalbaseNotificationsClient, Q as QueueClient, e as PalbaseRealtimeClient, D as DBClient, f as PalbaseStorageClient, A as AuthSpec, R as RateLimitConfig, H as HttpError, U as User$1 } from './endpoint-Cn3ICGTf.js';
2
- export { g as AuthConfig, B as BadRequest, h as ClientInfo, i as Conflict, j as DBOps, E as ErrorDef, k as ErrorMap, l as ErrorThrowers, F as FileContext, m as Forbidden, n as HttpMethod, M as Middleware, o as MiddlewareContext, p as MiddlewareHandler, N as NotFound, P as PBRequest, q as PalError, r as PalbaseAnalyticsClient, s as PalbaseAnalyticsManagementNamespace, t as PalbaseAnalyticsProperties, u as PalbaseAnalyticsQueryNamespace, v as PalbaseAttestAndroidParams, w as PalbaseAttestAndroidResult, x as PalbaseAttestiOSParams, y as PalbaseAttestiOSResult, z as PalbaseAuthClient, G as PalbaseBatchOverrideOperation, I as PalbaseBatchSetOverridesResult, J as PalbaseBindDeviceParams, K as PalbaseBucketClient, O as PalbaseClearAllOverridesResult, S as PalbaseClearOverrideResult, T as PalbaseCohortQueryInput, V as PalbaseCohortResult, W as PalbaseCollectionRef, X as PalbaseCountQueryInput, Y as PalbaseCountResult, Z as PalbaseCreateLinkParams, _ as PalbaseDeviceInfo, $ as PalbaseDeviceTokenView, a0 as PalbaseDocumentRef, a1 as PalbaseDocumentSnapshot, a2 as PalbaseEmailClient, a3 as PalbaseEmailSendParams, a4 as PalbaseEmailSendResponse, a5 as PalbaseEventNamesResult, a6 as PalbaseEventsQueryInput, a7 as PalbaseEventsResult, a8 as PalbaseFileObject, a9 as PalbaseFlag, aa as PalbaseFlagContext, ab as PalbaseFlagSource, ac as PalbaseFlagValue, ad as PalbaseFlagVariant, ae as PalbaseFlagsServiceClient, af as PalbaseFunctionsClient, ag as PalbaseFunnelQueryInput, ah as PalbaseFunnelResult, ai as PalbaseIdentifyTraits, aj as PalbaseInboxClient, ak as PalbaseInboxListOptions, al as PalbaseInboxListResult, am as PalbaseInboxMessage, an as PalbaseInboxSendParams, ao as PalbaseInboxSendResponse, ap as PalbaseInitialLink, aq as PalbaseInvokeOptions, ar as PalbaseLink, as as PalbaseLinkAnalytics, at as PalbaseLinkDetails, au as PalbaseLinksClient, av as PalbaseListLinksOptions, aw as PalbaseListLinksResult, ax as PalbaseListOptions, ay as PalbaseMatchParams, az as PalbaseMultiChannelResponse, aA as PalbaseOverviewResult, aB as PalbasePreferences, aC as PalbasePreferencesClient, aD as PalbasePublicUrlResponse, aE as PalbasePushClient, aF as PalbasePushSendParams, aG as PalbasePushSendResponse, aH as PalbaseQrCodeOptions, aI as PalbaseQuerySnapshot, aJ as PalbaseRegisterDeviceParams, aK as PalbaseResult, aL as PalbaseRetentionQueryInput, aM as PalbaseRetentionResult, aN as PalbaseSession, aO as PalbaseSetOverrideResult, aP as PalbaseSetOverridesResult, aQ as PalbaseSignedUrlResponse, aR as PalbaseSmsClient, aS as PalbaseSmsSendParams, aT as PalbaseSmsSendResponse, aU as PalbaseTransformOptions, aV as PalbaseUpdateLinkParams, aW as PalbaseUploadOptions, aX as PalbaseUser, aY as PalbaseUserDetailResult, aZ as PalbaseUsersQueryInput, a_ as PalbaseUsersResult, a$ as PalbaseVerifyRequestSignatureParams, b0 as PalbaseWhereOperator, b1 as TooManyRequests, b2 as TxClient, b3 as Unauthorized, b4 as VerifiedDevice, b5 as defineMiddleware } from './endpoint-Cn3ICGTf.js';
1
+ import { C as CacheClient, b as PalbaseDocsClient, c as PalbaseFlagsClient, L as Logger, d as PalbaseNotificationsClient, Q as QueueClient, e as PalbaseRealtimeClient, D as DBClient, f as PalbaseStorageClient, A as AuthSpec, R as RateLimitConfig, H as HttpError, U as User$1 } from './endpoint-92kVepng.js';
2
+ export { g as AuthConfig, B as BadRequest, h as ClientInfo, i as Conflict, j as DBOps, E as ErrorDef, k as ErrorMap, l as ErrorThrowers, F as FileContext, m as Forbidden, n as HttpMethod, M as Middleware, o as MiddlewareContext, p as MiddlewareHandler, N as NotFound, P as PBRequest, q as PalError, r as PalbaseAnalyticsClient, s as PalbaseAnalyticsManagementNamespace, t as PalbaseAnalyticsProperties, u as PalbaseAnalyticsQueryNamespace, v as PalbaseAttestAndroidParams, w as PalbaseAttestAndroidResult, x as PalbaseAttestiOSParams, y as PalbaseAttestiOSResult, z as PalbaseAuthClient, G as PalbaseBatchOverrideOperation, I as PalbaseBatchSetOverridesResult, J as PalbaseBindDeviceParams, K as PalbaseBucketClient, O as PalbaseClearAllOverridesResult, S as PalbaseClearOverrideResult, T as PalbaseCohortQueryInput, V as PalbaseCohortResult, W as PalbaseCollectionRef, X as PalbaseCountQueryInput, Y as PalbaseCountResult, Z as PalbaseCreateLinkParams, _ as PalbaseDeviceInfo, $ as PalbaseDeviceTokenView, a0 as PalbaseDocumentRef, a1 as PalbaseDocumentSnapshot, a2 as PalbaseEmailClient, a3 as PalbaseEmailSendParams, a4 as PalbaseEmailSendResponse, a5 as PalbaseEventNamesResult, a6 as PalbaseEventsQueryInput, a7 as PalbaseEventsResult, a8 as PalbaseFileObject, a9 as PalbaseFlag, aa as PalbaseFlagContext, ab as PalbaseFlagSource, ac as PalbaseFlagValue, ad as PalbaseFlagVariant, ae as PalbaseFlagsServiceClient, af as PalbaseFunctionsClient, ag as PalbaseFunnelQueryInput, ah as PalbaseFunnelResult, ai as PalbaseIdentifyTraits, aj as PalbaseInboxClient, ak as PalbaseInboxListOptions, al as PalbaseInboxListResult, am as PalbaseInboxMessage, an as PalbaseInboxSendParams, ao as PalbaseInboxSendResponse, ap as PalbaseInitialLink, aq as PalbaseInvokeOptions, ar as PalbaseLink, as as PalbaseLinkAnalytics, at as PalbaseLinkDetails, au as PalbaseLinksClient, av as PalbaseListLinksOptions, aw as PalbaseListLinksResult, ax as PalbaseListOptions, ay as PalbaseMatchParams, az as PalbaseMultiChannelResponse, aA as PalbaseOverviewResult, aB as PalbasePreferences, aC as PalbasePreferencesClient, aD as PalbasePublicUrlResponse, aE as PalbasePushClient, aF as PalbasePushSendParams, aG as PalbasePushSendResponse, aH as PalbaseQrCodeOptions, aI as PalbaseQuerySnapshot, aJ as PalbaseRegisterDeviceParams, aK as PalbaseResult, aL as PalbaseRetentionQueryInput, aM as PalbaseRetentionResult, aN as PalbaseSession, aO as PalbaseSetOverrideResult, aP as PalbaseSetOverridesResult, aQ as PalbaseSignedUrlResponse, aR as PalbaseSmsClient, aS as PalbaseSmsSendParams, aT as PalbaseSmsSendResponse, aU as PalbaseTransformOptions, aV as PalbaseUpdateLinkParams, aW as PalbaseUploadOptions, aX as PalbaseUser, aY as PalbaseUserDetailResult, aZ as PalbaseUsersQueryInput, a_ as PalbaseUsersResult, a$ as PalbaseVerifyRequestSignatureParams, b0 as PalbaseWhereOperator, b1 as TooManyRequests, b2 as TxClient, b3 as Unauthorized, b4 as VerifiedDevice, b5 as defineMiddleware } from './endpoint-92kVepng.js';
3
3
  import { AsyncLocalStorage } from 'node:async_hooks';
4
- import { E as EnvTypedDatabase, S as SchemaDef } from './index-V0ealeY-.js';
5
- export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EnvServiceDatabase, f as EnvTables, g as EnvTypedTable, h as EnvTypedTx, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, o as SchemaInput, T as TableDef, p as TableInput, q as TypedDB, r as TypedTable, s as TypedTx, t as bigint, u as boolean, v as defineSchema, w as enumType, x as integer, y as isPalbaseExtension, z as jsonb, A as makeTypedDB, B as numeric, D as policy, F as raw, G as text, H as timestamp, J as uuid } from './index-V0ealeY-.js';
4
+ import { E as EnvTypedDatabase, S as SchemaDef } from './index-DfryIw9U.js';
5
+ export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EnvServiceDatabase, f as EnvTables, g as EnvTypedTable, h as EnvTypedTx, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, o as SchemaInput, T as TableDef, p as TableInput, q as TypedDB, r as TypedTable, s as TypedTx, t as bigint, u as boolean, v as defineSchema, w as enumType, x as integer, y as isPalbaseExtension, z as jsonb, A as makeTypedDB, B as numeric, D as policy, F as raw, G as text, H as timestamp, J as uuid } from './index-DfryIw9U.js';
6
+ import { EntitlementKey, LimitKey } from './purchases/keys.js';
6
7
  import { TableTypes, Tables } from './db/env.js';
7
8
  import { ZodTypeAny, z } from 'zod';
8
9
  export { z } from 'zod';
9
10
 
11
+ /**
12
+ * The purchases surface the decorators need, declared as a NARROW STRUCTURAL
13
+ * interface rather than an import of `@palstore/purchases`.
14
+ *
15
+ * `PurchasesClient` (palstore's `sk_` backend SDK) satisfies this shape as-is,
16
+ * so the runtime injects the real client with no adapter — but `@palbase/backend`
17
+ * itself gains no dependency on it. That matters: this package is published
18
+ * public and baked into the br-pod image from a tarball, so a dependency on an
19
+ * unpublished sibling would break `npm install palbase-backend.tgz`. It is also
20
+ * the pattern `withSpend` already uses for the same reason (`SpendCapableClient`
21
+ * in palstore's own spend.ts: "a narrow structural interface … so this file has
22
+ * no dependency on client.ts").
23
+ *
24
+ * The methods here are a SUBSET of `PurchasesClient` — only what the two
25
+ * decorators call. Grants, refunds, credits and customer-info reads stay off
26
+ * this interface: a tenant that wants them imports the palstore SDK directly.
27
+ */
28
+ /** Store environment a subject is fixed to. Mirrors `StoreEnv` in `@palstore/purchases`. */
29
+ type StoreEnv = "production" | "sandbox";
30
+ /** Quota/credit state carried by a 429. Mirrors `LimitState` in `@palstore/purchases`
31
+ * (SPEC-purchases-v1 §11) — re-declared, not imported, for the reason above. */
32
+ interface LimitState {
33
+ key: string;
34
+ scope: string;
35
+ window: string;
36
+ used: number;
37
+ reserved: number;
38
+ max: number;
39
+ remaining: number;
40
+ resetAt: string;
41
+ }
42
+ /** Options for one spend. `idempotencyKey` is required by the server (§9). */
43
+ interface SpendOptions {
44
+ /** Defaults to 1. */
45
+ count?: number;
46
+ idempotencyKey: string;
47
+ }
48
+ interface PurchasesService {
49
+ /** Map a tenant-side user reference to its palstore subject, creating one on
50
+ * first sight. Server-authoritative — the caller never names a subject. */
51
+ resolveSubject(input: {
52
+ userRef: string;
53
+ storeEnv: StoreEnv;
54
+ }): Promise<{
55
+ subjectId: string;
56
+ }>;
57
+ /** Resolve silently when `entitlementKey` is active for `subjectId`; throw
58
+ * `EntitlementRequiredError` otherwise. Consumes nothing. */
59
+ require(subjectId: string, entitlementKey: string): Promise<void>;
60
+ /** Reserve → run `handler` → commit on success, cancel on throw, always
61
+ * rethrowing the handler's own error. The whole reason the decorators are a
62
+ * thin layer: this lifecycle is already written and tested in palstore's SDK. */
63
+ withSpend<T>(subjectId: string, key: string, opts: SpendOptions, handler: () => Promise<T>): Promise<T>;
64
+ }
65
+
10
66
  /**
11
67
  * runtime.ts — request-scoped service singletons.
12
68
  *
@@ -66,6 +122,28 @@ interface RuntimeServices {
66
122
  Notifications: PalbaseNotificationsClient;
67
123
  Flags: PalbaseFlagsClient;
68
124
  Realtime: PalbaseRealtimeClient;
125
+ Purchases: PurchasesService;
126
+ }
127
+ /**
128
+ * The per-request ALS box.
129
+ *
130
+ * `runtime` is the service bundle. `userId` is the request's authenticated user
131
+ * id, written by the runtime immediately after it assembles the request object
132
+ * (worker.js: `requestALS.getStore().userId = pbReq.user?.id || null`) and
133
+ * `null` on an anonymous request. It was already being written there for the
134
+ * Flags client's auto-bind; declaring it here makes the existing contract typed
135
+ * instead of implicit, which is what lets `currentSubjectId()` read a
136
+ * server-owned identity rather than trusting anything the caller sent.
137
+ */
138
+ interface RequestStore {
139
+ runtime: RuntimeServices;
140
+ userId?: string | null;
141
+ /** This request's id (`req_…`), written by the runtime. Used as the spend
142
+ * idempotency scope when the caller supplied no `Idempotency-Key`. */
143
+ requestId?: string;
144
+ /** The caller's `Idempotency-Key` header, or `null` when absent. What makes a
145
+ * client's retry replay its first result instead of charging twice. */
146
+ idempotencyKey?: string | null;
69
147
  }
70
148
  /**
71
149
  * Per-request store. The persistent runtime runs each request inside
@@ -76,9 +154,7 @@ interface RuntimeServices {
76
154
  * instance across the one module instance — two ALS instances would silently
77
155
  * not see each other's stores. NOT part of the public author-facing API.
78
156
  */
79
- declare const __requestALS: AsyncLocalStorage<{
80
- runtime: RuntimeServices;
81
- }>;
157
+ declare const __requestALS: AsyncLocalStorage<RequestStore>;
82
158
  /** Install the live clients in the process-global fallback slot.
83
159
  *
84
160
  * Persistent-server requests should use {@link __runWithRuntime} instead; this
@@ -129,6 +205,15 @@ declare const Queue: QueueClient;
129
205
  declare const Log: Logger;
130
206
  /** Push / email / SMS / in-app notifications. */
131
207
  declare const Notifications: PalbaseNotificationsClient;
208
+ /**
209
+ * Palstore purchases (entitlements + quota/credit spend).
210
+ *
211
+ * Reached by handlers through the `@RequireEntitlement` / `@Spend` decorators
212
+ * rather than called directly in the common case; exposed as a singleton for
213
+ * the cases the decorators deliberately do not cover (a dynamic spend count,
214
+ * which must run BEFORE the billable side-effect).
215
+ */
216
+ declare const Purchases: PurchasesService;
132
217
  /**
133
218
  * Feature flags.
134
219
  *
@@ -161,11 +246,120 @@ declare const Flags: PalbaseFlagsClient;
161
246
  */
162
247
  declare const Realtime: PalbaseRealtimeClient;
163
248
 
249
+ /**
250
+ * `@RequireEntitlement` and `@Spend` — access and metering at the decorator
251
+ * level, so a controller method says what it costs instead of wiring it.
252
+ *
253
+ * TWO decorators, deliberately, because not every subscription is limit-based.
254
+ * Most products just say "pro users may call this" and consume nothing; a
255
+ * zero-count spend would express that badly and run the whole reserve/commit
256
+ * machine for no reason.
257
+ *
258
+ * @RequireEntitlement('pro') pure gate → 403, consumes nothing
259
+ * @Spend('bookCreate') consumption → 429 when exhausted
260
+ *
261
+ * ORDER IS FIXED, and not by where you wrote them. Both decorators record
262
+ * metadata and share ONE installed wrapper that always runs the entitlement
263
+ * gate before it reserves quota. Reserving for someone who is about to get a
264
+ * 403 is wasted work and a race window, so the source order of the two
265
+ * decorators cannot introduce it.
266
+ */
267
+
268
+ type MethodDecorator$2 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
269
+ /**
270
+ * Require an active entitlement. Answers 403 `entitlement_required` when it is
271
+ * absent and consumes nothing.
272
+ *
273
+ * The key is a member of the generated `EntitlementKey` union, so a typo is a
274
+ * compile error rather than a gate that silently never matches.
275
+ */
276
+ declare function RequireEntitlement(key: EntitlementKey): MethodDecorator$2;
277
+ /**
278
+ * Consume one unit of a limit or credit for the request's subject.
279
+ *
280
+ * Reserves before the handler runs and commits only if it returns; a throw
281
+ * cancels the hold, so a user is never charged for work that did not complete.
282
+ * Answers 429 `quota_exceeded` (carrying the `LimitState`) when exhausted.
283
+ *
284
+ * The count is fixed at 1. A DYNAMIC amount is deliberately not expressible
285
+ * here: it has to be decided inside the handler and spent BEFORE the billable
286
+ * side-effect, which is an explicit `Purchases.withSpend(...)` call, not a
287
+ * decorator.
288
+ */
289
+ declare function Spend(key: LimitKey): MethodDecorator$2;
290
+
291
+ /**
292
+ * keys-gen.ts — generate the `palbase-purchases.d.ts` text from a catalog
293
+ * manifest.
294
+ *
295
+ * The twin of `db/env-gen.ts`: the CLI / deploy pipeline calls
296
+ * {@link makePurchasesDts} with the project's catalog revision and writes the
297
+ * result to `palbase-purchases.d.ts` at the project root. That file augments
298
+ * the `@palbase/backend/purchases` `Entitlements` / `Limits` interfaces, so
299
+ * `@RequireEntitlement(...)` and `@Spend(...)` accept the project's real keys
300
+ * and nothing else.
301
+ *
302
+ * Same catalog, two languages: this is the TypeScript half of what swiftgen
303
+ * already emits for iOS. Neither side is hand-maintained, so the two cannot
304
+ * drift from each other or from the manifest the server validated.
305
+ *
306
+ * The emitted file ends in `export {};` — same as `makeEnvDts`. Without it the
307
+ * `.d.ts` is a global script, and `declare module "…"` there DECLARES an
308
+ * ambient module (shadowing the real one, so every key silently becomes
309
+ * invalid) instead of AUGMENTING it.
310
+ */
311
+ /** A catalog entry that may be tombstoned. */
312
+ interface Removable {
313
+ removed?: boolean;
314
+ }
315
+ /**
316
+ * The slice of `pur_catalogs.manifest` this generator reads. Deliberately
317
+ * partial and permissive: the server already validated the manifest (its models
318
+ * are `extra="forbid"`), so re-checking here would be a second, weaker copy of
319
+ * that authority.
320
+ */
321
+ interface PurchasesManifest {
322
+ limits?: Record<string, Removable>;
323
+ credits?: Record<string, Removable>;
324
+ entitlements?: Record<string, Removable>;
325
+ }
326
+ /**
327
+ * Render the project's `palbase-purchases.d.ts`.
328
+ *
329
+ * `Limits` carries BOTH limits and credits: `@Spend` consumes either, and the
330
+ * server answers both with a 429 (`quota_exceeded` / `credit_insufficient`), so
331
+ * splitting them into two unions would make the author pick the right decorator
332
+ * for a distinction the spend path does not make.
333
+ */
334
+ declare function makePurchasesDts(manifest: PurchasesManifest): string;
335
+
336
+ /**
337
+ * Per-method purchases metadata, stored on the controller class the same way
338
+ * `decorators/registry.ts` stores routes: a symbol-keyed static, plain data, no
339
+ * `reflect-metadata`.
340
+ *
341
+ * Its only consumer is the OpenAPI step, which needs to know that a route is
342
+ * gated (declare 403) or metered (declare 429) so the iOS client codegen emits
343
+ * TYPED errors instead of a bare status number. Enforcement does NOT read this
344
+ * — the decorators wrap the method directly — so a stale registry can never
345
+ * cause a missed gate.
346
+ */
347
+
348
+ /** What `@Spend` recorded for one method. */
349
+ interface SpendMeta {
350
+ key: LimitKey;
351
+ count: number;
352
+ }
353
+ /** The entitlement `fnName` is gated on, or undefined when it is not gated. */
354
+ declare function entitlementFor(ctor: object, fnName: string): EntitlementKey | undefined;
355
+ /** What `fnName` spends, or undefined when it spends nothing. */
356
+ declare function spendFor(ctor: object, fnName: string): SpendMeta | undefined;
357
+
164
358
  /**
165
359
  * env-gen.ts — generate the `palbase-env.d.ts` text from a `defineSchema()`
166
360
  * result.
167
361
  *
168
- * The CLI (`palbase serve` / codegen) and the deploy pipeline call
362
+ * The CLI (`palbase db types` / codegen) and the deploy pipeline call
169
363
  * {@link makeEnvDts} with the project's schema and write the returned string to
170
364
  * `palbase-env.d.ts` at the project root. That file AUGMENTS the
171
365
  * `@palbase/backend/env` `Tables` interface (controlled global augmentation,
@@ -1654,4 +1848,4 @@ declare const documents: {
1654
1848
  onDocumentDeleted(handler: HookHandler<DocumentDeletedEvent>): ResolvedHook<DocumentDeletedEvent>;
1655
1849
  };
1656
1850
 
1657
- export { type AcsOptions, type ApnsOptions, type BackoffStrategy, Body, type BucketDef, type BucketOptions, Cache, CacheClient, Client, Controller, type ControllerOptions, type CustomWebhookConfig, DBClient, Database, type DefinedError, type DefinedErrorWithData, Delete, type DocumentCreatedEvent, type DocumentDeletedEvent, type DocumentUpdatedEvent, Documents, EGRESS_CONFIG_KIND, type EgressConfig, type EgressInput, type EnvSecretRef, EnvTypedDatabase, FLAGS_CONFIG_KIND, type FcmOptions, type FileDeletedEvent, type FileUploadedEvent, type FlagDef, type FlagJsonObject, type FlagJsonValue, type FlagOptions, type FlagType, type FlagValue, Flags, type FlagsConfig, type FlagsInput, Get, Headers, type HookHandler, type HookMeta, HttpError, type HttpMethodUpper, type JobConfig, type JobMeta, Log, Logger, NOTIFICATIONS_CONFIG_KIND, Notifications, type NotificationsConfig, type NotificationsInput, OptionalUser, type OwnedTablesOf, PROVIDER_CATALOG, PalbaseDocsClient, PalbaseFlagsClient, PalbaseNotificationsClient, PalbaseRealtimeClient, PalbaseStorageClient, Param, type ParamKind, type ParamMeta, type PasswordResetEvent, Patch, Post, type ProviderCatalogEntry, type ProviderDef, type ProviderEventMap, type ProviderName, type ProviderOptions, type ProviderWebhookConfig, Put, Query, QueryParams, Queue, QueueClient, RESERVED_SECRET_PREFIX, RateLimitConfig, Realtime, type RegisteredError, Req, RequestId, type ResolvedCustomWebhook, type ResolvedHook, type ResolvedJobConfig, type ResolvedProviderWebhook, type ResolvedWebhookConfig, type ResolvedWorkerConfig, Resource, type ResourceEnv, type RouteMeta, type RouteOptions, type RuntimeServices, STORAGE_CONFIG_KIND, SchemaDef, type Seed, type SeedFor, type SeedJson, type SeedRowFor, type SendgridOptions, type SesOptions, type SignInEvent, type SignOutEvent, type SmtpOptions, Storage, type StorageConfig, type StorageInput, TEST_USERS_CONFIG_KIND, type TableGraph, TableTypes, Tables, type TestUserDef, type TestUserOptions, type TestUsersConfig, type TestUsersInput, type ThrowDescriptor, TraceId, type TwilioOptions, Upload, type UploadConfig, UploadedObject, User, type UserCreatedEvent, User$1 as UserT, type WebhookEventHandler, type WebhookMeta, type WebhookProvider, type WebhookRequest, type WorkerConfig, type WorkerMeta, __getRuntime, __registerResource, __requestALS, __runResourceBoot, __runWithRuntime, __setRuntime, __shutdownResources, auth, bucket, buildProvider, defineEgress, defineError, defineFlags, defineJob, defineNotifications, defineStorage, defineTestUsers, defineWebhook, defineWorker, documents, flag, getErrorRegistry, getRoutes, makeEnvDts, parseFileSizeLimit, recordThrows, reservedSecretKey, storage, testUser, validateUploadAgainstStorage };
1851
+ export { type AcsOptions, type ApnsOptions, type BackoffStrategy, Body, type BucketDef, type BucketOptions, Cache, CacheClient, Client, Controller, type ControllerOptions, type CustomWebhookConfig, DBClient, Database, type DefinedError, type DefinedErrorWithData, Delete, type DocumentCreatedEvent, type DocumentDeletedEvent, type DocumentUpdatedEvent, Documents, EGRESS_CONFIG_KIND, type EgressConfig, type EgressInput, EntitlementKey, type EnvSecretRef, EnvTypedDatabase, FLAGS_CONFIG_KIND, type FcmOptions, type FileDeletedEvent, type FileUploadedEvent, type FlagDef, type FlagJsonObject, type FlagJsonValue, type FlagOptions, type FlagType, type FlagValue, Flags, type FlagsConfig, type FlagsInput, Get, Headers, type HookHandler, type HookMeta, HttpError, type HttpMethodUpper, type JobConfig, type JobMeta, LimitKey, type LimitState, Log, Logger, NOTIFICATIONS_CONFIG_KIND, Notifications, type NotificationsConfig, type NotificationsInput, OptionalUser, type OwnedTablesOf, PROVIDER_CATALOG, PalbaseDocsClient, PalbaseFlagsClient, PalbaseNotificationsClient, PalbaseRealtimeClient, PalbaseStorageClient, Param, type ParamKind, type ParamMeta, type PasswordResetEvent, Patch, Post, type ProviderCatalogEntry, type ProviderDef, type ProviderEventMap, type ProviderName, type ProviderOptions, type ProviderWebhookConfig, Purchases, type PurchasesManifest, type PurchasesService, Put, Query, QueryParams, Queue, QueueClient, RESERVED_SECRET_PREFIX, RateLimitConfig, Realtime, type RegisteredError, Req, RequestId, type RequestStore, RequireEntitlement, type ResolvedCustomWebhook, type ResolvedHook, type ResolvedJobConfig, type ResolvedProviderWebhook, type ResolvedWebhookConfig, type ResolvedWorkerConfig, Resource, type ResourceEnv, type RouteMeta, type RouteOptions, type RuntimeServices, STORAGE_CONFIG_KIND, SchemaDef, type Seed, type SeedFor, type SeedJson, type SeedRowFor, type SendgridOptions, type SesOptions, type SignInEvent, type SignOutEvent, type SmtpOptions, Spend, type SpendMeta, type SpendOptions, Storage, type StorageConfig, type StorageInput, type StoreEnv, TEST_USERS_CONFIG_KIND, type TableGraph, TableTypes, Tables, type TestUserDef, type TestUserOptions, type TestUsersConfig, type TestUsersInput, type ThrowDescriptor, TraceId, type TwilioOptions, Upload, type UploadConfig, UploadedObject, User, type UserCreatedEvent, User$1 as UserT, type WebhookEventHandler, type WebhookMeta, type WebhookProvider, type WebhookRequest, type WorkerConfig, type WorkerMeta, __getRuntime, __registerResource, __requestALS, __runResourceBoot, __runWithRuntime, __setRuntime, __shutdownResources, auth, bucket, buildProvider, defineEgress, defineError, defineFlags, defineJob, defineNotifications, defineStorage, defineTestUsers, defineWebhook, defineWorker, documents, entitlementFor, flag, getErrorRegistry, getRoutes, makeEnvDts, makePurchasesDts, parseFileSizeLimit, recordThrows, reservedSecretKey, spendFor, storage, testUser, validateUploadAgainstStorage };