@rebasepro/sdk-generator 0.2.1 → 0.2.4

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 (32) hide show
  1. package/dist/common/src/collections/default-collections.d.ts +12 -0
  2. package/dist/common/src/collections/index.d.ts +1 -0
  3. package/dist/common/src/data/query_builder.d.ts +51 -0
  4. package/dist/common/src/index.d.ts +1 -0
  5. package/dist/common/src/util/permissions.d.ts +1 -0
  6. package/dist/index.cjs +3 -0
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.es.js +3 -0
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/types/src/controllers/auth.d.ts +2 -24
  11. package/dist/types/src/controllers/client.d.ts +0 -3
  12. package/dist/types/src/controllers/collection_registry.d.ts +1 -1
  13. package/dist/types/src/controllers/data.d.ts +21 -0
  14. package/dist/types/src/controllers/data_driver.d.ts +18 -0
  15. package/dist/types/src/controllers/registry.d.ts +5 -4
  16. package/dist/types/src/rebase_context.d.ts +1 -1
  17. package/dist/types/src/types/auth_adapter.d.ts +2 -4
  18. package/dist/types/src/types/collections.d.ts +0 -4
  19. package/dist/types/src/types/component_ref.d.ts +1 -1
  20. package/dist/types/src/types/cron.d.ts +1 -1
  21. package/dist/types/src/types/entity_views.d.ts +1 -0
  22. package/dist/types/src/types/export_import.d.ts +1 -1
  23. package/dist/types/src/types/formex.d.ts +2 -2
  24. package/dist/types/src/types/properties.d.ts +2 -2
  25. package/dist/types/src/types/translations.d.ts +28 -12
  26. package/dist/types/src/types/user_management_delegate.d.ts +6 -4
  27. package/dist/types/src/users/roles.d.ts +0 -8
  28. package/package.json +11 -6
  29. package/src/generate-types.ts +5 -5
  30. package/src/utils.ts +3 -0
  31. package/test/sdk-generator.test.ts +456 -40
  32. package/src/json-logic-js.d.ts +0 -8
@@ -0,0 +1,12 @@
1
+ import { PostgresCollection } from "@rebasepro/types";
2
+ /**
3
+ * Default users collection definition.
4
+ *
5
+ * Shared between the admin UI (for navigation/display) and the backend
6
+ * (for schema generation). Both consumers prepend this to the developer's
7
+ * collections array and rely on generic slug-based deduplication
8
+ * (Map keyed by slug, last-write-wins) so that developer-defined
9
+ * collections with the same slug override this default — no hardcoded
10
+ * string checks required.
11
+ */
12
+ export declare const defaultUsersCollection: PostgresCollection;
@@ -1 +1,2 @@
1
1
  export * from "./CollectionRegistry";
2
+ export * from "./default-collections";
@@ -0,0 +1,51 @@
1
+ import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator } from "@rebasepro/types";
2
+ export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
3
+ private collection;
4
+ private params;
5
+ constructor(collection: CollectionAccessor<M>);
6
+ /**
7
+ * Add a filter condition to your query.
8
+ * @example
9
+ * client.collection('users').where('age', '>=', 18).find()
10
+ */
11
+ where(column: keyof M & string, operator: FilterOperator, value: unknown): this;
12
+ /**
13
+ * Order the results by a specific column.
14
+ * @example
15
+ * client.collection('users').orderBy('createdAt', 'desc').find()
16
+ */
17
+ orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
18
+ /**
19
+ * Limit the number of results returned.
20
+ */
21
+ limit(count: number): this;
22
+ /**
23
+ * Skip the first N results.
24
+ */
25
+ offset(count: number): this;
26
+ /**
27
+ * Set a free-text search string if supported by the backend.
28
+ */
29
+ search(searchString: string): this;
30
+ /**
31
+ * Include related entities in the response.
32
+ * Relations will be populated with full entity data instead of just IDs.
33
+ *
34
+ * @param relations - Relation names to include, or "*" for all.
35
+ * @example
36
+ * // Include specific relations
37
+ * client.data.posts.include("tags", "author").find()
38
+ *
39
+ * // Include all relations
40
+ * client.data.posts.include("*").find()
41
+ */
42
+ include(...relations: string[]): this;
43
+ /**
44
+ * Execute the find query and return the results.
45
+ */
46
+ find(): Promise<FindResponse<M>>;
47
+ /**
48
+ * Listen to realtime updates matching this query.
49
+ */
50
+ listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
51
+ }
@@ -1,3 +1,4 @@
1
1
  export * from "./util";
2
2
  export * from "./collections";
3
3
  export * from "./data/buildRebaseData";
4
+ export * from "./data/query_builder";
@@ -1,4 +1,5 @@
1
1
  import { AuthController, Entity, EntityCollection, User } from "@rebasepro/types";
2
+ export declare function checkOperation<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, entity: Entity<M> | null, targetOperation: "select" | "insert" | "update" | "delete"): boolean;
2
3
  export declare function canReadCollection<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>): boolean;
3
4
  export declare function canEditEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
4
5
  export declare function canCreateEntity<M extends Record<string, unknown>, USER extends User>(collection: EntityCollection<M>, authController: AuthController<USER>, path: string, entity: Entity<M> | null): boolean;
