@databricks/appkit 0.65.0 → 0.66.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CLAUDE.md +18 -0
  2. package/NOTICE.md +3 -2
  3. package/dist/appkit/package.js +1 -1
  4. package/dist/beta.d.ts +9 -1
  5. package/dist/beta.js +6 -1
  6. package/dist/cli/commands/generate-types.js +12 -3
  7. package/dist/cli/commands/generate-types.js.map +1 -1
  8. package/dist/database/contract/index.js +3 -0
  9. package/dist/database/contract/registry.d.ts +26 -0
  10. package/dist/database/contract/registry.d.ts.map +1 -0
  11. package/dist/database/contract/wire.d.ts +8 -0
  12. package/dist/database/contract/wire.d.ts.map +1 -0
  13. package/dist/database/contract/wire.js +37 -0
  14. package/dist/database/contract/wire.js.map +1 -0
  15. package/dist/database/errors.js +71 -0
  16. package/dist/database/errors.js.map +1 -0
  17. package/dist/database/runtime/data-path.js +39 -0
  18. package/dist/database/runtime/data-path.js.map +1 -0
  19. package/dist/database/runtime/engine/drizzle-data-path.js +194 -0
  20. package/dist/database/runtime/engine/drizzle-data-path.js.map +1 -0
  21. package/dist/database/runtime/engine/translate.js +176 -0
  22. package/dist/database/runtime/engine/translate.js.map +1 -0
  23. package/dist/database/schema-builder/columns.d.ts +39 -0
  24. package/dist/database/schema-builder/columns.d.ts.map +1 -0
  25. package/dist/database/schema-builder/columns.js +162 -0
  26. package/dist/database/schema-builder/columns.js.map +1 -0
  27. package/dist/database/schema-builder/define-schema.d.ts +12 -0
  28. package/dist/database/schema-builder/define-schema.d.ts.map +1 -0
  29. package/dist/database/schema-builder/define-schema.js +207 -0
  30. package/dist/database/schema-builder/define-schema.js.map +1 -0
  31. package/dist/database/schema-builder/engine/relations.js +37 -0
  32. package/dist/database/schema-builder/engine/relations.js.map +1 -0
  33. package/dist/database/schema-builder/engine/tables.js +124 -0
  34. package/dist/database/schema-builder/engine/tables.js.map +1 -0
  35. package/dist/database/schema-builder/fk.d.ts +9 -0
  36. package/dist/database/schema-builder/fk.d.ts.map +1 -0
  37. package/dist/database/schema-builder/fk.js +71 -0
  38. package/dist/database/schema-builder/fk.js.map +1 -0
  39. package/dist/database/schema-builder/index.js +6 -0
  40. package/dist/database/schema-builder/relations.js +51 -0
  41. package/dist/database/schema-builder/relations.js.map +1 -0
  42. package/dist/database/schema-builder/types.d.ts +121 -0
  43. package/dist/database/schema-builder/types.d.ts.map +1 -0
  44. package/dist/database/schema-builder/types.js +43 -0
  45. package/dist/database/schema-builder/types.js.map +1 -0
  46. package/dist/database/schema-builder/validators.js +53 -0
  47. package/dist/database/schema-builder/validators.js.map +1 -0
  48. package/dist/index.d.ts +2 -1
  49. package/dist/plugins/beta-exports.generated.d.ts +3 -1
  50. package/dist/plugins/beta-exports.generated.js +2 -0
  51. package/dist/plugins/database/database.d.ts +37 -0
  52. package/dist/plugins/database/database.d.ts.map +1 -0
  53. package/dist/plugins/database/database.js +68 -0
  54. package/dist/plugins/database/database.js.map +1 -0
  55. package/dist/plugins/database/defaults.js +12 -0
  56. package/dist/plugins/database/defaults.js.map +1 -0
  57. package/dist/plugins/database/entity-client.js +148 -0
  58. package/dist/plugins/database/entity-client.js.map +1 -0
  59. package/dist/plugins/database/entity-types.d.ts +76 -0
  60. package/dist/plugins/database/entity-types.d.ts.map +1 -0
  61. package/dist/plugins/database/index.d.ts +3 -0
  62. package/dist/plugins/database/index.js +3 -0
  63. package/dist/plugins/database/lifecycle.js +107 -0
  64. package/dist/plugins/database/lifecycle.js.map +1 -0
  65. package/dist/plugins/database/manifest.js +84 -0
  66. package/dist/plugins/database/manifest.js.map +1 -0
  67. package/dist/plugins/database/types.d.ts +10 -0
  68. package/dist/plugins/database/types.d.ts.map +1 -0
  69. package/dist/plugins/lakebase/manifest.js +1 -0
  70. package/dist/shared/src/schemas/manifest.d.ts +8 -8
  71. package/dist/type-generator/database/generate.d.ts +15 -0
  72. package/dist/type-generator/database/generate.d.ts.map +1 -0
  73. package/dist/type-generator/database/generate.js +104 -0
  74. package/dist/type-generator/database/generate.js.map +1 -0
  75. package/dist/type-generator/database/index.js +3 -0
  76. package/dist/type-generator/database/walk-schema.js +65 -0
  77. package/dist/type-generator/database/walk-schema.js.map +1 -0
  78. package/dist/type-generator/index.d.ts +148 -0
  79. package/dist/type-generator/index.d.ts.map +1 -0
  80. package/dist/type-generator/index.js +3 -1
  81. package/dist/type-generator/index.js.map +1 -1
  82. package/dist/type-generator/mv-registry/types.d.ts +99 -0
  83. package/dist/type-generator/mv-registry/types.d.ts.map +1 -0
  84. package/dist/type-generator/preflight.d.ts +16 -0
  85. package/dist/type-generator/preflight.d.ts.map +1 -0
  86. package/dist/type-generator/serving/generator.d.ts +20 -0
  87. package/dist/type-generator/serving/generator.d.ts.map +1 -0
  88. package/dist/type-generator/types.d.ts +72 -0
  89. package/dist/type-generator/types.d.ts.map +1 -0
  90. package/dist/type-generator/vite-plugin.d.ts +1 -0
  91. package/dist/type-generator/vite-plugin.d.ts.map +1 -1
  92. package/dist/type-generator/vite-plugin.js +41 -8
  93. package/dist/type-generator/vite-plugin.js.map +1 -1
  94. package/dist/type-generator/warehouse-status.d.ts +1 -0
  95. package/docs/api/appkit/Function.bigid.md +10 -0
  96. package/docs/api/appkit/Function.bigint.md +10 -0
  97. package/docs/api/appkit/Function.boolean.md +10 -0
  98. package/docs/api/appkit/Function.database.md +56 -0
  99. package/docs/api/appkit/Function.defineSchema.md +17 -0
  100. package/docs/api/appkit/Function.enumColumn.md +17 -0
  101. package/docs/api/appkit/Function.fk.md +18 -0
  102. package/docs/api/appkit/Function.id.md +10 -0
  103. package/docs/api/appkit/Function.integer.md +10 -0
  104. package/docs/api/appkit/Function.jsonb.md +10 -0
  105. package/docs/api/appkit/Function.text.md +10 -0
  106. package/docs/api/appkit/Function.timestamp.md +19 -0
  107. package/docs/api/appkit/Function.uuid.md +10 -0
  108. package/docs/api/appkit/Function.varchar.md +16 -0
  109. package/docs/api/appkit/Interface.DatabaseRegistry.md +3 -0
  110. package/docs/api/appkit/Interface.Schema.md +28 -0
  111. package/docs/api/appkit/TypeAlias.DatabaseExports.md +35 -0
  112. package/docs/api/appkit/TypeAlias.IDatabaseConfig.md +25 -0
  113. package/docs/api/appkit.md +18 -0
  114. package/llms.txt +18 -0
  115. package/package.json +4 -3
  116. package/sbom.cdx.json +1 -1
