@palbase/backend 24.3.0 → 25.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/bin/palbase-backend.cjs +103 -60
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +17 -13
  4. package/dist/bin/palbase-backend.js.map +1 -1
  5. package/dist/{chunk-EIXCY4SS.js → chunk-34I4GB7D.js} +82 -49
  6. package/dist/chunk-34I4GB7D.js.map +1 -0
  7. package/dist/{chunk-UWSYTUGM.js → chunk-35PNTIRN.js} +48 -1
  8. package/dist/chunk-35PNTIRN.js.map +1 -0
  9. package/dist/chunk-HBOJLP2Z.js +840 -0
  10. package/dist/chunk-HBOJLP2Z.js.map +1 -0
  11. package/dist/{chunk-7Z6MGMXQ.js → chunk-XJ2RSHEU.js} +11 -5
  12. package/dist/chunk-XJ2RSHEU.js.map +1 -0
  13. package/dist/{chunk-ERDL5VAE.js → chunk-YOY5DFQS.js} +2 -2
  14. package/dist/db/env.cjs.map +1 -1
  15. package/dist/db/env.d.cts +31 -14
  16. package/dist/db/env.d.ts +31 -14
  17. package/dist/db/index.cjs +226 -111
  18. package/dist/db/index.cjs.map +1 -1
  19. package/dist/db/index.d.cts +1 -1
  20. package/dist/db/index.d.ts +1 -1
  21. package/dist/db/index.js +11 -1
  22. package/dist/engine/index.cjs +89 -50
  23. package/dist/engine/index.cjs.map +1 -1
  24. package/dist/engine/index.d.cts +2 -2
  25. package/dist/engine/index.d.ts +2 -2
  26. package/dist/engine/index.js +3 -3
  27. package/dist/{index-BTMYod_l.d.ts → index-B4CcpqLb.d.ts} +224 -75
  28. package/dist/{index-DEneI8Mn.d.ts → index-B8v6hVyU.d.ts} +5 -2
  29. package/dist/{index-BLAbr9ZH.d.cts → index-DmVyY6N7.d.cts} +224 -75
  30. package/dist/{index-C-ALG22n.d.cts → index-VsjBQ4Kw.d.cts} +5 -2
  31. package/dist/index.cjs +580 -301
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +125 -22
  34. package/dist/index.d.ts +125 -22
  35. package/dist/index.js +173 -217
  36. package/dist/index.js.map +1 -1
  37. package/dist/openapi/index.cjs +100 -36
  38. package/dist/openapi/index.cjs.map +1 -1
  39. package/dist/openapi/index.js +59 -2
  40. package/dist/openapi/index.js.map +1 -1
  41. package/docs/README.md +64 -31
  42. package/docs/endpoints.md +25 -28
  43. package/docs/llms-full.txt +430 -153
  44. package/docs/schema.md +303 -91
  45. package/docs/services.md +39 -4
  46. package/package.json +1 -1
  47. package/template/AGENTS.md +119 -314
  48. package/template/CLAUDE.md +13 -0
  49. package/template/controllers/notes.controller.ts +6 -13
  50. package/template/db/public.ts +38 -0
  51. package/template/models/notes/create.ts +38 -0
  52. package/template/package.json +6 -3
  53. package/template/services/note.service.test.ts +45 -0
  54. package/template/services/note.service.ts +2 -2
  55. package/dist/chunk-7Z6MGMXQ.js.map +0 -1
  56. package/dist/chunk-D5CQES25.js +0 -556
  57. package/dist/chunk-D5CQES25.js.map +0 -1
  58. package/dist/chunk-EIXCY4SS.js.map +0 -1
  59. package/dist/chunk-UWSYTUGM.js.map +0 -1
  60. package/template/db/schema.ts +0 -35
  61. /package/dist/{chunk-ERDL5VAE.js.map → chunk-YOY5DFQS.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { h as PalbaseResult, A as AuthSpec, H as HttpError } from './endpoint-BSGw1pTu.cjs';
2
2
  export { i as AuthConfig, B as BadRequest, C as CacheClient, j as ClientInfo, k as Conflict, D as DBClient, f 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, g 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 UniqueViolation, bq as UserT, br as VerifiedDevice, bs as dec, bt as defineMiddleware, bu as inc, bv as now } from './endpoint-BSGw1pTu.cjs';
3
- import { M as ModuleClients } from './index-C-ALG22n.cjs';
4
- export { C as Cache, D as Database, a as Documents, F as Flags, L as LifecycleHook, b as Log, N as Notifications, R as Realtime, c as RequestStore, d as RuntimeServices, S as Secrets, e as ShutdownRunner, f as Storage, _ as __getRuntime, g as __requestALS, h as __resetLifecycleHooks, i as __runStartHooks, j as __runWithRuntime, k as __setRuntime, o as onShutdown, l as onStart } from './index-C-ALG22n.cjs';
5
- import { S as SchemaDef } from './index-BLAbr9ZH.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-BLAbr9ZH.cjs';
3
+ import { M as ModuleClients } from './index-VsjBQ4Kw.cjs';
4
+ export { C as Cache, D as Database, a as Documents, F as Flags, L as LifecycleHook, b as Log, N as Notifications, R as Realtime, c as RequestStore, d as RuntimeServices, S as Secrets, e as ShutdownRunner, f as Storage, _ as __getRuntime, g as __requestALS, h as __resetLifecycleHooks, i as __runStartHooks, j as __runWithRuntime, k as __setRuntime, o as onShutdown, l as onStart } from './index-VsjBQ4Kw.cjs';
5
+ import { S as SchemaDef } from './index-DmVyY6N7.cjs';
6
+ export { A as AnyColumn, C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, f as EnvSchemas, g as EnvServiceDatabase, h as EnvTables, E as EnvTypedDatabase, i as EnvTypedTable, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, j as PalbaseExtension, k as PolicyBuilder, l as PolicyCommand, m as PolicyDef, n as PolicyMode, R as RawConstraintDef, o as RowShape, T as TABLE_META, p as TableDef, q as TableHandle, r as TableInput, s as TxPlan, t as TxTables, u as TypedDB, v as TypedTable, w as TypedTx, x as bigint, y as boolean, z as defineSchema, B as defineTable, D as enumType, F as installationRef, G as integer, H as isPalbaseExtension, J as jsonb, K as makeTypedDB, L as numeric, M as openai, N as ownedByUser, Q as policy, U as raw, V as text, W as timestamp, X as userRef, Y as uuid, Z as vector } from './index-DmVyY6N7.cjs';
7
7
  export { TableTypes, Tables } from './db/env.cjs';
8
8
  export { PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName } from './stack.cjs';
9
9
  import { a as RouteOptions } from './registry-CgJvDYUW.cjs';
@@ -160,6 +160,14 @@ interface PolicyJSON {
160
160
  }
161
161
  /** One table. Mirrors Go's `schema.TableJSON`. */
162
162
  interface TableJSON {
163
+ /**
164
+ * The schema this table lives in. `public` unless declared otherwise.
165
+ *
166
+ * The table carries it because the diff iterates over KEYS but passes the
167
+ * VALUE around: a bare name inside a qualified key space writes the migration
168
+ * into the wrong schema, silently.
169
+ */
170
+ schema: string;
163
171
  name: string;
164
172
  columns: Record<string, ColumnJSON>;
165
173
  rls: boolean;
@@ -200,6 +208,19 @@ interface MemoryJSON {
200
208
  interface SchemaJSON {
201
209
  tables: Record<string, TableJSON>;
202
210
  extensions: string[];
211
+ /**
212
+ * Every declared schema, with its HTTP reachability.
213
+ *
214
+ * The flag has nowhere else to live: `/v1/db` must know which schemas are
215
+ * reachable, and introspection must know which schemas the project DECLARED —
216
+ * a live database also contains internal module schemas that are none of the
217
+ * diff's business.
218
+ */
219
+ schemas: SchemaMetaJSON[];
220
+ }
221
+ interface SchemaMetaJSON {
222
+ name: string;
223
+ exposed: boolean;
203
224
  }
204
225
  /** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).
205
226
  * `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);
@@ -233,13 +254,12 @@ interface SearchJSON {
233
254
  validity?: boolean;
234
255
  }
235
256
  /**
236
- * Serialize a `defineSchema(...)` result into the JSON the deploy applies.
257
+ * Serialize declared schemas into the JSON the deploy applies.
237
258
  *
238
- * Keyed by the SQL table name rather than by the author's object key, because
239
- * that is the name the live database answers to and the diff on the other side
240
- * compares against what it introspected.
259
+ * Takes every schema the project declares one file per schema because a
260
+ * cross-schema foreign key can only be checked when both ends are in hand.
241
261
  */
242
- declare function toSchemaJSON(schema: SchemaDef): SchemaJSON;
262
+ declare function toSchemaJSON(schemas: readonly SchemaDef[]): SchemaJSON;
243
263
 
244
264
  /**
245
265
  * channels.ts — the realtime channel authorization DSL (spec C-5).
@@ -348,18 +368,27 @@ declare function defineChannels(map: ChannelsInput): ChannelsDef;
348
368
  * The output is FLAT: each table gets a `{ row: {...}; insert: {...} }` entry
349
369
  * with plain TypeScript object types. The phantom `ColumnBuilder<...>` type
350
370
  * NEVER appears in the generated `.d.ts` — that type only lives at authoring
351
- * time inside `db/schema.ts`.
371
+ * time inside the project's `db/*.ts` schema files.
352
372
  */
353
373
 
354
374
  /**
355
- * Generate the full `palbase-env.d.ts` text for a schema.
375
+ * Generate the full `palbase-env.d.ts` text for the project's schemas.
376
+ *
377
+ * The emitted file ends in `export {};` — same as `makeStackDts`. Without it the
378
+ * `.d.ts` is a global script, and `declare module "…"` there DECLARES an ambient
379
+ * module (shadowing the real one, so every export of `@palbase/backend/env`
380
+ * silently becomes invalid) instead of AUGMENTING it. Measured on a minimal tsc
381
+ * repro: with the line, exit 0; without it, `TS2305: Module '"…"' has no
382
+ * exported member`. The line was dropped once in a rewrite and nothing caught
383
+ * it, so `env-gen.test.ts` now gates it directly.
356
384
  *
357
385
  * @example
358
386
  * import { makeEnvDts } from "@palbase/backend";
359
- * import schema from "./db/schema.js";
360
- * writeFileSync("palbase-env.d.ts", makeEnvDts(schema));
387
+ * import publicSchema from "./db/public.js";
388
+ * import billing from "./db/billing.js";
389
+ * writeFileSync("palbase-env.d.ts", makeEnvDts([publicSchema, billing]));
361
390
  */
362
- declare function makeEnvDts(schema: SchemaDef): string;
391
+ declare function makeEnvDts(schemas: readonly SchemaDef[]): string;
363
392
 
364
393
  /**
365
394
  * stack-gen.ts — generate the `palbase-stack.d.ts` text from the names the
@@ -497,20 +526,20 @@ declare function Controller(basePath: string, options?: ControllerOptions): <T e
497
526
  declare function assertZeroArgConstructor(Ctrl: unknown, kind: string): void;
498
527
 
499
528
  /** A legacy method decorator. */
500
- type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
529
+ type MethodDecorator$1 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
501
530
  /** `@Get(subpath, options?)` — declare a GET route. */
502
- declare const Get: (subpath: string, options?: RouteOptions) => MethodDecorator;
531
+ declare const Get: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
503
532
  /** `@Post(subpath, options?)` — declare a POST route. */
504
- declare const Post: (subpath: string, options?: RouteOptions) => MethodDecorator;
533
+ declare const Post: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
505
534
  /** `@Put(subpath, options?)` — declare a PUT route. */
506
- declare const Put: (subpath: string, options?: RouteOptions) => MethodDecorator;
535
+ declare const Put: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
507
536
  /** `@Patch(subpath, options?)` — declare a PATCH route. */
508
- declare const Patch: (subpath: string, options?: RouteOptions) => MethodDecorator;
537
+ declare const Patch: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
509
538
  /** `@Delete(subpath, options?)` — declare a DELETE route. */
510
- declare const Delete: (subpath: string, options?: RouteOptions) => MethodDecorator;
539
+ declare const Delete: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
511
540
  /** `@Query(subpath, options?)` — declare an HTTP QUERY route (RFC 10008):
512
541
  * safe + idempotent like GET, body-carrying like POST. Input rides `@Body`. */
513
- declare const Query: (subpath: string, options?: RouteOptions) => MethodDecorator;
542
+ declare const Query: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
514
543
 
515
544
  /**
516
545
  * The payloads a hook handler receives, and nothing else.
@@ -649,6 +678,80 @@ declare function Hook(event: string): (target: object, fnName: string | symbol)
649
678
  * here supplies them, so the field would be `undefined` on every event. */
650
679
  declare function getHookConfig(ctor: object): ResolvedHookClass;
651
680
 
681
+ interface RoomOptions {
682
+ /**
683
+ * The events this room sends to its clients, by name.
684
+ *
685
+ * Declared rather than inferred, because a room emits from anywhere in the
686
+ * class — there is no return type to read. The map is the room's public
687
+ * surface: it becomes a Swift enum and a TypeScript union in the generated
688
+ * clients, so a device gets `case .tick(n:)` instead of an opaque bag.
689
+ *
690
+ * Per-event rather than one blob because realtime is event-ADDRESSED all the
691
+ * way down (`Realtime.broadcast(channel, EVENT, payload)`).
692
+ */
693
+ events: Record<string, ZodTypeAny>;
694
+ /**
695
+ * How long a room is held after its last sign of life, in milliseconds.
696
+ *
697
+ * Default 60_000, and the floor is not a matter of taste: the decision must
698
+ * survive the SLOWEST client's heartbeat gap twice over, and the web SDK
699
+ * beats every 25 s (palbe/src/realtime/connection.ts:133) against iOS's 2 s
700
+ * (RealtimeConnection.swift:162). A shorter default would declare healthy web
701
+ * clients dead between two beats.
702
+ *
703
+ * Raise it for an upstream that is expensive to restart; lower it (never
704
+ * below ~50 s while web beats at 25 s) for one that is cheap.
705
+ */
706
+ graceMs?: number;
707
+ }
708
+ /**
709
+ * Declare a class as a room.
710
+ *
711
+ * ```ts
712
+ * @Room("chat:{roomId}", { events: { message: Message } })
713
+ * class ChatRoom {
714
+ * @OnAuthorize() can({ user, params }) { … }
715
+ * @OnFirst() open(ctx) { … } // the room filled
716
+ * @OnEmpty() close(ctx) { … } // nobody is watching any more
717
+ * @OnMessage("say", Say) say(ctx) { … }
718
+ * }
719
+ * ```
720
+ *
721
+ * The pattern is the topic: `chat:{roomId}` addresses `chat:42`. A room is
722
+ * marked by the PRESENCE of this config — never by a name, a base class or a
723
+ * naming convention.
724
+ */
725
+ declare function Room(pattern: string, options: RoomOptions): <T extends abstract new (...args: never[]) => object>(ctor: T) => T;
726
+ /** Who may enter. Return a grant to admit, `null` to refuse. */
727
+ declare const OnAuthorize: () => MethodDecorator;
728
+ /**
729
+ * The room is occupied and nobody owns it — start whatever the room needs.
730
+ *
731
+ * Deliberately a CONDITION rather than a 0→1 transition, and the difference is
732
+ * load-bearing: a runtime restart, a deploy pointer swap (the previous release
733
+ * is never torn down) and an owner that died all leave a full room with nobody
734
+ * holding it. A transition would fire once and never again; a condition
735
+ * recovers every time.
736
+ *
737
+ * Exactly one runtime in the cluster enters this hook for a given room, so
738
+ * three devices never open three upstreams.
739
+ */
740
+ declare const OnFirst: () => MethodDecorator;
741
+ /** A device arrived. Anything emitted here reaches ONLY that device. */
742
+ declare const OnJoin: () => MethodDecorator;
743
+ /** A device left. */
744
+ declare const OnLeave: () => MethodDecorator;
745
+ /** Nobody is watching any more — stop whatever `@OnFirst` started. */
746
+ declare const OnEmpty: () => MethodDecorator;
747
+ /**
748
+ * A message from a client, validated against `schema` before the method runs.
749
+ *
750
+ * A payload that fails the schema never reaches the method: the client is told
751
+ * why, and the room's code only ever sees the shape it declared.
752
+ */
753
+ declare function OnMessage(name: string, schema: ZodTypeAny): MethodDecorator;
754
+
652
755
  /** A legacy parameter decorator. */
653
756
  type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
654
757
  /** `@Body(schema)` — inject the request body, validated against `schema`. The
@@ -817,4 +920,4 @@ interface ResolvedJob {
817
920
  declare function Job(options: JobOptions): <T extends abstract new (...args: never[]) => object>(ctor: T) => T;
818
921
  declare function getJobConfig(ctor: object): ResolvedJob;
819
922
 
820
- 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, __resetDefaultAuth, __resetRegisteredControllers, assertZeroArgConstructor, buildModuleClients, defineChannels, defineDefaultAuth, defineError, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makeStackDts, ownerOnly, publicChannel, resolveEffectiveAuth, toSchemaJSON };
923
+ 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, OnAuthorize, OnEmpty, OnFirst, OnJoin, OnLeave, OnMessage, OptionalUser, PalbaseModuleError, PalbaseResult, Param, Patch, type PolicyJSON, Post, Put, Query, QueryParams, type RegisteredError, Req, RequestId, type RequestOptions, type ResolvedHookClass, type ResolvedJob, type ResolvedWebhook, Room, type RoomOptions, 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, __resetDefaultAuth, __resetRegisteredControllers, assertZeroArgConstructor, buildModuleClients, defineChannels, defineDefaultAuth, defineError, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makeStackDts, ownerOnly, publicChannel, resolveEffectiveAuth, toSchemaJSON };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { h as PalbaseResult, A as AuthSpec, H as HttpError } from './endpoint-DMwJjEHQ.js';
2
2
  export { i as AuthConfig, B as BadRequest, C as CacheClient, j as ClientInfo, k as Conflict, D as DBClient, f 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, g 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 UniqueViolation, bq as UserT, br as VerifiedDevice, bs as dec, bt as defineMiddleware, bu as inc, bv as now } from './endpoint-DMwJjEHQ.js';
3
- import { M as ModuleClients } from './index-DEneI8Mn.js';
4
- export { C as Cache, D as Database, a as Documents, F as Flags, L as LifecycleHook, b as Log, N as Notifications, R as Realtime, c as RequestStore, d as RuntimeServices, S as Secrets, e as ShutdownRunner, f as Storage, _ as __getRuntime, g as __requestALS, h as __resetLifecycleHooks, i as __runStartHooks, j as __runWithRuntime, k as __setRuntime, o as onShutdown, l as onStart } from './index-DEneI8Mn.js';
5
- import { S as SchemaDef } from './index-BTMYod_l.js';
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-BTMYod_l.js';
3
+ import { M as ModuleClients } from './index-B8v6hVyU.js';
4
+ export { C as Cache, D as Database, a as Documents, F as Flags, L as LifecycleHook, b as Log, N as Notifications, R as Realtime, c as RequestStore, d as RuntimeServices, S as Secrets, e as ShutdownRunner, f as Storage, _ as __getRuntime, g as __requestALS, h as __resetLifecycleHooks, i as __runStartHooks, j as __runWithRuntime, k as __setRuntime, o as onShutdown, l as onStart } from './index-B8v6hVyU.js';
5
+ import { S as SchemaDef } from './index-B4CcpqLb.js';
6
+ export { A as AnyColumn, C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, f as EnvSchemas, g as EnvServiceDatabase, h as EnvTables, E as EnvTypedDatabase, i as EnvTypedTable, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, j as PalbaseExtension, k as PolicyBuilder, l as PolicyCommand, m as PolicyDef, n as PolicyMode, R as RawConstraintDef, o as RowShape, T as TABLE_META, p as TableDef, q as TableHandle, r as TableInput, s as TxPlan, t as TxTables, u as TypedDB, v as TypedTable, w as TypedTx, x as bigint, y as boolean, z as defineSchema, B as defineTable, D as enumType, F as installationRef, G as integer, H as isPalbaseExtension, J as jsonb, K as makeTypedDB, L as numeric, M as openai, N as ownedByUser, Q as policy, U as raw, V as text, W as timestamp, X as userRef, Y as uuid, Z as vector } from './index-B4CcpqLb.js';
7
7
  export { TableTypes, Tables } from './db/env.js';
8
8
  export { PalbaseBucketName, PalbaseFlagKey, PalbaseSecretName } from './stack.js';
9
9
  import { a as RouteOptions } from './registry-B8pld3fj.js';
@@ -160,6 +160,14 @@ interface PolicyJSON {
160
160
  }
161
161
  /** One table. Mirrors Go's `schema.TableJSON`. */
162
162
  interface TableJSON {
163
+ /**
164
+ * The schema this table lives in. `public` unless declared otherwise.
165
+ *
166
+ * The table carries it because the diff iterates over KEYS but passes the
167
+ * VALUE around: a bare name inside a qualified key space writes the migration
168
+ * into the wrong schema, silently.
169
+ */
170
+ schema: string;
163
171
  name: string;
164
172
  columns: Record<string, ColumnJSON>;
165
173
  rls: boolean;
@@ -200,6 +208,19 @@ interface MemoryJSON {
200
208
  interface SchemaJSON {
201
209
  tables: Record<string, TableJSON>;
202
210
  extensions: string[];
211
+ /**
212
+ * Every declared schema, with its HTTP reachability.
213
+ *
214
+ * The flag has nowhere else to live: `/v1/db` must know which schemas are
215
+ * reachable, and introspection must know which schemas the project DECLARED —
216
+ * a live database also contains internal module schemas that are none of the
217
+ * diff's business.
218
+ */
219
+ schemas: SchemaMetaJSON[];
220
+ }
221
+ interface SchemaMetaJSON {
222
+ name: string;
223
+ exposed: boolean;
203
224
  }
204
225
  /** C-4 wire şekli — Go'nun SearchJSON'ıyla ALAN ADI sözleşmesi (C-5).
205
226
  * `mode`/`chunks` yalnız yeni-biçim chunk-modunda emit edilir (D-010);
@@ -233,13 +254,12 @@ interface SearchJSON {
233
254
  validity?: boolean;
234
255
  }
235
256
  /**
236
- * Serialize a `defineSchema(...)` result into the JSON the deploy applies.
257
+ * Serialize declared schemas into the JSON the deploy applies.
237
258
  *
238
- * Keyed by the SQL table name rather than by the author's object key, because
239
- * that is the name the live database answers to and the diff on the other side
240
- * compares against what it introspected.
259
+ * Takes every schema the project declares one file per schema because a
260
+ * cross-schema foreign key can only be checked when both ends are in hand.
241
261
  */
242
- declare function toSchemaJSON(schema: SchemaDef): SchemaJSON;
262
+ declare function toSchemaJSON(schemas: readonly SchemaDef[]): SchemaJSON;
243
263
 
244
264
  /**
245
265
  * channels.ts — the realtime channel authorization DSL (spec C-5).
@@ -348,18 +368,27 @@ declare function defineChannels(map: ChannelsInput): ChannelsDef;
348
368
  * The output is FLAT: each table gets a `{ row: {...}; insert: {...} }` entry
349
369
  * with plain TypeScript object types. The phantom `ColumnBuilder<...>` type
350
370
  * NEVER appears in the generated `.d.ts` — that type only lives at authoring
351
- * time inside `db/schema.ts`.
371
+ * time inside the project's `db/*.ts` schema files.
352
372
  */
353
373
 
354
374
  /**
355
- * Generate the full `palbase-env.d.ts` text for a schema.
375
+ * Generate the full `palbase-env.d.ts` text for the project's schemas.
376
+ *
377
+ * The emitted file ends in `export {};` — same as `makeStackDts`. Without it the
378
+ * `.d.ts` is a global script, and `declare module "…"` there DECLARES an ambient
379
+ * module (shadowing the real one, so every export of `@palbase/backend/env`
380
+ * silently becomes invalid) instead of AUGMENTING it. Measured on a minimal tsc
381
+ * repro: with the line, exit 0; without it, `TS2305: Module '"…"' has no
382
+ * exported member`. The line was dropped once in a rewrite and nothing caught
383
+ * it, so `env-gen.test.ts` now gates it directly.
356
384
  *
357
385
  * @example
358
386
  * import { makeEnvDts } from "@palbase/backend";
359
- * import schema from "./db/schema.js";
360
- * writeFileSync("palbase-env.d.ts", makeEnvDts(schema));
387
+ * import publicSchema from "./db/public.js";
388
+ * import billing from "./db/billing.js";
389
+ * writeFileSync("palbase-env.d.ts", makeEnvDts([publicSchema, billing]));
361
390
  */
362
- declare function makeEnvDts(schema: SchemaDef): string;
391
+ declare function makeEnvDts(schemas: readonly SchemaDef[]): string;
363
392
 
364
393
  /**
365
394
  * stack-gen.ts — generate the `palbase-stack.d.ts` text from the names the
@@ -497,20 +526,20 @@ declare function Controller(basePath: string, options?: ControllerOptions): <T e
497
526
  declare function assertZeroArgConstructor(Ctrl: unknown, kind: string): void;
498
527
 
499
528
  /** A legacy method decorator. */
500
- type MethodDecorator = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
529
+ type MethodDecorator$1 = (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
501
530
  /** `@Get(subpath, options?)` — declare a GET route. */
502
- declare const Get: (subpath: string, options?: RouteOptions) => MethodDecorator;
531
+ declare const Get: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
503
532
  /** `@Post(subpath, options?)` — declare a POST route. */
504
- declare const Post: (subpath: string, options?: RouteOptions) => MethodDecorator;
533
+ declare const Post: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
505
534
  /** `@Put(subpath, options?)` — declare a PUT route. */
506
- declare const Put: (subpath: string, options?: RouteOptions) => MethodDecorator;
535
+ declare const Put: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
507
536
  /** `@Patch(subpath, options?)` — declare a PATCH route. */
508
- declare const Patch: (subpath: string, options?: RouteOptions) => MethodDecorator;
537
+ declare const Patch: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
509
538
  /** `@Delete(subpath, options?)` — declare a DELETE route. */
510
- declare const Delete: (subpath: string, options?: RouteOptions) => MethodDecorator;
539
+ declare const Delete: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
511
540
  /** `@Query(subpath, options?)` — declare an HTTP QUERY route (RFC 10008):
512
541
  * safe + idempotent like GET, body-carrying like POST. Input rides `@Body`. */
513
- declare const Query: (subpath: string, options?: RouteOptions) => MethodDecorator;
542
+ declare const Query: (subpath: string, options?: RouteOptions) => MethodDecorator$1;
514
543
 
515
544
  /**
516
545
  * The payloads a hook handler receives, and nothing else.
@@ -649,6 +678,80 @@ declare function Hook(event: string): (target: object, fnName: string | symbol)
649
678
  * here supplies them, so the field would be `undefined` on every event. */
650
679
  declare function getHookConfig(ctor: object): ResolvedHookClass;
651
680
 
681
+ interface RoomOptions {
682
+ /**
683
+ * The events this room sends to its clients, by name.
684
+ *
685
+ * Declared rather than inferred, because a room emits from anywhere in the
686
+ * class — there is no return type to read. The map is the room's public
687
+ * surface: it becomes a Swift enum and a TypeScript union in the generated
688
+ * clients, so a device gets `case .tick(n:)` instead of an opaque bag.
689
+ *
690
+ * Per-event rather than one blob because realtime is event-ADDRESSED all the
691
+ * way down (`Realtime.broadcast(channel, EVENT, payload)`).
692
+ */
693
+ events: Record<string, ZodTypeAny>;
694
+ /**
695
+ * How long a room is held after its last sign of life, in milliseconds.
696
+ *
697
+ * Default 60_000, and the floor is not a matter of taste: the decision must
698
+ * survive the SLOWEST client's heartbeat gap twice over, and the web SDK
699
+ * beats every 25 s (palbe/src/realtime/connection.ts:133) against iOS's 2 s
700
+ * (RealtimeConnection.swift:162). A shorter default would declare healthy web
701
+ * clients dead between two beats.
702
+ *
703
+ * Raise it for an upstream that is expensive to restart; lower it (never
704
+ * below ~50 s while web beats at 25 s) for one that is cheap.
705
+ */
706
+ graceMs?: number;
707
+ }
708
+ /**
709
+ * Declare a class as a room.
710
+ *
711
+ * ```ts
712
+ * @Room("chat:{roomId}", { events: { message: Message } })
713
+ * class ChatRoom {
714
+ * @OnAuthorize() can({ user, params }) { … }
715
+ * @OnFirst() open(ctx) { … } // the room filled
716
+ * @OnEmpty() close(ctx) { … } // nobody is watching any more
717
+ * @OnMessage("say", Say) say(ctx) { … }
718
+ * }
719
+ * ```
720
+ *
721
+ * The pattern is the topic: `chat:{roomId}` addresses `chat:42`. A room is
722
+ * marked by the PRESENCE of this config — never by a name, a base class or a
723
+ * naming convention.
724
+ */
725
+ declare function Room(pattern: string, options: RoomOptions): <T extends abstract new (...args: never[]) => object>(ctor: T) => T;
726
+ /** Who may enter. Return a grant to admit, `null` to refuse. */
727
+ declare const OnAuthorize: () => MethodDecorator;
728
+ /**
729
+ * The room is occupied and nobody owns it — start whatever the room needs.
730
+ *
731
+ * Deliberately a CONDITION rather than a 0→1 transition, and the difference is
732
+ * load-bearing: a runtime restart, a deploy pointer swap (the previous release
733
+ * is never torn down) and an owner that died all leave a full room with nobody
734
+ * holding it. A transition would fire once and never again; a condition
735
+ * recovers every time.
736
+ *
737
+ * Exactly one runtime in the cluster enters this hook for a given room, so
738
+ * three devices never open three upstreams.
739
+ */
740
+ declare const OnFirst: () => MethodDecorator;
741
+ /** A device arrived. Anything emitted here reaches ONLY that device. */
742
+ declare const OnJoin: () => MethodDecorator;
743
+ /** A device left. */
744
+ declare const OnLeave: () => MethodDecorator;
745
+ /** Nobody is watching any more — stop whatever `@OnFirst` started. */
746
+ declare const OnEmpty: () => MethodDecorator;
747
+ /**
748
+ * A message from a client, validated against `schema` before the method runs.
749
+ *
750
+ * A payload that fails the schema never reaches the method: the client is told
751
+ * why, and the room's code only ever sees the shape it declared.
752
+ */
753
+ declare function OnMessage(name: string, schema: ZodTypeAny): MethodDecorator;
754
+
652
755
  /** A legacy parameter decorator. */
653
756
  type ParameterDecorator = (target: object, propertyKey: string | symbol, parameterIndex: number) => void;
654
757
  /** `@Body(schema)` — inject the request body, validated against `schema`. The
@@ -817,4 +920,4 @@ interface ResolvedJob {
817
920
  declare function Job(options: JobOptions): <T extends abstract new (...args: never[]) => object>(ctor: T) => T;
818
921
  declare function getJobConfig(ctor: object): ResolvedJob;
819
922
 
820
- 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, __resetDefaultAuth, __resetRegisteredControllers, assertZeroArgConstructor, buildModuleClients, defineChannels, defineDefaultAuth, defineError, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makeStackDts, ownerOnly, publicChannel, resolveEffectiveAuth, toSchemaJSON };
923
+ 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, OnAuthorize, OnEmpty, OnFirst, OnJoin, OnLeave, OnMessage, OptionalUser, PalbaseModuleError, PalbaseResult, Param, Patch, type PolicyJSON, Post, Put, Query, QueryParams, type RegisteredError, Req, RequestId, type RequestOptions, type ResolvedHookClass, type ResolvedJob, type ResolvedWebhook, Room, type RoomOptions, 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, __resetDefaultAuth, __resetRegisteredControllers, assertZeroArgConstructor, buildModuleClients, defineChannels, defineDefaultAuth, defineError, getErrorRegistry, getHookConfig, getJobConfig, getRegisteredControllers, getWebhookConfig, makeEnvDts, makeHttpClient, makeStackDts, ownerOnly, publicChannel, resolveEffectiveAuth, toSchemaJSON };