@rebasepro/sdk-generator 0.0.1-canary.09e5ec5

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/LICENSE +6 -0
  2. package/dist/common/src/collections/CollectionRegistry.d.ts +56 -0
  3. package/dist/common/src/collections/index.d.ts +1 -0
  4. package/dist/common/src/data/buildRebaseData.d.ts +14 -0
  5. package/dist/common/src/index.d.ts +3 -0
  6. package/dist/common/src/util/builders.d.ts +57 -0
  7. package/dist/common/src/util/callbacks.d.ts +6 -0
  8. package/dist/common/src/util/collections.d.ts +11 -0
  9. package/dist/common/src/util/common.d.ts +2 -0
  10. package/dist/common/src/util/conditions.d.ts +26 -0
  11. package/dist/common/src/util/entities.d.ts +58 -0
  12. package/dist/common/src/util/enums.d.ts +3 -0
  13. package/dist/common/src/util/index.d.ts +16 -0
  14. package/dist/common/src/util/navigation_from_path.d.ts +34 -0
  15. package/dist/common/src/util/navigation_utils.d.ts +20 -0
  16. package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
  17. package/dist/common/src/util/paths.d.ts +14 -0
  18. package/dist/common/src/util/permissions.d.ts +5 -0
  19. package/dist/common/src/util/references.d.ts +2 -0
  20. package/dist/common/src/util/relations.d.ts +22 -0
  21. package/dist/common/src/util/resolutions.d.ts +72 -0
  22. package/dist/common/src/util/storage.d.ts +24 -0
  23. package/dist/index.cjs +232 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.es.js +229 -0
  26. package/dist/index.es.js.map +1 -0
  27. package/dist/sdk-generator/src/generate-types.d.ts +2 -0
  28. package/dist/sdk-generator/src/index.d.ts +19 -0
  29. package/dist/sdk-generator/src/utils.d.ts +22 -0
  30. package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
  31. package/dist/types/src/controllers/auth.d.ts +119 -0
  32. package/dist/types/src/controllers/client.d.ts +170 -0
  33. package/dist/types/src/controllers/collection_registry.d.ts +45 -0
  34. package/dist/types/src/controllers/customization_controller.d.ts +60 -0
  35. package/dist/types/src/controllers/data.d.ts +168 -0
  36. package/dist/types/src/controllers/data_driver.d.ts +160 -0
  37. package/dist/types/src/controllers/database_admin.d.ts +11 -0
  38. package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
  39. package/dist/types/src/controllers/effective_role.d.ts +4 -0
  40. package/dist/types/src/controllers/email.d.ts +34 -0
  41. package/dist/types/src/controllers/index.d.ts +18 -0
  42. package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
  43. package/dist/types/src/controllers/navigation.d.ts +213 -0
  44. package/dist/types/src/controllers/registry.d.ts +54 -0
  45. package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
  46. package/dist/types/src/controllers/side_entity_controller.d.ts +90 -0
  47. package/dist/types/src/controllers/snackbar.d.ts +24 -0
  48. package/dist/types/src/controllers/storage.d.ts +171 -0
  49. package/dist/types/src/index.d.ts +4 -0
  50. package/dist/types/src/rebase_context.d.ts +105 -0
  51. package/dist/types/src/types/backend.d.ts +536 -0
  52. package/dist/types/src/types/builders.d.ts +15 -0
  53. package/dist/types/src/types/chips.d.ts +5 -0
  54. package/dist/types/src/types/collections.d.ts +856 -0
  55. package/dist/types/src/types/cron.d.ts +102 -0
  56. package/dist/types/src/types/data_source.d.ts +64 -0
  57. package/dist/types/src/types/entities.d.ts +145 -0
  58. package/dist/types/src/types/entity_actions.d.ts +98 -0
  59. package/dist/types/src/types/entity_callbacks.d.ts +173 -0
  60. package/dist/types/src/types/entity_link_builder.d.ts +7 -0
  61. package/dist/types/src/types/entity_overrides.d.ts +10 -0
  62. package/dist/types/src/types/entity_views.d.ts +61 -0
  63. package/dist/types/src/types/export_import.d.ts +21 -0
  64. package/dist/types/src/types/index.d.ts +23 -0
  65. package/dist/types/src/types/locales.d.ts +4 -0
  66. package/dist/types/src/types/modify_collections.d.ts +5 -0
  67. package/dist/types/src/types/plugins.d.ts +279 -0
  68. package/dist/types/src/types/properties.d.ts +1176 -0
  69. package/dist/types/src/types/property_config.d.ts +70 -0
  70. package/dist/types/src/types/relations.d.ts +336 -0
  71. package/dist/types/src/types/slots.d.ts +252 -0
  72. package/dist/types/src/types/translations.d.ts +870 -0
  73. package/dist/types/src/types/user_management_delegate.d.ts +121 -0
  74. package/dist/types/src/types/websockets.d.ts +78 -0
  75. package/dist/types/src/users/index.d.ts +2 -0
  76. package/dist/types/src/users/roles.d.ts +22 -0
  77. package/dist/types/src/users/user.d.ts +46 -0
  78. package/jest.config.cjs +13 -0
  79. package/package.json +51 -0
  80. package/src/generate-types.ts +199 -0
  81. package/src/index.ts +71 -0
  82. package/src/json-logic-js.d.ts +8 -0
  83. package/src/utils.ts +42 -0
  84. package/test/sdk-generator.test.ts +88 -0
  85. package/tsconfig.json +26 -0
  86. package/vite.config.ts +49 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,232 @@
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@rebasepro/common")) : typeof define === "function" && define.amd ? define(["exports", "@rebasepro/common"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.RebaseSDKGenerator = {}, global.common));
3
+ })(this, (function(exports2, common) {
4
+ "use strict";
5
+ function toPascalCase(str) {
6
+ return str.split(/[_\-\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
7
+ }
8
+ function toCamelCase(str) {
9
+ const pascal = toPascalCase(str);
10
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
11
+ }
12
+ function toSafeIdentifier(str) {
13
+ return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, "_"));
14
+ }
15
+ function indent(text, spaces) {
16
+ const pad = " ".repeat(spaces);
17
+ return text.split("\n").map((line) => line.trim() ? pad + line : line).join("\n");
18
+ }
19
+ function propertyToTypeScriptType(prop) {
20
+ switch (prop.type) {
21
+ case "string": {
22
+ const sp = prop;
23
+ if (sp.enum) {
24
+ const ids = Array.isArray(sp.enum) ? sp.enum.map((e) => typeof e === "object" ? String(e.id) : String(e)) : Object.keys(sp.enum);
25
+ return ids.map((v) => `"${v}"`).join(" | ");
26
+ }
27
+ return "string";
28
+ }
29
+ case "number": {
30
+ const np = prop;
31
+ if (np.enum) {
32
+ const ids = Array.isArray(np.enum) ? np.enum.map((e) => typeof e === "object" ? String(e.id) : String(e)) : Object.keys(np.enum);
33
+ return ids.join(" | ");
34
+ }
35
+ return "number";
36
+ }
37
+ case "boolean":
38
+ return "boolean";
39
+ case "date":
40
+ return "string";
41
+ // ISO 8601 string over the wire
42
+ case "geopoint":
43
+ return "{ latitude: number; longitude: number; }";
44
+ case "reference":
45
+ return "string | number";
46
+ case "relation":
47
+ return "string | number";
48
+ case "map": {
49
+ const mapProp = prop;
50
+ if (mapProp.properties) {
51
+ const inner = Object.entries(mapProp.properties).map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v)};`).join(" ");
52
+ return `{ ${inner} }`;
53
+ }
54
+ return "Record<string, any>";
55
+ }
56
+ case "array": {
57
+ const arrProp = prop;
58
+ if (arrProp.of) {
59
+ return `Array<${propertyToTypeScriptType(arrProp.of)}>`;
60
+ }
61
+ return "Array<any>";
62
+ }
63
+ default:
64
+ return "any";
65
+ }
66
+ }
67
+ function generateTypedefs(collections) {
68
+ const lines = [
69
+ "/**",
70
+ " * This file was auto-generated by Rebase.",
71
+ " * Do not make direct changes to the file.",
72
+ " */",
73
+ "",
74
+ "export interface Database {"
75
+ ];
76
+ for (const collection of collections) {
77
+ toPascalCase(collection.slug);
78
+ const properties = collection.properties ?? {};
79
+ let resolvedRelations = {};
80
+ try {
81
+ resolvedRelations = common.resolveCollectionRelations(collection);
82
+ } catch {
83
+ }
84
+ lines.push(` ${toSafeIdentifier(collection.slug)}: {`);
85
+ lines.push(" Row: {");
86
+ const emittedKeys = /* @__PURE__ */ new Set();
87
+ for (const [key, rawProp] of Object.entries(properties)) {
88
+ const prop = rawProp;
89
+ if (prop.type === "relation") continue;
90
+ const tsType = propertyToTypeScriptType(prop);
91
+ const isRequired = prop.validation?.required;
92
+ lines.push(` ${toSafeIdentifier(key)}${isRequired ? "" : "?"}: ${tsType};`);
93
+ emittedKeys.add(key);
94
+ }
95
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
96
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
97
+ const fkKey = relation.localKey;
98
+ if (emittedKeys.has(fkKey)) continue;
99
+ let fkType = "string | number";
100
+ try {
101
+ const target = relation.target();
102
+ if (target.properties) {
103
+ const idProp = Object.entries(target.properties).find(([_, p]) => p.isId);
104
+ if (idProp) {
105
+ fkType = idProp[1].type === "number" ? "number" : "string";
106
+ }
107
+ }
108
+ } catch {
109
+ }
110
+ const isRequired = relation.validation?.required;
111
+ lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? "" : "?"}: ${fkType};`);
112
+ emittedKeys.add(fkKey);
113
+ }
114
+ }
115
+ for (const [key, rawProp] of Object.entries(properties)) {
116
+ const prop = rawProp;
117
+ if (prop.type === "relation") {
118
+ if (emittedKeys.has(key)) continue;
119
+ const relation = resolvedRelations[key];
120
+ const isArray = relation?.cardinality === "many";
121
+ const relType = '{ id: string | number; path: string; __type: "relation"; data?: any }';
122
+ const tsType = isArray ? `Array<${relType}>` : relType;
123
+ lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);
124
+ emittedKeys.add(key);
125
+ }
126
+ }
127
+ lines.push(" };");
128
+ lines.push(" Insert: {");
129
+ emittedKeys.clear();
130
+ for (const [key, rawProp] of Object.entries(properties)) {
131
+ const prop = rawProp;
132
+ if (prop.type === "relation") continue;
133
+ const tsType = propertyToTypeScriptType(prop);
134
+ const isRequired = prop.validation?.required;
135
+ const typedProp = prop;
136
+ const isAutoId = "isId" in prop && typedProp.isId && typedProp.isId !== "manual" && typedProp.isId !== true;
137
+ const isOptional = !isRequired || isAutoId;
138
+ lines.push(` ${toSafeIdentifier(key)}${isOptional ? "?" : ""}: ${tsType};`);
139
+ emittedKeys.add(key);
140
+ }
141
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
142
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
143
+ const fkKey = relation.localKey;
144
+ if (emittedKeys.has(fkKey)) continue;
145
+ const fkType = "string | number";
146
+ const isRequired = relation.validation?.required;
147
+ lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? "" : "?"}: ${fkType};`);
148
+ emittedKeys.add(fkKey);
149
+ }
150
+ }
151
+ lines.push(" };");
152
+ lines.push(" Update: {");
153
+ emittedKeys.clear();
154
+ for (const [key, rawProp] of Object.entries(properties)) {
155
+ const prop = rawProp;
156
+ if (prop.type === "relation") continue;
157
+ const tsType = propertyToTypeScriptType(prop);
158
+ lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);
159
+ emittedKeys.add(key);
160
+ }
161
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
162
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
163
+ const fkKey = relation.localKey;
164
+ if (emittedKeys.has(fkKey)) continue;
165
+ lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);
166
+ emittedKeys.add(fkKey);
167
+ }
168
+ }
169
+ lines.push(" };");
170
+ lines.push(" };");
171
+ }
172
+ lines.push("}");
173
+ lines.push("");
174
+ lines.push("export type CollectionName = keyof Database;");
175
+ lines.push("export type CollectionsDictionary = { [K in CollectionName]: K };");
176
+ lines.push("");
177
+ lines.push("export const collectionsDictionary = {");
178
+ for (const collection of collections) {
179
+ lines.push(` ${toSafeIdentifier(collection.slug)}: "${collection.slug}",`);
180
+ }
181
+ lines.push("} as const;");
182
+ lines.push("");
183
+ return lines.join("\n");
184
+ }
185
+ function generateSDK(collections, options = {}) {
186
+ const files = [];
187
+ files.push({
188
+ path: "database.types.ts",
189
+ content: generateTypedefs(collections)
190
+ });
191
+ if (options.includeReadme !== false) {
192
+ files.push({
193
+ path: "README.md",
194
+ content: `# Rebase SDK
195
+
196
+ > Auto-generated by \`rebase generate-sdk\`. Do not edit manually.
197
+
198
+ ## Usage
199
+
200
+ 1. Install the client package:
201
+ \`\`\`bash
202
+ npm install @rebasepro/client
203
+ \`\`\`
204
+
205
+ 2. Initialize with your generated types:
206
+ \`\`\`typescript
207
+ import { createRebaseClient } from '@rebasepro/client';
208
+ import type { Database } from './database.types';
209
+
210
+ const rebase = createRebaseClient<Database>({
211
+ baseUrl: 'http://localhost:3001',
212
+ // token: '...', // User token if not using auth module
213
+ });
214
+
215
+ // Both syntax styles are fully typed!
216
+ const { data: users } = await rebase.data.users.find();
217
+ const { data: posts } = await rebase.data.collection('posts').find();
218
+ \`\`\`
219
+ `
220
+ });
221
+ }
222
+ return files;
223
+ }
224
+ exports2.generateSDK = generateSDK;
225
+ exports2.generateTypedefs = generateTypedefs;
226
+ exports2.indent = indent;
227
+ exports2.toCamelCase = toCamelCase;
228
+ exports2.toPascalCase = toPascalCase;
229
+ exports2.toSafeIdentifier = toSafeIdentifier;
230
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
231
+ }));
232
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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 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 const target = relation.target();\n if (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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"}
@@ -0,0 +1,229 @@
1
+ import { resolveCollectionRelations } from "@rebasepro/common";
2
+ function toPascalCase(str) {
3
+ return str.split(/[_\-\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
4
+ }
5
+ function toCamelCase(str) {
6
+ const pascal = toPascalCase(str);
7
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
8
+ }
9
+ function toSafeIdentifier(str) {
10
+ return toCamelCase(str.replace(/[^a-zA-Z0-9_]/g, "_"));
11
+ }
12
+ function indent(text, spaces) {
13
+ const pad = " ".repeat(spaces);
14
+ return text.split("\n").map((line) => line.trim() ? pad + line : line).join("\n");
15
+ }
16
+ function propertyToTypeScriptType(prop) {
17
+ switch (prop.type) {
18
+ case "string": {
19
+ const sp = prop;
20
+ if (sp.enum) {
21
+ const ids = Array.isArray(sp.enum) ? sp.enum.map((e) => typeof e === "object" ? String(e.id) : String(e)) : Object.keys(sp.enum);
22
+ return ids.map((v) => `"${v}"`).join(" | ");
23
+ }
24
+ return "string";
25
+ }
26
+ case "number": {
27
+ const np = prop;
28
+ if (np.enum) {
29
+ const ids = Array.isArray(np.enum) ? np.enum.map((e) => typeof e === "object" ? String(e.id) : String(e)) : Object.keys(np.enum);
30
+ return ids.join(" | ");
31
+ }
32
+ return "number";
33
+ }
34
+ case "boolean":
35
+ return "boolean";
36
+ case "date":
37
+ return "string";
38
+ // ISO 8601 string over the wire
39
+ case "geopoint":
40
+ return "{ latitude: number; longitude: number; }";
41
+ case "reference":
42
+ return "string | number";
43
+ case "relation":
44
+ return "string | number";
45
+ case "map": {
46
+ const mapProp = prop;
47
+ if (mapProp.properties) {
48
+ const inner = Object.entries(mapProp.properties).map(([k, v]) => `${toSafeIdentifier(k)}: ${propertyToTypeScriptType(v)};`).join(" ");
49
+ return `{ ${inner} }`;
50
+ }
51
+ return "Record<string, any>";
52
+ }
53
+ case "array": {
54
+ const arrProp = prop;
55
+ if (arrProp.of) {
56
+ return `Array<${propertyToTypeScriptType(arrProp.of)}>`;
57
+ }
58
+ return "Array<any>";
59
+ }
60
+ default:
61
+ return "any";
62
+ }
63
+ }
64
+ function generateTypedefs(collections) {
65
+ const lines = [
66
+ "/**",
67
+ " * This file was auto-generated by Rebase.",
68
+ " * Do not make direct changes to the file.",
69
+ " */",
70
+ "",
71
+ "export interface Database {"
72
+ ];
73
+ for (const collection of collections) {
74
+ toPascalCase(collection.slug);
75
+ const properties = collection.properties ?? {};
76
+ let resolvedRelations = {};
77
+ try {
78
+ resolvedRelations = resolveCollectionRelations(collection);
79
+ } catch {
80
+ }
81
+ lines.push(` ${toSafeIdentifier(collection.slug)}: {`);
82
+ lines.push(" Row: {");
83
+ const emittedKeys = /* @__PURE__ */ new Set();
84
+ for (const [key, rawProp] of Object.entries(properties)) {
85
+ const prop = rawProp;
86
+ if (prop.type === "relation") continue;
87
+ const tsType = propertyToTypeScriptType(prop);
88
+ const isRequired = prop.validation?.required;
89
+ lines.push(` ${toSafeIdentifier(key)}${isRequired ? "" : "?"}: ${tsType};`);
90
+ emittedKeys.add(key);
91
+ }
92
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
93
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
94
+ const fkKey = relation.localKey;
95
+ if (emittedKeys.has(fkKey)) continue;
96
+ let fkType = "string | number";
97
+ try {
98
+ const target = relation.target();
99
+ if (target.properties) {
100
+ const idProp = Object.entries(target.properties).find(([_, p]) => p.isId);
101
+ if (idProp) {
102
+ fkType = idProp[1].type === "number" ? "number" : "string";
103
+ }
104
+ }
105
+ } catch {
106
+ }
107
+ const isRequired = relation.validation?.required;
108
+ lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? "" : "?"}: ${fkType};`);
109
+ emittedKeys.add(fkKey);
110
+ }
111
+ }
112
+ for (const [key, rawProp] of Object.entries(properties)) {
113
+ const prop = rawProp;
114
+ if (prop.type === "relation") {
115
+ if (emittedKeys.has(key)) continue;
116
+ const relation = resolvedRelations[key];
117
+ const isArray = relation?.cardinality === "many";
118
+ const relType = '{ id: string | number; path: string; __type: "relation"; data?: any }';
119
+ const tsType = isArray ? `Array<${relType}>` : relType;
120
+ lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);
121
+ emittedKeys.add(key);
122
+ }
123
+ }
124
+ lines.push(" };");
125
+ lines.push(" Insert: {");
126
+ emittedKeys.clear();
127
+ for (const [key, rawProp] of Object.entries(properties)) {
128
+ const prop = rawProp;
129
+ if (prop.type === "relation") continue;
130
+ const tsType = propertyToTypeScriptType(prop);
131
+ const isRequired = prop.validation?.required;
132
+ const typedProp = prop;
133
+ const isAutoId = "isId" in prop && typedProp.isId && typedProp.isId !== "manual" && typedProp.isId !== true;
134
+ const isOptional = !isRequired || isAutoId;
135
+ lines.push(` ${toSafeIdentifier(key)}${isOptional ? "?" : ""}: ${tsType};`);
136
+ emittedKeys.add(key);
137
+ }
138
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
139
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
140
+ const fkKey = relation.localKey;
141
+ if (emittedKeys.has(fkKey)) continue;
142
+ const fkType = "string | number";
143
+ const isRequired = relation.validation?.required;
144
+ lines.push(` ${toSafeIdentifier(fkKey)}${isRequired ? "" : "?"}: ${fkType};`);
145
+ emittedKeys.add(fkKey);
146
+ }
147
+ }
148
+ lines.push(" };");
149
+ lines.push(" Update: {");
150
+ emittedKeys.clear();
151
+ for (const [key, rawProp] of Object.entries(properties)) {
152
+ const prop = rawProp;
153
+ if (prop.type === "relation") continue;
154
+ const tsType = propertyToTypeScriptType(prop);
155
+ lines.push(` ${toSafeIdentifier(key)}?: ${tsType};`);
156
+ emittedKeys.add(key);
157
+ }
158
+ for (const [relKey, relation] of Object.entries(resolvedRelations)) {
159
+ if (relation.direction === "owning" && relation.cardinality === "one" && relation.localKey) {
160
+ const fkKey = relation.localKey;
161
+ if (emittedKeys.has(fkKey)) continue;
162
+ lines.push(` ${toSafeIdentifier(fkKey)}?: string | number;`);
163
+ emittedKeys.add(fkKey);
164
+ }
165
+ }
166
+ lines.push(" };");
167
+ lines.push(" };");
168
+ }
169
+ lines.push("}");
170
+ lines.push("");
171
+ lines.push("export type CollectionName = keyof Database;");
172
+ lines.push("export type CollectionsDictionary = { [K in CollectionName]: K };");
173
+ lines.push("");
174
+ lines.push("export const collectionsDictionary = {");
175
+ for (const collection of collections) {
176
+ lines.push(` ${toSafeIdentifier(collection.slug)}: "${collection.slug}",`);
177
+ }
178
+ lines.push("} as const;");
179
+ lines.push("");
180
+ return lines.join("\n");
181
+ }
182
+ function generateSDK(collections, options = {}) {
183
+ const files = [];
184
+ files.push({
185
+ path: "database.types.ts",
186
+ content: generateTypedefs(collections)
187
+ });
188
+ if (options.includeReadme !== false) {
189
+ files.push({
190
+ path: "README.md",
191
+ content: `# Rebase SDK
192
+
193
+ > Auto-generated by \`rebase generate-sdk\`. Do not edit manually.
194
+
195
+ ## Usage
196
+
197
+ 1. Install the client package:
198
+ \`\`\`bash
199
+ npm install @rebasepro/client
200
+ \`\`\`
201
+
202
+ 2. Initialize with your generated types:
203
+ \`\`\`typescript
204
+ import { createRebaseClient } from '@rebasepro/client';
205
+ import type { Database } from './database.types';
206
+
207
+ const rebase = createRebaseClient<Database>({
208
+ baseUrl: 'http://localhost:3001',
209
+ // token: '...', // User token if not using auth module
210
+ });
211
+
212
+ // Both syntax styles are fully typed!
213
+ const { data: users } = await rebase.data.users.find();
214
+ const { data: posts } = await rebase.data.collection('posts').find();
215
+ \`\`\`
216
+ `
217
+ });
218
+ }
219
+ return files;
220
+ }
221
+ export {
222
+ generateSDK,
223
+ generateTypedefs,
224
+ indent,
225
+ toCamelCase,
226
+ toPascalCase,
227
+ toSafeIdentifier
228
+ };
229
+ //# sourceMappingURL=index.es.js.map
@@ -0,0 +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 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 const target = relation.target();\n if (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":"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"}
@@ -0,0 +1,2 @@
1
+ import { EntityCollection } from "@rebasepro/types";
2
+ export declare function generateTypedefs(collections: EntityCollection[]): string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @rebasepro/sdk-generator
3
+ *
4
+ * Generates a purely typed Typescript database definition.
5
+ */
6
+ import { EntityCollection } from "@rebasepro/types";
7
+ export { generateTypedefs } from "./generate-types";
8
+ export { toPascalCase, toCamelCase, toSafeIdentifier, indent } from "./utils";
9
+ export interface GeneratedFile {
10
+ /** Relative file path within the output directory */
11
+ path: string;
12
+ /** File content */
13
+ content: string;
14
+ }
15
+ export interface GenerateSDKOptions {
16
+ /** Whether to include a README file (default: true) */
17
+ includeReadme?: boolean;
18
+ }
19
+ export declare function generateSDK(collections: EntityCollection[], options?: GenerateSDKOptions): GeneratedFile[];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Utility functions for the SDK generator
3
+ */
4
+ /**
5
+ * Convert a slug/snake_case string to PascalCase
6
+ * e.g. "private_notes" → "PrivateNotes"
7
+ */
8
+ export declare function toPascalCase(str: string): string;
9
+ /**
10
+ * Convert a slug/snake_case string to camelCase
11
+ * e.g. "private_notes" → "privateNotes"
12
+ */
13
+ export declare function toCamelCase(str: string): string;
14
+ /**
15
+ * Convert a slug to a safe JS identifier
16
+ * e.g. "private-notes" → "privateNotes"
17
+ */
18
+ export declare function toSafeIdentifier(str: string): string;
19
+ /**
20
+ * Indent a block of text by a given number of spaces
21
+ */
22
+ export declare function indent(text: string, spaces: number): string;
@@ -0,0 +1,7 @@
1
+ export type AnalyticsController = {
2
+ /**
3
+ * Callback used to get analytics events from the CMS
4
+ */
5
+ onAnalyticsEvent?: (event: AnalyticsEvent, data?: object) => void;
6
+ };
7
+ export type AnalyticsEvent = "entity_click" | "entity_click_from_reference" | "reference_selection_clear" | "reference_selection_toggle" | "reference_selected_single" | "reference_selection_new_entity" | "edit_entity_clicked" | "entity_edited" | "new_entity_click" | "new_entity_saved" | "copy_entity_click" | "entity_copied" | "single_delete_dialog_open" | "multiple_delete_dialog_open" | "single_entity_deleted" | "multiple_entities_deleted" | "drawer_navigate_to_home" | "drawer_navigate_to_collection" | "drawer_navigate_to_view" | "home_navigate_to_collection" | "home_favorite_navigate_to_collection" | "home_navigate_to_view" | "home_navigate_to_admin_view" | "home_favorite_navigate_to_view" | "home_move_card" | "home_move_group" | "home_drop_new_group" | "collection_inline_editing" | "view_mode_changed" | "kanban_card_moved" | "kanban_column_reorder" | "kanban_property_changed" | "kanban_new_entity_in_column" | "kanban_backfill_order" | "card_view_entity_click" | "unmapped_event";