clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

feat/fix-sync-enrollment-startup
lofi / package / schema / mod.ts
mod.ts 9.0K
1/**2 * Declare application tables, permissions, and migrations without importing3 * Jazz directly.4 *5 * This module is a curated re-export of the pinned Jazz 2 schema DSL: the6 * same names and semantics, narrowed to the surface lofi documents and tests.7 * Author code imports {@link s} from here instead of `jazz-tools`, so version8 * bumps and upstream renames are absorbed by the package rather than by every9 * application schema.10 *11 * ```ts12 * import { s } from "@nzip/lofi/schema";13 *14 * export const app = s.defineApp({15 * tasks: s.table({16 * text: s.string(),17 * completed: s.boolean(),18 * createdAt: s.timestamp(),19 * }),20 * });21 * ```22 *23 * Shared-field columns ({@link sharedEncryptedText}, {@link sharedEncryptedJson})24 * declare only the sealed data shape here; the policy and key-lifecycle half —25 * group templates, key bootstrap and rotation, member reconciliation — lives in26 * `@nzip/lofi/access`, and pin remediation for changed peer keys is surfaced27 * through the main `@nzip/lofi` entry.28 *29 * @module30 */31import { schema } from "jazz-tools";32import { effect, insert, log, mutation, remove, update } from "./effects.ts";33import { chain, debug, mark, notice, trace, webhook } from "./effect-library.ts";34import {35 encryptedDate,36 encryptedJson,37 encryptedNumber,38 encryptedText,39 registerEncryptedColumns,40} from "./encrypted.ts";41import {42 defineNestedApp,43 defineNestedPermissions,44 flattenNestedSchema,45 mergeNestedPermissions,46} from "./nested.ts";47import { plain, privateTable } from "./private-table.ts";48import { sharedEncryptedJson, sharedEncryptedText } from "./shared-encrypted.ts";4950/**51 * The curated schema DSL type. Every Jazz member is the pinned Jazz 252 * original, unchanged; deprecated members (`rename`) are omitted, and53 * everything else re-exports one-to-one. The nested-namespace members54 * (`defineNestedApp`, `defineNestedPermissions`, `mergeNestedPermissions`,55 * `flattenNestedSchema`) are lofi-owned: a naming layer over the pinned56 * `defineSliceableApp`, not part of the Jazz DSL.57 */58export type SchemaDsl =59 & Pick<60 typeof schema,61 // Column constructors.62 | "string"63 | "boolean"64 | "int"65 | "float"66 | "timestamp"67 | "bytes"68 | "json"69 | "enum"70 | "ref"71 | "array"72 // Column migration operations.73 | "add"74 | "drop"75 | "renameFrom"76 // Tables, schemas, and apps.77 | "table"78 | "defineSchema"79 | "defineApp"80 | "defineSliceableApp"81 // Schema migrations.82 | "defineMigration"83 | "renameTableFrom"84 // Permissions.85 | "definePermissions"86 | "permissionIntrospectionColumns"87 >88 & {89 defineNestedApp: typeof defineNestedApp;90 defineNestedPermissions: typeof defineNestedPermissions;91 mergeNestedPermissions: typeof mergeNestedPermissions;92 flattenNestedSchema: typeof flattenNestedSchema;93 encryptedText: typeof encryptedText;94 encryptedJson: typeof encryptedJson;95 encryptedNumber: typeof encryptedNumber;96 encryptedDate: typeof encryptedDate;97 privateTable: typeof privateTable;98 plain: typeof plain;99 sharedEncryptedText: typeof sharedEncryptedText;100 sharedEncryptedJson: typeof sharedEncryptedJson;101 mutation: typeof mutation;102 effect: typeof effect;103 log: typeof log;104 trace: typeof trace;105 debug: typeof debug;106 notice: typeof notice;107 mark: typeof mark;108 chain: typeof chain;109 webhook: typeof webhook;110 insert: typeof insert;111 update: typeof update;112 remove: typeof remove;113 };114115// The define entry points additionally record every encrypted column into116// the table/column registry the access layer consults; behavior and types117// are otherwise the pinned originals.118function withEncryptedColumnRegistration<119 F extends (definition: never, ...rest: never[]) => unknown,120>(define: F): F {121 return ((definition: unknown, ...rest: unknown[]) => {122 registerEncryptedColumns(definition);123 return (define as unknown as (...args: unknown[]) => unknown)(definition, ...rest);124 }) as unknown as F;125}126127/**128 * The lofi schema surface. Use in `src/schema.ts` and `src/permissions.ts` in129 * place of a raw `jazz-tools` import; Jazz member names and behavior are130 * identical to the pinned Jazz 2 DSL. The lofi-owned members: nested131 * namespaces ({@link defineNestedApp}), sealed columns ({@link encryptedText},132 * {@link encryptedJson}, {@link encryptedNumber}, {@link encryptedDate}, with133 * {@link privateTable} and {@link plain} for encrypt-by-default tables), and134 * the verb grammar — {@link mutation} declares135 * callable verbs over {@link insert}, {@link update}, and {@link remove},136 * carrying {@link effect} units and {@link log} entries. Verb calls return a137 * `WriteHandle`, observed in UI through `useWrite` and `usePendingWrites`138 * from `@nzip/lofi/preact`.139 */140export const s: SchemaDsl = {141 ...schema,142 defineSchema: withEncryptedColumnRegistration(schema.defineSchema),143 defineApp: withEncryptedColumnRegistration(schema.defineApp),144 defineSliceableApp: withEncryptedColumnRegistration(schema.defineSliceableApp),145 defineNestedApp,146 defineNestedPermissions,147 mergeNestedPermissions,148 flattenNestedSchema,149 encryptedText,150 encryptedJson,151 encryptedNumber,152 encryptedDate,153 privateTable,154 plain,155 sharedEncryptedText,156 sharedEncryptedJson,157 mutation,158 effect,159 log,160 trace,161 debug,162 notice,163 mark,164 chain,165 webhook,166 insert,167 update,168 remove,169};170171export {172 type AnyColumnBuilder,173 plain,174 type PlainColumn,175 privateTable,176 type PrivateTableColumns,177} from "./private-table.ts";178179export {180 type SharedColumnOptions,181 sharedEncryptedJson,182 sharedEncryptedText,183 sharedFieldReady,184 type SharedFieldValue,185 unwrapSharedField,186} from "./shared-encrypted.ts";187export {188 isSharedFieldError,189 SharedFieldError,190 type SharedFieldErrorCode,191} from "./shared-crypto.ts";192export { type SharedColumnConfig } from "./shared-registry.ts";193194export {195 type EncryptedColumn,196 EncryptedColumnError,197 encryptedColumnsOf,198 encryptedDate,199 encryptedJson,200 encryptedNumber,201 type EncryptedStoredSql,202 encryptedText,203 isEncryptedColumn,204 matchDecrypted,205} from "./encrypted.ts";206export {207 defineNestedApp,208 defineNestedPermissions,209 flattenNestedSchema,210 mergeNestedPermissions,211 NESTED_SEPARATOR,212 type NestedApp,213 nestedAppDeployTarget,214 type NestedAppRoot,215 nestedAppTables,216 type NestedSchemaDefinition,217} from "./nested.ts";218export {219 effect,220 type EffectContext,221 type EffectHandlers,222 type EffectRow,223 type EffectUnit,224 type EffectUnitOptions,225 insert,226 type InsertVerb,227 isPermanentEffectError,228 log,229 mutation,230 type MutationOp,231 type MutationOpKind,232 type MutationOptions,233 type MutationVerb,234 type NoticeInput,235 PermanentEffectError,236 remove,237 type RemoveVerb,238 update,239 type UpdateVerb,240} from "./effects.ts";241export {242 chain,243 debug,244 mark,245 type MarkConfig,246 notice,247 type NoticeConfig,248 type NoticeResolver,249 trace,250 webhook,251 type WebhookOptions,252} from "./effect-library.ts";253// Type-only, so the authoring-only module graph stays free of runtime code:254// verb calls settle through the runtime write handle, and these names let255// schema-graph modules annotate that contract without importing the runtime.256export type { WriteHandle, WriteRejection, WriteStage } from "../runtime/write-handle.ts";257258// Store provisioning (./store.ts) is deliberately NOT re-exported here: the259// Jazz schema loader bundles the author's schema module graph — this facade260// included — and executes it to derive the deployed schema, so this module261// must stay authoring-only. Import provisioning from "@nzip/lofi/schema/store".262263/**264 * Schema-authoring types re-exported from the pinned Jazz 2 DSL for use in265 * application signatures: the app and table shapes, the table handle type266 * (`TableProxy`, what a declared table is at runtime and what verb267 * operations accept), and the permission types (`PolicyContext` for268 * `definePermissions` callbacks, `CompiledPermissions` for the bundles they269 * compile to and `mergeNestedPermissions` combines). Row types for UI code270 * come from `@nzip/lofi` (`RowOf`), not from this module.271 */272export type {273 App,274 CompiledPermissions,275 DefinedTable,276 InsertOf,277 PolicyContext,278 Schema,279 SchemaDefinition,280 TableDefinition,281 TableProxy,282 WhereOf,283} from "jazz-tools";284285/**286 * Column builder types re-exported for signatures and for the alpha.53287 * workaround below: calling `.merge()` or `.transform()` on a column loses288 * the typed builder (the legacy untyped signatures shadow the typed289 * overloads upstream), so cast the result back to the intended column type.290 * The runtime object is unchanged; only the declaration needs repair:291 *292 * ```ts293 * total: s.int().default(0).merge("counter") as unknown as IntColumn<false, true>,294 * tags: s.string().transform({295 * from: (value: string) => value.split(","),296 * to: (value: string[]) => value.join(","),297 * }) as unknown as StringColumn<false, false, string[]>,298 * ```299 */300export type {301 ArrayColumn,302 BooleanColumn,303 BytesColumn,304 EnumColumn,305 FloatColumn,306 IntColumn,307 JsonColumn,308 RefColumn,309 StringColumn,310 TimestampColumn,311} from "jazz-tools";