@lobb-js/core 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/package.json +48 -0
  2. package/src/Lobb.ts +150 -0
  3. package/src/LobbError.ts +105 -0
  4. package/src/TypesGenerator.ts +11 -0
  5. package/src/api/WebServer.ts +126 -0
  6. package/src/api/collections/CollectionControllers.ts +485 -0
  7. package/src/api/collections/CollectionService.ts +162 -0
  8. package/src/api/collections/collectionRoutes.ts +105 -0
  9. package/src/api/collections/collectionStore.ts +647 -0
  10. package/src/api/collections/transactions.ts +166 -0
  11. package/src/api/collections/utils.ts +73 -0
  12. package/src/api/errorHandler.ts +73 -0
  13. package/src/api/events/index.ts +129 -0
  14. package/src/api/meta/route.ts +66 -0
  15. package/src/api/meta/service.ts +163 -0
  16. package/src/api/middlewares.ts +71 -0
  17. package/src/api/openApiRoute.ts +1017 -0
  18. package/src/api/schema/SchemaService.ts +71 -0
  19. package/src/api/schema/schemaRoutes.ts +13 -0
  20. package/src/config/ConfigManager.ts +252 -0
  21. package/src/config/validations.ts +49 -0
  22. package/src/coreCollections/collectionsCollection.ts +56 -0
  23. package/src/coreCollections/index.ts +14 -0
  24. package/src/coreCollections/migrationsCollection.ts +36 -0
  25. package/src/coreCollections/queryCollection.ts +26 -0
  26. package/src/coreCollections/workflowsCollection.ts +73 -0
  27. package/src/coreDbSetup/index.ts +72 -0
  28. package/src/coreMigrations/index.ts +3 -0
  29. package/src/database/DatabaseService.ts +44 -0
  30. package/src/database/DatabaseSyncManager.ts +173 -0
  31. package/src/database/MigrationsManager.ts +95 -0
  32. package/src/database/drivers/MongoDriver.ts +750 -0
  33. package/src/database/drivers/pgDriver/PGDriver.ts +655 -0
  34. package/src/database/drivers/pgDriver/QueryBuilder.ts +474 -0
  35. package/src/database/drivers/pgDriver/utils.ts +6 -0
  36. package/src/events/EventSystem.ts +191 -0
  37. package/src/events/coreEvents/index.ts +218 -0
  38. package/src/events/studioEvents/index.ts +32 -0
  39. package/src/extension/ExtensionSystem.ts +236 -0
  40. package/src/extension/dashboardRoute.ts +35 -0
  41. package/src/fields/ArrayField.ts +33 -0
  42. package/src/fields/BoolField.ts +34 -0
  43. package/src/fields/DateField.ts +13 -0
  44. package/src/fields/DateTimeField.ts +13 -0
  45. package/src/fields/DecimalField.ts +13 -0
  46. package/src/fields/FieldUtils.ts +56 -0
  47. package/src/fields/FloatField.ts +13 -0
  48. package/src/fields/IntegerField.ts +13 -0
  49. package/src/fields/LongField.ts +13 -0
  50. package/src/fields/ObjectField.ts +15 -0
  51. package/src/fields/StringField.ts +13 -0
  52. package/src/fields/TextField.ts +13 -0
  53. package/src/fields/TimeField.ts +13 -0
  54. package/src/index.ts +53 -0
  55. package/src/studio/Studio.ts +108 -0
  56. package/src/types/CollectionControllers.ts +15 -0
  57. package/src/types/DatabaseDriver.ts +115 -0
  58. package/src/types/Extension.ts +46 -0
  59. package/src/types/Field.ts +29 -0
  60. package/src/types/apiSchema.ts +12 -0
  61. package/src/types/collectionServiceSchema.ts +18 -0
  62. package/src/types/config/collectionFields.ts +85 -0
  63. package/src/types/config/collectionsConfig.ts +50 -0
  64. package/src/types/config/config.ts +66 -0
  65. package/src/types/config/relations.ts +17 -0
  66. package/src/types/filterSchema.ts +88 -0
  67. package/src/types/index.ts +38 -0
  68. package/src/types/migrations.ts +12 -0
  69. package/src/types/websockets.ts +34 -0
  70. package/src/types/workflows/processors.ts +1 -0
  71. package/src/utils/lockCollectionToObject.ts +204 -0
  72. package/src/utils/utils.ts +310 -0
  73. package/src/workflows/WorkflowSystem.ts +182 -0
  74. package/src/workflows/coreWorkflows/collectionsTable/index.ts +118 -0
  75. package/src/workflows/coreWorkflows/index.ts +18 -0
  76. package/src/workflows/coreWorkflows/processors/postOperationsWorkflows.ts +46 -0
  77. package/src/workflows/coreWorkflows/processors/preOperationsWorkflows.ts +27 -0
  78. package/src/workflows/coreWorkflows/processors/processorForDB.ts +13 -0
  79. package/src/workflows/coreWorkflows/processors/processors/processor.ts +23 -0
  80. package/src/workflows/coreWorkflows/processors/processors/processorsFunctions.ts +47 -0
  81. package/src/workflows/coreWorkflows/processors/utils.ts +102 -0
  82. package/src/workflows/coreWorkflows/processors/validator/validator.ts +19 -0
  83. package/src/workflows/coreWorkflows/processors/validator/validatorsFunction.ts +52 -0
  84. package/src/workflows/coreWorkflows/queryCoreWorkflows.ts +31 -0
  85. package/src/workflows/coreWorkflows/utilsCoreWorkflows.ts +40 -0
  86. package/src/workflows/coreWorkflows/workflowsCollection/workflowsCollectionWorkflows.ts +101 -0