package/dist/index.cjs CHANGED
@@ -6,6 +6,9 @@
6
6
  return str.split(/[_\-\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
7
7
  }
8
8
  function toCamelCase(str) {
9
+ if (!/[_\-\s]/.test(str)) {
10
+ return str.charAt(0).toLowerCase() + str.slice(1);
11
+ }
9
12
  const pascal = toPascalCase(str);
10
13
  return pascal.charAt(0).toLowerCase() + pascal.slice(1);
11
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/generate-types.ts","../src/index.ts"],"sourcesContent":["/**\n * Utility functions for the SDK generator\n */\n\n/**\n * Convert a slug/snake_case string to PascalCase\n * e.g. \"private_notes\" → \"PrivateNotes\"\n */\nexport function toPascalCase(str: string): string {\n return str\n .split(/[_\\-\\s]+/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\n/**\n * Convert a slug/snake_case string to camelCase\n * e.g. \"private_notes\" → \"privateNotes\"\n */\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert a slug to a safe JS identifier\n * e.g. \"private-notes\" → \"privateNotes\"\n */\nexport function toSafeIdentifier(str: string): string {\n return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, \"_\"));\n}\n\n/**\n * Indent a block of text by a given number of spaces\n */\nexport function indent(text: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? pad + line : line))\n .join(\"\\n\");\n}\n","import { EntityCollection, PostgresCollection, Property, Properties, MapProperty, ArrayProperty, RelationProperty, StringProperty, NumberProperty } from \"@rebasepro/types\";\nimport { resolveCollectionRelations } from \"@rebasepro/common\";\nimport { toPascalCase, toSafeIdentifier } from \"./utils\";\n\nfunction propertyToTypeScriptType(prop: Property): string {\n switch (prop.type) {\n case \"string\": {\n const sp = prop as StringProperty;\n if (sp.enum) {\n const ids = Array.isArray(sp.enum)\n ? sp.enum.map((e: any) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(sp.enum);\n return ids.map(v => `\"${v}\"`).join(\" | \");\n }\n return \"string\";\n }\n case \"number\": {\n const np = prop as NumberProperty;\n if (np.enum) {\n const ids = Array.isArray(np.enum)\n ? np.enum.map((e: any) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(np.enum);\n return ids.join(\" | \");\n }\n return \"number\";\n }\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n return \"string\"; // ISO 8601 string over the wire\n case \"geopoint\":\n return \"{ latitude: number; longitude: number; }\";\n case \"reference\":\n return \"string | number\";\n case \"relation\":\n return \"string | number\";\n case \"map\": {\n const mapProp = prop as MapProperty;\n if (mapProp.properties) {\n const inner = Object.entries(mapProp.properties)\n .map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v as Property)};`)\n .join(\" \");\n return `{ ${inner} }`;\n }\n return \"Record<string, any>\";\n }\n case \"array\": {\n const arrProp = prop as ArrayProperty;\n if (arrProp.of) {\n return `Array<${propertyToTypeScriptType(arrProp.of as Property)}>`;\n }\n return \"Array<any>\";\n }\n case \"vector\":\n return \"number[]\";\n case \"binary\":\n return \"string\";\n default:\n return \"any\";\n }\n}\n\nexport function generateTypedefs(collections: EntityCollection[]): string {\n const lines: string[] = [\n \"/**\",\n \" * This file was auto-generated by Rebase.\",\n \" * Do not make direct changes to the file.\",\n \" */\",\n \"\",\n \"export interface Database {\"\n ];\n\n for (const collection of collections) {\n const typeName = toPascalCase(collection.slug);\n const properties = (collection.properties ?? {}) as Properties;\n\n // Resolve relations\n let resolvedRelations: Record<string, any> = {};\n try {\n resolvedRelations = resolveCollectionRelations(collection);\n } catch { /* ignore */ }\n\n lines.push(` ${toSafeIdentifier(collection.slug)}: {`);\n\n // ── Row Type ──\n lines.push(\" Row: {\");\n const emittedKeys = new Set<string>();\n\n // 1. Direct properties\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n lines.push(` ${toSafeIdentifier(key)}${isRequired ? \"\" : \"?\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n // 2. FK columns from relations\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n\n let fkType = \"string | number\";\n try {\n let target = relation.target();\n if (target && (target.default || target.__esModule)) {\n target = target.default || target;\n }\n if (target && target.properties) {\n const idProp = Object.entries(target.properties).find(([_, p]: [string, any]) => p.isId);\n if (idProp) {\n fkType = (idProp[1] as Property).type === \"number\" ? \"number\" : \"string\";\n }\n }\n } catch { /* ignore */ }\n\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n\n // 3. Relation fields\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") {\n if (emittedKeys.has(key)) continue;\n const relation = resolvedRelations[key];\n const isArray = relation?.cardinality === \"many\";\n const relType = \"{ id: string | number; path: string; __type: \\\"relation\\\"; data?: any }\";\n const tsType = isArray ? `Array<${relType}>` : relType;\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n }\n lines.push(\" };\");\n\n // ── Insert Type ──\n lines.push(\" Insert: {\");\n emittedKeys.clear();\n\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n const typedProp = prop as StringProperty | NumberProperty;\n const isAutoId = \"isId\" in prop && typedProp.isId && typedProp.isId !== \"manual\" && typedProp.isId !== true;\n const isOptional = !isRequired || isAutoId;\n lines.push(` ${toSafeIdentifier(key)}${isOptional ? \"?\" : \"\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n const fkType = \"string | number\";\n // simple fallback\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n // ── Update Type ──\n lines.push(\" Update: {\");\n emittedKeys.clear();\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n lines.push(\" };\");\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n lines.push(\"export type CollectionName = keyof Database;\");\n lines.push(\"export type CollectionsDictionary = { [K in CollectionName]: K };\");\n lines.push(\"\");\n lines.push(\"export const collectionsDictionary = {\");\n for (const collection of collections) {\n lines.push(` ${toSafeIdentifier(collection.slug)}: \"${collection.slug}\",`);\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * @rebasepro/sdk-generator\n *\n * Generates a purely typed Typescript database definition.\n */\n\nimport { EntityCollection } from \"@rebasepro/types\";\nimport { generateTypedefs } from \"./generate-types\";\n\nexport { generateTypedefs } from \"./generate-types\";\nexport { toPascalCase, toCamelCase, toSafeIdentifier, indent } from \"./utils\";\n\n// ─── Public API ────────────────────────────────────────────────────\n\nexport interface GeneratedFile {\n /** Relative file path within the output directory */\n path: string;\n /** File content */\n content: string;\n}\n\nexport interface GenerateSDKOptions {\n /** Whether to include a README file (default: true) */\n includeReadme?: boolean;\n}\n\nexport function generateSDK(\n collections: EntityCollection[],\n options: GenerateSDKOptions = {}\n): GeneratedFile[] {\n const files: GeneratedFile[] = [];\n\n files.push({\n path: \"database.types.ts\",\n content: generateTypedefs(collections)\n });\n\n if (options.includeReadme !== false) {\n files.push({\n path: \"README.md\",\n content: `# Rebase SDK\n\n> Auto-generated by \\`rebase generate-sdk\\`. Do not edit manually.\n\n## Usage\n\n1. Install the client package:\n \\`\\`\\`bash\n npm install @rebasepro/client\n \\`\\`\\`\n\n2. Initialize with your generated types:\n \\`\\`\\`typescript\n import { createRebaseClient } from '@rebasepro/client';\n import type { Database } from './database.types';\n\n const rebase = createRebaseClient<Database>({\n baseUrl: 'http://localhost:3001',\n // token: '...', // User token if not using auth module\n });\n\n // Both syntax styles are fully typed!\n const { data: users } = await rebase.data.users.find();\n const { data: posts } = await rebase.data.collection('posts').find();\n \\`\\`\\`\n`\n });\n }\n\n return files;\n}\n"],"names":["resolveCollectionRelations"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/generate-types.ts","../src/index.ts"],"sourcesContent":["/**\n * Utility functions for the SDK generator\n */\n\n/**\n * Convert a slug/snake_case string to PascalCase\n * e.g. \"private_notes\" → \"PrivateNotes\"\n */\nexport function toPascalCase(str: string): string {\n return str\n .split(/[_\\-\\s]+/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\n/**\n * Convert a slug/snake_case string to camelCase\n * e.g. \"private_notes\" → \"privateNotes\"\n */\nexport function toCamelCase(str: string): string {\n if (!/[_\\-\\s]/.test(str)) {\n return str.charAt(0).toLowerCase() + str.slice(1);\n }\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert a slug to a safe JS identifier\n * e.g. \"private-notes\" → \"privateNotes\"\n */\nexport function toSafeIdentifier(str: string): string {\n return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, \"_\"));\n}\n\n/**\n * Indent a block of text by a given number of spaces\n */\nexport function indent(text: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? pad + line : line))\n .join(\"\\n\");\n}\n","import { EntityCollection, PostgresCollection, Property, Properties, MapProperty, ArrayProperty, Relation, RelationProperty, StringProperty, NumberProperty } from \"@rebasepro/types\";\nimport { resolveCollectionRelations } from \"@rebasepro/common\";\nimport { toPascalCase, toSafeIdentifier } from \"./utils\";\n\nfunction propertyToTypeScriptType(prop: Property): string {\n switch (prop.type) {\n case \"string\": {\n const sp = prop as StringProperty;\n if (sp.enum) {\n const ids = Array.isArray(sp.enum)\n ? sp.enum.map((e: string | number | { id: string | number }) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(sp.enum);\n return ids.map(v => `\"${v}\"`).join(\" | \");\n }\n return \"string\";\n }\n case \"number\": {\n const np = prop as NumberProperty;\n if (np.enum) {\n const ids = Array.isArray(np.enum)\n ? np.enum.map((e: string | number | { id: string | number }) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(np.enum);\n return ids.join(\" | \");\n }\n return \"number\";\n }\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n return \"string\"; // ISO 8601 string over the wire\n case \"geopoint\":\n return \"{ latitude: number; longitude: number; }\";\n case \"reference\":\n return \"string | number\";\n case \"relation\":\n return \"string | number\";\n case \"map\": {\n const mapProp = prop as MapProperty;\n if (mapProp.properties) {\n const inner = Object.entries(mapProp.properties)\n .map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v as Property)};`)\n .join(\" \");\n return `{ ${inner} }`;\n }\n return \"Record<string, any>\";\n }\n case \"array\": {\n const arrProp = prop as ArrayProperty;\n if (arrProp.of) {\n return `Array<${propertyToTypeScriptType(arrProp.of as Property)}>`;\n }\n return \"Array<any>\";\n }\n case \"vector\":\n return \"number[]\";\n case \"binary\":\n return \"string\";\n default:\n return \"any\";\n }\n}\n\nexport function generateTypedefs(collections: EntityCollection[]): string {\n const lines: string[] = [\n \"/**\",\n \" * This file was auto-generated by Rebase.\",\n \" * Do not make direct changes to the file.\",\n \" */\",\n \"\",\n \"export interface Database {\"\n ];\n\n for (const collection of collections) {\n const typeName = toPascalCase(collection.slug);\n const properties = (collection.properties ?? {}) as Properties;\n\n // Resolve relations\n let resolvedRelations: Record<string, Relation> = {};\n try {\n resolvedRelations = resolveCollectionRelations(collection);\n } catch { /* ignore */ }\n\n lines.push(` ${toSafeIdentifier(collection.slug)}: {`);\n\n // ── Row Type ──\n lines.push(\" Row: {\");\n const emittedKeys = new Set<string>();\n\n // 1. Direct properties\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n lines.push(` ${toSafeIdentifier(key)}${isRequired ? \"\" : \"?\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n // 2. FK columns from relations\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n\n let fkType = \"string | number\";\n try {\n let target = relation.target();\n if (target && (target.default || target.__esModule)) {\n target = target.default || target;\n }\n if (target && target.properties) {\n const idProp = Object.entries(target.properties).find(([_, p]) => (p as Record<string, unknown>).isId);\n if (idProp) {\n fkType = (idProp[1] as Property).type === \"number\" ? \"number\" : \"string\";\n }\n }\n } catch { /* ignore */ }\n\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n\n // 3. Relation fields\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") {\n if (emittedKeys.has(key)) continue;\n const relation = resolvedRelations[key];\n const isArray = relation?.cardinality === \"many\";\n const relType = \"{ id: string | number; path: string; __type: \\\"relation\\\"; data?: any }\";\n const tsType = isArray ? `Array<${relType}>` : relType;\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n }\n lines.push(\" };\");\n\n // ── Insert Type ──\n lines.push(\" Insert: {\");\n emittedKeys.clear();\n\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n const typedProp = prop as StringProperty | NumberProperty;\n const isAutoId = \"isId\" in prop && typedProp.isId && typedProp.isId !== \"manual\" && typedProp.isId !== true;\n const isOptional = !isRequired || isAutoId;\n lines.push(` ${toSafeIdentifier(key)}${isOptional ? \"?\" : \"\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n const fkType = \"string | number\";\n // simple fallback\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n // ── Update Type ──\n lines.push(\" Update: {\");\n emittedKeys.clear();\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n lines.push(\" };\");\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n lines.push(\"export type CollectionName = keyof Database;\");\n lines.push(\"export type CollectionsDictionary = { [K in CollectionName]: K };\");\n lines.push(\"\");\n lines.push(\"export const collectionsDictionary = {\");\n for (const collection of collections) {\n lines.push(` ${toSafeIdentifier(collection.slug)}: \"${collection.slug}\",`);\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * @rebasepro/sdk-generator\n *\n * Generates a purely typed Typescript database definition.\n */\n\nimport { EntityCollection } from \"@rebasepro/types\";\nimport { generateTypedefs } from \"./generate-types\";\n\nexport { generateTypedefs } from \"./generate-types\";\nexport { toPascalCase, toCamelCase, toSafeIdentifier, indent } from \"./utils\";\n\n// ─── Public API ────────────────────────────────────────────────────\n\nexport interface GeneratedFile {\n /** Relative file path within the output directory */\n path: string;\n /** File content */\n content: string;\n}\n\nexport interface GenerateSDKOptions {\n /** Whether to include a README file (default: true) */\n includeReadme?: boolean;\n}\n\nexport function generateSDK(\n collections: EntityCollection[],\n options: GenerateSDKOptions = {}\n): GeneratedFile[] {\n const files: GeneratedFile[] = [];\n\n files.push({\n path: \"database.types.ts\",\n content: generateTypedefs(collections)\n });\n\n if (options.includeReadme !== false) {\n files.push({\n path: \"README.md\",\n content: `# Rebase SDK\n\n> Auto-generated by \\`rebase generate-sdk\\`. Do not edit manually.\n\n## Usage\n\n1. Install the client package:\n \\`\\`\\`bash\n npm install @rebasepro/client\n \\`\\`\\`\n\n2. Initialize with your generated types:\n \\`\\`\\`typescript\n import { createRebaseClient } from '@rebasepro/client';\n import type { Database } from './database.types';\n\n const rebase = createRebaseClient<Database>({\n baseUrl: 'http://localhost:3001',\n // token: '...', // User token if not using auth module\n });\n\n // Both syntax styles are fully typed!\n const { data: users } = await rebase.data.users.find();\n const { data: posts } = await rebase.data.collection('posts').find();\n \\`\\`\\`\n`\n });\n }\n\n return files;\n}\n"],"names":["resolveCollectionRelations"],"mappings":"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"}
package/dist/index.es.js CHANGED
@@ -3,6 +3,9 @@ function toPascalCase(str) {
3
3
  return str.split(/[_\-\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
4
4
  }
5
5
  function toCamelCase(str) {
6
+ if (!/[_\-\s]/.test(str)) {
7
+ return str.charAt(0).toLowerCase() + str.slice(1);
8
+ }
6
9
  const pascal = toPascalCase(str);
7
10
  return pascal.charAt(0).toLowerCase() + pascal.slice(1);
8
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/utils.ts","../src/generate-types.ts","../src/index.ts"],"sourcesContent":["/**\n * Utility functions for the SDK generator\n */\n\n/**\n * Convert a slug/snake_case string to PascalCase\n * e.g. \"private_notes\" → \"PrivateNotes\"\n */\nexport function toPascalCase(str: string): string {\n return str\n .split(/[_\\-\\s]+/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\n/**\n * Convert a slug/snake_case string to camelCase\n * e.g. \"private_notes\" → \"privateNotes\"\n */\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert a slug to a safe JS identifier\n * e.g. \"private-notes\" → \"privateNotes\"\n */\nexport function toSafeIdentifier(str: string): string {\n return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, \"_\"));\n}\n\n/**\n * Indent a block of text by a given number of spaces\n */\nexport function indent(text: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? pad + line : line))\n .join(\"\\n\");\n}\n","import { EntityCollection, PostgresCollection, Property, Properties, MapProperty, ArrayProperty, RelationProperty, StringProperty, NumberProperty } from \"@rebasepro/types\";\nimport { resolveCollectionRelations } from \"@rebasepro/common\";\nimport { toPascalCase, toSafeIdentifier } from \"./utils\";\n\nfunction propertyToTypeScriptType(prop: Property): string {\n switch (prop.type) {\n case \"string\": {\n const sp = prop as StringProperty;\n if (sp.enum) {\n const ids = Array.isArray(sp.enum)\n ? sp.enum.map((e: any) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(sp.enum);\n return ids.map(v => `\"${v}\"`).join(\" | \");\n }\n return \"string\";\n }\n case \"number\": {\n const np = prop as NumberProperty;\n if (np.enum) {\n const ids = Array.isArray(np.enum)\n ? np.enum.map((e: any) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(np.enum);\n return ids.join(\" | \");\n }\n return \"number\";\n }\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n return \"string\"; // ISO 8601 string over the wire\n case \"geopoint\":\n return \"{ latitude: number; longitude: number; }\";\n case \"reference\":\n return \"string | number\";\n case \"relation\":\n return \"string | number\";\n case \"map\": {\n const mapProp = prop as MapProperty;\n if (mapProp.properties) {\n const inner = Object.entries(mapProp.properties)\n .map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v as Property)};`)\n .join(\" \");\n return `{ ${inner} }`;\n }\n return \"Record<string, any>\";\n }\n case \"array\": {\n const arrProp = prop as ArrayProperty;\n if (arrProp.of) {\n return `Array<${propertyToTypeScriptType(arrProp.of as Property)}>`;\n }\n return \"Array<any>\";\n }\n case \"vector\":\n return \"number[]\";\n case \"binary\":\n return \"string\";\n default:\n return \"any\";\n }\n}\n\nexport function generateTypedefs(collections: EntityCollection[]): string {\n const lines: string[] = [\n \"/**\",\n \" * This file was auto-generated by Rebase.\",\n \" * Do not make direct changes to the file.\",\n \" */\",\n \"\",\n \"export interface Database {\"\n ];\n\n for (const collection of collections) {\n const typeName = toPascalCase(collection.slug);\n const properties = (collection.properties ?? {}) as Properties;\n\n // Resolve relations\n let resolvedRelations: Record<string, any> = {};\n try {\n resolvedRelations = resolveCollectionRelations(collection);\n } catch { /* ignore */ }\n\n lines.push(` ${toSafeIdentifier(collection.slug)}: {`);\n\n // ── Row Type ──\n lines.push(\" Row: {\");\n const emittedKeys = new Set<string>();\n\n // 1. Direct properties\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n lines.push(` ${toSafeIdentifier(key)}${isRequired ? \"\" : \"?\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n // 2. FK columns from relations\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n\n let fkType = \"string | number\";\n try {\n let target = relation.target();\n if (target && (target.default || target.__esModule)) {\n target = target.default || target;\n }\n if (target && target.properties) {\n const idProp = Object.entries(target.properties).find(([_, p]: [string, any]) => p.isId);\n if (idProp) {\n fkType = (idProp[1] as Property).type === \"number\" ? \"number\" : \"string\";\n }\n }\n } catch { /* ignore */ }\n\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n\n // 3. Relation fields\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") {\n if (emittedKeys.has(key)) continue;\n const relation = resolvedRelations[key];\n const isArray = relation?.cardinality === \"many\";\n const relType = \"{ id: string | number; path: string; __type: \\\"relation\\\"; data?: any }\";\n const tsType = isArray ? `Array<${relType}>` : relType;\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n }\n lines.push(\" };\");\n\n // ── Insert Type ──\n lines.push(\" Insert: {\");\n emittedKeys.clear();\n\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n const typedProp = prop as StringProperty | NumberProperty;\n const isAutoId = \"isId\" in prop && typedProp.isId && typedProp.isId !== \"manual\" && typedProp.isId !== true;\n const isOptional = !isRequired || isAutoId;\n lines.push(` ${toSafeIdentifier(key)}${isOptional ? \"?\" : \"\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n const fkType = \"string | number\";\n // simple fallback\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n // ── Update Type ──\n lines.push(\" Update: {\");\n emittedKeys.clear();\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n lines.push(\" };\");\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n lines.push(\"export type CollectionName = keyof Database;\");\n lines.push(\"export type CollectionsDictionary = { [K in CollectionName]: K };\");\n lines.push(\"\");\n lines.push(\"export const collectionsDictionary = {\");\n for (const collection of collections) {\n lines.push(` ${toSafeIdentifier(collection.slug)}: \"${collection.slug}\",`);\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * @rebasepro/sdk-generator\n *\n * Generates a purely typed Typescript database definition.\n */\n\nimport { EntityCollection } from \"@rebasepro/types\";\nimport { generateTypedefs } from \"./generate-types\";\n\nexport { generateTypedefs } from \"./generate-types\";\nexport { toPascalCase, toCamelCase, toSafeIdentifier, indent } from \"./utils\";\n\n// ─── Public API ────────────────────────────────────────────────────\n\nexport interface GeneratedFile {\n /** Relative file path within the output directory */\n path: string;\n /** File content */\n content: string;\n}\n\nexport interface GenerateSDKOptions {\n /** Whether to include a README file (default: true) */\n includeReadme?: boolean;\n}\n\nexport function generateSDK(\n collections: EntityCollection[],\n options: GenerateSDKOptions = {}\n): GeneratedFile[] {\n const files: GeneratedFile[] = [];\n\n files.push({\n path: \"database.types.ts\",\n content: generateTypedefs(collections)\n });\n\n if (options.includeReadme !== false) {\n files.push({\n path: \"README.md\",\n content: `# Rebase SDK\n\n> Auto-generated by \\`rebase generate-sdk\\`. Do not edit manually.\n\n## Usage\n\n1. Install the client package:\n \\`\\`\\`bash\n npm install @rebasepro/client\n \\`\\`\\`\n\n2. Initialize with your generated types:\n \\`\\`\\`typescript\n import { createRebaseClient } from '@rebasepro/client';\n import type { Database } from './database.types';\n\n const rebase = createRebaseClient<Database>({\n baseUrl: 'http://localhost:3001',\n // token: '...', // User token if not using auth module\n });\n\n // Both syntax styles are fully typed!\n const { data: users } = await rebase.data.users.find();\n const { data: posts } = await rebase.data.collection('posts').find();\n \\`\\`\\`\n`\n });\n }\n\n return files;\n}\n"],"names":[],"mappings":";AAQO,SAAS,aAAa,KAAqB;AAC9C,SAAO,IACF,MAAM,UAAU,EAChB,IAAI,CAAA,SAAQ,KAAK,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,CAAC,EAAE,aAAa,EACtE,KAAK,EAAE;AAChB;AAMO,SAAS,YAAY,KAAqB;AAC7C,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO,OAAO,OAAO,CAAC,EAAE,gBAAgB,OAAO,MAAM,CAAC;AAC1D;AAMO,SAAS,iBAAiB,KAAqB;AAClD,SAAO,YAAY,IAAI,QAAQ,kBAAkB,GAAG,CAAC;AACzD;AAKO,SAAS,OAAO,MAAc,QAAwB;AACzD,QAAM,MAAM,IAAI,OAAO,MAAM;AAC7B,SAAO,KACF,MAAM,IAAI,EACV,IAAI,CAAA,SAAS,KAAK,KAAA,IAAS,MAAM,OAAO,IAAK,EAC7C,KAAK,IAAI;AAClB;ACrCA,SAAS,yBAAyB,MAAwB;AACtD,UAAQ,KAAK,MAAA;AAAA,IACT,KAAK,UAAU;AACX,YAAM,KAAK;AACX,UAAI,GAAG,MAAM;AACT,cAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,IAC3B,GAAG,KAAK,IAAI,CAAC,MAAW,OAAO,MAAM,WAAW,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,CAAC,IACxE,OAAO,KAAK,GAAG,IAAI;AACzB,eAAO,IAAI,IAAI,CAAA,MAAK,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK;AAAA,MAC5C;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK,UAAU;AACX,YAAM,KAAK;AACX,UAAI,GAAG,MAAM;AACT,cAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,IAC3B,GAAG,KAAK,IAAI,CAAC,MAAW,OAAO,MAAM,WAAW,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,CAAC,IACxE,OAAO,KAAK,GAAG,IAAI;AACzB,eAAO,IAAI,KAAK,KAAK;AAAA,MACzB;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK,OAAO;AACR,YAAM,UAAU;AAChB,UAAI,QAAQ,YAAY;AACpB,cAAM,QAAQ,OAAO,QAAQ,QAAQ,UAAU,EAC1C,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,KAAK,yBAAyB,CAAa,CAAC,GAAG,EACrF,KAAK,GAAG;AACb,eAAO,KAAK,KAAK;AAAA,MACrB;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK,SAAS;AACV,YAAM,UAAU;AAChB,UAAI,QAAQ,IAAI;AACZ,eAAO,SAAS,yBAAyB,QAAQ,EAAc,CAAC;AAAA,MACpE;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EAAA;AAEnB;AAEO,SAAS,iBAAiB,aAAyC;AACtE,QAAM,QAAkB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGJ,aAAW,cAAc,aAAa;AACjB,iBAAa,WAAW,IAAI;AAC7C,UAAM,aAAc,WAAW,cAAc,CAAA;AAG7C,QAAI,oBAAyC,CAAA;AAC7C,QAAI;AACA,0BAAoB,2BAA2B,UAAU;AAAA,IAC7D,QAAQ;AAAA,IAAe;AAEvB,UAAM,KAAK,KAAK,iBAAiB,WAAW,IAAI,CAAC,KAAK;AAGtD,UAAM,KAAK,YAAY;AACvB,UAAM,kCAAkB,IAAA;AAGxB,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAE9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,aAAa,KAAK,YAAY;AACpC,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AAC/E,kBAAY,IAAI,GAAG;AAAA,IACvB;AAGA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAE5B,YAAI,SAAS;AACb,YAAI;AACA,cAAI,SAAS,SAAS,OAAA;AACtB,cAAI,WAAW,OAAO,WAAW,OAAO,aAAa;AACjD,qBAAS,OAAO,WAAW;AAAA,UAC/B;AACA,cAAI,UAAU,OAAO,YAAY;AAC7B,kBAAM,SAAS,OAAO,QAAQ,OAAO,UAAU,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,MAAqB,EAAE,IAAI;AACvF,gBAAI,QAAQ;AACR,uBAAU,OAAO,CAAC,EAAe,SAAS,WAAW,WAAW;AAAA,YACpE;AAAA,UACJ;AAAA,QACJ,QAAQ;AAAA,QAAe;AAEvB,cAAM,aAAa,SAAS,YAAY;AACxC,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AACjF,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AAGA,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,YAAY;AAC1B,YAAI,YAAY,IAAI,GAAG,EAAG;AAC1B,cAAM,WAAW,kBAAkB,GAAG;AACtC,cAAM,UAAU,UAAU,gBAAgB;AAC1C,cAAM,UAAU;AAChB,cAAM,SAAS,UAAU,SAAS,OAAO,MAAM;AAC/C,cAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,MAAM,MAAM,GAAG;AACxD,oBAAY,IAAI,GAAG;AAAA,MACvB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAGnB,UAAM,KAAK,eAAe;AAC1B,gBAAY,MAAA;AAEZ,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAC9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,aAAa,KAAK,YAAY;AACpC,YAAM,YAAY;AAClB,YAAM,WAAW,UAAU,QAAQ,UAAU,QAAQ,UAAU,SAAS,YAAY,UAAU,SAAS;AACvG,YAAM,aAAa,CAAC,cAAc;AAClC,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,GAAG,aAAa,MAAM,EAAE,KAAK,MAAM,GAAG;AAC/E,kBAAY,IAAI,GAAG;AAAA,IACvB;AAEA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,cAAM,SAAS;AAEf,cAAM,aAAa,SAAS,YAAY;AACxC,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AACjF,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAGnB,UAAM,KAAK,eAAe;AAC1B,gBAAY,MAAA;AACZ,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAC9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,MAAM,MAAM,GAAG;AACxD,kBAAY,IAAI,GAAG;AAAA,IACvB;AACA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,qBAAqB;AAChE,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAEnB,UAAM,KAAK,MAAM;AAAA,EACrB;AAEA,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,8CAA8C;AACzD,QAAM,KAAK,mEAAmE;AAC9E,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,wCAAwC;AACnD,aAAW,cAAc,aAAa;AAClC,UAAM,KAAK,KAAK,iBAAiB,WAAW,IAAI,CAAC,MAAM,WAAW,IAAI,IAAI;AAAA,EAC9E;AACA,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AAC1B;ACnLO,SAAS,YACZ,aACA,UAA8B,IACf;AACf,QAAM,QAAyB,CAAA;AAE/B,QAAM,KAAK;AAAA,IACP,MAAM;AAAA,IACN,SAAS,iBAAiB,WAAW;AAAA,EAAA,CACxC;AAED,MAAI,QAAQ,kBAAkB,OAAO;AACjC,UAAM,KAAK;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CA0BZ;AAAA,EACL;AAEA,SAAO;AACX;"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/utils.ts","../src/generate-types.ts","../src/index.ts"],"sourcesContent":["/**\n * Utility functions for the SDK generator\n */\n\n/**\n * Convert a slug/snake_case string to PascalCase\n * e.g. \"private_notes\" → \"PrivateNotes\"\n */\nexport function toPascalCase(str: string): string {\n return str\n .split(/[_\\-\\s]+/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n\n/**\n * Convert a slug/snake_case string to camelCase\n * e.g. \"private_notes\" → \"privateNotes\"\n */\nexport function toCamelCase(str: string): string {\n if (!/[_\\-\\s]/.test(str)) {\n return str.charAt(0).toLowerCase() + str.slice(1);\n }\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Convert a slug to a safe JS identifier\n * e.g. \"private-notes\" → \"privateNotes\"\n */\nexport function toSafeIdentifier(str: string): string {\n return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, \"_\"));\n}\n\n/**\n * Indent a block of text by a given number of spaces\n */\nexport function indent(text: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return text\n .split(\"\\n\")\n .map(line => (line.trim() ? pad + line : line))\n .join(\"\\n\");\n}\n","import { EntityCollection, PostgresCollection, Property, Properties, MapProperty, ArrayProperty, Relation, RelationProperty, StringProperty, NumberProperty } from \"@rebasepro/types\";\nimport { resolveCollectionRelations } from \"@rebasepro/common\";\nimport { toPascalCase, toSafeIdentifier } from \"./utils\";\n\nfunction propertyToTypeScriptType(prop: Property): string {\n switch (prop.type) {\n case \"string\": {\n const sp = prop as StringProperty;\n if (sp.enum) {\n const ids = Array.isArray(sp.enum)\n ? sp.enum.map((e: string | number | { id: string | number }) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(sp.enum);\n return ids.map(v => `\"${v}\"`).join(\" | \");\n }\n return \"string\";\n }\n case \"number\": {\n const np = prop as NumberProperty;\n if (np.enum) {\n const ids = Array.isArray(np.enum)\n ? np.enum.map((e: string | number | { id: string | number }) => typeof e === \"object\" ? String(e.id) : String(e))\n : Object.keys(np.enum);\n return ids.join(\" | \");\n }\n return \"number\";\n }\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n return \"string\"; // ISO 8601 string over the wire\n case \"geopoint\":\n return \"{ latitude: number; longitude: number; }\";\n case \"reference\":\n return \"string | number\";\n case \"relation\":\n return \"string | number\";\n case \"map\": {\n const mapProp = prop as MapProperty;\n if (mapProp.properties) {\n const inner = Object.entries(mapProp.properties)\n .map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v as Property)};`)\n .join(\" \");\n return `{ ${inner} }`;\n }\n return \"Record<string, any>\";\n }\n case \"array\": {\n const arrProp = prop as ArrayProperty;\n if (arrProp.of) {\n return `Array<${propertyToTypeScriptType(arrProp.of as Property)}>`;\n }\n return \"Array<any>\";\n }\n case \"vector\":\n return \"number[]\";\n case \"binary\":\n return \"string\";\n default:\n return \"any\";\n }\n}\n\nexport function generateTypedefs(collections: EntityCollection[]): string {\n const lines: string[] = [\n \"/**\",\n \" * This file was auto-generated by Rebase.\",\n \" * Do not make direct changes to the file.\",\n \" */\",\n \"\",\n \"export interface Database {\"\n ];\n\n for (const collection of collections) {\n const typeName = toPascalCase(collection.slug);\n const properties = (collection.properties ?? {}) as Properties;\n\n // Resolve relations\n let resolvedRelations: Record<string, Relation> = {};\n try {\n resolvedRelations = resolveCollectionRelations(collection);\n } catch { /* ignore */ }\n\n lines.push(` ${toSafeIdentifier(collection.slug)}: {`);\n\n // ── Row Type ──\n lines.push(\" Row: {\");\n const emittedKeys = new Set<string>();\n\n // 1. Direct properties\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n lines.push(` ${toSafeIdentifier(key)}${isRequired ? \"\" : \"?\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n // 2. FK columns from relations\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n\n let fkType = \"string | number\";\n try {\n let target = relation.target();\n if (target && (target.default || target.__esModule)) {\n target = target.default || target;\n }\n if (target && target.properties) {\n const idProp = Object.entries(target.properties).find(([_, p]) => (p as Record<string, unknown>).isId);\n if (idProp) {\n fkType = (idProp[1] as Property).type === \"number\" ? \"number\" : \"string\";\n }\n }\n } catch { /* ignore */ }\n\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n\n // 3. Relation fields\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") {\n if (emittedKeys.has(key)) continue;\n const relation = resolvedRelations[key];\n const isArray = relation?.cardinality === \"many\";\n const relType = \"{ id: string | number; path: string; __type: \\\"relation\\\"; data?: any }\";\n const tsType = isArray ? `Array<${relType}>` : relType;\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n }\n lines.push(\" };\");\n\n // ── Insert Type ──\n lines.push(\" Insert: {\");\n emittedKeys.clear();\n\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n const isRequired = prop.validation?.required;\n const typedProp = prop as StringProperty | NumberProperty;\n const isAutoId = \"isId\" in prop && typedProp.isId && typedProp.isId !== \"manual\" && typedProp.isId !== true;\n const isOptional = !isRequired || isAutoId;\n lines.push(` ${toSafeIdentifier(key)}${isOptional ? \"?\" : \"\"}: ${tsType};`);\n emittedKeys.add(key);\n }\n\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n const fkType = \"string | number\";\n // simple fallback\n const isRequired = relation.validation?.required;\n lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? \"\" : \"?\"}: ${fkType};`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n // ── Update Type ──\n lines.push(\" Update: {\");\n emittedKeys.clear();\n for (const [key, rawProp] of Object.entries(properties)) {\n const prop = rawProp as Property;\n if (prop.type === \"relation\") continue;\n const tsType = propertyToTypeScriptType(prop);\n lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);\n emittedKeys.add(key);\n }\n for (const [relKey, relation] of Object.entries(resolvedRelations)) {\n if (relation.direction === \"owning\" && relation.cardinality === \"one\" && relation.localKey) {\n const fkKey = relation.localKey;\n if (emittedKeys.has(fkKey)) continue;\n lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);\n emittedKeys.add(fkKey);\n }\n }\n lines.push(\" };\");\n\n lines.push(\" };\");\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n lines.push(\"export type CollectionName = keyof Database;\");\n lines.push(\"export type CollectionsDictionary = { [K in CollectionName]: K };\");\n lines.push(\"\");\n lines.push(\"export const collectionsDictionary = {\");\n for (const collection of collections) {\n lines.push(` ${toSafeIdentifier(collection.slug)}: \"${collection.slug}\",`);\n }\n lines.push(\"} as const;\");\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n","/**\n * @rebasepro/sdk-generator\n *\n * Generates a purely typed Typescript database definition.\n */\n\nimport { EntityCollection } from \"@rebasepro/types\";\nimport { generateTypedefs } from \"./generate-types\";\n\nexport { generateTypedefs } from \"./generate-types\";\nexport { toPascalCase, toCamelCase, toSafeIdentifier, indent } from \"./utils\";\n\n// ─── Public API ────────────────────────────────────────────────────\n\nexport interface GeneratedFile {\n /** Relative file path within the output directory */\n path: string;\n /** File content */\n content: string;\n}\n\nexport interface GenerateSDKOptions {\n /** Whether to include a README file (default: true) */\n includeReadme?: boolean;\n}\n\nexport function generateSDK(\n collections: EntityCollection[],\n options: GenerateSDKOptions = {}\n): GeneratedFile[] {\n const files: GeneratedFile[] = [];\n\n files.push({\n path: \"database.types.ts\",\n content: generateTypedefs(collections)\n });\n\n if (options.includeReadme !== false) {\n files.push({\n path: \"README.md\",\n content: `# Rebase SDK\n\n> Auto-generated by \\`rebase generate-sdk\\`. Do not edit manually.\n\n## Usage\n\n1. Install the client package:\n \\`\\`\\`bash\n npm install @rebasepro/client\n \\`\\`\\`\n\n2. Initialize with your generated types:\n \\`\\`\\`typescript\n import { createRebaseClient } from '@rebasepro/client';\n import type { Database } from './database.types';\n\n const rebase = createRebaseClient<Database>({\n baseUrl: 'http://localhost:3001',\n // token: '...', // User token if not using auth module\n });\n\n // Both syntax styles are fully typed!\n const { data: users } = await rebase.data.users.find();\n const { data: posts } = await rebase.data.collection('posts').find();\n \\`\\`\\`\n`\n });\n }\n\n return files;\n}\n"],"names":[],"mappings":";AAQO,SAAS,aAAa,KAAqB;AAC9C,SAAO,IACF,MAAM,UAAU,EAChB,IAAI,CAAA,SAAQ,KAAK,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,CAAC,EAAE,aAAa,EACtE,KAAK,EAAE;AAChB;AAMO,SAAS,YAAY,KAAqB;AAC7C,MAAI,CAAC,UAAU,KAAK,GAAG,GAAG;AACtB,WAAO,IAAI,OAAO,CAAC,EAAE,gBAAgB,IAAI,MAAM,CAAC;AAAA,EACpD;AACA,QAAM,SAAS,aAAa,GAAG;AAC/B,SAAO,OAAO,OAAO,CAAC,EAAE,gBAAgB,OAAO,MAAM,CAAC;AAC1D;AAMO,SAAS,iBAAiB,KAAqB;AAClD,SAAO,YAAY,IAAI,QAAQ,kBAAkB,GAAG,CAAC;AACzD;AAKO,SAAS,OAAO,MAAc,QAAwB;AACzD,QAAM,MAAM,IAAI,OAAO,MAAM;AAC7B,SAAO,KACF,MAAM,IAAI,EACV,IAAI,CAAA,SAAS,KAAK,KAAA,IAAS,MAAM,OAAO,IAAK,EAC7C,KAAK,IAAI;AAClB;ACxCA,SAAS,yBAAyB,MAAwB;AACtD,UAAQ,KAAK,MAAA;AAAA,IACT,KAAK,UAAU;AACX,YAAM,KAAK;AACX,UAAI,GAAG,MAAM;AACT,cAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,IAC3B,GAAG,KAAK,IAAI,CAAC,MAAiD,OAAO,MAAM,WAAW,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,CAAC,IAC9G,OAAO,KAAK,GAAG,IAAI;AACzB,eAAO,IAAI,IAAI,CAAA,MAAK,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK;AAAA,MAC5C;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK,UAAU;AACX,YAAM,KAAK;AACX,UAAI,GAAG,MAAM;AACT,cAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,IAC3B,GAAG,KAAK,IAAI,CAAC,MAAiD,OAAO,MAAM,WAAW,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,CAAC,IAC9G,OAAO,KAAK,GAAG,IAAI;AACzB,eAAO,IAAI,KAAK,KAAK;AAAA,MACzB;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK,OAAO;AACR,YAAM,UAAU;AAChB,UAAI,QAAQ,YAAY;AACpB,cAAM,QAAQ,OAAO,QAAQ,QAAQ,UAAU,EAC1C,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,iBAAiB,CAAC,CAAC,KAAK,yBAAyB,CAAa,CAAC,GAAG,EACrF,KAAK,GAAG;AACb,eAAO,KAAK,KAAK;AAAA,MACrB;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK,SAAS;AACV,YAAM,UAAU;AAChB,UAAI,QAAQ,IAAI;AACZ,eAAO,SAAS,yBAAyB,QAAQ,EAAc,CAAC;AAAA,MACpE;AACA,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EAAA;AAEnB;AAEO,SAAS,iBAAiB,aAAyC;AACtE,QAAM,QAAkB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGJ,aAAW,cAAc,aAAa;AACjB,iBAAa,WAAW,IAAI;AAC7C,UAAM,aAAc,WAAW,cAAc,CAAA;AAG7C,QAAI,oBAA8C,CAAA;AAClD,QAAI;AACA,0BAAoB,2BAA2B,UAAU;AAAA,IAC7D,QAAQ;AAAA,IAAe;AAEvB,UAAM,KAAK,KAAK,iBAAiB,WAAW,IAAI,CAAC,KAAK;AAGtD,UAAM,KAAK,YAAY;AACvB,UAAM,kCAAkB,IAAA;AAGxB,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAE9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,aAAa,KAAK,YAAY;AACpC,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AAC/E,kBAAY,IAAI,GAAG;AAAA,IACvB;AAGA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAE5B,YAAI,SAAS;AACb,YAAI;AACA,cAAI,SAAS,SAAS,OAAA;AACtB,cAAI,WAAW,OAAO,WAAW,OAAO,aAAa;AACjD,qBAAS,OAAO,WAAW;AAAA,UAC/B;AACA,cAAI,UAAU,OAAO,YAAY;AAC7B,kBAAM,SAAS,OAAO,QAAQ,OAAO,UAAU,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,MAAO,EAA8B,IAAI;AACrG,gBAAI,QAAQ;AACR,uBAAU,OAAO,CAAC,EAAe,SAAS,WAAW,WAAW;AAAA,YACpE;AAAA,UACJ;AAAA,QACJ,QAAQ;AAAA,QAAe;AAEvB,cAAM,aAAa,SAAS,YAAY;AACxC,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AACjF,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AAGA,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,YAAY;AAC1B,YAAI,YAAY,IAAI,GAAG,EAAG;AAC1B,cAAM,WAAW,kBAAkB,GAAG;AACtC,cAAM,UAAU,UAAU,gBAAgB;AAC1C,cAAM,UAAU;AAChB,cAAM,SAAS,UAAU,SAAS,OAAO,MAAM;AAC/C,cAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,MAAM,MAAM,GAAG;AACxD,oBAAY,IAAI,GAAG;AAAA,MACvB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAGnB,UAAM,KAAK,eAAe;AAC1B,gBAAY,MAAA;AAEZ,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAC9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,aAAa,KAAK,YAAY;AACpC,YAAM,YAAY;AAClB,YAAM,WAAW,UAAU,QAAQ,UAAU,QAAQ,UAAU,SAAS,YAAY,UAAU,SAAS;AACvG,YAAM,aAAa,CAAC,cAAc;AAClC,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,GAAG,aAAa,MAAM,EAAE,KAAK,MAAM,GAAG;AAC/E,kBAAY,IAAI,GAAG;AAAA,IACvB;AAEA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,cAAM,SAAS;AAEf,cAAM,aAAa,SAAS,YAAY;AACxC,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,GAAG,aAAa,KAAK,GAAG,KAAK,MAAM,GAAG;AACjF,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAGnB,UAAM,KAAK,eAAe;AAC1B,gBAAY,MAAA;AACZ,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAM,OAAO;AACb,UAAI,KAAK,SAAS,WAAY;AAC9B,YAAM,SAAS,yBAAyB,IAAI;AAC5C,YAAM,KAAK,SAAS,iBAAiB,GAAG,CAAC,MAAM,MAAM,GAAG;AACxD,kBAAY,IAAI,GAAG;AAAA,IACvB;AACA,eAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAChE,UAAI,SAAS,cAAc,YAAY,SAAS,gBAAgB,SAAS,SAAS,UAAU;AACxF,cAAM,QAAQ,SAAS;AACvB,YAAI,YAAY,IAAI,KAAK,EAAG;AAC5B,cAAM,KAAK,SAAS,iBAAiB,KAAK,CAAC,qBAAqB;AAChE,oBAAY,IAAI,KAAK;AAAA,MACzB;AAAA,IACJ;AACA,UAAM,KAAK,QAAQ;AAEnB,UAAM,KAAK,MAAM;AAAA,EACrB;AAEA,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,8CAA8C;AACzD,QAAM,KAAK,mEAAmE;AAC9E,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,wCAAwC;AACnD,aAAW,cAAc,aAAa;AAClC,UAAM,KAAK,KAAK,iBAAiB,WAAW,IAAI,CAAC,MAAM,WAAW,IAAI,IAAI;AAAA,EAC9E;AACA,QAAM,KAAK,aAAa;AACxB,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AAC1B;ACnLO,SAAS,YACZ,aACA,UAA8B,IACf;AACf,QAAM,QAAyB,CAAA;AAE/B,QAAM,KAAK;AAAA,IACP,MAAM;AAAA,IACN,SAAS,iBAAiB,WAAW;AAAA,EAAA,CACxC;AAED,MAAI,QAAQ,kBAAkB,OAAO;AACjC,UAAM,KAAK;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,CA0BZ;AAAA,EACL;AAEA,SAAO;AACX;"}
@@ -1,6 +1,4 @@
1
- import { StorageSource } from "./storage";
2
1
  import { Role, User } from "../users";
3
- import { RebaseData } from "./data";
4
2
  /**
5
3
  * Capabilities advertised by an auth provider.
6
4
  * UI components use this to show/hide features dynamically
@@ -89,6 +87,8 @@ export interface AuthControllerExtended<USER extends User = User, ExtraData = un
89
87
  code: string;
90
88
  redirectUri: string;
91
89
  }) => Promise<void>;
90
+ /** Generic OAuth login — works with any provider. Posts payload to /auth/{providerId}. */
91
+ oauthLogin?: (providerId: string, payload: Record<string, unknown>) => Promise<void>;
92
92
  /** Register a new user */
93
93
  register?(email: string, password: string, displayName?: string): Promise<void>;
94
94
  /** Skip login (for anonymous access if enabled) */
@@ -102,25 +102,3 @@ export interface AuthControllerExtended<USER extends User = User, ExtraData = un
102
102
  /** Update user profile */
103
103
  updateProfile?(displayName?: string, photoURL?: string): Promise<USER>;
104
104
  }
105
- /**
106
- * Implement this function to allow access to specific users.
107
- * @group Hooks and utilities
108
- */
109
- export type Authenticator<USER extends User = User> = (props: {
110
- /**
111
- * Logged-in user or null
112
- */
113
- user: USER | null;
114
- /**
115
- * AuthController
116
- */
117
- authController: AuthController<USER>;
118
- /**
119
- * Unified data access API
120
- */
121
- data: RebaseData;
122
- /**
123
- * Used storage implementation
124
- */
125
- storageSource: StorageSource;
126
- }) => boolean | Promise<boolean>;
@@ -65,7 +65,6 @@ export interface AdminRole {
65
65
  name: string;
66
66
  isAdmin: boolean;
67
67
  defaultPermissions: Record<string, unknown> | null;
68
- config: Record<string, unknown> | null;
69
68
  }
70
69
  /**
71
70
  * Client-side Admin API interface.
@@ -123,7 +122,6 @@ export interface AdminAPI {
123
122
  name: string;
124
123
  isAdmin?: boolean;
125
124
  defaultPermissions?: Record<string, unknown>;
126
- config?: Record<string, unknown>;
127
125
  }): Promise<{
128
126
  role: AdminRole;
129
127
  }>;
@@ -131,7 +129,6 @@ export interface AdminAPI {
131
129
  name?: string;
132
130
  isAdmin?: boolean;
133
131
  defaultPermissions?: Record<string, unknown>;
134
- config?: Record<string, unknown>;
135
132
  }): Promise<{
136
133
  role: AdminRole;
137
134
  }>;
@@ -4,7 +4,7 @@ import type { EntityReference } from "../types/entities";
4
4
  * Controller that provides access to the registered entity collections.
5
5
  * @group Models
6
6
  */
7
- export type CollectionRegistryController<DB = Record<string, unknown>, EC extends EntityCollection = EntityCollection<any>> = {
7
+ export type CollectionRegistryController<DB = Record<string, unknown>, EC extends EntityCollection = EntityCollection> = {
8
8
  /**
9
9
  * List of the mapped collections in the CMS.
10
10
  * Each entry relates to a collection in the root database.
@@ -76,6 +76,21 @@ export interface FindResponse<M extends Record<string, unknown> = Record<string,
76
76
  hasMore: boolean;
77
77
  };
78
78
  }
79
+ export type FilterOperator = WhereFilterOpShort;
80
+ /**
81
+ * Fluent Query Builder Interface supported on both client and server accessors.
82
+ * @group Data
83
+ */
84
+ export interface QueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {
85
+ where(column: keyof M & string, operator: FilterOperator, value: unknown): this;
86
+ orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
87
+ limit(count: number): this;
88
+ offset(count: number): this;
89
+ search(searchString: string): this;
90
+ include(...relations: string[]): this;
91
+ find(): Promise<FindResponse<M>>;
92
+ listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
93
+ }
79
94
  /**
80
95
  * A single collection's CRUD accessor.
81
96
  *
@@ -124,6 +139,12 @@ export interface CollectionAccessor<M extends Record<string, unknown> = Record<s
124
139
  * Count the number of records matching the given filter.
125
140
  */
126
141
  count?(params?: FindParams): Promise<number>;
142
+ where(column: keyof M & string, operator: FilterOperator, value: unknown): QueryBuilderInterface<M>;
143
+ orderBy(column: keyof M & string, ascending?: "asc" | "desc"): QueryBuilderInterface<M>;
144
+ limit(count: number): QueryBuilderInterface<M>;
145
+ offset(count: number): QueryBuilderInterface<M>;
146
+ search(searchString: string): QueryBuilderInterface<M>;
147
+ include(...relations: string[]): QueryBuilderInterface<M>;
127
148
  }
128
149
  /**
129
150
  * The unified data access object.
@@ -17,6 +17,21 @@ export type ListenEntityProps<M extends Record<string, unknown> = Record<string,
17
17
  onUpdate: (entity: Entity<M> | null) => void;
18
18
  onError?: (error: Error) => void;
19
19
  };
20
+ /**
21
+ * Configuration for vector similarity search queries.
22
+ * Vector search applies an ORDER BY distance expression and optionally
23
+ * filters results by a distance threshold.
24
+ */
25
+ export interface VectorSearchParams {
26
+ /** Property name containing the vector column */
27
+ property: string;
28
+ /** Query vector to compare against */
29
+ vector: number[];
30
+ /** Distance function (default: "cosine") */
31
+ distance?: "cosine" | "l2" | "inner_product";
32
+ /** Only return results within this distance threshold */
33
+ threshold?: number;
34
+ }
20
35
  /**
21
36
  * @internal
22
37
  */
@@ -30,6 +45,8 @@ export interface FetchCollectionProps<M extends Record<string, unknown> = Record
30
45
  orderBy?: string;
31
46
  searchString?: string;
32
47
  order?: "desc" | "asc";
48
+ /** Vector similarity search configuration */
49
+ vectorSearch?: VectorSearchParams;
33
50
  }
34
51
  /**
35
52
  * @internal
@@ -187,6 +204,7 @@ export interface RestFetchService {
187
204
  startAfter?: Record<string, unknown>;
188
205
  searchString?: string;
189
206
  databaseId?: string;
207
+ vectorSearch?: VectorSearchParams;
190
208
  }, include?: string[]): Promise<Record<string, unknown>[]>;
191
209
  /**
192
210
  * Fetch a single flattened entity with optional relation includes.
@@ -4,6 +4,7 @@ import type { EntityCollectionsBuilder } from "../types/builders";
4
4
  import type { EntityCustomView } from "../types/entity_views";
5
5
  import type { EntityAction } from "../types/entity_actions";
6
6
  import type { AppView, NavigationGroupMapping } from "./navigation";
7
+ import type { RebasePlugin } from "../types/plugins";
7
8
  /**
8
9
  * Options to enable the built-in collection editor.
9
10
  * When provided to `<RebaseCMS>`, the editor is auto-wired as a native feature.
@@ -19,12 +20,12 @@ export interface CollectionEditorOptions {
19
20
  /** Suggested base paths shown when creating new collections. */
20
21
  pathSuggestions?: string[];
21
22
  }
22
- export interface RebaseCMSConfig<EC extends EntityCollection = any> {
23
+ export interface RebaseCMSConfig<EC extends EntityCollection = EntityCollection> {
23
24
  collections?: EC[] | EntityCollectionsBuilder<EC>;
24
25
  homePage?: ReactNode;
25
- entityViews?: EntityCustomView<any>[];
26
+ entityViews?: EntityCustomView[];
26
27
  entityActions?: EntityAction[];
27
- plugins?: any[];
28
+ plugins?: RebasePlugin[];
28
29
  /**
29
30
  * Centralized configuration for how collections and views are grouped
30
31
  * in the navigation sidebar and home page.
@@ -42,7 +43,7 @@ export interface RebaseCMSConfig<EC extends EntityCollection = any> {
42
43
  collectionEditor?: boolean | CollectionEditorOptions;
43
44
  }
44
45
  export interface RebaseStudioConfig {
45
- tools?: ("sql" | "js" | "rls" | "schema" | "storage" | "cron" | "schema-visualizer" | "branches" | "api")[];
46
+ tools?: ("sql" | "js" | "rls" | "schema" | "storage" | "cron" | "schema-visualizer" | "branches" | "api" | "logs")[];
46
47
  homePage?: ReactNode;
47
48
  devViews?: AppView[];
48
49
  }
@@ -28,7 +28,7 @@ export type RebaseCallContext<USER extends User = User> = {
28
28
  * const { client } = props.context;
29
29
  * const result = await client.functions.invoke('extract-job', { url });
30
30
  */
31
- client: RebaseClient<any>;
31
+ client: RebaseClient;
32
32
  /**
33
33
  * Unified data access — `context.data.products.create(...)`.
34
34
  * Access any collection as a dynamic property.
@@ -133,7 +133,7 @@ export interface AuthUserData {
133
133
  displayName?: string | null;
134
134
  photoUrl?: string | null;
135
135
  emailVerified?: boolean;
136
- metadata?: Record<string, any>;
136
+ metadata?: Record<string, unknown>;
137
137
  createdAt?: Date;
138
138
  updatedAt?: Date;
139
139
  }
@@ -146,7 +146,7 @@ export interface AuthCreateUserData {
146
146
  password?: string;
147
147
  displayName?: string;
148
148
  photoUrl?: string;
149
- metadata?: Record<string, any>;
149
+ metadata?: Record<string, unknown>;
150
150
  }
151
151
  /**
152
152
  * Role data exposed by the auth adapter.
@@ -168,7 +168,6 @@ export interface AuthRoleData {
168
168
  edit?: boolean;
169
169
  delete?: boolean;
170
170
  }> | null;
171
- config?: Record<string, unknown> | null;
172
171
  }
173
172
  /**
174
173
  * Data for creating a role.
@@ -180,7 +179,6 @@ export interface AuthCreateRoleData {
180
179
  isAdmin?: boolean;
181
180
  defaultPermissions?: AuthRoleData["defaultPermissions"];
182
181
  collectionPermissions?: AuthRoleData["collectionPermissions"];
183
- config?: AuthRoleData["config"];
184
182
  }
185
183
  /**
186
184
  * User management operations for the admin panel.
@@ -589,10 +589,6 @@ export interface FilterPreset<Key extends string = string> {
589
589
  */
590
590
  sort?: [Key, "asc" | "desc"];
591
591
  }
592
- /**
593
- * @deprecated Use {@link FilterPreset} instead.
594
- */
595
- export type QuickFilter<Key extends string = string> = FilterPreset<Key>;
596
592
  /**
597
593
  * Used to indicate valid filter combinations (e.g. created in Firestore)
598
594
  * If the user selects a specific filter/sort combination, the CMS checks if it's
@@ -37,7 +37,7 @@ export interface LazyComponentRef<P = unknown> {
37
37
  *
38
38
  * @group Types
39
39
  */
40
- export type ComponentRef<P = unknown> = React.ComponentType<P> | LazyComponentRef<P> | (() => Promise<{
40
+ export type ComponentRef<P = any> = React.ComponentType<P> | LazyComponentRef<P> | (() => Promise<{
41
41
  default: React.ComponentType<P>;
42
42
  }>) | string;
43
43
  /**
@@ -44,7 +44,7 @@ export interface CronJobContext {
44
44
  /** A simple logger scoped to this job run. */
45
45
  log: (...args: unknown[]) => void;
46
46
  /** The RebaseClient instance to interact with the database. */
47
- client: RebaseClient<any>;
47
+ client: RebaseClient;
48
48
  }
49
49
  export type CronJobRunState = "idle" | "running" | "success" | "error" | "disabled";
50
50
  /**
@@ -50,6 +50,7 @@ export interface FormContext<M extends Record<string, unknown> = Record<string,
50
50
  export type EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {
51
51
  key: string;
52
52
  name: string;
53
+ icon?: string | React.ReactNode;
53
54
  tabComponent?: React.ReactNode;
54
55
  includeActions?: boolean | "bottom";
55
56
  Builder?: ComponentRef<EntityCustomViewParams<M>>;
@@ -15,7 +15,7 @@ export interface ExportConfig<USER extends User = User> {
15
15
  export interface ExportMappingFunction<USER extends User = User> {
16
16
  key: string;
17
17
  builder: ({ entity, context }: {
18
- entity: Entity<any>;
18
+ entity: Entity;
19
19
  context: RebaseContext<USER>;
20
20
  }) => Promise<string> | string;
21
21
  }
@@ -1,5 +1,5 @@
1
1
  import React, { FormEvent } from "react";
2
- export type FormexController<T = any> = {
2
+ export type FormexController<T = unknown> = {
3
3
  values: T;
4
4
  initialValues: T;
5
5
  setValues: (values: T) => void;
@@ -32,7 +32,7 @@ export type FormexController<T = any> = {
32
32
  canUndo: boolean;
33
33
  canRedo: boolean;
34
34
  };
35
- export type FormexResetProps<T = any> = {
35
+ export type FormexResetProps<T = unknown> = {
36
36
  values?: T;
37
37
  submitCount?: number;
38
38
  errors?: Record<string, string>;
@@ -104,8 +104,8 @@ export interface BaseUIConfig<CustomProps = unknown> {
104
104
  disabled?: boolean | PropertyDisabledConfig;
105
105
  widthPercentage?: number;
106
106
  customProps?: CustomProps;
107
- Field?: ComponentRef<any>;
108
- Preview?: ComponentRef<any>;
107
+ Field?: ComponentRef;
108
+ Preview?: ComponentRef;
109
109
  }
110
110
  export interface BaseProperty<CustomProps = unknown> {
111
111
  ui?: BaseUIConfig<CustomProps>;