@palbase/backend 22.1.0 → 23.0.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/bin/palbase-backend.cjs +439 -18
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -4
- package/dist/{chunk-SQC5EIWY.js → chunk-FSGSB42K.js} +11 -6
- package/dist/chunk-FSGSB42K.js.map +1 -0
- package/dist/{chunk-I3ON7MYF.js → chunk-HAF67F2H.js} +73 -16
- package/dist/chunk-HAF67F2H.js.map +1 -0
- package/dist/{chunk-QMVK4X3V.js → chunk-OMRTHM4X.js} +98 -98
- package/dist/chunk-OMRTHM4X.js.map +1 -0
- package/dist/{chunk-74XDEF5J.js → chunk-REZU6UKT.js} +432 -17
- package/dist/chunk-REZU6UKT.js.map +1 -0
- package/dist/{chunk-YL4C5NRY.js → chunk-Y5HXVUMP.js} +2 -2
- package/dist/{chunk-N32VDWKH.js → chunk-ZC6Q2BRD.js} +4 -59
- package/dist/chunk-ZC6Q2BRD.js.map +1 -0
- package/dist/db/env.cjs.map +1 -1
- package/dist/db/env.d.cts +3 -21
- package/dist/db/env.d.ts +3 -21
- package/dist/db/index.cjs +72 -15
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +3 -2
- package/dist/db/index.d.ts +3 -2
- package/dist/db/index.js +1 -1
- package/dist/{endpoint-BVT6jcVW.d.cts → endpoint-BavvbW4P.d.ts} +77 -7
- package/dist/{endpoint-BVT6jcVW.d.ts → endpoint-i8TTCohk.d.cts} +77 -7
- package/dist/engine/index.cjs +439 -18
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +6 -5
- package/dist/engine/index.d.ts +6 -5
- package/dist/engine/index.js +3 -3
- package/dist/{index-vwHoS0l2.d.ts → index-B3jmmItD.d.ts} +111 -5
- package/dist/{index-CCZqzych.d.ts → index-B7YBEG5w.d.ts} +96 -71
- package/dist/{index-BqCiHao8.d.cts → index-Bmvx1EvJ.d.cts} +111 -5
- package/dist/{index-BS1gW4nV.d.cts → index-E7OscPJT.d.cts} +96 -71
- package/dist/index.cjs +285 -1099
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -1134
- package/dist/index.d.ts +89 -1134
- package/dist/index.js +107 -902
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +3 -57
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +3 -2
- package/dist/openapi/index.d.ts +3 -2
- package/dist/openapi/index.js +5 -22
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-Bsuf-orT.d.ts → registry-C3H2uPeZ.d.cts} +13 -169
- package/dist/{registry-BWttGlaT.d.cts → registry-DY3d9l1k.d.ts} +13 -169
- package/dist/{purchases/keys.cjs → stack.cjs} +4 -4
- package/dist/stack.cjs.map +1 -0
- package/dist/stack.d.cts +76 -0
- package/dist/stack.d.ts +76 -0
- package/dist/stack.js +1 -0
- package/docs/README.md +7 -6
- package/docs/llms-full.txt +7 -260
- package/docs/llms.txt +0 -2
- package/package.json +6 -6
- package/template/package.json +1 -1
- package/dist/chunk-74XDEF5J.js.map +0 -1
- package/dist/chunk-I3ON7MYF.js.map +0 -1
- package/dist/chunk-N32VDWKH.js.map +0 -1
- package/dist/chunk-QMVK4X3V.js.map +0 -1
- package/dist/chunk-SQC5EIWY.js.map +0 -1
- package/dist/purchases/keys.cjs.map +0 -1
- package/dist/purchases/keys.d.cts +0 -42
- package/dist/purchases/keys.d.ts +0 -42
- package/dist/purchases/keys.js +0 -1
- package/docs/config.md +0 -147
- package/docs/resources.md +0 -97
- package/template/config/secrets.ts +0 -24
- /package/dist/{chunk-YL4C5NRY.js.map → chunk-Y5HXVUMP.js.map} +0 -0
- /package/dist/{purchases/keys.js.map → stack.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,59 +1,17 @@
|
|
|
1
|
-
import { g as PalbaseResult, A as AuthSpec, H as HttpError } from './endpoint-
|
|
2
|
-
export { h as AuthConfig, B as BadRequest, C as CacheClient, i as ClientInfo, j as Conflict, D as DBClient, k as DBOps, E as ErrorDef, l as ErrorMap, m as ErrorThrowers, F as FileContext, n as Forbidden, o as HttpMethod, L as Logger, M as Materialized, p as Middleware, q as MiddlewareContext, r as MiddlewareHandler, N as NotFound, s as PBRequest, t as PalError, u as PalbaseAnalyticsClient, v as PalbaseAnalyticsManagementNamespace, w as PalbaseAnalyticsProperties, x as PalbaseAnalyticsQueryNamespace, y as PalbaseAttestAndroidParams, z as PalbaseAttestAndroidResult, G as PalbaseAttestiOSParams, I as PalbaseAttestiOSResult, J as PalbaseAuthClient, K as PalbaseBatchOverrideOperation, O as PalbaseBatchSetOverridesResult, Q as PalbaseBindDeviceParams, e as PalbaseBucketClient, U as PalbaseClearAllOverridesResult, V as PalbaseClearOverrideResult, W as PalbaseCohortQueryInput, X as PalbaseCohortResult, Y as PalbaseCollectionRef, Z as PalbaseCountQueryInput, _ as PalbaseCountResult, $ as PalbaseCreateLinkParams, a0 as PalbaseDeviceInfo, a1 as PalbaseDeviceTokenView, P as PalbaseDocsClient, a2 as PalbaseDocumentRef, a3 as PalbaseDocumentSnapshot, a4 as PalbaseEmailClient, a5 as PalbaseEmailSendParams, a6 as PalbaseEmailSendResponse, a7 as PalbaseEventNamesResult, a8 as PalbaseEventsQueryInput, a9 as PalbaseEventsResult, aa as PalbaseFileObject, ab as PalbaseFlag, ac as PalbaseFlagContext, ad as PalbaseFlagSource, ae as PalbaseFlagValue, af as PalbaseFlagVariant, a as PalbaseFlagsClient, ag as PalbaseFlagsServiceClient, ah as PalbaseFunctionsClient, ai as PalbaseFunnelQueryInput, aj as PalbaseFunnelResult, ak as PalbaseIdentifyTraits, al as PalbaseInboxClient, am as PalbaseInboxListOptions, an as PalbaseInboxListResult, ao as PalbaseInboxMessage, ap as PalbaseInboxSendParams, aq as PalbaseInboxSendResponse, ar as PalbaseInitialLink, as as PalbaseInvokeOptions, at as PalbaseLink, au as PalbaseLinkAnalytics, av as PalbaseLinkDetails, aw as PalbaseLinksClient, ax as PalbaseListLinksOptions, ay as PalbaseListLinksResult, az as PalbaseListOptions, aA as PalbaseMatchParams, aB as PalbaseMultiChannelResponse, b as PalbaseNotificationsClient, aC as PalbaseOverviewResult, aD as PalbasePreferences, aE as PalbasePreferencesClient, aF as PalbasePushClient, aG as PalbasePushSendParams, aH as PalbasePushSendResponse, aI as PalbaseQrCodeOptions, aJ as PalbaseQuerySnapshot, c as PalbaseRealtimeClient, aK as PalbaseRegisterDeviceParams, 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, d as PalbaseStorageClient, 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, R as RateLimitConfig, b1 as Ref, S as SecretsService, b2 as TooManyRequests, b3 as TxColumnExpr, b4 as TxInsertShape, b5 as TxInsertValue, b6 as TxNow, T as TxPlanBody, b7 as TxPlanError, b8 as TxPlanHandle, b9 as TxPlanOpResult, ba as TxPlanRejection, f as TxPlanResponse, bb as TxRefError, bc as TxRow, bd as TxRows, be as TxSelectOptions, bf as TxSetShape, bg as TxSetValue, bh as TxTable, bi as TxWhere, bj as TxWireExpr, bk as TxWireGuard, bl as TxWireOp, bm as TxWireRef, bn as TxWireValue, bo as Unauthorized, bp as UserT, bq as VerifiedDevice, br as dec, bs as defineMiddleware, bt as inc, bu as now } from './endpoint-
|
|
3
|
-
import { M as ModuleClients } from './index-
|
|
4
|
-
export { C as Cache, D as Database, a as Documents, F as Flags, L as
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
|
|
9
|
-
import { a as RouteOptions } from './registry-
|
|
10
|
-
export {
|
|
1
|
+
import { g as PalbaseResult, A as AuthSpec, H as HttpError } from './endpoint-i8TTCohk.cjs';
|
|
2
|
+
export { h as AuthConfig, B as BadRequest, C as CacheClient, i as ClientInfo, j as Conflict, D as DBClient, k as DBOps, E as ErrorDef, l as ErrorMap, m as ErrorThrowers, F as FileContext, n as Forbidden, o as HttpMethod, L as Logger, M as Materialized, p as Middleware, q as MiddlewareContext, r as MiddlewareHandler, N as NotFound, s as PBRequest, t as PalError, u as PalbaseAnalyticsClient, v as PalbaseAnalyticsManagementNamespace, w as PalbaseAnalyticsProperties, x as PalbaseAnalyticsQueryNamespace, y as PalbaseAttestAndroidParams, z as PalbaseAttestAndroidResult, G as PalbaseAttestiOSParams, I as PalbaseAttestiOSResult, J as PalbaseAuthClient, K as PalbaseBatchOverrideOperation, O as PalbaseBatchSetOverridesResult, Q as PalbaseBindDeviceParams, e as PalbaseBucketClient, U as PalbaseClearAllOverridesResult, V as PalbaseClearOverrideResult, W as PalbaseCohortQueryInput, X as PalbaseCohortResult, Y as PalbaseCollectionRef, Z as PalbaseCountQueryInput, _ as PalbaseCountResult, $ as PalbaseCreateLinkParams, a0 as PalbaseDeviceInfo, a1 as PalbaseDeviceTokenView, P as PalbaseDocsClient, a2 as PalbaseDocumentRef, a3 as PalbaseDocumentSnapshot, a4 as PalbaseEmailClient, a5 as PalbaseEmailSendParams, a6 as PalbaseEmailSendResponse, a7 as PalbaseEventNamesResult, a8 as PalbaseEventsQueryInput, a9 as PalbaseEventsResult, aa as PalbaseFileObject, ab as PalbaseFlag, ac as PalbaseFlagContext, ad as PalbaseFlagSource, ae as PalbaseFlagValue, af as PalbaseFlagVariant, a as PalbaseFlagsClient, ag as PalbaseFlagsServiceClient, ah as PalbaseFunctionsClient, ai as PalbaseFunnelQueryInput, aj as PalbaseFunnelResult, ak as PalbaseIdentifyTraits, al as PalbaseInboxClient, am as PalbaseInboxListOptions, an as PalbaseInboxListResult, ao as PalbaseInboxMessage, ap as PalbaseInboxSendParams, aq as PalbaseInboxSendResponse, ar as PalbaseInitialLink, as as PalbaseInvokeOptions, at as PalbaseLink, au as PalbaseLinkAnalytics, av as PalbaseLinkDetails, aw as PalbaseLinksClient, ax as PalbaseListLinksOptions, ay as PalbaseListLinksResult, az as PalbaseListOptions, aA as PalbaseMatchParams, aB as PalbaseMultiChannelResponse, b as PalbaseNotificationsClient, aC as PalbaseOverviewResult, aD as PalbasePreferences, aE as PalbasePreferencesClient, aF as PalbasePushClient, aG as PalbasePushSendParams, aH as PalbasePushSendResponse, aI as PalbaseQrCodeOptions, aJ as PalbaseQuerySnapshot, c as PalbaseRealtimeClient, aK as PalbaseRegisterDeviceParams, 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, d as PalbaseStorageClient, 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, R as RateLimitConfig, b1 as Ref, S as SecretsService, b2 as TooManyRequests, b3 as TxColumnExpr, b4 as TxInsertShape, b5 as TxInsertValue, b6 as TxNow, T as TxPlanBody, b7 as TxPlanError, b8 as TxPlanHandle, b9 as TxPlanOpResult, ba as TxPlanRejection, f as TxPlanResponse, bb as TxRefError, bc as TxRow, bd as TxRows, be as TxSelectOptions, bf as TxSetShape, bg as TxSetValue, bh as TxTable, bi as TxWhere, bj as TxWireExpr, bk as TxWireGuard, bl as TxWireOp, bm as TxWireRef, bn as TxWireValue, bo as Unauthorized, bp as UserT, bq as VerifiedDevice, br as dec, bs as defineMiddleware, bt as inc, bu as now } from './endpoint-i8TTCohk.cjs';
|
|
3
|
+
import { M as ModuleClients } from './index-E7OscPJT.cjs';
|
|
4
|
+
export { C as Cache, D as Database, a as Documents, F as Flags, L as Log, N as Notifications, R as Realtime, b as RequestStore, c as RuntimeServices, S as Secrets, d as Storage, _ as __getRuntime, e as __requestALS, f as __runWithRuntime, g as __setRuntime } from './index-E7OscPJT.cjs';
|
|
5
|
+
import { S as SchemaDef } from './index-Bmvx1EvJ.cjs';
|
|
6
|
+
export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, f as EnvServiceDatabase, g as EnvTables, E as EnvTypedDatabase, h as EnvTypedTable, 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 TxPlan, r as TxTables, s as TypedDB, t as TypedTable, u as TypedTx, v as bigint, w as boolean, x as defineSchema, y as enumType, z as integer, A as isPalbaseExtension, B as jsonb, D as makeTypedDB, F as numeric, G as openai, H as policy, J as raw, K as text, L as timestamp, M as uuid, N as vector } from './index-Bmvx1EvJ.cjs';
|
|
7
|
+
export { TableTypes, Tables } from './db/env.cjs';
|
|
8
|
+
export { PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName } from './stack.cjs';
|
|
9
|
+
import { a as RouteOptions } from './registry-C3H2uPeZ.cjs';
|
|
10
|
+
export { H as HttpMethodUpper, b as ParamKind, P as ParamMeta, R as RouteMeta, T as ThrowDescriptor, c as Upload, U as UploadConfig, d as UploadedObject, g as getRoutes, r as recordThrows } from './registry-C3H2uPeZ.cjs';
|
|
11
11
|
import { ZodTypeAny, z } from 'zod';
|
|
12
12
|
export { z } from 'zod';
|
|
13
13
|
import 'node:async_hooks';
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* `@RequireEntitlement` and `@Spend` — access and metering at the decorator
|
|
17
|
-
* level, so a controller method says what it costs instead of wiring it.
|
|
18
|
-
*
|
|
19
|
-
* TWO decorators, deliberately, because not every subscription is limit-based.
|
|
20
|
-
* Most products just say "pro users may call this" and consume nothing; a
|
|
21
|
-
* zero-count spend would express that badly and run the whole reserve/commit
|
|
22
|
-
* machine for no reason.
|
|
23
|
-
*
|
|
24
|
-
* @RequireEntitlement('pro') pure gate → 403, consumes nothing
|
|
25
|
-
* @Spend('bookCreate') consumption → 429 when exhausted
|
|
26
|
-
*
|
|
27
|
-
* ORDER IS FIXED, and not by where you wrote them. Both decorators record
|
|
28
|
-
* metadata and share ONE installed wrapper that always runs the entitlement
|
|
29
|
-
* gate before it reserves quota. Reserving for someone who is about to get a
|
|
30
|
-
* 403 is wasted work and a race window, so the source order of the two
|
|
31
|
-
* decorators cannot introduce it.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
type MethodDecorator$1 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
|
|
35
|
-
/**
|
|
36
|
-
* Require an active entitlement. Answers 403 `entitlement_required` when it is
|
|
37
|
-
* absent and consumes nothing.
|
|
38
|
-
*
|
|
39
|
-
* The key is a member of the generated `EntitlementKey` union, so a typo is a
|
|
40
|
-
* compile error rather than a gate that silently never matches.
|
|
41
|
-
*/
|
|
42
|
-
declare function RequireEntitlement(key: EntitlementKey): MethodDecorator$1;
|
|
43
|
-
/**
|
|
44
|
-
* Consume one unit of a limit or credit for the request's subject.
|
|
45
|
-
*
|
|
46
|
-
* Reserves before the handler runs and commits only if it returns; a throw
|
|
47
|
-
* cancels the hold, so a user is never charged for work that did not complete.
|
|
48
|
-
* Answers 429 `quota_exceeded` (carrying the `LimitState`) when exhausted.
|
|
49
|
-
*
|
|
50
|
-
* The count is fixed at 1. A DYNAMIC amount is deliberately not expressible
|
|
51
|
-
* here: it has to be decided inside the handler and spent BEFORE the billable
|
|
52
|
-
* side-effect, which is an explicit `Purchases.withSpend(...)` call, not a
|
|
53
|
-
* decorator.
|
|
54
|
-
*/
|
|
55
|
-
declare function Spend(key: LimitKey): MethodDecorator$1;
|
|
56
|
-
|
|
57
15
|
/**
|
|
58
16
|
* clients/index.ts — the composition root for the module clients.
|
|
59
17
|
*
|
|
@@ -66,10 +24,13 @@ declare function Spend(key: LimitKey): MethodDecorator$1;
|
|
|
66
24
|
* for any of them (`runtime.ts` exports ten, and these four are not among
|
|
67
25
|
* them), so no handler could reach them. They were constructed on every
|
|
68
26
|
* boot and thrown away.
|
|
69
|
-
* - `Purchases` — its client
|
|
27
|
+
* - `Purchases` — its client talked to palstore, and v2 contains no palstore
|
|
70
28
|
* at all. The surface was unbacked before it was untyped. Dropped from v2
|
|
71
|
-
* by the user's decision on 2026-08-15
|
|
72
|
-
*
|
|
29
|
+
* by the user's decision on 2026-08-15, with the SDK's `src/purchases/`
|
|
30
|
+
* tree left in place because that decision was "deferred, not silently
|
|
31
|
+
* taken". It is taken now: the tree is GONE (2026-08-29), because a
|
|
32
|
+
* decorator standing in front of a service nothing serves is the same
|
|
33
|
+
* defect as `Resource` and `config/*`, which went with it.
|
|
73
34
|
* - The V1 host/executor transport — the isolate it existed for was removed
|
|
74
35
|
* on 2026-08-14. A single-tenant process has nobody to hide its own
|
|
75
36
|
* tenant's credentials from.
|
|
@@ -167,73 +128,6 @@ declare class PalbaseModuleError extends Error {
|
|
|
167
128
|
}
|
|
168
129
|
declare function makeHttpClient(cfg: TransportConfig): ModuleTransport;
|
|
169
130
|
|
|
170
|
-
/**
|
|
171
|
-
* keys-gen.ts — generate the `palbase-purchases.d.ts` text from a catalog
|
|
172
|
-
* manifest.
|
|
173
|
-
*
|
|
174
|
-
* The twin of `db/env-gen.ts`: the CLI / deploy pipeline calls
|
|
175
|
-
* {@link makePurchasesDts} with the project's catalog revision and writes the
|
|
176
|
-
* result to `palbase-purchases.d.ts` at the project root. That file augments
|
|
177
|
-
* the `@palbase/backend/purchases` `Entitlements` / `Limits` interfaces, so
|
|
178
|
-
* `@RequireEntitlement(...)` and `@Spend(...)` accept the project's real keys
|
|
179
|
-
* and nothing else.
|
|
180
|
-
*
|
|
181
|
-
* Same catalog, two languages: this is the TypeScript half of what swiftgen
|
|
182
|
-
* already emits for iOS. Neither side is hand-maintained, so the two cannot
|
|
183
|
-
* drift from each other or from the manifest the server validated.
|
|
184
|
-
*
|
|
185
|
-
* The emitted file ends in `export {};` — same as `makeEnvDts`. Without it the
|
|
186
|
-
* `.d.ts` is a global script, and `declare module "…"` there DECLARES an
|
|
187
|
-
* ambient module (shadowing the real one, so every key silently becomes
|
|
188
|
-
* invalid) instead of AUGMENTING it.
|
|
189
|
-
*/
|
|
190
|
-
/** A catalog entry that may be tombstoned. */
|
|
191
|
-
interface Removable {
|
|
192
|
-
removed?: boolean;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* The slice of `pur_catalogs.manifest` this generator reads. Deliberately
|
|
196
|
-
* partial and permissive: the server already validated the manifest (its models
|
|
197
|
-
* are `extra="forbid"`), so re-checking here would be a second, weaker copy of
|
|
198
|
-
* that authority.
|
|
199
|
-
*/
|
|
200
|
-
interface PurchasesManifest {
|
|
201
|
-
limits?: Record<string, Removable>;
|
|
202
|
-
credits?: Record<string, Removable>;
|
|
203
|
-
entitlements?: Record<string, Removable>;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Render the project's `palbase-purchases.d.ts`.
|
|
207
|
-
*
|
|
208
|
-
* `Limits` carries BOTH limits and credits: `@Spend` consumes either, and the
|
|
209
|
-
* server answers both with a 429 (`quota_exceeded` / `credit_insufficient`), so
|
|
210
|
-
* splitting them into two unions would make the author pick the right decorator
|
|
211
|
-
* for a distinction the spend path does not make.
|
|
212
|
-
*/
|
|
213
|
-
declare function makePurchasesDts(manifest: PurchasesManifest): string;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Per-method purchases metadata, stored on the controller class the same way
|
|
217
|
-
* `decorators/registry.ts` stores routes: a symbol-keyed static, plain data, no
|
|
218
|
-
* `reflect-metadata`.
|
|
219
|
-
*
|
|
220
|
-
* Its only consumer is the OpenAPI step, which needs to know that a route is
|
|
221
|
-
* gated (declare 403) or metered (declare 429) so the iOS client codegen emits
|
|
222
|
-
* TYPED errors instead of a bare status number. Enforcement does NOT read this
|
|
223
|
-
* — the decorators wrap the method directly — so a stale registry can never
|
|
224
|
-
* cause a missed gate.
|
|
225
|
-
*/
|
|
226
|
-
|
|
227
|
-
/** What `@Spend` recorded for one method. */
|
|
228
|
-
interface SpendMeta {
|
|
229
|
-
key: LimitKey;
|
|
230
|
-
count: number;
|
|
231
|
-
}
|
|
232
|
-
/** The entitlement `fnName` is gated on, or undefined when it is not gated. */
|
|
233
|
-
declare function entitlementFor(ctor: object, fnName: string): EntitlementKey | undefined;
|
|
234
|
-
/** What `fnName` spends, or undefined when it spends nothing. */
|
|
235
|
-
declare function spendFor(ctor: object, fnName: string): SpendMeta | undefined;
|
|
236
|
-
|
|
237
131
|
/** One column, flattened. Mirrors Go's `schema.ColumnJSON`. */
|
|
238
132
|
interface ColumnJSON {
|
|
239
133
|
type: string;
|
|
@@ -287,13 +181,27 @@ interface TableJSON {
|
|
|
287
181
|
columns: string[];
|
|
288
182
|
}[];
|
|
289
183
|
search?: SearchJSON;
|
|
184
|
+
memory?: MemoryJSON;
|
|
185
|
+
}
|
|
186
|
+
/** C-11 wire şekli — Go'nun MemoryJSON'ıyla alan-adı sözleşmesi (D-019).
|
|
187
|
+
* Beyansız tablolarda alan OMIT — eski şemalar bayt-aynı (NFR-B1). */
|
|
188
|
+
interface MemoryJSON {
|
|
189
|
+
from: string[];
|
|
190
|
+
into: string;
|
|
191
|
+
subject?: string;
|
|
192
|
+
extract: {
|
|
193
|
+
provider: string;
|
|
194
|
+
model: string;
|
|
195
|
+
};
|
|
290
196
|
}
|
|
291
197
|
/** A whole declaration. Mirrors Go's `schema.SchemaJSON`. */
|
|
292
198
|
interface SchemaJSON {
|
|
293
199
|
tables: Record<string, TableJSON>;
|
|
294
200
|
extensions: string[];
|
|
295
201
|
}
|
|
296
|
-
/** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).
|
|
202
|
+
/** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).
|
|
203
|
+
* `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);
|
|
204
|
+
* satır-modu ve eski biçim bayt-aynı kalır (NFR-B1). */
|
|
297
205
|
interface SearchJSON {
|
|
298
206
|
text?: {
|
|
299
207
|
columns: string[];
|
|
@@ -310,7 +218,17 @@ interface SearchJSON {
|
|
|
310
218
|
baseURL?: string;
|
|
311
219
|
};
|
|
312
220
|
staleness?: "null" | "keep";
|
|
221
|
+
mode?: "row" | "chunks";
|
|
222
|
+
chunks?: {
|
|
223
|
+
sizeChars?: number;
|
|
224
|
+
overlapChars?: number;
|
|
225
|
+
};
|
|
313
226
|
}[];
|
|
227
|
+
/** FR-026: sorgu-yeniden-yazımı haritası — beyan yoksa OMIT (NFR-B1). */
|
|
228
|
+
synonyms?: Record<string, string[]>;
|
|
229
|
+
/** C-1: sonuç yeniden-sıralama beyanı — beyan yoksa OMIT. */
|
|
230
|
+
/** FR-029: geçerlilik türevleri — beyan yoksa OMIT. */
|
|
231
|
+
validity?: boolean;
|
|
314
232
|
}
|
|
315
233
|
/**
|
|
316
234
|
* Serialize a `defineSchema(...)` result into the JSON the deploy applies.
|
|
@@ -442,931 +360,60 @@ declare function defineChannels(map: ChannelsInput): ChannelsDef;
|
|
|
442
360
|
declare function makeEnvDts(schema: SchemaDef): string;
|
|
443
361
|
|
|
444
362
|
/**
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
*
|
|
473
|
-
* Response bodies are BUFFERED whole (5 MB cap) before your fetch() resolves, so
|
|
474
|
-
* a streaming/SSE upstream gives you no partial output and no earlier
|
|
475
|
-
* first-byte: the entire stream must complete inside `timeoutMs`.
|
|
476
|
-
*
|
|
477
|
-
* Emits: { __config: "egress", hosts: [...], timeoutMs?: number }
|
|
478
|
-
*/
|
|
479
|
-
/** The discriminant written under `__config` so the deploy eval knows the kind. */
|
|
480
|
-
declare const EGRESS_CONFIG_KIND: "egress";
|
|
481
|
-
/**
|
|
482
|
-
* Bounds on `timeoutMs`, duplicated (deliberately) in the deploy's
|
|
483
|
-
* ParseEgressConfig. This copy shapes the authoring error; that one is
|
|
484
|
-
* authoritative and fail-closed. They must agree — a value this accepts and the
|
|
485
|
-
* deploy rejects is a broken deploy the author cannot see coming.
|
|
486
|
-
*/
|
|
487
|
-
declare const EGRESS_TIMEOUT_MIN_MS = 1000;
|
|
488
|
-
declare const EGRESS_TIMEOUT_MAX_MS = 300000;
|
|
489
|
-
/** Applied when `timeoutMs` is omitted. Also spelled in the isolate capability. */
|
|
490
|
-
declare const EGRESS_TIMEOUT_DEFAULT_MS = 30000;
|
|
491
|
-
/** The author-facing input to defineEgress. */
|
|
492
|
-
interface EgressInput {
|
|
493
|
-
hosts: string[];
|
|
494
|
-
/**
|
|
495
|
-
* Per-call ceiling for an outbound fetch, in milliseconds.
|
|
496
|
-
* 1_000..300_000; omitted ⇒ 30_000.
|
|
497
|
-
*/
|
|
498
|
-
timeoutMs?: number;
|
|
499
|
-
}
|
|
500
|
-
/** The evaluated config/egress.ts default export (what the deploy reads). */
|
|
501
|
-
interface EgressConfig {
|
|
502
|
-
__config: typeof EGRESS_CONFIG_KIND;
|
|
503
|
-
hosts: string[];
|
|
504
|
-
timeoutMs?: number;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Declare the backend's outbound-HTTP allowlist. Client-side this only shapes +
|
|
508
|
-
* validates the list; the authoritative fail-closed validation runs at deploy.
|
|
509
|
-
*/
|
|
510
|
-
declare function defineEgress(input: EgressInput): EgressConfig;
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* notifications.ts — the notification-providers config-as-code DSL.
|
|
514
|
-
*
|
|
515
|
-
* `defineNotifications({ push, email, sms })` is the second MODULE config-as-code
|
|
516
|
-
* surface (the sibling of `config/storage.ts`'s `defineStorage`). A
|
|
517
|
-
* `config/notifications.ts` file default-exports a `defineNotifications(...)`
|
|
518
|
-
* result; on deploy the br-pod evaluates it to JSON and reconciles the declared
|
|
519
|
-
* providers against the tenant's live providers via the PalNotify admin API
|
|
520
|
-
* (create missing; never auto-delete — dropping a provider is destructive and
|
|
521
|
-
* warned only).
|
|
522
|
-
*
|
|
523
|
-
* SECRETS ARE NEVER IN THE FILE. Each provider's NON-SECRET fields (team id, key
|
|
524
|
-
* id, bundle id, region, host, port, from address, account sid, …) are literals
|
|
525
|
-
* in the config. Each provider's SECRET material (the APNs .p8 key, the FCM
|
|
526
|
-
* service-account JSON, an api_key, an auth token, the SMTP/ACS password, …) is
|
|
527
|
-
* NOT a field here — it is bound BY CONVENTION to a RESERVED encrypted env var
|
|
528
|
-
* and resolved at deploy from control-pg. The env-key convention is:
|
|
529
|
-
*
|
|
530
|
-
* PB_NOTIFICATIONS_<PROVIDER>_<FIELD> (UPPER_SNAKE_CASE)
|
|
531
|
-
*
|
|
532
|
-
* e.g. `PB_NOTIFICATIONS_APNS_P8`, `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`,
|
|
533
|
-
* `PB_NOTIFICATIONS_TWILIO_AUTH_TOKEN`. The `PB_` namespace is reserved (the CLI
|
|
534
|
-
* refuses a hand-set `palbase secret set PB_*`); the CLI's `palbase notifications
|
|
535
|
-
* add <provider>` derives the key and uploads the secret for you, so an author
|
|
536
|
-
* never types either the secret or the env-key name into git.
|
|
537
|
-
*
|
|
538
|
-
* @example
|
|
539
|
-
* import { defineNotifications } from "@palbase/backend";
|
|
540
|
-
*
|
|
541
|
-
* export default defineNotifications({
|
|
542
|
-
* push: {
|
|
543
|
-
* apns: { enabled: true, teamId: "ABCDE12345", keyId: "KEY1234567", bundleId: "com.acme.app" },
|
|
544
|
-
* fcm: { enabled: true },
|
|
545
|
-
* },
|
|
546
|
-
* email: {
|
|
547
|
-
* sendgrid: { enabled: true, fromDomain: "mail.acme.com" },
|
|
548
|
-
* },
|
|
549
|
-
* sms: {
|
|
550
|
-
* twilio: { enabled: true, accountSid: "ACxxxxxxxx", messagingServiceSid: "MGxxxxxxxx" },
|
|
551
|
-
* },
|
|
552
|
-
* });
|
|
553
|
-
*
|
|
554
|
-
* The returned value is the EXACT JSON shape the runtime's generic config
|
|
555
|
-
* extractor (`config_extract.js`) emits and the Go apply step parses:
|
|
556
|
-
* { __config: "notifications", push: {...}, email: {...}, sms: {...} }
|
|
557
|
-
* Only ENABLED providers carry their non-secret fields; a disabled (or absent)
|
|
558
|
-
* provider serializes as `{ enabled: false }` so the apply step skips it.
|
|
559
|
-
*/
|
|
560
|
-
/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is
|
|
561
|
-
* a notifications config. Notifications is `"notifications"`. */
|
|
562
|
-
declare const NOTIFICATIONS_CONFIG_KIND: "notifications";
|
|
563
|
-
/** The reserved env-var prefix that backs provider secrets. A `palbase secret
|
|
564
|
-
* set` of a key under this prefix is REFUSED by the CLI (it is managed by
|
|
565
|
-
* `palbase notifications add`). Both the CLI and the br-pod apply step derive a
|
|
566
|
-
* provider's secret env key as `${RESERVED_SECRET_PREFIX}_<PROVIDER>_<FIELD>`. */
|
|
567
|
-
declare const RESERVED_SECRET_PREFIX: "PB_NOTIFICATIONS";
|
|
568
|
-
/** One provider's catalog entry: which non-secret fields are required, which are
|
|
569
|
-
* optional, and which secret field-name(s) bind to reserved env vars. */
|
|
570
|
-
interface ProviderCatalogEntry {
|
|
571
|
-
/** The channel this provider serves (`push` | `email` | `sms`). */
|
|
572
|
-
readonly channel: "push" | "email" | "sms";
|
|
573
|
-
/** Non-secret config fields the author MUST supply (validated eagerly). */
|
|
574
|
-
readonly required: readonly string[];
|
|
575
|
-
/** Non-secret config fields the author MAY supply. */
|
|
576
|
-
readonly optional: readonly string[];
|
|
577
|
-
/** Secret field name(s) — each backed by `PB_NOTIFICATIONS_<PROVIDER>_<FIELD>`
|
|
578
|
-
* (FIELD is the UPPER_SNAKE of the name here). NOT a config field. */
|
|
579
|
-
readonly secrets: readonly string[];
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* The provider catalog: provider key → fields. The non-secret field names are
|
|
583
|
-
* the camelCase keys an author writes in `config/notifications.ts`; the secret
|
|
584
|
-
* names are the snake-ish tokens that become the reserved env-var suffix.
|
|
585
|
-
*
|
|
586
|
-
* apns: team_id / key_id / bundle_id (+ optional is_production); secret = p8.
|
|
587
|
-
* fcm: no non-secret fields; secret = service_account (the full JSON).
|
|
588
|
-
* sendgrid: from_domain; secret = api_key.
|
|
589
|
-
* ses: region / from_domain / access_key_id; secret = secret_access_key.
|
|
590
|
-
* smtp: host / port / from_email (+ optional username, use_starttls); secret = password.
|
|
591
|
-
* acs: from_email (+ optional from_name); secret = connection_string.
|
|
592
|
-
* twilio: account_sid + (from_number OR messaging_service_sid); secret = auth_token.
|
|
593
|
-
*/
|
|
594
|
-
declare const PROVIDER_CATALOG: {
|
|
595
|
-
readonly apns: {
|
|
596
|
-
readonly channel: "push";
|
|
597
|
-
readonly required: readonly ["teamId", "keyId", "bundleId"];
|
|
598
|
-
readonly optional: readonly ["isProduction"];
|
|
599
|
-
readonly secrets: readonly ["p8"];
|
|
600
|
-
};
|
|
601
|
-
readonly fcm: {
|
|
602
|
-
readonly channel: "push";
|
|
603
|
-
readonly required: readonly [];
|
|
604
|
-
readonly optional: readonly [];
|
|
605
|
-
readonly secrets: readonly ["serviceAccount"];
|
|
606
|
-
};
|
|
607
|
-
readonly sendgrid: {
|
|
608
|
-
readonly channel: "email";
|
|
609
|
-
readonly required: readonly ["fromDomain"];
|
|
610
|
-
readonly optional: readonly [];
|
|
611
|
-
readonly secrets: readonly ["apiKey"];
|
|
612
|
-
};
|
|
613
|
-
readonly ses: {
|
|
614
|
-
readonly channel: "email";
|
|
615
|
-
readonly required: readonly ["region", "accessKeyId", "fromDomain"];
|
|
616
|
-
readonly optional: readonly [];
|
|
617
|
-
readonly secrets: readonly ["secretAccessKey"];
|
|
618
|
-
};
|
|
619
|
-
readonly smtp: {
|
|
620
|
-
readonly channel: "email";
|
|
621
|
-
readonly required: readonly ["host", "port", "fromEmail"];
|
|
622
|
-
readonly optional: readonly ["username", "useStarttls"];
|
|
623
|
-
readonly secrets: readonly ["password"];
|
|
624
|
-
};
|
|
625
|
-
readonly acs: {
|
|
626
|
-
readonly channel: "email";
|
|
627
|
-
readonly required: readonly ["fromEmail"];
|
|
628
|
-
readonly optional: readonly ["fromName"];
|
|
629
|
-
readonly secrets: readonly ["connectionString"];
|
|
630
|
-
};
|
|
631
|
-
readonly twilio: {
|
|
632
|
-
readonly channel: "sms";
|
|
633
|
-
readonly required: readonly ["accountSid"];
|
|
634
|
-
readonly optional: readonly ["fromNumber", "messagingServiceSid"];
|
|
635
|
-
readonly secrets: readonly ["authToken"];
|
|
636
|
-
};
|
|
637
|
-
};
|
|
638
|
-
/** A provider key (`"apns" | "fcm" | "sendgrid" | …`). */
|
|
639
|
-
type ProviderName = keyof typeof PROVIDER_CATALOG;
|
|
640
|
-
/** APNs (Apple Push) — non-secret fields. The `.p8` key is the reserved secret
|
|
641
|
-
* `PB_NOTIFICATIONS_APNS_P8` (uploaded via `palbase notifications add apns`). */
|
|
642
|
-
interface ApnsOptions {
|
|
643
|
-
enabled?: boolean;
|
|
644
|
-
teamId: string;
|
|
645
|
-
keyId: string;
|
|
646
|
-
bundleId: string;
|
|
647
|
-
/** APNs production gateway vs sandbox. Defaults to true (production). */
|
|
648
|
-
isProduction?: boolean;
|
|
649
|
-
}
|
|
650
|
-
/** FCM (Firebase Cloud Messaging) — no non-secret fields; the service-account
|
|
651
|
-
* JSON is the reserved secret `PB_NOTIFICATIONS_FCM_SERVICE_ACCOUNT`. */
|
|
652
|
-
interface FcmOptions {
|
|
653
|
-
enabled?: boolean;
|
|
654
|
-
}
|
|
655
|
-
/** SendGrid email — non-secret `fromDomain`; api_key is the reserved secret. */
|
|
656
|
-
interface SendgridOptions {
|
|
657
|
-
enabled?: boolean;
|
|
658
|
-
fromDomain: string;
|
|
659
|
-
}
|
|
660
|
-
/** Amazon SES email — secret_access_key is the reserved secret. */
|
|
661
|
-
interface SesOptions {
|
|
662
|
-
enabled?: boolean;
|
|
663
|
-
region: string;
|
|
664
|
-
accessKeyId: string;
|
|
665
|
-
fromDomain: string;
|
|
666
|
-
}
|
|
667
|
-
/** SMTP email — password is the reserved secret. */
|
|
668
|
-
interface SmtpOptions {
|
|
669
|
-
enabled?: boolean;
|
|
670
|
-
host: string;
|
|
671
|
-
port: number;
|
|
672
|
-
fromEmail: string;
|
|
673
|
-
username?: string;
|
|
674
|
-
useStarttls?: boolean;
|
|
675
|
-
}
|
|
676
|
-
/** Azure Communication Services email — connection_string is the reserved secret. */
|
|
677
|
-
interface AcsOptions {
|
|
678
|
-
enabled?: boolean;
|
|
679
|
-
fromEmail: string;
|
|
680
|
-
fromName?: string;
|
|
681
|
-
}
|
|
682
|
-
/** Twilio SMS — auth_token is the reserved secret. Exactly one of `fromNumber`
|
|
683
|
-
* or `messagingServiceSid` must be supplied. */
|
|
684
|
-
interface TwilioOptions {
|
|
685
|
-
enabled?: boolean;
|
|
686
|
-
accountSid: string;
|
|
687
|
-
fromNumber?: string;
|
|
688
|
-
messagingServiceSid?: string;
|
|
689
|
-
}
|
|
690
|
-
/** The union of every provider's author-facing options. `buildProvider` accepts
|
|
691
|
-
* this so each provider's typed options pass without a cast. */
|
|
692
|
-
type ProviderOptions = ApnsOptions | FcmOptions | SendgridOptions | SesOptions | SmtpOptions | AcsOptions | TwilioOptions;
|
|
693
|
-
/** The default locale a template row lands on when the author names none. Must
|
|
694
|
-
* match PalNotify's `model.DefaultLocale`. */
|
|
695
|
-
declare const DEFAULT_TEMPLATE_LOCALE: "en";
|
|
696
|
-
/** One locale's email content. */
|
|
697
|
-
interface EmailTemplateContent {
|
|
698
|
-
/** Subject line. Handlebars placeholders (`{{name}}`) are rendered at send. */
|
|
699
|
-
subject: string;
|
|
700
|
-
/** HTML body. */
|
|
701
|
-
html: string;
|
|
702
|
-
/** Plain-text body. Omit and the server derives one from `html` at render. */
|
|
703
|
-
text?: string;
|
|
704
|
-
/**
|
|
705
|
-
* Variables the sender MUST supply. Omit and they are DERIVED from the
|
|
706
|
-
* `{{placeholders}}` in this locale's content — see {@link extractVariables}.
|
|
707
|
-
* Supply explicitly to make a placeholder optional (leave it out of the list)
|
|
708
|
-
* or to require something a conditional references.
|
|
709
|
-
*/
|
|
710
|
-
variables?: readonly string[];
|
|
711
|
-
}
|
|
712
|
-
/** An email template: base content, plus optional per-locale overrides. */
|
|
713
|
-
interface EmailTemplateOptions extends EmailTemplateContent {
|
|
714
|
-
/** Locale of the base content. Defaults to `"en"`. */
|
|
715
|
-
locale?: string;
|
|
716
|
-
/** Additional locales, keyed by BCP47 short tag (`tr`, `de`, …). */
|
|
717
|
-
locales?: Record<string, EmailTemplateContent>;
|
|
718
|
-
}
|
|
719
|
-
/** One locale's SMS content. */
|
|
720
|
-
interface SmsTemplateContent {
|
|
721
|
-
/** Message body. Handlebars placeholders are rendered at send. */
|
|
722
|
-
body: string;
|
|
723
|
-
/** Variables the sender must supply. Derived from `body` when omitted. */
|
|
724
|
-
variables?: readonly string[];
|
|
725
|
-
}
|
|
726
|
-
/** An SMS template: base content, plus optional per-locale overrides. */
|
|
727
|
-
interface SmsTemplateOptions extends SmsTemplateContent {
|
|
728
|
-
/** Locale of the base content. Defaults to `"en"`. */
|
|
729
|
-
locale?: string;
|
|
730
|
-
/** Additional locales, keyed by BCP47 short tag. */
|
|
731
|
-
locales?: Record<string, SmsTemplateContent>;
|
|
732
|
-
}
|
|
733
|
-
/** Author-facing templates block: slug → template. */
|
|
734
|
-
interface TemplatesInput {
|
|
735
|
-
email?: Record<string, EmailTemplateOptions>;
|
|
736
|
-
sms?: Record<string, SmsTemplateOptions>;
|
|
737
|
-
}
|
|
738
|
-
/** A compiled email-template row — one (slug, locale) pair, in the snake_case
|
|
739
|
-
* wire shape PalNotify's templates API takes. */
|
|
740
|
-
interface EmailTemplateDef {
|
|
741
|
-
slug: string;
|
|
742
|
-
locale: string;
|
|
743
|
-
subject: string;
|
|
744
|
-
html_body: string;
|
|
745
|
-
text_body?: string;
|
|
746
|
-
variables: string[];
|
|
747
|
-
}
|
|
748
|
-
/** A compiled SMS-template row — one (slug, locale) pair. */
|
|
749
|
-
interface SmsTemplateDef {
|
|
750
|
-
slug: string;
|
|
751
|
-
locale: string;
|
|
752
|
-
body: string;
|
|
753
|
-
variables: string[];
|
|
754
|
-
}
|
|
755
|
-
/** The compiled templates block: flat, per-channel row lists. Flat rows (rather
|
|
756
|
-
* than a nested locale map) are what the apply step iterates — one row is one
|
|
757
|
-
* upsert against the (slug, locale) unique key. */
|
|
758
|
-
interface TemplatesConfig {
|
|
759
|
-
email: EmailTemplateDef[];
|
|
760
|
-
sms: SmsTemplateDef[];
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Pull the variable names out of Handlebars content.
|
|
764
|
-
*
|
|
765
|
-
* Only PLAIN mustaches count: `{{name}}` and `{{{name}}}`. Deliberately skipped:
|
|
766
|
-
* - block/section/partial/comment tokens (`{{#if}}`, `{{/if}}`, `{{else}}`,
|
|
767
|
-
* `{{> partial}}`, `{{! comment}}`) — structure, not data the sender passes;
|
|
768
|
-
* - helper calls (`{{formatDate at}}`) — the first token is a helper name;
|
|
769
|
-
* - `this` and `@index`-style frame references.
|
|
770
|
-
*
|
|
771
|
-
* A dotted path contributes its ROOT (`{{user.name}}` → `user`), because that is
|
|
772
|
-
* what the sender actually has to hand over.
|
|
773
|
-
*
|
|
774
|
-
* The list is what the server ENFORCES as required at render time, so keeping it
|
|
775
|
-
* to the unambiguous cases is the point: an over-eager derivation would turn an
|
|
776
|
-
* optional conditional into a mandatory argument and 400 real sends.
|
|
777
|
-
*/
|
|
778
|
-
declare function extractVariables(...sources: (string | undefined)[]): string[];
|
|
779
|
-
/** The author-facing input to `defineNotifications`. Every provider + every
|
|
780
|
-
* channel is optional — declare only what you use. */
|
|
781
|
-
interface NotificationsInput {
|
|
782
|
-
push?: {
|
|
783
|
-
apns?: ApnsOptions;
|
|
784
|
-
fcm?: FcmOptions;
|
|
785
|
-
};
|
|
786
|
-
email?: {
|
|
787
|
-
sendgrid?: SendgridOptions;
|
|
788
|
-
ses?: SesOptions;
|
|
789
|
-
smtp?: SmtpOptions;
|
|
790
|
-
acs?: AcsOptions;
|
|
791
|
-
};
|
|
792
|
-
sms?: {
|
|
793
|
-
twilio?: TwilioOptions;
|
|
794
|
-
};
|
|
795
|
-
/** Email + SMS templates, keyed by slug. Applied on every deploy. */
|
|
796
|
-
templates?: TemplatesInput;
|
|
797
|
-
}
|
|
798
|
-
/** A compiled provider def. `enabled` is always present; the remaining keys are
|
|
799
|
-
* the provider's non-secret fields (verbatim from the catalog). A disabled
|
|
800
|
-
* provider is `{ enabled: false }` with no other fields. */
|
|
801
|
-
type ProviderDef = {
|
|
802
|
-
enabled: boolean;
|
|
803
|
-
} & Record<string, unknown>;
|
|
804
|
-
/** The compiled notifications config — the discriminant + per-channel maps of
|
|
805
|
-
* provider name → {@link ProviderDef}. This is what `defineNotifications`
|
|
806
|
-
* returns and the runtime extractor serializes. */
|
|
807
|
-
interface NotificationsConfig {
|
|
808
|
-
__config: typeof NOTIFICATIONS_CONFIG_KIND;
|
|
809
|
-
push: Record<string, ProviderDef>;
|
|
810
|
-
email: Record<string, ProviderDef>;
|
|
811
|
-
sms: Record<string, ProviderDef>;
|
|
812
|
-
templates: TemplatesConfig;
|
|
813
|
-
}
|
|
814
|
-
/**
|
|
815
|
-
* Compile + validate one provider's author options into a {@link ProviderDef}.
|
|
816
|
-
*
|
|
817
|
-
* - A provider with `enabled === false` (or omitted) compiles to `{ enabled:
|
|
818
|
-
* false }` and its required fields are NOT enforced (you can declare a disabled
|
|
819
|
-
* provider as a placeholder without filling it in).
|
|
820
|
-
* - An ENABLED provider must supply every `required` non-secret field from the
|
|
821
|
-
* catalog; a missing one throws at config-author time (not silently at deploy).
|
|
822
|
-
* - Only the catalog's non-secret fields (required + optional) are copied into
|
|
823
|
-
* the def — an unknown extra key is ignored (it would have no effect on the
|
|
824
|
-
* live provider). Secrets are never read here.
|
|
825
|
-
*/
|
|
826
|
-
declare function buildProvider(name: ProviderName, opts: ProviderOptions): ProviderDef;
|
|
827
|
-
/**
|
|
828
|
-
* Define the notification-provider config for a project. Returns the
|
|
829
|
-
* discriminated {@link NotificationsConfig} the runtime config extractor
|
|
830
|
-
* serializes and the Go apply step reconciles. Validates eagerly: an enabled
|
|
831
|
-
* provider missing a required non-secret field throws here (config-author time),
|
|
832
|
-
* not at deploy.
|
|
833
|
-
*
|
|
834
|
-
* @example
|
|
835
|
-
* export default defineNotifications({
|
|
836
|
-
* push: { apns: { enabled: true, teamId: "T", keyId: "K", bundleId: "com.x" } },
|
|
837
|
-
* });
|
|
838
|
-
*/
|
|
839
|
-
declare function defineNotifications(input: NotificationsInput): NotificationsConfig;
|
|
840
|
-
/**
|
|
841
|
-
* Derive the RESERVED env-var key that backs a provider's secret field, e.g.
|
|
842
|
-
* `reservedSecretKey("apns", "p8")` → `"PB_NOTIFICATIONS_APNS_P8"`. The CLI uses
|
|
843
|
-
* this to upload the secret and the br-pod apply step uses the same derivation
|
|
844
|
-
* to resolve it — they never hand-type the key, so they cannot drift.
|
|
845
|
-
*/
|
|
846
|
-
declare function reservedSecretKey(provider: ProviderName, secretField: string): string;
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
* test-users.ts — the test-user fixtures config-as-code DSL.
|
|
850
|
-
*
|
|
851
|
-
* `defineTestUsers({ users })` is a MODULE config-as-code surface (a sibling of
|
|
852
|
-
* `config/storage.ts`'s `defineStorage` and `config/flags.ts`'s `defineFlags`).
|
|
853
|
-
* A `config/test-users.ts` file default-exports a `defineTestUsers(...)` result;
|
|
854
|
-
* on deploy the runtime evaluates it to JSON and hands it to Studio, which owns
|
|
855
|
-
* the single apply engine (mint + seed). Studio, the CLI and the deploy all go
|
|
856
|
-
* through that one engine — there is no second interpreter of this JSON.
|
|
857
|
-
*
|
|
858
|
-
* TWO SHAPES, ONE DSL:
|
|
859
|
-
*
|
|
860
|
-
* - `email` GIVEN → a FIXTURE. Deploy materializes it create-if-missing, so
|
|
861
|
-
* the app can always be signed into with the same credentials. Deliberately
|
|
862
|
-
* NOT applied to a production Environment (the password lives in git).
|
|
863
|
-
* - `email` OMITTED → a TEMPLATE. Deploy creates nothing; Studio and the CLI
|
|
864
|
-
* mint as many fresh instances from it as you want (random credentials).
|
|
865
|
-
*
|
|
866
|
-
* Every minted user is an `is_test` user: excluded from MAU/billing, carrying
|
|
867
|
-
* `test: true` in its token, and refused by the Test Data write path if it ever
|
|
868
|
-
* turns out not to be one.
|
|
869
|
-
*
|
|
870
|
-
* @example
|
|
871
|
-
* import { defineTestUsers, testUser } from "@palbase/backend";
|
|
872
|
-
*
|
|
873
|
-
* export default defineTestUsers({
|
|
874
|
-
* users: {
|
|
875
|
-
* demo: testUser({
|
|
876
|
-
* email: "demo@test.local",
|
|
877
|
-
* password: "demo-password-1234",
|
|
878
|
-
* seed: {
|
|
879
|
-
* profiles: [{ display_name: "Demo", tier: "pro" }],
|
|
880
|
-
* lists: [
|
|
881
|
-
* { title: "Groceries", todos: [{ title: "Milk" }, { title: "Eggs", done: true }] },
|
|
882
|
-
* ],
|
|
883
|
-
* },
|
|
884
|
-
* }),
|
|
885
|
-
* heavy_user: testUser({ seed: { lists: [{ title: "L", todos: [{ title: "t" }] }] } }),
|
|
886
|
-
* },
|
|
887
|
-
* });
|
|
888
|
-
*
|
|
889
|
-
* The returned value is the EXACT JSON shape the runtime's generic config
|
|
890
|
-
* extractor emits and the apply engine consumes:
|
|
891
|
-
* { __config: "test-users", users: { <name>: { email, password, seed } } }
|
|
892
|
-
* `email` / `password` are the string or `null`; `seed` is `{}` when omitted.
|
|
893
|
-
*/
|
|
894
|
-
|
|
895
|
-
/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is
|
|
896
|
-
* a test-users config. */
|
|
897
|
-
declare const TEST_USERS_CONFIG_KIND: "test-users";
|
|
898
|
-
/**
|
|
899
|
-
* A table graph in the shape the env `Tables` interface carries. The
|
|
900
|
-
* derivations below are parameterized over it (rather than reading the global
|
|
901
|
-
* `Tables` directly) so they can be type-tested against a fixture graph without
|
|
902
|
-
* augmenting the global interface — augmentation is program-wide and would leak
|
|
903
|
-
* into every other type test.
|
|
904
|
-
*
|
|
905
|
-
* The `Record<keyof G, …>` constraint is deliberate: a plain
|
|
906
|
-
* `Record<string, TableTypes>` would reject the `Tables` INTERFACE, which has
|
|
907
|
-
* no index signature.
|
|
908
|
-
*/
|
|
909
|
-
type TableGraph = Record<string, TableTypes>;
|
|
910
|
-
/** The user-rooted tables of `G` — the ones a test user owns rows in directly. */
|
|
911
|
-
type OwnedTablesOf<G extends Record<keyof G, TableTypes>> = {
|
|
912
|
-
[T in keyof G]: G[T]["owner"] extends string ? T : never;
|
|
913
|
-
}[keyof G];
|
|
914
|
-
/**
|
|
915
|
-
* One authored seed row for table `T` of graph `G`.
|
|
916
|
-
*
|
|
917
|
-
* Starts from the table's INSERT shape and removes the two columns the engine
|
|
918
|
-
* owns: the owner column (set to the minted user) and `Via` — the FK column
|
|
919
|
-
* this row hangs off its parent by, when the row is nested under one. What
|
|
920
|
-
* remains is extended with the table's children, each an optional array of
|
|
921
|
-
* their own seed rows.
|
|
922
|
-
*
|
|
923
|
-
* Recursion terminates because `makeEnvDts` drops self-FKs and cycle
|
|
924
|
-
* back-edges when it emits `children`.
|
|
925
|
-
*
|
|
926
|
-
* Name collision note: if a table has a COLUMN whose name equals a CHILD
|
|
927
|
-
* table's name, the intersection makes that key unusable (its type collapses).
|
|
928
|
-
* That is a schema-naming problem the author sees at compile time; the apply
|
|
929
|
-
* engine resolves the same ambiguity live in favour of the column, because it
|
|
930
|
-
* introspects the real table.
|
|
931
|
-
*/
|
|
932
|
-
type SeedRowFor<G extends Record<keyof G, TableTypes>, T extends keyof G, Via extends string = never> = Omit<G[T]["insert"], (G[T]["owner"] & string) | Via> & {
|
|
933
|
-
[C in keyof G[T]["children"]]?: Array<SeedRowFor<G, C & keyof G, G[T]["children"][C] & string>>;
|
|
934
|
-
};
|
|
935
|
-
/** The typed seed over graph `G`: top-level keys are user-rooted tables only;
|
|
936
|
-
* everything else is reached by nesting under its parent. */
|
|
937
|
-
type SeedFor<G extends Record<keyof G, TableTypes>> = {
|
|
938
|
-
[T in OwnedTablesOf<G>]?: Array<SeedRowFor<G, T>>;
|
|
939
|
-
};
|
|
940
|
-
/** The serialized seed — what travels as JSON and what the engine receives. */
|
|
941
|
-
type SeedJson = Record<string, Array<Record<string, unknown>>>;
|
|
942
|
-
/**
|
|
943
|
-
* The author-facing seed type. Falls back to the loose shape when `Tables` is
|
|
944
|
-
* still empty (no `db/schema.ts`, or `palbase-env.d.ts` not generated yet) so
|
|
945
|
-
* an unseeded project gets a usable DSL instead of an inscrutable `{}` error.
|
|
946
|
-
*/
|
|
947
|
-
type Seed = [keyof Tables] extends [never] ? SeedJson : SeedFor<Tables>;
|
|
948
|
-
/**
|
|
949
|
-
* The options for one declared test user.
|
|
950
|
-
*
|
|
951
|
-
* - `email` / `password`: supply BOTH to make this a fixture with stable
|
|
952
|
-
* credentials (deploy materializes it, the app signs in with them), or
|
|
953
|
-
* NEITHER to make it a template the server generates credentials for.
|
|
954
|
-
* - `seed`: the user's data tree, derived from `db/schema.ts`. Top-level keys
|
|
955
|
-
* are user-rooted tables; FK children nest inside their parent's rows.
|
|
956
|
-
*/
|
|
957
|
-
interface TestUserOptions {
|
|
958
|
-
email?: string;
|
|
959
|
-
password?: string;
|
|
960
|
-
/**
|
|
961
|
-
* A verified phone for this fixture, E.164 (`+905551112233`). Requires
|
|
962
|
-
* {@link TestUserOptions.otp}: nothing can receive an SMS at a fabricated
|
|
963
|
-
* number, so a phone fixture without a knowable code is one no test could
|
|
964
|
-
* ever sign in as.
|
|
965
|
-
*/
|
|
966
|
-
phone?: string;
|
|
967
|
-
/**
|
|
968
|
-
* The fixed code this fixture's phone accepts. Honoured ONLY for the
|
|
969
|
-
* `is_test` user it belongs to — the real rail is untouched, and no
|
|
970
|
-
* verification is ever sent (or billed) for a fixture.
|
|
971
|
-
*/
|
|
972
|
-
otp?: string;
|
|
973
|
-
seed?: Seed;
|
|
974
|
-
}
|
|
975
|
-
/** The compiled, serializable test-user definition — the EXACT shape emitted to
|
|
976
|
-
* JSON and consumed by the apply engine. */
|
|
977
|
-
interface TestUserDef {
|
|
978
|
-
/** Fixed login e-mail (fixture), or `null` when the server should generate one. */
|
|
979
|
-
email: string | null;
|
|
980
|
-
/** Fixed password (fixture), or `null` when the server should generate one. */
|
|
981
|
-
password: string | null;
|
|
982
|
-
/** Verified phone in E.164, or `null` for an e-mail-only fixture. */
|
|
983
|
-
phone: string | null;
|
|
984
|
-
/** The code that phone accepts, or `null` when there is no phone. */
|
|
985
|
-
otp: string | null;
|
|
986
|
-
/** The user's data tree; `{}` when nothing is seeded. */
|
|
987
|
-
seed: SeedJson;
|
|
988
|
-
}
|
|
989
|
-
/** A test-users config: the discriminant + the declared users by name. */
|
|
990
|
-
interface TestUsersConfig {
|
|
991
|
-
__config: typeof TEST_USERS_CONFIG_KIND;
|
|
992
|
-
users: Record<string, TestUserDef>;
|
|
993
|
-
}
|
|
994
|
-
/** The author-facing input to `defineTestUsers`. */
|
|
995
|
-
interface TestUsersInput {
|
|
996
|
-
users: Record<string, TestUserDef>;
|
|
997
|
-
}
|
|
998
|
-
/**
|
|
999
|
-
* Define a single test user. The NAME is supplied by the object key in
|
|
1000
|
-
* `defineTestUsers({ users: { <name>: testUser({...}) } })`, so `testUser()`
|
|
1001
|
-
* takes only the options.
|
|
1002
|
-
*
|
|
1003
|
-
* Validates eagerly (at config-author time):
|
|
1004
|
-
* - `email` and `password` are supplied together or not at all — half a
|
|
1005
|
-
* credential pair would silently degrade a fixture into a template.
|
|
1006
|
-
* - `email` looks like an address; `password` is at least
|
|
1007
|
-
* {@link MIN_PASSWORD_LENGTH} characters.
|
|
1008
|
-
* - `seed` is structurally `{ <table>: [ {...}, ... ] }` with non-empty arrays.
|
|
1009
|
-
*
|
|
1010
|
-
* The user NAME is validated by `defineTestUsers`, which is where it is known.
|
|
1011
|
-
*/
|
|
1012
|
-
declare function testUser(opts?: TestUserOptions): TestUserDef;
|
|
1013
|
-
/**
|
|
1014
|
-
* Define a project's test users. The user NAME comes from each object key
|
|
1015
|
-
* (authors never repeat it). Returns the discriminated {@link TestUsersConfig}
|
|
1016
|
-
* the runtime config extractor serializes and the apply engine consumes.
|
|
1017
|
-
*
|
|
1018
|
-
* Validates eagerly:
|
|
1019
|
-
* - each name matches `^[a-zA-Z][a-zA-Z0-9_]*$` (the CLI's `--template <name>`
|
|
1020
|
-
* and control-pg's scenario name share this vocabulary).
|
|
1021
|
-
* - no two fixtures declare the SAME e-mail — they would race to
|
|
1022
|
-
* create-if-missing the one account and the second would silently adopt the
|
|
1023
|
-
* first one's data tree.
|
|
1024
|
-
*
|
|
1025
|
-
* @example
|
|
1026
|
-
* export default defineTestUsers({
|
|
1027
|
-
* users: { demo: testUser({ email: "demo@test.local", password: "demo-password-1234" }) },
|
|
1028
|
-
* });
|
|
1029
|
-
*/
|
|
1030
|
-
declare function defineTestUsers(input: TestUsersInput): TestUsersConfig;
|
|
1031
|
-
|
|
1032
|
-
/**
|
|
1033
|
-
* flags.ts — the feature-flag-definitions config-as-code DSL.
|
|
1034
|
-
*
|
|
1035
|
-
* `defineFlags({ flags })` is the third MODULE config-as-code surface (a sibling
|
|
1036
|
-
* of `config/storage.ts`'s `defineStorage` and `config/notifications.ts`'s
|
|
1037
|
-
* `defineNotifications`). A `config/flags.ts` file default-exports a
|
|
1038
|
-
* `defineFlags(...)` result; on deploy the br-pod evaluates it to JSON and
|
|
1039
|
-
* UPSERTS the declared flag DEFINITIONS into PalFlags (the user-flags module's
|
|
1040
|
-
* system-flags admin API) — create-or-update, idempotent. A live flag NOT in
|
|
1041
|
-
* config is NEVER auto-deleted (an orphan flag is harmless; upsert-only).
|
|
1042
|
-
*
|
|
1043
|
-
* Flags are DECLARATIVE: a flag is a typed project-wide DEFAULT (its key, type,
|
|
1044
|
-
* default value, an optional description, and — for string flags — an optional
|
|
1045
|
-
* list of allowed `variants`). The VALUE of a flag for a specific USER (a
|
|
1046
|
-
* per-user override / A-B assignment) is runtime state set via the SDK, NEVER in
|
|
1047
|
-
* git. `variants` here is part of the DEFINITION (the allowed values a string
|
|
1048
|
-
* flag may take), not a per-user assignment.
|
|
1049
|
-
*
|
|
1050
|
-
* NO SECRETS. Unlike notifications, a flag carries no credentials — this is the
|
|
1051
|
-
* simplest module config (pure declarative data).
|
|
1052
|
-
*
|
|
1053
|
-
* @example
|
|
1054
|
-
* import { defineFlags, flag } from "@palbase/backend";
|
|
1055
|
-
*
|
|
1056
|
-
* export default defineFlags({
|
|
1057
|
-
* flags: {
|
|
1058
|
-
* new_dashboard: flag({ type: "boolean", default: false, description: "Roll out the new dashboard" }),
|
|
1059
|
-
* max_uploads: flag({ type: "number", default: 10 }),
|
|
1060
|
-
* theme: flag({ type: "string", default: "light", variants: ["light", "dark", "system"] }),
|
|
1061
|
-
* limits: flag({ type: "json", default: { daily: 10, burst: 50 } }),
|
|
1062
|
-
* },
|
|
1063
|
-
* });
|
|
1064
|
-
*
|
|
1065
|
-
* The returned value is the EXACT JSON shape the runtime's generic config
|
|
1066
|
-
* extractor (`config_extract.js`) emits and the Go apply step parses:
|
|
1067
|
-
* { __config: "flags", flags: { <key>: { type, default, variants, description }, ... } }
|
|
1068
|
-
* `variants` is the allowed-values list for a string flag, or `null` (any
|
|
1069
|
-
* string). `description` is the doc string, or `null`. The apply step maps the
|
|
1070
|
-
* author-facing `type` to PalFlags' `value_type`: "boolean" → "bool" and
|
|
1071
|
-
* "json" → "object"; "number"/"string" pass through.
|
|
1072
|
-
*/
|
|
1073
|
-
/** The `__config` discriminant the eval/apply reads to confirm a config/*.ts is
|
|
1074
|
-
* a flags config. Flags is `"flags"`. */
|
|
1075
|
-
declare const FLAGS_CONFIG_KIND: "flags";
|
|
1076
|
-
/**
|
|
1077
|
-
* A flag's type. The author-facing vocabulary is `"boolean" | "number" |
|
|
1078
|
-
* "string" | "json"`; the apply step maps it to PalFlags' `value_type` enum —
|
|
1079
|
-
* `"boolean"` → `"bool"`, `"json"` → `"object"`, the other two pass through. The
|
|
1080
|
-
* SDK keeps the JS-natural names so the DSL reads cleanly.
|
|
1081
|
-
*
|
|
1082
|
-
* `"json"` is a structured (object) flag. It is named for what an author types —
|
|
1083
|
-
* a JSON object literal — and matches the `--type json` the CLI's per-user
|
|
1084
|
-
* override commands already use for this same server type.
|
|
1085
|
-
*/
|
|
1086
|
-
type FlagType = "boolean" | "number" | "string" | "json";
|
|
1087
|
-
/** Any value expressible in JSON — what may appear INSIDE a `"json"` flag's default. */
|
|
1088
|
-
type FlagJsonValue = boolean | number | string | null | FlagJsonValue[] | {
|
|
1089
|
-
[key: string]: FlagJsonValue;
|
|
1090
|
-
};
|
|
1091
|
-
/**
|
|
1092
|
-
* The default of a `"json"` flag: a JSON OBJECT. Not an array and not a scalar —
|
|
1093
|
-
* PalFlags' `object` value type accepts a JSON object at the top level only
|
|
1094
|
-
* (`validate.ValidateValueTypeMatch`), and it caps nesting depth at 3.
|
|
1095
|
-
*/
|
|
1096
|
-
type FlagJsonObject = {
|
|
1097
|
-
[key: string]: FlagJsonValue;
|
|
1098
|
-
};
|
|
1099
|
-
/** The runtime JSON value a flag's `default` may hold (matches {@link FlagType}). */
|
|
1100
|
-
type FlagValue = boolean | number | string | FlagJsonObject;
|
|
1101
|
-
/**
|
|
1102
|
-
* The author-facing options for a single flag — a UNION keyed on `type`, so
|
|
1103
|
-
* `default` is checked against the declared type at compile time and `variants`
|
|
1104
|
-
* is only accepted where it means something.
|
|
1105
|
-
*
|
|
1106
|
-
* - `type`: the flag's type — `"boolean" | "number" | "string" | "json"`.
|
|
1107
|
-
* - `default`: the project-wide default value. MUST match `type` (a `number`
|
|
1108
|
-
* default with `type: "boolean"` is a type error, and throws at runtime).
|
|
1109
|
-
* - `variants`: ONLY valid for `type: "string"` — the allowed values the string
|
|
1110
|
-
* flag may take (a DEFINITION, not a per-user assignment). When given, the
|
|
1111
|
-
* `default` MUST be one of the variants. Supplying `variants` on any other
|
|
1112
|
-
* type is a type error, and throws at runtime. (PalFlags rejects variants for
|
|
1113
|
-
* every non-string `value_type`, so accepting them here would only produce a
|
|
1114
|
-
* config the server refuses.)
|
|
1115
|
-
* - `description`: an optional human description of what the flag controls.
|
|
1116
|
-
*/
|
|
1117
|
-
type FlagOptions = {
|
|
1118
|
-
type: "boolean";
|
|
1119
|
-
default: boolean;
|
|
1120
|
-
variants?: never;
|
|
1121
|
-
conditions?: FlagCondition<boolean>[];
|
|
1122
|
-
description?: string;
|
|
1123
|
-
} | {
|
|
1124
|
-
type: "number";
|
|
1125
|
-
default: number;
|
|
1126
|
-
variants?: never;
|
|
1127
|
-
conditions?: FlagCondition<number>[];
|
|
1128
|
-
description?: string;
|
|
1129
|
-
} | {
|
|
1130
|
-
type: "string";
|
|
1131
|
-
default: string;
|
|
1132
|
-
variants?: string[];
|
|
1133
|
-
conditions?: FlagCondition<string>[];
|
|
1134
|
-
description?: string;
|
|
1135
|
-
} | {
|
|
1136
|
-
type: "json";
|
|
1137
|
-
default: FlagJsonObject;
|
|
1138
|
-
variants?: never;
|
|
1139
|
-
conditions?: FlagCondition<FlagJsonObject>[];
|
|
1140
|
-
description?: string;
|
|
1141
|
-
};
|
|
1142
|
-
/**
|
|
1143
|
-
* One targeting branch: the value this flag resolves to when `when` matches the
|
|
1144
|
-
* caller's client context. Branch ORDER is priority — the first match wins, and
|
|
1145
|
-
* a flag with no matching branch falls back to its `default`.
|
|
1146
|
-
*
|
|
1147
|
-
* `when` is a small expression over what the client declares about itself:
|
|
1148
|
-
*
|
|
1149
|
-
* ```
|
|
1150
|
-
* client.platform == 'ios' && client.app_version >= '2.0.0'
|
|
1151
|
-
* client.locale startsWith 'tr'
|
|
1152
|
-
* client.platform in ['ios', 'android']
|
|
1153
|
-
* ```
|
|
1154
|
-
*
|
|
1155
|
-
* Those are CLAIMS, not proof — the server treats them as attacker-controlled.
|
|
1156
|
-
* They select WHICH value a caller sees, never WHETHER they may see it, so a
|
|
1157
|
-
* condition must not be the thing standing between a user and something paid.
|
|
1158
|
-
*/
|
|
1159
|
-
/**
|
|
1160
|
-
* The variables the server exposes. Mirrors `declaredVars` in
|
|
1161
|
-
* `modules/user-flags/internal/conditions/conditions.go`; the server rejects
|
|
1162
|
-
* anything it does not know, so the worst a stale copy here does is offer too
|
|
1163
|
-
* little.
|
|
1164
|
-
*
|
|
1165
|
-
* `client.*` is what the SDK reports about the caller. `percentile` and
|
|
1166
|
-
* `server.now` are DERIVED server-side and cannot be moved by a lying client,
|
|
1167
|
-
* which is what makes a rollout or a time window mean anything.
|
|
1168
|
-
*/
|
|
1169
|
-
type StringVar = "client.platform" | "client.locale";
|
|
1170
|
-
type SemverVar = "client.app_version" | "client.os_version";
|
|
1171
|
-
type EqualityOp = "==" | "!=";
|
|
1172
|
-
/** Ordering only where order exists — a platform string has none. */
|
|
1173
|
-
type OrderedOp = EqualityOp | "<" | "<=" | ">" | ">=";
|
|
1174
|
-
type TextOp = EqualityOp | "startsWith" | "endsWith" | "contains";
|
|
1175
|
-
/** A single-quoted literal. Quoting is the mistake people make most. */
|
|
1176
|
-
type Quoted = `'${string}'`;
|
|
1177
|
-
type Comparison = `${StringVar} ${TextOp} ${Quoted}` | `${StringVar} in [${string}]` | `${SemverVar} ${OrderedOp} ${Quoted}` | `percentile ${OrderedOp} ${number}` | `server.now ${OrderedOp} ${Quoted}`;
|
|
1178
|
-
/**
|
|
1179
|
-
* One expression: a comparison, optionally chained with `&&` / `||`, or a
|
|
1180
|
-
* parenthesised group.
|
|
1181
|
-
*
|
|
1182
|
-
* ONE level, and the limit is TypeScript's, not a preference. Unrolling a second
|
|
1183
|
-
* level produced `TS2590: union type too complex`, and the failure mode there is
|
|
1184
|
-
* the worst possible one: the checker gives up and the type silently degrades to
|
|
1185
|
-
* `string`, so NOTHING is checked while the code still compiles. Measured, not
|
|
1186
|
-
* assumed — the two-level version accepted `client.app_verison` without
|
|
1187
|
-
* complaint.
|
|
1188
|
-
*
|
|
1189
|
-
* So the FIRST term is fully checked and the rest of a chain is not. That is
|
|
1190
|
-
* where the mistakes are: a rule is usually one comparison, and a typo in the
|
|
1191
|
-
* first one is the common case. A typo after an `&&` still reaches the server,
|
|
1192
|
-
* which parses the real grammar and rejects it.
|
|
1193
|
-
*
|
|
1194
|
-
* A group's contents go unchecked for the same reason.
|
|
1195
|
-
*/
|
|
1196
|
-
type FlagConditionExpression = Comparison | `${Comparison} && ${string}` | `${Comparison} || ${string}` | `(${string})`;
|
|
1197
|
-
interface FlagCondition<V> {
|
|
1198
|
-
when: FlagConditionExpression;
|
|
1199
|
-
value: V;
|
|
1200
|
-
}
|
|
1201
|
-
/**
|
|
1202
|
-
* The COMPILED shape of a condition — the JSON actually emitted and parsed by
|
|
1203
|
-
* the Go apply step.
|
|
1204
|
-
*
|
|
1205
|
-
* `when` widens back to `string` here on purpose. The narrow type is an
|
|
1206
|
-
* authoring aid; once the expression has been trimmed and serialised it is just
|
|
1207
|
-
* text on the wire, and keeping the template-literal type would force a cast on
|
|
1208
|
-
* every string operation without checking anything the author had not already
|
|
1209
|
-
* been checked on.
|
|
1210
|
-
*/
|
|
1211
|
-
interface CompiledFlagCondition<V> {
|
|
1212
|
-
when: string;
|
|
1213
|
-
value: V;
|
|
1214
|
-
}
|
|
1215
|
-
/**
|
|
1216
|
-
* The compiled, serializable flag definition — the EXACT shape emitted to JSON
|
|
1217
|
-
* and consumed by the Go apply step.
|
|
1218
|
-
*
|
|
1219
|
-
* - `type`: the author-facing type verbatim (`"boolean" | "number" | "string" |
|
|
1220
|
-
* "json"`) — the apply step maps it to PalFlags' `value_type`.
|
|
1221
|
-
* - `default`: the default value (matches `type`).
|
|
1222
|
-
* - `variants`: the allowed-values list for a string flag, or `null` (any).
|
|
1223
|
-
* - `description`: the doc string, or `null`.
|
|
1224
|
-
*/
|
|
1225
|
-
interface FlagDef {
|
|
1226
|
-
type: FlagType;
|
|
1227
|
-
default: FlagValue;
|
|
1228
|
-
variants: string[] | null;
|
|
1229
|
-
/** Ordered targeting branches, or `null` when the flag is unconditional. */
|
|
1230
|
-
conditions: CompiledFlagCondition<FlagValue>[] | null;
|
|
1231
|
-
description: string | null;
|
|
1232
|
-
}
|
|
1233
|
-
/** A flags config definition: the discriminant + a map of flag key →
|
|
1234
|
-
* {@link FlagDef}. This is the value `defineFlags` returns and the runtime
|
|
1235
|
-
* config extractor serializes. */
|
|
1236
|
-
interface FlagsConfig {
|
|
1237
|
-
__config: typeof FLAGS_CONFIG_KIND;
|
|
1238
|
-
flags: Record<string, FlagDef>;
|
|
1239
|
-
}
|
|
1240
|
-
/** The author-facing input to `defineFlags`: a `flags` map whose keys are the
|
|
1241
|
-
* flag keys and whose values are `flag({...})` builders. */
|
|
1242
|
-
interface FlagsInput {
|
|
1243
|
-
flags: Record<string, FlagDef>;
|
|
363
|
+
* stack-gen.ts — generate the `palbase-stack.d.ts` text from the names the
|
|
364
|
+
* linked environment's stack holds.
|
|
365
|
+
*
|
|
366
|
+
* The twin of `db/env-gen.ts`: the CLI calls
|
|
367
|
+
* {@link makeStackDts} with the three name sets it read off the stack and
|
|
368
|
+
* writes the result to `palbase-stack.d.ts` at the project root. That file
|
|
369
|
+
* augments the `@palbase/backend/stack` interfaces, so `Secrets.get(...)`, the
|
|
370
|
+
* Flags client and `@Upload({ bucket })` accept the project's real names and
|
|
371
|
+
* nothing else.
|
|
372
|
+
*
|
|
373
|
+
* The generator does NOT reach the network and does NOT decide what a name is:
|
|
374
|
+
* it renders what it is handed. The stack is the authority on which names exist
|
|
375
|
+
* (`GET /v1/management/secrets`, `/flags`, `/storage/buckets`); re-deciding that
|
|
376
|
+
* here would be a second, weaker copy of it.
|
|
377
|
+
*
|
|
378
|
+
* The emitted file ends in `export {};` — same as `makeEnvDts` and
|
|
379
|
+
* `makePurchasesDts`. Without it the `.d.ts` is a global script, and
|
|
380
|
+
* `declare module "…"` there DECLARES an ambient module (shadowing the real one,
|
|
381
|
+
* so every name silently becomes invalid) instead of AUGMENTING it.
|
|
382
|
+
*/
|
|
383
|
+
/** The three name sets read off the stack. Order is irrelevant — each set is
|
|
384
|
+
* sorted here so the same stack always renders the same bytes and a diff shows
|
|
385
|
+
* what CHANGED rather than how the API happened to order its answer. */
|
|
386
|
+
/** One bucket and the renditions it declares. */
|
|
387
|
+
interface BucketInput {
|
|
388
|
+
name: string;
|
|
389
|
+
variants: readonly string[];
|
|
1244
390
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
* Validates eagerly (at config-author time):
|
|
1251
|
-
* - `type` is one of `"boolean" | "number" | "string" | "json"`.
|
|
1252
|
-
* - `default` matches `type` (e.g. a `number` default with `type: "boolean"`
|
|
1253
|
-
* throws; a `"json"` default must be a plain object, not an array or scalar).
|
|
1254
|
-
* - `variants` is ONLY allowed for a string flag (variants on any other type
|
|
1255
|
-
* throws); each entry is a non-empty string; the `default` must be one of the
|
|
1256
|
-
* variants.
|
|
1257
|
-
*
|
|
1258
|
-
* Returns a normalized {@link FlagDef}: `variants` deduped-or-null,
|
|
1259
|
-
* `description` trimmed-or-null.
|
|
1260
|
-
*/
|
|
1261
|
-
declare function flag(opts: FlagOptions): FlagDef;
|
|
1262
|
-
/**
|
|
1263
|
-
* Define the feature-flag definitions for a project. The flag KEY comes from
|
|
1264
|
-
* each object key (authors never repeat the key). Returns the discriminated
|
|
1265
|
-
* {@link FlagsConfig} the runtime config extractor serializes and the Go apply
|
|
1266
|
-
* step UPSERTS into PalFlags.
|
|
1267
|
-
*
|
|
1268
|
-
* @example
|
|
1269
|
-
* export default defineFlags({
|
|
1270
|
-
* flags: { dark_mode: flag({ type: "boolean", default: false }) },
|
|
1271
|
-
* });
|
|
1272
|
-
*/
|
|
1273
|
-
declare function defineFlags(input: FlagsInput): FlagsConfig;
|
|
1274
|
-
|
|
1275
|
-
/**
|
|
1276
|
-
* secrets.ts — the tenant SECRET REQUIREMENT config-as-code DSL.
|
|
1277
|
-
*
|
|
1278
|
-
* `defineSecrets({ secrets: [secret("NEO4J_PASSWORD")] })` declares WHICH secrets
|
|
1279
|
-
* a backend needs to run. It declares the requirement, never the value: the value
|
|
1280
|
-
* lives only in the vault, and nothing in this file — or in the repo it is
|
|
1281
|
-
* committed to — ever holds one.
|
|
1282
|
-
*
|
|
1283
|
-
* The gap it closes: today a backend's dependence on a secret is written nowhere
|
|
1284
|
-
* except inside the code that reads it (`process.env.NEO4J_PASSWORD`). Deploy a
|
|
1285
|
-
* project into an environment where that secret was never set and the build
|
|
1286
|
-
* passes, the pod starts, and the failure surfaces as a 500 on the first request
|
|
1287
|
-
* that touches it — measured on todoapp, whose `/graph/*` routes returned 500 for
|
|
1288
|
-
* exactly this reason. With the requirement declared, it travels WITH the code:
|
|
1289
|
-
* `push` compares this list against the environment's vault and refuses the
|
|
1290
|
-
* deploy, naming the missing secret, before anything ships.
|
|
1291
|
-
*
|
|
1292
|
-
* @example
|
|
1293
|
-
* // config/secrets.ts
|
|
1294
|
-
* import { defineSecrets, secret } from "@palbase/backend";
|
|
1295
|
-
* export default defineSecrets({
|
|
1296
|
-
* secrets: [
|
|
1297
|
-
* secret("NEO4J_PASSWORD", { description: "graph store password" }),
|
|
1298
|
-
* secret("SENTRY_DSN", { required: false, description: "crash reporting" }),
|
|
1299
|
-
* ],
|
|
1300
|
-
* });
|
|
1301
|
-
*
|
|
1302
|
-
* `required` defaults to TRUE. A declaration exists to be checked, so the safe
|
|
1303
|
-
* default is the checked one; `required: false` says the code has a working path
|
|
1304
|
-
* when the secret is absent, and downgrades a missing secret to a warning.
|
|
1305
|
-
*
|
|
1306
|
-
* Emits: { __config: "secrets", secrets: [{ name, required, description }] }
|
|
1307
|
-
* sorted by name, so the same declaration always evaluates to the same bytes and
|
|
1308
|
-
* a config diff shows what an author changed rather than how they reordered it.
|
|
1309
|
-
*/
|
|
1310
|
-
/** The discriminant written under `__config` so the deploy eval knows the kind. */
|
|
1311
|
-
declare const SECRETS_CONFIG_KIND: "secrets";
|
|
1312
|
-
/** The author-facing options for a single `secret()`. */
|
|
1313
|
-
interface SecretOptions {
|
|
391
|
+
interface StackNames {
|
|
392
|
+
/** Secret names from the project's vault. */
|
|
393
|
+
secrets: readonly string[];
|
|
394
|
+
/** Flag keys from the project's flag store. */
|
|
395
|
+
flags: readonly string[];
|
|
1314
396
|
/**
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
397
|
+
* Buckets from the project's storage — a bare name, or a name with the
|
|
398
|
+
* renditions it declares.
|
|
399
|
+
*
|
|
400
|
+
* A bucket is not only a NAME: `Storage.buckets.docs.getPublicUrl(p, {
|
|
401
|
+
* variant })` refuses a rendition the bucket does not have, so the variant
|
|
402
|
+
* union has to travel with it. The bare-string form is shorthand for "no
|
|
403
|
+
* variants", which renders `never` and accepts none.
|
|
1317
404
|
*/
|
|
1318
|
-
|
|
1319
|
-
/** What the secret is for — shown when the deploy reports it missing. */
|
|
1320
|
-
description?: string;
|
|
405
|
+
buckets: readonly (string | BucketInput)[];
|
|
1321
406
|
}
|
|
1322
407
|
/**
|
|
1323
|
-
*
|
|
1324
|
-
* JSON and consumed by the Go deploy step.
|
|
408
|
+
* Render the project's `palbase-stack.d.ts`.
|
|
1325
409
|
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
410
|
+
* An empty set renders an empty interface, which is a MEANINGFUL value: the
|
|
411
|
+
* stack holds no such names, so the corresponding union is `never` and every
|
|
412
|
+
* call spelling one fails to compile. It is not the same as "the file was never
|
|
413
|
+
* generated" only in that the file exists — both states refuse every name, and
|
|
414
|
+
* both are correct.
|
|
1329
415
|
*/
|
|
1330
|
-
|
|
1331
|
-
name: string;
|
|
1332
|
-
required: boolean;
|
|
1333
|
-
description: string | null;
|
|
1334
|
-
}
|
|
1335
|
-
/** A secrets config definition: the discriminant + the name-sorted declarations.
|
|
1336
|
-
* This is the value `defineSecrets` returns and the build's config extractor
|
|
1337
|
-
* serializes into `.palbase/config.json`. */
|
|
1338
|
-
interface SecretsConfig {
|
|
1339
|
-
__config: typeof SECRETS_CONFIG_KIND;
|
|
1340
|
-
secrets: SecretDef[];
|
|
1341
|
-
}
|
|
1342
|
-
/** The author-facing input to `defineSecrets`: a list of `secret(...)` builders. */
|
|
1343
|
-
interface SecretsInput {
|
|
1344
|
-
secrets: SecretDef[];
|
|
1345
|
-
}
|
|
1346
|
-
/**
|
|
1347
|
-
* Declare a single required (or optional) secret. Unlike `flag()` / `bucket()`,
|
|
1348
|
-
* the NAME is an argument rather than an object key: a secret's name is not a
|
|
1349
|
-
* label an author chooses, it is the exact env-var identifier the code already
|
|
1350
|
-
* reads, so it belongs where it can be validated as one.
|
|
1351
|
-
*
|
|
1352
|
-
* Validates eagerly (at config-author time):
|
|
1353
|
-
* - `name` is `[A-Z][A-Z0-9_]*` — anything else throws.
|
|
1354
|
-
* - `required` is a boolean; `description` is a string.
|
|
1355
|
-
*
|
|
1356
|
-
* Returns a normalized {@link SecretDef}: `required` defaulted to `true`,
|
|
1357
|
-
* `description` trimmed-or-null.
|
|
1358
|
-
*/
|
|
1359
|
-
declare function secret(name: string, opts?: SecretOptions): SecretDef;
|
|
1360
|
-
/**
|
|
1361
|
-
* Define the secrets a backend needs. Returns the discriminated
|
|
1362
|
-
* {@link SecretsConfig} the build's config extractor serializes and the deploy
|
|
1363
|
-
* checks against the target environment's vault BEFORE shipping anything.
|
|
1364
|
-
*
|
|
1365
|
-
* A name declared twice throws: two declarations of one name disagree about
|
|
1366
|
-
* something (usually `required`), and silently keeping either one is how a
|
|
1367
|
-
* secret stops being checked without anybody editing the check.
|
|
1368
|
-
*/
|
|
1369
|
-
declare function defineSecrets(input: SecretsInput): SecretsConfig;
|
|
416
|
+
declare function makeStackDts(names: StackNames): string;
|
|
1370
417
|
|
|
1371
418
|
/** Options accepted by `@Controller`. */
|
|
1372
419
|
interface ControllerOptions {
|
|
@@ -1712,96 +759,4 @@ interface ResolvedJob {
|
|
|
1712
759
|
declare function Job(options: JobOptions): <T extends abstract new (...args: never[]) => object>(ctor: T) => T;
|
|
1713
760
|
declare function getJobConfig(ctor: object): ResolvedJob;
|
|
1714
761
|
|
|
1715
|
-
|
|
1716
|
-
* resource.ts — external connections as lifecycle-managed classes.
|
|
1717
|
-
*
|
|
1718
|
-
* A `Resource` subclass models one external connection (a pooled datastore, a
|
|
1719
|
-
* stateless API client, or a per-user factory). The framework discovers each
|
|
1720
|
-
* instance, calls `init(env)` ONCE at boot with the declared secret subset, and
|
|
1721
|
-
* `shutdown()` (reverse order) on SIGTERM. On top of that lifecycle the author
|
|
1722
|
-
* exposes their own clean facade methods.
|
|
1723
|
-
*
|
|
1724
|
-
* // resources/neo4j.ts
|
|
1725
|
-
* import { Resource } from "@palbase/backend";
|
|
1726
|
-
* import neo4j, { type Driver, type Session } from "neo4j-driver";
|
|
1727
|
-
*
|
|
1728
|
-
* export class Neo4jResource extends Resource {
|
|
1729
|
-
* static secrets = ["NEO4J_URL", "NEO4J_USER", "NEO4J_PASSWORD"] as const;
|
|
1730
|
-
* private driver!: Driver;
|
|
1731
|
-
* async init(env: { NEO4J_URL: string; NEO4J_USER: string; NEO4J_PASSWORD: string }) {
|
|
1732
|
-
* this.driver = neo4j.driver(env.NEO4J_URL, neo4j.auth.basic(env.NEO4J_USER, env.NEO4J_PASSWORD));
|
|
1733
|
-
* }
|
|
1734
|
-
* async shutdown() { await this.driver.close(); }
|
|
1735
|
-
* session(): Session { return this.driver.session(); }
|
|
1736
|
-
* }
|
|
1737
|
-
* export const neo4j = new Neo4jResource(); // framework finds + manages it
|
|
1738
|
-
*
|
|
1739
|
-
* # Boot scope (NOT request-ALS)
|
|
1740
|
-
*
|
|
1741
|
-
* Resources are instantiated once at process boot. This is deliberately NOT the
|
|
1742
|
-
* per-request {@link AsyncLocalStorage} scope used for `Database`/`Cache`/… — a
|
|
1743
|
-
* connection pool must outlive a single request. The runtime discovers
|
|
1744
|
-
* resources from the project's `resources/` directory, registers each via
|
|
1745
|
-
* {@link __registerResource}, then calls {@link __runResourceBoot} before
|
|
1746
|
-
* serving and {@link __shutdownResources} on SIGTERM. Discovery is a runtime
|
|
1747
|
-
* concern; the SDK provides the base class + registry + boot/shutdown hooks.
|
|
1748
|
-
*/
|
|
1749
|
-
/** Map a declared `secrets` tuple to the `init(env)` argument type — a record
|
|
1750
|
-
* over the secret names, each `string`. An empty tuple maps to an empty
|
|
1751
|
-
* record. */
|
|
1752
|
-
type ResourceEnv<Secrets extends readonly string[]> = {
|
|
1753
|
-
[K in Secrets[number]]: string;
|
|
1754
|
-
};
|
|
1755
|
-
/**
|
|
1756
|
-
* Base class for external connections.
|
|
1757
|
-
*
|
|
1758
|
-
* - `static secrets` — OPTIONAL readonly tuple of env-var names this resource
|
|
1759
|
-
* needs. Drives (a) the `env` type passed to `init` and (b) the
|
|
1760
|
-
* missing-secret check at boot (deploy fails naming the absent secret).
|
|
1761
|
-
* - `init(env)` — called ONCE at boot with the declared secret subset. May be
|
|
1762
|
-
* sync (`void`) or async (`Promise<void>`).
|
|
1763
|
-
* - `shutdown()` — OPTIONAL drain hook, called on SIGTERM in reverse boot
|
|
1764
|
-
* order.
|
|
1765
|
-
*
|
|
1766
|
-
* @example
|
|
1767
|
-
* import { Resource } from "@palbase/backend";
|
|
1768
|
-
* import { Client } from "@googlemaps/google-maps-services-js";
|
|
1769
|
-
*
|
|
1770
|
-
* export class GoogleResource extends Resource {
|
|
1771
|
-
* static secrets = ["GOOGLE_MAPS_KEY"] as const;
|
|
1772
|
-
* private client = new Client();
|
|
1773
|
-
* private key = "";
|
|
1774
|
-
* init(env: { GOOGLE_MAPS_KEY: string }) { this.key = env.GOOGLE_MAPS_KEY; }
|
|
1775
|
-
* }
|
|
1776
|
-
* export const google = new GoogleResource();
|
|
1777
|
-
*/
|
|
1778
|
-
declare abstract class Resource {
|
|
1779
|
-
/** The env-var names this resource needs. Optional; omit for none. */
|
|
1780
|
-
static secrets?: readonly string[];
|
|
1781
|
-
/** Set up the connection from the declared secrets. Called once at boot. */
|
|
1782
|
-
abstract init(env: Record<string, string>): void | Promise<void>;
|
|
1783
|
-
/** Drain/close the connection on SIGTERM. Optional. */
|
|
1784
|
-
shutdown?(): void | Promise<void>;
|
|
1785
|
-
}
|
|
1786
|
-
/**
|
|
1787
|
-
* Register a resource instance with the boot registry. The runtime calls this
|
|
1788
|
-
* for each instance discovered under the project's `resources/` directory.
|
|
1789
|
-
* NOT part of the public author-facing API (prefixed `__`).
|
|
1790
|
-
*/
|
|
1791
|
-
declare function __registerResource(resource: Resource): void;
|
|
1792
|
-
/**
|
|
1793
|
-
* Boot every registered resource that has not yet been booted: resolve its
|
|
1794
|
-
* declared secret subset from `envMap`, then await its `init(env)`. Idempotent
|
|
1795
|
-
* — an already-booted resource is skipped. Throws (failing deploy/boot) when a
|
|
1796
|
-
* declared secret is absent, naming the missing secret. NOT part of the public
|
|
1797
|
-
* author-facing API.
|
|
1798
|
-
*/
|
|
1799
|
-
declare function __runResourceBoot(envMap: Record<string, string>): Promise<void>;
|
|
1800
|
-
/**
|
|
1801
|
-
* Shut down every booted resource in REVERSE registration order, awaiting each
|
|
1802
|
-
* `shutdown()` (a no-op when undefined). Clears the registry afterwards so a
|
|
1803
|
-
* second call is a no-op. NOT part of the public author-facing API.
|
|
1804
|
-
*/
|
|
1805
|
-
declare function __shutdownResources(): Promise<void>;
|
|
1806
|
-
|
|
1807
|
-
export { type AcsOptions, type ApnsOptions, type AuthHookEvent, Body, type ChannelAuthorizeCtx, type ChannelEntry, type ChannelGrant, type ChannelsDef, type ChannelsInput, Client, type ColumnJSON, Controller, type ControllerOptions, DEFAULT_TEMPLATE_LOCALE, type DefinedError, type DefinedErrorWithData, Delete, Deny, type DocumentHookEvent, EGRESS_CONFIG_KIND, EGRESS_TIMEOUT_DEFAULT_MS, EGRESS_TIMEOUT_MAX_MS, EGRESS_TIMEOUT_MIN_MS, type EgressConfig, type EgressInput, type EmailTemplateContent, type EmailTemplateDef, type EmailTemplateOptions, EntitlementKey, FLAGS_CONFIG_KIND, type FcmOptions, type FileDeletedEvent, type FileUploadedEvent, type FlagDef, type FlagJsonObject, type FlagJsonValue, type FlagOptions, type FlagType, type FlagValue, type FlagsConfig, type FlagsInput, Get, Headers, Hook, type HookFn, type HookMeta, HttpError, Job, type JobMeta, type JobOptions, LimitKey, type ModuleClientsConfig, type ModuleTransport, NOTIFICATIONS_CONFIG_KIND, type NotificationsConfig, type NotificationsInput, On, OptionalUser, type OwnedTablesOf, PROVIDER_CATALOG, PalbaseModuleError, PalbaseResult, Param, Patch, type PolicyJSON, Post, type ProviderCatalogEntry, type ProviderDef, type ProviderName, type ProviderOptions, type PurchasesManifest, Put, Query, QueryParams, RESERVED_SECRET_PREFIX, type RegisteredError, Req, RequestId, type RequestOptions, RequireEntitlement, type ResolvedHookClass, type ResolvedJob, type ResolvedWebhook, Resource, type ResourceEnv, RouteOptions, SECRETS_CONFIG_KIND, SchemaDef, type SchemaJSON, type SecretDef, type SecretOptions, type SecretsConfig, type SecretsInput, type Seed, type SeedFor, type SeedJson, type SeedRowFor, type SendgridOptions, type SesOptions, type SignatureSpec, type SmsTemplateContent, type SmsTemplateDef, type SmsTemplateOptions, type SmtpOptions, Spend, type SpendMeta, TEST_USERS_CONFIG_KIND, type TableGraph, type TableJSON, TableTypes, Tables, type TemplatesConfig, type TemplatesInput, type TestUserDef, type TestUserOptions, type TestUsersConfig, type TestUsersInput, TraceId, type TransportConfig, type TwilioOptions, User, Webhook, type WebhookEventHandler, type WebhookMeta, type WebhookOptions, type WebhookProvider, type WebhookRequest, __registerResource, __resetRegisteredControllers, __runResourceBoot, __shutdownResources, buildModuleClients, buildProvider, defineChannels, defineEgress, defineError, defineFlags, defineNotifications, defineSecrets, defineTestUsers, entitlementFor, extractVariables, flag, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makePurchasesDts, ownerOnly, publicChannel, reservedSecretKey, secret, spendFor, testUser, toSchemaJSON };
|
|
762
|
+
export { type AuthHookEvent, Body, type ChannelAuthorizeCtx, type ChannelEntry, type ChannelGrant, type ChannelsDef, type ChannelsInput, Client, type ColumnJSON, Controller, type ControllerOptions, type DefinedError, type DefinedErrorWithData, Delete, Deny, type DocumentHookEvent, type FileDeletedEvent, type FileUploadedEvent, Get, Headers, Hook, type HookFn, type HookMeta, HttpError, Job, type JobMeta, type JobOptions, type ModuleClientsConfig, type ModuleTransport, On, OptionalUser, PalbaseModuleError, PalbaseResult, Param, Patch, type PolicyJSON, Post, Put, Query, QueryParams, type RegisteredError, Req, RequestId, type RequestOptions, type ResolvedHookClass, type ResolvedJob, type ResolvedWebhook, RouteOptions, SchemaDef, type SchemaJSON, type SignatureSpec, type StackNames, type TableJSON, TraceId, type TransportConfig, User, Webhook, type WebhookEventHandler, type WebhookMeta, type WebhookOptions, type WebhookProvider, type WebhookRequest, __resetRegisteredControllers, buildModuleClients, defineChannels, defineError, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makeStackDts, ownerOnly, publicChannel, toSchemaJSON };
|