@@ -0,0 +1,13 @@
1
+ import { Field } from "../types/index.ts";
2
+
3
+ export class IntegerField extends Field {
4
+ public static override type: string = "integer";
5
+ protected fieldName: string;
6
+ protected collectionName: string;
7
+
8
+ constructor(fieldName: string, collectionName: string) {
9
+ super();
10
+ this.fieldName = fieldName;
11
+ this.collectionName = collectionName;
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { Field } from "../types/index.ts";
2
+
3
+ export class LongField extends Field {
4
+ public static override type: string = "long";
5
+ protected fieldName: string;
6
+ protected collectionName: string;
7
+
8
+ constructor(fieldName: string, collectionName: string) {
9
+ super();
10
+ this.fieldName = fieldName;
11
+ this.collectionName = collectionName;
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ // import { Field, type FieldOperatorsType } from "./Field.ts";
2
+ // import _ from "lodash";
3
+
4
+ // export class ObjectField extends Field {
5
+ // public static override type: string = "object";
6
+ // protected fieldName: string;
7
+ // protected collectionName: string;
8
+ // public fieldOperatorsType: FieldOperatorsType = "string";
9
+
10
+ // constructor(fieldName: string, collectionName: string) {
11
+ // super();
12
+ // this.fieldName = fieldName;
13
+ // this.collectionName = collectionName;
14
+ // }
15
+ // }
@@ -0,0 +1,13 @@
1
+ import { Field } from "../types/index.ts";
2
+
3
+ export class StringField extends Field {
4
+ public static override type: string = "string";
5
+ protected fieldName: string;
6
+ protected collectionName: string;
7
+
8
+ constructor(fieldName: string, collectionName: string) {
9
+ super();
10
+ this.fieldName = fieldName;
11
+ this.collectionName = collectionName;
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { Field } from "../types/index.ts";
2
+
3
+ export class TextField extends Field {
4
+ public static override type: string = "text";
5
+ protected fieldName: string;
6
+ protected collectionName: string;
7
+
8
+ constructor(fieldName: string, collectionName: string) {
9
+ super();
10
+ this.fieldName = fieldName;
11
+ this.collectionName = collectionName;
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ import { Field } from "../types/index.ts";
2
+
3
+ export class TimeField extends Field {
4
+ public static override type: string = "time";
5
+ protected fieldName: string;
6
+ protected collectionName: string;
7
+
8
+ constructor(fieldName: string, collectionName: string) {
9
+ super();
10
+ this.fieldName = fieldName;
11
+ this.collectionName = collectionName;
12
+ }
13
+ }
package/src/index.ts ADDED
@@ -0,0 +1,53 @@
1
+ // export lobb version
2
+ import packageJson from "../package.json" with { type: "json" };
3
+ export const version = packageJson.version;
4
+
5
+ // export Lobb core
6
+ export { run } from "./Lobb.ts";
7
+ export { Lobb } from "./Lobb.ts";
8
+ export { LobbError } from "./LobbError.ts";
9
+
10
+ // export core types
11
+ export type { Workflow } from "./workflows/WorkflowSystem.ts";
12
+ export type { CollectionService, ExposedServiceOutput, ExposedManyServiceOutput, ServiceOp } from "./api/collections/CollectionService.ts";
13
+ export type { EventContext } from "./events/EventSystem.ts";
14
+
15
+ // export all types from types directory
16
+ export { DatabaseDriver } from "./types/DatabaseDriver.ts";
17
+ export type { FindAllResult, MassReturn } from "./types/DatabaseDriver.ts";
18
+ export type { ApiCollectionAction } from "./types/apiSchema.ts";
19
+ export type { Config, WebConfig } from "./types/config/config.ts";
20
+ export type { RelationsConfig } from "./types/config/relations.ts";
21
+ export type {
22
+ CollectionConfig,
23
+ CollectionIndex,
24
+ CollectionIndexes,
25
+ CollectionsConfig,
26
+ } from "./types/config/collectionsConfig.ts";
27
+ export type { CollectionFieldsWithoutId } from "./types/config/collectionsConfig.ts";
28
+ export type {
29
+ CollectionField,
30
+ CollectionFieldBase,
31
+ } from "./types/config/collectionFields.ts";
32
+ export type { Dashboard, Extension } from "./types/Extension.ts";
33
+ export { Field } from "./types/Field.ts";
34
+ export type { Migration, MigrationProps, Migrations } from "./types/migrations.ts";
35
+ export type { Filter } from "./types/filterSchema.ts";
36
+ export {
37
+ basicFilterOperatorsSchema,
38
+ filterJsonSchema,
39
+ filterSchema,
40
+ } from "./types/filterSchema.ts";
41
+ export type {
42
+ FindAllParamsInput,
43
+ FindAllParamsOutput,
44
+ } from "./types/collectionServiceSchema.ts";
45
+ export { findAllParamsSchema } from "./types/collectionServiceSchema.ts";
46
+ export { CollectionConfigSchema } from "./types/config/collectionsConfig.ts";
47
+ export type { CollectionControllers } from "./types/CollectionControllers.ts";
48
+ export type {
49
+ HeartBeatMessage,
50
+ RequestMessage,
51
+ SubscribeMessage,
52
+ } from "./types/websockets.ts";
53
+ export type { ProcessorType } from "./types/workflows/processors.ts";
@@ -0,0 +1,108 @@
1
+ import { stat } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { createServer, createConnection } from "node:net";
5
+ import type { AddressInfo } from "node:net";
6
+
7
+ export class Studio {
8
+ private studioDir: string;
9
+ private process: ReturnType<typeof Bun.spawn> | null = null;
10
+
11
+ constructor(projectDir: string) {
12
+ // Support flat structure (vite.config.ts at project root) and nested (studio/ subdir).
13
+ this.studioDir = existsSync(join(projectDir, "vite.config.ts"))
14
+ ? projectDir
15
+ : join(projectDir, "studio");
16
+ }
17
+
18
+ public stop(): void {
19
+ this.process?.kill();
20
+ this.process = null;
21
+ }
22
+
23
+ public async start(webPort: number): Promise<number | null> {
24
+ if (!await this.exists()) return null;
25
+
26
+ const mode = process.env.LOBB_MODE;
27
+
28
+ if (mode === "prod") {
29
+ const buildDir = `${this.studioDir}/build`;
30
+ try {
31
+ const s = await stat(buildDir);
32
+ if (!s.isDirectory()) throw new Error();
33
+ } catch {
34
+ throw new Error(
35
+ "Studio build not found. Run 'bun run build:studio' before starting in production mode."
36
+ );
37
+ }
38
+ return await this.serveBuild(webPort);
39
+ }
40
+
41
+ return await this.runDevServer(webPort);
42
+ }
43
+
44
+ private async exists(): Promise<boolean> {
45
+ try {
46
+ const s = await stat(this.studioDir);
47
+ return s.isDirectory();
48
+ } catch {
49
+ return false;
50
+ }
51
+ }
52
+
53
+ private async serveBuild(webPort: number): Promise<number> {
54
+ console.log("Studio: running production build.");
55
+ const port = await Studio.getFreePort();
56
+ this.process = Bun.spawn(["bun", "run", "build/index.js"], {
57
+ cwd: this.studioDir,
58
+ env: { ...process.env, PORT: String(port) },
59
+ stdin: "pipe",
60
+ stdout: "inherit",
61
+ stderr: "inherit",
62
+ });
63
+ await Studio.waitForPort(port);
64
+ console.log(`Studio: http://localhost:${webPort}/studio`);
65
+ return port;
66
+ }
67
+
68
+ private async runDevServer(webPort: number): Promise<number> {
69
+ const port = await Studio.getFreePort();
70
+ console.log("Studio: running dev server.");
71
+ this.process = Bun.spawn(["bun", "run", "dev:studio", "--port", String(port)], {
72
+ cwd: this.studioDir,
73
+ env: { ...process.env },
74
+ stdin: "pipe",
75
+ stdout: "pipe",
76
+ stderr: "inherit",
77
+ });
78
+ await Studio.waitForPort(port);
79
+ console.log(`Studio: http://localhost:${webPort}/studio`);
80
+ return port;
81
+ }
82
+
83
+ private static getFreePort(): Promise<number> {
84
+ return new Promise((resolve, reject) => {
85
+ const server = createServer();
86
+ server.listen(0, "127.0.0.1", () => {
87
+ const port = (server.address() as AddressInfo).port;
88
+ server.close((err) => {
89
+ if (err) reject(err);
90
+ else resolve(port);
91
+ });
92
+ });
93
+ });
94
+ }
95
+
96
+ private static async waitForPort(port: number, maxAttempts = 50): Promise<void> {
97
+ for (let i = 0; i < maxAttempts; i++) {
98
+ const connected = await new Promise<boolean>((resolve) => {
99
+ const sock = createConnection({ port, host: "127.0.0.1" });
100
+ sock.once("connect", () => { sock.destroy(); resolve(true); });
101
+ sock.once("error", () => { sock.destroy(); resolve(false); });
102
+ });
103
+ if (connected) return;
104
+ await new Promise((r) => setTimeout(r, 200));
105
+ }
106
+ throw new Error(`Studio server did not start on port ${port}`);
107
+ }
108
+ }
@@ -0,0 +1,15 @@
1
+ import type { Context } from "hono";
2
+
3
+ export interface CollectionControllers {
4
+ findAll(c: Context): Promise<Response>;
5
+ findOne(c: Context): Promise<Response>;
6
+ createOne(c: Context): Promise<Response>;
7
+ updateOne(c: Context): Promise<Response>;
8
+ deleteOne(c: Context): Promise<Response>;
9
+ deleteMany(c: Context): Promise<Response>;
10
+ updateMany(c: Context): Promise<Response>;
11
+ createMany(c: Context): Promise<Response>;
12
+ readSingleton(c: Context): Promise<Response>;
13
+ updateSingleton(c: Context): Promise<Response>;
14
+ transactions(c: Context): Promise<Response>;
15
+ }
@@ -0,0 +1,115 @@
1
+ import type { FindAllParamsOutput } from "./collectionServiceSchema.ts";
2
+ import type { PoolClient } from "pg";
3
+ import type {
4
+ CollectionConfig,
5
+ CollectionIndex,
6
+ CollectionIndexes,
7
+ CollectionsConfig,
8
+ } from "./config/collectionsConfig.ts";
9
+ import type { DatabaseConfig } from "./config/config.ts";
10
+ import type { CollectionField } from "./config/collectionFields.ts";
11
+
12
+ export type Entry = {
13
+ id: string;
14
+ [key: string]: any;
15
+ };
16
+
17
+ export interface Meta {
18
+ totalCount: number;
19
+ }
20
+
21
+ export interface FindAllResult {
22
+ data: Entry[];
23
+ meta: Meta;
24
+ }
25
+
26
+ export interface MassReturn {
27
+ affectedCount: number;
28
+ }
29
+
30
+ export abstract class DatabaseDriver {
31
+ // Subclasses should set this in their constructor by accessing Lobb.instance
32
+ protected databaseConfig!: DatabaseConfig;
33
+
34
+ public abstract createConnection(): Promise<void>;
35
+ public abstract getConnection(): { connect(): Promise<any> };
36
+ public abstract close(): Promise<void>;
37
+ public abstract query<T>(sql: string): Promise<T[]>;
38
+ public abstract dropDatabase(): Promise<void>;
39
+ public abstract createCollection(
40
+ collectionName: string,
41
+ collectionConfig: CollectionConfig,
42
+ ): Promise<void>;
43
+ public abstract dropCollection(collectionName: string): Promise<void>;
44
+ public abstract addField(
45
+ collectionName: string,
46
+ fieldName: string,
47
+ field: CollectionField,
48
+ ): Promise<void>;
49
+ public abstract removeField(
50
+ collectionName: string,
51
+ fieldName: string,
52
+ ): Promise<void>;
53
+ public abstract getDbSchema(): Promise<CollectionsConfig>;
54
+ public abstract getIdsByFilter(
55
+ collectionName: string,
56
+ filter?: any,
57
+ client?: PoolClient,
58
+ ): Promise<string[]>;
59
+
60
+ /////////////////////////
61
+ // Indexes Operations //
62
+ ////////////////////////
63
+ public abstract createIndex(
64
+ collectionName: string,
65
+ indexName: string,
66
+ index: CollectionIndex,
67
+ ): Promise<void>;
68
+ public abstract dropIndex(
69
+ collectionName: string,
70
+ indexName: string,
71
+ ): Promise<any>;
72
+ public abstract getIndexes(
73
+ collectionName: string,
74
+ ): Promise<CollectionIndexes>;
75
+
76
+ /////////////////////
77
+ // CRUD Operations //
78
+ /////////////////////
79
+ public abstract findAll(
80
+ collectionName: string,
81
+ params: FindAllParamsOutput,
82
+ client?: PoolClient,
83
+ ): Promise<FindAllResult>;
84
+
85
+ public abstract createOne(
86
+ collectionName: string,
87
+ data: any,
88
+ client?: PoolClient,
89
+ ): Promise<Entry>;
90
+
91
+ public abstract updateOne(
92
+ collectionName: string,
93
+ id: string,
94
+ data: any,
95
+ client?: PoolClient,
96
+ ): Promise<Entry | null>;
97
+
98
+ public abstract deleteOne(
99
+ collectionName: string,
100
+ id: string,
101
+ client?: PoolClient,
102
+ ): Promise<Entry | null>;
103
+
104
+ ///////////////////////////////////////////////////////////
105
+ // parse some types of data to be compatible with the db //
106
+ // used mainly for mongodb //
107
+ ///////////////////////////////////////////////////////////
108
+ public encodeFieldValue(fieldType: string, value: any) {
109
+ return value;
110
+ }
111
+
112
+ public decodeFieldValue(fieldType: string, value: any) {
113
+ return value;
114
+ }
115
+ }
@@ -0,0 +1,46 @@
1
+ import type { Hono, MiddlewareHandler } from "hono";
2
+ import type { CollectionConfig } from "./config/collectionsConfig.ts";
3
+ import type { Migrations } from "./migrations.ts";
4
+ import type { OpenAPIV3_1 } from "openapi-types";
5
+ import type { RelationsConfig } from "./config/relations.ts";
6
+ import type { Lobb } from "../Lobb.ts";
7
+ import type { Workflow } from "../workflows/WorkflowSystem.ts";
8
+
9
+ interface OpenApiProperty {
10
+ paths: OpenAPIV3_1.Document["paths"];
11
+ components?: Record<string, any>;
12
+ }
13
+
14
+ export interface Dashboard {
15
+ extension?: string;
16
+ }
17
+
18
+ interface ExtensionBase {
19
+ name: string;
20
+ workflows?: Workflow[];
21
+ migrations?: Migrations;
22
+ init?: (lobb: Lobb) => Promise<void>;
23
+ close?: (lobb: Lobb) => Promise<void>;
24
+ collectionRoutes?: (routes: Hono) => void;
25
+ collectionMiddlewares?: Array<MiddlewareHandler>;
26
+ routes?: () => Hono;
27
+ collections?: (lobb: Lobb) => Record<string, CollectionConfig>;
28
+ relations?: (lobb: Lobb) => RelationsConfig;
29
+ meta?: (lobb: Lobb) => Promise<any>;
30
+ openapi?: OpenApiProperty;
31
+ services?: (lobb: Lobb) => object;
32
+ }
33
+
34
+ // Has dashboard → version is required
35
+ interface ExtensionWithDashboard extends ExtensionBase {
36
+ dashboard: Dashboard;
37
+ version?: string;
38
+ }
39
+
40
+ // No dashboard → version is optional
41
+ interface ExtensionWithoutDashboard extends ExtensionBase {
42
+ dashboard?: undefined;
43
+ version?: string;
44
+ }
45
+
46
+ export type Extension = ExtensionWithDashboard | ExtensionWithoutDashboard;
@@ -0,0 +1,29 @@
1
+ import { LobbError } from "../LobbError.ts";
2
+
3
+ export abstract class Field {
4
+ protected abstract fieldName: string;
5
+ protected abstract collectionName: string;
6
+
7
+ // this forces all child classes to define a static 'type' property
8
+ static get type(): string {
9
+ throw new Error(
10
+ `(${this.name}) class must define a static 'type' property.`,
11
+ );
12
+ }
13
+
14
+ public encodeFieldValue(value: any): any {
15
+ return value;
16
+ }
17
+
18
+ public decodeFieldValue(value: any): any {
19
+ return value;
20
+ }
21
+
22
+ protected throwIncompatibleValueTypeError(): never {
23
+ throw new LobbError({
24
+ code: "BAD_REQUEST",
25
+ message:
26
+ `The value provided for the (${this.fieldName}) field is incompatible.`,
27
+ });
28
+ }
29
+ }
@@ -0,0 +1,12 @@
1
+ export type ApiCollectionAction =
2
+ | "findAll"
3
+ | "findOne"
4
+ | "deleteOne"
5
+ | "createOne"
6
+ | "updateOne"
7
+ | "createMany"
8
+ | "deleteMany"
9
+ | "updateMany"
10
+ | "transactions"
11
+ | "readSingleton"
12
+ | "updateSingleton";
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+
3
+ export const findAllParamsSchema = z
4
+ .object({
5
+ sort: z.string().optional(),
6
+ limit: z.coerce.number().default(100),
7
+ offset: z.coerce.number().default(0),
8
+ page: z.coerce.number().optional(),
9
+ fields: z.string().default("*"),
10
+ filter: z.any(),
11
+ }).strict()
12
+ .default({
13
+ fields: "*",
14
+ limit: 100,
15
+ offset: 0,
16
+ });
17
+ export type FindAllParamsInput = z.input<typeof findAllParamsSchema>;
18
+ export type FindAllParamsOutput = z.output<typeof findAllParamsSchema>;
@@ -0,0 +1,85 @@
1
+ import { RelationCollectionFieldSchema } from "./relations.ts";
2
+
3
+ import { z } from "zod";
4
+
5
+ // Define the UiInput schema
6
+ const UiInputSchema = z.object({
7
+ type: z.string(),
8
+ args: z.any().optional(),
9
+ });
10
+
11
+ // Defining the ui property schema
12
+ const UiSchema = z.object({
13
+ disabled: z.boolean().optional(),
14
+ placeholder: z.string().optional(),
15
+ input: UiInputSchema.optional(),
16
+ });
17
+
18
+ // Base field schema
19
+ export const CollectionFieldBaseSchema = z.object({
20
+ pre_processors: z.record(z.any()).optional(),
21
+ post_processors: z.record(z.any()).optional(),
22
+ validators: z.record(z.any()).optional(),
23
+ ui: UiSchema.optional(),
24
+ });
25
+
26
+ export type CollectionFieldBase = z.infer<typeof CollectionFieldBaseSchema>;
27
+
28
+ // Specialized field schemas
29
+ export const CollectionBoolFieldSchema = CollectionFieldBaseSchema.extend({
30
+ type: z.literal("bool"),
31
+ });
32
+
33
+ export const CollectionDateFieldSchema = CollectionFieldBaseSchema.extend({
34
+ type: z.literal("date"),
35
+ });
36
+
37
+ export const CollectionDateTimeFieldSchema = CollectionFieldBaseSchema.extend({
38
+ type: z.literal("datetime"),
39
+ });
40
+
41
+ export const CollectionDecimalFieldSchema = CollectionFieldBaseSchema.extend({
42
+ type: z.literal("decimal"),
43
+ });
44
+
45
+ export const CollectionFloatFieldSchema = CollectionFieldBaseSchema.extend({
46
+ type: z.literal("float"),
47
+ });
48
+
49
+ export const CollectionIntegerFieldSchema = CollectionFieldBaseSchema.extend({
50
+ type: z.literal("integer"),
51
+ references: RelationCollectionFieldSchema.optional(),
52
+ });
53
+
54
+ export const CollectionLongFieldSchema = CollectionFieldBaseSchema.extend({
55
+ type: z.literal("long"),
56
+ });
57
+
58
+ export const CollectionStringFieldSchema = CollectionFieldBaseSchema.extend({
59
+ type: z.literal("string"),
60
+ length: z.number(),
61
+ });
62
+
63
+ export const CollectionTextFieldSchema = CollectionFieldBaseSchema.extend({
64
+ type: z.literal("text"),
65
+ });
66
+
67
+ export const CollectionTimeFieldSchema = CollectionFieldBaseSchema.extend({
68
+ type: z.literal("time"),
69
+ });
70
+
71
+ // Union type if you want a single schema for all
72
+ export const CollectionFieldSchema = z.union([
73
+ CollectionBoolFieldSchema,
74
+ CollectionDateFieldSchema,
75
+ CollectionDateTimeFieldSchema,
76
+ CollectionDecimalFieldSchema,
77
+ CollectionFloatFieldSchema,
78
+ CollectionIntegerFieldSchema,
79
+ CollectionLongFieldSchema,
80
+ CollectionStringFieldSchema,
81
+ CollectionTextFieldSchema,
82
+ CollectionTimeFieldSchema,
83
+ ]);
84
+
85
+ export type CollectionField = z.infer<typeof CollectionFieldSchema>;
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+ import {
3
+ CollectionFieldSchema,
4
+ CollectionIntegerFieldSchema,
5
+ } from "./collectionFields.ts";
6
+
7
+ // CollectionIndexField
8
+ export const CollectionIndexFieldSchema = z.object({
9
+ order: z.enum(["asc", "desc"]),
10
+ });
11
+
12
+ // CollectionIndexFields (Record<string, CollectionIndexField>)
13
+ export const CollectionIndexFieldsSchema = z.record(CollectionIndexFieldSchema);
14
+
15
+ // CollectionIndex
16
+ export const CollectionIndexSchema = z.object({
17
+ unique: z.boolean(),
18
+ fields: CollectionIndexFieldsSchema,
19
+ });
20
+
21
+ // CollectionIndexes (Record<string, CollectionIndex>)
22
+ export const CollectionIndexesSchema = z.record(CollectionIndexSchema);
23
+
24
+ // CollectionFields (Record<string, CollectionField>)
25
+ export const CollectionFieldsSchema = z.intersection(
26
+ z.object({
27
+ id: CollectionIntegerFieldSchema,
28
+ }),
29
+ z.record(CollectionFieldSchema),
30
+ );
31
+
32
+ // CollectionConfig
33
+ export const CollectionConfigSchema = z.object({
34
+ category: z.string().optional(),
35
+ singleton: z.boolean().optional(),
36
+ indexes: CollectionIndexesSchema,
37
+ fields: CollectionFieldsSchema,
38
+ });
39
+
40
+ export const CollectionsConfigSchema = z.record(CollectionConfigSchema);
41
+
42
+ // Inferred Types
43
+ export type CollectionIndexField = z.infer<typeof CollectionIndexFieldSchema>;
44
+ export type CollectionIndexFields = z.infer<typeof CollectionIndexFieldsSchema>;
45
+ export type CollectionIndex = z.infer<typeof CollectionIndexSchema>;
46
+ export type CollectionIndexes = z.infer<typeof CollectionIndexesSchema>;
47
+ export type CollectionFields = z.infer<typeof CollectionFieldsSchema>;
48
+ export type CollectionFieldsWithoutId = Omit<CollectionFields, "id">;
49
+ export type CollectionConfig = z.infer<typeof CollectionConfigSchema>;
50
+ export type CollectionsConfig = z.infer<typeof CollectionsConfigSchema>;