@@ -0,0 +1,148 @@
1
+ import { DatabasePluginError, classifyDatabaseError, databaseErrorFromStatus } from "../../database/errors.js";
2
+ import { andWhere, validateLimit, validateOffset } from "../../database/runtime/data-path.js";
3
+ import { databaseReadDefaults, databaseWriteDefaults } from "./defaults.js";
4
+
5
+ //#region src/plugins/database/entity-client.ts
6
+ /** Clone plain acyclic input so caller mutation cannot change a built query. */
7
+ function snapshotPlain(value, seen = /* @__PURE__ */ new Set()) {
8
+ if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "number" && Number.isFinite(value)) return value;
9
+ if (typeof value !== "object") throw new DatabasePluginError("INVALID_REQUEST", "read");
10
+ if (seen.has(value)) throw new DatabasePluginError("INVALID_REQUEST", "read");
11
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) throw new DatabasePluginError("INVALID_REQUEST", "read");
12
+ seen.add(value);
13
+ const copy = Array.isArray(value) ? value.map((item) => snapshotPlain(item, seen)) : Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshotPlain(item, seen)]));
14
+ seen.delete(value);
15
+ return copy;
16
+ }
17
+ /** Report eager fluent-input failures through the public read phase. */
18
+ function validateReadInput(validate) {
19
+ try {
20
+ return validate();
21
+ } catch (error) {
22
+ throw classifyDatabaseError(error, "read");
23
+ }
24
+ }
25
+ /**
26
+ * Plugin-facing client that composes immutable query state. The DataPath remains
27
+ * the schema-aware validation and execution boundary.
28
+ */
29
+ var EntityClient = class EntityClient {
30
+ constructor(ctx, state = {}) {
31
+ this.ctx = ctx;
32
+ this.state = state;
33
+ }
34
+ clone(state) {
35
+ return new EntityClient(this.ctx, state);
36
+ }
37
+ /** Snapshot and compose predicates; the adapter validates columns/operators. */
38
+ where(filter) {
39
+ const snapshot = snapshotPlain(filter);
40
+ return this.clone({
41
+ ...this.state,
42
+ where: andWhere(this.state.where, snapshot)
43
+ });
44
+ }
45
+ /** Merge ordering, replacing the direction for repeated columns. */
46
+ order(order) {
47
+ const snapshot = snapshotPlain(order);
48
+ return this.clone({
49
+ ...this.state,
50
+ order: {
51
+ ...this.state.order,
52
+ ...snapshot
53
+ }
54
+ });
55
+ }
56
+ select(columns) {
57
+ return this.clone({
58
+ ...this.state,
59
+ select: snapshotPlain(columns)
60
+ });
61
+ }
62
+ /** Merge relation includes, replacing repeated relation options. */
63
+ include(include) {
64
+ const snapshot = snapshotPlain(include);
65
+ return this.clone({
66
+ ...this.state,
67
+ include: {
68
+ ...this.state.include,
69
+ ...snapshot
70
+ }
71
+ });
72
+ }
73
+ limit(limit) {
74
+ return validateReadInput(() => this.clone({
75
+ ...this.state,
76
+ limit: validateLimit(limit)
77
+ }));
78
+ }
79
+ offset(offset) {
80
+ return validateReadInput(() => this.clone({
81
+ ...this.state,
82
+ offset: validateOffset(offset)
83
+ }));
84
+ }
85
+ /** Execute a collection read; DataPath applies the default upper bound. */
86
+ async toArray() {
87
+ return this.run("read", (dataPath) => dataPath.select(this.ctx.table, this.state));
88
+ }
89
+ async first() {
90
+ return (await this.limit(1).toArray())[0] ?? null;
91
+ }
92
+ find(id) {
93
+ return this.run("read", (dataPath) => dataPath.findOne(this.ctx.table, id, {
94
+ where: this.state.where,
95
+ select: this.state.select,
96
+ include: this.state.include
97
+ }));
98
+ }
99
+ count() {
100
+ return this.run("read", (dataPath) => dataPath.count(this.ctx.table, this.state.where));
101
+ }
102
+ create(values) {
103
+ return this.write("create", values, (dataPath, payload) => dataPath.insert(this.ctx.table, payload));
104
+ }
105
+ update(id, values) {
106
+ return this.write("update", values, (dataPath, payload) => dataPath.update(this.ctx.table, id, payload));
107
+ }
108
+ upsert(values, options) {
109
+ const onConflict = options.onConflict;
110
+ return this.write("create", values, (dataPath, payload) => dataPath.upsert(this.ctx.table, payload, onConflict));
111
+ }
112
+ delete(id) {
113
+ return this.run("write", (dataPath) => dataPath.delete(this.ctx.table, id), databaseWriteDefaults);
114
+ }
115
+ /** Validate caller values against the finalized trusted-write schema. */
116
+ async write(kind, values, operation) {
117
+ if (kind === "update" && Object.keys(values).length === 0) throw new DatabasePluginError("INVALID_REQUEST", "write");
118
+ let parsed;
119
+ try {
120
+ parsed = (kind === "create" ? this.ctx.table.$insertSchema : this.ctx.table.$updateSchema).parse(values);
121
+ } catch {
122
+ throw new DatabasePluginError("INVALID_REQUEST", "write");
123
+ }
124
+ return this.run("write", (dataPath) => operation(dataPath, parsed), databaseWriteDefaults);
125
+ }
126
+ /** Execute through AppKit interceptors and expose only safe failures. */
127
+ async run(phase, operation, defaults = databaseReadDefaults) {
128
+ try {
129
+ this.ctx.assertActive();
130
+ } catch (error) {
131
+ throw classifyDatabaseError(error, phase);
132
+ }
133
+ const result = await this.ctx.execute(async () => {
134
+ try {
135
+ this.ctx.assertActive();
136
+ return await operation(this.ctx.getDataPath());
137
+ } catch (error) {
138
+ throw classifyDatabaseError(error, phase);
139
+ }
140
+ }, { default: defaults });
141
+ if (result.ok) return result.data;
142
+ throw databaseErrorFromStatus(result.status, phase);
143
+ }
144
+ };
145
+
146
+ //#endregion
147
+ export { EntityClient };
148
+ //# sourceMappingURL=entity-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-client.js","names":[],"sources":["../../../src/plugins/database/entity-client.ts"],"sourcesContent":["import type { PluginExecuteConfig } from \"shared\";\n\nimport {\n classifyDatabaseError,\n DatabasePluginError,\n databaseErrorFromStatus,\n} from \"../../database/errors\";\nimport type {\n DataPath,\n IdValue,\n IncludeSpec,\n OrderSpec,\n QuerySpec,\n Row,\n WhereClause,\n} from \"../../database/runtime\";\nimport {\n andWhere,\n validateLimit,\n validateOffset,\n} from \"../../database/runtime/data-path\";\nimport type { AppKitTable } from \"../../database/schema-builder\";\nimport type { ExecutionResult } from \"../../plugin/execution-result\";\nimport { databaseReadDefaults, databaseWriteDefaults } from \"./defaults\";\n\n/** Apply AppKit execution policy to an entity operation. */\nexport type EntityExecute = <T>(\n fn: (signal?: AbortSignal) => Promise<T>,\n options: { default: PluginExecuteConfig; user?: PluginExecuteConfig },\n) => Promise<ExecutionResult<T>>;\n\n/** Runtime dependencies shared by immutable clients for one table. */\nexport interface EntityClientContext {\n readonly table: AppKitTable;\n readonly getDataPath: () => DataPath;\n readonly execute: EntityExecute;\n readonly assertActive: () => void;\n}\n\n/** Clone plain acyclic input so caller mutation cannot change a built query. */\nfunction snapshotPlain<T>(value: T, seen = new Set<object>()): T {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\" ||\n (typeof value === \"number\" && Number.isFinite(value))\n ) {\n return value;\n }\n if (typeof value !== \"object\") {\n throw new DatabasePluginError(\"INVALID_REQUEST\", \"read\");\n }\n if (seen.has(value)) throw new DatabasePluginError(\"INVALID_REQUEST\", \"read\");\n if (\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) !== Object.prototype\n )\n throw new DatabasePluginError(\"INVALID_REQUEST\", \"read\");\n seen.add(value);\n const copy = (\n Array.isArray(value)\n ? value.map((item) => snapshotPlain(item, seen))\n : Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n snapshotPlain(item, seen),\n ]),\n )\n ) as T;\n seen.delete(value);\n return copy;\n}\n\n/** Report eager fluent-input failures through the public read phase. */\nfunction validateReadInput<T>(validate: () => T): T {\n try {\n return validate();\n } catch (error) {\n throw classifyDatabaseError(error, \"read\");\n }\n}\n\n/**\n * Plugin-facing client that composes immutable query state. The DataPath remains\n * the schema-aware validation and execution boundary.\n */\nexport class EntityClient {\n constructor(\n private readonly ctx: EntityClientContext,\n private readonly state: QuerySpec = {},\n ) {}\n\n private clone(state: QuerySpec): EntityClient {\n return new EntityClient(this.ctx, state);\n }\n\n /** Snapshot and compose predicates; the adapter validates columns/operators. */\n where(filter: WhereClause): EntityClient {\n const snapshot = snapshotPlain(filter);\n return this.clone({\n ...this.state,\n where: andWhere(this.state.where, snapshot),\n });\n }\n\n /** Merge ordering, replacing the direction for repeated columns. */\n order(order: OrderSpec): EntityClient {\n const snapshot = snapshotPlain(order);\n return this.clone({\n ...this.state,\n order: { ...this.state.order, ...snapshot },\n });\n }\n\n select(columns: readonly string[]): EntityClient {\n return this.clone({ ...this.state, select: snapshotPlain(columns) });\n }\n\n /** Merge relation includes, replacing repeated relation options. */\n include(include: IncludeSpec): EntityClient {\n const snapshot = snapshotPlain(include);\n return this.clone({\n ...this.state,\n include: { ...this.state.include, ...snapshot },\n });\n }\n\n limit(limit: number): EntityClient {\n return validateReadInput(() =>\n this.clone({ ...this.state, limit: validateLimit(limit) }),\n );\n }\n\n offset(offset: number): EntityClient {\n return validateReadInput(() =>\n this.clone({ ...this.state, offset: validateOffset(offset) }),\n );\n }\n\n /** Execute a collection read; DataPath applies the default upper bound. */\n async toArray(): Promise<Row[]> {\n return this.run(\"read\", (dataPath) =>\n dataPath.select(this.ctx.table, this.state),\n );\n }\n\n async first(): Promise<Row | null> {\n return (await this.limit(1).toArray())[0] ?? null;\n }\n\n find(id: IdValue): Promise<Row | null> {\n return this.run(\"read\", (dataPath) =>\n dataPath.findOne(this.ctx.table, id, {\n where: this.state.where,\n select: this.state.select,\n include: this.state.include,\n }),\n );\n }\n\n count(): Promise<number> {\n return this.run(\"read\", (dataPath) =>\n dataPath.count(this.ctx.table, this.state.where),\n );\n }\n\n create(values: Row): Promise<Row> {\n return this.write(\"create\", values, (dataPath, payload) =>\n dataPath.insert(this.ctx.table, payload),\n );\n }\n\n update(id: IdValue, values: Row): Promise<Row | null> {\n return this.write(\"update\", values, (dataPath, payload) =>\n dataPath.update(this.ctx.table, id, payload),\n );\n }\n\n upsert(values: Row, options: { onConflict: string }): Promise<Row> {\n const onConflict = options.onConflict;\n return this.write(\"create\", values, (dataPath, payload) =>\n dataPath.upsert(this.ctx.table, payload, onConflict),\n );\n }\n\n delete(id: IdValue): Promise<boolean> {\n return this.run(\n \"write\",\n (dataPath) => dataPath.delete(this.ctx.table, id),\n databaseWriteDefaults,\n );\n }\n\n /** Validate caller values against the finalized trusted-write schema. */\n private async write<T>(\n kind: \"create\" | \"update\",\n values: Row,\n operation: (dataPath: DataPath, values: Row) => Promise<T>,\n ): Promise<T> {\n if (kind === \"update\" && Object.keys(values).length === 0) {\n throw new DatabasePluginError(\"INVALID_REQUEST\", \"write\");\n }\n let parsed: Row;\n try {\n const validator = (\n kind === \"create\"\n ? this.ctx.table.$insertSchema\n : this.ctx.table.$updateSchema\n ) as { parse(value: unknown): Row };\n parsed = validator.parse(values);\n } catch {\n throw new DatabasePluginError(\"INVALID_REQUEST\", \"write\");\n }\n return this.run(\n \"write\",\n (dataPath) => operation(dataPath, parsed),\n databaseWriteDefaults,\n );\n }\n\n /** Execute through AppKit interceptors and expose only safe failures. */\n private async run<T>(\n phase: \"read\" | \"write\",\n operation: (dataPath: DataPath) => Promise<T>,\n defaults: PluginExecuteConfig = databaseReadDefaults,\n ): Promise<T> {\n try {\n this.ctx.assertActive();\n } catch (error) {\n throw classifyDatabaseError(error, phase);\n }\n const result = await this.ctx.execute(\n async () => {\n try {\n this.ctx.assertActive();\n return await operation(this.ctx.getDataPath());\n } catch (error) {\n throw classifyDatabaseError(error, phase);\n }\n },\n { default: defaults },\n );\n if (result.ok) return result.data;\n throw databaseErrorFromStatus(result.status, phase);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { DatabaseRegistry, DatabaseRegistryEntry } from "../../database/contract/registry.js";
2
+ import { IdValue, OrderDirection } from "../../database/contract/wire.js";
3
+
4
+ //#region src/plugins/database/entity-types.d.ts
5
+ /** Registry shape accepted by reusable entity type helpers. */
6
+ type RegistryShape<R> = { readonly [K in keyof R]: DatabaseRegistryEntry };
7
+ type EntityNameFor<R extends RegistryShape<R>> = Extract<keyof R, string>;
8
+ type EntryFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = R[K] extends DatabaseRegistryEntry ? R[K] : never;
9
+ type RowOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["row"];
10
+ type PublicRowOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["publicRow"];
11
+ type InsertOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["insert"];
12
+ type UpdateOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["update"];
13
+ type FiltersOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["filters"];
14
+ type IncludesOfFor<R extends RegistryShape<R>, K extends EntityNameFor<R>> = EntryFor<R, K>["includes"];
15
+ type EntityName = EntityNameFor<DatabaseRegistry>;
16
+ type PublicRowOf<K extends EntityName> = PublicRowOfFor<DatabaseRegistry, K>;
17
+ type RelationTargetFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Relation extends keyof IncludesOfFor<Registry, K>> = IncludesOfFor<Registry, K>[Relation] extends {
18
+ to: infer Target extends EntityNameFor<Registry>;
19
+ } ? Target : never;
20
+ type IncludeOptionsFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Many extends boolean> = {
21
+ readonly select?: readonly (keyof RowOfFor<Registry, K> & string)[];
22
+ readonly where?: FiltersOfFor<Registry, K>;
23
+ readonly order?: Partial<Record<keyof RowOfFor<Registry, K> & string, OrderDirection>>;
24
+ } & (Many extends true ? {
25
+ readonly limit?: number;
26
+ } : {
27
+ readonly limit?: never;
28
+ });
29
+ type IncludeArgFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>> = { readonly [Relation in keyof IncludesOfFor<Registry, K>]?: boolean | IncludeOptionsFor<Registry, RelationTargetFor<Registry, K, Relation>, IncludesOfFor<Registry, K>[Relation] extends {
30
+ many: infer Many extends boolean;
31
+ } ? Many : false> };
32
+ type IncludedRowFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Config> = Config extends {
33
+ readonly select: infer Columns extends readonly (keyof RowOfFor<Registry, K> & string)[];
34
+ } ? Pick<RowOfFor<Registry, K>, Columns[number]> : PublicRowOfFor<Registry, K>;
35
+ type IncludedResultFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, I> = I extends Record<string, unknown> ? { [Relation in keyof I & keyof IncludesOfFor<Registry, K> as I[Relation] extends false ? never : Relation]: IncludesOfFor<Registry, K>[Relation] extends {
36
+ to: infer Target extends EntityNameFor<Registry>;
37
+ many: infer Many;
38
+ } ? Many extends true ? IncludedRowFor<Registry, Target, I[Relation]>[] : IncludedRowFor<Registry, Target, I[Relation]> | null : never } : Record<never, never>;
39
+ type EntityResultFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Selected, I> = Selected & IncludedResultFor<Registry, K, I>;
40
+ /** Fluent entity API shared by keyed and keyless tables. */
41
+ interface CommonEntityClientFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Selected = PublicRowOfFor<Registry, K>, I = Record<never, never>> {
42
+ where(filter: FiltersOfFor<Registry, K>): TypedEntityClientFor<Registry, K, Selected, I>;
43
+ order(order: Partial<Record<keyof RowOfFor<Registry, K> & string, OrderDirection>>): TypedEntityClientFor<Registry, K, Selected, I>;
44
+ select<const C extends readonly (keyof RowOfFor<Registry, K> & string)[]>(columns: C): TypedEntityClientFor<Registry, K, Pick<RowOfFor<Registry, K>, C[number]>, I>;
45
+ include<const Next extends IncludeArgFor<Registry, K>>(include: Next): TypedEntityClientFor<Registry, K, Selected, Omit<I, keyof Next> & Next>;
46
+ limit(limit: number): TypedEntityClientFor<Registry, K, Selected, I>;
47
+ offset(offset: number): TypedEntityClientFor<Registry, K, Selected, I>;
48
+ toArray(): Promise<Array<EntityResultFor<Registry, K, Selected, I>>>;
49
+ first(): Promise<EntityResultFor<Registry, K, Selected, I> | null>;
50
+ count(): Promise<number>;
51
+ create(values: InsertOfFor<Registry, K>): Promise<RowOfFor<Registry, K>>;
52
+ upsert(values: InsertOfFor<Registry, K>, options: {
53
+ onConflict: keyof RowOfFor<Registry, K> & string;
54
+ }): Promise<RowOfFor<Registry, K>>;
55
+ }
56
+ /** Add keyed operations only when typegen records a primary key. */
57
+ type KeyedEntityClientFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Selected, I> = EntryFor<Registry, K>["hasPrimaryKey"] extends true ? {
58
+ find(id: IdValue): Promise<EntityResultFor<Registry, K, Selected, I> | null>;
59
+ update(id: IdValue, values: UpdateOfFor<Registry, K>): Promise<RowOfFor<Registry, K> | null>;
60
+ delete(id: IdValue): Promise<boolean>;
61
+ } : Record<never, never>;
62
+ type TypedEntityClientFor<Registry extends RegistryShape<Registry>, K extends EntityNameFor<Registry>, Selected = PublicRowOfFor<Registry, K>, I = Record<never, never>> = CommonEntityClientFor<Registry, K, Selected, I> & KeyedEntityClientFor<Registry, K, Selected, I>;
63
+ type TypedEntityClient<K extends EntityName, Selected = PublicRowOf<K>, I = Record<never, never>> = TypedEntityClientFor<DatabaseRegistry, K, Selected, I>;
64
+ /** Parameterized SQL tag whose interpolations are always bound values. */
65
+ type SqlTag = <T = Record<string, unknown>>(strings: TemplateStringsArray, ...values: unknown[]) => Promise<T[]>;
66
+ /** Entity and SQL capabilities bound to one transaction. */
67
+ type TransactionClient = { readonly [K in EntityName]: TypedEntityClient<K> } & {
68
+ readonly sql: SqlTag;
69
+ };
70
+ /** Typed database API published by the plugin. */
71
+ type DatabaseExports = TransactionClient & {
72
+ transaction<T>(callback: (tx: TransactionClient) => Promise<T>): Promise<T>;
73
+ };
74
+ //#endregion
75
+ export { DatabaseExports };
76
+ //# sourceMappingURL=entity-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-types.d.ts","names":[],"sources":["../../../src/plugins/database/entity-types.ts"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { DatabaseExports } from "./entity-types.js";
2
+ import { IDatabaseConfig } from "./types.js";
3
+ import { database } from "./database.js";
@@ -0,0 +1,3 @@
1
+ import { database } from "./database.js";
2
+
3
+ export { };
@@ -0,0 +1,107 @@
1
+ import { createLogger } from "../../logging/logger.js";
2
+ import { createLakebasePool } from "../../connectors/lakebase/index.js";
3
+ import { assertFinalizedSchema } from "../../database/schema-builder/define-schema.js";
4
+ import { DatabasePluginError, classifyDatabaseError } from "../../database/errors.js";
5
+ import { createDrizzleDataPath, createDrizzleDb } from "../../database/runtime/engine/drizzle-data-path.js";
6
+ import { EntityClient } from "./entity-client.js";
7
+
8
+ //#region src/plugins/database/lifecycle.ts
9
+ const logger = createLogger("database");
10
+ /** Execute value-only SQL on the bound DataPath without per-statement retries. */
11
+ function buildSql(context) {
12
+ return async (strings, ...values) => {
13
+ try {
14
+ context.assertActive();
15
+ return await context.getDataPath().raw(strings, ...values);
16
+ } catch (error) {
17
+ throw classifyDatabaseError(error, "read");
18
+ }
19
+ };
20
+ }
21
+ /** Build entities and SQL bound to either the root pool or one transaction. */
22
+ function buildTransactionClient(context) {
23
+ const result = Object.create(null);
24
+ for (const [name, table] of Object.entries(context.schema.$tables)) result[name] = new EntityClient({
25
+ table,
26
+ getDataPath: context.getDataPath,
27
+ execute: context.execute,
28
+ assertActive: context.assertActive
29
+ });
30
+ result.sql = buildSql(context);
31
+ return result;
32
+ }
33
+ /** Add the transaction entry point to the root database surface. */
34
+ function buildDatabaseExports(context) {
35
+ const result = buildTransactionClient(context);
36
+ result.transaction = async (callback) => {
37
+ try {
38
+ context.assertActive();
39
+ return await context.getDataPath().transaction(async (txDataPath) => {
40
+ let active = true;
41
+ const assertTransactionActive = () => {
42
+ context.assertActive();
43
+ if (!active) throw new DatabasePluginError("INTERNAL", "transaction");
44
+ };
45
+ const directExecute = async (operation) => ({
46
+ ok: true,
47
+ data: await operation()
48
+ });
49
+ const tx = buildTransactionClient({
50
+ ...context,
51
+ getDataPath: () => txDataPath,
52
+ execute: directExecute,
53
+ assertActive: assertTransactionActive
54
+ });
55
+ try {
56
+ return await callback(tx);
57
+ } finally {
58
+ active = false;
59
+ }
60
+ });
61
+ } catch (error) {
62
+ throw classifyDatabaseError(error, "transaction");
63
+ }
64
+ };
65
+ return result;
66
+ }
67
+ /** Validate the schema, create one pool-backed API, and verify connectivity. */
68
+ async function createDatabaseState(schema, execute) {
69
+ try {
70
+ assertFinalizedSchema(schema);
71
+ } catch (error) {
72
+ logger.error("Database schema failed validation: %O", error);
73
+ throw new DatabasePluginError("SETUP_FAILED", "setup");
74
+ }
75
+ let active = true;
76
+ let pool;
77
+ const assertActive = () => {
78
+ if (!active) throw new DatabasePluginError("INTERNAL", "runtime");
79
+ };
80
+ try {
81
+ pool = createLakebasePool();
82
+ const dataPath = createDrizzleDataPath(createDrizzleDb(pool, schema), schema, { columnAccess: "trusted" });
83
+ const exports = buildDatabaseExports({
84
+ schema,
85
+ getDataPath: () => dataPath,
86
+ execute,
87
+ assertActive
88
+ });
89
+ await dataPath.raw`select 1`;
90
+ return {
91
+ pool,
92
+ exports,
93
+ deactivate: () => {
94
+ active = false;
95
+ }
96
+ };
97
+ } catch (error) {
98
+ logger.error("Database setup failed: %O", error);
99
+ active = false;
100
+ await pool?.end().catch(() => void 0);
101
+ throw new DatabasePluginError("SETUP_FAILED", "setup");
102
+ }
103
+ }
104
+
105
+ //#endregion
106
+ export { createDatabaseState };
107
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","names":[],"sources":["../../../src/plugins/database/lifecycle.ts"],"sourcesContent":["import { createLakebasePool } from \"../../connectors/lakebase\";\nimport {\n classifyDatabaseError,\n DatabasePluginError,\n} from \"../../database/errors\";\nimport type { DataPath } from \"../../database/runtime\";\nimport {\n createDrizzleDataPath,\n createDrizzleDb,\n} from \"../../database/runtime/engine/drizzle-data-path\";\nimport type { Schema } from \"../../database/schema-builder\";\nimport { assertFinalizedSchema } from \"../../database/schema-builder/define-schema\";\nimport { createLogger } from \"../../logging/logger\";\nimport { EntityClient, type EntityExecute } from \"./entity-client\";\nimport type {\n DatabaseExports,\n SqlTag,\n TransactionClient,\n} from \"./entity-types\";\n\nconst logger = createLogger(\"database\");\n\n/** Resources owned by one successfully initialized plugin instance. */\nexport interface DatabaseState {\n readonly pool: ReturnType<typeof createLakebasePool>;\n readonly exports: DatabaseExports;\n readonly deactivate: () => void;\n}\n\ninterface ExportContext {\n readonly schema: Schema;\n readonly getDataPath: () => DataPath;\n readonly execute: EntityExecute;\n readonly assertActive: () => void;\n}\n\n/** Execute value-only SQL on the bound DataPath without per-statement retries. */\nfunction buildSql(context: ExportContext): SqlTag {\n return async <T = Record<string, unknown>>(\n strings: TemplateStringsArray,\n ...values: unknown[]\n ) => {\n try {\n context.assertActive();\n // DataPath accepts value interpolation only and keeps Drizzle private.\n return await context.getDataPath().raw<T>(strings, ...values);\n } catch (error) {\n throw classifyDatabaseError(error, \"read\");\n }\n };\n}\n\n/** Build entities and SQL bound to either the root pool or one transaction. */\nfunction buildTransactionClient(context: ExportContext): TransactionClient {\n const result: Record<string, unknown> = Object.create(null);\n for (const [name, table] of Object.entries(context.schema.$tables)) {\n result[name] = new EntityClient({\n table,\n getDataPath: context.getDataPath,\n execute: context.execute,\n assertActive: context.assertActive,\n });\n }\n result.sql = buildSql(context);\n return result as TransactionClient;\n}\n\n/** Add the transaction entry point to the root database surface. */\nfunction buildDatabaseExports(context: ExportContext): DatabaseExports {\n const result = buildTransactionClient(context) as DatabaseExports;\n result.transaction = async <T>(\n callback: (tx: TransactionClient) => Promise<T>,\n ) => {\n try {\n context.assertActive();\n return await context.getDataPath().transaction(async (txDataPath) => {\n let active = true;\n const assertTransactionActive = () => {\n context.assertActive();\n if (!active) throw new DatabasePluginError(\"INTERNAL\", \"transaction\");\n };\n // The outer transaction owns execution; inner clients use its connection.\n const directExecute: EntityExecute = async (operation) => ({\n ok: true,\n data: await operation(),\n });\n const tx = buildTransactionClient({\n ...context,\n getDataPath: () => txDataPath,\n execute: directExecute,\n assertActive: assertTransactionActive,\n });\n try {\n return await callback(tx);\n } finally {\n // Captured clients must not outlive the transaction callback.\n active = false;\n }\n });\n } catch (error) {\n throw classifyDatabaseError(error, \"transaction\");\n }\n };\n return result;\n}\n\n/** Validate the schema, create one pool-backed API, and verify connectivity. */\nexport async function createDatabaseState<TSchema extends Schema>(\n schema: TSchema,\n execute: EntityExecute,\n): Promise<DatabaseState> {\n try {\n assertFinalizedSchema(schema);\n } catch (error) {\n logger.error(\"Database schema failed validation: %O\", error);\n throw new DatabasePluginError(\"SETUP_FAILED\", \"setup\");\n }\n\n let active = true;\n let pool: ReturnType<typeof createLakebasePool> | undefined;\n const assertActive = () => {\n if (!active) throw new DatabasePluginError(\"INTERNAL\", \"runtime\");\n };\n try {\n pool = createLakebasePool();\n const db = createDrizzleDb(pool, schema);\n const dataPath = createDrizzleDataPath(db, schema, {\n columnAccess: \"trusted\",\n });\n const exports = buildDatabaseExports({\n schema,\n getDataPath: () => dataPath,\n execute,\n assertActive,\n });\n // Do not publish exports until an authenticated statement succeeds.\n await dataPath.raw`select 1`;\n return {\n pool,\n exports,\n deactivate: () => {\n active = false;\n },\n };\n } catch (error) {\n logger.error(\"Database setup failed: %O\", error);\n active = false;\n await pool?.end().catch(() => undefined);\n throw new DatabasePluginError(\"SETUP_FAILED\", \"setup\");\n }\n}\n"],"mappings":";;;;;;;;AAoBA,MAAM,SAAS,aAAa,WAAW;;AAiBvC,SAAS,SAAS,SAAgC;AAChD,QAAO,OACL,SACA,GAAG,WACA;AACH,MAAI;AACF,WAAQ,cAAc;AAEtB,UAAO,MAAM,QAAQ,aAAa,CAAC,IAAO,SAAS,GAAG,OAAO;WACtD,OAAO;AACd,SAAM,sBAAsB,OAAO,OAAO;;;;;AAMhD,SAAS,uBAAuB,SAA2C;CACzE,MAAM,SAAkC,OAAO,OAAO,KAAK;AAC3D,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,QAAQ,OAAO,QAAQ,CAChE,QAAO,QAAQ,IAAI,aAAa;EAC9B;EACA,aAAa,QAAQ;EACrB,SAAS,QAAQ;EACjB,cAAc,QAAQ;EACvB,CAAC;AAEJ,QAAO,MAAM,SAAS,QAAQ;AAC9B,QAAO;;;AAIT,SAAS,qBAAqB,SAAyC;CACrE,MAAM,SAAS,uBAAuB,QAAQ;AAC9C,QAAO,cAAc,OACnB,aACG;AACH,MAAI;AACF,WAAQ,cAAc;AACtB,UAAO,MAAM,QAAQ,aAAa,CAAC,YAAY,OAAO,eAAe;IACnE,IAAI,SAAS;IACb,MAAM,gCAAgC;AACpC,aAAQ,cAAc;AACtB,SAAI,CAAC,OAAQ,OAAM,IAAI,oBAAoB,YAAY,cAAc;;IAGvE,MAAM,gBAA+B,OAAO,eAAe;KACzD,IAAI;KACJ,MAAM,MAAM,WAAW;KACxB;IACD,MAAM,KAAK,uBAAuB;KAChC,GAAG;KACH,mBAAmB;KACnB,SAAS;KACT,cAAc;KACf,CAAC;AACF,QAAI;AACF,YAAO,MAAM,SAAS,GAAG;cACjB;AAER,cAAS;;KAEX;WACK,OAAO;AACd,SAAM,sBAAsB,OAAO,cAAc;;;AAGrD,QAAO;;;AAIT,eAAsB,oBACpB,QACA,SACwB;AACxB,KAAI;AACF,wBAAsB,OAAO;UACtB,OAAO;AACd,SAAO,MAAM,yCAAyC,MAAM;AAC5D,QAAM,IAAI,oBAAoB,gBAAgB,QAAQ;;CAGxD,IAAI,SAAS;CACb,IAAI;CACJ,MAAM,qBAAqB;AACzB,MAAI,CAAC,OAAQ,OAAM,IAAI,oBAAoB,YAAY,UAAU;;AAEnE,KAAI;AACF,SAAO,oBAAoB;EAE3B,MAAM,WAAW,sBADN,gBAAgB,MAAM,OAAO,EACG,QAAQ,EACjD,cAAc,WACf,CAAC;EACF,MAAM,UAAU,qBAAqB;GACnC;GACA,mBAAmB;GACnB;GACA;GACD,CAAC;AAEF,QAAM,SAAS,GAAG;AAClB,SAAO;GACL;GACA;GACA,kBAAkB;AAChB,aAAS;;GAEZ;UACM,OAAO;AACd,SAAO,MAAM,6BAA6B,MAAM;AAChD,WAAS;AACT,QAAM,MAAM,KAAK,CAAC,YAAY,OAAU;AACxC,QAAM,IAAI,oBAAoB,gBAAgB,QAAQ"}
@@ -0,0 +1,84 @@
1
+ //#region src/plugins/database/manifest.json
2
+ var manifest_default = {
3
+ $schema: "https://databricks.github.io/appkit/schemas/plugin-manifest.schema.json",
4
+ name: "database",
5
+ displayName: "Database (Beta)",
6
+ description: "Schema-driven typed access to Databricks Lakebase PostgreSQL",
7
+ stability: "beta",
8
+ hidden: false,
9
+ resources: {
10
+ "required": [{
11
+ "type": "postgres",
12
+ "alias": "Postgres",
13
+ "resourceKey": "postgres",
14
+ "description": "Lakebase Postgres database for persistent storage",
15
+ "permission": "CAN_CONNECT_AND_CREATE",
16
+ "fields": {
17
+ "project": {
18
+ "description": "Lakebase project resource name",
19
+ "examples": ["projects/{project-id}"],
20
+ "discovery": {
21
+ "type": "kind",
22
+ "resourceKind": "postgres_project",
23
+ "select": "name"
24
+ }
25
+ },
26
+ "branch": {
27
+ "description": "Lakebase branch resource name",
28
+ "examples": ["projects/{project-id}/branches/{branch-id}"],
29
+ "discovery": {
30
+ "type": "kind",
31
+ "resourceKind": "postgres_branch",
32
+ "select": "name",
33
+ "dependsOn": "project"
34
+ }
35
+ },
36
+ "database": {
37
+ "description": "Lakebase database resource name",
38
+ "examples": ["projects/{project-id}/branches/{branch-id}/databases/{database-id}"],
39
+ "discovery": {
40
+ "type": "kind",
41
+ "resourceKind": "postgres_database",
42
+ "select": "name",
43
+ "dependsOn": "branch"
44
+ }
45
+ },
46
+ "host": {
47
+ "env": "PGHOST",
48
+ "localOnly": true,
49
+ "resolve": "postgres:host",
50
+ "description": "Postgres host"
51
+ },
52
+ "databaseName": {
53
+ "env": "PGDATABASE",
54
+ "localOnly": true,
55
+ "resolve": "postgres:databaseName",
56
+ "description": "Postgres database name"
57
+ },
58
+ "endpointPath": {
59
+ "env": "LAKEBASE_ENDPOINT",
60
+ "bundleIgnore": true,
61
+ "resolve": "postgres:endpointPath",
62
+ "description": "Lakebase endpoint resource name"
63
+ },
64
+ "port": {
65
+ "env": "PGPORT",
66
+ "localOnly": true,
67
+ "value": "5432",
68
+ "description": "Postgres port"
69
+ },
70
+ "sslmode": {
71
+ "env": "PGSSLMODE",
72
+ "localOnly": true,
73
+ "value": "require",
74
+ "description": "Postgres SSL mode"
75
+ }
76
+ }
77
+ }],
78
+ "optional": []
79
+ }
80
+ };
81
+
82
+ //#endregion
83
+ export { manifest_default as default };
84
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","names":[],"sources":["../../../src/plugins/database/manifest.json"],"sourcesContent":[""],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { Schema } from "../../database/schema-builder/types.js";
2
+
3
+ //#region src/plugins/database/types.d.ts
4
+ /** Configuration for one schema-bound DatabasePlugin instance. */
5
+ type IDatabaseConfig<TSchema extends Schema> = {
6
+ readonly schema: TSchema;
7
+ };
8
+ //#endregion
9
+ export { IDatabaseConfig };
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/plugins/database/types.ts"],"mappings":";;;;KAGY,eAAA,iBAAgC,MAAA;EAAA,SACjC,MAAA,EAAQ,OAAA;AAAA"}
@@ -16,6 +16,7 @@ var manifest_default = {
16
16
  "project": {
17
17
  "description": "Full Lakebase Postgres project resource name. Obtain by running `databricks postgres list-projects`, select the desired item from the output array and use its .name value.",
18
18
  "examples": ["projects/{project-id}"],
19
+ "bundleIgnore": true,
19
20
  "discovery": {
20
21
  "type": "kind",
21
22
  "resourceKind": "postgres_project",
@@ -81,8 +81,8 @@ declare const pluginManifestSchema: z.ZodObject<{
81
81
  type: z.ZodLiteral<"secret">;
82
82
  }, z.core.$strict>, z.ZodObject<{
83
83
  permission: z.ZodEnum<{
84
- CAN_VIEW: "CAN_VIEW";
85
84
  CAN_MANAGE_RUN: "CAN_MANAGE_RUN";
85
+ CAN_VIEW: "CAN_VIEW";
86
86
  CAN_MANAGE: "CAN_MANAGE";
87
87
  }>;
88
88
  alias: z.ZodString;
@@ -162,9 +162,9 @@ declare const pluginManifestSchema: z.ZodObject<{
162
162
  type: z.ZodLiteral<"sql_warehouse">;
163
163
  }, z.core.$strict>, z.ZodObject<{
164
164
  permission: z.ZodEnum<{
165
- CAN_QUERY: "CAN_QUERY";
166
165
  CAN_VIEW: "CAN_VIEW";
167
166
  CAN_MANAGE: "CAN_MANAGE";
167
+ CAN_QUERY: "CAN_QUERY";
168
168
  }>;
169
169
  alias: z.ZodString;
170
170
  resourceKey: z.ZodString;
@@ -438,10 +438,10 @@ declare const pluginManifestSchema: z.ZodObject<{
438
438
  type: z.ZodLiteral<"postgres">;
439
439
  }, z.core.$strict>, z.ZodObject<{
440
440
  permission: z.ZodEnum<{
441
- CAN_EDIT: "CAN_EDIT";
442
441
  CAN_VIEW: "CAN_VIEW";
443
442
  CAN_MANAGE: "CAN_MANAGE";
444
443
  CAN_RUN: "CAN_RUN";
444
+ CAN_EDIT: "CAN_EDIT";
445
445
  }>;
446
446
  alias: z.ZodString;
447
447
  resourceKey: z.ZodString;
@@ -480,8 +480,8 @@ declare const pluginManifestSchema: z.ZodObject<{
480
480
  type: z.ZodLiteral<"genie_space">;
481
481
  }, z.core.$strict>, z.ZodObject<{
482
482
  permission: z.ZodEnum<{
483
- CAN_EDIT: "CAN_EDIT";
484
483
  CAN_MANAGE: "CAN_MANAGE";
484
+ CAN_EDIT: "CAN_EDIT";
485
485
  CAN_READ: "CAN_READ";
486
486
  }>;
487
487
  alias: z.ZodString;
@@ -602,8 +602,8 @@ declare const pluginManifestSchema: z.ZodObject<{
602
602
  type: z.ZodLiteral<"secret">;
603
603
  }, z.core.$strict>, z.ZodObject<{
604
604
  permission: z.ZodEnum<{
605
- CAN_VIEW: "CAN_VIEW";
606
605
  CAN_MANAGE_RUN: "CAN_MANAGE_RUN";
606
+ CAN_VIEW: "CAN_VIEW";
607
607
  CAN_MANAGE: "CAN_MANAGE";
608
608
  }>;
609
609
  alias: z.ZodString;
@@ -683,9 +683,9 @@ declare const pluginManifestSchema: z.ZodObject<{
683
683
  type: z.ZodLiteral<"sql_warehouse">;
684
684
  }, z.core.$strict>, z.ZodObject<{
685
685
  permission: z.ZodEnum<{
686
- CAN_QUERY: "CAN_QUERY";
687
686
  CAN_VIEW: "CAN_VIEW";
688
687
  CAN_MANAGE: "CAN_MANAGE";
688
+ CAN_QUERY: "CAN_QUERY";
689
689
  }>;
690
690
  alias: z.ZodString;
691
691
  resourceKey: z.ZodString;
@@ -959,10 +959,10 @@ declare const pluginManifestSchema: z.ZodObject<{
959
959
  type: z.ZodLiteral<"postgres">;
960
960
  }, z.core.$strict>, z.ZodObject<{
961
961
  permission: z.ZodEnum<{
962
- CAN_EDIT: "CAN_EDIT";
963
962
  CAN_VIEW: "CAN_VIEW";
964
963
  CAN_MANAGE: "CAN_MANAGE";
965
964
  CAN_RUN: "CAN_RUN";
965
+ CAN_EDIT: "CAN_EDIT";
966
966
  }>;
967
967
  alias: z.ZodString;
968
968
  resourceKey: z.ZodString;
@@ -1001,8 +1001,8 @@ declare const pluginManifestSchema: z.ZodObject<{
1001
1001
  type: z.ZodLiteral<"genie_space">;
1002
1002
  }, z.core.$strict>, z.ZodObject<{
1003
1003
  permission: z.ZodEnum<{
1004
- CAN_EDIT: "CAN_EDIT";
1005
1004
  CAN_MANAGE: "CAN_MANAGE";
1005
+ CAN_EDIT: "CAN_EDIT";
1006
1006
  CAN_READ: "CAN_READ";
1007
1007
  }>;
1008
1008
  alias: z.ZodString;
@@ -0,0 +1,15 @@
1
+ //#region src/type-generator/database/generate.d.ts
2
+ /** Safe diagnostic raised when database declarations cannot be generated. */
3
+ declare class DatabaseTypegenError extends Error {
4
+ constructor(message?: string);
5
+ }
6
+ interface GenerateDatabaseTypesOptions {
7
+ readonly schemaFile: string;
8
+ readonly outFile: string;
9
+ }
10
+ declare const DATABASE_TYPES_FILE = "database.d.ts";
11
+ /** Generate current registry types or neutralize them when loading fails. */
12
+ declare function generateDatabaseTypes(options: GenerateDatabaseTypesOptions): Promise<void>;
13
+ //#endregion
14
+ export { DATABASE_TYPES_FILE, DatabaseTypegenError, generateDatabaseTypes };
15
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","names":[],"sources":["../../../src/type-generator/database/generate.ts"],"mappings":";;cAUa,oBAAA,SAA6B,KAAA;cAC5B,OAAA;AAAA;AAAA,UAMJ,4BAAA;EAAA,SACC,UAAA;EAAA,SACA,OAAA;AAAA;AAAA,cAGE,mBAAA;;iBA0FS,qBAAA,CACpB,OAAA,EAAS,4BAAA,GACR,OAAA"}